diff --git a/.eslintrc b/.eslintrc index 884b8f6..85ded6e 100644 --- a/.eslintrc +++ b/.eslintrc @@ -61,6 +61,7 @@ "no-unused-vars": ["error", { "varsIgnorePattern": "^_", "argsIgnorePattern": "^_", "caughtErrors": "none" }], "consistent-return": ["warn", { "treatUndefinedAsUnspecified": false }], "object-curly-newline": 0, - "unicorn/no-useless-undefined": 0 + "unicorn/no-useless-undefined": 0, + "sonarjs/cognitive-complexity": 0 } } diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f894cb..460d96a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,20 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [4.1.0](https://github.com/uttori/uttori-storage-provider-json-file/compare/v4.0.0...v4.1.0) - 2021-02-28 + +- 🛠 Switch memory cache data type (Array ➜ Object) +- 🛠 Fix return types +- 🛠 Remove auto adding `tags`, `customData` fields +- 🛠 Fix history race condition where writes with identical timestamps would lead to out of order history +- 🧰 Add option to disable in memory cache and always read from file +- 🎁 Update dev dependencies + ## [4.0.0](https://github.com/uttori/uttori-storage-provider-json-file/compare/v3.4.3...v4.0.0) - 2021-01-16 - 🧰 Add ESM Support - 🧰 Add explicit exports -- 🧰 Add support for `COUNT(*)` as stand alone `SELECT` field for returning counts. +- 🧰 Add support for `COUNT(*)` as stand alone `SELECT` field for returning counts - 🎁 Update dev dependencies ## [3.4.3](https://github.com/uttori/uttori-storage-provider-json-file/compare/v3.4.2...v3.4.3) - 2020-11-15 diff --git a/README.md b/README.md index 75bf4d9..2517626 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,13 @@ const results = s.getQuery('SELECT COUNT(*) FROM documents WHERE slug IS_NOT_NUL +## Functions + +
+
debug() : function
+
+
+ ## Typedefs
@@ -121,21 +128,20 @@ Storage for Uttori documents using JSON files stored on the local file system. | [config.extension] | string | "'json'" | The file extension to use for file, name of the employee. | | [config.spaces_document] | number | | The spaces parameter for JSON stringifying documents. | | [config.spaces_history] | number | | The spaces parameter for JSON stringifying history. | -| documents | [Array.<UttoriDocument>](#UttoriDocument) | | The collection of documents. | +| documents | object | | The collection of documents where the slug is the key and the value is the document. | * [StorageProvider](#StorageProvider) * [new StorageProvider(config)](#new_StorageProvider_new) - * [.all()](#StorageProvider+all) ⇒ Promise - * [.getQuery(query)](#StorageProvider+getQuery) ⇒ Promise - * [.get(slug)](#StorageProvider+get) ⇒ Promise - * [.getHistory(slug)](#StorageProvider+getHistory) ⇒ Promise - * [.getRevision(params)](#StorageProvider+getRevision) ⇒ Promise + * [.all()](#StorageProvider+all) ⇒ object + * [.getQuery(query)](#StorageProvider+getQuery) ⇒ Promise.<(Array.<UttoriDocument>\|number)> + * [.get(slug)](#StorageProvider+get) ⇒ Promise.<(UttoriDocument\|undefined)> * [.add(document)](#StorageProvider+add) * [.updateValid(document, originalSlug)](#StorageProvider+updateValid) ℗ * [.update(params)](#StorageProvider+update) * [.delete(slug)](#StorageProvider+delete) - * [.refresh()](#StorageProvider+refresh) + * [.getHistory(slug)](#StorageProvider+getHistory) ⇒ Promise.<Array.<string>> + * [.getRevision(params)](#StorageProvider+getRevision) ⇒ Promise.<(UttoriDocument\|undefined)> * [.updateHistory(slug, content, [originalSlug])](#StorageProvider+updateHistory) @@ -152,6 +158,7 @@ Creates an instance of StorageProvider. | [config.extension] | string | "json" | The file extension to use for file, name of the employee. | | [config.update_timestamps] | boolean | true | Should update times be marked at the time of edit. | | [config.use_history] | boolean | true | Should history entries be created. | +| [config.use_cache] | boolean | true | Should we cache files in memory? | | [config.spaces_document] | number | | The spaces parameter for JSON stringifying documents. | | [config.spaces_history] | number | | The spaces parameter for JSON stringifying history. | @@ -161,23 +168,23 @@ const storageProvider = new StorageProvider({ content_directory: 'content', hist ``` -### storageProvider.all() ⇒ Promise +### storageProvider.all() ⇒ object Returns all documents. **Kind**: instance method of [StorageProvider](#StorageProvider) -**Returns**: Promise - Promise object represents all documents. +**Returns**: object - All documents. **Example** ```js storageProvider.all(); -➜ [{ slug: 'first-document', ... }, ...] +➜ { first-document: { slug: 'first-document', ... }, ...} ``` -### storageProvider.getQuery(query) ⇒ Promise +### storageProvider.getQuery(query) ⇒ Promise.<(Array.<UttoriDocument>\|number)> Returns all documents matching a given query. **Kind**: instance method of [StorageProvider](#StorageProvider) -**Returns**: Promise - Promise object represents all matching documents. +**Returns**: Promise.<(Array.<UttoriDocument>\|number)> - Promise object represents all matching documents. | Param | Type | Description | | --- | --- | --- | @@ -185,42 +192,16 @@ Returns all documents matching a given query. -### storageProvider.get(slug) ⇒ Promise +### storageProvider.get(slug) ⇒ Promise.<(UttoriDocument\|undefined)> Returns a document for a given slug. **Kind**: instance method of [StorageProvider](#StorageProvider) -**Returns**: Promise - Promise object represents the returned UttoriDocument. +**Returns**: Promise.<(UttoriDocument\|undefined)> - Promise object represents the returned UttoriDocument. | Param | Type | Description | | --- | --- | --- | | slug | string | The slug of the document to be returned. | - - -### storageProvider.getHistory(slug) ⇒ Promise -Returns the history of edits for a given slug. - -**Kind**: instance method of [StorageProvider](#StorageProvider) -**Returns**: Promise - Promise object represents the returned history. - -| Param | Type | Description | -| --- | --- | --- | -| slug | string | The slug of the document to get history for. | - - - -### storageProvider.getRevision(params) ⇒ Promise -Returns a specifc revision from the history of edits for a given slug and revision timestamp. - -**Kind**: instance method of [StorageProvider](#StorageProvider) -**Returns**: Promise - Promise object represents the returned revision of the document. - -| Param | Type | Description | -| --- | --- | --- | -| params | object | The params object. | -| params.slug | string | The slug of the document to be returned. | -| params.revision | number | The unix timestamp of the history to be returned. | - ### storageProvider.add(document) @@ -269,12 +250,32 @@ Removes a document from the file system. | --- | --- | --- | | slug | string | The slug identifying the document. | - + + +### storageProvider.getHistory(slug) ⇒ Promise.<Array.<string>> +Returns the history of edits for a given slug. + +**Kind**: instance method of [StorageProvider](#StorageProvider) +**Returns**: Promise.<Array.<string>> - Promise object represents the returned history. + +| Param | Type | Description | +| --- | --- | --- | +| slug | string | The slug of the document to get history for. | + + -### storageProvider.refresh() -Reloads all documents from the file system into the cache. +### storageProvider.getRevision(params) ⇒ Promise.<(UttoriDocument\|undefined)> +Returns a specifc revision from the history of edits for a given slug and revision timestamp. **Kind**: instance method of [StorageProvider](#StorageProvider) +**Returns**: Promise.<(UttoriDocument\|undefined)> - Promise object represents the returned revision of the document. + +| Param | Type | Description | +| --- | --- | --- | +| params | object | The params object. | +| params.slug | string | The slug of the document to be returned. | +| params.revision | string \| number | The unix timestamp of the history to be returned. | + ### storageProvider.updateHistory(slug, content, [originalSlug]) @@ -288,6 +289,10 @@ Updates History for a given slug, renaming the store file and history folder as | content | string | The revision of the document to be saved. | | [originalSlug] | string | The original slug identifying the document, or the slug if it has not changed. | + + +## debug() : function +**Kind**: global function ## UttoriDocument diff --git a/docs/plugin.md b/docs/plugin.md index 146885e..59eee11 100644 --- a/docs/plugin.md +++ b/docs/plugin.md @@ -1,3 +1,18 @@ +## Classes + +
+
Plugin
+

Uttori Storage Provider - JSON File

+
+
+ +## Functions + +
+
debug() : function
+
+
+ ## Plugin @@ -71,3 +86,7 @@ const context = { }; Plugin.register(context); ``` + + +## debug() : function +**Kind**: global function diff --git a/docs/query-tools.md b/docs/query-tools.md index 2fa37bb..1ec99d1 100644 --- a/docs/query-tools.md +++ b/docs/query-tools.md @@ -1,10 +1,24 @@ +## Functions + +
+
debug() : function
+
+
processQuery(query, objects)Array.<object> | number
+

Processes a query string.

+
+
+ + + +## debug() : function +**Kind**: global function -## processQuery(query, objects) ⇒ Array.<object> +## processQuery(query, objects) ⇒ Array.<object> \| number Processes a query string. **Kind**: global function -**Returns**: Array.<object> - Returns an array of all matched documents. +**Returns**: Array.<object> \| number - Returns an array of all matched documents, or a count. | Param | Type | Description | | --- | --- | --- | diff --git a/docs/storage-provider.md b/docs/storage-provider.md index cc57ab9..68d8173 100644 --- a/docs/storage-provider.md +++ b/docs/storage-provider.md @@ -6,6 +6,13 @@
+## Functions + +
+
debug() : function
+
+
+ ## Typedefs
@@ -29,21 +36,20 @@ Storage for Uttori documents using JSON files stored on the local file system. | [config.extension] | string | "'json'" | The file extension to use for file, name of the employee. | | [config.spaces_document] | number | | The spaces parameter for JSON stringifying documents. | | [config.spaces_history] | number | | The spaces parameter for JSON stringifying history. | -| documents | [Array.<UttoriDocument>](#UttoriDocument) | | The collection of documents. | +| documents | object | | The collection of documents where the slug is the key and the value is the document. | * [StorageProvider](#StorageProvider) * [new StorageProvider(config)](#new_StorageProvider_new) - * [.all()](#StorageProvider+all) ⇒ Promise - * [.getQuery(query)](#StorageProvider+getQuery) ⇒ Promise - * [.get(slug)](#StorageProvider+get) ⇒ Promise - * [.getHistory(slug)](#StorageProvider+getHistory) ⇒ Promise - * [.getRevision(params)](#StorageProvider+getRevision) ⇒ Promise + * [.all()](#StorageProvider+all) ⇒ object + * [.getQuery(query)](#StorageProvider+getQuery) ⇒ Promise.<(Array.<UttoriDocument>\|number)> + * [.get(slug)](#StorageProvider+get) ⇒ Promise.<(UttoriDocument\|undefined)> * [.add(document)](#StorageProvider+add) * [.updateValid(document, originalSlug)](#StorageProvider+updateValid) ℗ * [.update(params)](#StorageProvider+update) * [.delete(slug)](#StorageProvider+delete) - * [.refresh()](#StorageProvider+refresh) + * [.getHistory(slug)](#StorageProvider+getHistory) ⇒ Promise.<Array.<string>> + * [.getRevision(params)](#StorageProvider+getRevision) ⇒ Promise.<(UttoriDocument\|undefined)> * [.updateHistory(slug, content, [originalSlug])](#StorageProvider+updateHistory) @@ -60,6 +66,7 @@ Creates an instance of StorageProvider. | [config.extension] | string | "json" | The file extension to use for file, name of the employee. | | [config.update_timestamps] | boolean | true | Should update times be marked at the time of edit. | | [config.use_history] | boolean | true | Should history entries be created. | +| [config.use_cache] | boolean | true | Should we cache files in memory? | | [config.spaces_document] | number | | The spaces parameter for JSON stringifying documents. | | [config.spaces_history] | number | | The spaces parameter for JSON stringifying history. | @@ -69,23 +76,23 @@ const storageProvider = new StorageProvider({ content_directory: 'content', hist ``` -### storageProvider.all() ⇒ Promise +### storageProvider.all() ⇒ object Returns all documents. **Kind**: instance method of [StorageProvider](#StorageProvider) -**Returns**: Promise - Promise object represents all documents. +**Returns**: object - All documents. **Example** ```js storageProvider.all(); -➜ [{ slug: 'first-document', ... }, ...] +➜ { first-document: { slug: 'first-document', ... }, ...} ``` -### storageProvider.getQuery(query) ⇒ Promise +### storageProvider.getQuery(query) ⇒ Promise.<(Array.<UttoriDocument>\|number)> Returns all documents matching a given query. **Kind**: instance method of [StorageProvider](#StorageProvider) -**Returns**: Promise - Promise object represents all matching documents. +**Returns**: Promise.<(Array.<UttoriDocument>\|number)> - Promise object represents all matching documents. | Param | Type | Description | | --- | --- | --- | @@ -93,42 +100,16 @@ Returns all documents matching a given query. -### storageProvider.get(slug) ⇒ Promise +### storageProvider.get(slug) ⇒ Promise.<(UttoriDocument\|undefined)> Returns a document for a given slug. **Kind**: instance method of [StorageProvider](#StorageProvider) -**Returns**: Promise - Promise object represents the returned UttoriDocument. +**Returns**: Promise.<(UttoriDocument\|undefined)> - Promise object represents the returned UttoriDocument. | Param | Type | Description | | --- | --- | --- | | slug | string | The slug of the document to be returned. | - - -### storageProvider.getHistory(slug) ⇒ Promise -Returns the history of edits for a given slug. - -**Kind**: instance method of [StorageProvider](#StorageProvider) -**Returns**: Promise - Promise object represents the returned history. - -| Param | Type | Description | -| --- | --- | --- | -| slug | string | The slug of the document to get history for. | - - - -### storageProvider.getRevision(params) ⇒ Promise -Returns a specifc revision from the history of edits for a given slug and revision timestamp. - -**Kind**: instance method of [StorageProvider](#StorageProvider) -**Returns**: Promise - Promise object represents the returned revision of the document. - -| Param | Type | Description | -| --- | --- | --- | -| params | object | The params object. | -| params.slug | string | The slug of the document to be returned. | -| params.revision | number | The unix timestamp of the history to be returned. | - ### storageProvider.add(document) @@ -177,12 +158,32 @@ Removes a document from the file system. | --- | --- | --- | | slug | string | The slug identifying the document. | - + + +### storageProvider.getHistory(slug) ⇒ Promise.<Array.<string>> +Returns the history of edits for a given slug. + +**Kind**: instance method of [StorageProvider](#StorageProvider) +**Returns**: Promise.<Array.<string>> - Promise object represents the returned history. + +| Param | Type | Description | +| --- | --- | --- | +| slug | string | The slug of the document to get history for. | + + -### storageProvider.refresh() -Reloads all documents from the file system into the cache. +### storageProvider.getRevision(params) ⇒ Promise.<(UttoriDocument\|undefined)> +Returns a specifc revision from the history of edits for a given slug and revision timestamp. **Kind**: instance method of [StorageProvider](#StorageProvider) +**Returns**: Promise.<(UttoriDocument\|undefined)> - Promise object represents the returned revision of the document. + +| Param | Type | Description | +| --- | --- | --- | +| params | object | The params object. | +| params.slug | string | The slug of the document to be returned. | +| params.revision | string \| number | The unix timestamp of the history to be returned. | + ### storageProvider.updateHistory(slug, content, [originalSlug]) @@ -196,6 +197,10 @@ Updates History for a given slug, renaming the store file and history folder as | content | string | The revision of the document to be saved. | | [originalSlug] | string | The original slug identifying the document, or the slug if it has not changed. | + + +## debug() : function +**Kind**: global function ## UttoriDocument diff --git a/package-lock.json b/package-lock.json index a0df807..d7dae2e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,54 +1,61 @@ { "name": "@uttori/storage-provider-json-file", - "version": "3.4.3", + "version": "4.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { "@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", + "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", "dev": true, "requires": { - "@babel/highlight": "^7.10.4" + "@babel/highlight": "^7.12.13" } }, + "@babel/compat-data": { + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.13.8.tgz", + "integrity": "sha512-EaI33z19T4qN3xLXsGf48M2cDqa6ei9tPZlfLdb2HC+e/cFtREiRd8hdSqDbwdLB0/+gLwqJmCYASH0z2bUdog==", + "dev": true + }, "@babel/core": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.10.tgz", - "integrity": "sha512-eTAlQKq65zHfkHZV0sIVODCPGVgoo1HdBlbSLi9CqOzuZanMv2ihzY+4paiKr1mH+XmYESMAmJ/dpZ68eN6d8w==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.10", - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helpers": "^7.12.5", - "@babel/parser": "^7.12.10", - "@babel/template": "^7.12.7", - "@babel/traverse": "^7.12.10", - "@babel/types": "^7.12.10", + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.13.8.tgz", + "integrity": "sha512-oYapIySGw1zGhEFRd6lzWNLWFX2s5dA/jm+Pw/+59ZdXtjyIuwlXbrId22Md0rgZVop+aVoqow2riXhBLNyuQg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@babel/generator": "^7.13.0", + "@babel/helper-compilation-targets": "^7.13.8", + "@babel/helper-module-transforms": "^7.13.0", + "@babel/helpers": "^7.13.0", + "@babel/parser": "^7.13.4", + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.13.0", + "@babel/types": "^7.13.0", "convert-source-map": "^1.7.0", "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", + "gensync": "^1.0.0-beta.2", "json5": "^2.1.2", "lodash": "^4.17.19", - "semver": "^5.4.1", + "semver": "^6.3.0", "source-map": "^0.5.0" }, "dependencies": { "json5": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", - "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", "dev": true, "requires": { "minimist": "^1.2.5" } }, "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, "source-map": { @@ -59,13 +66,48 @@ } } }, + "@babel/eslint-parser": { + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.13.8.tgz", + "integrity": "sha512-XewKkiyukrGzMeqToXJQk6hjg2veI9SNQElGzAoAjKxYCLbgcVX4KA2WhoyqMon9N4RMdCZhNTJNOBcp9spsiw==", + "dev": true, + "requires": { + "eslint-scope": "5.1.0", + "eslint-visitor-keys": "^1.3.0", + "semver": "^6.3.0" + }, + "dependencies": { + "eslint-scope": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz", + "integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, "@babel/generator": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.11.tgz", - "integrity": "sha512-Ggg6WPOJtSi8yYQvLVjG8F/TlpWDlKx0OpS4Kt+xMQPs5OaGYWy+v1A+1TvxI6sAMGZpKWWoAQ1DaeQbImlItA==", + "version": "7.13.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.9.tgz", + "integrity": "sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==", "dev": true, "requires": { - "@babel/types": "^7.12.11", + "@babel/types": "^7.13.0", "jsesc": "^2.5.1", "source-map": "^0.5.0" }, @@ -78,98 +120,118 @@ } } }, + "@babel/helper-compilation-targets": { + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.8.tgz", + "integrity": "sha512-pBljUGC1y3xKLn1nrx2eAhurLMA8OqBtBP/JwG4U8skN7kf8/aqwwxpV1N6T0e7r6+7uNitIa/fUxPFagSXp3A==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.13.8", + "@babel/helper-validator-option": "^7.12.17", + "browserslist": "^4.14.5", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, "@babel/helper-function-name": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.11.tgz", - "integrity": "sha512-AtQKjtYNolKNi6nNNVLQ27CP6D9oFR6bq/HPYSizlzbp7uC1M59XJe8L+0uXjbIaZaUJF99ruHqVGiKXU/7ybA==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", + "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "^7.12.10", - "@babel/template": "^7.12.7", - "@babel/types": "^7.12.11" + "@babel/helper-get-function-arity": "^7.12.13", + "@babel/template": "^7.12.13", + "@babel/types": "^7.12.13" } }, "@babel/helper-get-function-arity": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.10.tgz", - "integrity": "sha512-mm0n5BPjR06wh9mPQaDdXWDoll/j5UpCAPl1x8fS71GHm7HA6Ua2V4ylG1Ju8lvcTOietbPNNPaSilKj+pj+Ag==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", + "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", "dev": true, "requires": { - "@babel/types": "^7.12.10" + "@babel/types": "^7.12.13" } }, "@babel/helper-member-expression-to-functions": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.7.tgz", - "integrity": "sha512-DCsuPyeWxeHgh1Dus7APn7iza42i/qXqiFPWyBDdOFtvS581JQePsc1F/nD+fHrcswhLlRc2UpYS1NwERxZhHw==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.0.tgz", + "integrity": "sha512-yvRf8Ivk62JwisqV1rFRMxiSMDGnN6KH1/mDMmIrij4jztpQNRoHqqMG3U6apYbGRPJpgPalhva9Yd06HlUxJQ==", "dev": true, "requires": { - "@babel/types": "^7.12.7" + "@babel/types": "^7.13.0" } }, "@babel/helper-module-imports": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz", - "integrity": "sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.13.tgz", + "integrity": "sha512-NGmfvRp9Rqxy0uHSSVP+SRIW1q31a7Ji10cLBcqSDUngGentY4FRiHOFZFE1CLU5eiL0oE8reH7Tg1y99TDM/g==", "dev": true, "requires": { - "@babel/types": "^7.12.5" + "@babel/types": "^7.12.13" } }, "@babel/helper-module-transforms": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.12.1.tgz", - "integrity": "sha512-QQzehgFAZ2bbISiCpmVGfiGux8YVFXQ0abBic2Envhej22DVXV9nCFaS5hIQbkyo1AdGb+gNME2TSh3hYJVV/w==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.12.1", - "@babel/helper-replace-supers": "^7.12.1", - "@babel/helper-simple-access": "^7.12.1", - "@babel/helper-split-export-declaration": "^7.11.0", - "@babel/helper-validator-identifier": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.12.1", - "@babel/types": "^7.12.1", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.13.0.tgz", + "integrity": "sha512-Ls8/VBwH577+pw7Ku1QkUWIyRRNHpYlts7+qSqBBFCW3I8QteB9DxfcZ5YJpOwH6Ihe/wn8ch7fMGOP1OhEIvw==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.12.13", + "@babel/helper-replace-supers": "^7.13.0", + "@babel/helper-simple-access": "^7.12.13", + "@babel/helper-split-export-declaration": "^7.12.13", + "@babel/helper-validator-identifier": "^7.12.11", + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.13.0", + "@babel/types": "^7.13.0", "lodash": "^4.17.19" } }, "@babel/helper-optimise-call-expression": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.10.tgz", - "integrity": "sha512-4tpbU0SrSTjjt65UMWSrUOPZTsgvPgGG4S8QSTNHacKzpS51IVWGDj0yCwyeZND/i+LSN2g/O63jEXEWm49sYQ==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz", + "integrity": "sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA==", "dev": true, "requires": { - "@babel/types": "^7.12.10" + "@babel/types": "^7.12.13" } }, "@babel/helper-replace-supers": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.11.tgz", - "integrity": "sha512-q+w1cqmhL7R0FNzth/PLLp2N+scXEK/L2AHbXUyydxp828F4FEa5WcVoqui9vFRiHDQErj9Zof8azP32uGVTRA==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.13.0.tgz", + "integrity": "sha512-Segd5me1+Pz+rmN/NFBOplMbZG3SqRJOBlY+mA0SxAv6rjj7zJqr1AVr3SfzUVTLCv7ZLU5FycOM/SBGuLPbZw==", "dev": true, "requires": { - "@babel/helper-member-expression-to-functions": "^7.12.7", - "@babel/helper-optimise-call-expression": "^7.12.10", - "@babel/traverse": "^7.12.10", - "@babel/types": "^7.12.11" + "@babel/helper-member-expression-to-functions": "^7.13.0", + "@babel/helper-optimise-call-expression": "^7.12.13", + "@babel/traverse": "^7.13.0", + "@babel/types": "^7.13.0" } }, "@babel/helper-simple-access": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.12.1.tgz", - "integrity": "sha512-OxBp7pMrjVewSSC8fXDFrHrBcJATOOFssZwv16F3/6Xtc138GHybBfPbm9kfiqQHKhYQrlamWILwlDCeyMFEaA==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.12.13.tgz", + "integrity": "sha512-0ski5dyYIHEfwpWGx5GPWhH35j342JaflmCeQmsPWcrOQDtCN6C1zKAVRFVbK53lPW2c9TsuLLSUDf0tIGJ5hA==", "dev": true, "requires": { - "@babel/types": "^7.12.1" + "@babel/types": "^7.12.13" } }, "@babel/helper-split-export-declaration": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.11.tgz", - "integrity": "sha512-LsIVN8j48gHgwzfocYUSkO/hjYAOJqlpJEc7tGXcIm4cubjVUf8LGW6eWRyxEu7gA25q02p0rQUWoCI33HNS5g==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", + "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", "dev": true, "requires": { - "@babel/types": "^7.12.11" + "@babel/types": "^7.12.13" } }, "@babel/helper-validator-identifier": { @@ -178,24 +240,30 @@ "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", "dev": true }, + "@babel/helper-validator-option": { + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz", + "integrity": "sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw==", + "dev": true + }, "@babel/helpers": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.12.5.tgz", - "integrity": "sha512-lgKGMQlKqA8meJqKsW6rUnc4MdUk35Ln0ATDqdM1a/UpARODdI4j5Y5lVfUScnSNkJcdCRAaWkspykNoFg9sJA==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.13.0.tgz", + "integrity": "sha512-aan1MeFPxFacZeSz6Ld7YZo5aPuqnKlD7+HZY75xQsueczFccP9A7V05+oe0XpLwHK3oLorPe9eaAUljL7WEaQ==", "dev": true, "requires": { - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.12.5", - "@babel/types": "^7.12.5" + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.13.0", + "@babel/types": "^7.13.0" } }, "@babel/highlight": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", - "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.8.tgz", + "integrity": "sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.10.4", + "@babel/helper-validator-identifier": "^7.12.11", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, @@ -253,24 +321,24 @@ } }, "@babel/parser": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.11.tgz", - "integrity": "sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg==", + "version": "7.13.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.9.tgz", + "integrity": "sha512-nEUfRiARCcaVo3ny3ZQjURjHQZUo/JkEw7rLlSZy/psWGnvwXFtPcr6jb7Yb41DVW5LTe6KRq9LGleRNsg1Frw==", "dev": true }, "@babel/runtime": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.5.tgz", - "integrity": "sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==", + "version": "7.13.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.9.tgz", + "integrity": "sha512-aY2kU+xgJ3dJ1eU6FMB9EH8dIe8dmusF1xEku52joLvw6eAFN0AI+WxCLDnpev2LEejWBAy2sBvBOBAjI3zmvA==", "dev": true, "requires": { "regenerator-runtime": "^0.13.4" } }, "@babel/runtime-corejs3": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.12.5.tgz", - "integrity": "sha512-roGr54CsTmNPPzZoCP1AmDXuBoNao7tnSA83TXTwt+UK5QVyh1DIJnrgYRPWKCF2flqZQXwa7Yr8v7VmLzF0YQ==", + "version": "7.13.9", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.13.9.tgz", + "integrity": "sha512-p6WSr71+5u/VBf1KDS/Y4dK3ZwbV+DD6wQO3X2EbUVluEOiyXUk09DzcwSaUH4WomYXrEPC+i2rqzuthhZhOJw==", "dev": true, "requires": { "core-js-pure": "^3.0.0", @@ -278,28 +346,28 @@ } }, "@babel/template": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.7.tgz", - "integrity": "sha512-GkDzmHS6GV7ZeXfJZ0tLRBhZcMcY0/Lnb+eEbXDBfCAcZCjrZKe6p3J4we/D24O9Y8enxWAg1cWwof59yLh2ow==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", + "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", "dev": true, "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/parser": "^7.12.7", - "@babel/types": "^7.12.7" + "@babel/code-frame": "^7.12.13", + "@babel/parser": "^7.12.13", + "@babel/types": "^7.12.13" } }, "@babel/traverse": { - "version": "7.12.12", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.12.tgz", - "integrity": "sha512-s88i0X0lPy45RrLM8b9mz8RPH5FqO9G9p7ti59cToE44xFm1Q+Pjh5Gq4SXBbtb88X7Uy7pexeqRIQDDMNkL0w==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.0.tgz", + "integrity": "sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ==", "dev": true, "requires": { - "@babel/code-frame": "^7.12.11", - "@babel/generator": "^7.12.11", - "@babel/helper-function-name": "^7.12.11", - "@babel/helper-split-export-declaration": "^7.12.11", - "@babel/parser": "^7.12.11", - "@babel/types": "^7.12.12", + "@babel/code-frame": "^7.12.13", + "@babel/generator": "^7.13.0", + "@babel/helper-function-name": "^7.12.13", + "@babel/helper-split-export-declaration": "^7.12.13", + "@babel/parser": "^7.13.0", + "@babel/types": "^7.13.0", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.19" @@ -314,9 +382,9 @@ } }, "@babel/types": { - "version": "7.12.12", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.12.tgz", - "integrity": "sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", + "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.12.11", @@ -342,9 +410,9 @@ } }, "@eslint/eslintrc": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.3.0.tgz", - "integrity": "sha512-1JTKgrOKAHVivSvOYw+sJOunkBjUOvjqWk1DPja7ZFhIS2mX/4EgTT8M7eTK9jrKhL/FvXXEbQwIs3pg1xp3dg==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz", + "integrity": "sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog==", "dev": true, "requires": { "ajv": "^6.12.4", @@ -354,7 +422,6 @@ "ignore": "^4.0.6", "import-fresh": "^3.2.1", "js-yaml": "^3.13.1", - "lodash": "^4.17.20", "minimatch": "^3.0.4", "strip-json-comments": "^3.1.1" }, @@ -390,12 +457,20 @@ "get-package-type": "^0.1.0", "js-yaml": "^3.13.1", "resolve-from": "^5.0.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + } } }, "@istanbuljs/schema": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", - "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true }, "@nodelib/fs.scandir": { @@ -425,18 +500,18 @@ } }, "@octokit/auth-token": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.4.tgz", - "integrity": "sha512-LNfGu3Ro9uFAYh10MUZVaT7X2CnNm2C8IDQmabx+3DygYIQjs9FwzFAHN/0t6mu5HEPhxcb1XOuxdpY82vCg2Q==", + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.5.tgz", + "integrity": "sha512-BpGYsPgJt05M7/L/5FoE1PiAbdxXFZkX/3kDYcsvd1v6UhlnE5e96dTDr0ezX/EFwciQxf3cNV0loipsURU+WA==", "dev": true, "requires": { - "@octokit/types": "^6.0.0" + "@octokit/types": "^6.0.3" } }, "@octokit/core": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.2.4.tgz", - "integrity": "sha512-d9dTsqdePBqOn7aGkyRFe7pQpCXdibSJ5SFnrTr0axevObZrpz3qkWm7t/NjYv5a66z6vhfteriaq4FRz3e0Qg==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.2.5.tgz", + "integrity": "sha512-+DCtPykGnvXKWWQI0E1XD+CCeWSBhB6kwItXqfFmNBlIlhczuDPbg+P6BtLnVBaRJDAjv+1mrUJuRsFSjktopg==", "dev": true, "requires": { "@octokit/auth-token": "^2.4.4", @@ -448,78 +523,67 @@ } }, "@octokit/endpoint": { - "version": "6.0.10", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.10.tgz", - "integrity": "sha512-9+Xef8nT7OKZglfkOMm7IL6VwxXUQyR7DUSU0LH/F7VNqs8vyd7es5pTfz9E7DwUIx7R3pGscxu1EBhYljyu7Q==", + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.11.tgz", + "integrity": "sha512-fUIPpx+pZyoLW4GCs3yMnlj2LfoXTWDUVPTC4V3MUEKZm48W+XYpeWSZCv+vYF1ZABUm2CqnDVf1sFtIYrj7KQ==", "dev": true, "requires": { - "@octokit/types": "^6.0.0", + "@octokit/types": "^6.0.3", "is-plain-object": "^5.0.0", "universal-user-agent": "^6.0.0" } }, "@octokit/graphql": { - "version": "4.5.8", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.5.8.tgz", - "integrity": "sha512-WnCtNXWOrupfPJgXe+vSmprZJUr0VIu14G58PMlkWGj3cH+KLZEfKMmbUQ6C3Wwx6fdhzVW1CD5RTnBdUHxhhA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.6.0.tgz", + "integrity": "sha512-CJ6n7izLFXLvPZaWzCQDjU/RP+vHiZmWdOunaCS87v+2jxMsW9FB5ktfIxybRBxZjxuJGRnxk7xJecWTVxFUYQ==", "dev": true, "requires": { "@octokit/request": "^5.3.0", - "@octokit/types": "^6.0.0", + "@octokit/types": "^6.0.3", "universal-user-agent": "^6.0.0" } }, "@octokit/openapi-types": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-2.2.0.tgz", - "integrity": "sha512-274lNUDonw10kT8wHg8fCcUc1ZjZHbWv0/TbAwb0ojhBQqZYc1cQ/4yqTVTtPMDeZ//g7xVEYe/s3vURkRghPg==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-5.2.1.tgz", + "integrity": "sha512-Bf7MBvQ1nMpv15ANaQtRBsC7YnwQFPM0eUztp3luQs9L6sBEiQ6ArM1Wx5CG+N7tXETtd0oE0DMcU4wbLlCZIw==", "dev": true }, "@octokit/plugin-paginate-rest": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.7.0.tgz", - "integrity": "sha512-+zARyncLjt9b0FjqPAbJo4ss7HOlBi1nprq+cPlw5vu2+qjy7WvlXhtXFdRHQbSL1Pt+bfAKaLADEkkvg8sP8w==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.11.0.tgz", + "integrity": "sha512-7L9xQank2G3r1dGqrVPo1z62V5utbykOUzlmNHPz87Pww/JpZQ9KyG5CHtUzgmB4n5iDRKYNK/86A8D98HP0yA==", "dev": true, "requires": { - "@octokit/types": "^6.0.1" + "@octokit/types": "^6.11.0" } }, "@octokit/plugin-request-log": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.2.tgz", - "integrity": "sha512-oTJSNAmBqyDR41uSMunLQKMX0jmEXbwD1fpz8FG27lScV3RhtGfBa1/BBLym+PxcC16IBlF7KH9vP1BUYxA+Eg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.3.tgz", + "integrity": "sha512-4RFU4li238jMJAzLgAwkBAw+4Loile5haQMQr+uhFq27BmyJXcXSKvoQKqh0agsZEiUlW6iSv3FAgvmGkur7OQ==", "dev": true }, "@octokit/plugin-rest-endpoint-methods": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-4.2.1.tgz", - "integrity": "sha512-QyFr4Bv807Pt1DXZOC5a7L5aFdrwz71UHTYoHVajYV5hsqffWm8FUl9+O7nxRu5PDMtB/IKrhFqTmdBTK5cx+A==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-4.12.0.tgz", + "integrity": "sha512-RgnQ1aoetdOJjZYC37LV5FNlL7GY/v1CdC5dur1Zp/UiADJlbRFbAz/xLx26ovXw67dK7EUtwCghS+6QyiI9RA==", "dev": true, "requires": { - "@octokit/types": "^5.5.0", + "@octokit/types": "^6.10.0", "deprecation": "^2.3.1" - }, - "dependencies": { - "@octokit/types": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-5.5.0.tgz", - "integrity": "sha512-UZ1pErDue6bZNjYOotCNveTXArOMZQFG6hKJfOnGnulVCMcVVi7YIIuuR4WfBhjo7zgpmzn/BkPDnUXtNx+PcQ==", - "dev": true, - "requires": { - "@types/node": ">= 8" - } - } } }, "@octokit/request": { - "version": "5.4.12", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.12.tgz", - "integrity": "sha512-MvWYdxengUWTGFpfpefBBpVmmEYfkwMoxonIB3sUGp5rhdgwjXL1ejo6JbgzG/QD9B/NYt/9cJX1pxXeSIUCkg==", + "version": "5.4.14", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.14.tgz", + "integrity": "sha512-VkmtacOIQp9daSnBmDI92xNIeLuSRDOIuplp/CJomkvzt7M18NXgG044Cx/LFKLgjKt9T2tZR6AtJayba9GTSA==", "dev": true, "requires": { "@octokit/endpoint": "^6.0.1", "@octokit/request-error": "^2.0.0", - "@octokit/types": "^6.0.3", + "@octokit/types": "^6.7.1", "deprecation": "^2.0.0", "is-plain-object": "^5.0.0", "node-fetch": "^2.6.1", @@ -528,36 +592,35 @@ } }, "@octokit/request-error": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.0.4.tgz", - "integrity": "sha512-LjkSiTbsxIErBiRh5wSZvpZqT4t0/c9+4dOe0PII+6jXR+oj/h66s7E4a/MghV7iT8W9ffoQ5Skoxzs96+gBPA==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.0.5.tgz", + "integrity": "sha512-T/2wcCFyM7SkXzNoyVNWjyVlUwBvW3igM3Btr/eKYiPmucXTtkxt2RBsf6gn3LTzaLSLTQtNmvg+dGsOxQrjZg==", "dev": true, "requires": { - "@octokit/types": "^6.0.0", + "@octokit/types": "^6.0.3", "deprecation": "^2.0.0", "once": "^1.4.0" } }, "@octokit/rest": { - "version": "18.0.9", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.0.9.tgz", - "integrity": "sha512-CC5+cIx974Ygx9lQNfUn7/oXDQ9kqGiKUC6j1A9bAVZZ7aoTF8K6yxu0pQhQrLBwSl92J6Z3iVDhGhGFgISCZg==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.2.0.tgz", + "integrity": "sha512-xsp6bIqL2sb/NmgLXTxw96caegobRw+YHnzdIi70ruquHtPPDW2cBAONhDYMUuAOeXx0JH2auOeplpk4SQJy1w==", "dev": true, "requires": { - "@octokit/core": "^3.0.0", - "@octokit/plugin-paginate-rest": "^2.2.0", - "@octokit/plugin-request-log": "^1.0.0", - "@octokit/plugin-rest-endpoint-methods": "4.2.1" + "@octokit/core": "^3.2.3", + "@octokit/plugin-paginate-rest": "^2.6.2", + "@octokit/plugin-request-log": "^1.0.2", + "@octokit/plugin-rest-endpoint-methods": "4.12.0" } }, "@octokit/types": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.2.1.tgz", - "integrity": "sha512-jHs9OECOiZxuEzxMZcXmqrEO8GYraHF+UzNVH2ACYh8e/Y7YoT+hUf9ldvVd6zIvWv4p3NdxbQ0xx3ku5BnSiA==", + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.11.1.tgz", + "integrity": "sha512-UiSRTG2lrFbMUMwhKNR0uSV33Fzv4bNu1n5iFuuNOg80XCh0VYNhR4TQWgrkLhVxdDuej6s61aP3eQvVm6K6uA==", "dev": true, "requires": { - "@octokit/openapi-types": "^2.2.0", - "@types/node": ">= 8" + "@octokit/openapi-types": "^5.2.1" } }, "@sindresorhus/is": { @@ -609,9 +672,9 @@ } }, "@types/node": { - "version": "14.14.20", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.20.tgz", - "integrity": "sha512-Y93R97Ouif9JEOWPIUyU+eyIdyRqQR0I8Ez1dzku4hDx34NWh4HbtIc3WNzwB1Y9ULvNGeu5B8h8bVL5cAk4/A==", + "version": "14.14.31", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.31.tgz", + "integrity": "sha512-vFHy/ezP5qI0rFgJ7aQnjDXwAMrG0KqqIH7tQG5PPv3BWBayOPIQNBjVc/P6hhdZfMx51REc6tfDNXHUio893g==", "dev": true }, "@types/normalize-package-data": { @@ -636,17 +699,17 @@ } }, "@uttori/event-dispatcher": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@uttori/event-dispatcher/-/event-dispatcher-1.0.4.tgz", - "integrity": "sha512-/JyMbdBXDcGOv7aQj1Gh0pxl+t38zhHUwdKKBKMmSsvya8osNbz7Q6QlgSpREJVFPDILSBhn3IO+PzCJ400l0g==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@uttori/event-dispatcher/-/event-dispatcher-2.0.0.tgz", + "integrity": "sha512-PVR+v2Zxm+5dYZhKI+OgP+kFMdFPS9Ey4b2SWGORwATUP9bbVXxZcyCGZDXWNkjYSPCBRp2mg7rFAh2YkcBWZw==", "requires": { "debug": "^4.3.1" } }, "acorn": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.0.4.tgz", - "integrity": "sha512-XNP0PqF1XD19ZlLKvB7cMmnZswW4C/03pRHgirB30uSJTaS3A3V1/P4sS3HPvFmjoriPCJQs+JDSbm4bL1TxGQ==", + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.0.5.tgz", + "integrity": "sha512-v+DieK/HJkJOpFBETDJioequtc3PfxsWMaxIdIwujtF7FEV/MAyDQLlm6/zPvr7Mix07mLh6ccVwIsloceodlg==", "dev": true }, "acorn-jsx": { @@ -656,9 +719,9 @@ "dev": true }, "acorn-walk": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.0.1.tgz", - "integrity": "sha512-zn/7dYtoTVkG4EoMU55QlQU4F+m+T7Kren6Vj3C2DapWPnakG/DL9Ns5aPAPW5Ixd3uxXrV/BoMKKVFIazPcdg==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.0.2.tgz", + "integrity": "sha512-+bpA9MJsHdZ4bgfDcpk0ozQyhhVct7rzOmO0s1IIr0AGGgKBljss8n2zp11rRP2wid5VGeh04CgeKzgat5/25A==", "dev": true }, "aggregate-error": { @@ -779,9 +842,9 @@ "dev": true }, "ansi-styles": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.0.0.tgz", - "integrity": "sha512-6564t0m0fuQMnockqBv7wJxo9T5C2V9JpYXyNScfRDPVLusOQQhkpMGrFC17QbiolraQ1sMXX+Y5nJpjqozL4g==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.1.0.tgz", + "integrity": "sha512-osxifZo3ar56+e8tdYreU6p8FZGciBHo5O0JoDAxMUqZuyNUb+yHEwYtJZ+Z32R459jEgtwVf1u8D7qYwU0l6w==", "dev": true }, "anymatch": { @@ -829,9 +892,9 @@ } }, "array-back": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.1.tgz", - "integrity": "sha512-Z/JnaVEXv+A9xabHzN43FiiiWEE7gPCRXMrVmRm00tWbjZRul1iHm7ECzlyNq1p4a4ATXz+G9FJ3GqGOkOV3fg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-5.0.0.tgz", + "integrity": "sha512-kgVWwJReZWmVuWOQKEOohXKJX+nD02JAZ54D1RRWlv8L0NebauKAaFxACKzB74RTclt1+WNz5KHaLRDAPZbDEw==", "dev": true }, "array-find-index": { @@ -841,15 +904,15 @@ "dev": true }, "array-includes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.2.tgz", - "integrity": "sha512-w2GspexNQpx+PutG3QpT437/BenZBj0M/MZGn5mzv/MofYqo0xmRHzn4lFsoDlWJ+THYsGJmFlW68WlDFx7VRw==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz", + "integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==", "dev": true, "requires": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "get-intrinsic": "^1.0.1", + "es-abstract": "^1.18.0-next.2", + "get-intrinsic": "^1.1.1", "is-string": "^1.0.5" } }, @@ -1032,9 +1095,9 @@ "dev": true }, "axe-core": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.1.1.tgz", - "integrity": "sha512-5Kgy8Cz6LPC9DJcNb3yjAXTu3XihQgEdnIg50c//zOC/MyLP0Clg+Y8Sh9ZjjnvBrDZU4DgXS9C3T9r4/scGZQ==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.1.2.tgz", + "integrity": "sha512-V+Nq70NxKhYt89ArVcaNL9FDryB3vQOd+BFXZIfO3RP6rwtj+2yqqqdHEkacutglPaZLkJeuXKCjCJDMGPtPqg==", "dev": true }, "axobject-query": { @@ -1043,28 +1106,6 @@ "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==", "dev": true }, - "babel-eslint": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", - "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.7.0", - "@babel/traverse": "^7.7.0", - "@babel/types": "^7.7.0", - "eslint-visitor-keys": "^1.0.0", - "resolve": "^1.12.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } - } - }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -1087,9 +1128,9 @@ } }, "before-after-hook": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.1.0.tgz", - "integrity": "sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.1.1.tgz", + "integrity": "sha512-5ekuQOvO04MDj7kYZJaMab2S8SPjGJbotVNyv7QYFCOAwrGZs/YnoDNlh1U+m5hl7H2D/+n0taaAV/tfyd3KMA==", "dev": true }, "binary-extensions": { @@ -1099,9 +1140,9 @@ "dev": true }, "bl": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.3.tgz", - "integrity": "sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dev": true, "requires": { "buffer": "^5.5.0", @@ -1122,44 +1163,25 @@ "dev": true }, "boxen": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", - "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.0.0.tgz", + "integrity": "sha512-5bvsqw+hhgUi3oYGK0Vf4WpIkyemp60WBInn7+WNfoISzAqk/HX4L7WNROq38E6UR/y3YADpv6pEm4BfkeEAdA==", "dev": true, "requires": { "ansi-align": "^3.0.0", - "camelcase": "^5.3.1", - "chalk": "^3.0.0", - "cli-boxes": "^2.2.0", - "string-width": "^4.1.0", - "term-size": "^2.1.0", - "type-fest": "^0.8.1", - "widest-line": "^3.1.0" + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.0", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true } } @@ -1183,6 +1205,19 @@ "fill-range": "^7.0.1" } }, + "browserslist": { + "version": "4.16.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.3.tgz", + "integrity": "sha512-vIyhWmIkULaq04Gt93txdh+j02yX/JzlyhLYbV3YQCn/zvES3JnY7TifHHvvr1w5hTDluNKMkV05cs4vy8Q7sw==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001181", + "colorette": "^1.2.1", + "electron-to-chromium": "^1.3.649", + "escalade": "^3.1.1", + "node-releases": "^1.1.70" + } + }, "buf-compare": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buf-compare/-/buf-compare-1.0.1.tgz", @@ -1214,6 +1249,14 @@ "array-back": "^4.0.1", "fs-then-native": "^2.0.0", "mkdirp2": "^1.0.4" + }, + "dependencies": { + "array-back": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.1.tgz", + "integrity": "sha512-Z/JnaVEXv+A9xabHzN43FiiiWEE7gPCRXMrVmRm00tWbjZRul1iHm7ECzlyNq1p4a4ATXz+G9FJ3GqGOkOV3fg==", + "dev": true + } } }, "cacheable-lookup": { @@ -1283,9 +1326,15 @@ "dev": true }, "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001192", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001192.tgz", + "integrity": "sha512-63OrUnwJj5T1rUmoyqYTdRWBqFFxZFlyZnRRjDR8NSUQFB6A+j/uBORU/SyJ5WzDLg4SPiZH40hQCBNdZ/jmAw==", "dev": true }, "caseless": { @@ -1331,9 +1380,9 @@ "dev": true }, "chokidar": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.0.tgz", - "integrity": "sha512-JgQM9JS92ZbFR4P90EvmzNpSGhpPBGBSj10PILeDyYFwp4h2/D9OM03wsJ4zW1fEp4ka2DGrnUeD7FuvQ2aZ2Q==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", + "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", "dev": true, "requires": { "anymatch": "~3.1.1", @@ -1494,6 +1543,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "colorette": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", + "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", + "dev": true + }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -1577,9 +1632,9 @@ } }, "comment-parser": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.0.1.tgz", - "integrity": "sha512-korDJ16mBVZexVd485jz4AeAcAFP1UzeecfVgfBCBojLFjMEHEHOY9vgk3e9o1zRSP0EscavonLki4JZDCKmrg==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.1.2.tgz", + "integrity": "sha512-AOdq0i8ghZudnYv8RUnHrhTgafUGs61Rdz9jemU5x2lnZwAWyOq7vySo626K59e1fVKH1xSRorJwPVRLSWOoAQ==", "dev": true }, "common-path-prefix": { @@ -1645,9 +1700,9 @@ } }, "concordance": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/concordance/-/concordance-5.0.1.tgz", - "integrity": "sha512-TbNtInKVElgEBnJ1v2Xg+MFX2lvFLbmlv3EuSC5wTfCwpB8kC3w3mffF6cKuUhkn475Ym1f1I4qmuXzx2+uXpw==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/concordance/-/concordance-5.0.2.tgz", + "integrity": "sha512-hC63FKdGM9tBcd4VQIa+LQjmrgorrnxESb8B3J21Qe/FzL0blBv0pb8iNyymt+bmsvGSUqO0uhPi2ZSLgLtLdg==", "dev": true, "requires": { "date-time": "^3.1.0", @@ -1764,9 +1819,9 @@ } }, "core-js-pure": { - "version": "3.8.2", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.8.2.tgz", - "integrity": "sha512-v6zfIQqL/pzTVAbZvYUozsxNfxcFb6Ks3ZfEbuneJl3FW9Jb8F6vLWB6f+qTmAu72msUdyb84V8d/yBFf7FNnw==", + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.9.1.tgz", + "integrity": "sha512-laz3Zx0avrw9a4QEIdmIblnVuJz8W51leY9iLThatCsFawWxC3sE4guASC78JbCin+DkwMpCdp1AVAuzL/GN7A==", "dev": true }, "core-util-is": { @@ -1789,9 +1844,9 @@ }, "dependencies": { "parse-json": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", - "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -2044,25 +2099,31 @@ } }, "dmd": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/dmd/-/dmd-5.0.2.tgz", - "integrity": "sha512-npXsE2+/onRPk/LCrUmx7PcUSqcSVnbrDDMi2nBSawNZ8QXlHE/8xaEZ6pNqPD1lQZv8LGr1xEIpyxP336xyfw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/dmd/-/dmd-6.0.0.tgz", + "integrity": "sha512-PwWZlqZnJPETwqZZ70haRa+UDZcD5jeBD3ywW1Kf+jYYv0MHu/S7Ri9jsSoeTMwkcMVW9hXOMA1IZUMEufBhOg==", "dev": true, "requires": { - "array-back": "^4.0.1", + "array-back": "^5.0.0", "cache-point": "^2.0.0", "common-sequence": "^2.0.0", "file-set": "^4.0.1", - "handlebars": "^4.7.6", - "marked": "^1.1.0", + "handlebars": "^4.7.7", + "marked": "^2.0.0", "object-get": "^2.1.1", "reduce-flatten": "^3.0.0", "reduce-unique": "^2.0.1", "reduce-without": "^1.0.1", "test-value": "^3.0.0", - "walk-back": "^4.0.0" + "walk-back": "^5.0.0" }, "dependencies": { + "marked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/marked/-/marked-2.0.1.tgz", + "integrity": "sha512-5+/fKgMv2hARmMW7DOpykr2iLhl0NgjyELk5yn92iE7z8Se1IS9n3UsFm86hFXIkvMBmVxki8+ckcpjBeyo/hw==", + "dev": true + }, "reduce-flatten": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-3.0.0.tgz", @@ -2072,16 +2133,16 @@ } }, "docsify": { - "version": "4.11.6", - "resolved": "https://registry.npmjs.org/docsify/-/docsify-4.11.6.tgz", - "integrity": "sha512-6h3hB2Ni7gpOeu1fl1sDOmufuplIDmeFHsps17Qbg9VOS3h2tJ63FiW2w5oAydGyzaLrqu58FV7Mg4b6p0z9mg==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/docsify/-/docsify-4.12.0.tgz", + "integrity": "sha512-oLr48dLeJ8sTVQfL8HLFqd2sPPG8DNAOvYAXXJQr/+/K9uC2KDhoeu+GGj5U2uFGR5czF3oLvqNBxhEElg1wGw==", "dev": true, "requires": { - "dompurify": "^2.0.8", - "marked": "^1.1.1", + "dompurify": "^2.2.6", + "marked": "^1.2.9", "medium-zoom": "^1.0.6", "opencollective-postinstall": "^2.0.2", - "prismjs": "^1.19.0", + "prismjs": "^1.23.0", "strip-indent": "^3.0.0", "tinydate": "^1.3.0", "tweezer.js": "^1.4.0" @@ -2126,6 +2187,79 @@ "color-convert": "^1.9.0" } }, + "boxen": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", + "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", + "dev": true, + "requires": { + "ansi-align": "^3.0.0", + "camelcase": "^5.3.1", + "chalk": "^3.0.0", + "cli-boxes": "^2.2.0", + "string-width": "^4.1.0", + "term-size": "^2.1.0", + "type-fest": "^0.8.1", + "widest-line": "^3.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -2146,6 +2280,19 @@ "string-width": "^3.1.0", "strip-ansi": "^5.2.0", "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } } }, "color-convert": { @@ -2189,18 +2336,43 @@ "universalify": "^0.1.0" } }, + "global-dirs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.1.0.tgz", + "integrity": "sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==", + "dev": true, + "requires": { + "ini": "1.3.7" + } + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, + "ini": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz", + "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==", + "dev": true + }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, + "is-installed-globally": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", + "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", + "dev": true, + "requires": { + "global-dirs": "^2.0.1", + "is-path-inside": "^3.0.1" + } + }, "is-npm": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", @@ -2250,17 +2422,6 @@ "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", "dev": true }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -2279,6 +2440,12 @@ "has-flag": "^3.0.0" } }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -2366,6 +2533,19 @@ "ansi-styles": "^3.2.0", "string-width": "^3.0.0", "strip-ansi": "^5.0.0" + }, + "dependencies": { + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } } }, "y18n": { @@ -2397,6 +2577,19 @@ "which-module": "^2.0.0", "y18n": "^4.0.0", "yargs-parser": "^15.0.1" + }, + "dependencies": { + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } } }, "yargs-parser": { @@ -2412,16 +2605,27 @@ } }, "docsify-server-renderer": { - "version": "4.11.6", - "resolved": "https://registry.npmjs.org/docsify-server-renderer/-/docsify-server-renderer-4.11.6.tgz", - "integrity": "sha512-IAEM+kKsDfo1qnrEdaBH5pCQFjAWA7B7jWWmfCKzDA/BPcHO+zCR4++Mw/NPR/huJKU58AzuGtEJ/NhF/l0Y6Q==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/docsify-server-renderer/-/docsify-server-renderer-4.12.0.tgz", + "integrity": "sha512-0uTh+yFggwubJGx7y6XjorWqwMmL0iZVAZiHslMakmdqitQDQzoWR38MpPTrpx3hRAnQ3rniSuk+fFtDuOXDrg==", "dev": true, "requires": { - "debug": "^4.1.1", - "docsify": "^4.11.4", - "dompurify": "^2.0.8", + "debug": "^4.3.2", + "docsify": "^4.11.6", + "dompurify": "^2.2.6", "node-fetch": "^2.6.0", "resolve-pathname": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + } } }, "doctrine": { @@ -2470,6 +2674,12 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", "dev": true }, + "electron-to-chromium": { + "version": "1.3.676", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.676.tgz", + "integrity": "sha512-t0eEgYCP+XEbH/KwxWYZDY0XKwzmokDAsjFJ2rBstp2XuwuBCUZ+ni5qXI6XDRNkvDpVJcAOp2aJxkSkshKkmw==", + "dev": true + }, "emittery": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", @@ -2537,23 +2747,25 @@ } }, "es-abstract": { - "version": "1.18.0-next.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", - "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", + "version": "1.18.0-next.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.2.tgz", + "integrity": "sha512-Ih4ZMFHEtZupnUh6497zEL4y2+w8+1ljnCyaTa+adcoafI1GOvMwFlDjBLfWR7y9VLfrjRJe9ocuHY1PSR9jjw==", "dev": true, "requires": { + "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2", "has": "^1.0.3", "has-symbols": "^1.0.1", "is-callable": "^1.2.2", - "is-negative-zero": "^2.0.0", + "is-negative-zero": "^2.0.1", "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", + "object-inspect": "^1.9.0", "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.3", + "string.prototype.trimstart": "^1.0.3" } }, "es-to-primitive": { @@ -2598,13 +2810,13 @@ "dev": true }, "eslint": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.18.0.tgz", - "integrity": "sha512-fbgTiE8BfUJZuBeq2Yi7J3RB3WGUQ9PNuNbmgi6jt9Iv8qrkxfy19Ds3OpL1Pm7zg3BtTVhvcUZbIRQ0wmSjAQ==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.21.0.tgz", + "integrity": "sha512-W2aJbXpMNofUp0ztQaF40fveSsJBjlSCSWpy//gzfTvwC+USs/nceBrKmlJOiM8r1bLwP2EuYkCqArn/6QTIgg==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@eslint/eslintrc": "^0.3.0", + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.0", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -2615,9 +2827,9 @@ "eslint-utils": "^2.1.0", "eslint-visitor-keys": "^2.0.0", "espree": "^7.3.1", - "esquery": "^1.2.0", + "esquery": "^1.4.0", "esutils": "^2.0.2", - "file-entry-cache": "^6.0.0", + "file-entry-cache": "^6.0.1", "functional-red-black-tree": "^1.0.1", "glob-parent": "^5.0.0", "globals": "^12.1.0", @@ -2642,6 +2854,15 @@ "v8-compile-cache": "^2.0.3" }, "dependencies": { + "@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", @@ -2656,16 +2877,6 @@ } } }, - "eslint-ast-utils": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/eslint-ast-utils/-/eslint-ast-utils-1.1.0.tgz", - "integrity": "sha512-otzzTim2/1+lVrlH19EfQQJEhVJSu0zOb9ygb3iapN6UlyaDtyRq4b5U1FuW0v1lRa9Fp/GJyHkSwm6NqABgCA==", - "dev": true, - "requires": { - "lodash.get": "^4.4.2", - "lodash.zip": "^4.2.0" - } - }, "eslint-config-airbnb": { "version": "18.2.1", "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-18.2.1.tgz", @@ -2876,12 +3087,12 @@ } }, "eslint-plugin-jsdoc": { - "version": "31.0.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-31.0.5.tgz", - "integrity": "sha512-TiBVItHnBAtSAY4YfYq0PBIfcCqmInYpK7ziCgCQgBUdRT30JtIqZ6TLrH5kF237fpfSdFUFYCVkdlc+MZPd0g==", + "version": "32.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-32.2.0.tgz", + "integrity": "sha512-ikeVeF3JVmzjcmGd04OZK0rXjgiw46TWtNX+OhyF2jQlw3w1CAU1vyAyLv8PZcIjp7WxP4N20Vg1CI9bp/52dw==", "dev": true, "requires": { - "comment-parser": "1.0.1", + "comment-parser": "1.1.2", "debug": "^4.3.1", "jsdoctypeparser": "^9.0.0", "lodash": "^4.17.20", @@ -2910,9 +3121,9 @@ }, "dependencies": { "emoji-regex": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.0.tgz", - "integrity": "sha512-DNc3KFPK18bPdElMJnf/Pkv5TXhxFU3YFDEuGLDRtPmV4rkmCjBkCSEp22u6rBHdSN9Vlp/GK7k98prmE1Jgug==", + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.1.tgz", + "integrity": "sha512-117l1H6U4X3Krn+MrzYrL57d5H7siRHWraBs7s+LjRuFK7Fe7hJqnJ0skWlinqsycVLU5YAo6L8CsEYQ0V5prg==", "dev": true } } @@ -3019,27 +3230,27 @@ } }, "eslint-plugin-sonarjs": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-0.5.0.tgz", - "integrity": "sha512-XW5MnzlRjhXpIdbULC/qAdJYHWw3rRLws/DyawdlPU/IdVr9AmRK1r2LaCvabwKOAW2XYYSo3kDX58E4MrB7PQ==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-0.6.0.tgz", + "integrity": "sha512-y+sXXWsYVW2kNEjmZI87laFspwC/hic7wyMjsPFoST8aQ2hESUVavkZjnTeVdHMOmlmcloKkyX/GJJetmfBY4Q==", "dev": true }, "eslint-plugin-unicorn": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-26.0.1.tgz", - "integrity": "sha512-SWgF9sIVY74zqkkSN2dclSCqRfocWSUGD0haC0NX2oRfmdp9p8dQvJYkYSQePaCyssPUE/pqpsIEEZNTh8crUA==", + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-28.0.2.tgz", + "integrity": "sha512-k4AoFP7n8/oq6lBXkdc9Flid6vw2B8j7aXFCxgzJCyKvmaKrCUFb1TFPhG9eSJQFZowqmymMPRtl8oo9NKLUbw==", "dev": true, "requires": { "ci-info": "^2.0.0", "clean-regexp": "^1.0.0", - "eslint-ast-utils": "^1.1.0", "eslint-template-visitor": "^2.2.2", "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", "import-modules": "^2.1.0", "lodash": "^4.17.20", "pluralize": "^8.0.0", "read-pkg-up": "^7.0.1", - "regexp-tree": "^0.1.21", + "regexp-tree": "^0.1.22", "reserved-words": "^0.1.2", "safe-regex": "^2.1.1", "semver": "^7.3.4" @@ -3093,12 +3304,13 @@ } }, "eslint-template-visitor": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/eslint-template-visitor/-/eslint-template-visitor-2.2.2.tgz", - "integrity": "sha512-SkcLjzKw3JjKTWHacRDeLBa2gxb600zbCKTkXj/V97QnZ9yxkknoPL8vc8PFueqbFXP7mYNTQzjCjcMpTRdRaA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/eslint-template-visitor/-/eslint-template-visitor-2.3.2.tgz", + "integrity": "sha512-3ydhqFpuV7x1M9EK52BPNj6V0Kwu0KKkcIAfpUhwHbR8ocRln/oUHgfxQupY8O1h4Qv/POHDumb/BwwNfxbtnA==", "dev": true, "requires": { - "babel-eslint": "^10.1.0", + "@babel/core": "^7.12.16", + "@babel/eslint-parser": "^7.12.16", "eslint-visitor-keys": "^2.0.0", "esquery": "^1.3.1", "multimap": "^1.1.0" @@ -3165,9 +3377,9 @@ "dev": true }, "esquery": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", - "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", "dev": true, "requires": { "estraverse": "^5.1.0" @@ -3217,30 +3429,27 @@ "dev": true }, "execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.0.0.tgz", + "integrity": "sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==", "dev": true, "requires": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" }, "dependencies": { "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.0.tgz", + "integrity": "sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg==", + "dev": true } } }, @@ -3280,9 +3489,9 @@ "dev": true }, "fast-glob": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", - "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", + "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", @@ -3306,9 +3515,9 @@ "dev": true }, "fastq": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.10.0.tgz", - "integrity": "sha512-NL2Qc5L3iQEsyYzweq7qfgy5OtXCmGzGvhElGEd/SoFWEMOEczNh5s5ocaF01HDetxz+p8ecjNPA6cZxxIHmzA==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", + "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", "dev": true, "requires": { "reusify": "^1.0.4" @@ -3330,9 +3539,9 @@ } }, "file-entry-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.0.tgz", - "integrity": "sha512-fqoO76jZ3ZnYrXLDRxBR1YvOvc0k844kcOg40bgsPrE25LAb/PDqTY+ho64Xh2c8ZXgIKldchCFHczG2UVRcWA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, "requires": { "flat-cache": "^3.0.4" @@ -3346,6 +3555,14 @@ "requires": { "array-back": "^4.0.1", "glob": "^7.1.6" + }, + "dependencies": { + "array-back": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.1.tgz", + "integrity": "sha512-Z/JnaVEXv+A9xabHzN43FiiiWEE7gPCRXMrVmRm00tWbjZRul1iHm7ECzlyNq1p4a4ATXz+G9FJ3GqGOkOV3fg==", + "dev": true + } } }, "fill-range": { @@ -3357,6 +3574,12 @@ "to-regex-range": "^5.0.1" } }, + "filter-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz", + "integrity": "sha1-mzERErxsYSehbgFsbF1/GeCAXFs=", + "dev": true + }, "finalhandler": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", @@ -3444,9 +3667,9 @@ } }, "flatted": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.0.tgz", - "integrity": "sha512-tW+UkmtNg/jv9CSofAKvgVcO7c2URjhTdW1ZTkcAritblu8tajiYy7YisnIflEwtKssCtOxpnBRoCB7iap0/TA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", + "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", "dev": true }, "foreground-child": { @@ -3489,14 +3712,14 @@ "dev": true }, "fs-extra": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz", - "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "requires": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", - "universalify": "^1.0.0" + "universalify": "^2.0.0" } }, "fs-then-native": { @@ -3512,9 +3735,9 @@ "dev": true }, "fsevents": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.1.tgz", - "integrity": "sha512-YR47Eg4hChJGAB1O3yEAOkGO+rlzutoICGqGo9EZ4lKWokzZRSyIW1QmTzqjtw8MJdj9srP869CuWw/hyzSiBw==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "dev": true, "optional": true }, @@ -3543,9 +3766,9 @@ "dev": true }, "get-intrinsic": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.2.tgz", - "integrity": "sha512-aeX0vrFm21ILl3+JpFFRNe9aUvp6VFZb2/CTbgLb8j75kOhvoNYjt9d8KA/tJG4gSo8nzEDedRl0h7vDmBYRVg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", "dev": true, "requires": { "function-bind": "^1.1.1", @@ -3594,9 +3817,9 @@ } }, "git-url-parse": { - "version": "11.4.0", - "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-11.4.0.tgz", - "integrity": "sha512-KlIa5jvMYLjXMQXkqpFzobsyD/V2K5DRHl5OAf+6oDFPlPLxrGDVQlIdI63c4/Kt6kai4kALENSALlzTGST3GQ==", + "version": "11.4.4", + "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-11.4.4.tgz", + "integrity": "sha512-Y4o9o7vQngQDIU9IjyCmRJBin5iYjI5u9ZITnddRZpD7dcCFQj2sL2XuMNbLRE4b4B/4ENPsp2Q8P44fjAZ0Pw==", "dev": true, "requires": { "git-up": "^4.0.0" @@ -3626,12 +3849,12 @@ } }, "global-dirs": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.1.0.tgz", - "integrity": "sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", + "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", "dev": true, "requires": { - "ini": "1.3.7" + "ini": "2.0.0" } }, "globals": { @@ -3695,14 +3918,14 @@ } }, "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==" }, "handlebars": { - "version": "4.7.6", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz", - "integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==", + "version": "4.7.7", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", + "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", "dev": true, "requires": { "minimist": "^1.2.5", @@ -3761,9 +3984,9 @@ "dev": true }, "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", "dev": true }, "has-yarn": { @@ -3833,9 +4056,9 @@ } }, "http2-wrapper": { - "version": "1.0.0-beta.5.2", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.0-beta.5.2.tgz", - "integrity": "sha512-xYz9goEyBnC8XwXDTuC/MZ6t+MrKVQZOk4s7+PaDkwIsQd8IwqvM+0M6bA/2lvG8GHXcPdf+MejTUeO2LCPCeQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", "dev": true, "requires": { "quick-lru": "^5.1.1", @@ -3843,9 +4066,9 @@ } }, "human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true }, "iconv-lite": { @@ -3962,9 +4185,9 @@ "dev": true }, "ini": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz", - "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", "dev": true }, "inquirer": { @@ -3989,35 +4212,14 @@ } }, "internal-slot": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.2.tgz", - "integrity": "sha512-2cQNfwhAfJIkU4KZPkDI+Gj5yNNnbqi40W9Gge6dfnk4TocEVm00B3bdiL+JINrbGJil2TeHvM4rETGzk/f/0g==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", "dev": true, "requires": { - "es-abstract": "^1.17.0-next.1", + "get-intrinsic": "^1.1.0", "has": "^1.0.3", - "side-channel": "^1.0.2" - }, - "dependencies": { - "es-abstract": { - "version": "1.17.7", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", - "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - } + "side-channel": "^1.0.4" } }, "interpret": { @@ -4048,9 +4250,9 @@ } }, "is-callable": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", - "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", + "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", "dev": true }, "is-ci": { @@ -4105,13 +4307,13 @@ } }, "is-installed-globally": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", - "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", "dev": true, "requires": { - "global-dirs": "^2.0.1", - "is-path-inside": "^3.0.1" + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" } }, "is-interactive": { @@ -4169,11 +4371,12 @@ "dev": true }, "is-regex": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", - "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz", + "integrity": "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==", "dev": true, "requires": { + "call-bind": "^1.0.2", "has-symbols": "^1.0.1" } }, @@ -4436,35 +4639,49 @@ "object-to-spawn-args": "^2.0.0", "temp-path": "^1.0.0", "walk-back": "^4.0.0" + }, + "dependencies": { + "array-back": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.1.tgz", + "integrity": "sha512-Z/JnaVEXv+A9xabHzN43FiiiWEE7gPCRXMrVmRm00tWbjZRul1iHm7ECzlyNq1p4a4ATXz+G9FJ3GqGOkOV3fg==", + "dev": true + }, + "walk-back": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/walk-back/-/walk-back-4.0.0.tgz", + "integrity": "sha512-kudCA8PXVQfrqv2mFTG72vDBRi8BKWxGgFLwPpzHcpZnSwZk93WMwUDVcLHWNsnm+Y0AC4Vb6MUNRgaHfyV2DQ==", + "dev": true + } } }, "jsdoc-parse": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/jsdoc-parse/-/jsdoc-parse-5.0.0.tgz", - "integrity": "sha512-Khw8c3glrTeA3/PfUJUBvhrMhWpSClORBUvL4pvq2wFcqvUVmA96wxnMkCno2GfZY4pnd8BStK5WGKGyn4Vckg==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/jsdoc-parse/-/jsdoc-parse-6.0.0.tgz", + "integrity": "sha512-35DhfCHL1bq5r0TvolhyyGhhoem700IfEvviL8I1t99Qxa3aSmWbBEpnvvouA7TyXlwxcQfSg75ryXW8Ppq7FA==", "dev": true, "requires": { - "array-back": "^4.0.1", + "array-back": "^5.0.0", "lodash.omit": "^4.5.0", "lodash.pick": "^4.4.0", "reduce-extract": "^1.0.0", - "sort-array": "^4.1.1", + "sort-array": "^4.1.3", "test-value": "^3.0.0" } }, "jsdoc-to-markdown": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/jsdoc-to-markdown/-/jsdoc-to-markdown-6.0.1.tgz", - "integrity": "sha512-hUI2PAR5n/KlmQU3mAWO9i3D7jVbhyvUHfQ6oYVBt+wnnsyxpsAuhCODY1ryLOb2U9OPJd4GIK9mL2hqy7fHDg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/jsdoc-to-markdown/-/jsdoc-to-markdown-7.0.0.tgz", + "integrity": "sha512-pcZluhsRqi+qx/BKcBfdUWBOXPk7G0aRKGkBgxemedqnqM0XfxO+SYFeouExrIsuAGGmsQ/eQk2uqynG6FM2ug==", "dev": true, "requires": { - "array-back": "^4.0.1", + "array-back": "^5.0.0", "command-line-tool": "^0.8.0", "config-master": "^3.1.0", - "dmd": "^5.0.1", + "dmd": "^6.0.0", "jsdoc-api": "^6.0.0", - "jsdoc-parse": "^5.0.0", - "walk-back": "^4.0.0" + "jsdoc-parse": "^6.0.0", + "walk-back": "^5.0.0" } }, "jsdoctypeparser": { @@ -4537,13 +4754,6 @@ "requires": { "graceful-fs": "^4.1.6", "universalify": "^2.0.0" - }, - "dependencies": { - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" - } } }, "jsprim": { @@ -4682,9 +4892,9 @@ } }, "lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, "lodash.camelcase": { @@ -4723,12 +4933,6 @@ "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=", "dev": true }, - "lodash.zip": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.zip/-/lodash.zip-4.2.0.tgz", - "integrity": "sha1-7GZi5IlkCO1KtsVCo5kLcswIACA=", - "dev": true - }, "log-driver": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", @@ -4820,9 +5024,9 @@ "dev": true }, "marked": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/marked/-/marked-1.2.7.tgz", - "integrity": "sha512-No11hFYcXr/zkBvL6qFmAp1z6BKY3zqLMHny/JN/ey+al7qwCM2+CMBL9BOgqMxZU36fz4cCWfn2poWIf7QRXA==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/marked/-/marked-1.2.9.tgz", + "integrity": "sha512-H8lIX2SvyitGX+TRdtS06m1jHMijKN/XjfH6Ooii9fvxMlh8QdqBfBDkGUpMWH2kQNrtixjzYUa3SH8ROTgRRw==", "dev": true }, "matcher": { @@ -4916,18 +5120,18 @@ "dev": true }, "mime-db": { - "version": "1.45.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.45.0.tgz", - "integrity": "sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==", + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz", + "integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==", "dev": true }, "mime-types": { - "version": "2.1.28", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.28.tgz", - "integrity": "sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==", + "version": "2.1.29", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz", + "integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==", "dev": true, "requires": { - "mime-db": "1.45.0" + "mime-db": "1.46.0" } }, "mimic-fn": { @@ -5025,6 +5229,12 @@ "process-on-spawn": "^1.0.0" } }, + "node-releases": { + "version": "1.1.71", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.71.tgz", + "integrity": "sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg==", + "dev": true + }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -5110,6 +5320,12 @@ "color-convert": "^2.0.1" } }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, "cliui": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", @@ -5239,26 +5455,26 @@ } }, "object.fromentries": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.3.tgz", - "integrity": "sha512-IDUSMXs6LOSJBWE++L0lzIbSqHl9KDCfff2x/JSEIDtEUavUnyMYC2ZGay/04Zq4UT8lvd4xNhU4/YHKibAOlw==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.4.tgz", + "integrity": "sha512-EsFBshs5RUUpQEY1D4q/m59kMfz4YJvxuNCJcv/jWwOJr34EaVnG11ZrZa0UHB3wnzV1wx8m58T4hQL8IuNXlQ==", "dev": true, "requires": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", + "es-abstract": "^1.18.0-next.2", "has": "^1.0.3" } }, "object.values": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.2.tgz", - "integrity": "sha512-MYC0jvJopr8EK6dPBiO8Nb9mvjdypOachO5REGk6MXzujbBrAisKo3HmdEI6kZDL6fC31Mwee/5YbtMebixeag==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.3.tgz", + "integrity": "sha512-nkF6PfDB9alkOUxpf1HNm/QlkeW3SReqL5WXeBLpEJJnlPSvRaDQpW3gQTksTN3fgJX4hL42RzKyOin6ff3tyw==", "dev": true, "requires": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", + "es-abstract": "^1.18.0-next.2", "has": "^1.0.3" } }, @@ -5325,9 +5541,9 @@ "dev": true }, "ora": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.2.0.tgz", - "integrity": "sha512-+wG2v8TUU8EgzPHun1k/n45pXquQ9fHnbXVetl9rRgO6kjZszGGbraF3XPTIdgeA+s1lbRjSEftAnyT0w8ZMvQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.3.0.tgz", + "integrity": "sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==", "dev": true, "requires": { "bl": "^4.0.3", @@ -5507,9 +5723,9 @@ }, "dependencies": { "qs": { - "version": "6.9.5", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.5.tgz", - "integrity": "sha512-T0SnbxGiMcB09qd3bFcPt8rufxPs7T7TjePk33r1WsJNt12/rWsK/ofKqRHQ0rY/iMGE0mVdkc6Yg9CuL/ty0Q==", + "version": "6.9.6", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz", + "integrity": "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==", "dev": true } } @@ -5834,16 +6050,23 @@ "dev": true }, "query-string": { - "version": "6.13.8", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.13.8.tgz", - "integrity": "sha512-jxJzQI2edQPE/NPUOusNjO/ZOGqr1o2OBa/3M00fU76FsLXDVbJDv/p7ng5OdQyorKrkRz1oqfwmbe5MAMePQg==", + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.14.1.tgz", + "integrity": "sha512-XDxAeVmpfu1/6IjyT/gXHOl+S0vQ9owggJ30hhWKdHAsNPOcasn5o9BW0eejZqL2e4vMjhAxoW3jVHcD6mbcYw==", "dev": true, "requires": { "decode-uri-component": "^0.2.0", + "filter-obj": "^1.1.0", "split-on-first": "^1.0.0", "strict-uri-encode": "^2.0.0" } }, + "queue-microtask": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.2.tgz", + "integrity": "sha512-dB15eXv3p2jDlbOiNLyMabYg1/sXvppd8DP2J3EOCQ0AkuSXCW2tP7mnVouVLJKgUMY6yP0kcQDVpLCN13h4Xg==", + "dev": true + }, "quick-lru": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", @@ -5871,6 +6094,14 @@ "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + } } }, "react-is": { @@ -5892,9 +6123,9 @@ }, "dependencies": { "parse-json": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", - "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -6127,40 +6358,19 @@ "dev": true }, "regexp-tree": { - "version": "0.1.21", - "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.21.tgz", - "integrity": "sha512-kUUXjX4AnqnR8KRTCrayAo9PzYMRKmVoGgaz2tBuz0MF3g1ZbGebmtW0yFHfFK9CmBjQKeYIgoL22pFLBJY7sw==", + "version": "0.1.23", + "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.23.tgz", + "integrity": "sha512-+7HWfb4Bvu8Rs2eQTUIpX9I/PlQkYOuTNbRpKLJlQpSgwSkzFYh+pUj0gtvglnOZLKB6YgnIgRuJ2/IlpL48qw==", "dev": true }, "regexp.prototype.flags": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", - "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", + "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", "dev": true, "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" - }, - "dependencies": { - "es-abstract": { - "version": "1.17.7", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", - "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - } + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" } }, "regexpp": { @@ -6194,39 +6404,39 @@ } }, "release-it": { - "version": "14.2.2", - "resolved": "https://registry.npmjs.org/release-it/-/release-it-14.2.2.tgz", - "integrity": "sha512-rnJOzDIXErrwCD9cRMtDgmOZlcLQiL0z0dVyN95G2T1FQVBQNr7AD5EiH3U+K6X7s+EVoK90lF96NXe5QuvG1A==", + "version": "14.4.1", + "resolved": "https://registry.npmjs.org/release-it/-/release-it-14.4.1.tgz", + "integrity": "sha512-fNvl2hIiTA3wKOQMu/cS07acuvibaTlvLUJmhuHarPsYJZpwX+nugb0a4PG20vlpuU5jKfnhkP8uPmvKXtRfuw==", "dev": true, "requires": { "@iarna/toml": "2.2.5", - "@octokit/rest": "18.0.9", + "@octokit/rest": "18.2.0", "async-retry": "1.3.1", "chalk": "4.1.0", "cosmiconfig": "7.0.0", "debug": "4.3.1", "deprecated-obj": "2.0.0", - "execa": "4.1.0", + "execa": "5.0.0", "find-up": "5.0.0", - "form-data": "3.0.0", - "git-url-parse": "11.4.0", - "globby": "11.0.1", - "got": "11.8.0", + "form-data": "4.0.0", + "git-url-parse": "11.4.4", + "globby": "11.0.2", + "got": "11.8.1", "import-cwd": "3.0.0", "inquirer": "7.3.3", - "is-ci": "2.0.0", + "is-ci": "3.0.0", "lodash": "4.17.20", - "mime-types": "2.1.27", - "ora": "5.1.0", + "mime-types": "2.1.29", + "ora": "5.3.0", "os-name": "4.0.0", - "parse-json": "5.1.0", - "semver": "7.3.2", + "parse-json": "5.2.0", + "semver": "7.3.4", "shelljs": "0.8.4", - "update-notifier": "5.0.1", + "update-notifier": "5.1.0", "url-join": "4.0.1", - "uuid": "8.3.1", + "uuid": "8.3.2", "yaml": "1.10.0", - "yargs-parser": "20.2.4" + "yargs-parser": "20.2.5" }, "dependencies": { "@sindresorhus/is": { @@ -6259,6 +6469,12 @@ "responselike": "^2.0.0" } }, + "ci-info": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.1.1.tgz", + "integrity": "sha512-kdRWLBIJwdsYJWYJFtAFFYxybguqeF91qpZaggjG5Nf8QKdizFG2hjqvaTXbxFIcYbSaD74KpAXv6BSm17DHEQ==", + "dev": true + }, "decompress-response": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", @@ -6269,9 +6485,9 @@ } }, "defer-to-connect": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.0.tgz", - "integrity": "sha512-bYL2d05vOSf1JEZNx5vSAtPuBMkX8K9EUutg7zlKvTqKXHt7RhWJFbmd7qakVuf13i+IkGmp6FwSsONOf6VYIg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", "dev": true }, "find-up": { @@ -6285,9 +6501,9 @@ } }, "form-data": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", - "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", "dev": true, "requires": { "asynckit": "^0.4.0", @@ -6304,24 +6520,10 @@ "pump": "^3.0.0" } }, - "globby": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", - "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - } - }, "got": { - "version": "11.8.0", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.0.tgz", - "integrity": "sha512-k9noyoIIY9EejuhaBNLyZ31D5328LeqnyPNXJQb2XlJZcKakLqN5m6O/ikhq/0lw56kUYS54fVm+D1x57YC9oQ==", + "version": "11.8.1", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.1.tgz", + "integrity": "sha512-9aYdZL+6nHmvJwHALLwKSUZ0hMwGaJGYv3hoPLPgnT8BoBXm1SjnZeky+91tfwJaDzun2s4RsBRy48IEYv2q2Q==", "dev": true, "requires": { "@sindresorhus/is": "^4.0.0", @@ -6337,6 +6539,15 @@ "responselike": "^2.0.0" } }, + "is-ci": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz", + "integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==", + "dev": true, + "requires": { + "ci-info": "^3.1.1" + } + }, "json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -6361,49 +6572,24 @@ "p-locate": "^5.0.0" } }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "dev": true + }, "lowercase-keys": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", "dev": true }, - "mime-db": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", - "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", - "dev": true - }, - "mime-types": { - "version": "2.1.27", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", - "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", - "dev": true, - "requires": { - "mime-db": "1.44.0" - } - }, "mimic-response": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", "dev": true }, - "ora": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.1.0.tgz", - "integrity": "sha512-9tXIMPvjZ7hPTbk8DFq1f7Kow/HU/pQYB60JbNq+QnGwcyhWVZaQ4hM9zQDEsPxw/muLpgiHSaumUZxCAmod/w==", - "dev": true, - "requires": { - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.4.0", - "is-interactive": "^1.0.0", - "log-symbols": "^4.0.0", - "mute-stream": "0.0.8", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - } - }, "p-cancelable": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.0.0.tgz", @@ -6429,9 +6615,9 @@ } }, "parse-json": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", - "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -6449,16 +6635,16 @@ "lowercase-keys": "^2.0.0" } }, - "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "dev": true }, - "uuid": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz", - "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==", + "yargs-parser": { + "version": "20.2.5", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.5.tgz", + "integrity": "sha512-jYRGS3zWy20NtDtK2kBgo/TlAoy5YUuhD9/LZ7z7W4j1Fdw2cqD0xEEclf8fxc8xjD6X5Qr+qQQwCEsP8iRiYg==", "dev": true } } @@ -6546,12 +6732,12 @@ "dev": true }, "resolve": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", - "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", "dev": true, "requires": { - "is-core-module": "^2.1.0", + "is-core-module": "^2.2.0", "path-parse": "^1.0.6" } }, @@ -6635,15 +6821,18 @@ "dev": true }, "run-parallel": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.10.tgz", - "integrity": "sha512-zb/1OuZ6flOlH6tQyMPUrE3x3Ulxjlo9WIVXR4yVYi4H9UXQaeIsPbLn2R3O3vQCnDKkAl2qHiuocKKX4Tz/Sw==", - "dev": true + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } }, "rxjs": { - "version": "6.6.3", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz", - "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==", + "version": "6.6.6", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.6.tgz", + "integrity": "sha512-/oTwee4N4iWzAMAL9xdGKjkEHmIwupR3oXbQjCKywF1BeFohswF3vZdogbmEF6pZkOsXTzWkrZszrWpQTByYVg==", "dev": true, "requires": { "tslib": "^1.9.0" @@ -6879,12 +7068,6 @@ "typical": "^6.0.1" }, "dependencies": { - "array-back": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-5.0.0.tgz", - "integrity": "sha512-kgVWwJReZWmVuWOQKEOohXKJX+nD02JAZ54D1RRWlv8L0NebauKAaFxACKzB74RTclt1+WNz5KHaLRDAPZbDEw==", - "dev": true - }, "typical": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/typical/-/typical-6.0.1.tgz", @@ -7050,9 +7233,9 @@ "dev": true }, "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", "dev": true, "requires": { "emoji-regex": "^8.0.0", @@ -7061,37 +7244,37 @@ } }, "string.prototype.matchall": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.3.tgz", - "integrity": "sha512-OBxYDA2ifZQ2e13cP82dWFMaCV9CGF8GzmN4fljBVw5O5wep0lu4gacm1OL6MjROoUnB8VbkWRThqkV2YFLNxw==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.4.tgz", + "integrity": "sha512-pknFIWVachNcyqRfaQSeu/FUfpvJTe4uskUSZ9Wc1RijsPuzbZ8TyYT8WCNnntCjUEqQ3vUHMAfVj2+wLAisPQ==", "dev": true, "requires": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", + "es-abstract": "^1.18.0-next.2", "has-symbols": "^1.0.1", - "internal-slot": "^1.0.2", - "regexp.prototype.flags": "^1.3.0", - "side-channel": "^1.0.3" + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.3.1", + "side-channel": "^1.0.4" } }, "string.prototype.trimend": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz", - "integrity": "sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", "dev": true, "requires": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3" } }, "string.prototype.trimstart": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz", - "integrity": "sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", "dev": true, "requires": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3" } }, @@ -7183,9 +7366,9 @@ }, "dependencies": { "ajv": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.0.3.tgz", - "integrity": "sha512-R50QRlXSxqXcQP5SvKUrw8VZeypvo12i2IX0EeR5PiZ7bEKeHWgzgo264LDadUsCU42lTJVhFikTqJwNeH34gQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.1.1.tgz", + "integrity": "sha512-ga/aqDYnUy/o7vbsRTFhhTsNeXiYb5JWDIcRIeZfwRNCefwjNTVYCGdGSUrEmiu3yDK3vFvNbgJxvrQW4JXrYQ==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -7463,9 +7646,9 @@ } }, "typescript": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz", - "integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.2.tgz", + "integrity": "sha512-tbb+NVrLfnsJy3M59lsDgrzWIflR4d4TIUjz+heUnHZwdF7YsrMTKoRERiIvI2lvBG95dfpLxB21WZhys1bgaQ==", "dev": true }, "typical": { @@ -7481,9 +7664,9 @@ "dev": true }, "uglify-js": { - "version": "3.12.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.12.4.tgz", - "integrity": "sha512-L5i5jg/SHkEqzN18gQMTWsZk3KelRsfD1wUVNqtq0kzqWQqcJjyL8yc1o8hJgRrWqrAl2mUFbhfznEIoi7zi2A==", + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.0.tgz", + "integrity": "sha512-TWYSWa9T2pPN4DIJYbU9oAjQx+5qdV5RUDxwARg8fmJZrD/V27Zj0JngW5xg1DFz42G0uDYl2XhzF6alSzD62w==", "dev": true, "optional": true }, @@ -7509,9 +7692,9 @@ "dev": true }, "universalify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", - "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" }, "unpipe": { "version": "1.0.0", @@ -7520,23 +7703,23 @@ "dev": true }, "update-notifier": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.0.1.tgz", - "integrity": "sha512-BuVpRdlwxeIOvmc32AGYvO1KVdPlsmqSh8KDDBxS6kDE5VR7R8OMP1d8MdhaVBvxl4H3551k9akXr0Y1iIB2Wg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", + "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", "dev": true, "requires": { - "boxen": "^4.2.0", + "boxen": "^5.0.0", "chalk": "^4.1.0", "configstore": "^5.0.1", "has-yarn": "^2.1.0", "import-lazy": "^2.1.0", "is-ci": "^2.0.0", - "is-installed-globally": "^0.3.2", + "is-installed-globally": "^0.4.0", "is-npm": "^5.0.0", "is-yarn-global": "^0.3.0", "latest-version": "^5.1.0", "pupa": "^2.1.1", - "semver": "^7.3.2", + "semver": "^7.3.4", "semver-diff": "^3.1.1", "xdg-basedir": "^4.0.0" } @@ -7627,9 +7810,9 @@ } }, "walk-back": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/walk-back/-/walk-back-4.0.0.tgz", - "integrity": "sha512-kudCA8PXVQfrqv2mFTG72vDBRi8BKWxGgFLwPpzHcpZnSwZk93WMwUDVcLHWNsnm+Y0AC4Vb6MUNRgaHfyV2DQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/walk-back/-/walk-back-5.0.0.tgz", + "integrity": "sha512-ASerU3aOj9ok+uMNiW0A6/SEwNOxhPmiprbHmPFw1faz7Qmoy9wD3sbmL5HYG+IBxT5c/4cX9O2kSpNv8OAM9A==", "dev": true }, "wcwidth": { @@ -7678,6 +7861,40 @@ "dev": true, "requires": { "execa": "^4.0.2" + }, + "dependencies": { + "execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + } + }, + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true + } } }, "word-wrap": { @@ -7850,9 +8067,9 @@ } }, "yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "version": "20.2.6", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.6.tgz", + "integrity": "sha512-AP1+fQIWSM/sMiET8fyayjx/J+JmTPt2Mr0FkrgqB4todtfa53sOsrSAcIrJRD5XS20bKUwaDIuMkWKCEiQLKA==", "dev": true }, "yocto-queue": { diff --git a/package.json b/package.json index 8678dd6..2ef2681 100644 --- a/package.json +++ b/package.json @@ -22,8 +22,8 @@ "node": ">= 12" }, "dependencies": { - "@uttori/event-dispatcher": "^1.0.4", - "fs-extra": "^9.0.1", + "@uttori/event-dispatcher": "^2.0.0", + "fs-extra": "^9.1.0", "ramda": "^0.27.1", "sanitize-filename": "^1.6.3", "uttori-utilities": "^2.3.0" @@ -35,11 +35,11 @@ "ava": "^3.15.0", "coveralls": "^3.1.0", "docsify-cli": "^4.4.2", - "eslint": "^7.18.0", + "eslint": "^7.21.0", "eslint-config-airbnb": "^18.2.1", "eslint-plugin-ava": "^11.0.0", "eslint-plugin-import": "^2.22.1", - "eslint-plugin-jsdoc": "^31.0.5", + "eslint-plugin-jsdoc": "^32.2.0", "eslint-plugin-jsx-a11y": "^6.4.1", "eslint-plugin-no-inferred-method-name": "^2.0.0", "eslint-plugin-node": "^11.1.0", @@ -48,15 +48,15 @@ "eslint-plugin-react": "^7.22.0", "eslint-plugin-react-hooks": "^4.2.0", "eslint-plugin-security": "^1.4.0", - "eslint-plugin-sonarjs": "^0.5.0", - "eslint-plugin-unicorn": "^26.0.1", + "eslint-plugin-sonarjs": "^0.6.0", + "eslint-plugin-unicorn": "^28.0.2", "eslint-plugin-xss": "^0.1.10", "jsdoc": "^3.6.6", - "jsdoc-to-markdown": "^6.0.1", + "jsdoc-to-markdown": "^7.0.0", "nyc": "^15.1.0", "pre-commit": "^1.2.2", - "release-it": "^14.2.2", - "typescript": "^4.1.3" + "release-it": "^14.4.1", + "typescript": "^4.2.2" }, "files": [ "esm/*", @@ -114,7 +114,7 @@ "release": "release-it", "report": "nyc report --reporter=html", "test": "NODE_ENV=test nyc ava --serial --concurrency=1", - "test-debug": "DEBUG=Uttori.StorageProvider* NODE_ENV=test ava --serial --concurrency=1", + "test-debug": "DEBUG=Uttori* NODE_ENV=test ava --serial --concurrency=1", "validate": "npm ls" }, "directories": { diff --git a/src/plugin.js b/src/plugin.js index 4fe3b37..3524687 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -1,4 +1,4 @@ -/* eslint-disable unicorn/no-fn-reference-in-iterator */ +/** @type {Function} */ let debug = () => {}; try { debug = require('debug')('Uttori.Plugin.StorageProvider.JSON'); } catch {} const StorageProvider = require('./storage-provider'); @@ -36,6 +36,9 @@ class Plugin { content_directory: '', history_directory: '', extension: 'json', + update_timestamps: true, + use_history: true, + use_cache: true, spaces_document: undefined, spaces_history: undefined, events: { @@ -94,15 +97,16 @@ class Plugin { } const storage = new StorageProvider(config); - Object.keys(config.events).forEach((method) => { - config.events[method].forEach((event) => { + const methods = Object.keys(config.events); + for (const method of methods) { + for (const event of config.events[method]) { if (typeof storage[method] !== 'function') { debug(`Missing function "${method}" for key "${event}"`); return; } context.hooks.on(event, storage[method]); - }); - }); + } + } } } diff --git a/src/query-tools.js b/src/query-tools.js index 9da1627..833a727 100644 --- a/src/query-tools.js +++ b/src/query-tools.js @@ -1,4 +1,5 @@ /* eslint-disable unicorn/no-array-callback-reference, unicorn/no-fn-reference-in-iterator, unicorn/prefer-ternary */ +/** @type {Function} */ let debug = () => {}; try { debug = require('debug')('Uttori.StorageProvider.JSON.QueryTools'); } catch {} const R = require('ramda'); const { parseQueryToRamda, validateQuery, fyShuffle } = require('uttori-utilities'); @@ -8,10 +9,12 @@ const { parseQueryToRamda, validateQuery, fyShuffle } = require('uttori-utilitie * * @param {string} query - The SQL-like query to parse. * @param {object[]} objects - An array of object to search within. - * @returns {object[]} Returns an array of all matched documents. + * @returns {object[]|number} Returns an array of all matched documents, or a count. * @example + * ```js * processQuery('SELECT name FROM table WHERE age > 1 ORDER BY RANDOM LIMIT 3', [{ ... }, ...]); * ➜ [{ ... }, ...] + * ``` */ const processQuery = (query, objects) => { debug('Processing Query:', query); @@ -42,28 +45,6 @@ const processQuery = (query, objects) => { )(filtered); } - // const sorter = R.cond([ - // [ - // R.pathEq(['sort'], 'ASC'), - // value => - // R.ascend( - // R.prop(R.path(['prop'], value)) - // ) - // ], - // [ - // R.pathEq(['sort'], 'DESC'), - // value => - // R.descend( - // R.prop(R.path(['prop'], value)) - // ) - // ], - // [ - // R.pathEq(['sort'], 'RANDOM'), - // value => R.comparator(() => Math.random() - Math.random()) - // ], - // ])({ prop: 'age', sort: 'RANDOM' }); - // R.sortWith([sorter])(docs); - // Limit if (limit > 0) { output = R.take(limit, output); diff --git a/src/storage-provider.js b/src/storage-provider.js index c5b9e64..175baa5 100644 --- a/src/storage-provider.js +++ b/src/storage-provider.js @@ -1,19 +1,15 @@ -/* eslint-disable unicorn/no-fn-reference-in-iterator */ +/** @type {Function} */ let debug = () => {}; try { debug = require('debug')('Uttori.StorageProvider.JSON'); } catch {} const fs = require('fs-extra'); const sanitize = require('sanitize-filename'); -const R = require('ramda'); const path = require('path'); -const { FileUtility } = require('uttori-utilities'); const { processQuery } = require('./query-tools'); /** * @typedef UttoriDocument The document object we store, with only the minimum methods we access listed. * @property {string} slug The unique identifier for the document. - * @property {string} [title=''] The unique identifier for the document. * @property {number|Date} [createDate] The creation date of the document. * @property {number|Date} [updateDate] The last date the document was updated. - * @property {string[]} [tags=[]] The unique identifier for the document. */ /** @@ -25,7 +21,7 @@ const { processQuery } = require('./query-tools'); * @property {string} [config.extension='json'] - The file extension to use for file, name of the employee. * @property {number} [config.spaces_document=undefined] - The spaces parameter for JSON stringifying documents. * @property {number} [config.spaces_history=undefined] - The spaces parameter for JSON stringifying history. - * @property {UttoriDocument[]} documents - The collection of documents. + * @property {object} documents - The collection of documents where the slug is the key and the value is the document. * @example Init StorageProvider * const storageProvider = new StorageProvider({ content_directory: 'content', history_directory: 'history', spaces_document: 2 }); * @class @@ -40,6 +36,7 @@ class StorageProvider { * @param {string} [config.extension=json] - The file extension to use for file, name of the employee. * @param {boolean} [config.update_timestamps=true] - Should update times be marked at the time of edit. * @param {boolean} [config.use_history=true] - Should history entries be created. + * @param {boolean} [config.use_cache=true] - Should we cache files in memory? * @param {number} [config.spaces_document=undefined] - The spaces parameter for JSON stringifying documents. * @param {number} [config.spaces_history=undefined] - The spaces parameter for JSON stringifying history. * @class @@ -61,16 +58,18 @@ class StorageProvider { this.config = { extension: 'json', - spaces_document: undefined, - spaces_history: undefined, update_timestamps: true, use_history: true, + use_cache: true, + spaces_document: undefined, + spaces_history: undefined, ...config, }; - this.documents = []; - FileUtility.ensureDirectorySync(this.config.content_directory); - FileUtility.ensureDirectorySync(this.config.history_directory); + this.refresh = true; + this.documents = {}; + fs.ensureDirSync(this.config.content_directory); + fs.ensureDirSync(this.config.history_directory); this.all = this.all.bind(this); this.getQuery = this.getQuery.bind(this); @@ -82,22 +81,43 @@ class StorageProvider { this.update = this.update.bind(this); this.delete = this.delete.bind(this); this.updateHistory = this.updateHistory.bind(this); - - this.refresh(); } /** * Returns all documents. * - * @async - * @returns {Promise} Promise object represents all documents. + * @returns {object} All documents. * @example * storageProvider.all(); - * ➜ [{ slug: 'first-document', ... }, ...] + * ➜ { first-document: { slug: 'first-document', ... }, ...} */ - async all() { + all() { debug('all'); - return Promise.all(this.documents); + if (this.config.use_cache && this.refresh === false) { + return this.documents; + } + + const documents = {}; + try { + const fileNames = fs.readdirSync(this.config.content_directory); + const validFiles = fileNames.filter((name) => (name.length >= 6) && name.endsWith(this.config.extension)); + for (const name of validFiles) { + const file = path.join(this.config.content_directory, `${path.parse(name).name}.${this.config.extension}`); + debug('all: Reading', file); + const content = fs.readFileSync(file, 'utf8'); + const data = JSON.parse(content); + documents[data.slug] = data; + } + debug('all: found', Object.values(documents).length); + if (this.config.use_cache) { + this.documents = documents; + this.refresh = false; + } + } catch (error) { + /* istanbul ignore next */ + debug('all: Error:', error); + } + return documents; } /** @@ -105,12 +125,11 @@ class StorageProvider { * * @async * @param {string} query - The conditions on which documents should be returned. - * @returns {Promise} Promise object represents all matching documents. + * @returns {Promise} Promise object represents all matching documents. */ async getQuery(query) { debug('getQuery:', query); - const all = await this.all(); - return processQuery(query, all); + return processQuery(query, Object.values(this.all())); } /** @@ -118,70 +137,31 @@ class StorageProvider { * * @async * @param {string} slug - The slug of the document to be returned. - * @returns {Promise} Promise object represents the returned UttoriDocument. + * @returns {Promise} Promise object represents the returned UttoriDocument. */ async get(slug) { - debug('get', slug); + debug('get:', slug); if (!slug) { - debug('Cannot get document without slug.', slug); - return undefined; - } - const all = await this.all(); - const document = R.clone( - R.find( - R.propEq('slug', slug), - )(all), - ); - if (!document) { - debug('No document found!'); + debug('get: Cannot get document without slug.'); return undefined; } - return document; - } + slug = sanitize(`${slug}`); - /** - * Returns the history of edits for a given slug. - * - * @async - * @param {string} slug - The slug of the document to get history for. - * @returns {Promise} Promise object represents the returned history. - */ - async getHistory(slug) { - debug('getHistory', slug); - if (!slug) { - debug('Cannot get document history without slug.', slug); - return undefined; + // Check the cache, fall back to reading the file. + if (this.config.use_cache && this.documents[slug]) { + return { ...this.documents[slug] }; } - const folder = path.join(this.config.history_directory, sanitize(`${slug}`)); - return FileUtility.readFolder(folder); - } - /** - * Returns a specifc revision from the history of edits for a given slug and revision timestamp. - * - * @async - * @param {object} params - The params object. - * @param {string} params.slug - The slug of the document to be returned. - * @param {number} params.revision - The unix timestamp of the history to be returned. - * @returns {Promise} Promise object represents the returned revision of the document. - */ - async getRevision({ slug, revision }) { - debug('getRevision', slug, revision); - if (!slug) { - debug('Cannot get document history without slug.', slug); - return undefined; - } - if (!revision) { - debug('Cannot get document history without revision.', revision); - return undefined; - } - const folder = path.join(this.config.history_directory, sanitize(`${slug}`)); - const document = await FileUtility.readJSON(folder, `${revision}`, this.config.extension); - if (!document) { - debug(`Document history not found for "${slug}", with revision "${revision}"`); + // Either not in cache or not using cache, read a document from a file. + try { + const file = path.join(this.config.content_directory, `${slug}.${this.config.extension}`); + debug('get:', file); + const content = await fs.readFile(file, 'utf8'); + return JSON.parse(content); + } catch (error) { + debug(`get: Error reading "${slug}":`, error); return undefined; } - return document; } /** @@ -199,18 +179,26 @@ class StorageProvider { debug('add:', document.slug); const existing = await this.get(document.slug); if (!existing) { - debug('Adding document.', document); + debug('add: new document', document); document.createDate = Date.now(); document.updateDate = document.createDate; - document.tags = R.isEmpty(document.tags) ? [] : document.tags; - document.customData = R.isEmpty(document.customData) ? {} : document.customData; if (this.config.use_history) { await this.updateHistory(document.slug, JSON.stringify(document, undefined, this.config.spaces_history)); } - await FileUtility.writeFile(this.config.content_directory, document.slug, this.config.extension, JSON.stringify(document, undefined, this.config.spaces_document)); - await this.refresh(); + if (this.config.use_cache) { + this.documents[document.slug] = document; + } + + try { + const file = path.join(this.config.content_directory, `${document.slug}.${this.config.extension}`); + debug('add: Creating content file:', file); + await fs.writeFile(file, JSON.stringify(document, undefined, this.config.spaces_document), 'utf8'); + } catch (error) { + /* istanbul ignore next */ + debug('add: Error creating content file:', error); + } } else { - debug('Cannot add, existing document!'); + debug('add: Cannot add, existing document!'); } } @@ -227,16 +215,21 @@ class StorageProvider { if (this.config.update_timestamps) { document.updateDate = Date.now(); } - /* istanbul ignore next */ - document.tags = R.isEmpty(document.tags) ? [] : document.tags; - /* istanbul ignore next */ - document.customData = R.isEmpty(document.customData) ? {} : document.customData; if (this.config.use_history) { await this.updateHistory(document.slug, JSON.stringify(document, undefined, this.config.spaces_history), originalSlug); } - await FileUtility.writeFile(this.config.content_directory, document.slug, this.config.extension, JSON.stringify(document, undefined, this.config.spaces_document)); - await this.refresh(); - debug('updateValid complete'); + if (this.config.use_cache) { + this.documents[document.slug] = document; + } + + try { + const file = path.join(this.config.content_directory, `${document.slug}.${this.config.extension}`); + debug('updateValid: Updating content file:', file); + await fs.writeFile(file, JSON.stringify(document, undefined, this.config.spaces_document), 'utf8'); + } catch (error) { + /* istanbul ignore next */ + debug('updateValid: Error updating content file:', error); + } } /** @@ -253,23 +246,36 @@ class StorageProvider { debug('Cannot update, missing slug.'); return; } - debug('update:', document.slug, originalSlug); + debug('update:', document.slug, 'originalSlug:', originalSlug); const existing = await this.get(document.slug); - const original = originalSlug ? await this.get(originalSlug) : undefined; + let original; + if (originalSlug) { + original = await this.get(originalSlug); + } if (existing && original && original.slug !== existing.slug) { - debug(`Cannot update, existing document with slug "${originalSlug}"!`); + debug(`update: Cannot update, existing document with new slug "${originalSlug}"!`); } else if (existing && original && original.slug === existing.slug) { - debug(`Updating document with slug "${document.slug}"`); + debug(`update: Updating document with slug "${document.slug}"`); await this.updateValid(document, originalSlug); } else if (existing && !original) { - debug(`Updating document with slug "${document.slug}" but no originalSlug`); + debug(`update: Updating document with slug "${document.slug}" but no originalSlug`); await this.updateValid(document, document.slug); } else if (!existing && original) { - debug(`Updating document with slug from "${originalSlug}" to "${document.slug}"`); - await FileUtility.deleteFile(this.config.content_directory, originalSlug, this.config.extension); + debug(`update: Updating document and changing slug from "${originalSlug}" to "${document.slug}"`); + if (this.config.use_cache) { + delete this.documents[originalSlug]; + } + /* istanbul ignore next */ + try { + const file = path.join(this.config.content_directory, `${originalSlug}.${this.config.extension}`); + debug('update: Deleting old file:', file); + fs.unlink(file); + } catch (error) { + debug('update: Error deleteing old file:', error); + } await this.updateValid(document, originalSlug); } else { - debug(`No document found to update with slug "${originalSlug}", adding document with slug "${document.slug}"`); + debug(`update: No document found to update with slug "${originalSlug}", adding document with slug "${document.slug}"`); await this.add(document); } } @@ -286,43 +292,82 @@ class StorageProvider { if (existing) { debug('Document found, deleting document:', slug); if (this.config.use_history) { - await this.updateHistory(existing.slug, JSON.stringify(existing, undefined, this.config.spaces_history)); + await this.updateHistory(slug, JSON.stringify(existing, undefined, this.config.spaces_history)); + } + if (this.config.use_cache) { + delete this.documents[slug]; + } + /* istanbul ignore next */ + try { + const file = path.join(this.config.content_directory, `${slug}.${this.config.extension}`); + debug('delete: Deleting content file:', file); + fs.unlink(file); + } catch (error) { + debug('delete: Error deleteing content file:', error); } - await FileUtility.deleteFile(this.config.content_directory, slug, this.config.extension); - await this.refresh(); } else { debug('Document not found:', slug); } } - // Format Specific Methods + /** + * Returns the history of edits for a given slug. + * + * @async + * @param {string} slug - The slug of the document to get history for. + * @returns {Promise} Promise object represents the returned history. + */ + async getHistory(slug) { + debug('getHistory', slug); + if (!slug) { + debug('Cannot get document history without slug.', slug); + return []; + } + + let history = []; + const folder = path.join(this.config.history_directory, sanitize(`${slug}`)); + debug('getHistory: folder', folder); + // eslint-disable-next-line no-bitwise + const access = await new Promise((resolve) => fs.access(folder, fs.constants.R_OK | fs.constants.W_OK, (err) => (!err ? resolve(true) : resolve(false)))); + if (access) { + history = await fs.readdir(folder); + } + debug('getHistory: history', history); + return history; + } /** - * Reloads all documents from the file system into the cache. + * Returns a specifc revision from the history of edits for a given slug and revision timestamp. * * @async + * @param {object} params - The params object. + * @param {string} params.slug - The slug of the document to be returned. + * @param {string|number} params.revision - The unix timestamp of the history to be returned. + * @returns {Promise} Promise object represents the returned revision of the document. */ - async refresh() { - debug('refresh'); - let documents = []; + async getRevision({ slug, revision }) { + debug('getRevision', slug, revision); + if (!slug) { + debug('getRevision: Cannot get document history without slug.', slug); + return undefined; + } + if (!revision) { + debug('getRevision: Cannot get document history without revision.', revision); + return undefined; + } try { - const fileNames = fs.readdirSync(this.config.content_directory); - const validFiles = R.filter( - (name) => (name.length >= 6) && name.endsWith(this.config.extension), - fileNames, - ); - documents = R.map( - (name) => FileUtility.readJSON(this.config.content_directory, path.parse(name).name, this.config.extension), - validFiles, - ); + const file = path.join(this.config.history_directory, sanitize(`${slug}`), sanitize(`${revision}`)); + debug('getRevision: Reading history file:', file); + const content = await fs.readFile(file, 'utf8'); + return JSON.parse(content); } catch (error) { - /* istanbul ignore next */ - debug('Error refreshing documents:', error); + debug('getRevision: Error reading history file:', error); + return undefined; } - - this.documents = R.reject(R.isNil, documents); } + // Format Specific Methods + /** * Updates History for a given slug, renaming the store file and history folder as needed. * @@ -332,19 +377,19 @@ class StorageProvider { * @param {string} [originalSlug] - The original slug identifying the document, or the slug if it has not changed. */ async updateHistory(slug, content, originalSlug) { - debug('updateHistory', slug, content, originalSlug); + debug('updateHistory:', slug, content, originalSlug); const original_folder = path.join(this.config.history_directory, sanitize(`${originalSlug}`)); const new_folder = path.join(this.config.history_directory, sanitize(`${slug}`)); // Rename old history folder if one existed if (slug && originalSlug && originalSlug !== slug) { - debug(`Updating history from "${originalSlug}" to "${slug}"`); + debug(`updateHistory: Updating history from "${originalSlug}" to "${slug}"`); /* istanbul ignore else */ if (await fs.pathExists(original_folder)) { - debug(`Renaming history folder from "${original_folder}" to "${new_folder}"`); + debug(`updateHistory: Renaming history folder from "${original_folder}" to "${new_folder}"`); try { await fs.move(original_folder, new_folder); } catch (error) { /* istanbul ignore next */ - debug(`Error renaming history folder from "${original_folder}" to "${new_folder}"`, error); + debug(`updateHistory: Error renaming history folder from "${original_folder}" to "${new_folder}"`, error); } } } @@ -352,15 +397,29 @@ class StorageProvider { /* istanbul ignore else */ const pathExists = await fs.pathExists(new_folder); if (!pathExists) { - debug('Creating document history folder:', new_folder); + debug('updateHistory: Creating document history folder:', new_folder); /* istanbul ignore next */ - try { await FileUtility.ensureDirectory(new_folder); } catch (error) { + try { + await fs.mkdir(new_folder); + } catch (error) { /* istanbul ignore next */ - debug('Error creating document history folder:', new_folder, error); + debug('updateHistory: Error creating document history folder:', new_folder, error); } } - - await FileUtility.writeFile(new_folder, `${Date.now()}`, this.config.extension, content); + /* istanbul ignore next */ + try { + let file = path.join(new_folder, `${Date.now()}.${this.config.extension}`); + let fileExists = await fs.pathExists(file); + while (fileExists) { + file = path.join(new_folder, `${Date.now()}.${this.config.extension}`); + // eslint-disable-next-line no-await-in-loop + fileExists = await fs.pathExists(file); + } + debug('updateHistory: Creating history file:', file); + await fs.writeFile(file, content, 'utf8'); + } catch (error) { + debug('updateHistory: Error creating history file:', error); + } } } diff --git a/test/index.test.js b/test/index.test.js index a79b74a..b25192c 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -19,6 +19,6 @@ test('Plugin: is properly exported', (t) => { test('StorageProvider: is properly exported', (t) => { t.notThrows(() => { const storage = new StorageProvider(config); - storage.refresh(); + storage.all(); }); }); diff --git a/test/plugin.test.js b/test/plugin.test.js index 5720d0d..267dad6 100644 --- a/test/plugin.test.js +++ b/test/plugin.test.js @@ -8,6 +8,9 @@ const config = { content_directory: 'test/site/content', history_directory: 'test/site/content/history', extension: 'json', + update_timestamps: true, + use_history: true, + use_cache: true, spaces_document: undefined, spaces_history: undefined, }; @@ -21,6 +24,10 @@ test.afterEach.always(async () => { await fs.remove('test/site'); }); +test('Plugin.configKey: returns a stable string', (t) => { + t.is(Plugin.configKey, 'uttori-plugin-storage-provider-json-file'); +}); + test('Plugin.register(context): can register', (t) => { t.notThrows(() => { Plugin.register({ hooks: { on: () => {} }, config: { [Plugin.configKey]: { ...config, events: { callback: [] } } } }); diff --git a/test/storage-provider-no-cache.test.js b/test/storage-provider-no-cache.test.js new file mode 100644 index 0000000..a97a428 --- /dev/null +++ b/test/storage-provider-no-cache.test.js @@ -0,0 +1,930 @@ +// @ts-nocheck +const fs = require('fs-extra'); +const test = require('ava'); +const R = require('ramda'); +const { StorageProvider } = require('../src'); + +const tagExample = 'Example Tag'; +const tagFake = 'Fake'; +const exampleSlug = 'example-title'; +const secondFile = 'second-file'; +const secondFileNewDirectory = 'second-file-new-directory'; +const secondFileV1 = 'second file'; +const secondFileV2 = 'second file-v2'; +const secondFileV3 = 'second file-v3'; +const secondFileV4 = 'second file-v4'; + +const config = { + content_directory: 'test/site/content', + history_directory: 'test/site/content/history', + extension: 'json', + spaces_document: undefined, + spaces_history: undefined, + update_timestamps: true, + use_cache: false, + use_history: true, +}; + +const example = { + title: 'Example Title', + slug: exampleSlug, + content: '## Example Title', + html: '', + updateDate: 1459310452001, + createDate: 1459310452001, + tags: [tagExample], +}; + +const empty = { + title: 'empty', + slug: 'empty', + content: 'empty', + html: '', + updateDate: 1459310452002, + createDate: 1459310452002, + tags: [tagFake], +}; + +const fake = { + title: tagFake, + slug: 'fake', + content: '# Fake', + html: '', + updateDate: 1459310452002, + createDate: 1459310452002, + tags: [tagExample, tagFake], +}; + +test.beforeEach(async () => { + await fs.remove('test/site'); + await fs.ensureDir('test/site/content/history', { recursive: true }); + await fs.writeFile('test/site/content/example-title.json', JSON.stringify(example)); +}); + +test.afterEach.always(async () => { + await fs.remove('test/site'); +}); + +test('constructor(config): does not error', (t) => { + t.notThrows(() => new StorageProvider(config)); +}); + +test('constructor(config): throws an error when missing config', (t) => { + t.throws(() => new StorageProvider()); +}); + +test('constructor(config): throws an error when missing config content directory', (t) => { + t.throws(() => new StorageProvider({ history_directory: '_' })); +}); + +test('constructor(config): throws an error when missing config history directory', (t) => { + t.throws(() => new StorageProvider({ content_directory: '_' })); +}); + +test('all(): returns all the documents', (t) => { + const s = new StorageProvider(config); + const results = s.all(); + t.deepEqual(results, { [exampleSlug]: example }); +}); + +test('getQuery(query): returns all unique tags from all the documents', async (t) => { + const s = new StorageProvider(config); + await s.add(example); + await s.add(fake); + await s.add(empty); + const results = await s.getQuery('SELECT tags FROM documents WHERE slug IS_NOT_NULL ORDER BY slug ASC LIMIT 3'); + t.deepEqual(results, [ + { + tags: [ + tagFake, + ], + }, + { + tags: [ + tagExample, + ], + }, + { + tags: [ + tagExample, + tagFake, + ], + }, + ]); + + const tags = R.pipe( + R.pluck('tags'), + R.flatten, + R.uniq, + R.filter(Boolean), + R.sort((a, b) => a.localeCompare(b)), + )(results); + t.deepEqual(tags, [tagExample, tagFake]); +}); + +test('getQuery(query): returns all unique tags and slug from all the documents', async (t) => { + const s = new StorageProvider(config); + await s.add(example); + await s.add(fake); + await s.add(empty); + const results = await s.getQuery('SELECT slug, tags FROM documents WHERE slug IS_NOT_NULL ORDER BY slug ASC LIMIT 3'); + t.deepEqual(results, [ + { + slug: 'empty', + tags: [ + tagFake, + ], + }, + { + slug: exampleSlug, + tags: [ + tagExample, + ], + }, + { + slug: 'fake', + tags: [ + tagExample, + tagFake, + ], + }, + ]); + + const tags = R.pipe( + R.pluck('tags'), + R.flatten, + R.uniq, + R.filter(Boolean), + R.sort((a, b) => a.localeCompare(b)), + )(results); + t.deepEqual(tags, [tagExample, tagFake]); +}); + +test('getQuery(query): returns documents with the given tag', async (t) => { + const s = new StorageProvider(config); + await s.add(fake); + await s.add(empty); + + let tag = tagExample; + let query = `SELECT * FROM documents WHERE 'tags' INCLUDES ('${tag}') ORDER BY title ASC LIMIT 100`; + let output = await s.getQuery(query); + t.deepEqual(output, [example, fake]); + + tag = tagFake; + query = `SELECT * FROM documents WHERE 'tags' INCLUDES ('${tag}') ORDER BY title ASC LIMIT 100`; + output = await s.getQuery(query); + t.deepEqual(output, [fake, empty]); + + tag = 'No Tag'; + query = `SELECT * FROM documents WHERE 'tags' INCLUDES ('${tag}') ORDER BY title ASC LIMIT 100`; + output = await s.getQuery(query); + t.deepEqual(output, []); +}); + +test('getQuery(query): returns the requested number of the most recently updated documents', async (t) => { + const s = new StorageProvider(config); + await s.add(fake); + await s.add(empty); + + let limit = 1; + let query = `SELECT * FROM documents WHERE 'slug' != '' ORDER BY updateDate DESC LIMIT ${limit}`; + let output = await s.getQuery(query); + t.deepEqual(output, [empty]); + + limit = 2; + query = `SELECT * FROM documents WHERE 'slug' != '' ORDER BY updateDate DESC LIMIT ${limit}`; + output = await s.getQuery(query); + t.deepEqual(output, [empty, fake]); + + limit = 3; + query = `SELECT * FROM documents WHERE 'slug' != '' ORDER BY updateDate DESC LIMIT ${limit}`; + output = await s.getQuery(query); + t.deepEqual(output, [empty, fake, example]); +}); + +test('getQuery(query): returns the requested number of the related documents', async (t) => { + const s = new StorageProvider(config); + await s.add(fake); + const tagged = { ...empty, tags: [tagExample] }; + await s.add(tagged); + + const query = `SELECT * FROM documents WHERE 'tags' INCLUDES ('${example.tags.join(',')}') AND slug != ${example.slug} ORDER BY title DESC LIMIT 2`; + const output = await s.getQuery(query); + t.deepEqual(output, [tagged, fake]); +}); + +test('getQuery(query): returns the requested number of random documents', async (t) => { + const s = new StorageProvider(config); + await s.add(fake); + await s.add(empty); + + let limit = 1; + let query = `SELECT * FROM documents WHERE 'slug' != '' ORDER BY RANDOM LIMIT ${limit}`; + let output = await s.getQuery(query); + t.is(output.length, 1); + + limit = 2; + query = `SELECT * FROM documents WHERE 'slug' != '' ORDER BY RANDOM LIMIT ${limit}`; + output = await s.getQuery(query); + t.is(output.length, 2); + + limit = 3; + query = `SELECT * FROM documents WHERE 'slug' != '' ORDER BY RANDOM LIMIT ${limit}`; + output = await s.getQuery(query); + t.is(output.length, 3); +}); + +test('get(slug): returns the matching document', async (t) => { + const s = new StorageProvider(config); + const results = await s.get(example.slug); + t.deepEqual(results, example); +}); + +test('get(slug): returns undefined when there is no slug', async (t) => { + const s = new StorageProvider(config); + const results = await s.get(); + t.is(results, undefined); +}); + +test('get(slug): returns undefined when no document is found', async (t) => { + const s = new StorageProvider(config); + const document = await s.get('missing-file'); + t.is(document, undefined); +}); + +test('getHistory(slug): returns undefined when missing a slug', async (t) => { + const s = new StorageProvider(config); + const history = await s.getHistory(''); + t.deepEqual(history, []); +}); + +test('getHistory(slug): returns an empty array when a slug is not found', async (t) => { + const s = new StorageProvider(config); + t.deepEqual(await s.getHistory(''), []); + t.deepEqual(await s.getHistory('missing'), []); +}); + +test('getHistory(slug): returns an array of the history revisions', async (t) => { + let all; + let history; + await fs.remove('test/site'); + + const s = new StorageProvider(config); + await s.add({ + content: '', + createDate: undefined, + html: '', + slug: secondFile, + tags: ['test'], + title: secondFileV1, + updateDate: undefined, + }); + all = Object.values(s.all()); + t.is(all.length, 1); + t.is(all[0].title, secondFileV1); + + // TODO Sometimes returns 0, not 1. + history = await s.getHistory(secondFile); + t.is(history.length, 1); + + await s.update({ + document: { + content: secondFileV2, + createDate: undefined, + html: '', + slug: secondFile, + tags: ['test'], + title: secondFileV2, + updateDate: undefined, + }, + originalSlug: secondFile, + }); + all = Object.values(s.all()); + t.is(all.length, 1); + t.is(all[0].title, secondFileV2); + + // TODO Sometimes returns 1, not 2. + history = await s.getHistory(secondFile); + t.is(history.length, 2); + + await s.update({ + document: { + content: secondFileV3, + createDate: undefined, + html: '', + slug: secondFile, + tags: ['test'], + title: secondFileV3, + updateDate: undefined, + }, + originalSlug: secondFile, + }); + all = Object.values(s.all()); + t.is(all.length, 1); + t.is(all[0].title, secondFileV3); + + // TODO Sometimes returns 2, not 3. + history = await s.getHistory(secondFile); + t.is(history.length, 3); + + await s.update({ + document: { + content: secondFileV4, + createDate: undefined, + html: '', + slug: secondFileNewDirectory, + tags: ['test'], + title: secondFileV4, + updateDate: undefined, + }, + originalSlug: secondFile, + }); + all = Object.values(s.all()); + t.is(all.length, 1); + t.is(all[0].title, secondFileV4); + + history = await s.getHistory(secondFileNewDirectory); + t.is(history.length, 4); +}); + +test('getRevision({ slug, revision }): returns undefined when missing a slug', async (t) => { + const s = new StorageProvider(config); + const revision = await s.getRevision({ slug: '' }); + t.is(revision, undefined); +}); + +test('getRevision({ slug, revision }): returns undefined when missing a revision', async (t) => { + const s = new StorageProvider(config); + const revision = await s.getRevision({ slug: 'slug', revision: '' }); + t.is(revision, undefined); +}); + +test('getRevision({ slug, revision }): returns undefined when no revision is found', async (t) => { + const s = new StorageProvider(config); + const revision = await s.getRevision({ slug: 'slug', revision: -1 }); + t.is(revision, undefined); +}); + +test('getRevision({ slug, revision }): returns a specific revision of an article', async (t) => { + let all; + let history; + await fs.remove('test/site'); + + const s = new StorageProvider(config); + await s.add({ + slug: secondFile, + title: secondFileV1, + }); + all = Object.values(s.all()); + t.is(all.length, 1); + t.is(all[0].title, secondFileV1); + history = await s.getHistory(secondFile); + t.is(history.length, 1); + + await s.update({ + document: { + slug: secondFile, + title: secondFileV2, + }, + originalSlug: secondFile, + }); + all = Object.values(s.all()); + t.is(all.length, 1); + t.is(all[0].title, secondFileV2); + + // TODO: Occasionally this returns 1, not 2. + history = await s.getHistory(secondFile); + t.is(history.length, 2); + + await s.update({ + document: { + slug: secondFile, + title: secondFileV3, + }, + originalSlug: secondFile, + }); + all = Object.values(s.all()); + t.is(all.length, 1); + t.is(all[0].title, secondFileV3); + + // TODO: Occasionlly returns 2, not 3. + history = await s.getHistory(secondFile); + t.is(history.length, 3); + + await s.update({ + document: { + slug: secondFileNewDirectory, + title: secondFileV4, + }, + originalSlug: secondFile, + }); + all = Object.values(s.all()); + t.is(all.length, 1); + t.is(all[0].title, secondFileV4); + + // TODO: Occasionlly returns 3, not 4. + history = await s.getHistory(secondFileNewDirectory); + t.is(history.length, 4); + + let revision; + // TODO: Occasionlly return secondFileV2, not secondFileV1. + revision = await s.getRevision({ slug: secondFileNewDirectory, revision: history[0] }); + t.is(revision.title, secondFileV1); + // TODO: Occasionlly return secondFileV3, not secondFileV2. + revision = await s.getRevision({ slug: secondFileNewDirectory, revision: history[1] }); + t.is(revision.title, secondFileV2); + revision = await s.getRevision({ slug: secondFileNewDirectory, revision: history[2] }); + t.is(revision.title, secondFileV3); + revision = await s.getRevision({ slug: secondFileNewDirectory, revision: history[3] }); + t.is(revision.title, secondFileV4); +}); + +test('add(document): cannot add without a document or a slug', async (t) => { + let all; + const s = new StorageProvider(config); + await s.add(); + all = Object.values(s.all()); + t.is(all.length, 1); + await s.add({}); + all = Object.values(s.all()); + t.is(all.length, 1); +}); + +test('add(document): creates a new document', async (t) => { + const s = new StorageProvider(config); + await s.add({ + content: '', + createDate: undefined, + html: '', + slug: secondFile, + tags: [], + title: secondFileV1, + updateDate: undefined, + }); + const all = Object.values(s.all()); + t.deepEqual(all[0], example); + t.is(all[1].slug, secondFile); +}); + +test('add(document): creates a new document without saving a history', async (t) => { + const s = new StorageProvider({ ...config, use_history: false }); + await s.add({ + content: '', + createDate: undefined, + html: '', + slug: secondFile, + tags: [], + title: secondFileV1, + updateDate: undefined, + }); + const all = Object.values(s.all()); + t.deepEqual(all[0], example); + t.is(all[1].slug, secondFile); +}); + +test('add(document): creates a new document with missing fields', async (t) => { + const s = new StorageProvider(config); + await s.add({ + content: '', + createDate: undefined, + html: '', + slug: secondFile, + title: secondFileV1, + updateDate: undefined, + }); + const all = Object.values(s.all()); + t.deepEqual(all[0], example); + t.is(all[1].slug, secondFile); +}); + +test('add(document): does not create a document with the same slug', async (t) => { + let all; + const s = new StorageProvider(config); + await s.add({ + content: '', + createDate: undefined, + html: '', + slug: secondFile, + tags: [], + title: secondFileV1, + updateDate: undefined, + }); + all = Object.values(s.all()); + t.deepEqual(all[0], example); + t.is(all[1].slug, secondFile); + t.is(all.length, 2); + await s.add({ + slug: secondFile, + }); + all = Object.values(s.all()); + t.is(all.length, 2); +}); + +test('update({ document, originalSlug }): does not update without a document or slug', async (t) => { + let all; + const s = new StorageProvider(config); + all = Object.values(s.all()); + t.is(all.length, 1); + await s.update({ document: undefined, originalSlug: secondFile }); + all = Object.values(s.all()); + t.is(all.length, 1); + + await s.update({ document: { title: 'New' }, originalSlug: secondFile }); + all = Object.values(s.all()); + t.is(all.length, 1); +}); + +test('update({ document, originalSlug }): does not update without a document with an existing slug', async (t) => { + let all; + const s = new StorageProvider(config); + all = Object.values(s.all()); + t.is(all.length, 1); + await s.add({ + content: '', + createDate: undefined, + html: '', + slug: secondFile, + tags: ['test'], + title: secondFileV1, + updateDate: undefined, + }); + all = Object.values(s.all()); + t.is(all.length, 2); + await s.update({ + document: { + title: 'New', + slug: exampleSlug, + }, + originalSlug: secondFile, + }); + all = Object.values(s.all()); + t.is(all.length, 2); +}); + +test('update({ document, originalSlug }): updates the file on disk', async (t) => { + let all; + const s = new StorageProvider(config); + await s.add({ + content: '', + createDate: undefined, + html: '', + slug: secondFile, + tags: ['test'], + title: secondFileV1, + updateDate: undefined, + }); + all = Object.values(s.all()); + t.is(all.length, 2); + await s.update({ + document: { + content: '', + createDate: undefined, + html: '', + slug: secondFile, + tags: ['test'], + title: secondFileV2, + updateDate: undefined, + }, + originalSlug: secondFile, + }); + all = Object.values(s.all()); + t.is(all.length, 2); + const output = await s.get(secondFile); + t.is(output.title, secondFileV2); +}); + +test('update({ document, originalSlug }): updates the file on disk without an originalSlug', async (t) => { + let all; + const s = new StorageProvider({ ...config, use_history: false }); + await s.add({ + content: '', + createDate: undefined, + html: '', + slug: secondFile, + tags: ['test'], + title: secondFileV1, + updateDate: undefined, + }); + all = Object.values(s.all()); + t.is(all.length, 2); + await s.update({ + document: { + content: '', + createDate: undefined, + html: '', + slug: secondFile, + tags: ['test'], + title: secondFileV2, + updateDate: undefined, + }, + originalSlug: undefined, + }); + all = Object.values(s.all()); + t.is(all.length, 2); + const output = await s.get(secondFile); + t.is(output.title, secondFileV2); +}); + +test('update({ document, originalSlug }): renames the history directory if it exists', async (t) => { + let all; + let history; + const s = new StorageProvider(config); + await s.add({ + content: '', + createDate: undefined, + html: '', + slug: secondFile, + tags: ['test'], + title: secondFileV1, + updateDate: undefined, + }); + all = Object.values(s.all()); + t.is(all.length, 2); + history = await s.getHistory(secondFile); + t.is(history.length, 1); + + await s.update({ + document: { + content: secondFileV2, + createDate: undefined, + html: '', + slug: secondFile, + tags: ['test'], + title: secondFileV2, + updateDate: undefined, + }, + originalSlug: secondFile, + }); + all = Object.values(s.all()); + t.is(all.length, 2); + t.is(all[1].title, secondFileV2); + + // TODO Sometimes returns 1, not 2. + history = await s.getHistory(secondFile); + t.is(history.length, 2); + + await s.update({ + document: { + content: secondFileV3, + createDate: undefined, + html: '', + slug: secondFile, + tags: ['test'], + title: secondFileV3, + updateDate: undefined, + }, + originalSlug: secondFile, + }); + all = Object.values(s.all()); + t.is(all.length, 2); + t.is(all[1].title, secondFileV3); + + // TODO Sometimes returns 2, not 3. + history = await s.getHistory(secondFile); + t.is(history.length, 3); + + await s.update({ + document: { + content: secondFileV4, + createDate: undefined, + html: '', + slug: secondFileNewDirectory, + tags: ['test'], + title: secondFileV4, + updateDate: undefined, + }, + originalSlug: secondFile, + }); + all = Object.values(s.all()); + t.is(all.length, 2); + t.is(all[1].title, secondFileV4); + + // TODO Sometimes returns 3, not 4. + history = await s.getHistory(secondFileNewDirectory); + t.is(history.length, 4); + + t.is(fs.existsSync(`${config.history_directory}/second-file-new-directory`), true); + t.is(fs.existsSync(`${config.history_directory}/second-file`), false); +}); + +test('update({ document, originalSlug }): updates the file on disk with missing fields', async (t) => { + let all; + const s = new StorageProvider(config); + await s.add({ + content: '', + createDate: undefined, + html: '', + slug: secondFile, + title: secondFileV1, + updateDate: undefined, + }); + all = Object.values(s.all()); + t.is(all.length, 2); + await s.update({ + document: { + content: '', + createDate: undefined, + html: '', + slug: secondFile, + title: secondFileV2, + updateDate: undefined, + }, + originalSlug: secondFile, + }); + all = Object.values(s.all()); + t.is(all.length, 2); + t.is(all[1].title, secondFileV2); +}); + +test('update({ document, originalSlug }): does not update when file exists', async (t) => { + let all; + const s = new StorageProvider(config); + await s.add({ + content: '', + createDate: undefined, + html: '', + slug: secondFile, + title: secondFileV1, + updateDate: undefined, + }); + all = Object.values(s.all()); + t.is(all.length, 2); + await s.update({ + content: '', + createDate: undefined, + html: '', + slug: secondFile, + title: secondFileV2, + updateDate: undefined, + originalSlug: exampleSlug, + }); + all = Object.values(s.all()); + t.is(all.length, 2); + t.is(all[1].title, secondFileV1); +}); + +test('update({ document, originalSlug }): adds a document if the one to update is no found', async (t) => { + const s = new StorageProvider(config); + await s.update({ + document: { + content: '', + createDate: 1, + html: '', + slug: 'third-file', + tags: [], + title: 'third file', + updateDate: 1, + }, + originalSlug: '', + }); + const all = Object.values(s.all()); + t.is(all.length, 2); +}); + +test('update({ document, originalSlug }): updates the file on disk without updating timestamps', async (t) => { + let all; + const s = new StorageProvider({ ...config, update_timestamps: false }); + await s.add({ + content: '', + createDate: undefined, + html: '', + slug: secondFile, + tags: ['test'], + title: secondFileV1, + updateDate: undefined, + }); + all = Object.values(s.all()); + t.is(all.length, 2); + await s.update({ + document: { + content: '', + createDate: 1459310452001, + html: '', + slug: secondFile, + tags: ['test'], + title: secondFileV2, + updateDate: 1459310452001, + }, + originalSlug: secondFile, + }); + all = Object.values(s.all()); + t.is(all.length, 2); + t.deepEqual(all[1], { + content: '', + createDate: 1459310452001, + html: '', + slug: secondFile, + tags: ['test'], + title: secondFileV2, + updateDate: 1459310452001, + }); +}); + +test('update({ document, originalSlug }): updates the file on disk without updating history', async (t) => { + let all; + const s = new StorageProvider({ ...config, update_timestamps: false, use_history: false }); + + await s.add({ + content: '', + createDate: 1459310452001, + html: '', + slug: secondFile, + tags: ['test'], + title: secondFileV1, + updateDate: 1459310452001, + }); + all = Object.values(s.all()); + t.is(all.length, 2); + await s.update({ + document: { + content: '', + createDate: 1459310452001, + html: '', + slug: secondFile, + tags: ['test'], + updateDate: 1459310452001, + title: secondFileV2, + }, + originalSlug: secondFile, + }); + all = Object.values(s.all()); + t.is(all.length, 2); + t.deepEqual(all[1], { + content: '', + createDate: 1459310452001, + html: '', + slug: secondFile, + tags: ['test'], + updateDate: 1459310452001, + title: secondFileV2, + }); +}); + +test('delete(document): removes the file from disk', async (t) => { + let all; + const s = new StorageProvider(config); + await s.add({ + content: '', + createDate: 1, + html: '', + slug: secondFile, + tags: [], + title: secondFileV1, + updateDate: 1, + }); + all = Object.values(s.all()); + t.is(all.length, 2); + await s.delete(secondFile); + all = Object.values(s.all()); + t.is(all.length, 1); +}); + +test('delete(document): removes the file from disk without history', async (t) => { + let all; + const s = new StorageProvider({ ...config, use_history: false }); + await s.add({ + content: '', + createDate: 1, + html: '', + slug: secondFile, + tags: [], + title: secondFileV1, + updateDate: 1, + }); + all = Object.values(s.all()); + t.is(all.length, 2); + await s.delete(secondFile); + all = Object.values(s.all()); + t.is(all.length, 1); +}); + +test('delete(document): does nothing when no file is found', async (t) => { + let all; + const s = new StorageProvider(config); + await s.add({ + content: '', + createDate: undefined, + html: '', + slug: secondFile, + tags: [], + title: secondFileV1, + updateDate: undefined, + }); + all = Object.values(s.all()); + t.is(all.length, 2); + await s.delete('slug'); + all = Object.values(s.all()); + t.is(all.length, 2); +}); + +test('getQuery(query): returns all matching documents with an array of slugs', async (t) => { + const s = new StorageProvider(config); + await s.add(fake); + await s.add(empty); + + const search_results = [{ slug: exampleSlug }, { slug: 'fake' }]; + const includes = search_results.map((result) => `'${result.slug}'`).join(','); + const query = `SELECT * FROM documents WHERE slug INCLUDES (${includes}) ORDER BY title ASC LIMIT 100`; + const output = await s.getQuery(query); + t.deepEqual(output, [example, fake]); +}); diff --git a/test/storage-provider.test.js b/test/storage-provider.test.js index 7059572..57320b5 100644 --- a/test/storage-provider.test.js +++ b/test/storage-provider.test.js @@ -21,7 +21,9 @@ const config = { spaces_document: undefined, spaces_history: undefined, update_timestamps: true, + use_cache: true, use_history: true, + }; const example = { @@ -32,11 +34,6 @@ const example = { updateDate: 1459310452001, createDate: 1459310452001, tags: [tagExample], - customData: { - keyA: 'value-a', - keyB: 'value-b', - keyC: 'value-c', - }, }; const empty = { @@ -47,7 +44,6 @@ const empty = { updateDate: 1459310452002, createDate: 1459310452002, tags: [tagFake], - customData: {}, }; const fake = { @@ -58,7 +54,6 @@ const fake = { updateDate: 1459310452002, createDate: 1459310452002, tags: [tagExample, tagFake], - customData: {}, }; test.beforeEach(async () => { @@ -87,10 +82,10 @@ test('constructor(config): throws an error when missing config history directory t.throws(() => new StorageProvider({ content_directory: '_' })); }); -test('all(): returns all the documents', async (t) => { +test('all(): returns all the documents', (t) => { const s = new StorageProvider(config); - const results = await s.all(); - t.deepEqual(results, [example]); + const results = s.all(); + t.deepEqual(results, { [exampleSlug]: example }); }); test('getQuery(query): returns all unique tags from all the documents', async (t) => { @@ -261,12 +256,12 @@ test('get(slug): returns undefined when no document is found', async (t) => { test('getHistory(slug): returns undefined when missing a slug', async (t) => { const s = new StorageProvider(config); const history = await s.getHistory(''); - t.is(history, undefined); + t.deepEqual(history, []); }); test('getHistory(slug): returns an empty array when a slug is not found', async (t) => { const s = new StorageProvider(config); - t.is(await s.getHistory(''), undefined); + t.deepEqual(await s.getHistory(''), []); t.deepEqual(await s.getHistory('missing'), []); }); @@ -276,53 +271,77 @@ test('getHistory(slug): returns an array of the history revisions', async (t) => await fs.remove('test/site'); const s = new StorageProvider(config); - const document = { + await s.add({ content: '', createDate: undefined, - customData: { test: true }, html: '', slug: secondFile, tags: ['test'], title: secondFileV1, updateDate: undefined, - }; - await s.add(document); - all = await s.all(); + }); + all = Object.values(s.all()); t.is(all.length, 1); t.is(all[0].title, secondFileV1); - history = await s.getHistory(document.slug); + + history = await s.getHistory(secondFile); t.is(history.length, 1); - document.title = secondFileV2; - document.content = secondFileV2; - await s.update({ document, originalSlug: secondFile }); - all = await s.all(); + await s.update({ + document: { + content: secondFileV2, + createDate: undefined, + html: '', + slug: secondFile, + tags: ['test'], + title: secondFileV2, + updateDate: undefined, + }, + originalSlug: secondFile, + }); + all = Object.values(s.all()); t.is(all.length, 1); t.is(all[0].title, secondFileV2); - await s.refresh(); - history = await s.getHistory(document.slug); - // TODO Sometimes returns 1, not 2. + + history = await s.getHistory(secondFile); t.is(history.length, 2); - document.title = secondFileV3; - document.content = secondFileV3; - await s.update({ document, originalSlug: secondFile }); - all = await s.all(); + await s.update({ + document: { + content: secondFileV3, + createDate: undefined, + html: '', + slug: secondFile, + tags: ['test'], + title: secondFileV3, + updateDate: undefined, + }, + originalSlug: secondFile, + }); + all = Object.values(s.all()); t.is(all.length, 1); t.is(all[0].title, secondFileV3); - await s.refresh(); - history = await s.getHistory(document.slug); - // TODO Sometimes returns 2, not 3. + + history = await s.getHistory(secondFile); t.is(history.length, 3); - document.slug = secondFileNewDirectory; - document.title = secondFileV4; - document.content = secondFileV4; - await s.update({ document, originalSlug: secondFile }); - all = await s.all(); + await s.update({ + document: { + content: secondFileV4, + createDate: undefined, + html: '', + slug: secondFileNewDirectory, + tags: ['test'], + title: secondFileV4, + updateDate: undefined, + }, + originalSlug: secondFile, + }); + all = Object.values(s.all()); t.is(all.length, 1); t.is(all[0].title, secondFileV4); - history = await s.getHistory(document.slug); + + history = await s.getHistory(secondFileNewDirectory); t.is(history.length, 4); }); @@ -350,66 +369,66 @@ test('getRevision({ slug, revision }): returns a specific revision of an article await fs.remove('test/site'); const s = new StorageProvider(config); - const document = { - content: '', - createDate: undefined, - customData: { test: true }, - html: '', + await s.add({ slug: secondFile, - tags: ['test'], title: secondFileV1, - updateDate: undefined, - }; - await s.add(document); - all = await s.all(); + }); + all = Object.values(s.all()); t.is(all.length, 1); t.is(all[0].title, secondFileV1); - history = await s.getHistory(document.slug); + history = await s.getHistory(secondFile); t.is(history.length, 1); - document.title = secondFileV2; - document.content = secondFileV2; - await s.update({ document, originalSlug: secondFile }); - all = await s.all(); + await s.update({ + document: { + slug: secondFile, + title: secondFileV2, + }, + originalSlug: secondFile, + }); + all = Object.values(s.all()); t.is(all.length, 1); t.is(all[0].title, secondFileV2); - await s.refresh(); - history = await s.getHistory(document.slug); - // TODO: Occasionally this returns 1, not 2. + + history = await s.getHistory(secondFile); t.is(history.length, 2); - document.title = secondFileV3; - document.content = secondFileV3; - await s.update({ document, originalSlug: secondFile }); - all = await s.all(); + await s.update({ + document: { + slug: secondFile, + title: secondFileV3, + }, + originalSlug: secondFile, + }); + all = Object.values(s.all()); t.is(all.length, 1); t.is(all[0].title, secondFileV3); - await s.refresh(); - history = await s.getHistory(document.slug); - // TODO: Occasionlly returns 2, not 3. + + history = await s.getHistory(secondFile); t.is(history.length, 3); - document.slug = secondFileNewDirectory; - document.title = secondFileV4; - document.content = secondFileV4; - await s.update({ document, originalSlug: secondFile }); - all = await s.all(); + await s.update({ + document: { + slug: secondFileNewDirectory, + title: secondFileV4, + }, + originalSlug: secondFile, + }); + all = Object.values(s.all()); t.is(all.length, 1); t.is(all[0].title, secondFileV4); - history = await s.getHistory(document.slug); - t.is(history.length, 4); - history = await s.getHistory(document.slug); + history = await s.getHistory(secondFileNewDirectory); t.is(history.length, 4); let revision; - revision = await s.getRevision({ slug: document.slug, revision: history[0] }); + revision = await s.getRevision({ slug: secondFileNewDirectory, revision: history[0] }); t.is(revision.title, secondFileV1); - revision = await s.getRevision({ slug: document.slug, revision: history[1] }); + revision = await s.getRevision({ slug: secondFileNewDirectory, revision: history[1] }); t.is(revision.title, secondFileV2); - revision = await s.getRevision({ slug: document.slug, revision: history[2] }); + revision = await s.getRevision({ slug: secondFileNewDirectory, revision: history[2] }); t.is(revision.title, secondFileV3); - revision = await s.getRevision({ slug: document.slug, revision: history[3] }); + revision = await s.getRevision({ slug: secondFileNewDirectory, revision: history[3] }); t.is(revision.title, secondFileV4); }); @@ -417,201 +436,261 @@ test('add(document): cannot add without a document or a slug', async (t) => { let all; const s = new StorageProvider(config); await s.add(); - all = await s.all(); + all = Object.values(s.all()); t.is(all.length, 1); - s.add({}); - all = await s.all(); + await s.add({}); + all = Object.values(s.all()); t.is(all.length, 1); }); test('add(document): creates a new document', async (t) => { const s = new StorageProvider(config); - const document = { + await s.add({ content: '', createDate: undefined, - customData: {}, html: '', slug: secondFile, tags: [], title: secondFileV1, updateDate: undefined, - }; - await s.add(document); - const all = await s.all(); + }); + const all = Object.values(s.all()); t.deepEqual(all[0], example); - t.is(all[1].slug, document.slug); + t.is(all[1].slug, secondFile); }); test('add(document): creates a new document without saving a history', async (t) => { const s = new StorageProvider({ ...config, use_history: false }); - const document = { + await s.add({ content: '', createDate: undefined, - customData: {}, html: '', slug: secondFile, tags: [], title: secondFileV1, updateDate: undefined, - }; - await s.add(document); - const all = await s.all(); + }); + const all = Object.values(s.all()); t.deepEqual(all[0], example); - t.is(all[1].slug, document.slug); + t.is(all[1].slug, secondFile); }); test('add(document): creates a new document with missing fields', async (t) => { const s = new StorageProvider(config); - const document = { + await s.add({ content: '', createDate: undefined, html: '', slug: secondFile, title: secondFileV1, updateDate: undefined, - }; - await s.add(document); - const all = await s.all(); + }); + const all = Object.values(s.all()); t.deepEqual(all[0], example); - t.is(all[1].slug, document.slug); + t.is(all[1].slug, secondFile); }); test('add(document): does not create a document with the same slug', async (t) => { let all; const s = new StorageProvider(config); - const document = { + await s.add({ content: '', createDate: undefined, - customData: {}, html: '', slug: secondFile, tags: [], title: secondFileV1, updateDate: undefined, - }; - await s.add(document); - all = await s.all(); + }); + all = Object.values(s.all()); t.deepEqual(all[0], example); - t.is(all[1].slug, document.slug); + t.is(all[1].slug, secondFile); t.is(all.length, 2); - await s.add(document); - all = await s.all(); + await s.add({ + slug: secondFile, + }); + all = Object.values(s.all()); t.is(all.length, 2); }); test('update({ document, originalSlug }): does not update without a document or slug', async (t) => { let all; const s = new StorageProvider(config); + all = Object.values(s.all()); + t.is(all.length, 1); await s.update({ document: undefined, originalSlug: secondFile }); - all = await s.all(); + all = Object.values(s.all()); t.is(all.length, 1); - t.is(all[0].title, example.title); await s.update({ document: { title: 'New' }, originalSlug: secondFile }); - all = await s.all(); + all = Object.values(s.all()); t.is(all.length, 1); - t.is(all[0].title, example.title); +}); + +test('update({ document, originalSlug }): does not update without a document with an existing slug', async (t) => { + let all; + const s = new StorageProvider(config); + all = Object.values(s.all()); + t.is(all.length, 1); + await s.add({ + content: '', + createDate: undefined, + html: '', + slug: secondFile, + tags: ['test'], + title: secondFileV1, + updateDate: undefined, + }); + all = Object.values(s.all()); + t.is(all.length, 2); + await s.update({ + document: { + title: 'New', + slug: exampleSlug, + }, + originalSlug: secondFile, + }); + all = Object.values(s.all()); + t.is(all.length, 2); }); test('update({ document, originalSlug }): updates the file on disk', async (t) => { let all; const s = new StorageProvider(config); - const document = { + await s.add({ content: '', createDate: undefined, - customData: { test: true }, html: '', slug: secondFile, tags: ['test'], title: secondFileV1, updateDate: undefined, - }; - await s.add(document); - all = await s.all(); + }); + all = Object.values(s.all()); t.is(all.length, 2); - document.title = secondFileV2; - await s.update({ document, originalSlug: secondFile }); - all = await s.all(); + await s.update({ + document: { + content: '', + createDate: undefined, + html: '', + slug: secondFile, + tags: ['test'], + title: secondFileV2, + updateDate: undefined, + }, + originalSlug: secondFile, + }); + all = Object.values(s.all()); t.is(all.length, 2); const output = await s.get(secondFile); - t.is(output.title, document.title); + t.is(output.title, secondFileV2); }); test('update({ document, originalSlug }): updates the file on disk without an originalSlug', async (t) => { let all; const s = new StorageProvider({ ...config, use_history: false }); - const document = { + await s.add({ content: '', createDate: undefined, - customData: { test: true }, html: '', slug: secondFile, tags: ['test'], title: secondFileV1, updateDate: undefined, - }; - await s.add(document); - all = await s.all(); + }); + all = Object.values(s.all()); t.is(all.length, 2); - document.title = secondFileV2; - await s.update({ document, originalSlug: undefined }); - all = await s.all(); + await s.update({ + document: { + content: '', + createDate: undefined, + html: '', + slug: secondFile, + tags: ['test'], + title: secondFileV2, + updateDate: undefined, + }, + originalSlug: undefined, + }); + all = Object.values(s.all()); t.is(all.length, 2); const output = await s.get(secondFile); - t.is(output.title, document.title); + t.is(output.title, secondFileV2); }); test('update({ document, originalSlug }): renames the history directory if it exists', async (t) => { let all; let history; const s = new StorageProvider(config); - const document = { + await s.add({ content: '', createDate: undefined, - customData: { test: true }, html: '', slug: secondFile, tags: ['test'], title: secondFileV1, updateDate: undefined, - }; - await s.add(document); - all = await s.all(); + }); + all = Object.values(s.all()); t.is(all.length, 2); - history = await s.getHistory(document.slug); + history = await s.getHistory(secondFile); t.is(history.length, 1); - document.title = secondFileV2; - document.content = secondFileV2; - await s.update({ document, originalSlug: secondFile }); - all = await s.all(); + await s.update({ + document: { + content: secondFileV2, + createDate: undefined, + html: '', + slug: secondFile, + tags: ['test'], + title: secondFileV2, + updateDate: undefined, + }, + originalSlug: secondFile, + }); + all = Object.values(s.all()); t.is(all.length, 2); - t.is(all[1].title, document.title); + t.is(all[1].title, secondFileV2); - await s.refresh(); - // TODO Sometimes returns 1, not 2. - history = await s.getHistory(document.slug); + history = await s.getHistory(secondFile); t.is(history.length, 2); - document.title = secondFileV3; - document.content = secondFileV3; - await s.update({ document, originalSlug: secondFile }); - all = await s.all(); + await s.update({ + document: { + content: secondFileV3, + createDate: undefined, + html: '', + slug: secondFile, + tags: ['test'], + title: secondFileV3, + updateDate: undefined, + }, + originalSlug: secondFile, + }); + all = Object.values(s.all()); t.is(all.length, 2); - t.is(all[1].title, document.title); - await s.refresh(); - history = await s.getHistory(document.slug); + t.is(all[1].title, secondFileV3); + + history = await s.getHistory(secondFile); t.is(history.length, 3); - document.slug = secondFileNewDirectory; - document.title = secondFileV4; - document.content = secondFileV4; - await s.update({ document, originalSlug: secondFile }); - all = await s.all(); + await s.update({ + document: { + content: secondFileV4, + createDate: undefined, + html: '', + slug: secondFileNewDirectory, + tags: ['test'], + title: secondFileV4, + updateDate: undefined, + }, + originalSlug: secondFile, + }); + all = Object.values(s.all()); t.is(all.length, 2); - t.is(all[1].title, document.title); - await s.refresh(); - history = await s.getHistory(document.slug); + t.is(all[1].title, secondFileV4); + + history = await s.getHistory(secondFileNewDirectory); t.is(history.length, 4); t.is(fs.existsSync(`${config.history_directory}/second-file-new-directory`), true); @@ -621,168 +700,210 @@ test('update({ document, originalSlug }): renames the history directory if it ex test('update({ document, originalSlug }): updates the file on disk with missing fields', async (t) => { let all; const s = new StorageProvider(config); - const document = { + await s.add({ content: '', createDate: undefined, html: '', slug: secondFile, title: secondFileV1, updateDate: undefined, - }; - await s.add(document); - all = await s.all(); + }); + all = Object.values(s.all()); t.is(all.length, 2); - document.title = secondFileV2; - await s.update({ document, originalSlug: secondFile }); - all = await s.all(); + await s.update({ + document: { + content: '', + createDate: undefined, + html: '', + slug: secondFile, + title: secondFileV2, + updateDate: undefined, + }, + originalSlug: secondFile, + }); + all = Object.values(s.all()); t.is(all.length, 2); - t.is(all[1].title, document.title); + t.is(all[1].title, secondFileV2); }); test('update({ document, originalSlug }): does not update when file exists', async (t) => { let all; const s = new StorageProvider(config); - const document = { + await s.add({ content: '', createDate: undefined, html: '', slug: secondFile, title: secondFileV1, updateDate: undefined, - }; - await s.add(document); - all = await s.all(); + }); + all = Object.values(s.all()); t.is(all.length, 2); - document.title = secondFileV2; - await s.update({ document, originalSlug: exampleSlug }); - all = await s.all(); + await s.update({ + content: '', + createDate: undefined, + html: '', + slug: secondFile, + title: secondFileV2, + updateDate: undefined, + originalSlug: exampleSlug, + }); + all = Object.values(s.all()); t.is(all.length, 2); t.is(all[1].title, secondFileV1); }); test('update({ document, originalSlug }): adds a document if the one to update is no found', async (t) => { const s = new StorageProvider(config); - const document = { - content: '', - createDate: 1, - customData: {}, - html: '', - slug: 'third-file', - tags: [], - title: 'third file', - updateDate: 1, - }; - await s.update({ document, originalSlug: '' }); - const all = await s.all(); + await s.update({ + document: { + content: '', + createDate: 1, + html: '', + slug: 'third-file', + tags: [], + title: 'third file', + updateDate: 1, + }, + originalSlug: '', + }); + const all = Object.values(s.all()); t.is(all.length, 2); }); test('update({ document, originalSlug }): updates the file on disk without updating timestamps', async (t) => { let all; const s = new StorageProvider({ ...config, update_timestamps: false }); - const document = { + await s.add({ content: '', createDate: undefined, - customData: { test: true }, html: '', slug: secondFile, tags: ['test'], title: secondFileV1, updateDate: undefined, - }; - await s.add(document); - all = await s.all(); + }); + all = Object.values(s.all()); t.is(all.length, 2); - document.title = secondFileV2; - await s.update({ document, originalSlug: secondFile }); - all = await s.all(); + await s.update({ + document: { + content: '', + createDate: undefined, + html: '', + slug: secondFile, + tags: ['test'], + title: secondFileV2, + updateDate: undefined, + }, + originalSlug: secondFile, + }); + all = Object.values(s.all()); t.is(all.length, 2); - t.deepEqual(all[1], document); + t.deepEqual(all[1], { + content: '', + createDate: undefined, + html: '', + slug: secondFile, + tags: ['test'], + title: secondFileV2, + updateDate: undefined, + }); }); test('update({ document, originalSlug }): updates the file on disk without updating history', async (t) => { let all; const s = new StorageProvider({ ...config, update_timestamps: false, use_history: false }); - const document = { + + await s.add({ content: '', createDate: undefined, - customData: { test: true }, html: '', slug: secondFile, tags: ['test'], title: secondFileV1, updateDate: undefined, - }; - await s.add(document); - all = await s.all(); + }); + all = Object.values(s.all()); t.is(all.length, 2); - document.title = secondFileV2; - await s.update({ document, originalSlug: secondFile }); - all = await s.all(); + await s.update({ + document: { + content: '', + createDate: undefined, + html: '', + slug: secondFile, + tags: ['test'], + updateDate: undefined, + title: secondFileV2, + }, + originalSlug: secondFile, + }); + all = Object.values(s.all()); t.is(all.length, 2); - t.deepEqual(all[1], document); + t.deepEqual(all[1], { + content: '', + createDate: undefined, + html: '', + slug: secondFile, + tags: ['test'], + updateDate: undefined, + title: secondFileV2, + }); }); test('delete(document): removes the file from disk', async (t) => { let all; const s = new StorageProvider(config); - const document = { + await s.add({ content: '', createDate: 1, - customData: {}, html: '', slug: secondFile, tags: [], title: secondFileV1, updateDate: 1, - }; - await s.add(document); - all = await s.all(); + }); + all = Object.values(s.all()); t.is(all.length, 2); - await s.delete(document.slug); - all = await s.all(); + await s.delete(secondFile); + all = Object.values(s.all()); t.is(all.length, 1); }); test('delete(document): removes the file from disk without history', async (t) => { let all; const s = new StorageProvider({ ...config, use_history: false }); - const document = { + await s.add({ content: '', createDate: 1, - customData: {}, html: '', slug: secondFile, tags: [], title: secondFileV1, updateDate: 1, - }; - await s.add(document); - all = await s.all(); + }); + all = Object.values(s.all()); t.is(all.length, 2); - await s.delete(document.slug); - all = await s.all(); + await s.delete(secondFile); + all = Object.values(s.all()); t.is(all.length, 1); }); test('delete(document): does nothing when no file is found', async (t) => { let all; const s = new StorageProvider(config); - const document = { + await s.add({ content: '', createDate: undefined, - customData: {}, html: '', slug: secondFile, tags: [], title: secondFileV1, updateDate: undefined, - }; - await s.add(document); - all = await s.all(); + }); + all = Object.values(s.all()); t.is(all.length, 2); await s.delete('slug'); - all = await s.all(); + all = Object.values(s.all()); t.is(all.length, 2); }); diff --git a/types/index.d.ts b/types/index.d.ts index e70f03e..1e1c5eb 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,5 +1,5 @@ declare module "query-tools" { - export function processQuery(query: string, objects: object[]): object[]; + export function processQuery(query: string, objects: object[]): object[] | number; } declare module "storage-provider" { export = StorageProvider; @@ -7,11 +7,12 @@ declare module "storage-provider" { constructor(config: { content_directory: string; history_directory: string; - extension: string; - update_timestamps: boolean; - use_history: boolean; - spaces_document: number; - spaces_history: number; + extension?: string; + update_timestamps?: boolean; + use_history?: boolean; + use_cache?: boolean; + spaces_document?: number; + spaces_history?: number; }); config: { content_directory: string; @@ -19,18 +20,20 @@ declare module "storage-provider" { extension: string; update_timestamps: boolean; use_history: boolean; + use_cache: boolean; spaces_document: number; spaces_history: number; }; - documents: any[]; - all(): Promise; - getQuery(query: string): Promise; - get(slug: string): Promise; - getHistory(slug: string): Promise; + refresh: boolean; + documents: {}; + all(): object; + getQuery(query: string): Promise; + get(slug: string): Promise; + getHistory(slug: string): Promise; getRevision({ slug, revision }: { slug: string; - revision: number; - }): Promise; + revision: string | number; + }): Promise; add(document: UttoriDocument): Promise; private updateValid; update({ document, originalSlug }: { @@ -39,7 +42,6 @@ declare module "storage-provider" { }): Promise; delete(slug: string): Promise; updateHistory(slug: string, content: string, originalSlug?: string): Promise; - refresh(): Promise; } namespace StorageProvider { export { UttoriDocument };