From d4476da24e961c3bbdc3a50b5bc32fe82ced6ff0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Sun, 8 Dec 2019 20:18:50 +0100 Subject: [PATCH 01/48] feat(layered-storage): add a new storage for options This is intended to replace the prototype plus hacks insanity used at the moment. However this is still WIP. There is no documentations yet and more testing is necessary. TODO: - Add off. - Write docs. - Probably some other things too. In a quick test I was able to resolve the issue discussed in visjs/vis-network#178 and visjs/vis-network#213 with just a few lines of code. Which is much better than the massive mess of weird hacks that doesn't work reliably anyway. Putting this to use will be a lot of work but fortunately it should be possible to do it in parts. I would first use this in LayoutEngine and EdgesHandler to resolve the forementioned issues and then probably one module at the time. Features: - Encapsulates options merging. - Explicit layer/segment/key structure instead of prototype chains. - Observable. - Overrides. * - Type safety in TypeScript. * Hierarchical layout is incompatible with smooth edges and has to disable them. Overrides combined with observing easily and elegently solve that. See the forementioned issues for current state. --- .eslintrc.js | 2 + package-lock.json | 93 +++++++++ package.json | 1 + rollup.config.js | 5 + src/layered-storage/common.ts | 6 + src/layered-storage/core.ts | 124 ++++++++++++ src/layered-storage/index.ts | 7 + src/layered-storage/layered-storage.ts | 214 ++++++++++++++++++++ src/layered-storage/segment.ts | 58 ++++++ src/layered-storage/transactions.ts | 258 ++++++++++++++++++++++++ src/util.ts | 1 + test/layered-storage/all-combined.ts | 157 ++++++++++++++ test/layered-storage/events.ts | 172 ++++++++++++++++ test/layered-storage/index.test.ts | 15 ++ test/layered-storage/multiple-keys.ts | 112 ++++++++++ test/layered-storage/multiple-layers.ts | 137 +++++++++++++ test/layered-storage/segmented-layer.ts | 118 +++++++++++ test/layered-storage/single-layer.ts | 78 +++++++ tsconfig.code.json | 9 + 19 files changed, 1567 insertions(+) create mode 100644 src/layered-storage/common.ts create mode 100644 src/layered-storage/core.ts create mode 100644 src/layered-storage/index.ts create mode 100644 src/layered-storage/layered-storage.ts create mode 100644 src/layered-storage/segment.ts create mode 100644 src/layered-storage/transactions.ts create mode 100644 test/layered-storage/all-combined.ts create mode 100644 test/layered-storage/events.ts create mode 100644 test/layered-storage/index.test.ts create mode 100644 test/layered-storage/multiple-keys.ts create mode 100644 test/layered-storage/multiple-layers.ts create mode 100644 test/layered-storage/segmented-layer.ts create mode 100644 test/layered-storage/single-layer.ts create mode 100644 tsconfig.code.json diff --git a/.eslintrc.js b/.eslintrc.js index 5dc3e7b6d..dac17b72f 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -53,6 +53,8 @@ module.exports = { // Empty functions are useful sometimes. "@typescript-eslint/no-empty-function": "off", + // This would be great if TypeScript was perfect but sometimes tsc can't infer the correct type. + '@typescript-eslint/no-non-null-assertion': 'off', // This is really crazy given the functions in this package. "@typescript-eslint/no-explicit-any": "off", // These are hoisted, I have no idea why it reports them by default. diff --git a/package-lock.json b/package-lock.json index 998f81750..6b0ef7685 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16148,6 +16148,99 @@ "terser": "^4.1.0" } }, + "rollup-plugin-typescript2": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/rollup-plugin-typescript2/-/rollup-plugin-typescript2-0.25.3.tgz", + "integrity": "sha512-ADkSaidKBovJmf5VBnZBZe+WzaZwofuvYdzGAKTN/J4hN7QJCFYAq7IrH9caxlru6T5qhX41PNFS1S4HqhsGQg==", + "dev": true, + "requires": { + "find-cache-dir": "^3.0.0", + "fs-extra": "8.1.0", + "resolve": "1.12.0", + "rollup-pluginutils": "2.8.1", + "tslib": "1.10.0" + }, + "dependencies": { + "find-cache-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.1.0.tgz", + "integrity": "sha512-zw+EFiNBNPgI2NTrKkDd1xd7q0cs6wr/iWnr/oUkI0yF9K9GqQ+riIt4aiyFaaqpaWbxPrJXHI+QvmNUQbX+0Q==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.0", + "pkg-dir": "^4.1.0" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "make-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.0.0.tgz", + "integrity": "sha512-grNJDhb8b1Jm1qeqW5R/O63wUo4UXo2v2HMic6YT9i/HBlF93S8jkMgH7yugvY9ABDShH4VZMn8I+U8+fCNegw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "resolve": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, "rollup-pluginutils": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.1.tgz", diff --git a/package.json b/package.json index 403cbec42..90b53697b 100644 --- a/package.json +++ b/package.json @@ -125,6 +125,7 @@ "rollup-plugin-copy-glob": "^0.3.1", "rollup-plugin-node-resolve": "^5.2.0", "rollup-plugin-terser": "^5.1.3", + "rollup-plugin-typescript2": "^0.25.3", "semantic-release": "^16.0.0", "sinon": "^8.0.1", "snap-shot-it": "^7.9.1", diff --git a/rollup.config.js b/rollup.config.js index 5206f551a..bdaef31c2 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -2,6 +2,7 @@ import babel from "rollup-plugin-babel"; import commonjs from "rollup-plugin-commonjs"; import copyGlob from "rollup-plugin-copy-glob"; import resolve from "rollup-plugin-node-resolve"; +import typescript from "rollup-plugin-typescript2"; import { generateHeader } from "vis-dev-utils"; import { terser } from "rollup-plugin-terser"; @@ -12,6 +13,10 @@ const commonPlugins = [ extensions: [".ts", ".js", ".json"] }), commonjs(), + typescript({ + objectHashIgnoreUnknownHack: true, + tsconfig: "tsconfig.code.json" + }), babel({ extensions: [".ts", ".js"], runtimeHelpers: true diff --git a/src/layered-storage/common.ts b/src/layered-storage/common.ts new file mode 100644 index 000000000..ed472adcb --- /dev/null +++ b/src/layered-storage/common.ts @@ -0,0 +1,6 @@ +export type KeyRange = number | string | symbol; +export type KeyValueLookup = Record; +export type LayerRange = number; +export type Segment = boolean | number | object | string | symbol; + +export type EventCallback = (keys: Key[]) => void; diff --git a/src/layered-storage/core.ts b/src/layered-storage/core.ts new file mode 100644 index 000000000..a1c067d64 --- /dev/null +++ b/src/layered-storage/core.ts @@ -0,0 +1,124 @@ +import { KeyValueLookup, LayerRange, Segment } from "./common"; + +const reverseNumeric = (a: number, b: number): number => b - a; + +export class LayeredStorageCore< + KeyValue extends KeyValueLookup, + Layer extends LayerRange +> { + public monolithic = Symbol("Monolithic"); + + private _data = new Map< + Layer, + Map> + >(); + + private _layers: Layer[] = []; + private readonly _segments = new Set(); + + private readonly _topLevelCache = new Map< + Segment, + Map + >(); + + private _updateCache(key: keyof KeyValue): void { + segmentsLoop: for (const segment of this._segments) { + const sCache = + this._topLevelCache.get(segment) || + this._topLevelCache.set(segment, new Map()).get(segment)!; + + sCache.delete(key); + + for (const layer of this._layers) { + const lsData = this._getLSData(layer, segment); + if (lsData.has(key)) { + sCache.set(key, lsData.get(key)!); + continue segmentsLoop; + } + + const lmData = this._getLSData(layer, this.monolithic); + if (lmData.has(key)) { + sCache.set(key, lmData.get(key)!); + continue segmentsLoop; + } + } + } + } + + private _getLSData( + layer: Layer, + segment: Segment + ): Map { + let lData = this._data.get(layer); + if (lData == null) { + lData = new Map(); + this._data.set(layer, lData); + + this._layers = [...this._data.keys()].sort(reverseNumeric); + } + + let lsData = lData.get(segment); + if (lsData == null) { + lsData = new Map(); + lData.set(segment, lsData); + + this._segments.add(segment); + } + + return lsData; + } + + public get( + segment: Segment, + key: Key + ): KeyValue[Key] | undefined { + const sData = this._topLevelCache.get(segment); + if (sData == null) { + return; + } + + return sData.get(key); + } + + public has(segment: Segment, key: Key): boolean { + const sData = this._topLevelCache.get(segment); + if (sData == null) { + return false; + } + + return sData.has(key); + } + + public set( + layer: Layer, + segment: Segment, + key: Key, + value: KeyValue[Key] + ): void { + const lsData = this._getLSData(layer, segment); + lsData.set(key, value); + + this._updateCache(key); + } + + public delete( + layer: Layer, + segment: Segment, + key: Key + ): boolean { + const lsData = this._getLSData(layer, segment); + const didItExist = lsData.delete(key); + + this._updateCache(key); + + return didItExist; + } + + public deleteSegmentData(segment: Segment): void { + for (const lData of this._data.values()) { + lData.delete(segment); + } + this._topLevelCache.delete(segment); + this._segments.delete(segment); + } +} diff --git a/src/layered-storage/index.ts b/src/layered-storage/index.ts new file mode 100644 index 000000000..d7ef8993e --- /dev/null +++ b/src/layered-storage/index.ts @@ -0,0 +1,7 @@ +export { + LayeredStorage, + LayeredStorageSegmentTransaction, + LayeredStorageTransaction +} from "./layered-storage"; +export { LayeredStorageSegment } from "./segment"; +export { EventCallback, KeyValueLookup, LayerRange, Segment } from "./common"; diff --git a/src/layered-storage/layered-storage.ts b/src/layered-storage/layered-storage.ts new file mode 100644 index 000000000..bead904ff --- /dev/null +++ b/src/layered-storage/layered-storage.ts @@ -0,0 +1,214 @@ +import { + KeyRange, + KeyValueLookup, + LayerRange, + Segment, + EventCallback +} from "./common"; +import { LayeredStorageCore } from "./core"; +import { LayeredStorageSegment } from "./segment"; +import { + LayeredStorageSegmentTransaction, + LayeredStorageTransaction, + Listeners, + MonolithicTransaction, + SegmentTransaction +} from "./transactions"; + +export { + LayeredStorageSegmentTransaction, + LayeredStorageTransaction, + MonolithicTransaction, + SegmentTransaction +}; + +export class LayeredStorage< + KeyValue extends KeyValueLookup, + Layer extends LayerRange +> { + private _core = new LayeredStorageCore(); + private _listeners: Listeners = new Map(); + + public get( + segment: Segment, + key: Key + ): KeyValue[Key] | undefined; + public get(key: Key): KeyValue[Key] | undefined; + public get( + ...rest: [Key] | [Segment, Key] + ): KeyValue[Key] | undefined { + return rest.length === 1 + ? this._core.get(this._core.monolithic, rest[0]) + : this._core.get(rest[0], rest[1]); + } + + public has(segment: Segment, key: Key): boolean; + public has(key: Key): boolean; + public has(...rest: [keyof KeyValue] | [Segment, keyof KeyValue]): boolean { + return rest.length === 1 + ? this._core.has(this._core.monolithic, rest[0]) + : this._core.has(rest[0], rest[1]); + } + + public set( + layer: Layer, + segment: Segment, + key: Key, + value: KeyValue[Key] + ): void; + public set( + layer: Layer, + key: Key, + value: KeyValue[Key] + ): void; + public set( + ...rest: [Layer, Segment, Key, KeyValue[Key]] | [Layer, Key, KeyValue[Key]] + ): void { + this.runTransaction( + (transaction): void => + void (rest.length === 3 + ? transaction.set(rest[0], rest[1], rest[2]) + : transaction.set(rest[0], rest[1], rest[2], rest[3])) + ); + } + + public delete( + layer: Layer, + segment: Segment, + key: Key + ): KeyValue[Key]; + public delete( + layer: Layer, + key: Key + ): KeyValue[Key]; + public delete( + ...rest: [Layer, Segment, Key] | [Layer, Key] + ): void { + this.runTransaction( + (transaction): void => + void (rest.length === 2 + ? transaction.delete(rest[0], rest[1]) + : transaction.delete(rest[0], rest[1], rest[2])) + ); + } + + public openTransaction( + segment: Segment + ): LayeredStorageSegmentTransaction; + public openTransaction(): LayeredStorageTransaction; + public openTransaction( + segment?: Segment + ): + | LayeredStorageSegmentTransaction + | LayeredStorageTransaction { + return segment == null + ? new MonolithicTransaction(this._core, this._listeners) + : new SegmentTransaction( + this._core, + this._listeners, + segment + ); + } + + public runTransaction( + segment: Segment, + callback: ( + transaction: LayeredStorageSegmentTransaction + ) => void + ): void; + public runTransaction( + callback: (transaction: LayeredStorageTransaction) => void + ): void; + public runTransaction( + ...rest: + | [ + Segment, + ( + transaction: LayeredStorageSegmentTransaction + ) => void + ] + | [(transaction: LayeredStorageTransaction) => void] + ): void { + if (rest.length === 1) { + const callback = rest[0]; + + const transaction = this.openTransaction(); + + // If the following throws uncommited changes will be discarded. + callback(transaction); + + transaction.commit(); + } else { + const [segment, callback] = rest; + + const transaction = this.openTransaction(segment); + + // If the following throws uncommited changes will be discarded. + callback(transaction); + + transaction.commit(); + } + } + + public openSegment(segment: Segment): LayeredStorageSegment { + return new LayeredStorageSegment(this, segment); + } + public deleteSegmentData(segment: Segment): void { + return this._core.deleteSegmentData(segment); + } + + public on( + segment: Segment, + keys: (keyof KeyValue | RegExp) | (keyof KeyValue | RegExp)[], + callback: EventCallback + ): void; + public on( + keys: (keyof KeyValue | RegExp) | (keyof KeyValue | RegExp)[], + callback: EventCallback + ): void; + public on( + ...rest: + | [ + Segment, + (keyof KeyValue | RegExp) | (keyof KeyValue | RegExp)[], + EventCallback + ] + | [ + (keyof KeyValue | RegExp) | (keyof KeyValue | RegExp)[], + EventCallback + ] + ): void { + return rest.length === 2 + ? this._on( + this._core.monolithic, + Array.isArray(rest[0]) ? rest[0] : [rest[0]], + rest[1] + ) + : this._on( + rest[0], + Array.isArray(rest[1]) ? rest[1] : [rest[1]], + rest[2] + ); + } + private _on( + segment: Segment, + keys: (keyof KeyValue | RegExp)[], + callback: EventCallback + ): void { + const literals = keys.filter( + (value): value is keyof KeyValue => !(value instanceof RegExp) + ); + const functions = keys + .filter((value): value is RegExp => value instanceof RegExp) + .map((regexp): ((input: string) => boolean) => regexp.test.bind(regexp)); + + const test = (key: KeyRange): boolean => + literals.includes(key) || + (typeof key === "string" && functions.some((func): boolean => func(key))); + + ( + this._listeners.get(segment) || + this._listeners.set(segment, []).get(segment)! + ).push({ test, callback }); + } +} diff --git a/src/layered-storage/segment.ts b/src/layered-storage/segment.ts new file mode 100644 index 000000000..e3b78a897 --- /dev/null +++ b/src/layered-storage/segment.ts @@ -0,0 +1,58 @@ +import { KeyValueLookup, LayerRange, Segment, EventCallback } from "./common"; +import { + LayeredStorage, + LayeredStorageSegmentTransaction +} from "./layered-storage"; + +export class LayeredStorageSegment< + KeyValue extends KeyValueLookup, + Layer extends LayerRange +> { + public constructor( + private _layeredStorage: LayeredStorage, + private _segment: Segment + ) {} + + public get(key: Key): KeyValue[Key] | undefined { + return this._layeredStorage.get(this._segment, key); + } + + public has(key: Key): boolean { + return this._layeredStorage.has(this._segment, key); + } + + public set( + layer: Layer, + key: Key, + value: KeyValue[Key] + ): void { + return this._layeredStorage.set(layer, this._segment, key, value); + } + + public delete(layer: Layer, key: Key): void { + return this._layeredStorage.delete(layer, this._segment, key); + } + + public openTransaction(): LayeredStorageSegmentTransaction { + return this._layeredStorage.openTransaction(this._segment); + } + + public runTransaction( + callback: ( + transaction: LayeredStorageSegmentTransaction + ) => void + ): void { + return this._layeredStorage.runTransaction(this._segment, callback); + } + + public close(): void { + return this._layeredStorage.deleteSegmentData(this._segment); + } + + public on( + keys: (keyof KeyValue | RegExp) | (keyof KeyValue | RegExp)[], + callback: EventCallback + ): void { + return this._layeredStorage.on(this._segment, keys, callback); + } +} diff --git a/src/layered-storage/transactions.ts b/src/layered-storage/transactions.ts new file mode 100644 index 000000000..905997ea2 --- /dev/null +++ b/src/layered-storage/transactions.ts @@ -0,0 +1,258 @@ +import { + KeyRange, + KeyValueLookup, + LayerRange, + Segment, + EventCallback +} from "./common"; +import { LayeredStorageCore } from "./core"; + +export type Listeners = Map< + Segment, + { test: (key: KeyRange) => boolean; callback: EventCallback }[] +>; + +class TransactionCore< + KeyValue extends KeyValueLookup, + Layer extends LayerRange +> { + private _actions: (() => void)[] = []; + private _events = new Map>(); + + public constructor( + private _core: LayeredStorageCore, + private _listeners: Listeners + ) {} + + public set( + layer: Layer, + segment: Segment, + key: Key, + value: KeyValue[Key] + ): void { + this._actions.push( + this._core.set.bind(this._core, layer, segment, key, value) + ); + + this._addEvent(segment, key); + } + + public delete( + layer: Layer, + segment: Segment, + key: Key + ): void { + this._actions.push(this._core.delete.bind(this._core, layer, segment, key)); + + this._addEvent(segment, key); + } + + public commit(): void { + const actions = this._actions; + this._actions = []; + const events = this._events; + this._events = new Map(); + + actions.forEach((action): void => { + action(); + }); + + const monolithicKeySet = events.get(this._core.monolithic); + if (monolithicKeySet) { + const allKeys = [...monolithicKeySet]; + + [...this._listeners.values()] + .flat() + .forEach(({ test, callback }): void => { + const keys = allKeys.filter((key): boolean => test(key)); + if (keys.length === 0) { + return; + } + + callback(keys); + }); + + events.delete(this._core.monolithic); + } + + events.forEach((keySet, segment): void => { + const allKeys = [...keySet]; + + const segmentListeners = this._listeners.get(segment); + if (segmentListeners == null) { + return; + } + + segmentListeners.forEach(({ test, callback }): void => { + const keys = allKeys.filter((key): boolean => test(key)); + if (keys.length === 0) { + return; + } + + callback(keys); + }); + }); + } + + public revert(): void { + this._actions = []; + this._events = new Map(); + } + + private _addEvent(segment: Segment, key: keyof KeyValue): void { + ( + this._events.get(segment) || + this._events.set(segment, new Set()).get(segment)! + ).add(key); + } +} + +export interface LayeredStorageTransaction< + KeyValue extends KeyValueLookup, + Layer extends LayerRange +> { + set( + layer: Layer, + segment: Segment, + key: Key, + value: KeyValue[Key] + ): void; + set( + layer: Layer, + key: Key, + value: KeyValue[Key] + ): void; + + delete( + layer: Layer, + segment: Segment, + key: Key + ): void; + delete(layer: Layer, key: Key): void; + + commit(): void; + + revert(): void; +} + +export class MonolithicTransaction< + KeyValue extends KeyValueLookup, + Layer extends LayerRange +> implements LayeredStorageTransaction { + private readonly _transactionCore: TransactionCore; + + public constructor( + private readonly _storageCore: LayeredStorageCore, + private readonly _listeners: Listeners + ) { + this._transactionCore = new TransactionCore( + this._storageCore, + this._listeners + ); + } + + public set( + layer: Layer, + segment: Segment, + key: Key, + value: KeyValue[Key] + ): void; + public set( + layer: Layer, + key: Key, + value: KeyValue[Key] + ): void; + public set( + ...rest: [Layer, Segment, Key, KeyValue[Key]] | [Layer, Key, KeyValue[Key]] + ): void { + return rest.length === 3 + ? this._transactionCore.set( + rest[0], + this._storageCore.monolithic, + rest[1], + rest[2] + ) + : this._transactionCore.set(rest[0], rest[1], rest[2], rest[3]); + } + + public delete( + layer: Layer, + segment: Segment, + key: Key + ): void; + public delete(layer: Layer, key: Key): void; + public delete( + ...rest: [Layer, Segment, Key] | [Layer, Key] + ): void { + return rest.length === 2 + ? this._transactionCore.delete( + rest[0], + this._storageCore.monolithic, + rest[1] + ) + : this._transactionCore.delete(rest[0], rest[1], rest[2]); + } + + public commit(): void { + return this._transactionCore.commit(); + } + + public revert(): void { + return this._transactionCore.revert(); + } +} + +export interface LayeredStorageSegmentTransaction< + KeyValue extends KeyValueLookup, + Layer extends LayerRange +> { + set( + layer: Layer, + key: Key, + value: KeyValue[Key] + ): void; + + delete(layer: Layer, key: Key): void; + + commit(): void; + + revert(): void; +} + +export class SegmentTransaction< + KeyValue extends KeyValueLookup, + Layer extends LayerRange +> implements LayeredStorageSegmentTransaction { + private readonly _transactionCore: TransactionCore; + + public constructor( + private readonly _storageCore: LayeredStorageCore, + private readonly _listeners: Listeners, + private readonly _segment: Segment + ) { + this._transactionCore = new TransactionCore( + this._storageCore, + this._listeners + ); + } + + public set( + layer: Layer, + key: Key, + value: KeyValue[Key] + ): void { + return this._transactionCore.set(layer, this._segment, key, value); + } + + public delete(layer: Layer, key: Key): void { + return this._transactionCore.delete(layer, this._segment, key); + } + + public commit(): void { + return this._transactionCore.commit(); + } + + public revert(): void { + return this._transactionCore.revert(); + } +} diff --git a/src/util.ts b/src/util.ts index 3de2b2424..0b3aebc8f 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,6 +1,7 @@ // utility functions export { uuid4 as randomUUID } from "vis-uuid"; +export * from "./layered-storage"; // parse ASP.Net Date pattern, // for example '/Date(1198908717056)/' or '/Date(1198908717056-0700)/' diff --git a/test/layered-storage/all-combined.ts b/test/layered-storage/all-combined.ts new file mode 100644 index 000000000..4a7de93d5 --- /dev/null +++ b/test/layered-storage/all-combined.ts @@ -0,0 +1,157 @@ +import { LayeredStorage } from "../../src/layered-storage"; +import { deepFreeze } from "../helpers"; +import { expect } from "chai"; + +type KV = Record; + +const allUndefined = deepFreeze({ + "test.value1": undefined, + "test.value2": undefined, + "test.value3": undefined +}); + +const expectedResult = deepFreeze({ + monolithic: { + "test.value1": 5, + "test.value2": undefined, + "test.value3": undefined + }, + a: { + "test.value1": 5, + "test.value2": 2, + "test.value3": undefined + }, + b: { + "test.value1": 5, + "test.value2": 8, + "test.value3": 9 + }, + c: { + "test.value1": 3, + "test.value2": 7, + "test.value3": undefined + } +}); + +const expectedResultMinusC = deepFreeze({ + monolithic: expectedResult.monolithic, + a: expectedResult.a, + b: expectedResult.b, + c: allUndefined +}); + +const expectedResultMinusAC = deepFreeze({ + monolithic: expectedResult.monolithic, + a: allUndefined, + b: expectedResult.b, + c: allUndefined +}); + +const expectedResultMinusABC = deepFreeze({ + monolithic: expectedResult.monolithic, + a: allUndefined, + b: allUndefined, + c: allUndefined +}); + +export function allCombined(): void { + describe("All combined", function(): void { + it("Main instance only", function(): void { + const ls = new LayeredStorage(); + + const getData = (): unknown => { + const data: any = {}; + for (const segment of ["monolithic", "a", "b", "c"]) { + data[segment] = {}; + for (const key of ["test.value1", "test.value2", "test.value3"]) { + data[segment][key] = + segment === "monolithic" ? ls.get(key) : ls.get(segment, key); + } + } + + return data; + }; + + ls.set(1, "b", "test.value3", 6); + ls.set(1, "c", "test.value2", 7); + ls.set(1, "a", "test.value1", 1); + ls.delete(4, "b", "test.value1"); + ls.set(4, "test.value1", 4); + ls.set(4, "b", "test.value3", 9); + ls.delete(4, "c", "test.value1"); + ls.delete(9, "test.value1"); + ls.set(9, "test.value3", 3); + ls.set(4, "a", "test.value2", 2); + ls.set(9, "b", "test.value2", 8); + ls.delete(9, "test.value3"); + ls.set(9, "test.value1", 5); + ls.delete(4, "a", "test.value1"); + ls.set(9, "c", "test.value1", 3); + expect(getData()).to.deep.equal(expectedResult); + + ls.deleteSegmentData("c"); + expect(getData()).to.deep.equal(expectedResultMinusC); + + ls.deleteSegmentData("a"); + expect(getData()).to.deep.equal(expectedResultMinusAC); + + ls.deleteSegmentData("b"); + expect(getData()).to.deep.equal(expectedResultMinusABC); + }); + + it("Main and segment instances", function(): void { + const ls = new LayeredStorage(); + + const a = ls.openSegment("a"); + const b = ls.openSegment("b"); + const c = ls.openSegment("c"); + const segments = { a, b, c }; + + const getData = (): unknown => { + const data: any = {}; + for (const segment of [ + "monolithic" as const, + "a" as const, + "b" as const, + "c" as const + ]) { + data[segment] = {}; + for (const key of ["test.value1", "test.value2", "test.value3"]) { + data[segment][key] = + segment === "monolithic" + ? ls.get(key) + : segments[segment].get(key); + } + } + + return data; + }; + + b.set(1, "test.value3", 6); + c.set(1, "test.value2", 7); + a.set(1, "test.value1", 1); + b.delete(4, "test.value1"); + ls.set(4, "test.value1", 4); + b.set(4, "test.value3", 9); + c.delete(4, "test.value1"); + ls.delete(9, "test.value1"); + ls.set(9, "test.value3", 3); + a.set(4, "test.value2", 2); + b.set(9, "test.value2", 8); + ls.delete(9, "test.value3"); + ls.set(9, "test.value1", 5); + a.delete(4, "test.value1"); + c.set(9, "test.value1", 3); + expect(getData()).to.deep.equal(expectedResult); + + c.close(); + expect(getData()).to.deep.equal(expectedResultMinusC); + + a.close(); + expect(getData()).to.deep.equal(expectedResultMinusAC); + + b.close(); + expect(getData()).to.deep.equal(expectedResultMinusABC); + }); + }); +} diff --git a/test/layered-storage/events.ts b/test/layered-storage/events.ts new file mode 100644 index 000000000..129c993c5 --- /dev/null +++ b/test/layered-storage/events.ts @@ -0,0 +1,172 @@ +import { LayeredStorage } from "../../src/layered-storage"; +import { assert, spy } from "sinon"; +import { deepFreeze } from "../helpers"; + +type KV = Record; + +export function events(): void { + describe("Events", function(): void { + deepFreeze([ + { name: "Single regex", keys: /^test\..*$/ }, + { name: "Single regex in an array", keys: [/^test\..*$/] }, + { name: "Literals", keys: ["test.value1", "test.value2", "test.value3"] }, + { name: "Two regexes", keys: [/^nonexistent$/, /^test\..*$/] }, + { + name: "Regex that never passes and literals that do", + keys: [/^nonexistent$/, "test.value1", "test.value2", "test.value3"] + }, + { + name: "Literals that never pass and regex that does", + keys: ["nonexistent", /^test\..*$/] + } + ]).forEach(({ name, keys }): void => { + describe(name, function(): void { + it("Monolithic", function(): void { + const ms = new LayeredStorage(); + + const msSpy = spy(); + + ms.on(keys, msSpy); + assert.notCalled(msSpy); + + ms.set(4, "other.value1", 7); + assert.notCalled(msSpy); + + ms.set(1, "test.value1", 6); + assert.callCount(msSpy, 1); + assert.calledWithExactly(msSpy.lastCall, ["test.value1"]); + + ms.set(4, "test.value2", 5); + assert.callCount(msSpy, 2); + assert.calledWithExactly(msSpy.lastCall, ["test.value2"]); + + ms.delete(4, "test.value3"); + assert.callCount(msSpy, 3); + assert.calledWithExactly(msSpy.lastCall, ["test.value3"]); + + ms.delete(1, "test.value1"); + assert.callCount(msSpy, 4); + assert.calledWithExactly(msSpy.lastCall, ["test.value1"]); + }); + + it("Segmened", function(): void { + const ms = new LayeredStorage(); + const ss = ms.openSegment("a"); + + const msSpy = spy(); + const ssSpy = spy(); + + ms.on(keys, msSpy); + ss.on(keys, ssSpy); + assert.notCalled(msSpy); + assert.notCalled(ssSpy); + + ms.set(4, "other.value1", 7); + assert.notCalled(msSpy); + assert.notCalled(ssSpy); + + ms.set(1, "test.value1", 6); + assert.callCount(msSpy, 1); + assert.callCount(ssSpy, 1); + assert.calledWithExactly(msSpy.lastCall, ["test.value1"]); + assert.calledWithExactly(ssSpy.lastCall, ["test.value1"]); + + ss.set(1, "test.value1", 6); + assert.callCount(msSpy, 1); + assert.callCount(ssSpy, 2); + assert.calledWithExactly(ssSpy.lastCall, ["test.value1"]); + + ms.set(4, "test.value2", 5); + assert.callCount(msSpy, 2); + assert.callCount(ssSpy, 3); + assert.calledWithExactly(msSpy.lastCall, ["test.value2"]); + assert.calledWithExactly(ssSpy.lastCall, ["test.value2"]); + + ms.delete(4, "test.value3"); + assert.callCount(msSpy, 3); + assert.callCount(ssSpy, 4); + assert.calledWithExactly(msSpy.lastCall, ["test.value3"]); + assert.calledWithExactly(ssSpy.lastCall, ["test.value3"]); + + ss.delete(4, "test.value2"); + assert.callCount(msSpy, 3); + assert.callCount(ssSpy, 5); + assert.calledWithExactly(ssSpy.lastCall, ["test.value2"]); + + ms.delete(1, "test.value1"); + assert.callCount(msSpy, 4); + assert.callCount(ssSpy, 6); + assert.calledWithExactly(msSpy.lastCall, ["test.value1"]); + assert.calledWithExactly(ssSpy.lastCall, ["test.value1"]); + }); + + it("Monolithic transaction", function(): void { + const ms = new LayeredStorage(); + const ss = ms.openSegment("a"); + + const msSpy = spy(); + const ssSpy = spy(); + + ms.on(keys, msSpy); + ss.on(keys, ssSpy); + assert.notCalled(msSpy); + assert.notCalled(ssSpy); + + ms.runTransaction((transaction): void => { + transaction.set(4, "other.value1", 7); + transaction.set(1, "test.value1", 6); + transaction.set(4, "test.value2", 5); + transaction.delete(4, "test.value3"); + transaction.delete(1, "test.value1"); + + assert.notCalled(msSpy); + assert.notCalled(ssSpy); + }); + assert.callCount(msSpy, 1); + assert.callCount(ssSpy, 1); + assert.calledWithExactly(msSpy.lastCall, [ + "test.value1", + "test.value2", + "test.value3" + ]); + assert.calledWithExactly(ssSpy.lastCall, [ + "test.value1", + "test.value2", + "test.value3" + ]); + }); + + it("Segmented transaction", function(): void { + const ms = new LayeredStorage(); + const ss = ms.openSegment("a"); + + const msSpy = spy(); + const ssSpy = spy(); + + ms.on(keys, msSpy); + ss.on(keys, ssSpy); + assert.notCalled(msSpy); + assert.notCalled(ssSpy); + + ss.runTransaction((transaction): void => { + transaction.set(4, "other.value1", 7); + transaction.set(1, "test.value1", 6); + transaction.set(4, "test.value2", 5); + transaction.delete(4, "test.value3"); + transaction.delete(1, "test.value1"); + + assert.notCalled(msSpy); + assert.notCalled(ssSpy); + }); + assert.callCount(msSpy, 0); + assert.callCount(ssSpy, 1); + assert.calledWithExactly(ssSpy.lastCall, [ + "test.value1", + "test.value2", + "test.value3" + ]); + }); + }); + }); + }); +} diff --git a/test/layered-storage/index.test.ts b/test/layered-storage/index.test.ts new file mode 100644 index 000000000..d00d6345e --- /dev/null +++ b/test/layered-storage/index.test.ts @@ -0,0 +1,15 @@ +import { allCombined } from "./all-combined"; +import { events } from "./events"; +import { multipleKeys } from "./multiple-keys"; +import { multipleLayers } from "./multiple-layers"; +import { segmentedLayer } from "./segmented-layer"; +import { singleLayer } from "./single-layer"; + +describe("Layered storage", function(): void { + allCombined(); + events(); + multipleKeys(); + multipleLayers(); + segmentedLayer(); + singleLayer(); +}); diff --git a/test/layered-storage/multiple-keys.ts b/test/layered-storage/multiple-keys.ts new file mode 100644 index 000000000..fb428c797 --- /dev/null +++ b/test/layered-storage/multiple-keys.ts @@ -0,0 +1,112 @@ +import { LayeredStorage } from "../../src/layered-storage"; +import { expect } from "chai"; + +interface KV { + "test.value1": boolean; + "test.value2": number; + "test.value3": string; +} + +export function multipleKeys(): void { + describe("Multiple keys", function(): void { + const testValue1: KV["test.value1"] = false; + const testValue2: KV["test.value2"] = 4; + const testValue3: KV["test.value3"] = "abc"; + + it("Set and get", function(): void { + const ls = new LayeredStorage(); + + ls.set(3, "test.value1", testValue1); + ls.set(3, "test.value2", testValue2); + ls.set(3, "test.value3", testValue3); + + expect( + ls.get("test.value1"), + "The same value that was set should be returned." + ).to.equal(testValue1); + expect( + ls.get("test.value2"), + "The same value that was set should be returned." + ).to.equal(testValue2); + expect( + ls.get("test.value3"), + "The same value that was set should be returned." + ).to.equal(testValue3); + }); + + it("Set and has", function(): void { + const ls = new LayeredStorage(); + + ls.set(3, "test.value1", testValue1); + ls.set(3, "test.value2", testValue2); + ls.set(3, "test.value3", testValue3); + + expect( + ls.has("test.value1"), + "This value was set and should be reported as present." + ).to.be.true; + expect( + ls.has("test.value2"), + "This value was set and should be reported as present." + ).to.be.true; + expect( + ls.has("test.value3"), + "This value was set and should be reported as present." + ).to.be.true; + }); + + it("Set, delete and get", function(): void { + const ls = new LayeredStorage(); + + expect( + ls.get("test.value2"), + "There is no value yet so it should be undefined." + ).to.be.undefined; + + ls.set(3, "test.value1", testValue1); + expect( + ls.get("test.value2"), + "Different value was set, undefined should be returned." + ).to.be.undefined; + + ls.set(3, "test.value2", testValue2); + expect( + ls.get("test.value2"), + "The value that was set should also be returned." + ).to.equal(testValue2); + + ls.delete(3, "test.value2"); + expect( + ls.get("test.value2"), + "Undefined should be returned for deleted values." + ).to.be.undefined; + }); + + it("Set, delete and has", function(): void { + const ls = new LayeredStorage(); + + expect( + ls.has("test.value2"), + "There is no value yet so it should be false." + ).to.be.false; + + ls.set(3, "test.value1", testValue1); + expect( + ls.has("test.value2"), + "Different value was set, false should be returned." + ).to.be.false; + + ls.set(3, "test.value2", testValue2); + expect( + ls.has("test.value2"), + "True should be returned for existing values." + ).to.be.true; + + ls.delete(3, "test.value2"); + expect( + ls.has("test.value2"), + "False should be returned for deleted values." + ).to.be.false; + }); + }); +} diff --git a/test/layered-storage/multiple-layers.ts b/test/layered-storage/multiple-layers.ts new file mode 100644 index 000000000..9fbf8236c --- /dev/null +++ b/test/layered-storage/multiple-layers.ts @@ -0,0 +1,137 @@ +import { LayeredStorage } from "../../src/layered-storage"; +import { deepFreeze } from "../helpers"; +import { expect } from "chai"; + +interface KV { + "test.value": { number: number; value: { string: string } }; +} + +export function multipleLayers(): void { + describe("Multiple layers", function(): void { + const testValue1: KV["test.value"] = deepFreeze({ + number: 1, + value: { string: "test" } + }); + const testValue2: KV["test.value"] = deepFreeze({ + number: 2, + value: { string: "test" } + }); + const testValue3: KV["test.value"] = deepFreeze({ + number: 3, + value: { string: "test" } + }); + const testValue4: KV["test.value"] = deepFreeze({ + number: 4, + value: { string: "test" } + }); + + it("Set and get", function(): void { + const ls = new LayeredStorage(); + + ls.set(1, "test.value", testValue1); + expect( + ls.get("test.value"), + "The first layer should be returned since it's the highest." + ).to.equal(testValue1); + + ls.set(2, "test.value", testValue2); + expect( + ls.get("test.value"), + "The second layer should be returned since it's the highest." + ).to.equal(testValue2); + + ls.set(4, "test.value", testValue4); + expect( + ls.get("test.value"), + "The fourth layer should be returned since it's the highest now." + ).to.equal(testValue4); + }); + + it("Set and has", function(): void { + const ls = new LayeredStorage(); + + expect( + ls.has("test.value"), + "There is no value yet so it shouldn't be reported as empty." + ).to.be.false; + + ls.set(3, "test.value", testValue3); + expect( + ls.has("test.value"), + "There is one value so it should be reported as present." + ).to.be.true; + + ls.set(2, "test.value", testValue2); + expect( + ls.has("test.value"), + "There are two value so it should be reported as present." + ).to.be.true; + }); + + it("Set, delete and get", function(): void { + const ls = new LayeredStorage(); + + expect( + ls.get("test.value"), + "There is no value yet so it should be undefined." + ).to.be.undefined; + + ls.set(3, "test.value", testValue3); + expect( + ls.get("test.value"), + "Layer three has a value that should be returned." + ).to.equal(testValue3); + + ls.set(2, "test.value", testValue2); + expect( + ls.get("test.value"), + "Layer three has a value that should be returned." + ).to.equal(testValue3); + + ls.delete(3, "test.value"); + expect( + ls.get("test.value"), + "Layer two has a value that should be returned." + ).to.equal(testValue2); + + ls.delete(2, "test.value"); + expect( + ls.get("test.value"), + "There isn't any value anymore so it should be undefined." + ).to.be.undefined; + }); + + it("Set, delete and has", function(): void { + const ls = new LayeredStorage(); + + expect( + ls.has("test.value"), + "There is no value yet so it should be reported as empty." + ).to.be.false; + + ls.set(3, "test.value", testValue3); + expect( + ls.has("test.value"), + "There is one value so it should be reported as present." + ).to.be.true; + + ls.set(2, "test.value", testValue2); + expect( + ls.has("test.value"), + "There are two value so it should be reported as present." + ).to.be.true; + + ls.delete(2, "test.value"); + expect( + ls.has("test.value"), + "There is one value so it should be reported as present." + ).to.be.true; + + ls.delete(3, "test.value"); + expect( + ls.has("test.value"), + "There isn't any value anymore so it should be reported as empty." + ).to.be.false; + }); + }); +} diff --git a/test/layered-storage/segmented-layer.ts b/test/layered-storage/segmented-layer.ts new file mode 100644 index 000000000..16c241ac5 --- /dev/null +++ b/test/layered-storage/segmented-layer.ts @@ -0,0 +1,118 @@ +import { LayeredStorage } from "../../src/layered-storage"; +import { deepFreeze } from "../helpers"; +import { expect } from "chai"; + +interface KV { + "test.value": { number: number; value: { string: string } }; +} + +export function segmentedLayer(): void { + describe("Segmented layer", function(): void { + const testValueA: KV["test.value"] = deepFreeze({ + number: 1, + value: { string: "A" } + }); + const testValueB: KV["test.value"] = deepFreeze({ + number: 2, + value: { string: "B" } + }); + const testValueC: KV["test.value"] = deepFreeze({ + number: 3, + value: { string: "C" } + }); + + const a = Symbol("A"); + const b = Symbol("B"); + const c = Symbol("C"); + + it("Set and get", function(): void { + const ls = new LayeredStorage(); + + ls.set(7, a, "test.value", testValueA); + ls.set(7, b, "test.value", testValueB); + ls.set(7, c, "test.value", testValueC); + + expect( + ls.get("test.value"), + "Only segmented values were set, this should be undefined." + ).to.be.undefined; + + expect( + ls.get(a, "test.value"), + "The A segment should return A test value." + ).to.equal(testValueA); + expect( + ls.get(b, "test.value"), + "The B segment should return B test value." + ).to.equal(testValueB); + expect( + ls.get(c, "test.value"), + "The C segment should return C test value." + ).to.equal(testValueC); + }); + + it("Set and has", function(): void { + const ls = new LayeredStorage(); + + ls.set(7, b, "test.value", testValueB); + + expect(ls.has("test.value"), "Only B segment was set and should be true.") + .to.be.false; + + expect( + ls.has(a, "test.value"), + "Only B segment was set and should be true." + ).to.be.false; + expect( + ls.has(b, "test.value"), + "Only B segment was set and should be true." + ).to.be.true; + expect( + ls.has(c, "test.value"), + "Only B segment was set and should be true." + ).to.be.false; + }); + + it("Set, delete and get", function(): void { + const ls = new LayeredStorage(); + + expect( + ls.get(c, "test.value"), + "There is no value yet so it should be undefined." + ).to.be.undefined; + + ls.set(7, c, "test.value", testValueC); + expect( + ls.get(c, "test.value"), + "Layer 7 segment C has a value that should be returned." + ).to.equal(testValueC); + + ls.delete(7, c, "test.value"); + expect( + ls.get(c, "test.value"), + "There isn't any value anymore so it should be undefined." + ).to.be.undefined; + }); + + it("Set, delete and has", function(): void { + const ls = new LayeredStorage(); + + expect( + ls.get(c, "test.value"), + "There is no value yet so it should be undefined." + ).to.be.undefined; + + ls.set(7, c, "test.value", testValueC); + expect( + ls.has(c, "test.value"), + "Layer 7 segment C has a value therefore it should return true." + ).to.be.true; + + ls.delete(7, c, "test.value"); + expect( + ls.has(c, "test.value"), + "There isn't any value anymore so it should return false." + ).to.be.false; + }); + }); +} diff --git a/test/layered-storage/single-layer.ts b/test/layered-storage/single-layer.ts new file mode 100644 index 000000000..a8b5464dd --- /dev/null +++ b/test/layered-storage/single-layer.ts @@ -0,0 +1,78 @@ +import { LayeredStorage } from "../../src/layered-storage"; +import { deepFreeze } from "../helpers"; +import { expect } from "chai"; + +interface KV { + "test.value": { number: number; value: { string: string } }; +} + +export function singleLayer(): void { + describe("Single layer", function(): void { + const testValue: KV["test.value"] = deepFreeze({ + number: 7, + value: { string: "test" } + }); + + it("Set and get", function(): void { + const ls = new LayeredStorage(); + + ls.set(0, "test.value", testValue); + expect( + ls.get("test.value"), + "The same value that was set should be returned." + ).to.equal(testValue); + }); + + it("Set and has", function(): void { + const ls = new LayeredStorage(); + + ls.set(0, "test.value", testValue); + expect( + ls.has("test.value"), + "The value should be reported as present after being set." + ).to.be.true; + }); + + it("Set, delete and get", function(): void { + const ls = new LayeredStorage(); + + expect( + ls.get("test.value"), + "There is no value yet so it should be undefined." + ).to.be.undefined; + + ls.set(0, "test.value", testValue); + expect( + ls.get("test.value"), + "The same value that was set should be returned." + ).to.equal(testValue); + + ls.delete(0, "test.value"); + expect( + ls.get("test.value"), + "Undefined should be returned for deleted values." + ).to.be.undefined; + }); + + it("Set, delete and has", function(): void { + const ls = new LayeredStorage(); + + expect( + ls.has("test.value"), + "There is no value yet so it should be reported as empty." + ).to.be.false; + + ls.set(0, "test.value", testValue); + expect( + ls.has("test.value"), + "The value should be reported as present after being set." + ).to.be.true; + + ls.delete(0, "test.value"); + expect( + ls.has("test.value"), + "The value should be reported as not present after being deleted." + ).to.be.false; + }); + }); +} diff --git a/tsconfig.code.json b/tsconfig.code.json new file mode 100644 index 000000000..ab4e993cd --- /dev/null +++ b/tsconfig.code.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig", + "compilerOptions": { + "declaration": false, + "declarationMap": false, + "noImplicitAny": false + }, + "exclude": ["test"] +} From 285977da3d57f1535c12f9b5327a307526208347 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Mon, 9 Dec 2019 10:07:35 +0100 Subject: [PATCH 02/48] feat(layered-storage): return off function from on --- src/layered-storage/layered-storage.ts | 26 ++++++++++++++++++++------ src/layered-storage/segment.ts | 2 +- src/layered-storage/transactions.ts | 9 +++++---- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/layered-storage/layered-storage.ts b/src/layered-storage/layered-storage.ts index bead904ff..74ff3516b 100644 --- a/src/layered-storage/layered-storage.ts +++ b/src/layered-storage/layered-storage.ts @@ -12,7 +12,8 @@ import { LayeredStorageTransaction, Listeners, MonolithicTransaction, - SegmentTransaction + SegmentTransaction, + Listener } from "./transactions"; export { @@ -161,11 +162,11 @@ export class LayeredStorage< segment: Segment, keys: (keyof KeyValue | RegExp) | (keyof KeyValue | RegExp)[], callback: EventCallback - ): void; + ): () => void; public on( keys: (keyof KeyValue | RegExp) | (keyof KeyValue | RegExp)[], callback: EventCallback - ): void; + ): () => void; public on( ...rest: | [ @@ -177,7 +178,7 @@ export class LayeredStorage< (keyof KeyValue | RegExp) | (keyof KeyValue | RegExp)[], EventCallback ] - ): void { + ): () => void { return rest.length === 2 ? this._on( this._core.monolithic, @@ -194,7 +195,7 @@ export class LayeredStorage< segment: Segment, keys: (keyof KeyValue | RegExp)[], callback: EventCallback - ): void { + ): () => void { const literals = keys.filter( (value): value is keyof KeyValue => !(value instanceof RegExp) ); @@ -206,9 +207,22 @@ export class LayeredStorage< literals.includes(key) || (typeof key === "string" && functions.some((func): boolean => func(key))); + const listener: Listener = { test, callback }; + ( this._listeners.get(segment) || this._listeners.set(segment, []).get(segment)! - ).push({ test, callback }); + ).push(listener); + + return this._off.bind(this, segment, listener); + } + + private _off(segment: Segment, listener: Listener): void { + const listeners = this._listeners.get(segment); + if (listeners == null) { + return; + } + + listeners.splice(listeners.indexOf(listener), 1); } } diff --git a/src/layered-storage/segment.ts b/src/layered-storage/segment.ts index e3b78a897..fd1dfe9b2 100644 --- a/src/layered-storage/segment.ts +++ b/src/layered-storage/segment.ts @@ -52,7 +52,7 @@ export class LayeredStorageSegment< public on( keys: (keyof KeyValue | RegExp) | (keyof KeyValue | RegExp)[], callback: EventCallback - ): void { + ): () => void { return this._layeredStorage.on(this._segment, keys, callback); } } diff --git a/src/layered-storage/transactions.ts b/src/layered-storage/transactions.ts index 905997ea2..6a4ee87f8 100644 --- a/src/layered-storage/transactions.ts +++ b/src/layered-storage/transactions.ts @@ -7,10 +7,11 @@ import { } from "./common"; import { LayeredStorageCore } from "./core"; -export type Listeners = Map< - Segment, - { test: (key: KeyRange) => boolean; callback: EventCallback }[] ->; +export type Listener = { + test: (key: KeyRange) => boolean; + callback: EventCallback; +}; +export type Listeners = Map[]>; class TransactionCore< KeyValue extends KeyValueLookup, From 4b49dc1ebd1091c1efeb7dbc327f91d4ad584f51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Mon, 9 Dec 2019 22:57:22 +0100 Subject: [PATCH 03/48] docs(layered-storage): add some docs --- src/layered-storage/layered-storage.ts | 26 ++++++++++++++++++++++++++ src/layered-storage/segment.ts | 9 +++++++++ 2 files changed, 35 insertions(+) diff --git a/src/layered-storage/layered-storage.ts b/src/layered-storage/layered-storage.ts index 74ff3516b..86bee25de 100644 --- a/src/layered-storage/layered-storage.ts +++ b/src/layered-storage/layered-storage.ts @@ -23,6 +23,19 @@ export { SegmentTransaction }; +/** + * Stores data in layers and optionally segments. + * + * @remarks + * - Higher layers override lowerlayers. + * - Each layer can be segmented using arbitrary values. + * - Segmented value overrides monolithic (nonsegmented) value. + * + * @typeparam KeyValue - Sets the value types associeated with their keys. + * (TS only, ignored in JS). + * @typeparam Layer - Sets the allowed layers. + * (TS only, ignored in JS). + */ export class LayeredStorage< KeyValue extends KeyValueLookup, Layer extends LayerRange @@ -151,9 +164,22 @@ export class LayeredStorage< } } + /** + * Create a new segmented instance for working with a single segment. + * + * @param segment - The segment that will be used by this instance. + * + * @returns A new segmented instance premanently bound to this instance. + */ public openSegment(segment: Segment): LayeredStorageSegment { return new LayeredStorageSegment(this, segment); } + + /** + * Delete all data belonging to a segment. + * + * @param segment - The segment whose data will be deleted. + */ public deleteSegmentData(segment: Segment): void { return this._core.deleteSegmentData(segment); } diff --git a/src/layered-storage/segment.ts b/src/layered-storage/segment.ts index fd1dfe9b2..d6a493865 100644 --- a/src/layered-storage/segment.ts +++ b/src/layered-storage/segment.ts @@ -4,6 +4,15 @@ import { LayeredStorageSegmentTransaction } from "./layered-storage"; +/** + * This is similar as `LayeredStorage` except that it is permanently bound to + * given `LayeredStorage` and can only access a single `Segment`. + * + * @typeparam KeyValue - Sets the value types associeated with their keys. + * (TS only, ignored in JS). + * @typeparam Layer - Sets the allowed layers. + * (TS only, ignored in JS). + */ export class LayeredStorageSegment< KeyValue extends KeyValueLookup, Layer extends LayerRange From 9fb537a101d0ad8e6b8d445f896bdb505dc0e6a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Wed, 11 Dec 2019 22:27:17 +0100 Subject: [PATCH 04/48] docs(layered-storage): add yet more docs About half should be done by now. --- src/layered-storage/layered-storage.ts | 118 +++++++++++++++++++++++- src/layered-storage/segment.ts | 71 +++++++++++++- test/layered-storage/all-combined.ts | 3 + test/layered-storage/events.ts | 3 + test/layered-storage/multiple-keys.ts | 4 + test/layered-storage/multiple-layers.ts | 4 + test/layered-storage/segmented-layer.ts | 3 + test/layered-storage/single-layer.ts | 3 + 8 files changed, 203 insertions(+), 6 deletions(-) diff --git a/src/layered-storage/layered-storage.ts b/src/layered-storage/layered-storage.ts index 86bee25de..fe51e7b14 100644 --- a/src/layered-storage/layered-storage.ts +++ b/src/layered-storage/layered-storage.ts @@ -43,11 +43,23 @@ export class LayeredStorage< private _core = new LayeredStorageCore(); private _listeners: Listeners = new Map(); + /** + * @param segment - Which segment to search through in addition to the monolithic part of the storage. + * @param key - The key corresponding to the requested value. + */ public get( segment: Segment, key: Key ): KeyValue[Key] | undefined; + /** + * @param key - The key corresponding to the requested value. + */ public get(key: Key): KeyValue[Key] | undefined; + /** + * Retrieve a value. + * + * @returns The value or undefined if not found. + */ public get( ...rest: [Key] | [Segment, Key] ): KeyValue[Key] | undefined { @@ -56,25 +68,51 @@ export class LayeredStorage< : this._core.get(rest[0], rest[1]); } + /** + * @param segment - Which segment to search through in addition to the monolithic part of the storage. + * @param key - The key corresponding to the requested value. + */ public has(segment: Segment, key: Key): boolean; + /** + * @param key - The key corresponding to the requested value. + */ public has(key: Key): boolean; + /** + * Check if a value is present. + * + * @returns True if found, false otherwise. + */ public has(...rest: [keyof KeyValue] | [Segment, keyof KeyValue]): boolean { return rest.length === 1 ? this._core.has(this._core.monolithic, rest[0]) : this._core.has(rest[0], rest[1]); } + /** + * @param layer - Which layer to save the value into. + * @param segment - Which segment to save the value into. + * @param key - Key that can be used to retrieve or overwrite this value later. + * @param value - The value to be saved. + */ public set( layer: Layer, segment: Segment, key: Key, value: KeyValue[Key] ): void; + /** + * @param layer - Which layer to save the value into. + * @param key - Key that can be used to retrieve or overwrite this value later. + * @param value - The value to be saved. + */ public set( layer: Layer, key: Key, value: KeyValue[Key] ): void; + /** + * Save a value. + */ public set( ...rest: [Layer, Segment, Key, KeyValue[Key]] | [Layer, Key, KeyValue[Key]] ): void { @@ -86,15 +124,27 @@ export class LayeredStorage< ); } + /** + * @param layer - Which layer to delete from. + * @param segment - Which segment to delete from. + * @param key - The key that identifies the value to be deleted. + */ public delete( layer: Layer, segment: Segment, key: Key ): KeyValue[Key]; + /** + * @param layer - Which layer to delete from. + * @param key - The key that identifies the value to be deleted. + */ public delete( layer: Layer, key: Key ): KeyValue[Key]; + /** + * Delete a value from the storage. + */ public delete( ...rest: [Layer, Segment, Key] | [Layer, Key] ): void { @@ -110,6 +160,19 @@ export class LayeredStorage< segment: Segment ): LayeredStorageSegmentTransaction; public openTransaction(): LayeredStorageTransaction; + /** + * Open a new transaction. + * + * @remarks + * The transaction accumulates changes but doesn't change the content of the + * storage until commit is called. + * + * @param segment - If segment is passed the transaction will be locked to + * given segment. Otherwise the monolithic portion and all the segments will + * be accessible. + * + * @returns The new transaction that can be used to set or delete values. + */ public openTransaction( segment?: Segment ): @@ -124,15 +187,32 @@ export class LayeredStorage< ); } + /** + * @param segment - The segment that this transaction will be limited to. + * @param callback - This callback will be called with the transaction as + * it's sole parameter. + */ public runTransaction( segment: Segment, callback: ( transaction: LayeredStorageSegmentTransaction ) => void ): void; + /** + * @param callback - This callback will be called with the transaction as + * it's sole parameter. + */ public runTransaction( callback: (transaction: LayeredStorageTransaction) => void ): void; + /** + * Run a new transaction. + * + * @remarks + * This is the same as `openTransaction` except that it automatically commits + * when the callback finishes execution. It is still possible to commit + * within the body of the callback though. + */ public runTransaction( ...rest: | [ @@ -169,7 +249,7 @@ export class LayeredStorage< * * @param segment - The segment that will be used by this instance. * - * @returns A new segmented instance premanently bound to this instance. + * @returns A new segmented instance permanently bound to this instance. */ public openSegment(segment: Segment): LayeredStorageSegment { return new LayeredStorageSegment(this, segment); @@ -181,18 +261,32 @@ export class LayeredStorage< * @param segment - The segment whose data will be deleted. */ public deleteSegmentData(segment: Segment): void { - return this._core.deleteSegmentData(segment); + this._core.deleteSegmentData(segment); } + /** + * @param segment - Which segment does the listener observe. + * @param keys - These determine which keys is the listener interested in. + * @param callback - Will be called when interesting changes are detected. + */ public on( segment: Segment, keys: (keyof KeyValue | RegExp) | (keyof KeyValue | RegExp)[], callback: EventCallback ): () => void; + /** + * @param keys - These determine which keys is the listener interested in. + * @param callback - Will be called when interesting changes are detected. + */ public on( keys: (keyof KeyValue | RegExp) | (keyof KeyValue | RegExp)[], callback: EventCallback ): () => void; + /** + * Bind a listener to given changes. + * + * @returns An off function that can be used to unbind the listener later. + */ public on( ...rest: | [ @@ -217,6 +311,16 @@ export class LayeredStorage< rest[2] ); } + + /** + * Bind a listener to given changes. + * + * @param segment - Which segment does the listener observe. + * @param keys - These determine which keys is the listener interested in. + * @param callback - Will be called when interesting changes are detected. + * + * @returns An off function that can be used to unbind the listener later. + */ private _on( segment: Segment, keys: (keyof KeyValue | RegExp)[], @@ -243,6 +347,16 @@ export class LayeredStorage< return this._off.bind(this, segment, listener); } + /** + * Remove given listener. + * + * @remarks + * This is internal method that should be exposed only as fully bound + * function returned from the on method. + * + * @param segment - Which segment does the listener observe. + * @param listener - The listener object itself. + */ private _off(segment: Segment, listener: Listener): void { const listeners = this._listeners.get(segment); if (listeners == null) { diff --git a/src/layered-storage/segment.ts b/src/layered-storage/segment.ts index d6a493865..08eb249ab 100644 --- a/src/layered-storage/segment.ts +++ b/src/layered-storage/segment.ts @@ -17,47 +17,110 @@ export class LayeredStorageSegment< KeyValue extends KeyValueLookup, Layer extends LayerRange > { + /** + * Create a new storage instance for given segment. + * + * @param _layeredStorage - The storage that this instance will be bound to. + * @param _segment - The segment this instance will manage. + */ public constructor( private _layeredStorage: LayeredStorage, private _segment: Segment ) {} + /** + * Retrieve a value. + * + * @param key - The key corresponding to the requested value. + * + * @returns The value or undefined if not found. + */ public get(key: Key): KeyValue[Key] | undefined { return this._layeredStorage.get(this._segment, key); } + /** + * Check if a value is present. + * + * @param key - The key corresponding to the requested value. + * + * @returns True if found, false otherwise. + */ public has(key: Key): boolean { return this._layeredStorage.has(this._segment, key); } + /** + * Save a value. + * + * @param layer - Which layer to save the value into. + * @param key - Key that can be used to retrieve or overwrite this value later. + * @param value - The value to be saved. + */ public set( layer: Layer, key: Key, value: KeyValue[Key] ): void { - return this._layeredStorage.set(layer, this._segment, key, value); + this._layeredStorage.set(layer, this._segment, key, value); } + /** + * Delete a value from the storage. + * + * @param layer - Which layer to delete from. + * @param key - The key that identifies the value to be deleted. + */ public delete(layer: Layer, key: Key): void { - return this._layeredStorage.delete(layer, this._segment, key); + this._layeredStorage.delete(layer, this._segment, key); } + /** + * Open a new transaction. + * + * @remarks + * The transaction accumulates changes but doesn't change the content of the + * storage until commit is called. + * + * @returns The new transaction that can be used to set or delete values. + */ public openTransaction(): LayeredStorageSegmentTransaction { return this._layeredStorage.openTransaction(this._segment); } + /** + * Run a new transaction. + * + * @remarks + * This is the same as `openTransaction` except that it automatically commits + * when the callback finishes execution. It is still possible to commit + * within the body of the callback though. + * + * @param callback - This callback will be called with the transaction as + */ public runTransaction( callback: ( transaction: LayeredStorageSegmentTransaction ) => void ): void { - return this._layeredStorage.runTransaction(this._segment, callback); + this._layeredStorage.runTransaction(this._segment, callback); } + /** + * Delete all data belonging to this segment. + */ public close(): void { - return this._layeredStorage.deleteSegmentData(this._segment); + this._layeredStorage.deleteSegmentData(this._segment); } + /** + * Bind a listener to given changes. + * + * @param keys - These determine which keys is the listener interested in. + * @param callback - Will be called when interesting changes are detected. + * + * @returns An off function that can be used to unbind the listener later. + */ public on( keys: (keyof KeyValue | RegExp) | (keyof KeyValue | RegExp)[], callback: EventCallback diff --git a/test/layered-storage/all-combined.ts b/test/layered-storage/all-combined.ts index 4a7de93d5..3acabd0b0 100644 --- a/test/layered-storage/all-combined.ts +++ b/test/layered-storage/all-combined.ts @@ -54,6 +54,9 @@ const expectedResultMinusABC = deepFreeze({ c: allUndefined }); +/** + * Test all mutatins including segmented mutations with Layered Storage. + */ export function allCombined(): void { describe("All combined", function(): void { it("Main instance only", function(): void { diff --git a/test/layered-storage/events.ts b/test/layered-storage/events.ts index 129c993c5..ed4e18207 100644 --- a/test/layered-storage/events.ts +++ b/test/layered-storage/events.ts @@ -4,6 +4,9 @@ import { deepFreeze } from "../helpers"; type KV = Record; +/** + * Test if mutations ant transactions trigger events as they should. + */ export function events(): void { describe("Events", function(): void { deepFreeze([ diff --git a/test/layered-storage/multiple-keys.ts b/test/layered-storage/multiple-keys.ts index fb428c797..b16d42006 100644 --- a/test/layered-storage/multiple-keys.ts +++ b/test/layered-storage/multiple-keys.ts @@ -7,6 +7,10 @@ interface KV { "test.value3": string; } +/** + * Test that multiple different values can be saved and retrieved each using + * it's own key. + */ export function multipleKeys(): void { describe("Multiple keys", function(): void { const testValue1: KV["test.value1"] = false; diff --git a/test/layered-storage/multiple-layers.ts b/test/layered-storage/multiple-layers.ts index 9fbf8236c..5e28a886e 100644 --- a/test/layered-storage/multiple-layers.ts +++ b/test/layered-storage/multiple-layers.ts @@ -6,6 +6,10 @@ interface KV { "test.value": { number: number; value: { string: string } }; } +/** + * Test that values can be set accross layers and override each other the way + * they should. + */ export function multipleLayers(): void { describe("Multiple layers", function(): void { const testValue1: KV["test.value"] = deepFreeze({ diff --git a/test/layered-storage/segmented-layer.ts b/test/layered-storage/segmented-layer.ts index 16c241ac5..03b0fe81e 100644 --- a/test/layered-storage/segmented-layer.ts +++ b/test/layered-storage/segmented-layer.ts @@ -6,6 +6,9 @@ interface KV { "test.value": { number: number; value: { string: string } }; } +/** + * Test that values can be set accross segments and later retrieved. + */ export function segmentedLayer(): void { describe("Segmented layer", function(): void { const testValueA: KV["test.value"] = deepFreeze({ diff --git a/test/layered-storage/single-layer.ts b/test/layered-storage/single-layer.ts index a8b5464dd..b30c3f3bd 100644 --- a/test/layered-storage/single-layer.ts +++ b/test/layered-storage/single-layer.ts @@ -6,6 +6,9 @@ interface KV { "test.value": { number: number; value: { string: string } }; } +/** + * Test that values can be set and retrieved from single monolithic layer. + */ export function singleLayer(): void { describe("Single layer", function(): void { const testValue: KV["test.value"] = deepFreeze({ From 357b9515bddbbf227ae38f55de566a0d4c100b5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Thu, 12 Dec 2019 17:33:05 +0100 Subject: [PATCH 05/48] docs(layered-storage): add docs to transactions --- src/layered-storage/transactions.ts | 211 +++++++++++++++++++++++----- 1 file changed, 178 insertions(+), 33 deletions(-) diff --git a/src/layered-storage/transactions.ts b/src/layered-storage/transactions.ts index 6a4ee87f8..b2bef8a57 100644 --- a/src/layered-storage/transactions.ts +++ b/src/layered-storage/transactions.ts @@ -7,24 +7,63 @@ import { } from "./common"; import { LayeredStorageCore } from "./core"; +/** + * Internal data structure for holding listener related data. + */ export type Listener = { test: (key: KeyRange) => boolean; callback: EventCallback; }; + +/** + * Internal data structure for holding listeners observing each segment. + */ export type Listeners = Map[]>; +/** + * This is used through composition to create monolithic and segmented + * transactions without massive code duplicities. + * + * @typeparam KeyValue - Sets the value types associeated with their keys. + * (TS only, ignored in JS). + * @typeparam Layer - Sets the allowed layers. + * (TS only, ignored in JS). + */ class TransactionCore< KeyValue extends KeyValueLookup, Layer extends LayerRange > { + /** + * Functions that perform requested mutations when executed without any + * arguments or this. Intended to be filled bound set and delete methods from + * `LayeredStorageCore`. + */ private _actions: (() => void)[] = []; + /** + * Lists the changes from `_actions` in a way for easy event dispatching. + */ private _events = new Map>(); + /** + * Create a new instance of transaction core. + * + * @param _storageCore - The core that this instance will save mutations to. + * @param _listeners - Listeners that should be notified after a transaction + * was commited. + */ public constructor( - private _core: LayeredStorageCore, + private _storageCore: LayeredStorageCore, private _listeners: Listeners ) {} + /** + * Queue set mutation. + * + * @param layer - Which layer to save the value into. + * @param segment - Which segment to save the value into. + * @param key - Key that can be used to retrieve or overwrite this value later. + * @param value - The value to be saved. + */ public set( layer: Layer, segment: Segment, @@ -32,33 +71,48 @@ class TransactionCore< value: KeyValue[Key] ): void { this._actions.push( - this._core.set.bind(this._core, layer, segment, key, value) + this._storageCore.set.bind(this._storageCore, layer, segment, key, value) ); this._addEvent(segment, key); } + /** + * Queue delete mutation. + * + * @param layer - Which layer to delete from. + * @param segment - Which segment to delete from. + * @param key - The key that identifies the value to be deleted. + */ public delete( layer: Layer, segment: Segment, key: Key ): void { - this._actions.push(this._core.delete.bind(this._core, layer, segment, key)); + this._actions.push( + this._storageCore.delete.bind(this._storageCore, layer, segment, key) + ); this._addEvent(segment, key); } + /** + * Commit all queued operations. + */ public commit(): void { + // Reset the structures for next transaction. const actions = this._actions; this._actions = []; const events = this._events; this._events = new Map(); + // Run the mutations. actions.forEach((action): void => { action(); }); - const monolithicKeySet = events.get(this._core.monolithic); + // Inform monolithic listeners about the mutations. + const monolithicKeySet = events.get(this._storageCore.monolithic); if (monolithicKeySet) { const allKeys = [...monolithicKeySet]; @@ -73,9 +127,10 @@ class TransactionCore< callback(keys); }); - events.delete(this._core.monolithic); + events.delete(this._storageCore.monolithic); } + // Inform listeners on segments about the changes. events.forEach((keySet, segment): void => { const allKeys = [...keySet]; @@ -95,11 +150,20 @@ class TransactionCore< }); } + /** + * Discard all queued operations. + */ public revert(): void { this._actions = []; this._events = new Map(); } + /** + * Record which segments and keys were affected by the queued mutations. + * + * @param segment - Which segment does this mutation belong to. + * @param key - Which key's value does this mutation affect. + */ private _addEvent(segment: Segment, key: keyof KeyValue): void { ( this._events.get(segment) || @@ -108,48 +172,97 @@ class TransactionCore< } } +/** + * A transaction working with the whole storage. + * + * @typeparam KeyValue - Sets the value types associeated with their keys. + * (TS only, ignored in JS). + * @typeparam Layer - Sets the allowed layers. + * (TS only, ignored in JS). + */ export interface LayeredStorageTransaction< KeyValue extends KeyValueLookup, Layer extends LayerRange > { + /** + * Queue a value to be set. + * + * @param layer - Which layer to save the value into. + * @param segment - Which segment to save the value into. + * @param key - Key that can be used to retrieve or overwrite this value later. + * @param value - The value to be saved. + */ set( layer: Layer, segment: Segment, key: Key, value: KeyValue[Key] ): void; + /** + * Queue a value to be set. + * + * @param layer - Which layer to save the value into. + * @param key - Key that can be used to retrieve or overwrite this value later. + * @param value - The value to be saved. + */ set( layer: Layer, key: Key, value: KeyValue[Key] ): void; + /** + * Queue a value to be deleted. + * + * @param layer - Which layer to delete from. + * @param segment - Which segment to delete from. + * @param key - The key that identifies the value to be deleted. + */ delete( layer: Layer, segment: Segment, key: Key ): void; + /** + * Queue a value to be deleted. + * + * @param layer - Which layer to delete from. + * @param key - The key that identifies the value to be deleted. + */ delete(layer: Layer, key: Key): void; + /** + * Commit all queued operations. + */ commit(): void; - revert(): void; + /** + * Discard all queued operations. + */ + abort(): void; } +/** @inheritdoc */ export class MonolithicTransaction< KeyValue extends KeyValueLookup, Layer extends LayerRange > implements LayeredStorageTransaction { private readonly _transactionCore: TransactionCore; - + private readonly _monolithic: symbol; + + /** + * Create a new transaction for given storage. + * + * @param storageCore - The core that this instance will save mutations to. + * @param listeners - Listeners that should be notified after a transaction + * was commited. + */ public constructor( - private readonly _storageCore: LayeredStorageCore, - private readonly _listeners: Listeners + storageCore: LayeredStorageCore, + listeners: Listeners ) { - this._transactionCore = new TransactionCore( - this._storageCore, - this._listeners - ); + this._monolithic = storageCore.monolithic; + this._transactionCore = new TransactionCore(storageCore, listeners); } public set( @@ -163,16 +276,12 @@ export class MonolithicTransaction< key: Key, value: KeyValue[Key] ): void; + /** @inheritdoc */ public set( ...rest: [Layer, Segment, Key, KeyValue[Key]] | [Layer, Key, KeyValue[Key]] ): void { return rest.length === 3 - ? this._transactionCore.set( - rest[0], - this._storageCore.monolithic, - rest[1], - rest[2] - ) + ? this._transactionCore.set(rest[0], this._monolithic, rest[1], rest[2]) : this._transactionCore.set(rest[0], rest[1], rest[2], rest[3]); } @@ -182,61 +291,94 @@ export class MonolithicTransaction< key: Key ): void; public delete(layer: Layer, key: Key): void; + /** @inheritdoc */ public delete( ...rest: [Layer, Segment, Key] | [Layer, Key] ): void { return rest.length === 2 - ? this._transactionCore.delete( - rest[0], - this._storageCore.monolithic, - rest[1] - ) + ? this._transactionCore.delete(rest[0], this._monolithic, rest[1]) : this._transactionCore.delete(rest[0], rest[1], rest[2]); } + /** @inheritdoc */ public commit(): void { return this._transactionCore.commit(); } - public revert(): void { + /** @inheritdoc */ + public abort(): void { return this._transactionCore.revert(); } } +/** @inheritdoc */ export interface LayeredStorageSegmentTransaction< KeyValue extends KeyValueLookup, Layer extends LayerRange > { + /** + * Queue a value to be set. + * + * @param layer - Which layer to save the value into. + * @param key - Key that can be used to retrieve or overwrite this value later. + * @param value - The value to be saved. + */ set( layer: Layer, key: Key, value: KeyValue[Key] ): void; + /** + * Queue a value to be deleted. + * + * @param layer - Which layer to delete from. + * @param key - The key that identifies the value to be deleted. + */ delete(layer: Layer, key: Key): void; + /** + * Commit all queued operations. + */ commit(): void; - revert(): void; + /** + * Discard all queued operations. + */ + abort(): void; } +/** + * A transaction working with a single segment. + * + * @typeparam KeyValue - Sets the value types associeated with their keys. + * (TS only, ignored in JS). + * @typeparam Layer - Sets the allowed layers. + * (TS only, ignored in JS). + */ export class SegmentTransaction< KeyValue extends KeyValueLookup, Layer extends LayerRange > implements LayeredStorageSegmentTransaction { private readonly _transactionCore: TransactionCore; + /** + * Create a new transaction for a segment of given storage. + * + * @param storageCore - The core that this instance will save mutations to. + * @param listeners - Listeners that should be notified after a transaction + * was commited. + * @param _segment - The segment this instance will manage. + */ public constructor( - private readonly _storageCore: LayeredStorageCore, - private readonly _listeners: Listeners, + storageCore: LayeredStorageCore, + listeners: Listeners, private readonly _segment: Segment ) { - this._transactionCore = new TransactionCore( - this._storageCore, - this._listeners - ); + this._transactionCore = new TransactionCore(storageCore, listeners); } + /** @inheritdoc */ public set( layer: Layer, key: Key, @@ -245,15 +387,18 @@ export class SegmentTransaction< return this._transactionCore.set(layer, this._segment, key, value); } + /** @inheritdoc */ public delete(layer: Layer, key: Key): void { return this._transactionCore.delete(layer, this._segment, key); } + /** @inheritdoc */ public commit(): void { return this._transactionCore.commit(); } - public revert(): void { + /** @inheritdoc */ + public abort(): void { return this._transactionCore.revert(); } } From 353f22083278a3503af0918167ff1da61d340619 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Thu, 12 Dec 2019 18:03:47 +0100 Subject: [PATCH 06/48] style(layered-storage): rename revert to abort It makes more sense given what it actually does. --- src/layered-storage/transactions.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/layered-storage/transactions.ts b/src/layered-storage/transactions.ts index b2bef8a57..3e5e8a30a 100644 --- a/src/layered-storage/transactions.ts +++ b/src/layered-storage/transactions.ts @@ -153,7 +153,7 @@ class TransactionCore< /** * Discard all queued operations. */ - public revert(): void { + public abort(): void { this._actions = []; this._events = new Map(); } @@ -307,7 +307,7 @@ export class MonolithicTransaction< /** @inheritdoc */ public abort(): void { - return this._transactionCore.revert(); + return this._transactionCore.abort(); } } @@ -399,6 +399,6 @@ export class SegmentTransaction< /** @inheritdoc */ public abort(): void { - return this._transactionCore.revert(); + return this._transactionCore.abort(); } } From 47bfa2fbc2e8dc7a14e00981670d134cccc0972b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Thu, 12 Dec 2019 18:29:47 +0100 Subject: [PATCH 07/48] docs(layered-storage): finish the docs --- src/layered-storage/core.ts | 102 ++++++++++++++++++++++++++++++++++-- 1 file changed, 98 insertions(+), 4 deletions(-) diff --git a/src/layered-storage/core.ts b/src/layered-storage/core.ts index a1c067d64..102d4ac13 100644 --- a/src/layered-storage/core.ts +++ b/src/layered-storage/core.ts @@ -2,53 +2,107 @@ import { KeyValueLookup, LayerRange, Segment } from "./common"; const reverseNumeric = (a: number, b: number): number => b - a; +/** + * Internal core to handle simple data storage, mutation and retrieval. Also + * handles the special monolithic segment. + * + * @typeparam KeyValue - Sets the value types associeated with their keys. + * (TS only, ignored in JS). + * @typeparam Layer - Sets the allowed layers. + * (TS only, ignored in JS). + */ export class LayeredStorageCore< KeyValue extends KeyValueLookup, Layer extends LayerRange > { + /** + * This is a special segment that is used as fallback if the requested + * segment doesn't have a value in given layer. + */ public monolithic = Symbol("Monolithic"); + /** + * Data stored as layer → segment → key → value. + */ private _data = new Map< Layer, Map> >(); + /** + * An ordered list of layers. The highest priority (equals highest number) + * layer is first. + */ private _layers: Layer[] = []; + + /** + * A set of segments that keeps track what segments have data in the storage. + */ private readonly _segments = new Set(); + /** + * This is used to speed up retrieval of data upon request. Since the storage + * is seen as mostly static this structure is populated up front and updated + * with each change. Thanks to this quering data from the storage is always + * just `Map.get().get()` away. + */ private readonly _topLevelCache = new Map< Segment, Map >(); + /** + * Update the value held in top level cache after it was changed in data. + * + * @param key - The key that was subject to the mutation. + */ private _updateCache(key: keyof KeyValue): void { + // Run the search for each segment to update the cached the top level value + // for each of them. segmentsLoop: for (const segment of this._segments) { const sCache = this._topLevelCache.get(segment) || this._topLevelCache.set(segment, new Map()).get(segment)!; + // Delete the outdated value. sCache.delete(key); + // Search the layers from highest to lowest priority. for (const layer of this._layers) { + // Check the segmented first and quit if found. const lsData = this._getLSData(layer, segment); if (lsData.has(key)) { sCache.set(key, lsData.get(key)!); continue segmentsLoop; } + // Check the monolithic and quit if found. const lmData = this._getLSData(layer, this.monolithic); if (lmData.has(key)) { sCache.set(key, lmData.get(key)!); continue segmentsLoop; } } + + // If nothing was found by now all the values for this key were deleted. } } + /** + * Fetch the key value map for given segment on given layer. Nonexistent + * layers and segments will be automatically created and the new instances + * returned. + * + * @param layer - Which layer to fetch. + * @param segment - Which segment to fetch from fetched layer. + * + * @returns Key value map. + */ private _getLSData( layer: Layer, segment: Segment ): Map { + // Get or create the requested layer. let lData = this._data.get(layer); if (lData == null) { lData = new Map(); @@ -57,6 +111,7 @@ export class LayeredStorageCore< this._layers = [...this._data.keys()].sort(reverseNumeric); } + // Get or create the requested segment on the layer. let lsData = lData.get(segment); if (lsData == null) { lsData = new Map(); @@ -68,6 +123,14 @@ export class LayeredStorageCore< return lsData; } + /** + * Retrieve a value. + * + * @param segment - Which segment to search through in addition to the monolithic part of the storage. + * @param key - The key corresponding to the requested value. + * + * @returns The value or undefined if not found. + */ public get( segment: Segment, key: Key @@ -80,6 +143,14 @@ export class LayeredStorageCore< return sData.get(key); } + /** + * Check if a value is present. + * + * @param segment - Which segment to search through in addition to the monolithic part of the storage. + * @param key - The key corresponding to the requested value. + * + * @returns True if found, false otherwise. + */ public has(segment: Segment, key: Key): boolean { const sData = this._topLevelCache.get(segment); if (sData == null) { @@ -89,6 +160,14 @@ export class LayeredStorageCore< return sData.has(key); } + /** + * Save a value. + * + * @param layer - Which layer to save the value into. + * @param segment - Which segment to save the value into. + * @param key - Key that can be used to retrieve or overwrite this value later. + * @param value - The value to be saved. + */ public set( layer: Layer, segment: Segment, @@ -101,19 +180,34 @@ export class LayeredStorageCore< this._updateCache(key); } + /** + * Delete a value from the storage. + * + * @param layer - Which layer to delete from. + * @param segment - Which segment to delete from. + * @param key - The key that identifies the value to be deleted. + */ public delete( layer: Layer, segment: Segment, key: Key - ): boolean { + ): void { const lsData = this._getLSData(layer, segment); - const didItExist = lsData.delete(key); + lsData.delete(key); this._updateCache(key); - - return didItExist; } + /** + * Delete all the data associeated with given segment. + * + * @remarks + * New data can be saved into the storage for the same segment right away. + * Also calling this with nonexistent segment or with segment that has no + * data is fine. + * + * @param segment - The segment whose data should be deleted. + */ public deleteSegmentData(segment: Segment): void { for (const lData of this._data.values()) { lData.delete(segment); From bfb7012178fceaf981f6d839cd169aa6a4c0838c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Thu, 12 Dec 2019 18:34:39 +0100 Subject: [PATCH 08/48] test(layered-storage): check that off unbinds listeners --- test/layered-storage/events.ts | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/test/layered-storage/events.ts b/test/layered-storage/events.ts index ed4e18207..f694ef19a 100644 --- a/test/layered-storage/events.ts +++ b/test/layered-storage/events.ts @@ -29,7 +29,7 @@ export function events(): void { const msSpy = spy(); - ms.on(keys, msSpy); + const msSpyOff = ms.on(keys, msSpy); assert.notCalled(msSpy); ms.set(4, "other.value1", 7); @@ -50,6 +50,10 @@ export function events(): void { ms.delete(1, "test.value1"); assert.callCount(msSpy, 4); assert.calledWithExactly(msSpy.lastCall, ["test.value1"]); + + msSpyOff(); + ms.set(4, "test.value1", -3); + assert.callCount(msSpy, 4); }); it("Segmened", function(): void { @@ -59,8 +63,8 @@ export function events(): void { const msSpy = spy(); const ssSpy = spy(); - ms.on(keys, msSpy); - ss.on(keys, ssSpy); + const msSpyOff = ms.on(keys, msSpy); + const ssSpyOff = ss.on(keys, ssSpy); assert.notCalled(msSpy); assert.notCalled(ssSpy); @@ -101,6 +105,12 @@ export function events(): void { assert.callCount(ssSpy, 6); assert.calledWithExactly(msSpy.lastCall, ["test.value1"]); assert.calledWithExactly(ssSpy.lastCall, ["test.value1"]); + + msSpyOff(); + ssSpyOff(); + ms.set(4, "test.value1", -3); + assert.callCount(msSpy, 4); + assert.callCount(ssSpy, 6); }); it("Monolithic transaction", function(): void { From b2f0408ebce62142fb0bb95d3c5bacc880f7b03e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Sat, 14 Dec 2019 19:02:19 +0100 Subject: [PATCH 09/48] fix(layered-storage): fix unwritten segments being undefined --- src/layered-storage/core.ts | 7 ++++++- test/layered-storage/all-combined.ts | 18 ++++++------------ test/layered-storage/segmented-layer.ts | 11 +++++++++++ 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/layered-storage/core.ts b/src/layered-storage/core.ts index 102d4ac13..c32b86a07 100644 --- a/src/layered-storage/core.ts +++ b/src/layered-storage/core.ts @@ -135,7 +135,12 @@ export class LayeredStorageCore< segment: Segment, key: Key ): KeyValue[Key] | undefined { - const sData = this._topLevelCache.get(segment); + const sData = + // Get the segment if it exists. + this._topLevelCache.get(segment) || + // Fall back to monolithic if nothing was saved into the segment yet. + this._topLevelCache.get(this.monolithic); + if (sData == null) { return; } diff --git a/test/layered-storage/all-combined.ts b/test/layered-storage/all-combined.ts index 3acabd0b0..bc11a45fa 100644 --- a/test/layered-storage/all-combined.ts +++ b/test/layered-storage/all-combined.ts @@ -4,12 +4,6 @@ import { expect } from "chai"; type KV = Record; -const allUndefined = deepFreeze({ - "test.value1": undefined, - "test.value2": undefined, - "test.value3": undefined -}); - const expectedResult = deepFreeze({ monolithic: { "test.value1": 5, @@ -37,21 +31,21 @@ const expectedResultMinusC = deepFreeze({ monolithic: expectedResult.monolithic, a: expectedResult.a, b: expectedResult.b, - c: allUndefined + c: expectedResult.monolithic }); const expectedResultMinusAC = deepFreeze({ monolithic: expectedResult.monolithic, - a: allUndefined, + a: expectedResult.monolithic, b: expectedResult.b, - c: allUndefined + c: expectedResult.monolithic }); const expectedResultMinusABC = deepFreeze({ monolithic: expectedResult.monolithic, - a: allUndefined, - b: allUndefined, - c: allUndefined + a: expectedResult.monolithic, + b: expectedResult.monolithic, + c: expectedResult.monolithic }); /** diff --git a/test/layered-storage/segmented-layer.ts b/test/layered-storage/segmented-layer.ts index 03b0fe81e..e17f5f312 100644 --- a/test/layered-storage/segmented-layer.ts +++ b/test/layered-storage/segmented-layer.ts @@ -28,6 +28,17 @@ export function segmentedLayer(): void { const b = Symbol("B"); const c = Symbol("C"); + it("Get without set", function(): void { + const ls = new LayeredStorage(); + + ls.set(7, "test.value", testValueA); + + expect( + ls.get(b, "test.value"), + "Monolithic value should be used if the segment doesn't exist." + ).to.equal(testValueA); + }); + it("Set and get", function(): void { const ls = new LayeredStorage(); From 85ea039d1c0f3542a962a967c839f240e669d7da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Sat, 14 Dec 2019 21:03:22 +0100 Subject: [PATCH 10/48] fix(layered-storage): cache the values when accessed Caching up front would be too complex to implement properly without rebuilding the whole cache due to every change. --- src/layered-storage/core.ts | 114 +++++++++++++++--------- test/layered-storage/segmented-layer.ts | 13 +++ 2 files changed, 83 insertions(+), 44 deletions(-) diff --git a/src/layered-storage/core.ts b/src/layered-storage/core.ts index c32b86a07..b135e1a05 100644 --- a/src/layered-storage/core.ts +++ b/src/layered-storage/core.ts @@ -48,44 +48,85 @@ export class LayeredStorageCore< */ private readonly _topLevelCache = new Map< Segment, - Map + Map >(); /** - * Update the value held in top level cache after it was changed in data. + * Remove outdated values from the cache. * * @param key - The key that was subject to the mutation. */ - private _updateCache(key: keyof KeyValue): void { - // Run the search for each segment to update the cached the top level value - // for each of them. - segmentsLoop: for (const segment of this._segments) { - const sCache = - this._topLevelCache.get(segment) || - this._topLevelCache.set(segment, new Map()).get(segment)!; + private _cleanCache(key: keyof KeyValue): void { + // Run the search for each segment to clean the cached top level value for + // each of them. + for (const segment of this._segments) { + const sCache = this._topLevelCache.get(segment); + + if (!sCache) { + // This segment has no cache yet. + continue; + } // Delete the outdated value. sCache.delete(key); - // Search the layers from highest to lowest priority. - for (const layer of this._layers) { - // Check the segmented first and quit if found. - const lsData = this._getLSData(layer, segment); - if (lsData.has(key)) { - sCache.set(key, lsData.get(key)!); - continue segmentsLoop; - } - - // Check the monolithic and quit if found. - const lmData = this._getLSData(layer, this.monolithic); - if (lmData.has(key)) { - sCache.set(key, lmData.get(key)!); - continue segmentsLoop; - } + // Delete the whole segment if empty. + if (sCache.size === 0) { + this._topLevelCache.delete(segment); } + } + } + + /** + * Find a top level value. + * + * @param segment - Which segment to look into (monolithic is always used as + * fallback on each level). + * @param key - The key identifying requested value. + * + * @returns Whether such value exists (`has`) and the value itself (`value`). + */ + private _findValue( + segment: Segment, + key: Key + ): { has: boolean; value: KeyValue[Key] | undefined } { + const sCache = + this._topLevelCache.get(segment) || + this._topLevelCache.set(segment, new Map()).get(segment)!; - // If nothing was found by now all the values for this key were deleted. + // Return cached value if it exists. + const cached = sCache.get(key); + if (cached) { + return cached; } + + // Search the layers from highest to lowest priority. + for (const layer of this._layers) { + // Check the segmented first and quit if found. + const lsData = this._getLSData(layer, segment); + if (lsData.has(key)) { + const value = { has: true, value: lsData.get(key)! }; + + // Save to the cache. + sCache.set(key, value); + + return value; + } + + // Check the monolithic and quit if found. + const lmData = this._getLSData(layer, this.monolithic); + if (lmData.has(key)) { + const value = { has: true, value: lmData.get(key)! }; + + // Save to the cache. + sCache.set(key, value); + + return value; + } + } + + // If nothing was found by now there are no values for the key. + return { has: false, value: undefined }; } /** @@ -135,17 +176,7 @@ export class LayeredStorageCore< segment: Segment, key: Key ): KeyValue[Key] | undefined { - const sData = - // Get the segment if it exists. - this._topLevelCache.get(segment) || - // Fall back to monolithic if nothing was saved into the segment yet. - this._topLevelCache.get(this.monolithic); - - if (sData == null) { - return; - } - - return sData.get(key); + return this._findValue(segment, key).value; } /** @@ -157,12 +188,7 @@ export class LayeredStorageCore< * @returns True if found, false otherwise. */ public has(segment: Segment, key: Key): boolean { - const sData = this._topLevelCache.get(segment); - if (sData == null) { - return false; - } - - return sData.has(key); + return this._findValue(segment, key).has; } /** @@ -182,7 +208,7 @@ export class LayeredStorageCore< const lsData = this._getLSData(layer, segment); lsData.set(key, value); - this._updateCache(key); + this._cleanCache(key); } /** @@ -200,7 +226,7 @@ export class LayeredStorageCore< const lsData = this._getLSData(layer, segment); lsData.delete(key); - this._updateCache(key); + this._cleanCache(key); } /** diff --git a/test/layered-storage/segmented-layer.ts b/test/layered-storage/segmented-layer.ts index e17f5f312..211879156 100644 --- a/test/layered-storage/segmented-layer.ts +++ b/test/layered-storage/segmented-layer.ts @@ -4,6 +4,7 @@ import { expect } from "chai"; interface KV { "test.value": { number: number; value: { string: string } }; + "unrelated.value": { number: number; value: { string: string } }; } /** @@ -39,6 +40,18 @@ export function segmentedLayer(): void { ).to.equal(testValueA); }); + it("Get without set after unrelated set", function(): void { + const ls = new LayeredStorage(); + + ls.set(7, "test.value", testValueA); + ls.set(7, b, "unrelated.value", testValueB); + + expect( + ls.get(b, "test.value"), + "Monolithic value should be used if the segment doesn't have it's own." + ).to.equal(testValueA); + }); + it("Set and get", function(): void { const ls = new LayeredStorage(); From e5d429c6d50536cb7cf15f2d860546597e7aba27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Sat, 14 Dec 2019 23:36:55 +0100 Subject: [PATCH 11/48] fix(layered-storage): throw for nonnumeric layers The sorting fails and TS already prohibits them. There's no indisputable way of sorting nonnumbers anyway. --- src/layered-storage/core.ts | 8 ++++++++ test/layered-storage/segmented-layer.ts | 15 +++++++++++++++ test/layered-storage/single-layer.ts | 15 +++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/src/layered-storage/core.ts b/src/layered-storage/core.ts index b135e1a05..588e0b25f 100644 --- a/src/layered-storage/core.ts +++ b/src/layered-storage/core.ts @@ -205,6 +205,10 @@ export class LayeredStorageCore< key: Key, value: KeyValue[Key] ): void { + if (typeof layer !== "number") { + throw new TypeError("Layers have to be numbers."); + } + const lsData = this._getLSData(layer, segment); lsData.set(key, value); @@ -223,6 +227,10 @@ export class LayeredStorageCore< segment: Segment, key: Key ): void { + if (typeof layer !== "number") { + throw new TypeError("Layers have to be numbers."); + } + const lsData = this._getLSData(layer, segment); lsData.delete(key); diff --git a/test/layered-storage/segmented-layer.ts b/test/layered-storage/segmented-layer.ts index 211879156..c4b141a7d 100644 --- a/test/layered-storage/segmented-layer.ts +++ b/test/layered-storage/segmented-layer.ts @@ -141,5 +141,20 @@ export function segmentedLayer(): void { "There isn't any value anymore so it should return false." ).to.be.false; }); + + describe("Invalid layer names", function(): void { + [undefined, null, "string", true, false, {}].forEach( + (layer: any): void => { + it("" + layer, function(): void { + const ls = new LayeredStorage(); + + expect( + (): void => void ls.set(layer, b, "test.value", testValueB), + "Layers have to be ordered which is only possible with numbers as that's the only thing that has universally accepted indisputable order." + ).to.throw(); + }); + } + ); + }); }); } diff --git a/test/layered-storage/single-layer.ts b/test/layered-storage/single-layer.ts index b30c3f3bd..165f2432a 100644 --- a/test/layered-storage/single-layer.ts +++ b/test/layered-storage/single-layer.ts @@ -77,5 +77,20 @@ export function singleLayer(): void { "The value should be reported as not present after being deleted." ).to.be.false; }); + + describe("Invalid layer names", function(): void { + [undefined, null, "string", true, false, {}].forEach( + (layer: any): void => { + it("" + layer, function(): void { + const ls = new LayeredStorage(); + + expect( + (): void => void ls.set(layer, "test.value", testValue), + "Layers have to be ordered which is only possible with numbers as that's the only thing that has universally accepted indisputable order." + ).to.throw(); + }); + } + ); + }); }); } From 689c154d21a1e21d653650957cdff9a5d869d625 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Sat, 14 Dec 2019 23:56:17 +0100 Subject: [PATCH 12/48] feat(layered-storage): add console dump method This is to simplify debugging. It logs the content of the storage to the console using collased groups to denote the structure of the storage. --- src/layered-storage/core.ts | 37 ++++++++++++++++++++++++++ src/layered-storage/layered-storage.ts | 7 +++++ 2 files changed, 44 insertions(+) diff --git a/src/layered-storage/core.ts b/src/layered-storage/core.ts index 588e0b25f..8ff17cac6 100644 --- a/src/layered-storage/core.ts +++ b/src/layered-storage/core.ts @@ -254,4 +254,41 @@ export class LayeredStorageCore< this._topLevelCache.delete(segment); this._segments.delete(segment); } + + /** + * Log the content of the storage into the console. + */ + public dumpContent(): void { + console.groupCollapsed("Storage content dump"); + + console.log("Time:", new Date()); + console.log("Layers:", [...this._layers.values()]); + console.log("Segments:", [...this._segments.values()]); + + console.groupCollapsed("Cache"); + for (const [segment, cData] of this._topLevelCache.entries()) { + console.groupCollapsed(`Segment: ${String(segment)}`); + for (const [key, value] of cData.entries()) { + console.log([key, value]); + } + console.groupEnd(); + } + console.groupEnd(); + + console.groupCollapsed("Data"); + for (const [layer, lData] of this._data.entries()) { + console.groupCollapsed(`Layer: ${layer}`); + for (const [segment, lsData] of lData.entries()) { + console.groupCollapsed(`Segment: ${String(segment)}`); + for (const [key, value] of lsData.entries()) { + console.log([key, value]); + } + console.groupEnd(); + } + console.groupEnd(); + } + console.groupEnd(); + + console.groupEnd(); + } } diff --git a/src/layered-storage/layered-storage.ts b/src/layered-storage/layered-storage.ts index fe51e7b14..bba3bcedc 100644 --- a/src/layered-storage/layered-storage.ts +++ b/src/layered-storage/layered-storage.ts @@ -365,4 +365,11 @@ export class LayeredStorage< listeners.splice(listeners.indexOf(listener), 1); } + + /** + * Log the content of the storage into the console. + */ + public dumpContent(): void { + this._core.dumpContent(); + } } From b6f13b8a9e1d6297e7938f0ace4a9f1ca6f6ac8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Sun, 15 Dec 2019 20:48:33 +0100 Subject: [PATCH 13/48] fix(layered-storage): purge empty structures Previously the structures were kept even if all values were deleted. --- src/layered-storage/core.ts | 89 ++++++++++++++++++------------ test/layered-storage/index.test.ts | 2 + test/layered-storage/other.ts | 80 +++++++++++++++++++++++++++ 3 files changed, 137 insertions(+), 34 deletions(-) create mode 100644 test/layered-storage/other.ts diff --git a/src/layered-storage/core.ts b/src/layered-storage/core.ts index 8ff17cac6..578d45b85 100644 --- a/src/layered-storage/core.ts +++ b/src/layered-storage/core.ts @@ -2,6 +2,19 @@ import { KeyValueLookup, LayerRange, Segment } from "./common"; const reverseNumeric = (a: number, b: number): number => b - a; +type SegmentData = Map< + keyof KeyValue, + KeyValue[keyof KeyValue] +>; +type LayerData = Map< + Segment, + SegmentData +>; +type Data = Map< + Layer, + LayerData +>; + /** * Internal core to handle simple data storage, mutation and retrieval. Also * handles the special monolithic segment. @@ -24,10 +37,7 @@ export class LayeredStorageCore< /** * Data stored as layer → segment → key → value. */ - private _data = new Map< - Layer, - Map> - >(); + private _data: Data = new Map(); /** * An ordered list of layers. The highest priority (equals highest number) @@ -90,12 +100,12 @@ export class LayeredStorageCore< segment: Segment, key: Key ): { has: boolean; value: KeyValue[Key] | undefined } { - const sCache = + const segmentCache = this._topLevelCache.get(segment) || this._topLevelCache.set(segment, new Map()).get(segment)!; // Return cached value if it exists. - const cached = sCache.get(key); + const cached = segmentCache.get(key); if (cached) { return cached; } @@ -103,23 +113,24 @@ export class LayeredStorageCore< // Search the layers from highest to lowest priority. for (const layer of this._layers) { // Check the segmented first and quit if found. - const lsData = this._getLSData(layer, segment); - if (lsData.has(key)) { - const value = { has: true, value: lsData.get(key)! }; + const segmentData = this._getLSData(layer, segment).segmentData; + if (segmentData.has(key)) { + const value = { has: true, value: segmentData.get(key)! }; // Save to the cache. - sCache.set(key, value); + segmentCache.set(key, value); return value; } // Check the monolithic and quit if found. - const lmData = this._getLSData(layer, this.monolithic); - if (lmData.has(key)) { - const value = { has: true, value: lmData.get(key)! }; + const monolithicData = this._getLSData(layer, this.monolithic) + .segmentData; + if (monolithicData.has(key)) { + const value = { has: true, value: monolithicData.get(key)! }; // Save to the cache. - sCache.set(key, value); + segmentCache.set(key, value); return value; } @@ -142,26 +153,26 @@ export class LayeredStorageCore< private _getLSData( layer: Layer, segment: Segment - ): Map { + ): { layerData: LayerData; segmentData: SegmentData } { // Get or create the requested layer. - let lData = this._data.get(layer); - if (lData == null) { - lData = new Map(); - this._data.set(layer, lData); + let layerData = this._data.get(layer); + if (layerData == null) { + layerData = new Map(); + this._data.set(layer, layerData); this._layers = [...this._data.keys()].sort(reverseNumeric); } // Get or create the requested segment on the layer. - let lsData = lData.get(segment); - if (lsData == null) { - lsData = new Map(); - lData.set(segment, lsData); + let segmentData = layerData.get(segment); + if (segmentData == null) { + segmentData = new Map(); + layerData.set(segment, segmentData); this._segments.add(segment); } - return lsData; + return { layerData, segmentData }; } /** @@ -209,8 +220,8 @@ export class LayeredStorageCore< throw new TypeError("Layers have to be numbers."); } - const lsData = this._getLSData(layer, segment); - lsData.set(key, value); + const { segmentData } = this._getLSData(layer, segment); + segmentData.set(key, value); this._cleanCache(key); } @@ -231,8 +242,18 @@ export class LayeredStorageCore< throw new TypeError("Layers have to be numbers."); } - const lsData = this._getLSData(layer, segment); - lsData.delete(key); + const { layerData, segmentData } = this._getLSData(layer, segment); + segmentData.delete(key); + + // Purge the segment if empty. + if (segmentData.size === 0) { + layerData.delete(segment); + } + + // Purge the layer if empty. + if (layerData.size === 0) { + this._data.delete(layer); + } this._cleanCache(key); } @@ -248,8 +269,8 @@ export class LayeredStorageCore< * @param segment - The segment whose data should be deleted. */ public deleteSegmentData(segment: Segment): void { - for (const lData of this._data.values()) { - lData.delete(segment); + for (const layerData of this._data.values()) { + layerData.delete(segment); } this._topLevelCache.delete(segment); this._segments.delete(segment); @@ -266,9 +287,9 @@ export class LayeredStorageCore< console.log("Segments:", [...this._segments.values()]); console.groupCollapsed("Cache"); - for (const [segment, cData] of this._topLevelCache.entries()) { + for (const [segment, cacheData] of this._topLevelCache.entries()) { console.groupCollapsed(`Segment: ${String(segment)}`); - for (const [key, value] of cData.entries()) { + for (const [key, value] of cacheData.entries()) { console.log([key, value]); } console.groupEnd(); @@ -278,9 +299,9 @@ export class LayeredStorageCore< console.groupCollapsed("Data"); for (const [layer, lData] of this._data.entries()) { console.groupCollapsed(`Layer: ${layer}`); - for (const [segment, lsData] of lData.entries()) { + for (const [segment, segmentData] of lData.entries()) { console.groupCollapsed(`Segment: ${String(segment)}`); - for (const [key, value] of lsData.entries()) { + for (const [key, value] of segmentData.entries()) { console.log([key, value]); } console.groupEnd(); diff --git a/test/layered-storage/index.test.ts b/test/layered-storage/index.test.ts index d00d6345e..16a8b1462 100644 --- a/test/layered-storage/index.test.ts +++ b/test/layered-storage/index.test.ts @@ -2,6 +2,7 @@ import { allCombined } from "./all-combined"; import { events } from "./events"; import { multipleKeys } from "./multiple-keys"; import { multipleLayers } from "./multiple-layers"; +import { other } from "./other"; import { segmentedLayer } from "./segmented-layer"; import { singleLayer } from "./single-layer"; @@ -10,6 +11,7 @@ describe("Layered storage", function(): void { events(); multipleKeys(); multipleLayers(); + other(); segmentedLayer(); singleLayer(); }); diff --git a/test/layered-storage/other.ts b/test/layered-storage/other.ts new file mode 100644 index 000000000..259c47560 --- /dev/null +++ b/test/layered-storage/other.ts @@ -0,0 +1,80 @@ +import { LayeredStorage } from "../../src/layered-storage"; +import { expect } from "chai"; + +type KV = Record; + +/** + * Other tests that don't fit elsewhere. + */ +export function other(): void { + it("Empty data structure purging", function(): void { + const ls = new LayeredStorage(); + + const getStructCount = (): number => + [ + // Ignore private property access errors. It's no big deal since this + // is a unit test. + // @ts-ignore + ...ls._core._data.values() + ].reduce((acc, lData): number => { + return ( + acc + + 1 + + [...lData.values()].reduce((acc, sData): number => { + return acc + 1 + sData.size; + }, 0) + ); + }, 0); + + ([1, 4, 9] as const).forEach((layer): void => { + ls.set(layer, "test.value1", 1); + ls.set(layer, "test.value2", 2); + ["a", "b", "c"].forEach((segment): void => { + ls.set(layer, segment, "test.value1", 1); + ls.set(layer, segment, "test.value2", 2); + }); + }); + + expect(getStructCount()).to.equal( + 3 + // layers + 3 * 4 + // 4 segments on each layer + 3 * 4 * 2 // 2 values in each segment + ); + + ([1, 4, 9] as const).forEach((layer): void => { + ls.delete(layer, "test.value1"); + ["a", "b", "c"].forEach((segment): void => { + ls.delete(layer, segment, "test.value1"); + }); + }); + + expect(getStructCount()).to.equal( + 3 + // layers + 3 * 4 + // 4 segments on each layer + 3 * 4 * 1 // 1 value in each segment + ); + + ([1, 4, 9] as const).forEach((layer): void => { + ls.delete(layer, "test.value2"); + ["b"].forEach((segment): void => { + ls.delete(layer, segment, "test.value2"); + }); + }); + + expect(getStructCount()).to.equal( + 3 + // layers + 3 * 2 + // 2 segments on each layer + 3 * 2 * 1 // 1 value in each segment + ); + + ([1, 4, 9] as const).forEach((layer): void => { + ["a", "c"].forEach((segment): void => { + ls.delete(layer, segment, "test.value2"); + }); + }); + + expect(getStructCount()).to.equal( + 0 // no layers, no segments, no values + ); + }); +} From 7c4350cbce3267ef835ca301f56efc695bcb71c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Sun, 15 Dec 2019 21:06:50 +0100 Subject: [PATCH 14/48] fix(layered-storage): do not create new structures on access --- src/layered-storage/core.ts | 15 ++++++---- test/layered-storage/other.ts | 55 ++++++++++++++++++++++------------- 2 files changed, 45 insertions(+), 25 deletions(-) diff --git a/src/layered-storage/core.ts b/src/layered-storage/core.ts index 578d45b85..c0e8da174 100644 --- a/src/layered-storage/core.ts +++ b/src/layered-storage/core.ts @@ -113,8 +113,14 @@ export class LayeredStorageCore< // Search the layers from highest to lowest priority. for (const layer of this._layers) { // Check the segmented first and quit if found. - const segmentData = this._getLSData(layer, segment).segmentData; - if (segmentData.has(key)) { + const layerData = this._data.get(layer); + if (layerData == null) { + // Empty layer. + continue; + } + + const segmentData = layerData.get(segment); + if (segmentData != null && segmentData.has(key)) { const value = { has: true, value: segmentData.get(key)! }; // Save to the cache. @@ -124,9 +130,8 @@ export class LayeredStorageCore< } // Check the monolithic and quit if found. - const monolithicData = this._getLSData(layer, this.monolithic) - .segmentData; - if (monolithicData.has(key)) { + const monolithicData = layerData.get(this.monolithic); + if (monolithicData != null && monolithicData.has(key)) { const value = { has: true, value: monolithicData.get(key)! }; // Save to the cache. diff --git a/test/layered-storage/other.ts b/test/layered-storage/other.ts index 259c47560..18e1423f7 100644 --- a/test/layered-storage/other.ts +++ b/test/layered-storage/other.ts @@ -7,25 +7,25 @@ type KV = Record; * Other tests that don't fit elsewhere. */ export function other(): void { + const getStructCount = (ls: LayeredStorage): number => + [ + // Ignore private property access errors. It's no big deal since this + // is a unit test. + // @ts-ignore + ...ls._core._data.values() + ].reduce((acc, lData): number => { + return ( + acc + + 1 + + [...lData.values()].reduce((acc, sData): number => { + return acc + 1 + sData.size; + }, 0) + ); + }, 0); + it("Empty data structure purging", function(): void { const ls = new LayeredStorage(); - const getStructCount = (): number => - [ - // Ignore private property access errors. It's no big deal since this - // is a unit test. - // @ts-ignore - ...ls._core._data.values() - ].reduce((acc, lData): number => { - return ( - acc + - 1 + - [...lData.values()].reduce((acc, sData): number => { - return acc + 1 + sData.size; - }, 0) - ); - }, 0); - ([1, 4, 9] as const).forEach((layer): void => { ls.set(layer, "test.value1", 1); ls.set(layer, "test.value2", 2); @@ -35,7 +35,7 @@ export function other(): void { }); }); - expect(getStructCount()).to.equal( + expect(getStructCount(ls)).to.equal( 3 + // layers 3 * 4 + // 4 segments on each layer 3 * 4 * 2 // 2 values in each segment @@ -48,7 +48,7 @@ export function other(): void { }); }); - expect(getStructCount()).to.equal( + expect(getStructCount(ls)).to.equal( 3 + // layers 3 * 4 + // 4 segments on each layer 3 * 4 * 1 // 1 value in each segment @@ -61,7 +61,7 @@ export function other(): void { }); }); - expect(getStructCount()).to.equal( + expect(getStructCount(ls)).to.equal( 3 + // layers 3 * 2 + // 2 segments on each layer 3 * 2 * 1 // 1 value in each segment @@ -73,8 +73,23 @@ export function other(): void { }); }); - expect(getStructCount()).to.equal( + expect(getStructCount(ls)).to.equal( 0 // no layers, no segments, no values ); }); + + it("Empty data structure creation", function(): void { + const ls = new LayeredStorage(); + + ls.set(4, "c", "test.value1", 1); + + ls.get("test.value1"); + ls.get("b", "test.value1"); + ls.has("test.value2"); + ls.has("a", "test.value2"); + + expect(getStructCount(ls)).to.equal( + 3 // 1 layer, 1 segment, 1 value + ); + }); } From d9eb64cc839a59aab643a57182156371c04dfbb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Sun, 15 Dec 2019 21:28:40 +0100 Subject: [PATCH 15/48] style: fix linting issues --- .eslintrc.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index dac17b72f..1b3a19674 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -54,7 +54,7 @@ module.exports = { // Empty functions are useful sometimes. "@typescript-eslint/no-empty-function": "off", // This would be great if TypeScript was perfect but sometimes tsc can't infer the correct type. - '@typescript-eslint/no-non-null-assertion': 'off', + "@typescript-eslint/no-non-null-assertion": "off", // This is really crazy given the functions in this package. "@typescript-eslint/no-explicit-any": "off", // These are hoisted, I have no idea why it reports them by default. @@ -73,5 +73,14 @@ module.exports = { jsdoc: { mode: "typescript" } - } + }, + overrides: [ + { + files: ["test/**/*.ts"], + rules: { + // This is useful to ignore private property access in a test. + "@typescript-eslint/ban-ts-ignore": "off" + } + } + ] }; From de132b4ae3771510cacb930c53aadaa4c9cda44a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Tue, 17 Dec 2019 23:51:48 +0100 Subject: [PATCH 16/48] feat(layered-storage): remove events BREAKING CHANGE: The on methods were removed from Layered Storage. This was unbearably slow. Most of the time was actually spent handling events. Making it faster without reducing it's functionality to the same level as Emitter seems impossible to me. Since we already use the Emitter there's no point in having such thing. --- src/layered-storage/common.ts | 2 - src/layered-storage/index.ts | 2 +- src/layered-storage/layered-storage.ts | 123 +--------------- src/layered-storage/segment.ts | 17 +-- src/layered-storage/transactions.ts | 104 +------------- test/layered-storage/events.ts | 185 ------------------------- test/layered-storage/index.test.ts | 2 - 7 files changed, 13 insertions(+), 422 deletions(-) delete mode 100644 test/layered-storage/events.ts diff --git a/src/layered-storage/common.ts b/src/layered-storage/common.ts index ed472adcb..e7fc58923 100644 --- a/src/layered-storage/common.ts +++ b/src/layered-storage/common.ts @@ -2,5 +2,3 @@ export type KeyRange = number | string | symbol; export type KeyValueLookup = Record; export type LayerRange = number; export type Segment = boolean | number | object | string | symbol; - -export type EventCallback = (keys: Key[]) => void; diff --git a/src/layered-storage/index.ts b/src/layered-storage/index.ts index d7ef8993e..5aa8b2fdd 100644 --- a/src/layered-storage/index.ts +++ b/src/layered-storage/index.ts @@ -4,4 +4,4 @@ export { LayeredStorageTransaction } from "./layered-storage"; export { LayeredStorageSegment } from "./segment"; -export { EventCallback, KeyValueLookup, LayerRange, Segment } from "./common"; +export { KeyValueLookup, LayerRange, Segment } from "./common"; diff --git a/src/layered-storage/layered-storage.ts b/src/layered-storage/layered-storage.ts index bba3bcedc..ce9a869cc 100644 --- a/src/layered-storage/layered-storage.ts +++ b/src/layered-storage/layered-storage.ts @@ -1,19 +1,11 @@ -import { - KeyRange, - KeyValueLookup, - LayerRange, - Segment, - EventCallback -} from "./common"; +import { KeyRange, KeyValueLookup, LayerRange, Segment } from "./common"; import { LayeredStorageCore } from "./core"; import { LayeredStorageSegment } from "./segment"; import { LayeredStorageSegmentTransaction, LayeredStorageTransaction, - Listeners, MonolithicTransaction, - SegmentTransaction, - Listener + SegmentTransaction } from "./transactions"; export { @@ -41,7 +33,6 @@ export class LayeredStorage< Layer extends LayerRange > { private _core = new LayeredStorageCore(); - private _listeners: Listeners = new Map(); /** * @param segment - Which segment to search through in addition to the monolithic part of the storage. @@ -179,12 +170,8 @@ export class LayeredStorage< | LayeredStorageSegmentTransaction | LayeredStorageTransaction { return segment == null - ? new MonolithicTransaction(this._core, this._listeners) - : new SegmentTransaction( - this._core, - this._listeners, - segment - ); + ? new MonolithicTransaction(this._core) + : new SegmentTransaction(this._core, segment); } /** @@ -264,108 +251,6 @@ export class LayeredStorage< this._core.deleteSegmentData(segment); } - /** - * @param segment - Which segment does the listener observe. - * @param keys - These determine which keys is the listener interested in. - * @param callback - Will be called when interesting changes are detected. - */ - public on( - segment: Segment, - keys: (keyof KeyValue | RegExp) | (keyof KeyValue | RegExp)[], - callback: EventCallback - ): () => void; - /** - * @param keys - These determine which keys is the listener interested in. - * @param callback - Will be called when interesting changes are detected. - */ - public on( - keys: (keyof KeyValue | RegExp) | (keyof KeyValue | RegExp)[], - callback: EventCallback - ): () => void; - /** - * Bind a listener to given changes. - * - * @returns An off function that can be used to unbind the listener later. - */ - public on( - ...rest: - | [ - Segment, - (keyof KeyValue | RegExp) | (keyof KeyValue | RegExp)[], - EventCallback - ] - | [ - (keyof KeyValue | RegExp) | (keyof KeyValue | RegExp)[], - EventCallback - ] - ): () => void { - return rest.length === 2 - ? this._on( - this._core.monolithic, - Array.isArray(rest[0]) ? rest[0] : [rest[0]], - rest[1] - ) - : this._on( - rest[0], - Array.isArray(rest[1]) ? rest[1] : [rest[1]], - rest[2] - ); - } - - /** - * Bind a listener to given changes. - * - * @param segment - Which segment does the listener observe. - * @param keys - These determine which keys is the listener interested in. - * @param callback - Will be called when interesting changes are detected. - * - * @returns An off function that can be used to unbind the listener later. - */ - private _on( - segment: Segment, - keys: (keyof KeyValue | RegExp)[], - callback: EventCallback - ): () => void { - const literals = keys.filter( - (value): value is keyof KeyValue => !(value instanceof RegExp) - ); - const functions = keys - .filter((value): value is RegExp => value instanceof RegExp) - .map((regexp): ((input: string) => boolean) => regexp.test.bind(regexp)); - - const test = (key: KeyRange): boolean => - literals.includes(key) || - (typeof key === "string" && functions.some((func): boolean => func(key))); - - const listener: Listener = { test, callback }; - - ( - this._listeners.get(segment) || - this._listeners.set(segment, []).get(segment)! - ).push(listener); - - return this._off.bind(this, segment, listener); - } - - /** - * Remove given listener. - * - * @remarks - * This is internal method that should be exposed only as fully bound - * function returned from the on method. - * - * @param segment - Which segment does the listener observe. - * @param listener - The listener object itself. - */ - private _off(segment: Segment, listener: Listener): void { - const listeners = this._listeners.get(segment); - if (listeners == null) { - return; - } - - listeners.splice(listeners.indexOf(listener), 1); - } - /** * Log the content of the storage into the console. */ diff --git a/src/layered-storage/segment.ts b/src/layered-storage/segment.ts index 08eb249ab..14e224022 100644 --- a/src/layered-storage/segment.ts +++ b/src/layered-storage/segment.ts @@ -1,4 +1,4 @@ -import { KeyValueLookup, LayerRange, Segment, EventCallback } from "./common"; +import { KeyValueLookup, LayerRange, Segment } from "./common"; import { LayeredStorage, LayeredStorageSegmentTransaction @@ -112,19 +112,4 @@ export class LayeredStorageSegment< public close(): void { this._layeredStorage.deleteSegmentData(this._segment); } - - /** - * Bind a listener to given changes. - * - * @param keys - These determine which keys is the listener interested in. - * @param callback - Will be called when interesting changes are detected. - * - * @returns An off function that can be used to unbind the listener later. - */ - public on( - keys: (keyof KeyValue | RegExp) | (keyof KeyValue | RegExp)[], - callback: EventCallback - ): () => void { - return this._layeredStorage.on(this._segment, keys, callback); - } } diff --git a/src/layered-storage/transactions.ts b/src/layered-storage/transactions.ts index 3e5e8a30a..127c33865 100644 --- a/src/layered-storage/transactions.ts +++ b/src/layered-storage/transactions.ts @@ -1,25 +1,6 @@ -import { - KeyRange, - KeyValueLookup, - LayerRange, - Segment, - EventCallback -} from "./common"; +import { KeyValueLookup, LayerRange, Segment } from "./common"; import { LayeredStorageCore } from "./core"; -/** - * Internal data structure for holding listener related data. - */ -export type Listener = { - test: (key: KeyRange) => boolean; - callback: EventCallback; -}; - -/** - * Internal data structure for holding listeners observing each segment. - */ -export type Listeners = Map[]>; - /** * This is used through composition to create monolithic and segmented * transactions without massive code duplicities. @@ -39,10 +20,6 @@ class TransactionCore< * `LayeredStorageCore`. */ private _actions: (() => void)[] = []; - /** - * Lists the changes from `_actions` in a way for easy event dispatching. - */ - private _events = new Map>(); /** * Create a new instance of transaction core. @@ -52,8 +29,7 @@ class TransactionCore< * was commited. */ public constructor( - private _storageCore: LayeredStorageCore, - private _listeners: Listeners + private _storageCore: LayeredStorageCore ) {} /** @@ -73,8 +49,6 @@ class TransactionCore< this._actions.push( this._storageCore.set.bind(this._storageCore, layer, segment, key, value) ); - - this._addEvent(segment, key); } /** @@ -92,62 +66,16 @@ class TransactionCore< this._actions.push( this._storageCore.delete.bind(this._storageCore, layer, segment, key) ); - - this._addEvent(segment, key); } /** * Commit all queued operations. */ public commit(): void { - // Reset the structures for next transaction. - const actions = this._actions; - this._actions = []; - const events = this._events; - this._events = new Map(); - - // Run the mutations. - actions.forEach((action): void => { + // Run the mutations and clean the array for next use. + this._actions.splice(0).forEach((action): void => { action(); }); - - // Inform monolithic listeners about the mutations. - const monolithicKeySet = events.get(this._storageCore.monolithic); - if (monolithicKeySet) { - const allKeys = [...monolithicKeySet]; - - [...this._listeners.values()] - .flat() - .forEach(({ test, callback }): void => { - const keys = allKeys.filter((key): boolean => test(key)); - if (keys.length === 0) { - return; - } - - callback(keys); - }); - - events.delete(this._storageCore.monolithic); - } - - // Inform listeners on segments about the changes. - events.forEach((keySet, segment): void => { - const allKeys = [...keySet]; - - const segmentListeners = this._listeners.get(segment); - if (segmentListeners == null) { - return; - } - - segmentListeners.forEach(({ test, callback }): void => { - const keys = allKeys.filter((key): boolean => test(key)); - if (keys.length === 0) { - return; - } - - callback(keys); - }); - }); } /** @@ -155,20 +83,6 @@ class TransactionCore< */ public abort(): void { this._actions = []; - this._events = new Map(); - } - - /** - * Record which segments and keys were affected by the queued mutations. - * - * @param segment - Which segment does this mutation belong to. - * @param key - Which key's value does this mutation affect. - */ - private _addEvent(segment: Segment, key: keyof KeyValue): void { - ( - this._events.get(segment) || - this._events.set(segment, new Set()).get(segment)! - ).add(key); } } @@ -257,12 +171,9 @@ export class MonolithicTransaction< * @param listeners - Listeners that should be notified after a transaction * was commited. */ - public constructor( - storageCore: LayeredStorageCore, - listeners: Listeners - ) { + public constructor(storageCore: LayeredStorageCore) { this._monolithic = storageCore.monolithic; - this._transactionCore = new TransactionCore(storageCore, listeners); + this._transactionCore = new TransactionCore(storageCore); } public set( @@ -372,10 +283,9 @@ export class SegmentTransaction< */ public constructor( storageCore: LayeredStorageCore, - listeners: Listeners, private readonly _segment: Segment ) { - this._transactionCore = new TransactionCore(storageCore, listeners); + this._transactionCore = new TransactionCore(storageCore); } /** @inheritdoc */ diff --git a/test/layered-storage/events.ts b/test/layered-storage/events.ts deleted file mode 100644 index f694ef19a..000000000 --- a/test/layered-storage/events.ts +++ /dev/null @@ -1,185 +0,0 @@ -import { LayeredStorage } from "../../src/layered-storage"; -import { assert, spy } from "sinon"; -import { deepFreeze } from "../helpers"; - -type KV = Record; - -/** - * Test if mutations ant transactions trigger events as they should. - */ -export function events(): void { - describe("Events", function(): void { - deepFreeze([ - { name: "Single regex", keys: /^test\..*$/ }, - { name: "Single regex in an array", keys: [/^test\..*$/] }, - { name: "Literals", keys: ["test.value1", "test.value2", "test.value3"] }, - { name: "Two regexes", keys: [/^nonexistent$/, /^test\..*$/] }, - { - name: "Regex that never passes and literals that do", - keys: [/^nonexistent$/, "test.value1", "test.value2", "test.value3"] - }, - { - name: "Literals that never pass and regex that does", - keys: ["nonexistent", /^test\..*$/] - } - ]).forEach(({ name, keys }): void => { - describe(name, function(): void { - it("Monolithic", function(): void { - const ms = new LayeredStorage(); - - const msSpy = spy(); - - const msSpyOff = ms.on(keys, msSpy); - assert.notCalled(msSpy); - - ms.set(4, "other.value1", 7); - assert.notCalled(msSpy); - - ms.set(1, "test.value1", 6); - assert.callCount(msSpy, 1); - assert.calledWithExactly(msSpy.lastCall, ["test.value1"]); - - ms.set(4, "test.value2", 5); - assert.callCount(msSpy, 2); - assert.calledWithExactly(msSpy.lastCall, ["test.value2"]); - - ms.delete(4, "test.value3"); - assert.callCount(msSpy, 3); - assert.calledWithExactly(msSpy.lastCall, ["test.value3"]); - - ms.delete(1, "test.value1"); - assert.callCount(msSpy, 4); - assert.calledWithExactly(msSpy.lastCall, ["test.value1"]); - - msSpyOff(); - ms.set(4, "test.value1", -3); - assert.callCount(msSpy, 4); - }); - - it("Segmened", function(): void { - const ms = new LayeredStorage(); - const ss = ms.openSegment("a"); - - const msSpy = spy(); - const ssSpy = spy(); - - const msSpyOff = ms.on(keys, msSpy); - const ssSpyOff = ss.on(keys, ssSpy); - assert.notCalled(msSpy); - assert.notCalled(ssSpy); - - ms.set(4, "other.value1", 7); - assert.notCalled(msSpy); - assert.notCalled(ssSpy); - - ms.set(1, "test.value1", 6); - assert.callCount(msSpy, 1); - assert.callCount(ssSpy, 1); - assert.calledWithExactly(msSpy.lastCall, ["test.value1"]); - assert.calledWithExactly(ssSpy.lastCall, ["test.value1"]); - - ss.set(1, "test.value1", 6); - assert.callCount(msSpy, 1); - assert.callCount(ssSpy, 2); - assert.calledWithExactly(ssSpy.lastCall, ["test.value1"]); - - ms.set(4, "test.value2", 5); - assert.callCount(msSpy, 2); - assert.callCount(ssSpy, 3); - assert.calledWithExactly(msSpy.lastCall, ["test.value2"]); - assert.calledWithExactly(ssSpy.lastCall, ["test.value2"]); - - ms.delete(4, "test.value3"); - assert.callCount(msSpy, 3); - assert.callCount(ssSpy, 4); - assert.calledWithExactly(msSpy.lastCall, ["test.value3"]); - assert.calledWithExactly(ssSpy.lastCall, ["test.value3"]); - - ss.delete(4, "test.value2"); - assert.callCount(msSpy, 3); - assert.callCount(ssSpy, 5); - assert.calledWithExactly(ssSpy.lastCall, ["test.value2"]); - - ms.delete(1, "test.value1"); - assert.callCount(msSpy, 4); - assert.callCount(ssSpy, 6); - assert.calledWithExactly(msSpy.lastCall, ["test.value1"]); - assert.calledWithExactly(ssSpy.lastCall, ["test.value1"]); - - msSpyOff(); - ssSpyOff(); - ms.set(4, "test.value1", -3); - assert.callCount(msSpy, 4); - assert.callCount(ssSpy, 6); - }); - - it("Monolithic transaction", function(): void { - const ms = new LayeredStorage(); - const ss = ms.openSegment("a"); - - const msSpy = spy(); - const ssSpy = spy(); - - ms.on(keys, msSpy); - ss.on(keys, ssSpy); - assert.notCalled(msSpy); - assert.notCalled(ssSpy); - - ms.runTransaction((transaction): void => { - transaction.set(4, "other.value1", 7); - transaction.set(1, "test.value1", 6); - transaction.set(4, "test.value2", 5); - transaction.delete(4, "test.value3"); - transaction.delete(1, "test.value1"); - - assert.notCalled(msSpy); - assert.notCalled(ssSpy); - }); - assert.callCount(msSpy, 1); - assert.callCount(ssSpy, 1); - assert.calledWithExactly(msSpy.lastCall, [ - "test.value1", - "test.value2", - "test.value3" - ]); - assert.calledWithExactly(ssSpy.lastCall, [ - "test.value1", - "test.value2", - "test.value3" - ]); - }); - - it("Segmented transaction", function(): void { - const ms = new LayeredStorage(); - const ss = ms.openSegment("a"); - - const msSpy = spy(); - const ssSpy = spy(); - - ms.on(keys, msSpy); - ss.on(keys, ssSpy); - assert.notCalled(msSpy); - assert.notCalled(ssSpy); - - ss.runTransaction((transaction): void => { - transaction.set(4, "other.value1", 7); - transaction.set(1, "test.value1", 6); - transaction.set(4, "test.value2", 5); - transaction.delete(4, "test.value3"); - transaction.delete(1, "test.value1"); - - assert.notCalled(msSpy); - assert.notCalled(ssSpy); - }); - assert.callCount(msSpy, 0); - assert.callCount(ssSpy, 1); - assert.calledWithExactly(ssSpy.lastCall, [ - "test.value1", - "test.value2", - "test.value3" - ]); - }); - }); - }); - }); -} diff --git a/test/layered-storage/index.test.ts b/test/layered-storage/index.test.ts index 16a8b1462..72ad2e9e3 100644 --- a/test/layered-storage/index.test.ts +++ b/test/layered-storage/index.test.ts @@ -1,5 +1,4 @@ import { allCombined } from "./all-combined"; -import { events } from "./events"; import { multipleKeys } from "./multiple-keys"; import { multipleLayers } from "./multiple-layers"; import { other } from "./other"; @@ -8,7 +7,6 @@ import { singleLayer } from "./single-layer"; describe("Layered storage", function(): void { allCombined(); - events(); multipleKeys(); multipleLayers(); other(); From 24beaa2dac159161a0a4eb7c08d31ad7feb1a586 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Tue, 17 Dec 2019 23:52:50 +0100 Subject: [PATCH 17/48] style(layered-storage): remove unused import --- src/layered-storage/layered-storage.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layered-storage/layered-storage.ts b/src/layered-storage/layered-storage.ts index ce9a869cc..be0775695 100644 --- a/src/layered-storage/layered-storage.ts +++ b/src/layered-storage/layered-storage.ts @@ -1,4 +1,4 @@ -import { KeyRange, KeyValueLookup, LayerRange, Segment } from "./common"; +import { KeyValueLookup, LayerRange, Segment } from "./common"; import { LayeredStorageCore } from "./core"; import { LayeredStorageSegment } from "./segment"; import { From b1787b8b4c320fec29e02c65d2c33d1998a1a050 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Wed, 18 Dec 2019 23:26:10 +0100 Subject: [PATCH 18/48] feat(layered-layout): add validation --- src/layered-storage/core.ts | 77 ++++++++++++++++ src/layered-storage/layered-storage.ts | 30 +++++++ test/layered-storage/index.test.ts | 2 + test/layered-storage/validation.ts | 116 +++++++++++++++++++++++++ 4 files changed, 225 insertions(+) create mode 100644 test/layered-storage/validation.ts diff --git a/src/layered-storage/core.ts b/src/layered-storage/core.ts index c0e8da174..252f5e583 100644 --- a/src/layered-storage/core.ts +++ b/src/layered-storage/core.ts @@ -15,6 +15,12 @@ type Data = Map< LayerData >; +interface TypedMap + extends Map { + get(key: Key): undefined | KeyValue[Key]; + set(key: Key, value: KeyValue[Key]): this; +} + /** * Internal core to handle simple data storage, mutation and retrieval. Also * handles the special monolithic segment. @@ -50,6 +56,30 @@ export class LayeredStorageCore< */ private readonly _segments = new Set(); + /** + * A list of validators for each key. + */ + private readonly _validators: TypedMap< + { + [Key in keyof KeyValue]: ((value: KeyValue[Key]) => true | string)[]; + } + > = new Map(); + + /** + * This is called whenever a validity test fails. + * + * @param key - The key of the invalid value. + * @param value - The invalid value itself. + * @param message - The message returned by the validator that failed. + */ + private _invalidHandler: ( + key: Key, + value: KeyValue[Key], + message: string + ) => void = (key, value, message): void => { + console.error("Invalid value was ignored.", { key, value, message }); + }; + /** * This is used to speed up retrieval of data upon request. Since the storage * is seen as mostly static this structure is populated up front and updated @@ -225,6 +255,21 @@ export class LayeredStorageCore< throw new TypeError("Layers have to be numbers."); } + for (const validator of this._validators.get(key) || []) { + const message = validator(value); + if (message === true) { + // The value is valid. Proceed with another test or save the value into + // the storage if this was the last one. + continue; + } else { + // The value is invalid. Call the invalid value handler and, if the + // handler didn't throw, stop execution of this function to prevent the + // value from being saved into the storage. + this._invalidHandler(key, value, message); + return; + } + } + const { segmentData } = this._getLSData(layer, segment); segmentData.set(key, value); @@ -281,6 +326,38 @@ export class LayeredStorageCore< this._segments.delete(segment); } + /** + * Set a handler for invalid values. + * + * @param handler - The function that will be called with the key, invalid + * value and a message from the failed validator. + */ + public setInvalidHandler( + handler: ( + key: Key, + value: KeyValue[Key], + message: string + ) => void + ): void { + this._invalidHandler = handler; + } + + /** + * Add validators for given key. + * + * @param key - The key whose values will be validated by this validator. + * @param validators - The functions that return true if valid or a string + * explaining what's wrong with the value. + */ + public addValidators( + key: Key, + ...validators: ((value: KeyValue[Key]) => true | string)[] + ): void { + (this._validators.get(key) || this._validators.set(key, []).get(key)!).push( + ...validators + ); + } + /** * Log the content of the storage into the console. */ diff --git a/src/layered-storage/layered-storage.ts b/src/layered-storage/layered-storage.ts index be0775695..fb2783c64 100644 --- a/src/layered-storage/layered-storage.ts +++ b/src/layered-storage/layered-storage.ts @@ -251,6 +251,36 @@ export class LayeredStorage< this._core.deleteSegmentData(segment); } + /** + * Set a handler for invalid values. + * + * @param handler - The function that will be called with the key, invalid + * value and a message from the failed validator. + */ + public setInvalidHandler( + handler: ( + key: Key, + value: KeyValue[Key], + message: string + ) => void + ): void { + this._core.setInvalidHandler(handler); + } + + /** + * Add validators for given key. + * + * @param key - The key whose values will be validated by this validator. + * @param validators - The functions that return true if valid or a string + * explaining what's wrong with the value. + */ + public addValidators( + key: Key, + ...validators: ((value: KeyValue[Key]) => true | string)[] + ): void { + this._core.addValidators(key, ...validators); + } + /** * Log the content of the storage into the console. */ diff --git a/test/layered-storage/index.test.ts b/test/layered-storage/index.test.ts index 72ad2e9e3..fcb8d8786 100644 --- a/test/layered-storage/index.test.ts +++ b/test/layered-storage/index.test.ts @@ -4,6 +4,7 @@ import { multipleLayers } from "./multiple-layers"; import { other } from "./other"; import { segmentedLayer } from "./segmented-layer"; import { singleLayer } from "./single-layer"; +import { validation } from "./validation"; describe("Layered storage", function(): void { allCombined(); @@ -12,4 +13,5 @@ describe("Layered storage", function(): void { other(); segmentedLayer(); singleLayer(); + validation(); }); diff --git a/test/layered-storage/validation.ts b/test/layered-storage/validation.ts new file mode 100644 index 000000000..5937ab3fa --- /dev/null +++ b/test/layered-storage/validation.ts @@ -0,0 +1,116 @@ +import { LayeredStorage } from "../../src/layered-storage"; +import { expect } from "chai"; + +interface KV { + "test.boolean": boolean; + "test.fail": unknown; + "test.integer": number; + "test.number": number; + "test.pass": unknown; + "test.string": string; +} + +/** + * Test that values can be set and retrieved from single monolithic layer. + */ +export function validation(): void { + describe("Validation", function(): void { + [ + // No handler. + ["Default", null, null] as const, + // Handler that does nothing. + ["Ignore", null, (): void => {}] as const, + // Handler that throws. + [ + "Throw", + TypeError, + (key: string, value: unknown, message: string): void => { + throw new TypeError(`${key}: ${value} (${message})`); + } + ] as const + ].forEach(([name, throws, handler]): void => { + describe(name, function(): void { + [ + [false, "test.boolean", 77] as const, + [false, "test.fail", null] as const, + [false, "test.integer", "3.5"] as const, + [false, "test.integer", 3.5] as const, + [false, "test.string", undefined] as const, + [true, "test.boolean", true] as const, + [true, "test.integer", 77] as const, + [true, "test.number", 3.5] as const, + [true, "test.number", 77] as const, + [true, "test.pass", null] as const, + [true, "test.string", "test"] as const + ].forEach(([valid, key, value]): void => { + it(`${key}: ${value}`, function(): void { + const ls = new LayeredStorage(); + + // Add handler. + if (handler != null) { + ls.setInvalidHandler(handler); + } + + // Add validators. + ls.addValidators( + "test.boolean", + (value: unknown): true | string => + typeof value === "boolean" || "it's not valid" + ); + ls.addValidators( + "test.fail", + (): true | string => false || "it's not valid" + ); + ls.addValidators( + "test.integer", + // This tests multiple validators. + (value: unknown): true | string => + typeof value === "number" || "it's not valid", + (value: unknown): true | string => + (typeof value === "number" && value % 1 === 0) || + "it's not valid" + ); + ls.addValidators( + "test.number", + (value: unknown): true | string => + typeof value === "number" || "it's not valid" + ); + ls.addValidators("test.pass", (): true | string => true); + ls.addValidators( + "test.string", + (value: unknown): true | string => + typeof value === "string" || "it's not valid" + ); + + if (valid) { + expect((): void => { + ls.set(0, key, value); + }, "No error should be thrown for valid values.").to.not.throw(); + expect( + ls.get(key), + "Valid values should be saved in the storage." + ).to.equal(value); + } else { + if (throws != null) { + expect((): void => { + ls.set(0, key, value); + }, "If the handler throws the set should throw too.").to.throw( + TypeError, + `${key}: ${value} (it's not valid)` + ); + } else { + expect((): void => { + ls.set(0, key, value); + }, "If the handler doesn't throw neither should the set.").to.not.throw(); + } + expect( + ls.has(key), + "Invalid values should not be saved in the storage." + ).to.be.false; + } + }); + }); + }); + }); + }); +} From b64c4fd997ed3a4488e75d6b0203d4bf2bb4db27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Mon, 23 Dec 2019 22:18:56 +0100 Subject: [PATCH 19/48] perf(layered-storage): do not clean unaffacted cache Prior to this all cache for given key was cleaned on set or delete. However this is only necessary for monolithic segment. Other segments can't affect anything but themselves so it's okay to keep the other segments cached. This greatly improves set and delete performance. --- src/layered-storage/core.ts | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/src/layered-storage/core.ts b/src/layered-storage/core.ts index 252f5e583..a238168bf 100644 --- a/src/layered-storage/core.ts +++ b/src/layered-storage/core.ts @@ -94,17 +94,37 @@ export class LayeredStorageCore< /** * Remove outdated values from the cache. * + * @param segment - Which segment to clean. * @param key - The key that was subject to the mutation. */ - private _cleanCache(key: keyof KeyValue): void { - // Run the search for each segment to clean the cached top level value for - // each of them. - for (const segment of this._segments) { + private _cleanCache(segment: Segment, key: keyof KeyValue): void { + if (segment === this.monolithic) { + // Run the search for each segment to clean the cached top level value + // for each of them. The reason for this is that the monolithic segment + // affects all other segments. + for (const segment of this._segments) { + const sCache = this._topLevelCache.get(segment); + + if (!sCache) { + // This segment has no cache yet. + continue; + } + + // Delete the outdated value. + sCache.delete(key); + + // Delete the whole segment if empty. + if (sCache.size === 0) { + this._topLevelCache.delete(segment); + } + } + } else { + // Clean only the relevant segment. const sCache = this._topLevelCache.get(segment); if (!sCache) { // This segment has no cache yet. - continue; + return; } // Delete the outdated value. @@ -273,7 +293,7 @@ export class LayeredStorageCore< const { segmentData } = this._getLSData(layer, segment); segmentData.set(key, value); - this._cleanCache(key); + this._cleanCache(segment, key); } /** @@ -305,7 +325,7 @@ export class LayeredStorageCore< this._data.delete(layer); } - this._cleanCache(key); + this._cleanCache(segment, key); } /** From 4bf2f3a28e9832ec997acd769521cb255c6a3f99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Wed, 25 Dec 2019 20:13:18 +0100 Subject: [PATCH 20/48] perf(layered-storage): cache nonexistent values too This greatly improves performance on mostly static data as it avoids repeated traversing through the data just to find nothing over and over again. --- src/layered-storage/core.ts | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/layered-storage/core.ts b/src/layered-storage/core.ts index a238168bf..45c14e448 100644 --- a/src/layered-storage/core.ts +++ b/src/layered-storage/core.ts @@ -21,6 +21,19 @@ interface TypedMap set(key: Key, value: KeyValue[Key]): this; } +interface CachedValue { + has: boolean; + value: undefined | Value; +} +interface EmptyCacheValue { + has: false; + value: undefined; +} +const emptyCacheValue: EmptyCacheValue = { + has: false, + value: undefined +}; + /** * Internal core to handle simple data storage, mutation and retrieval. Also * handles the special monolithic segment. @@ -88,7 +101,7 @@ export class LayeredStorageCore< */ private readonly _topLevelCache = new Map< Segment, - Map + TypedMap<{ [Key in keyof KeyValue]: CachedValue }> >(); /** @@ -149,7 +162,7 @@ export class LayeredStorageCore< private _findValue( segment: Segment, key: Key - ): { has: boolean; value: KeyValue[Key] | undefined } { + ): CachedValue | EmptyCacheValue { const segmentCache = this._topLevelCache.get(segment) || this._topLevelCache.set(segment, new Map()).get(segment)!; @@ -192,7 +205,12 @@ export class LayeredStorageCore< } // If nothing was found by now there are no values for the key. - return { has: false, value: undefined }; + + // Save to the cache. + segmentCache.set(key, emptyCacheValue); + + // Return the empty value. + return emptyCacheValue; } /** From 80f189ced8f33ab847de4878400558e2f2ba6fd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Wed, 25 Dec 2019 20:54:53 +0100 Subject: [PATCH 21/48] perf(layered-storage): iterate over cache when clearing it Before this all segments were iterated over and then checked for existence. This is faster as it iterates only over existing cache without checking for each segment's cache existence and also less code. Also includes a test for possible regression that was unchecked before. --- src/layered-storage/core.ts | 17 +++++---------- test/layered-storage/other.ts | 41 +++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 11 deletions(-) diff --git a/src/layered-storage/core.ts b/src/layered-storage/core.ts index 45c14e448..ff69c15cc 100644 --- a/src/layered-storage/core.ts +++ b/src/layered-storage/core.ts @@ -112,23 +112,18 @@ export class LayeredStorageCore< */ private _cleanCache(segment: Segment, key: keyof KeyValue): void { if (segment === this.monolithic) { - // Run the search for each segment to clean the cached top level value - // for each of them. The reason for this is that the monolithic segment - // affects all other segments. - for (const segment of this._segments) { - const sCache = this._topLevelCache.get(segment); - - if (!sCache) { - // This segment has no cache yet. - continue; - } + // Run the search for each cached segment to clean the cached top level + // value for each of them. The reason for this is that the monolithic + // segment affects all other segments. + for (const cache of this._topLevelCache) { + const sCache = cache[1]; // Delete the outdated value. sCache.delete(key); // Delete the whole segment if empty. if (sCache.size === 0) { - this._topLevelCache.delete(segment); + this._topLevelCache.delete(cache[0]); } } } else { diff --git a/test/layered-storage/other.ts b/test/layered-storage/other.ts index 18e1423f7..c9358c060 100644 --- a/test/layered-storage/other.ts +++ b/test/layered-storage/other.ts @@ -23,6 +23,12 @@ export function other(): void { ); }, 0); + const getCacheSize = (ls: LayeredStorage): number => + // Ignore private property access errors. It's no big deal since this + // is a unit test. + // @ts-ignore + ls._core._topLevelCache.size; + it("Empty data structure purging", function(): void { const ls = new LayeredStorage(); @@ -78,6 +84,41 @@ export function other(): void { ); }); + it("Cache purging", function(): void { + const ls = new LayeredStorage(); + + expect(getCacheSize(ls)).to.equal(0); + + ls.set(1, "test.value1", 7); + ls.set(1, "a", "test.value1", 7); + ls.set(1, "b", "test.value1", 7); + ls.set(1, "c", "test.value1", 7); + + expect(getCacheSize(ls)).to.equal(0); + + ls.get("test.value1"); + ls.get("a", "test.value1"); + ls.get("b", "test.value1"); + ls.get("c", "test.value1"); + ls.get("test.value2"); + ls.get("a", "test.value2"); + ls.get("b", "test.value2"); + ls.get("c", "test.value2"); + + expect(getCacheSize(ls)).to.equal(4); + + ls.set(1, "test.value1", 7); + ls.set(1, "a", "test.value1", 7); + ls.set(1, "b", "test.value1", 7); + ls.set(1, "c", "test.value1", 7); + + expect(getCacheSize(ls)).to.equal(4); + + ls.set(1, "test.value2", 7); + + expect(getCacheSize(ls)).to.equal(0); + }); + it("Empty data structure creation", function(): void { const ls = new LayeredStorage(); From e87368a4f942851c7bf6d3510a9c469bea9e6c2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Thu, 26 Dec 2019 17:04:04 +0100 Subject: [PATCH 22/48] feat(layered-storage): add expanders These are used to expand short hand values to their full forms. --- src/layered-storage/common.ts | 9 ++ src/layered-storage/core.ts | 198 +++++++++++++++++++------ src/layered-storage/index.ts | 2 +- src/layered-storage/layered-storage.ts | 107 +++++++------ src/layered-storage/segment.ts | 22 ++- src/layered-storage/transactions.ts | 119 ++++++++------- test/layered-storage/expanders.ts | 117 +++++++++++++++ test/layered-storage/index.test.ts | 2 + 8 files changed, 411 insertions(+), 165 deletions(-) create mode 100644 test/layered-storage/expanders.ts diff --git a/src/layered-storage/common.ts b/src/layered-storage/common.ts index e7fc58923..17b447421 100644 --- a/src/layered-storage/common.ts +++ b/src/layered-storage/common.ts @@ -2,3 +2,12 @@ export type KeyRange = number | string | symbol; export type KeyValueLookup = Record; export type LayerRange = number; export type Segment = boolean | number | object | string | symbol; +export type KeyValuePair = { + [Key in keyof KV]: readonly [Key, KV[Key]]; +}[keyof KV]; +export type FilteredKeyValuePair< + KV extends KeyValueLookup, + Keys extends keyof KV +> = { + [Key in Keys]: readonly [Key, KV[Key]]; +}[Keys]; diff --git a/src/layered-storage/core.ts b/src/layered-storage/core.ts index ff69c15cc..8b5085ef1 100644 --- a/src/layered-storage/core.ts +++ b/src/layered-storage/core.ts @@ -1,24 +1,24 @@ -import { KeyValueLookup, LayerRange, Segment } from "./common"; +import { + KeyValueLookup, + LayerRange, + Segment, + KeyValuePair, + FilteredKeyValuePair +} from "./common"; const reverseNumeric = (a: number, b: number): number => b - a; -type SegmentData = Map< - keyof KeyValue, - KeyValue[keyof KeyValue] ->; -type LayerData = Map< - Segment, - SegmentData ->; -type Data = Map< +type SegmentData = Map; +type LayerData = Map>; +type Data = Map< Layer, - LayerData + LayerData >; -interface TypedMap - extends Map { - get(key: Key): undefined | KeyValue[Key]; - set(key: Key, value: KeyValue[Key]): this; +interface TypedMap + extends Map { + get(key: Key): undefined | KV[Key]; + set(key: Key, value: KV[Key]): this; } interface CachedValue { @@ -38,13 +38,13 @@ const emptyCacheValue: EmptyCacheValue = { * Internal core to handle simple data storage, mutation and retrieval. Also * handles the special monolithic segment. * - * @typeparam KeyValue - Sets the value types associeated with their keys. + * @typeparam KV - Sets the value types associeated with their keys. * (TS only, ignored in JS). * @typeparam Layer - Sets the allowed layers. * (TS only, ignored in JS). */ export class LayeredStorageCore< - KeyValue extends KeyValueLookup, + KV extends KeyValueLookup, Layer extends LayerRange > { /** @@ -56,7 +56,7 @@ export class LayeredStorageCore< /** * Data stored as layer → segment → key → value. */ - private _data: Data = new Map(); + private _data: Data = new Map(); /** * An ordered list of layers. The highest priority (equals highest number) @@ -74,10 +74,27 @@ export class LayeredStorageCore< */ private readonly _validators: TypedMap< { - [Key in keyof KeyValue]: ((value: KeyValue[Key]) => true | string)[]; + [Key in keyof KV]: ((value: KV[Key]) => true | string)[]; + } + > = new Map(); + + /** + * An expander for each key. + */ + private readonly _setExpanders: TypedMap< + { + [Key in keyof KV]: (value: KV[Key]) => KeyValuePair[]; } > = new Map(); + /** + * An expander for each key. + */ + private readonly _deleteExpanders: Map< + keyof KV, + readonly (keyof KV)[] + > = new Map(); + /** * This is called whenever a validity test fails. * @@ -85,9 +102,9 @@ export class LayeredStorageCore< * @param value - The invalid value itself. * @param message - The message returned by the validator that failed. */ - private _invalidHandler: ( + private _invalidHandler: ( key: Key, - value: KeyValue[Key], + value: KV[Key], message: string ) => void = (key, value, message): void => { console.error("Invalid value was ignored.", { key, value, message }); @@ -101,7 +118,7 @@ export class LayeredStorageCore< */ private readonly _topLevelCache = new Map< Segment, - TypedMap<{ [Key in keyof KeyValue]: CachedValue }> + TypedMap<{ [Key in keyof KV]: CachedValue }> >(); /** @@ -110,7 +127,7 @@ export class LayeredStorageCore< * @param segment - Which segment to clean. * @param key - The key that was subject to the mutation. */ - private _cleanCache(segment: Segment, key: keyof KeyValue): void { + private _cleanCache(segment: Segment, key: keyof KV): void { if (segment === this.monolithic) { // Run the search for each cached segment to clean the cached top level // value for each of them. The reason for this is that the monolithic @@ -154,10 +171,10 @@ export class LayeredStorageCore< * * @returns Whether such value exists (`has`) and the value itself (`value`). */ - private _findValue( + private _findValue( segment: Segment, key: Key - ): CachedValue | EmptyCacheValue { + ): CachedValue | EmptyCacheValue { const segmentCache = this._topLevelCache.get(segment) || this._topLevelCache.set(segment, new Map()).get(segment)!; @@ -221,7 +238,7 @@ export class LayeredStorageCore< private _getLSData( layer: Layer, segment: Segment - ): { layerData: LayerData; segmentData: SegmentData } { + ): { layerData: LayerData; segmentData: SegmentData } { // Get or create the requested layer. let layerData = this._data.get(layer); if (layerData == null) { @@ -251,10 +268,10 @@ export class LayeredStorageCore< * * @returns The value or undefined if not found. */ - public get( + public get( segment: Segment, key: Key - ): KeyValue[Key] | undefined { + ): KV[Key] | undefined { return this._findValue(segment, key).value; } @@ -266,7 +283,7 @@ export class LayeredStorageCore< * * @returns True if found, false otherwise. */ - public has(segment: Segment, key: Key): boolean { + public has(segment: Segment, key: Key): boolean { return this._findValue(segment, key).has; } @@ -278,28 +295,31 @@ export class LayeredStorageCore< * @param key - Key that can be used to retrieve or overwrite this value later. * @param value - The value to be saved. */ - public set( + public set( layer: Layer, segment: Segment, key: Key, - value: KeyValue[Key] + value: KV[Key] ): void { if (typeof layer !== "number") { throw new TypeError("Layers have to be numbers."); } - for (const validator of this._validators.get(key) || []) { - const message = validator(value); - if (message === true) { - // The value is valid. Proceed with another test or save the value into - // the storage if this was the last one. - continue; - } else { - // The value is invalid. Call the invalid value handler and, if the - // handler didn't throw, stop execution of this function to prevent the - // value from being saved into the storage. - this._invalidHandler(key, value, message); - return; + const validators = this._validators.get(key); + if (validators) { + for (const validator of validators) { + const message = validator(value); + if (message === true) { + // The value is valid. Proceed with another test or save the value + // into the storage if this was the last one. + continue; + } else { + // The value is invalid. Call the invalid value handler and, if the + // handler didn't throw, stop execution of this function to prevent + // the value from being saved into the storage. + this._invalidHandler(key, value, message); + return; + } } } @@ -316,7 +336,7 @@ export class LayeredStorageCore< * @param segment - Which segment to delete from. * @param key - The key that identifies the value to be deleted. */ - public delete( + public delete( layer: Layer, segment: Segment, key: Key @@ -366,9 +386,9 @@ export class LayeredStorageCore< * value and a message from the failed validator. */ public setInvalidHandler( - handler: ( + handler: ( key: Key, - value: KeyValue[Key], + value: KV[Key], message: string ) => void ): void { @@ -382,15 +402,97 @@ export class LayeredStorageCore< * @param validators - The functions that return true if valid or a string * explaining what's wrong with the value. */ - public addValidators( + public addValidators( key: Key, - ...validators: ((value: KeyValue[Key]) => true | string)[] + ...validators: ((value: KV[Key]) => true | string)[] ): void { (this._validators.get(key) || this._validators.set(key, []).get(key)!).push( ...validators ); } + /** + * Set an expander for given key. + * + * @remarks + * These are used in transactions to expand keys prior to them being + * applied. Using them here would prevent transactions from being atomic. + * + * @param key - The key whose values will be expanded by this expander. + * @param affects - The expanded keys that will be returned by the + * expaner and also deleted if this key is deleted. + * @param expander - The functions that returns an array of expanded key + * value pairs. + * @param replace - If true existing expander will be relaced, if false an + * error will be thrown if an expander already exists for given key. + */ + public setExpander( + key: Key, + affects: readonly Affects[], + expander: (value: KV[Key]) => FilteredKeyValuePair[], + replace: boolean + ): void { + if ( + !replace && + (this._setExpanders.has(key) || this._deleteExpanders.has(key)) + ) { + throw new Error("An expander for this key already exists."); + } + + this._setExpanders.set(key, expander); + this._deleteExpanders.set(key, affects); + } + + /** + * Expand given value. + * + * @param key - Which key this value belongs to. + * @param value - The value to be expanded. + * + * @returns Expanded key value pairs or empty array for invalid input. + */ + public expandSet( + key: Key, + value: KV[Key] + ): KeyValuePair[] { + const validators = this._validators.get(key); + if (validators) { + for (const validator of validators) { + const message = validator(value); + if (message === true) { + // The value is valid. Proceed with another test or save the value + // into the storage if this was the last one. + continue; + } else { + // The value is invalid. Call the invalid value handler and, if the + // handler didn't throw, stop execution of this function to prevent + // the value from being saved into the storage. + this._invalidHandler(key, value, message); + return []; + } + } + } + + const expand = this._setExpanders.get(key); + if (expand) { + return expand(value); + } else { + return [[key, value]]; + } + } + + /** + * Expand given value. + * + * @param key - Which key this value belongs to. + * @param value - The value to be expanded. + * + * @returns Expanded key value pairs or empty array for invalid input. + */ + public expandDelete(key: Key): readonly (keyof KV)[] { + return this._deleteExpanders.get(key) || [key]; + } + /** * Log the content of the storage into the console. */ diff --git a/src/layered-storage/index.ts b/src/layered-storage/index.ts index 5aa8b2fdd..c1f2c4a87 100644 --- a/src/layered-storage/index.ts +++ b/src/layered-storage/index.ts @@ -4,4 +4,4 @@ export { LayeredStorageTransaction } from "./layered-storage"; export { LayeredStorageSegment } from "./segment"; -export { KeyValueLookup, LayerRange, Segment } from "./common"; +export * from "./common"; diff --git a/src/layered-storage/layered-storage.ts b/src/layered-storage/layered-storage.ts index fb2783c64..ed2cb2879 100644 --- a/src/layered-storage/layered-storage.ts +++ b/src/layered-storage/layered-storage.ts @@ -1,4 +1,10 @@ -import { KeyValueLookup, LayerRange, Segment } from "./common"; +import { + KeyValueLookup, + LayerRange, + Segment, + KeyValuePair, + FilteredKeyValuePair +} from "./common"; import { LayeredStorageCore } from "./core"; import { LayeredStorageSegment } from "./segment"; import { @@ -23,37 +29,37 @@ export { * - Each layer can be segmented using arbitrary values. * - Segmented value overrides monolithic (nonsegmented) value. * - * @typeparam KeyValue - Sets the value types associeated with their keys. + * @typeparam KV - Sets the value types associeated with their keys. * (TS only, ignored in JS). * @typeparam Layer - Sets the allowed layers. * (TS only, ignored in JS). */ export class LayeredStorage< - KeyValue extends KeyValueLookup, + KV extends KeyValueLookup, Layer extends LayerRange > { - private _core = new LayeredStorageCore(); + private _core = new LayeredStorageCore(); /** * @param segment - Which segment to search through in addition to the monolithic part of the storage. * @param key - The key corresponding to the requested value. */ - public get( + public get( segment: Segment, key: Key - ): KeyValue[Key] | undefined; + ): KV[Key] | undefined; /** * @param key - The key corresponding to the requested value. */ - public get(key: Key): KeyValue[Key] | undefined; + public get(key: Key): KV[Key] | undefined; /** * Retrieve a value. * * @returns The value or undefined if not found. */ - public get( + public get( ...rest: [Key] | [Segment, Key] - ): KeyValue[Key] | undefined { + ): KV[Key] | undefined { return rest.length === 1 ? this._core.get(this._core.monolithic, rest[0]) : this._core.get(rest[0], rest[1]); @@ -63,17 +69,17 @@ export class LayeredStorage< * @param segment - Which segment to search through in addition to the monolithic part of the storage. * @param key - The key corresponding to the requested value. */ - public has(segment: Segment, key: Key): boolean; + public has(segment: Segment, key: Key): boolean; /** * @param key - The key corresponding to the requested value. */ - public has(key: Key): boolean; + public has(key: Key): boolean; /** * Check if a value is present. * * @returns True if found, false otherwise. */ - public has(...rest: [keyof KeyValue] | [Segment, keyof KeyValue]): boolean { + public has(...rest: [keyof KV] | [Segment, keyof KV]): boolean { return rest.length === 1 ? this._core.has(this._core.monolithic, rest[0]) : this._core.has(rest[0], rest[1]); @@ -85,27 +91,27 @@ export class LayeredStorage< * @param key - Key that can be used to retrieve or overwrite this value later. * @param value - The value to be saved. */ - public set( + public set( layer: Layer, segment: Segment, key: Key, - value: KeyValue[Key] + value: KV[Key] ): void; /** * @param layer - Which layer to save the value into. * @param key - Key that can be used to retrieve or overwrite this value later. * @param value - The value to be saved. */ - public set( + public set( layer: Layer, key: Key, - value: KeyValue[Key] + value: KV[Key] ): void; /** * Save a value. */ - public set( - ...rest: [Layer, Segment, Key, KeyValue[Key]] | [Layer, Key, KeyValue[Key]] + public set( + ...rest: [Layer, Segment, Key, KV[Key]] | [Layer, Key, KV[Key]] ): void { this.runTransaction( (transaction): void => @@ -120,23 +126,20 @@ export class LayeredStorage< * @param segment - Which segment to delete from. * @param key - The key that identifies the value to be deleted. */ - public delete( + public delete( layer: Layer, segment: Segment, key: Key - ): KeyValue[Key]; + ): KV[Key]; /** * @param layer - Which layer to delete from. * @param key - The key that identifies the value to be deleted. */ - public delete( - layer: Layer, - key: Key - ): KeyValue[Key]; + public delete(layer: Layer, key: Key): KV[Key]; /** * Delete a value from the storage. */ - public delete( + public delete( ...rest: [Layer, Segment, Key] | [Layer, Key] ): void { this.runTransaction( @@ -149,8 +152,8 @@ export class LayeredStorage< public openTransaction( segment: Segment - ): LayeredStorageSegmentTransaction; - public openTransaction(): LayeredStorageTransaction; + ): LayeredStorageSegmentTransaction; + public openTransaction(): LayeredStorageTransaction; /** * Open a new transaction. * @@ -167,11 +170,11 @@ export class LayeredStorage< public openTransaction( segment?: Segment ): - | LayeredStorageSegmentTransaction - | LayeredStorageTransaction { + | LayeredStorageSegmentTransaction + | LayeredStorageTransaction { return segment == null - ? new MonolithicTransaction(this._core) - : new SegmentTransaction(this._core, segment); + ? new MonolithicTransaction(this._core) + : new SegmentTransaction(this._core, segment); } /** @@ -181,16 +184,14 @@ export class LayeredStorage< */ public runTransaction( segment: Segment, - callback: ( - transaction: LayeredStorageSegmentTransaction - ) => void + callback: (transaction: LayeredStorageSegmentTransaction) => void ): void; /** * @param callback - This callback will be called with the transaction as * it's sole parameter. */ public runTransaction( - callback: (transaction: LayeredStorageTransaction) => void + callback: (transaction: LayeredStorageTransaction) => void ): void; /** * Run a new transaction. @@ -204,11 +205,9 @@ export class LayeredStorage< ...rest: | [ Segment, - ( - transaction: LayeredStorageSegmentTransaction - ) => void + (transaction: LayeredStorageSegmentTransaction) => void ] - | [(transaction: LayeredStorageTransaction) => void] + | [(transaction: LayeredStorageTransaction) => void] ): void { if (rest.length === 1) { const callback = rest[0]; @@ -238,7 +237,7 @@ export class LayeredStorage< * * @returns A new segmented instance permanently bound to this instance. */ - public openSegment(segment: Segment): LayeredStorageSegment { + public openSegment(segment: Segment): LayeredStorageSegment { return new LayeredStorageSegment(this, segment); } @@ -258,9 +257,9 @@ export class LayeredStorage< * value and a message from the failed validator. */ public setInvalidHandler( - handler: ( + handler: ( key: Key, - value: KeyValue[Key], + value: KV[Key], message: string ) => void ): void { @@ -274,13 +273,33 @@ export class LayeredStorage< * @param validators - The functions that return true if valid or a string * explaining what's wrong with the value. */ - public addValidators( + public addValidators( key: Key, - ...validators: ((value: KeyValue[Key]) => true | string)[] + ...validators: ((value: KV[Key]) => true | string)[] ): void { this._core.addValidators(key, ...validators); } + /** + * Set an expander for given key. + * + * @param key - The key whose values will be expanded by this expander. + * @param affects - The expanded keys that will be returned by the + * expaner and also deleted if this key is deleted. + * @param expander - The functions that returns an array of expanded key + * value pairs. + * @param replace - If true existing expander will be relaced, if false an + * error will be thrown if an expander already exists for given key. + */ + public setExpander( + key: Key, + affects: readonly Affects[], + expander: (value: KV[Key]) => FilteredKeyValuePair[], + replace = false + ): void { + this._core.setExpander(key, affects, expander, replace); + } + /** * Log the content of the storage into the console. */ diff --git a/src/layered-storage/segment.ts b/src/layered-storage/segment.ts index 14e224022..c9ea6179a 100644 --- a/src/layered-storage/segment.ts +++ b/src/layered-storage/segment.ts @@ -8,13 +8,13 @@ import { * This is similar as `LayeredStorage` except that it is permanently bound to * given `LayeredStorage` and can only access a single `Segment`. * - * @typeparam KeyValue - Sets the value types associeated with their keys. + * @typeparam KV - Sets the value types associeated with their keys. * (TS only, ignored in JS). * @typeparam Layer - Sets the allowed layers. * (TS only, ignored in JS). */ export class LayeredStorageSegment< - KeyValue extends KeyValueLookup, + KV extends KeyValueLookup, Layer extends LayerRange > { /** @@ -24,7 +24,7 @@ export class LayeredStorageSegment< * @param _segment - The segment this instance will manage. */ public constructor( - private _layeredStorage: LayeredStorage, + private _layeredStorage: LayeredStorage, private _segment: Segment ) {} @@ -35,7 +35,7 @@ export class LayeredStorageSegment< * * @returns The value or undefined if not found. */ - public get(key: Key): KeyValue[Key] | undefined { + public get(key: Key): KV[Key] | undefined { return this._layeredStorage.get(this._segment, key); } @@ -46,7 +46,7 @@ export class LayeredStorageSegment< * * @returns True if found, false otherwise. */ - public has(key: Key): boolean { + public has(key: Key): boolean { return this._layeredStorage.has(this._segment, key); } @@ -57,10 +57,10 @@ export class LayeredStorageSegment< * @param key - Key that can be used to retrieve or overwrite this value later. * @param value - The value to be saved. */ - public set( + public set( layer: Layer, key: Key, - value: KeyValue[Key] + value: KV[Key] ): void { this._layeredStorage.set(layer, this._segment, key, value); } @@ -71,7 +71,7 @@ export class LayeredStorageSegment< * @param layer - Which layer to delete from. * @param key - The key that identifies the value to be deleted. */ - public delete(layer: Layer, key: Key): void { + public delete(layer: Layer, key: Key): void { this._layeredStorage.delete(layer, this._segment, key); } @@ -84,7 +84,7 @@ export class LayeredStorageSegment< * * @returns The new transaction that can be used to set or delete values. */ - public openTransaction(): LayeredStorageSegmentTransaction { + public openTransaction(): LayeredStorageSegmentTransaction { return this._layeredStorage.openTransaction(this._segment); } @@ -99,9 +99,7 @@ export class LayeredStorageSegment< * @param callback - This callback will be called with the transaction as */ public runTransaction( - callback: ( - transaction: LayeredStorageSegmentTransaction - ) => void + callback: (transaction: LayeredStorageSegmentTransaction) => void ): void { this._layeredStorage.runTransaction(this._segment, callback); } diff --git a/src/layered-storage/transactions.ts b/src/layered-storage/transactions.ts index 127c33865..718289813 100644 --- a/src/layered-storage/transactions.ts +++ b/src/layered-storage/transactions.ts @@ -5,15 +5,12 @@ import { LayeredStorageCore } from "./core"; * This is used through composition to create monolithic and segmented * transactions without massive code duplicities. * - * @typeparam KeyValue - Sets the value types associeated with their keys. + * @typeparam KV - Sets the value types associeated with their keys. * (TS only, ignored in JS). * @typeparam Layer - Sets the allowed layers. * (TS only, ignored in JS). */ -class TransactionCore< - KeyValue extends KeyValueLookup, - Layer extends LayerRange -> { +class TransactionCore { /** * Functions that perform requested mutations when executed without any * arguments or this. Intended to be filled bound set and delete methods from @@ -28,9 +25,7 @@ class TransactionCore< * @param _listeners - Listeners that should be notified after a transaction * was commited. */ - public constructor( - private _storageCore: LayeredStorageCore - ) {} + public constructor(private _storageCore: LayeredStorageCore) {} /** * Queue set mutation. @@ -40,15 +35,24 @@ class TransactionCore< * @param key - Key that can be used to retrieve or overwrite this value later. * @param value - The value to be saved. */ - public set( + public set( layer: Layer, segment: Segment, key: Key, - value: KeyValue[Key] + value: KV[Key] ): void { - this._actions.push( - this._storageCore.set.bind(this._storageCore, layer, segment, key, value) - ); + const expandedPairs = this._storageCore.expandSet(key, value); + for (const expanded of expandedPairs) { + this._actions.push( + this._storageCore.set.bind( + this._storageCore, + layer, + segment, + expanded[0], + expanded[1] + ) + ); + } } /** @@ -58,14 +62,21 @@ class TransactionCore< * @param segment - Which segment to delete from. * @param key - The key that identifies the value to be deleted. */ - public delete( + public delete( layer: Layer, segment: Segment, key: Key ): void { - this._actions.push( - this._storageCore.delete.bind(this._storageCore, layer, segment, key) - ); + for (const expandedKey of this._storageCore.expandDelete(key)) { + this._actions.push( + this._storageCore.delete.bind( + this._storageCore, + layer, + segment, + expandedKey + ) + ); + } } /** @@ -89,13 +100,13 @@ class TransactionCore< /** * A transaction working with the whole storage. * - * @typeparam KeyValue - Sets the value types associeated with their keys. + * @typeparam KV - Sets the value types associeated with their keys. * (TS only, ignored in JS). * @typeparam Layer - Sets the allowed layers. * (TS only, ignored in JS). */ export interface LayeredStorageTransaction< - KeyValue extends KeyValueLookup, + KV extends KeyValueLookup, Layer extends LayerRange > { /** @@ -106,11 +117,11 @@ export interface LayeredStorageTransaction< * @param key - Key that can be used to retrieve or overwrite this value later. * @param value - The value to be saved. */ - set( + set( layer: Layer, segment: Segment, key: Key, - value: KeyValue[Key] + value: KV[Key] ): void; /** * Queue a value to be set. @@ -119,11 +130,7 @@ export interface LayeredStorageTransaction< * @param key - Key that can be used to retrieve or overwrite this value later. * @param value - The value to be saved. */ - set( - layer: Layer, - key: Key, - value: KeyValue[Key] - ): void; + set(layer: Layer, key: Key, value: KV[Key]): void; /** * Queue a value to be deleted. @@ -132,18 +139,14 @@ export interface LayeredStorageTransaction< * @param segment - Which segment to delete from. * @param key - The key that identifies the value to be deleted. */ - delete( - layer: Layer, - segment: Segment, - key: Key - ): void; + delete(layer: Layer, segment: Segment, key: Key): void; /** * Queue a value to be deleted. * * @param layer - Which layer to delete from. * @param key - The key that identifies the value to be deleted. */ - delete(layer: Layer, key: Key): void; + delete(layer: Layer, key: Key): void; /** * Commit all queued operations. @@ -158,10 +161,10 @@ export interface LayeredStorageTransaction< /** @inheritdoc */ export class MonolithicTransaction< - KeyValue extends KeyValueLookup, + KV extends KeyValueLookup, Layer extends LayerRange -> implements LayeredStorageTransaction { - private readonly _transactionCore: TransactionCore; +> implements LayeredStorageTransaction { + private readonly _transactionCore: TransactionCore; private readonly _monolithic: symbol; /** @@ -171,39 +174,39 @@ export class MonolithicTransaction< * @param listeners - Listeners that should be notified after a transaction * was commited. */ - public constructor(storageCore: LayeredStorageCore) { + public constructor(storageCore: LayeredStorageCore) { this._monolithic = storageCore.monolithic; this._transactionCore = new TransactionCore(storageCore); } - public set( + public set( layer: Layer, segment: Segment, key: Key, - value: KeyValue[Key] + value: KV[Key] ): void; - public set( + public set( layer: Layer, key: Key, - value: KeyValue[Key] + value: KV[Key] ): void; /** @inheritdoc */ - public set( - ...rest: [Layer, Segment, Key, KeyValue[Key]] | [Layer, Key, KeyValue[Key]] + public set( + ...rest: [Layer, Segment, Key, KV[Key]] | [Layer, Key, KV[Key]] ): void { return rest.length === 3 ? this._transactionCore.set(rest[0], this._monolithic, rest[1], rest[2]) : this._transactionCore.set(rest[0], rest[1], rest[2], rest[3]); } - public delete( + public delete( layer: Layer, segment: Segment, key: Key ): void; - public delete(layer: Layer, key: Key): void; + public delete(layer: Layer, key: Key): void; /** @inheritdoc */ - public delete( + public delete( ...rest: [Layer, Segment, Key] | [Layer, Key] ): void { return rest.length === 2 @@ -224,7 +227,7 @@ export class MonolithicTransaction< /** @inheritdoc */ export interface LayeredStorageSegmentTransaction< - KeyValue extends KeyValueLookup, + KV extends KeyValueLookup, Layer extends LayerRange > { /** @@ -234,11 +237,7 @@ export interface LayeredStorageSegmentTransaction< * @param key - Key that can be used to retrieve or overwrite this value later. * @param value - The value to be saved. */ - set( - layer: Layer, - key: Key, - value: KeyValue[Key] - ): void; + set(layer: Layer, key: Key, value: KV[Key]): void; /** * Queue a value to be deleted. @@ -246,7 +245,7 @@ export interface LayeredStorageSegmentTransaction< * @param layer - Which layer to delete from. * @param key - The key that identifies the value to be deleted. */ - delete(layer: Layer, key: Key): void; + delete(layer: Layer, key: Key): void; /** * Commit all queued operations. @@ -262,16 +261,16 @@ export interface LayeredStorageSegmentTransaction< /** * A transaction working with a single segment. * - * @typeparam KeyValue - Sets the value types associeated with their keys. + * @typeparam KV - Sets the value types associeated with their keys. * (TS only, ignored in JS). * @typeparam Layer - Sets the allowed layers. * (TS only, ignored in JS). */ export class SegmentTransaction< - KeyValue extends KeyValueLookup, + KV extends KeyValueLookup, Layer extends LayerRange -> implements LayeredStorageSegmentTransaction { - private readonly _transactionCore: TransactionCore; +> implements LayeredStorageSegmentTransaction { + private readonly _transactionCore: TransactionCore; /** * Create a new transaction for a segment of given storage. @@ -282,23 +281,23 @@ export class SegmentTransaction< * @param _segment - The segment this instance will manage. */ public constructor( - storageCore: LayeredStorageCore, + storageCore: LayeredStorageCore, private readonly _segment: Segment ) { this._transactionCore = new TransactionCore(storageCore); } /** @inheritdoc */ - public set( + public set( layer: Layer, key: Key, - value: KeyValue[Key] + value: KV[Key] ): void { return this._transactionCore.set(layer, this._segment, key, value); } /** @inheritdoc */ - public delete(layer: Layer, key: Key): void { + public delete(layer: Layer, key: Key): void { return this._transactionCore.delete(layer, this._segment, key); } diff --git a/test/layered-storage/expanders.ts b/test/layered-storage/expanders.ts new file mode 100644 index 000000000..03d4a6937 --- /dev/null +++ b/test/layered-storage/expanders.ts @@ -0,0 +1,117 @@ +import { + LayeredStorage, + KeyValuePair, + FilteredKeyValuePair +} from "../../src/layered-storage"; +import { deepFreeze } from "../helpers"; +import { expect } from "chai"; + +interface KV { + test: string; // `${test.boolean} ${test.number} ${test.string}` + "test.boolean": boolean; + "test.number": number; + "test.string": string; +} + +/** + * Test that values can be set and retrieved from single monolithic layer. + */ +export function expanders(): void { + describe("Expanders", function(): void { + const expanderAffects = [ + "test.boolean", + "test.number", + "test.string" + ] as const; + const expander = ( + input: string + ): FilteredKeyValuePair< + KV, + "test.boolean" | "test.number" | "test.string" + >[] => { + const [boolean, number, string] = input.split(" "); + return [ + ["test.boolean", boolean === "true" ? true : false], + ["test.number", +number], + ["test.string", string] + ]; + }; + const invalidHandler = (): never => { + throw new Error("Invalid input."); + }; + + it("Without validation", function(): void { + const ls = new LayeredStorage(); + + ls.setExpander("test", expanderAffects, expander); + + const testValue = "false 7 seven"; + + ls.set(0, "test", testValue); + + expect(ls.has("test"), "The raw value should not be saved.").to.be.false; + + expect( + [ls.get("test.boolean"), ls.get("test.number"), ls.get("test.string")], + "The expanded values from the expander should be returned." + ).to.deep.equal([false, 7, "seven"]); + }); + + it("Invalid short value", function(): void { + const ls = new LayeredStorage(); + + ls.addValidators( + "test", + (value): true | string => + /^(true|false) \d+ .*$/.test(value) || "Invalid." + ); + ls.setInvalidHandler(invalidHandler); + ls.setExpander("test", expanderAffects, expander); + + const testValue = "false7seven"; + + expect( + (): void => void ls.set(0, "test", testValue), + "Invalid values should not pass validation." + ).to.throw(); + }); + + it("Invalid expanded value", function(): void { + const ls = new LayeredStorage(); + + ls.addValidators( + "test.number", + (value): true | string => value < 7 || "Invalid input." + ); + ls.setInvalidHandler(invalidHandler); + ls.setExpander("test", expanderAffects, expander); + + const testValue = "false 7 seven"; + + expect( + (): void => void ls.set(0, "test", testValue), + "Invalid values should not pass validation." + ).to.throw(); + }); + + it("Delete expanded values", function(): void { + const ls = new LayeredStorage(); + + ls.setExpander("test", expanderAffects, expander); + + const testValue = "false 7 seven"; + + ls.set(0, "test", testValue); + expect( + [ls.has("test.boolean"), ls.has("test.number"), ls.has("test.string")], + "All expanded values should be set." + ).deep.equal([true, true, true]); + + ls.delete(0, "test"); + expect( + [ls.has("test.boolean"), ls.has("test.number"), ls.has("test.string")], + "All expanded values should be deleted." + ).deep.equal([false, false, false]); + }); + }); +} diff --git a/test/layered-storage/index.test.ts b/test/layered-storage/index.test.ts index fcb8d8786..be007007d 100644 --- a/test/layered-storage/index.test.ts +++ b/test/layered-storage/index.test.ts @@ -1,4 +1,5 @@ import { allCombined } from "./all-combined"; +import { expanders } from "./expanders"; import { multipleKeys } from "./multiple-keys"; import { multipleLayers } from "./multiple-layers"; import { other } from "./other"; @@ -8,6 +9,7 @@ import { validation } from "./validation"; describe("Layered storage", function(): void { allCombined(); + expanders(); multipleKeys(); multipleLayers(); other(); From 1ca06e15a25fa7fe317574f5899252df7856d6b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Fri, 27 Dec 2019 00:01:47 +0100 Subject: [PATCH 23/48] feat(layered-storage): unify validator and expander API BREAKING CHANGE: addValidators no longer exists Appending validators to already existing one is most likely an error. At least in Vis Network I see no reason to do it. Therefore it makes more sense to throw in such a case. --- src/layered-storage/core.ts | 25 ++++++++++------- src/layered-storage/layered-storage.ts | 14 ++++++---- test/layered-storage/expanders.ts | 16 ++++------- test/layered-storage/validation.ts | 38 +++++++++++++++----------- 4 files changed, 51 insertions(+), 42 deletions(-) diff --git a/src/layered-storage/core.ts b/src/layered-storage/core.ts index 8b5085ef1..ae4ae139c 100644 --- a/src/layered-storage/core.ts +++ b/src/layered-storage/core.ts @@ -83,7 +83,7 @@ export class LayeredStorageCore< */ private readonly _setExpanders: TypedMap< { - [Key in keyof KV]: (value: KV[Key]) => KeyValuePair[]; + [Key in keyof KV]: (value: KV[Key]) => readonly KeyValuePair[]; } > = new Map(); @@ -396,19 +396,24 @@ export class LayeredStorageCore< } /** - * Add validators for given key. + * Set validators for given key. * * @param key - The key whose values will be validated by this validator. * @param validators - The functions that return true if valid or a string * explaining what's wrong with the value. + * @param replace - If true existing validators will be replaced, if false an + * error will be thrown if some validators already exist for given key. */ - public addValidators( + public setValidators( key: Key, - ...validators: ((value: KV[Key]) => true | string)[] + validators: ((value: KV[Key]) => true | string)[], + replace: boolean ): void { - (this._validators.get(key) || this._validators.set(key, []).get(key)!).push( - ...validators - ); + if (!replace && this._validators.has(key)) { + throw new Error("Some validators for this key already exist."); + } + + this._validators.set(key, validators); } /** @@ -423,13 +428,13 @@ export class LayeredStorageCore< * expaner and also deleted if this key is deleted. * @param expander - The functions that returns an array of expanded key * value pairs. - * @param replace - If true existing expander will be relaced, if false an + * @param replace - If true existing expander will be replaced, if false an * error will be thrown if an expander already exists for given key. */ public setExpander( key: Key, affects: readonly Affects[], - expander: (value: KV[Key]) => FilteredKeyValuePair[], + expander: (value: KV[Key]) => readonly FilteredKeyValuePair[], replace: boolean ): void { if ( @@ -454,7 +459,7 @@ export class LayeredStorageCore< public expandSet( key: Key, value: KV[Key] - ): KeyValuePair[] { + ): readonly KeyValuePair[] { const validators = this._validators.get(key); if (validators) { for (const validator of validators) { diff --git a/src/layered-storage/layered-storage.ts b/src/layered-storage/layered-storage.ts index ed2cb2879..5ab5d5f21 100644 --- a/src/layered-storage/layered-storage.ts +++ b/src/layered-storage/layered-storage.ts @@ -2,7 +2,6 @@ import { KeyValueLookup, LayerRange, Segment, - KeyValuePair, FilteredKeyValuePair } from "./common"; import { LayeredStorageCore } from "./core"; @@ -267,17 +266,20 @@ export class LayeredStorage< } /** - * Add validators for given key. + * Set validators for given key. * * @param key - The key whose values will be validated by this validator. * @param validators - The functions that return true if valid or a string * explaining what's wrong with the value. + * @param replace - If true existing validators will be replaced, if false an + * error will be thrown if some validators already exist for given key. */ - public addValidators( + public setValidators( key: Key, - ...validators: ((value: KV[Key]) => true | string)[] + validators: ((value: KV[Key]) => true | string)[], + replace = false ): void { - this._core.addValidators(key, ...validators); + this._core.setValidators(key, validators, replace); } /** @@ -294,7 +296,7 @@ export class LayeredStorage< public setExpander( key: Key, affects: readonly Affects[], - expander: (value: KV[Key]) => FilteredKeyValuePair[], + expander: (value: KV[Key]) => readonly FilteredKeyValuePair[], replace = false ): void { this._core.setExpander(key, affects, expander, replace); diff --git a/test/layered-storage/expanders.ts b/test/layered-storage/expanders.ts index 03d4a6937..948d82406 100644 --- a/test/layered-storage/expanders.ts +++ b/test/layered-storage/expanders.ts @@ -1,9 +1,7 @@ import { LayeredStorage, - KeyValuePair, FilteredKeyValuePair } from "../../src/layered-storage"; -import { deepFreeze } from "../helpers"; import { expect } from "chai"; interface KV { @@ -25,7 +23,7 @@ export function expanders(): void { ] as const; const expander = ( input: string - ): FilteredKeyValuePair< + ): readonly FilteredKeyValuePair< KV, "test.boolean" | "test.number" | "test.string" >[] => { @@ -34,7 +32,7 @@ export function expanders(): void { ["test.boolean", boolean === "true" ? true : false], ["test.number", +number], ["test.string", string] - ]; + ] as const; }; const invalidHandler = (): never => { throw new Error("Invalid input."); @@ -60,11 +58,10 @@ export function expanders(): void { it("Invalid short value", function(): void { const ls = new LayeredStorage(); - ls.addValidators( - "test", + ls.setValidators("test", [ (value): true | string => /^(true|false) \d+ .*$/.test(value) || "Invalid." - ); + ]); ls.setInvalidHandler(invalidHandler); ls.setExpander("test", expanderAffects, expander); @@ -79,10 +76,9 @@ export function expanders(): void { it("Invalid expanded value", function(): void { const ls = new LayeredStorage(); - ls.addValidators( - "test.number", + ls.setValidators("test.number", [ (value): true | string => value < 7 || "Invalid input." - ); + ]); ls.setInvalidHandler(invalidHandler); ls.setExpander("test", expanderAffects, expander); diff --git a/test/layered-storage/validation.ts b/test/layered-storage/validation.ts index 5937ab3fa..4a812a4e0 100644 --- a/test/layered-storage/validation.ts +++ b/test/layered-storage/validation.ts @@ -52,35 +52,30 @@ export function validation(): void { } // Add validators. - ls.addValidators( - "test.boolean", + ls.setValidators("test.boolean", [ (value: unknown): true | string => typeof value === "boolean" || "it's not valid" - ); - ls.addValidators( - "test.fail", + ]); + ls.setValidators("test.fail", [ (): true | string => false || "it's not valid" - ); - ls.addValidators( - "test.integer", + ]); + ls.setValidators("test.integer", [ // This tests multiple validators. (value: unknown): true | string => typeof value === "number" || "it's not valid", (value: unknown): true | string => (typeof value === "number" && value % 1 === 0) || "it's not valid" - ); - ls.addValidators( - "test.number", + ]); + ls.setValidators("test.number", [ (value: unknown): true | string => typeof value === "number" || "it's not valid" - ); - ls.addValidators("test.pass", (): true | string => true); - ls.addValidators( - "test.string", + ]); + ls.setValidators("test.pass", [(): true | string => true]); + ls.setValidators("test.string", [ (value: unknown): true | string => typeof value === "string" || "it's not valid" - ); + ]); if (valid) { expect((): void => { @@ -112,5 +107,16 @@ export function validation(): void { }); }); }); + + it("Setting validators twice", function(): void { + const ls = new LayeredStorage(); + + expect((): void => { + ls.setValidators("test.fail", [ + (): true | string => false || "it's not valid" + ]); + ls.setValidators("test.fail", [(): true | string => true]); + }, "Setting validators repeatedly without replace shoudn't be allowed.").to.throw(); + }); }); } From 1fed169ee4b12d979f5dd4bcbbec5f0f2a662d62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Fri, 27 Dec 2019 19:51:29 +0100 Subject: [PATCH 24/48] feat(layered-storage): add segment cloning --- src/layered-storage/core.ts | 36 +++++++++- src/layered-storage/layered-storage.ts | 19 ++++++ src/layered-storage/segment.ts | 16 +++++ test/layered-storage/cloning.ts | 91 ++++++++++++++++++++++++++ test/layered-storage/index.test.ts | 2 + 5 files changed, 162 insertions(+), 2 deletions(-) create mode 100644 test/layered-storage/cloning.ts diff --git a/src/layered-storage/core.ts b/src/layered-storage/core.ts index ae4ae139c..c0c158486 100644 --- a/src/layered-storage/core.ts +++ b/src/layered-storage/core.ts @@ -51,12 +51,12 @@ export class LayeredStorageCore< * This is a special segment that is used as fallback if the requested * segment doesn't have a value in given layer. */ - public monolithic = Symbol("Monolithic"); + public readonly monolithic = Symbol("Monolithic"); /** * Data stored as layer → segment → key → value. */ - private _data: Data = new Map(); + private readonly _data: Data = new Map(); /** * An ordered list of layers. The highest priority (equals highest number) @@ -361,6 +361,38 @@ export class LayeredStorageCore< this._cleanCache(segment, key); } + /** + * Clone all data from one segment to another. + * + * @param sourceSegment - The existing segment to be cloned. + * @param targetSegment - The target segment which should be created. + * + * @throws If the target segment already exists. + */ + public cloneSegmentData( + sourceSegment: Segment, + targetSegment: Segment + ): void { + if (this._segments.has(targetSegment)) { + throw new Error( + "The target segment already exists. If this was intentional delete it's data before cloning, please." + ); + } + + for (const layerData of this._data.values()) { + const sourceSegmentData = layerData.get(sourceSegment); + if (sourceSegmentData) { + const sourceSegmentCopy: SegmentData = new Map(); + for (const entry of sourceSegmentData.entries()) { + sourceSegmentCopy.set(entry[0], entry[1]); + } + layerData.set(targetSegment, sourceSegmentCopy); + } + } + + this._segments.add(targetSegment); + } + /** * Delete all the data associeated with given segment. * diff --git a/src/layered-storage/layered-storage.ts b/src/layered-storage/layered-storage.ts index 5ab5d5f21..138e98192 100644 --- a/src/layered-storage/layered-storage.ts +++ b/src/layered-storage/layered-storage.ts @@ -240,6 +240,25 @@ export class LayeredStorage< return new LayeredStorageSegment(this, segment); } + /** + * Create a new segmented instance for working with a single segment with a + * copy of another segments data. + * + * @param sourceSegment - The existing segment to be cloned. + * @param targetSegment - The target segment which should be created. + * + * @throws If the target segment already exists. + * + * @returns A new segmented instance permanently bound to this instance. + */ + public cloneSegment( + sourceSegment: Segment, + targetSegment: Segment + ): LayeredStorageSegment { + this._core.cloneSegmentData(sourceSegment, targetSegment); + return new LayeredStorageSegment(this, targetSegment); + } + /** * Delete all data belonging to a segment. * diff --git a/src/layered-storage/segment.ts b/src/layered-storage/segment.ts index c9ea6179a..06d419a91 100644 --- a/src/layered-storage/segment.ts +++ b/src/layered-storage/segment.ts @@ -75,6 +75,22 @@ export class LayeredStorageSegment< this._layeredStorage.delete(layer, this._segment, key); } + /** + * Create a new segmented instance for working with a single segment with a + * copy of another segments data. + * + * @param targetSegment - The target segment which should be created. + * + * @throws If the target segment already exists. + * + * @returns A new segmented instance permanently bound to this instance. + */ + public cloneSegment( + targetSegment: Segment + ): LayeredStorageSegment { + return this._layeredStorage.cloneSegment(this._segment, targetSegment); + } + /** * Open a new transaction. * diff --git a/test/layered-storage/cloning.ts b/test/layered-storage/cloning.ts new file mode 100644 index 000000000..8222c85fd --- /dev/null +++ b/test/layered-storage/cloning.ts @@ -0,0 +1,91 @@ +import { + LayeredStorage, + LayeredStorageSegment +} from "../../src/layered-storage"; +import { expect } from "chai"; + +interface KV { + test: number; +} + +/** + * Test that segments can be cloned. + */ +export function cloning(): void { + describe("Cloning", function(): void { + const configs: { + name: string; + clone( + ls: LayeredStorage, + s1: LayeredStorageSegment + ): LayeredStorageSegment; + }[] = [ + { + name: "From main instance", + clone: (ls): LayeredStorageSegment => + ls.cloneSegment(1, 2) + }, + { + name: "From segment instance", + clone: (_ls, s1): LayeredStorageSegment => + s1.cloneSegment(2) + } + ]; + + configs.forEach(({ name, clone }): void => { + it(name, function(): void { + const ls = new LayeredStorage(); + + const s1 = ls.openSegment(1); + + s1.set(0, "test", 0); + s1.set(1, "test", 1); + s1.set(2, "test", 2); + + const s2 = clone(ls, s1); + + expect( + s2.get("test"), + "The cloned segment should be initialized with the original's values." + ).to.equal(2); + + s2.set(1, "test", 11); + + expect( + s2.get("test"), + "The cloned segment should be initialized with the original's values on all layers." + ).to.equal(2); + + s2.delete(2, "test"); + + expect( + s2.get("test"), + "It should be possible to modify the cloned segment." + ).to.equal(11); + + expect( + s1.get("test"), + "The original segment should be unaffected." + ).to.equal(2); + }); + }); + + it("Cloning into existing segment", function(): void { + const ls = new LayeredStorage(); + + const s1 = ls.openSegment(1); + const s2 = ls.openSegment(2); + + s1.set(1, "test", 1); + s2.set(1, "test", 2); + + expect((): void => { + s1.cloneSegment(2); + }, "It shouldn't be possible to overwrite a segment by cloning.").to.throw(); + + expect((): void => { + ls.cloneSegment(1, 2); + }, "It shouldn't be possible to overwrite a segment by cloning.").to.throw(); + }); + }); +} diff --git a/test/layered-storage/index.test.ts b/test/layered-storage/index.test.ts index be007007d..4b7f118b0 100644 --- a/test/layered-storage/index.test.ts +++ b/test/layered-storage/index.test.ts @@ -1,4 +1,5 @@ import { allCombined } from "./all-combined"; +import { cloning } from "./cloning"; import { expanders } from "./expanders"; import { multipleKeys } from "./multiple-keys"; import { multipleLayers } from "./multiple-layers"; @@ -9,6 +10,7 @@ import { validation } from "./validation"; describe("Layered storage", function(): void { allCombined(); + cloning(); expanders(); multipleKeys(); multipleLayers(); From b9b559c95d3da411de9bd9ce22c5bab70e7fd36f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Fri, 27 Dec 2019 20:04:15 +0100 Subject: [PATCH 25/48] fix(layered-storage): use entries instead of pair BREAKING CHANGE: Some types were renamed. It has the same format as the various .entries() methods so it makes more sense to call it entries. --- src/layered-storage/common.ts | 4 ++-- src/layered-storage/core.ts | 10 +++++----- src/layered-storage/layered-storage.ts | 4 ++-- test/layered-storage/expanders.ts | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/layered-storage/common.ts b/src/layered-storage/common.ts index 17b447421..b030a5416 100644 --- a/src/layered-storage/common.ts +++ b/src/layered-storage/common.ts @@ -2,10 +2,10 @@ export type KeyRange = number | string | symbol; export type KeyValueLookup = Record; export type LayerRange = number; export type Segment = boolean | number | object | string | symbol; -export type KeyValuePair = { +export type KeyValueEntry = { [Key in keyof KV]: readonly [Key, KV[Key]]; }[keyof KV]; -export type FilteredKeyValuePair< +export type FilteredKeyValueEntry< KV extends KeyValueLookup, Keys extends keyof KV > = { diff --git a/src/layered-storage/core.ts b/src/layered-storage/core.ts index c0c158486..726082274 100644 --- a/src/layered-storage/core.ts +++ b/src/layered-storage/core.ts @@ -2,8 +2,8 @@ import { KeyValueLookup, LayerRange, Segment, - KeyValuePair, - FilteredKeyValuePair + KeyValueEntry, + FilteredKeyValueEntry } from "./common"; const reverseNumeric = (a: number, b: number): number => b - a; @@ -83,7 +83,7 @@ export class LayeredStorageCore< */ private readonly _setExpanders: TypedMap< { - [Key in keyof KV]: (value: KV[Key]) => readonly KeyValuePair[]; + [Key in keyof KV]: (value: KV[Key]) => readonly KeyValueEntry[]; } > = new Map(); @@ -466,7 +466,7 @@ export class LayeredStorageCore< public setExpander( key: Key, affects: readonly Affects[], - expander: (value: KV[Key]) => readonly FilteredKeyValuePair[], + expander: (value: KV[Key]) => readonly FilteredKeyValueEntry[], replace: boolean ): void { if ( @@ -491,7 +491,7 @@ export class LayeredStorageCore< public expandSet( key: Key, value: KV[Key] - ): readonly KeyValuePair[] { + ): readonly KeyValueEntry[] { const validators = this._validators.get(key); if (validators) { for (const validator of validators) { diff --git a/src/layered-storage/layered-storage.ts b/src/layered-storage/layered-storage.ts index 138e98192..4e59d7139 100644 --- a/src/layered-storage/layered-storage.ts +++ b/src/layered-storage/layered-storage.ts @@ -2,7 +2,7 @@ import { KeyValueLookup, LayerRange, Segment, - FilteredKeyValuePair + FilteredKeyValueEntry } from "./common"; import { LayeredStorageCore } from "./core"; import { LayeredStorageSegment } from "./segment"; @@ -315,7 +315,7 @@ export class LayeredStorage< public setExpander( key: Key, affects: readonly Affects[], - expander: (value: KV[Key]) => readonly FilteredKeyValuePair[], + expander: (value: KV[Key]) => readonly FilteredKeyValueEntry[], replace = false ): void { this._core.setExpander(key, affects, expander, replace); diff --git a/test/layered-storage/expanders.ts b/test/layered-storage/expanders.ts index 948d82406..244a9a6aa 100644 --- a/test/layered-storage/expanders.ts +++ b/test/layered-storage/expanders.ts @@ -1,6 +1,6 @@ import { LayeredStorage, - FilteredKeyValuePair + FilteredKeyValueEntry } from "../../src/layered-storage"; import { expect } from "chai"; @@ -23,7 +23,7 @@ export function expanders(): void { ] as const; const expander = ( input: string - ): readonly FilteredKeyValuePair< + ): readonly FilteredKeyValueEntry< KV, "test.boolean" | "test.number" | "test.string" >[] => { From 9d61fa2162f96766fc58e346ed8eb696c52039ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Fri, 27 Dec 2019 21:56:22 +0100 Subject: [PATCH 26/48] fix(layered-storage): sort debug output --- src/layered-storage/core.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/layered-storage/core.ts b/src/layered-storage/core.ts index 726082274..557febb35 100644 --- a/src/layered-storage/core.ts +++ b/src/layered-storage/core.ts @@ -536,8 +536,10 @@ export class LayeredStorageCore< public dumpContent(): void { console.groupCollapsed("Storage content dump"); + const layers = [...this._layers.values()]; + console.log("Time:", new Date()); - console.log("Layers:", [...this._layers.values()]); + console.log("Layers:", layers); console.log("Segments:", [...this._segments.values()]); console.groupCollapsed("Cache"); @@ -551,11 +553,12 @@ export class LayeredStorageCore< console.groupEnd(); console.groupCollapsed("Data"); - for (const [layer, lData] of this._data.entries()) { + for (const layer of layers) { + const lData = this._data.get(layer)!; console.groupCollapsed(`Layer: ${layer}`); for (const [segment, segmentData] of lData.entries()) { console.groupCollapsed(`Segment: ${String(segment)}`); - for (const [key, value] of segmentData.entries()) { + for (const [key, value] of [...segmentData.entries()].sort()) { console.log([key, value]); } console.groupEnd(); From 84f4d27e393c6a93391b428edbaaf7dba84f7aec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Tue, 21 Jan 2020 20:14:06 +0100 Subject: [PATCH 27/48] chore(layered-storage): fix some doc comments --- src/layered-storage/core.ts | 5 ++--- src/layered-storage/layered-storage.ts | 19 +++++++++++++++++-- src/layered-storage/segment.ts | 5 +++-- src/layered-storage/transactions.ts | 18 ++++++------------ 4 files changed, 28 insertions(+), 19 deletions(-) diff --git a/src/layered-storage/core.ts b/src/layered-storage/core.ts index 557febb35..f9132ab6b 100644 --- a/src/layered-storage/core.ts +++ b/src/layered-storage/core.ts @@ -38,9 +38,9 @@ const emptyCacheValue: EmptyCacheValue = { * Internal core to handle simple data storage, mutation and retrieval. Also * handles the special monolithic segment. * - * @typeparam KV - Sets the value types associeated with their keys. + * @typeParam KV - Sets the value types associeated with their keys. * (TS only, ignored in JS). - * @typeparam Layer - Sets the allowed layers. + * @typeParam Layer - Sets the allowed layers. * (TS only, ignored in JS). */ export class LayeredStorageCore< @@ -522,7 +522,6 @@ export class LayeredStorageCore< * Expand given value. * * @param key - Which key this value belongs to. - * @param value - The value to be expanded. * * @returns Expanded key value pairs or empty array for invalid input. */ diff --git a/src/layered-storage/layered-storage.ts b/src/layered-storage/layered-storage.ts index 4e59d7139..0c9e4df65 100644 --- a/src/layered-storage/layered-storage.ts +++ b/src/layered-storage/layered-storage.ts @@ -28,9 +28,9 @@ export { * - Each layer can be segmented using arbitrary values. * - Segmented value overrides monolithic (nonsegmented) value. * - * @typeparam KV - Sets the value types associeated with their keys. + * @typeParam KV - Sets the value types associeated with their keys. * (TS only, ignored in JS). - * @typeparam Layer - Sets the allowed layers. + * @typeParam Layer - Sets the allowed layers. * (TS only, ignored in JS). */ export class LayeredStorage< @@ -54,6 +54,9 @@ export class LayeredStorage< /** * Retrieve a value. * + * @param rest - Either a key only for monolithic or segment and key for + * specific segment. + * * @returns The value or undefined if not found. */ public get( @@ -76,6 +79,9 @@ export class LayeredStorage< /** * Check if a value is present. * + * @param rest - Either a key only for monolithic or segment and key for + * specific segment. + * * @returns True if found, false otherwise. */ public has(...rest: [keyof KV] | [Segment, keyof KV]): boolean { @@ -108,6 +114,9 @@ export class LayeredStorage< ): void; /** * Save a value. + * + * @param rest - Either layer, key and value only for monolithic or with + * segment for specific segment. */ public set( ...rest: [Layer, Segment, Key, KV[Key]] | [Layer, Key, KV[Key]] @@ -137,6 +146,9 @@ export class LayeredStorage< public delete(layer: Layer, key: Key): KV[Key]; /** * Delete a value from the storage. + * + * @param rest - Either a key only for monolithic or segment and key for + * specific segment. */ public delete( ...rest: [Layer, Segment, Key] | [Layer, Key] @@ -199,6 +211,9 @@ export class LayeredStorage< * This is the same as `openTransaction` except that it automatically commits * when the callback finishes execution. It is still possible to commit * within the body of the callback though. + * + * @param rest - Either a callback only for monolithic or segment and + * callback for specific segment. */ public runTransaction( ...rest: diff --git a/src/layered-storage/segment.ts b/src/layered-storage/segment.ts index 06d419a91..6b16a8c16 100644 --- a/src/layered-storage/segment.ts +++ b/src/layered-storage/segment.ts @@ -8,9 +8,9 @@ import { * This is similar as `LayeredStorage` except that it is permanently bound to * given `LayeredStorage` and can only access a single `Segment`. * - * @typeparam KV - Sets the value types associeated with their keys. + * @typeParam KV - Sets the value types associeated with their keys. * (TS only, ignored in JS). - * @typeparam Layer - Sets the allowed layers. + * @typeParam Layer - Sets the allowed layers. * (TS only, ignored in JS). */ export class LayeredStorageSegment< @@ -113,6 +113,7 @@ export class LayeredStorageSegment< * within the body of the callback though. * * @param callback - This callback will be called with the transaction as + * it's sole argument. */ public runTransaction( callback: (transaction: LayeredStorageSegmentTransaction) => void diff --git a/src/layered-storage/transactions.ts b/src/layered-storage/transactions.ts index 718289813..31a576e07 100644 --- a/src/layered-storage/transactions.ts +++ b/src/layered-storage/transactions.ts @@ -5,9 +5,9 @@ import { LayeredStorageCore } from "./core"; * This is used through composition to create monolithic and segmented * transactions without massive code duplicities. * - * @typeparam KV - Sets the value types associeated with their keys. + * @typeParam KV - Sets the value types associeated with their keys. * (TS only, ignored in JS). - * @typeparam Layer - Sets the allowed layers. + * @typeParam Layer - Sets the allowed layers. * (TS only, ignored in JS). */ class TransactionCore { @@ -22,8 +22,6 @@ class TransactionCore { * Create a new instance of transaction core. * * @param _storageCore - The core that this instance will save mutations to. - * @param _listeners - Listeners that should be notified after a transaction - * was commited. */ public constructor(private _storageCore: LayeredStorageCore) {} @@ -100,9 +98,9 @@ class TransactionCore { /** * A transaction working with the whole storage. * - * @typeparam KV - Sets the value types associeated with their keys. + * @typeParam KV - Sets the value types associeated with their keys. * (TS only, ignored in JS). - * @typeparam Layer - Sets the allowed layers. + * @typeParam Layer - Sets the allowed layers. * (TS only, ignored in JS). */ export interface LayeredStorageTransaction< @@ -171,8 +169,6 @@ export class MonolithicTransaction< * Create a new transaction for given storage. * * @param storageCore - The core that this instance will save mutations to. - * @param listeners - Listeners that should be notified after a transaction - * was commited. */ public constructor(storageCore: LayeredStorageCore) { this._monolithic = storageCore.monolithic; @@ -261,9 +257,9 @@ export interface LayeredStorageSegmentTransaction< /** * A transaction working with a single segment. * - * @typeparam KV - Sets the value types associeated with their keys. + * @typeParam KV - Sets the value types associeated with their keys. * (TS only, ignored in JS). - * @typeparam Layer - Sets the allowed layers. + * @typeParam Layer - Sets the allowed layers. * (TS only, ignored in JS). */ export class SegmentTransaction< @@ -276,8 +272,6 @@ export class SegmentTransaction< * Create a new transaction for a segment of given storage. * * @param storageCore - The core that this instance will save mutations to. - * @param listeners - Listeners that should be notified after a transaction - * was commited. * @param _segment - The segment this instance will manage. */ public constructor( From 093040ffee1fcd79a3c014027b0abbe90fdb8729 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Tue, 21 Jan 2020 20:16:23 +0100 Subject: [PATCH 28/48] perf(layered-storage): improve performance Those are a few micro optimalizations. However since this is executed over and over again it adds up to noticable improvement. --- src/layered-storage/core.ts | 58 +++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/src/layered-storage/core.ts b/src/layered-storage/core.ts index f9132ab6b..990dcd749 100644 --- a/src/layered-storage/core.ts +++ b/src/layered-storage/core.ts @@ -6,7 +6,10 @@ import { FilteredKeyValueEntry } from "./common"; -const reverseNumeric = (a: number, b: number): number => b - a; +const entriesByKeyPriority = ( + a: [number, unknown], + b: [number, unknown] +): number => b[0] - a[0]; type SegmentData = Map; type LayerData = Map>; @@ -59,10 +62,10 @@ export class LayeredStorageCore< private readonly _data: Data = new Map(); /** - * An ordered list of layers. The highest priority (equals highest number) - * layer is first. + * An ordered list of layer datas. The highest priority (equals highest + * number) layer is first. */ - private _layers: Layer[] = []; + private _layerDatas: LayerData[] = []; /** * A set of segments that keeps track what segments have data in the storage. @@ -175,9 +178,11 @@ export class LayeredStorageCore< segment: Segment, key: Key ): CachedValue | EmptyCacheValue { - const segmentCache = - this._topLevelCache.get(segment) || - this._topLevelCache.set(segment, new Map()).get(segment)!; + let segmentCache = this._topLevelCache.get(segment); + if (typeof segmentCache === "undefined") { + segmentCache = new Map(); + this._topLevelCache.set(segment, segmentCache); + } // Return cached value if it exists. const cached = segmentCache.get(key); @@ -186,33 +191,38 @@ export class LayeredStorageCore< } // Search the layers from highest to lowest priority. - for (const layer of this._layers) { - // Check the segmented first and quit if found. - const layerData = this._data.get(layer); + for (const layerData of this._layerDatas) { if (layerData == null) { // Empty layer. continue; } + // Check the segment and quit if found. const segmentData = layerData.get(segment); - if (segmentData != null && segmentData.has(key)) { - const value = { has: true, value: segmentData.get(key)! }; + if (typeof segmentData !== "undefined") { + const value = segmentData.get(key); + if (typeof value !== "undefined" || segmentData.has(key)) { + const cachedValue = { has: true, value }; - // Save to the cache. - segmentCache.set(key, value); + // Save to the cache. + segmentCache.set(key, cachedValue); - return value; + return cachedValue; + } } // Check the monolithic and quit if found. const monolithicData = layerData.get(this.monolithic); - if (monolithicData != null && monolithicData.has(key)) { - const value = { has: true, value: monolithicData.get(key)! }; + if (typeof monolithicData !== "undefined") { + const value = monolithicData.get(key); + if (typeof value !== "undefined" || monolithicData.has(key)) { + const cachedValue = { has: true, value }; - // Save to the cache. - segmentCache.set(key, value); + // Save to the cache. + segmentCache.set(key, cachedValue); - return value; + return cachedValue; + } } } @@ -245,7 +255,9 @@ export class LayeredStorageCore< layerData = new Map(); this._data.set(layer, layerData); - this._layers = [...this._data.keys()].sort(reverseNumeric); + this._layerDatas = [...this._data.entries()] + .sort(entriesByKeyPriority) + .map((pair): LayerData => pair[1]); } // Get or create the requested segment on the layer. @@ -535,7 +547,9 @@ export class LayeredStorageCore< public dumpContent(): void { console.groupCollapsed("Storage content dump"); - const layers = [...this._layers.values()]; + const layers = [...this._data.entries()] + .sort(entriesByKeyPriority) + .map((pair): Layer => pair[0]); console.log("Time:", new Date()); console.log("Layers:", layers); From fd2a42e83299773ef200fceb2e972f57e75dfcf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Tue, 21 Jan 2020 20:46:29 +0100 Subject: [PATCH 29/48] docs(layered-storage): update outdated comment --- src/layered-storage/core.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/layered-storage/core.ts b/src/layered-storage/core.ts index 990dcd749..2d951622f 100644 --- a/src/layered-storage/core.ts +++ b/src/layered-storage/core.ts @@ -114,10 +114,8 @@ export class LayeredStorageCore< }; /** - * This is used to speed up retrieval of data upon request. Since the storage - * is seen as mostly static this structure is populated up front and updated - * with each change. Thanks to this quering data from the storage is always - * just `Map.get().get()` away. + * This is used to speed up retrieval of data upon request. Thanks to this + * quering data from the storage is always just `Map.get().get()` away. */ private readonly _topLevelCache = new Map< Segment, From 84a01449716d9ed56d493e93361445269a31d14d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Tue, 21 Jan 2020 22:18:57 +0100 Subject: [PATCH 30/48] style(layered-storage): unify the way existence is checked in core --- src/layered-storage/core.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/layered-storage/core.ts b/src/layered-storage/core.ts index 2d951622f..b6dd4020d 100644 --- a/src/layered-storage/core.ts +++ b/src/layered-storage/core.ts @@ -184,13 +184,13 @@ export class LayeredStorageCore< // Return cached value if it exists. const cached = segmentCache.get(key); - if (cached) { + if (typeof cached !== "undefined") { return cached; } // Search the layers from highest to lowest priority. for (const layerData of this._layerDatas) { - if (layerData == null) { + if (typeof layerData === "undefined") { // Empty layer. continue; } @@ -249,7 +249,7 @@ export class LayeredStorageCore< ): { layerData: LayerData; segmentData: SegmentData } { // Get or create the requested layer. let layerData = this._data.get(layer); - if (layerData == null) { + if (typeof layerData === "undefined") { layerData = new Map(); this._data.set(layer, layerData); @@ -260,7 +260,7 @@ export class LayeredStorageCore< // Get or create the requested segment on the layer. let segmentData = layerData.get(segment); - if (segmentData == null) { + if (typeof segmentData === "undefined") { segmentData = new Map(); layerData.set(segment, segmentData); From cc0f8667b27e6126f51497f5b045adb14752b25f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Sun, 26 Jan 2020 21:45:27 +0100 Subject: [PATCH 31/48] feat(layered-storage): simplify BREAKING CHANGE: Most stuff was changed. This is a really big overhaul that greatly reduces the API and the codebase. This should be much easier to maintain and also more performant when used at the expense of removing support for some niche features. --- src/layered-storage/common.ts | 20 +- src/layered-storage/core.ts | 262 +++++++++++------------ src/layered-storage/index.ts | 6 +- src/layered-storage/layered-storage.ts | 259 +++-------------------- src/layered-storage/segment.ts | 74 ++++--- src/layered-storage/transactions.ts | 269 +++--------------------- test/layered-storage/all-combined.ts | 169 ++++++--------- test/layered-storage/cloning.ts | 14 +- test/layered-storage/expanders.ts | 48 +++-- test/layered-storage/multiple-keys.ts | 60 +++--- test/layered-storage/multiple-layers.ts | 66 +++--- test/layered-storage/other.ts | 85 ++++---- test/layered-storage/segmented-layer.ts | 79 +++---- test/layered-storage/single-layer.ts | 42 ++-- test/layered-storage/validation.ts | 20 +- 15 files changed, 513 insertions(+), 960 deletions(-) diff --git a/src/layered-storage/common.ts b/src/layered-storage/common.ts index b030a5416..267456867 100644 --- a/src/layered-storage/common.ts +++ b/src/layered-storage/common.ts @@ -1,13 +1,15 @@ export type KeyRange = number | string | symbol; -export type KeyValueLookup = Record; export type LayerRange = number; export type Segment = boolean | number | object | string | symbol; -export type KeyValueEntry = { - [Key in keyof KV]: readonly [Key, KV[Key]]; -}[keyof KV]; -export type FilteredKeyValueEntry< - KV extends KeyValueLookup, - Keys extends keyof KV + +export type KeyValueLookup = Record< + Keys, + boolean | number | object | string | symbol +>; + +export type KeyValueEntry< + KV extends object, + Key extends keyof KV = keyof KV > = { - [Key in Keys]: readonly [Key, KV[Key]]; -}[Keys]; + [Key in keyof KV]: readonly [Key, KV[Key]]; +}[Key]; diff --git a/src/layered-storage/core.ts b/src/layered-storage/core.ts index b6dd4020d..3a71aef99 100644 --- a/src/layered-storage/core.ts +++ b/src/layered-storage/core.ts @@ -1,9 +1,9 @@ import { + KeyRange, + KeyValueEntry, KeyValueLookup, LayerRange, - Segment, - KeyValueEntry, - FilteredKeyValueEntry + Segment } from "./common"; const entriesByKeyPriority = ( @@ -11,61 +11,60 @@ const entriesByKeyPriority = ( b: [number, unknown] ): number => b[0] - a[0]; -type SegmentData = Map; -type LayerData = Map>; -type Data = Map< - Layer, - LayerData +type SegmentData< + KV extends KeyValueLookup, + Keys extends KeyRange = keyof KV +> = TypedMap; +type LayerData, Keys extends KeyRange> = Map< + Segment, + SegmentData >; - -interface TypedMap - extends Map { - get(key: Key): undefined | KV[Key]; - set(key: Key, value: KV[Key]): this; +type Data< + Layer extends LayerRange, + KV extends KeyValueLookup, + Keys extends KeyRange = keyof KV +> = Map>; + +interface TypedMap< + KV extends Record, + Keys extends KeyRange = keyof KV +> extends Map { + get(key: Key): undefined | KV[Key]; + set(key: Key, value: KV[Key]): this; } -interface CachedValue { - has: boolean; - value: undefined | Value; -} -interface EmptyCacheValue { - has: false; - value: undefined; -} -const emptyCacheValue: EmptyCacheValue = { - has: false, - value: undefined -}; - /** * Internal core to handle simple data storage, mutation and retrieval. Also - * handles the special monolithic segment. + * handles the special global segment. * - * @typeParam KV - Sets the value types associeated with their keys. + * @typeParam Layer - The allowed layers. + * (TS only, ignored in JS). + * @typeParam KV - The value types associeated with their keys. * (TS only, ignored in JS). - * @typeParam Layer - Sets the allowed layers. + * @typeParam Keys - The allowed keys. * (TS only, ignored in JS). */ export class LayeredStorageCore< - KV extends KeyValueLookup, - Layer extends LayerRange + Layer extends LayerRange, + KV extends KeyValueLookup, + Keys extends KeyRange = keyof KV > { /** * This is a special segment that is used as fallback if the requested * segment doesn't have a value in given layer. */ - public readonly monolithic = Symbol("Monolithic"); + public readonly globalSegment = Symbol("Global Segment"); /** * Data stored as layer → segment → key → value. */ - private readonly _data: Data = new Map(); + private readonly _data: Data = new Map(); /** * An ordered list of layer datas. The highest priority (equals highest * number) layer is first. */ - private _layerDatas: LayerData[] = []; + private _layerDatas: LayerData[] = []; /** * A set of segments that keeps track what segments have data in the storage. @@ -77,8 +76,9 @@ export class LayeredStorageCore< */ private readonly _validators: TypedMap< { - [Key in keyof KV]: ((value: KV[Key]) => true | string)[]; - } + [Key in Keys]: ((value: KV[Key]) => true | string)[]; + }, + Keys > = new Map(); /** @@ -86,17 +86,15 @@ export class LayeredStorageCore< */ private readonly _setExpanders: TypedMap< { - [Key in keyof KV]: (value: KV[Key]) => readonly KeyValueEntry[]; - } + [Key in Keys]: (value: KV[Key]) => readonly KeyValueEntry[]; + }, + Keys > = new Map(); /** * An expander for each key. */ - private readonly _deleteExpanders: Map< - keyof KV, - readonly (keyof KV)[] - > = new Map(); + private readonly _deleteExpanders: Map = new Map(); /** * This is called whenever a validity test fails. @@ -105,7 +103,7 @@ export class LayeredStorageCore< * @param value - The invalid value itself. * @param message - The message returned by the validator that failed. */ - private _invalidHandler: ( + private _invalidHandler: ( key: Key, value: KV[Key], message: string @@ -115,11 +113,14 @@ export class LayeredStorageCore< /** * This is used to speed up retrieval of data upon request. Thanks to this - * quering data from the storage is always just `Map.get().get()` away. + * quering data from the storage is almost always just `Map.get().get()` away. + * + * @remarks + * The `null` stands for value that was looked up but is not set. */ private readonly _topLevelCache = new Map< Segment, - TypedMap<{ [Key in keyof KV]: CachedValue }> + TypedMap<{ [Key in Keys]: KV[Key] | null }, Keys> >(); /** @@ -128,11 +129,11 @@ export class LayeredStorageCore< * @param segment - Which segment to clean. * @param key - The key that was subject to the mutation. */ - private _cleanCache(segment: Segment, key: keyof KV): void { - if (segment === this.monolithic) { + private _cleanCache(segment: Segment, key: Keys): void { + if (segment === this.globalSegment) { // Run the search for each cached segment to clean the cached top level - // value for each of them. The reason for this is that the monolithic - // segment affects all other segments. + // value for each of them. The reason for this is that the global segment + // affects all other segments. for (const cache of this._topLevelCache) { const sCache = cache[1]; @@ -163,76 +164,6 @@ export class LayeredStorageCore< } } - /** - * Find a top level value. - * - * @param segment - Which segment to look into (monolithic is always used as - * fallback on each level). - * @param key - The key identifying requested value. - * - * @returns Whether such value exists (`has`) and the value itself (`value`). - */ - private _findValue( - segment: Segment, - key: Key - ): CachedValue | EmptyCacheValue { - let segmentCache = this._topLevelCache.get(segment); - if (typeof segmentCache === "undefined") { - segmentCache = new Map(); - this._topLevelCache.set(segment, segmentCache); - } - - // Return cached value if it exists. - const cached = segmentCache.get(key); - if (typeof cached !== "undefined") { - return cached; - } - - // Search the layers from highest to lowest priority. - for (const layerData of this._layerDatas) { - if (typeof layerData === "undefined") { - // Empty layer. - continue; - } - - // Check the segment and quit if found. - const segmentData = layerData.get(segment); - if (typeof segmentData !== "undefined") { - const value = segmentData.get(key); - if (typeof value !== "undefined" || segmentData.has(key)) { - const cachedValue = { has: true, value }; - - // Save to the cache. - segmentCache.set(key, cachedValue); - - return cachedValue; - } - } - - // Check the monolithic and quit if found. - const monolithicData = layerData.get(this.monolithic); - if (typeof monolithicData !== "undefined") { - const value = monolithicData.get(key); - if (typeof value !== "undefined" || monolithicData.has(key)) { - const cachedValue = { has: true, value }; - - // Save to the cache. - segmentCache.set(key, cachedValue); - - return cachedValue; - } - } - } - - // If nothing was found by now there are no values for the key. - - // Save to the cache. - segmentCache.set(key, emptyCacheValue); - - // Return the empty value. - return emptyCacheValue; - } - /** * Fetch the key value map for given segment on given layer. Nonexistent * layers and segments will be automatically created and the new instances @@ -246,7 +177,7 @@ export class LayeredStorageCore< private _getLSData( layer: Layer, segment: Segment - ): { layerData: LayerData; segmentData: SegmentData } { + ): { layerData: LayerData; segmentData: SegmentData } { // Get or create the requested layer. let layerData = this._data.get(layer); if (typeof layerData === "undefined") { @@ -255,7 +186,7 @@ export class LayeredStorageCore< this._layerDatas = [...this._data.entries()] .sort(entriesByKeyPriority) - .map((pair): LayerData => pair[1]); + .map((pair): LayerData => pair[1]); } // Get or create the requested segment on the layer. @@ -273,28 +204,81 @@ export class LayeredStorageCore< /** * Retrieve a value. * - * @param segment - Which segment to search through in addition to the monolithic part of the storage. + * @param segment - Which segment to search through in addition to the global + * segment which is used as the fallback on each level. * @param key - The key corresponding to the requested value. * - * @returns The value or undefined if not found. + * @returns The value or undefined if it wasn't found. */ - public get( + public get( segment: Segment, key: Key ): KV[Key] | undefined { - return this._findValue(segment, key).value; + let segmentCache = this._topLevelCache.get(segment); + if (typeof segmentCache === "undefined") { + segmentCache = new Map(); + this._topLevelCache.set(segment, segmentCache); + } + + // Return cached value if it exists. + const cached = segmentCache.get(key); + if (typeof cached !== "undefined") { + // TODO: The non null assertion shouldn't be necessary. + return cached === null ? void 0 : cached!; + } + + // Search the layers from highest to lowest priority. + for (const layerData of this._layerDatas) { + if (typeof layerData === "undefined") { + // Empty layer. + continue; + } + + // Check the segment and quit if found. + const segmentData = layerData.get(segment); + if (typeof segmentData !== "undefined") { + const value = segmentData.get(key); + if (typeof value !== "undefined") { + // Save to the cache. + segmentCache.set(key, value); + + return value; + } + } + + // Check the global segment and quit if found. + const globalData = layerData.get(this.globalSegment); + if (typeof globalData !== "undefined") { + const value = globalData.get(key); + if (typeof value !== "undefined") { + // Save to the cache. + segmentCache.set(key, value); + + return value; + } + } + } + + // If nothing was found by now there are no values for the key. + + // Save to the cache. + segmentCache.set(key, null); + + // Return the empty value. + return; } /** * Check if a value is present. * - * @param segment - Which segment to search through in addition to the monolithic part of the storage. + * @param segment - Which segment to search through in addition to the global + * segment which is used as the fallback on each level. * @param key - The key corresponding to the requested value. * * @returns True if found, false otherwise. */ - public has(segment: Segment, key: Key): boolean { - return this._findValue(segment, key).has; + public has(segment: Segment, key: Key): boolean { + return typeof this.get(segment, key) !== "undefined"; } /** @@ -305,7 +289,7 @@ export class LayeredStorageCore< * @param key - Key that can be used to retrieve or overwrite this value later. * @param value - The value to be saved. */ - public set( + public set( layer: Layer, segment: Segment, key: Key, @@ -346,7 +330,7 @@ export class LayeredStorageCore< * @param segment - Which segment to delete from. * @param key - The key that identifies the value to be deleted. */ - public delete( + public delete( layer: Layer, segment: Segment, key: Key @@ -392,7 +376,7 @@ export class LayeredStorageCore< for (const layerData of this._data.values()) { const sourceSegmentData = layerData.get(sourceSegment); if (sourceSegmentData) { - const sourceSegmentCopy: SegmentData = new Map(); + const sourceSegmentCopy: SegmentData = new Map(); for (const entry of sourceSegmentData.entries()) { sourceSegmentCopy.set(entry[0], entry[1]); } @@ -428,7 +412,7 @@ export class LayeredStorageCore< * value and a message from the failed validator. */ public setInvalidHandler( - handler: ( + handler: ( key: Key, value: KV[Key], message: string @@ -446,7 +430,7 @@ export class LayeredStorageCore< * @param replace - If true existing validators will be replaced, if false an * error will be thrown if some validators already exist for given key. */ - public setValidators( + public setValidators( key: Key, validators: ((value: KV[Key]) => true | string)[], replace: boolean @@ -473,10 +457,10 @@ export class LayeredStorageCore< * @param replace - If true existing expander will be replaced, if false an * error will be thrown if an expander already exists for given key. */ - public setExpander( + public setExpander( key: Key, affects: readonly Affects[], - expander: (value: KV[Key]) => readonly FilteredKeyValueEntry[], + expander: (value: KV[Key]) => readonly KeyValueEntry[], replace: boolean ): void { if ( @@ -496,12 +480,14 @@ export class LayeredStorageCore< * @param key - Which key this value belongs to. * @param value - The value to be expanded. * + * @throws If the value is invalid and the invalid handler throws. + * * @returns Expanded key value pairs or empty array for invalid input. */ - public expandSet( + public expandSet( key: Key, value: KV[Key] - ): readonly KeyValueEntry[] { + ): readonly KeyValueEntry[] { const validators = this._validators.get(key); if (validators) { for (const validator of validators) { @@ -535,7 +521,7 @@ export class LayeredStorageCore< * * @returns Expanded key value pairs or empty array for invalid input. */ - public expandDelete(key: Key): readonly (keyof KV)[] { + public expandDelete(key: Key): readonly Keys[] { return this._deleteExpanders.get(key) || [key]; } diff --git a/src/layered-storage/index.ts b/src/layered-storage/index.ts index c1f2c4a87..588561c4f 100644 --- a/src/layered-storage/index.ts +++ b/src/layered-storage/index.ts @@ -1,7 +1,3 @@ -export { - LayeredStorage, - LayeredStorageSegmentTransaction, - LayeredStorageTransaction -} from "./layered-storage"; +export { LayeredStorage, LayeredStorageTransaction } from "./layered-storage"; export { LayeredStorageSegment } from "./segment"; export * from "./common"; diff --git a/src/layered-storage/layered-storage.ts b/src/layered-storage/layered-storage.ts index 0c9e4df65..d5a1f2ae2 100644 --- a/src/layered-storage/layered-storage.ts +++ b/src/layered-storage/layered-storage.ts @@ -1,248 +1,43 @@ import { + KeyRange, KeyValueLookup, LayerRange, Segment, - FilteredKeyValueEntry + KeyValueEntry } from "./common"; import { LayeredStorageCore } from "./core"; import { LayeredStorageSegment } from "./segment"; -import { - LayeredStorageSegmentTransaction, - LayeredStorageTransaction, - MonolithicTransaction, - SegmentTransaction -} from "./transactions"; +import { LayeredStorageTransaction } from "./transactions"; -export { - LayeredStorageSegmentTransaction, - LayeredStorageTransaction, - MonolithicTransaction, - SegmentTransaction -}; +export { LayeredStorageTransaction }; /** * Stores data in layers and optionally segments. * * @remarks - * - Higher layers override lowerlayers. + * - Higher layers override lower layers. * - Each layer can be segmented using arbitrary values. - * - Segmented value overrides monolithic (nonsegmented) value. + * - Segmented value overrides global (nonsegmented) value. * - * @typeParam KV - Sets the value types associeated with their keys. + * @typeParam Layer - The allowed layers. + * (TS only, ignored in JS). + * @typeParam KV - The value types associeated with their keys. * (TS only, ignored in JS). - * @typeParam Layer - Sets the allowed layers. + * @typeParam Keys - The allowed keys. * (TS only, ignored in JS). */ export class LayeredStorage< - KV extends KeyValueLookup, - Layer extends LayerRange + Layer extends LayerRange, + KV extends KeyValueLookup, + Keys extends KeyRange = keyof KV > { - private _core = new LayeredStorageCore(); - - /** - * @param segment - Which segment to search through in addition to the monolithic part of the storage. - * @param key - The key corresponding to the requested value. - */ - public get( - segment: Segment, - key: Key - ): KV[Key] | undefined; - /** - * @param key - The key corresponding to the requested value. - */ - public get(key: Key): KV[Key] | undefined; - /** - * Retrieve a value. - * - * @param rest - Either a key only for monolithic or segment and key for - * specific segment. - * - * @returns The value or undefined if not found. - */ - public get( - ...rest: [Key] | [Segment, Key] - ): KV[Key] | undefined { - return rest.length === 1 - ? this._core.get(this._core.monolithic, rest[0]) - : this._core.get(rest[0], rest[1]); - } - - /** - * @param segment - Which segment to search through in addition to the monolithic part of the storage. - * @param key - The key corresponding to the requested value. - */ - public has(segment: Segment, key: Key): boolean; - /** - * @param key - The key corresponding to the requested value. - */ - public has(key: Key): boolean; - /** - * Check if a value is present. - * - * @param rest - Either a key only for monolithic or segment and key for - * specific segment. - * - * @returns True if found, false otherwise. - */ - public has(...rest: [keyof KV] | [Segment, keyof KV]): boolean { - return rest.length === 1 - ? this._core.has(this._core.monolithic, rest[0]) - : this._core.has(rest[0], rest[1]); - } - - /** - * @param layer - Which layer to save the value into. - * @param segment - Which segment to save the value into. - * @param key - Key that can be used to retrieve or overwrite this value later. - * @param value - The value to be saved. - */ - public set( - layer: Layer, - segment: Segment, - key: Key, - value: KV[Key] - ): void; - /** - * @param layer - Which layer to save the value into. - * @param key - Key that can be used to retrieve or overwrite this value later. - * @param value - The value to be saved. - */ - public set( - layer: Layer, - key: Key, - value: KV[Key] - ): void; - /** - * Save a value. - * - * @param rest - Either layer, key and value only for monolithic or with - * segment for specific segment. - */ - public set( - ...rest: [Layer, Segment, Key, KV[Key]] | [Layer, Key, KV[Key]] - ): void { - this.runTransaction( - (transaction): void => - void (rest.length === 3 - ? transaction.set(rest[0], rest[1], rest[2]) - : transaction.set(rest[0], rest[1], rest[2], rest[3])) - ); - } + private readonly _core = new LayeredStorageCore(); - /** - * @param layer - Which layer to delete from. - * @param segment - Which segment to delete from. - * @param key - The key that identifies the value to be deleted. - */ - public delete( - layer: Layer, - segment: Segment, - key: Key - ): KV[Key]; - /** - * @param layer - Which layer to delete from. - * @param key - The key that identifies the value to be deleted. - */ - public delete(layer: Layer, key: Key): KV[Key]; - /** - * Delete a value from the storage. - * - * @param rest - Either a key only for monolithic or segment and key for - * specific segment. - */ - public delete( - ...rest: [Layer, Segment, Key] | [Layer, Key] - ): void { - this.runTransaction( - (transaction): void => - void (rest.length === 2 - ? transaction.delete(rest[0], rest[1]) - : transaction.delete(rest[0], rest[1], rest[2])) - ); - } - - public openTransaction( - segment: Segment - ): LayeredStorageSegmentTransaction; - public openTransaction(): LayeredStorageTransaction; - /** - * Open a new transaction. - * - * @remarks - * The transaction accumulates changes but doesn't change the content of the - * storage until commit is called. - * - * @param segment - If segment is passed the transaction will be locked to - * given segment. Otherwise the monolithic portion and all the segments will - * be accessible. - * - * @returns The new transaction that can be used to set or delete values. - */ - public openTransaction( - segment?: Segment - ): - | LayeredStorageSegmentTransaction - | LayeredStorageTransaction { - return segment == null - ? new MonolithicTransaction(this._core) - : new SegmentTransaction(this._core, segment); - } - - /** - * @param segment - The segment that this transaction will be limited to. - * @param callback - This callback will be called with the transaction as - * it's sole parameter. - */ - public runTransaction( - segment: Segment, - callback: (transaction: LayeredStorageSegmentTransaction) => void - ): void; - /** - * @param callback - This callback will be called with the transaction as - * it's sole parameter. - */ - public runTransaction( - callback: (transaction: LayeredStorageTransaction) => void - ): void; - /** - * Run a new transaction. - * - * @remarks - * This is the same as `openTransaction` except that it automatically commits - * when the callback finishes execution. It is still possible to commit - * within the body of the callback though. - * - * @param rest - Either a callback only for monolithic or segment and - * callback for specific segment. - */ - public runTransaction( - ...rest: - | [ - Segment, - (transaction: LayeredStorageSegmentTransaction) => void - ] - | [(transaction: LayeredStorageTransaction) => void] - ): void { - if (rest.length === 1) { - const callback = rest[0]; - - const transaction = this.openTransaction(); - - // If the following throws uncommited changes will be discarded. - callback(transaction); - - transaction.commit(); - } else { - const [segment, callback] = rest; - - const transaction = this.openTransaction(segment); - - // If the following throws uncommited changes will be discarded. - callback(transaction); - - transaction.commit(); - } - } + public readonly global = new LayeredStorageSegment( + this, + this._core, + this._core.globalSegment + ); /** * Create a new segmented instance for working with a single segment. @@ -251,8 +46,8 @@ export class LayeredStorage< * * @returns A new segmented instance permanently bound to this instance. */ - public openSegment(segment: Segment): LayeredStorageSegment { - return new LayeredStorageSegment(this, segment); + public openSegment(segment: Segment): LayeredStorageSegment { + return new LayeredStorageSegment(this, this._core, segment); } /** @@ -269,9 +64,9 @@ export class LayeredStorage< public cloneSegment( sourceSegment: Segment, targetSegment: Segment - ): LayeredStorageSegment { + ): LayeredStorageSegment { this._core.cloneSegmentData(sourceSegment, targetSegment); - return new LayeredStorageSegment(this, targetSegment); + return new LayeredStorageSegment(this, this._core, targetSegment); } /** @@ -290,7 +85,7 @@ export class LayeredStorage< * value and a message from the failed validator. */ public setInvalidHandler( - handler: ( + handler: ( key: Key, value: KV[Key], message: string @@ -308,7 +103,7 @@ export class LayeredStorage< * @param replace - If true existing validators will be replaced, if false an * error will be thrown if some validators already exist for given key. */ - public setValidators( + public setValidators( key: Key, validators: ((value: KV[Key]) => true | string)[], replace = false @@ -327,10 +122,10 @@ export class LayeredStorage< * @param replace - If true existing expander will be relaced, if false an * error will be thrown if an expander already exists for given key. */ - public setExpander( + public setExpander( key: Key, affects: readonly Affects[], - expander: (value: KV[Key]) => readonly FilteredKeyValueEntry[], + expander: (value: KV[Key]) => readonly KeyValueEntry[], replace = false ): void { this._core.setExpander(key, affects, expander, replace); diff --git a/src/layered-storage/segment.ts b/src/layered-storage/segment.ts index 6b16a8c16..6889e14e1 100644 --- a/src/layered-storage/segment.ts +++ b/src/layered-storage/segment.ts @@ -1,31 +1,34 @@ -import { KeyValueLookup, LayerRange, Segment } from "./common"; -import { - LayeredStorage, - LayeredStorageSegmentTransaction -} from "./layered-storage"; +import { KeyValueLookup, LayerRange, Segment, KeyRange } from "./common"; +import { LayeredStorage, LayeredStorageTransaction } from "./layered-storage"; +import { LayeredStorageCore } from "./core"; /** * This is similar as `LayeredStorage` except that it is permanently bound to * given `LayeredStorage` and can only access a single `Segment`. * - * @typeParam KV - Sets the value types associeated with their keys. + * @typeParam Layer - The allowed layers. * (TS only, ignored in JS). - * @typeParam Layer - Sets the allowed layers. + * @typeParam KV - The value types associeated with their keys. + * (TS only, ignored in JS). + * @typeParam Keys - The allowed keys. * (TS only, ignored in JS). */ export class LayeredStorageSegment< - KV extends KeyValueLookup, - Layer extends LayerRange + Layer extends LayerRange, + KV extends KeyValueLookup, + Keys extends KeyRange = keyof KV > { /** * Create a new storage instance for given segment. * * @param _layeredStorage - The storage that this instance will be bound to. - * @param _segment - The segment this instance will manage. + * @param _core - The core of the Layered Storage instance. + * @param segment - The segment this instance will manage. */ public constructor( - private _layeredStorage: LayeredStorage, - private _segment: Segment + private readonly _layeredStorage: LayeredStorage, + private readonly _core: LayeredStorageCore, + public readonly segment: Segment ) {} /** @@ -35,8 +38,8 @@ export class LayeredStorageSegment< * * @returns The value or undefined if not found. */ - public get(key: Key): KV[Key] | undefined { - return this._layeredStorage.get(this._segment, key); + public get(key: Key): KV[Key] | undefined { + return this._core.get(this.segment, key); } /** @@ -46,8 +49,8 @@ export class LayeredStorageSegment< * * @returns True if found, false otherwise. */ - public has(key: Key): boolean { - return this._layeredStorage.has(this._segment, key); + public has(key: Key): boolean { + return this._core.has(this.segment, key); } /** @@ -57,12 +60,10 @@ export class LayeredStorageSegment< * @param key - Key that can be used to retrieve or overwrite this value later. * @param value - The value to be saved. */ - public set( - layer: Layer, - key: Key, - value: KV[Key] - ): void { - this._layeredStorage.set(layer, this._segment, key, value); + public set(layer: Layer, key: Key, value: KV[Key]): void { + this.runTransaction((transaction): void => { + transaction.set(layer, key, value); + }); } /** @@ -71,8 +72,10 @@ export class LayeredStorageSegment< * @param layer - Which layer to delete from. * @param key - The key that identifies the value to be deleted. */ - public delete(layer: Layer, key: Key): void { - this._layeredStorage.delete(layer, this._segment, key); + public delete(layer: Layer, key: Key): void { + this.runTransaction((transaction): void => { + transaction.delete(layer, key); + }); } /** @@ -87,8 +90,8 @@ export class LayeredStorageSegment< */ public cloneSegment( targetSegment: Segment - ): LayeredStorageSegment { - return this._layeredStorage.cloneSegment(this._segment, targetSegment); + ): LayeredStorageSegment { + return this._layeredStorage.cloneSegment(this.segment, targetSegment); } /** @@ -100,8 +103,11 @@ export class LayeredStorageSegment< * * @returns The new transaction that can be used to set or delete values. */ - public openTransaction(): LayeredStorageSegmentTransaction { - return this._layeredStorage.openTransaction(this._segment); + public openTransaction(): LayeredStorageTransaction { + return new LayeredStorageTransaction( + this._core, + this.segment + ); } /** @@ -116,15 +122,21 @@ export class LayeredStorageSegment< * it's sole argument. */ public runTransaction( - callback: (transaction: LayeredStorageSegmentTransaction) => void + callback: (transaction: LayeredStorageTransaction) => void ): void { - this._layeredStorage.runTransaction(this._segment, callback); + const transaction = this.openTransaction(); + + // If the following throws uncommited changes will get out of scope and will + // be discarded and garbage collected. + callback(transaction); + + transaction.commit(); } /** * Delete all data belonging to this segment. */ public close(): void { - this._layeredStorage.deleteSegmentData(this._segment); + this._layeredStorage.deleteSegmentData(this.segment); } } diff --git a/src/layered-storage/transactions.ts b/src/layered-storage/transactions.ts index 31a576e07..5d8efa07a 100644 --- a/src/layered-storage/transactions.ts +++ b/src/layered-storage/transactions.ts @@ -1,16 +1,21 @@ -import { KeyValueLookup, LayerRange, Segment } from "./common"; +import { KeyValueLookup, LayerRange, Segment, KeyRange } from "./common"; import { LayeredStorageCore } from "./core"; /** - * This is used through composition to create monolithic and segmented - * transactions without massive code duplicities. + * A transaction working with a single segment. * - * @typeParam KV - Sets the value types associeated with their keys. + * @typeParam Layer - The allowed layers. + * (TS only, ignored in JS). + * @typeParam KV - The value types associeated with their keys. * (TS only, ignored in JS). - * @typeParam Layer - Sets the allowed layers. + * @typeParam Keys - The allowed keys. * (TS only, ignored in JS). */ -class TransactionCore { +export class LayeredStorageTransaction< + Layer extends LayerRange, + KV extends KeyValueLookup, + Keys extends KeyRange = keyof KV +> { /** * Functions that perform requested mutations when executed without any * arguments or this. Intended to be filled bound set and delete methods from @@ -19,58 +24,45 @@ class TransactionCore { private _actions: (() => void)[] = []; /** - * Create a new instance of transaction core. + * Create a new transaction for a segment of given storage. * * @param _storageCore - The core that this instance will save mutations to. + * @param _segment - The segment this instance will manage. */ - public constructor(private _storageCore: LayeredStorageCore) {} + public constructor( + private readonly _storageCore: LayeredStorageCore, + private readonly _segment: Segment + ) {} /** - * Queue set mutation. + * Queue a value to be set. * * @param layer - Which layer to save the value into. - * @param segment - Which segment to save the value into. * @param key - Key that can be used to retrieve or overwrite this value later. * @param value - The value to be saved. */ - public set( - layer: Layer, - segment: Segment, - key: Key, - value: KV[Key] - ): void { + public set(layer: Layer, key: Key, value: KV[Key]): void { const expandedPairs = this._storageCore.expandSet(key, value); for (const expanded of expandedPairs) { - this._actions.push( - this._storageCore.set.bind( - this._storageCore, - layer, - segment, - expanded[0], - expanded[1] - ) - ); + this._actions.push((): void => { + this._storageCore.set(layer, this._segment, expanded[0], expanded[1]); + }); } } /** - * Queue delete mutation. + * Queue a value to be deleted. * * @param layer - Which layer to delete from. - * @param segment - Which segment to delete from. * @param key - The key that identifies the value to be deleted. */ - public delete( - layer: Layer, - segment: Segment, - key: Key - ): void { + public delete(layer: Layer, key: Key): void { for (const expandedKey of this._storageCore.expandDelete(key)) { this._actions.push( this._storageCore.delete.bind( this._storageCore, layer, - segment, + this._segment, expandedKey ) ); @@ -94,214 +86,3 @@ class TransactionCore { this._actions = []; } } - -/** - * A transaction working with the whole storage. - * - * @typeParam KV - Sets the value types associeated with their keys. - * (TS only, ignored in JS). - * @typeParam Layer - Sets the allowed layers. - * (TS only, ignored in JS). - */ -export interface LayeredStorageTransaction< - KV extends KeyValueLookup, - Layer extends LayerRange -> { - /** - * Queue a value to be set. - * - * @param layer - Which layer to save the value into. - * @param segment - Which segment to save the value into. - * @param key - Key that can be used to retrieve or overwrite this value later. - * @param value - The value to be saved. - */ - set( - layer: Layer, - segment: Segment, - key: Key, - value: KV[Key] - ): void; - /** - * Queue a value to be set. - * - * @param layer - Which layer to save the value into. - * @param key - Key that can be used to retrieve or overwrite this value later. - * @param value - The value to be saved. - */ - set(layer: Layer, key: Key, value: KV[Key]): void; - - /** - * Queue a value to be deleted. - * - * @param layer - Which layer to delete from. - * @param segment - Which segment to delete from. - * @param key - The key that identifies the value to be deleted. - */ - delete(layer: Layer, segment: Segment, key: Key): void; - /** - * Queue a value to be deleted. - * - * @param layer - Which layer to delete from. - * @param key - The key that identifies the value to be deleted. - */ - delete(layer: Layer, key: Key): void; - - /** - * Commit all queued operations. - */ - commit(): void; - - /** - * Discard all queued operations. - */ - abort(): void; -} - -/** @inheritdoc */ -export class MonolithicTransaction< - KV extends KeyValueLookup, - Layer extends LayerRange -> implements LayeredStorageTransaction { - private readonly _transactionCore: TransactionCore; - private readonly _monolithic: symbol; - - /** - * Create a new transaction for given storage. - * - * @param storageCore - The core that this instance will save mutations to. - */ - public constructor(storageCore: LayeredStorageCore) { - this._monolithic = storageCore.monolithic; - this._transactionCore = new TransactionCore(storageCore); - } - - public set( - layer: Layer, - segment: Segment, - key: Key, - value: KV[Key] - ): void; - public set( - layer: Layer, - key: Key, - value: KV[Key] - ): void; - /** @inheritdoc */ - public set( - ...rest: [Layer, Segment, Key, KV[Key]] | [Layer, Key, KV[Key]] - ): void { - return rest.length === 3 - ? this._transactionCore.set(rest[0], this._monolithic, rest[1], rest[2]) - : this._transactionCore.set(rest[0], rest[1], rest[2], rest[3]); - } - - public delete( - layer: Layer, - segment: Segment, - key: Key - ): void; - public delete(layer: Layer, key: Key): void; - /** @inheritdoc */ - public delete( - ...rest: [Layer, Segment, Key] | [Layer, Key] - ): void { - return rest.length === 2 - ? this._transactionCore.delete(rest[0], this._monolithic, rest[1]) - : this._transactionCore.delete(rest[0], rest[1], rest[2]); - } - - /** @inheritdoc */ - public commit(): void { - return this._transactionCore.commit(); - } - - /** @inheritdoc */ - public abort(): void { - return this._transactionCore.abort(); - } -} - -/** @inheritdoc */ -export interface LayeredStorageSegmentTransaction< - KV extends KeyValueLookup, - Layer extends LayerRange -> { - /** - * Queue a value to be set. - * - * @param layer - Which layer to save the value into. - * @param key - Key that can be used to retrieve or overwrite this value later. - * @param value - The value to be saved. - */ - set(layer: Layer, key: Key, value: KV[Key]): void; - - /** - * Queue a value to be deleted. - * - * @param layer - Which layer to delete from. - * @param key - The key that identifies the value to be deleted. - */ - delete(layer: Layer, key: Key): void; - - /** - * Commit all queued operations. - */ - commit(): void; - - /** - * Discard all queued operations. - */ - abort(): void; -} - -/** - * A transaction working with a single segment. - * - * @typeParam KV - Sets the value types associeated with their keys. - * (TS only, ignored in JS). - * @typeParam Layer - Sets the allowed layers. - * (TS only, ignored in JS). - */ -export class SegmentTransaction< - KV extends KeyValueLookup, - Layer extends LayerRange -> implements LayeredStorageSegmentTransaction { - private readonly _transactionCore: TransactionCore; - - /** - * Create a new transaction for a segment of given storage. - * - * @param storageCore - The core that this instance will save mutations to. - * @param _segment - The segment this instance will manage. - */ - public constructor( - storageCore: LayeredStorageCore, - private readonly _segment: Segment - ) { - this._transactionCore = new TransactionCore(storageCore); - } - - /** @inheritdoc */ - public set( - layer: Layer, - key: Key, - value: KV[Key] - ): void { - return this._transactionCore.set(layer, this._segment, key, value); - } - - /** @inheritdoc */ - public delete(layer: Layer, key: Key): void { - return this._transactionCore.delete(layer, this._segment, key); - } - - /** @inheritdoc */ - public commit(): void { - return this._transactionCore.commit(); - } - - /** @inheritdoc */ - public abort(): void { - return this._transactionCore.abort(); - } -} diff --git a/test/layered-storage/all-combined.ts b/test/layered-storage/all-combined.ts index bc11a45fa..795020995 100644 --- a/test/layered-storage/all-combined.ts +++ b/test/layered-storage/all-combined.ts @@ -5,7 +5,7 @@ import { expect } from "chai"; type KV = Record; const expectedResult = deepFreeze({ - monolithic: { + global: { "test.value1": 5, "test.value2": undefined, "test.value3": undefined @@ -28,127 +28,82 @@ const expectedResult = deepFreeze({ }); const expectedResultMinusC = deepFreeze({ - monolithic: expectedResult.monolithic, + global: expectedResult.global, a: expectedResult.a, b: expectedResult.b, - c: expectedResult.monolithic + c: expectedResult.global }); const expectedResultMinusAC = deepFreeze({ - monolithic: expectedResult.monolithic, - a: expectedResult.monolithic, + global: expectedResult.global, + a: expectedResult.global, b: expectedResult.b, - c: expectedResult.monolithic + c: expectedResult.global }); const expectedResultMinusABC = deepFreeze({ - monolithic: expectedResult.monolithic, - a: expectedResult.monolithic, - b: expectedResult.monolithic, - c: expectedResult.monolithic + global: expectedResult.global, + a: expectedResult.global, + b: expectedResult.global, + c: expectedResult.global }); /** * Test all mutatins including segmented mutations with Layered Storage. */ export function allCombined(): void { - describe("All combined", function(): void { - it("Main instance only", function(): void { - const ls = new LayeredStorage(); - - const getData = (): unknown => { - const data: any = {}; - for (const segment of ["monolithic", "a", "b", "c"]) { - data[segment] = {}; - for (const key of ["test.value1", "test.value2", "test.value3"]) { - data[segment][key] = - segment === "monolithic" ? ls.get(key) : ls.get(segment, key); - } + it("All combined", function(): void { + const ls = new LayeredStorage<1 | 4 | 9, KV, keyof KV>(); + + const a = ls.openSegment("a"); + const b = ls.openSegment("b"); + const c = ls.openSegment("c"); + const segments = { a, b, c }; + + const getData = (): unknown => { + const data: any = {}; + for (const segment of [ + "global" as const, + "a" as const, + "b" as const, + "c" as const + ]) { + data[segment] = {}; + for (const key of ["test.value1", "test.value2", "test.value3"]) { + data[segment][key] = + segment === "global" + ? ls.global.get(key) + : segments[segment].get(key); } - - return data; - }; - - ls.set(1, "b", "test.value3", 6); - ls.set(1, "c", "test.value2", 7); - ls.set(1, "a", "test.value1", 1); - ls.delete(4, "b", "test.value1"); - ls.set(4, "test.value1", 4); - ls.set(4, "b", "test.value3", 9); - ls.delete(4, "c", "test.value1"); - ls.delete(9, "test.value1"); - ls.set(9, "test.value3", 3); - ls.set(4, "a", "test.value2", 2); - ls.set(9, "b", "test.value2", 8); - ls.delete(9, "test.value3"); - ls.set(9, "test.value1", 5); - ls.delete(4, "a", "test.value1"); - ls.set(9, "c", "test.value1", 3); - expect(getData()).to.deep.equal(expectedResult); - - ls.deleteSegmentData("c"); - expect(getData()).to.deep.equal(expectedResultMinusC); - - ls.deleteSegmentData("a"); - expect(getData()).to.deep.equal(expectedResultMinusAC); - - ls.deleteSegmentData("b"); - expect(getData()).to.deep.equal(expectedResultMinusABC); - }); - - it("Main and segment instances", function(): void { - const ls = new LayeredStorage(); - - const a = ls.openSegment("a"); - const b = ls.openSegment("b"); - const c = ls.openSegment("c"); - const segments = { a, b, c }; - - const getData = (): unknown => { - const data: any = {}; - for (const segment of [ - "monolithic" as const, - "a" as const, - "b" as const, - "c" as const - ]) { - data[segment] = {}; - for (const key of ["test.value1", "test.value2", "test.value3"]) { - data[segment][key] = - segment === "monolithic" - ? ls.get(key) - : segments[segment].get(key); - } - } - - return data; - }; - - b.set(1, "test.value3", 6); - c.set(1, "test.value2", 7); - a.set(1, "test.value1", 1); - b.delete(4, "test.value1"); - ls.set(4, "test.value1", 4); - b.set(4, "test.value3", 9); - c.delete(4, "test.value1"); - ls.delete(9, "test.value1"); - ls.set(9, "test.value3", 3); - a.set(4, "test.value2", 2); - b.set(9, "test.value2", 8); - ls.delete(9, "test.value3"); - ls.set(9, "test.value1", 5); - a.delete(4, "test.value1"); - c.set(9, "test.value1", 3); - expect(getData()).to.deep.equal(expectedResult); - - c.close(); - expect(getData()).to.deep.equal(expectedResultMinusC); - - a.close(); - expect(getData()).to.deep.equal(expectedResultMinusAC); - - b.close(); - expect(getData()).to.deep.equal(expectedResultMinusABC); - }); + } + + return data; + }; + + b.set(1, "test.value3", 6); + c.set(1, "test.value2", 7); + a.set(1, "test.value1", 1); + b.delete(4, "test.value1"); + ls.global.set(4, "test.value1", 4); + b.set(4, "test.value3", 9); + c.delete(4, "test.value1"); + ls.global.delete(9, "test.value1"); + ls.global.set(9, "test.value3", 3); + a.set(4, "test.value2", 2); + b.set(9, "test.value2", 8); + ls.global.delete(9, "test.value3"); + ls.global.set(9, "test.value1", 5); + a.delete(4, "test.value1"); + c.set(9, "test.value1", 3); + expect(getData()).to.deep.equal(expectedResult); + + c.close(); + expect(getData()).to.deep.equal(expectedResultMinusC); + + a.close(); + expect(getData()).to.deep.equal(expectedResultMinusAC); + + b.close(); + expect(getData()).to.deep.equal(expectedResultMinusABC); }); } diff --git a/test/layered-storage/cloning.ts b/test/layered-storage/cloning.ts index 8222c85fd..4462fcaa0 100644 --- a/test/layered-storage/cloning.ts +++ b/test/layered-storage/cloning.ts @@ -16,25 +16,25 @@ export function cloning(): void { const configs: { name: string; clone( - ls: LayeredStorage, - s1: LayeredStorageSegment - ): LayeredStorageSegment; + ls: LayeredStorage<0 | 1 | 2, KV, keyof KV>, + s1: LayeredStorageSegment<0 | 1 | 2, KV, keyof KV> + ): LayeredStorageSegment<0 | 1 | 2, KV, keyof KV>; }[] = [ { name: "From main instance", - clone: (ls): LayeredStorageSegment => + clone: (ls): LayeredStorageSegment<0 | 1 | 2, KV, keyof KV> => ls.cloneSegment(1, 2) }, { name: "From segment instance", - clone: (_ls, s1): LayeredStorageSegment => + clone: (_ls, s1): LayeredStorageSegment<0 | 1 | 2, KV, keyof KV> => s1.cloneSegment(2) } ]; configs.forEach(({ name, clone }): void => { it(name, function(): void { - const ls = new LayeredStorage(); + const ls = new LayeredStorage<0 | 1 | 2, KV, keyof KV>(); const s1 = ls.openSegment(1); @@ -71,7 +71,7 @@ export function cloning(): void { }); it("Cloning into existing segment", function(): void { - const ls = new LayeredStorage(); + const ls = new LayeredStorage<1, KV, keyof KV>(); const s1 = ls.openSegment(1); const s2 = ls.openSegment(2); diff --git a/test/layered-storage/expanders.ts b/test/layered-storage/expanders.ts index 244a9a6aa..8549c023d 100644 --- a/test/layered-storage/expanders.ts +++ b/test/layered-storage/expanders.ts @@ -1,7 +1,4 @@ -import { - LayeredStorage, - FilteredKeyValueEntry -} from "../../src/layered-storage"; +import { KeyValueEntry, LayeredStorage } from "../../src/layered-storage"; import { expect } from "chai"; interface KV { @@ -12,7 +9,7 @@ interface KV { } /** - * Test that values can be set and retrieved from single monolithic layer. + * Test that values can be set and retrieved from single global layer. */ export function expanders(): void { describe("Expanders", function(): void { @@ -23,7 +20,7 @@ export function expanders(): void { ] as const; const expander = ( input: string - ): readonly FilteredKeyValueEntry< + ): readonly KeyValueEntry< KV, "test.boolean" | "test.number" | "test.string" >[] => { @@ -39,24 +36,29 @@ export function expanders(): void { }; it("Without validation", function(): void { - const ls = new LayeredStorage(); + const ls = new LayeredStorage<0, KV, keyof KV>(); ls.setExpander("test", expanderAffects, expander); const testValue = "false 7 seven"; - ls.set(0, "test", testValue); + ls.global.set(0, "test", testValue); - expect(ls.has("test"), "The raw value should not be saved.").to.be.false; + expect(ls.global.has("test"), "The raw value should not be saved.").to.be + .false; expect( - [ls.get("test.boolean"), ls.get("test.number"), ls.get("test.string")], + [ + ls.global.get("test.boolean"), + ls.global.get("test.number"), + ls.global.get("test.string") + ], "The expanded values from the expander should be returned." ).to.deep.equal([false, 7, "seven"]); }); it("Invalid short value", function(): void { - const ls = new LayeredStorage(); + const ls = new LayeredStorage<0, KV, keyof KV>(); ls.setValidators("test", [ (value): true | string => @@ -68,13 +70,13 @@ export function expanders(): void { const testValue = "false7seven"; expect( - (): void => void ls.set(0, "test", testValue), + (): void => void ls.global.set(0, "test", testValue), "Invalid values should not pass validation." ).to.throw(); }); it("Invalid expanded value", function(): void { - const ls = new LayeredStorage(); + const ls = new LayeredStorage<0, KV, keyof KV>(); ls.setValidators("test.number", [ (value): true | string => value < 7 || "Invalid input." @@ -85,27 +87,35 @@ export function expanders(): void { const testValue = "false 7 seven"; expect( - (): void => void ls.set(0, "test", testValue), + (): void => void ls.global.set(0, "test", testValue), "Invalid values should not pass validation." ).to.throw(); }); it("Delete expanded values", function(): void { - const ls = new LayeredStorage(); + const ls = new LayeredStorage<0, KV, keyof KV>(); ls.setExpander("test", expanderAffects, expander); const testValue = "false 7 seven"; - ls.set(0, "test", testValue); + ls.global.set(0, "test", testValue); expect( - [ls.has("test.boolean"), ls.has("test.number"), ls.has("test.string")], + [ + ls.global.has("test.boolean"), + ls.global.has("test.number"), + ls.global.has("test.string") + ], "All expanded values should be set." ).deep.equal([true, true, true]); - ls.delete(0, "test"); + ls.global.delete(0, "test"); expect( - [ls.has("test.boolean"), ls.has("test.number"), ls.has("test.string")], + [ + ls.global.has("test.boolean"), + ls.global.has("test.number"), + ls.global.has("test.string") + ], "All expanded values should be deleted." ).deep.equal([false, false, false]); }); diff --git a/test/layered-storage/multiple-keys.ts b/test/layered-storage/multiple-keys.ts index b16d42006..bbd664f9d 100644 --- a/test/layered-storage/multiple-keys.ts +++ b/test/layered-storage/multiple-keys.ts @@ -18,97 +18,97 @@ export function multipleKeys(): void { const testValue3: KV["test.value3"] = "abc"; it("Set and get", function(): void { - const ls = new LayeredStorage(); + const ls = new LayeredStorage<3, KV, keyof KV>(); - ls.set(3, "test.value1", testValue1); - ls.set(3, "test.value2", testValue2); - ls.set(3, "test.value3", testValue3); + ls.global.set(3, "test.value1", testValue1); + ls.global.set(3, "test.value2", testValue2); + ls.global.set(3, "test.value3", testValue3); expect( - ls.get("test.value1"), + ls.global.get("test.value1"), "The same value that was set should be returned." ).to.equal(testValue1); expect( - ls.get("test.value2"), + ls.global.get("test.value2"), "The same value that was set should be returned." ).to.equal(testValue2); expect( - ls.get("test.value3"), + ls.global.get("test.value3"), "The same value that was set should be returned." ).to.equal(testValue3); }); it("Set and has", function(): void { - const ls = new LayeredStorage(); + const ls = new LayeredStorage<3, KV, keyof KV>(); - ls.set(3, "test.value1", testValue1); - ls.set(3, "test.value2", testValue2); - ls.set(3, "test.value3", testValue3); + ls.global.set(3, "test.value1", testValue1); + ls.global.set(3, "test.value2", testValue2); + ls.global.set(3, "test.value3", testValue3); expect( - ls.has("test.value1"), + ls.global.has("test.value1"), "This value was set and should be reported as present." ).to.be.true; expect( - ls.has("test.value2"), + ls.global.has("test.value2"), "This value was set and should be reported as present." ).to.be.true; expect( - ls.has("test.value3"), + ls.global.has("test.value3"), "This value was set and should be reported as present." ).to.be.true; }); it("Set, delete and get", function(): void { - const ls = new LayeredStorage(); + const ls = new LayeredStorage<3, KV, keyof KV>(); expect( - ls.get("test.value2"), + ls.global.get("test.value2"), "There is no value yet so it should be undefined." ).to.be.undefined; - ls.set(3, "test.value1", testValue1); + ls.global.set(3, "test.value1", testValue1); expect( - ls.get("test.value2"), + ls.global.get("test.value2"), "Different value was set, undefined should be returned." ).to.be.undefined; - ls.set(3, "test.value2", testValue2); + ls.global.set(3, "test.value2", testValue2); expect( - ls.get("test.value2"), + ls.global.get("test.value2"), "The value that was set should also be returned." ).to.equal(testValue2); - ls.delete(3, "test.value2"); + ls.global.delete(3, "test.value2"); expect( - ls.get("test.value2"), + ls.global.get("test.value2"), "Undefined should be returned for deleted values." ).to.be.undefined; }); it("Set, delete and has", function(): void { - const ls = new LayeredStorage(); + const ls = new LayeredStorage<3, KV, keyof KV>(); expect( - ls.has("test.value2"), + ls.global.has("test.value2"), "There is no value yet so it should be false." ).to.be.false; - ls.set(3, "test.value1", testValue1); + ls.global.set(3, "test.value1", testValue1); expect( - ls.has("test.value2"), + ls.global.has("test.value2"), "Different value was set, false should be returned." ).to.be.false; - ls.set(3, "test.value2", testValue2); + ls.global.set(3, "test.value2", testValue2); expect( - ls.has("test.value2"), + ls.global.has("test.value2"), "True should be returned for existing values." ).to.be.true; - ls.delete(3, "test.value2"); + ls.global.delete(3, "test.value2"); expect( - ls.has("test.value2"), + ls.global.has("test.value2"), "False should be returned for deleted values." ).to.be.false; }); diff --git a/test/layered-storage/multiple-layers.ts b/test/layered-storage/multiple-layers.ts index 5e28a886e..e0a6892b7 100644 --- a/test/layered-storage/multiple-layers.ts +++ b/test/layered-storage/multiple-layers.ts @@ -30,110 +30,110 @@ export function multipleLayers(): void { }); it("Set and get", function(): void { - const ls = new LayeredStorage(); + const ls = new LayeredStorage<1 | 2 | 3 | 4, KV, keyof KV>(); - ls.set(1, "test.value", testValue1); + ls.global.set(1, "test.value", testValue1); expect( - ls.get("test.value"), + ls.global.get("test.value"), "The first layer should be returned since it's the highest." ).to.equal(testValue1); - ls.set(2, "test.value", testValue2); + ls.global.set(2, "test.value", testValue2); expect( - ls.get("test.value"), + ls.global.get("test.value"), "The second layer should be returned since it's the highest." ).to.equal(testValue2); - ls.set(4, "test.value", testValue4); + ls.global.set(4, "test.value", testValue4); expect( - ls.get("test.value"), + ls.global.get("test.value"), "The fourth layer should be returned since it's the highest now." ).to.equal(testValue4); }); it("Set and has", function(): void { - const ls = new LayeredStorage(); + const ls = new LayeredStorage<1 | 2 | 3 | 4, KV, keyof KV>(); expect( - ls.has("test.value"), + ls.global.has("test.value"), "There is no value yet so it shouldn't be reported as empty." ).to.be.false; - ls.set(3, "test.value", testValue3); + ls.global.set(3, "test.value", testValue3); expect( - ls.has("test.value"), + ls.global.has("test.value"), "There is one value so it should be reported as present." ).to.be.true; - ls.set(2, "test.value", testValue2); + ls.global.set(2, "test.value", testValue2); expect( - ls.has("test.value"), + ls.global.has("test.value"), "There are two value so it should be reported as present." ).to.be.true; }); it("Set, delete and get", function(): void { - const ls = new LayeredStorage(); + const ls = new LayeredStorage<1 | 2 | 3 | 4, KV, keyof KV>(); expect( - ls.get("test.value"), + ls.global.get("test.value"), "There is no value yet so it should be undefined." ).to.be.undefined; - ls.set(3, "test.value", testValue3); + ls.global.set(3, "test.value", testValue3); expect( - ls.get("test.value"), + ls.global.get("test.value"), "Layer three has a value that should be returned." ).to.equal(testValue3); - ls.set(2, "test.value", testValue2); + ls.global.set(2, "test.value", testValue2); expect( - ls.get("test.value"), + ls.global.get("test.value"), "Layer three has a value that should be returned." ).to.equal(testValue3); - ls.delete(3, "test.value"); + ls.global.delete(3, "test.value"); expect( - ls.get("test.value"), + ls.global.get("test.value"), "Layer two has a value that should be returned." ).to.equal(testValue2); - ls.delete(2, "test.value"); + ls.global.delete(2, "test.value"); expect( - ls.get("test.value"), + ls.global.get("test.value"), "There isn't any value anymore so it should be undefined." ).to.be.undefined; }); it("Set, delete and has", function(): void { - const ls = new LayeredStorage(); + const ls = new LayeredStorage<1 | 2 | 3 | 4, KV, keyof KV>(); expect( - ls.has("test.value"), + ls.global.has("test.value"), "There is no value yet so it should be reported as empty." ).to.be.false; - ls.set(3, "test.value", testValue3); + ls.global.set(3, "test.value", testValue3); expect( - ls.has("test.value"), + ls.global.has("test.value"), "There is one value so it should be reported as present." ).to.be.true; - ls.set(2, "test.value", testValue2); + ls.global.set(2, "test.value", testValue2); expect( - ls.has("test.value"), + ls.global.has("test.value"), "There are two value so it should be reported as present." ).to.be.true; - ls.delete(2, "test.value"); + ls.global.delete(2, "test.value"); expect( - ls.has("test.value"), + ls.global.has("test.value"), "There is one value so it should be reported as present." ).to.be.true; - ls.delete(3, "test.value"); + ls.global.delete(3, "test.value"); expect( - ls.has("test.value"), + ls.global.has("test.value"), "There isn't any value anymore so it should be reported as empty." ).to.be.false; }); diff --git a/test/layered-storage/other.ts b/test/layered-storage/other.ts index c9358c060..abb237753 100644 --- a/test/layered-storage/other.ts +++ b/test/layered-storage/other.ts @@ -7,7 +7,9 @@ type KV = Record; * Other tests that don't fit elsewhere. */ export function other(): void { - const getStructCount = (ls: LayeredStorage): number => + const getStructCount = ( + ls: LayeredStorage<1 | 4 | 9, KV, keyof KV> + ): number => [ // Ignore private property access errors. It's no big deal since this // is a unit test. @@ -23,21 +25,21 @@ export function other(): void { ); }, 0); - const getCacheSize = (ls: LayeredStorage): number => + const getCacheSize = (ls: LayeredStorage<1 | 4 | 9, KV, keyof KV>): number => // Ignore private property access errors. It's no big deal since this // is a unit test. // @ts-ignore ls._core._topLevelCache.size; it("Empty data structure purging", function(): void { - const ls = new LayeredStorage(); + const ls = new LayeredStorage<1 | 4 | 9, KV, keyof KV>(); ([1, 4, 9] as const).forEach((layer): void => { - ls.set(layer, "test.value1", 1); - ls.set(layer, "test.value2", 2); + ls.global.set(layer, "test.value1", 1); + ls.global.set(layer, "test.value2", 2); ["a", "b", "c"].forEach((segment): void => { - ls.set(layer, segment, "test.value1", 1); - ls.set(layer, segment, "test.value2", 2); + ls.openSegment(segment).set(layer, "test.value1", 1); + ls.openSegment(segment).set(layer, "test.value2", 2); }); }); @@ -48,9 +50,9 @@ export function other(): void { ); ([1, 4, 9] as const).forEach((layer): void => { - ls.delete(layer, "test.value1"); + ls.global.delete(layer, "test.value1"); ["a", "b", "c"].forEach((segment): void => { - ls.delete(layer, segment, "test.value1"); + ls.openSegment(segment).delete(layer, "test.value1"); }); }); @@ -61,9 +63,9 @@ export function other(): void { ); ([1, 4, 9] as const).forEach((layer): void => { - ls.delete(layer, "test.value2"); + ls.global.delete(layer, "test.value2"); ["b"].forEach((segment): void => { - ls.delete(layer, segment, "test.value2"); + ls.openSegment(segment).delete(layer, "test.value2"); }); }); @@ -75,7 +77,7 @@ export function other(): void { ([1, 4, 9] as const).forEach((layer): void => { ["a", "c"].forEach((segment): void => { - ls.delete(layer, segment, "test.value2"); + ls.openSegment(segment).delete(layer, "test.value2"); }); }); @@ -85,52 +87,63 @@ export function other(): void { }); it("Cache purging", function(): void { - const ls = new LayeredStorage(); + const ls = new LayeredStorage<1, KV, keyof KV>(); expect(getCacheSize(ls)).to.equal(0); - ls.set(1, "test.value1", 7); - ls.set(1, "a", "test.value1", 7); - ls.set(1, "b", "test.value1", 7); - ls.set(1, "c", "test.value1", 7); + ls.global.set(1, "test.value1", 7); + ls.openSegment("a").set(1, "test.value1", 7); + ls.openSegment("b").set(1, "test.value1", 7); + ls.openSegment("c").set(1, "test.value1", 7); expect(getCacheSize(ls)).to.equal(0); - ls.get("test.value1"); - ls.get("a", "test.value1"); - ls.get("b", "test.value1"); - ls.get("c", "test.value1"); - ls.get("test.value2"); - ls.get("a", "test.value2"); - ls.get("b", "test.value2"); - ls.get("c", "test.value2"); + ls.global.get("test.value1"); + ls.openSegment("a").get("test.value1"); + ls.openSegment("b").get("test.value1"); + ls.openSegment("c").get("test.value1"); + ls.global.get("test.value2"); + ls.openSegment("a").get("test.value2"); + ls.openSegment("b").get("test.value2"); + ls.openSegment("c").get("test.value2"); expect(getCacheSize(ls)).to.equal(4); - ls.set(1, "test.value1", 7); - ls.set(1, "a", "test.value1", 7); - ls.set(1, "b", "test.value1", 7); - ls.set(1, "c", "test.value1", 7); + ls.global.set(1, "test.value1", 7); + ls.openSegment("a").set(1, "test.value1", 7); + ls.openSegment("b").set(1, "test.value1", 7); + ls.openSegment("c").set(1, "test.value1", 7); expect(getCacheSize(ls)).to.equal(4); - ls.set(1, "test.value2", 7); + ls.global.set(1, "test.value2", 7); expect(getCacheSize(ls)).to.equal(0); }); it("Empty data structure creation", function(): void { - const ls = new LayeredStorage(); + const ls = new LayeredStorage<1 | 4 | 9, KV, keyof KV>(); - ls.set(4, "c", "test.value1", 1); + ls.openSegment("c").set(4, "test.value1", 1); - ls.get("test.value1"); - ls.get("b", "test.value1"); - ls.has("test.value2"); - ls.has("a", "test.value2"); + ls.global.get("test.value1"); + ls.openSegment("b").get("test.value1"); + ls.global.has("test.value2"); + ls.openSegment("a").has("test.value2"); expect(getStructCount(ls)).to.equal( 3 // 1 layer, 1 segment, 1 value ); }); + + it("Segment storage reports it's segment", function(): void { + const ls = new LayeredStorage<1 | 4 | 9, KV, keyof KV>(); + + expect( + ls.openSegment("$"), + "Each segment should exposes a property with the name of the segment." + ) + .have.ownProperty("segment") + .that.equals("$"); + }); } diff --git a/test/layered-storage/segmented-layer.ts b/test/layered-storage/segmented-layer.ts index c4b141a7d..d7943c8ff 100644 --- a/test/layered-storage/segmented-layer.ts +++ b/test/layered-storage/segmented-layer.ts @@ -30,114 +30,116 @@ export function segmentedLayer(): void { const c = Symbol("C"); it("Get without set", function(): void { - const ls = new LayeredStorage(); + const ls = new LayeredStorage<7, KV, keyof KV>(); - ls.set(7, "test.value", testValueA); + ls.global.set(7, "test.value", testValueA); expect( - ls.get(b, "test.value"), - "Monolithic value should be used if the segment doesn't exist." + ls.openSegment(b).get("test.value"), + "Global value should be used if the segment doesn't exist." ).to.equal(testValueA); }); it("Get without set after unrelated set", function(): void { - const ls = new LayeredStorage(); + const ls = new LayeredStorage<7, KV, keyof KV>(); - ls.set(7, "test.value", testValueA); - ls.set(7, b, "unrelated.value", testValueB); + ls.global.set(7, "test.value", testValueA); + ls.openSegment(b).set(7, "unrelated.value", testValueB); expect( - ls.get(b, "test.value"), - "Monolithic value should be used if the segment doesn't have it's own." + ls.openSegment(b).get("test.value"), + "Global value should be used if the segment doesn't have it's own." ).to.equal(testValueA); }); it("Set and get", function(): void { - const ls = new LayeredStorage(); + const ls = new LayeredStorage<7, KV, keyof KV>(); - ls.set(7, a, "test.value", testValueA); - ls.set(7, b, "test.value", testValueB); - ls.set(7, c, "test.value", testValueC); + ls.openSegment(a).set(7, "test.value", testValueA); + ls.openSegment(b).set(7, "test.value", testValueB); + ls.openSegment(c).set(7, "test.value", testValueC); expect( - ls.get("test.value"), + ls.global.get("test.value"), "Only segmented values were set, this should be undefined." ).to.be.undefined; expect( - ls.get(a, "test.value"), + ls.openSegment(a).get("test.value"), "The A segment should return A test value." ).to.equal(testValueA); expect( - ls.get(b, "test.value"), + ls.openSegment(b).get("test.value"), "The B segment should return B test value." ).to.equal(testValueB); expect( - ls.get(c, "test.value"), + ls.openSegment(c).get("test.value"), "The C segment should return C test value." ).to.equal(testValueC); }); it("Set and has", function(): void { - const ls = new LayeredStorage(); + const ls = new LayeredStorage<7, KV, keyof KV>(); - ls.set(7, b, "test.value", testValueB); + ls.openSegment(b).set(7, "test.value", testValueB); - expect(ls.has("test.value"), "Only B segment was set and should be true.") - .to.be.false; + expect( + ls.global.has("test.value"), + "Only B segment was set and should be true." + ).to.be.false; expect( - ls.has(a, "test.value"), + ls.openSegment(a).has("test.value"), "Only B segment was set and should be true." ).to.be.false; expect( - ls.has(b, "test.value"), + ls.openSegment(b).has("test.value"), "Only B segment was set and should be true." ).to.be.true; expect( - ls.has(c, "test.value"), + ls.openSegment(c).has("test.value"), "Only B segment was set and should be true." ).to.be.false; }); it("Set, delete and get", function(): void { - const ls = new LayeredStorage(); + const ls = new LayeredStorage<7, KV, keyof KV>(); expect( - ls.get(c, "test.value"), + ls.openSegment(c).get("test.value"), "There is no value yet so it should be undefined." ).to.be.undefined; - ls.set(7, c, "test.value", testValueC); + ls.openSegment(c).set(7, "test.value", testValueC); expect( - ls.get(c, "test.value"), + ls.openSegment(c).get("test.value"), "Layer 7 segment C has a value that should be returned." ).to.equal(testValueC); - ls.delete(7, c, "test.value"); + ls.openSegment(c).delete(7, "test.value"); expect( - ls.get(c, "test.value"), + ls.openSegment(c).get("test.value"), "There isn't any value anymore so it should be undefined." ).to.be.undefined; }); it("Set, delete and has", function(): void { - const ls = new LayeredStorage(); + const ls = new LayeredStorage<7, KV, keyof KV>(); expect( - ls.get(c, "test.value"), + ls.openSegment(c).get("test.value"), "There is no value yet so it should be undefined." ).to.be.undefined; - ls.set(7, c, "test.value", testValueC); + ls.openSegment(c).set(7, "test.value", testValueC); expect( - ls.has(c, "test.value"), + ls.openSegment(c).has("test.value"), "Layer 7 segment C has a value therefore it should return true." ).to.be.true; - ls.delete(7, c, "test.value"); + ls.openSegment(c).delete(7, "test.value"); expect( - ls.has(c, "test.value"), + ls.openSegment(c).has("test.value"), "There isn't any value anymore so it should return false." ).to.be.false; }); @@ -146,10 +148,11 @@ export function segmentedLayer(): void { [undefined, null, "string", true, false, {}].forEach( (layer: any): void => { it("" + layer, function(): void { - const ls = new LayeredStorage(); + const ls = new LayeredStorage<0, KV, keyof KV>(); expect( - (): void => void ls.set(layer, b, "test.value", testValueB), + (): void => + void ls.openSegment(b).set(layer, "test.value", testValueB), "Layers have to be ordered which is only possible with numbers as that's the only thing that has universally accepted indisputable order." ).to.throw(); }); diff --git a/test/layered-storage/single-layer.ts b/test/layered-storage/single-layer.ts index 165f2432a..2dafaeda5 100644 --- a/test/layered-storage/single-layer.ts +++ b/test/layered-storage/single-layer.ts @@ -7,7 +7,7 @@ interface KV { } /** - * Test that values can be set and retrieved from single monolithic layer. + * Test that values can be set and retrieved from single global layer. */ export function singleLayer(): void { describe("Single layer", function(): void { @@ -17,63 +17,63 @@ export function singleLayer(): void { }); it("Set and get", function(): void { - const ls = new LayeredStorage(); + const ls = new LayeredStorage<0, KV, keyof KV>(); - ls.set(0, "test.value", testValue); + ls.global.set(0, "test.value", testValue); expect( - ls.get("test.value"), + ls.global.get("test.value"), "The same value that was set should be returned." ).to.equal(testValue); }); it("Set and has", function(): void { - const ls = new LayeredStorage(); + const ls = new LayeredStorage<0, KV, keyof KV>(); - ls.set(0, "test.value", testValue); + ls.global.set(0, "test.value", testValue); expect( - ls.has("test.value"), + ls.global.has("test.value"), "The value should be reported as present after being set." ).to.be.true; }); it("Set, delete and get", function(): void { - const ls = new LayeredStorage(); + const ls = new LayeredStorage<0, KV, keyof KV>(); expect( - ls.get("test.value"), + ls.global.get("test.value"), "There is no value yet so it should be undefined." ).to.be.undefined; - ls.set(0, "test.value", testValue); + ls.global.set(0, "test.value", testValue); expect( - ls.get("test.value"), + ls.global.get("test.value"), "The same value that was set should be returned." ).to.equal(testValue); - ls.delete(0, "test.value"); + ls.global.delete(0, "test.value"); expect( - ls.get("test.value"), + ls.global.get("test.value"), "Undefined should be returned for deleted values." ).to.be.undefined; }); it("Set, delete and has", function(): void { - const ls = new LayeredStorage(); + const ls = new LayeredStorage<0, KV, keyof KV>(); expect( - ls.has("test.value"), + ls.global.has("test.value"), "There is no value yet so it should be reported as empty." ).to.be.false; - ls.set(0, "test.value", testValue); + ls.global.set(0, "test.value", testValue); expect( - ls.has("test.value"), + ls.global.has("test.value"), "The value should be reported as present after being set." ).to.be.true; - ls.delete(0, "test.value"); + ls.global.delete(0, "test.value"); expect( - ls.has("test.value"), + ls.global.has("test.value"), "The value should be reported as not present after being deleted." ).to.be.false; }); @@ -82,10 +82,10 @@ export function singleLayer(): void { [undefined, null, "string", true, false, {}].forEach( (layer: any): void => { it("" + layer, function(): void { - const ls = new LayeredStorage(); + const ls = new LayeredStorage<0, KV, keyof KV>(); expect( - (): void => void ls.set(layer, "test.value", testValue), + (): void => void ls.global.set(layer, "test.value", testValue), "Layers have to be ordered which is only possible with numbers as that's the only thing that has universally accepted indisputable order." ).to.throw(); }); diff --git a/test/layered-storage/validation.ts b/test/layered-storage/validation.ts index 4a812a4e0..3c2e21a84 100644 --- a/test/layered-storage/validation.ts +++ b/test/layered-storage/validation.ts @@ -3,15 +3,15 @@ import { expect } from "chai"; interface KV { "test.boolean": boolean; - "test.fail": unknown; + "test.fail": any; "test.integer": number; "test.number": number; - "test.pass": unknown; + "test.pass": any; "test.string": string; } /** - * Test that values can be set and retrieved from single monolithic layer. + * Test that values can be set and retrieved from single global layer. */ export function validation(): void { describe("Validation", function(): void { @@ -44,7 +44,7 @@ export function validation(): void { [true, "test.string", "test"] as const ].forEach(([valid, key, value]): void => { it(`${key}: ${value}`, function(): void { - const ls = new LayeredStorage(); + const ls = new LayeredStorage<0, KV, keyof KV>(); // Add handler. if (handler != null) { @@ -79,27 +79,27 @@ export function validation(): void { if (valid) { expect((): void => { - ls.set(0, key, value); + ls.global.set(0, key, value); }, "No error should be thrown for valid values.").to.not.throw(); expect( - ls.get(key), + ls.global.get(key), "Valid values should be saved in the storage." ).to.equal(value); } else { if (throws != null) { expect((): void => { - ls.set(0, key, value); + ls.global.set(0, key, value); }, "If the handler throws the set should throw too.").to.throw( TypeError, `${key}: ${value} (it's not valid)` ); } else { expect((): void => { - ls.set(0, key, value); + ls.global.set(0, key, value); }, "If the handler doesn't throw neither should the set.").to.not.throw(); } expect( - ls.has(key), + ls.global.has(key), "Invalid values should not be saved in the storage." ).to.be.false; } @@ -109,7 +109,7 @@ export function validation(): void { }); it("Setting validators twice", function(): void { - const ls = new LayeredStorage(); + const ls = new LayeredStorage<0, KV, keyof KV>(); expect((): void => { ls.setValidators("test.fail", [ From cc7e879b221281e93ddd463f0e89be8d4a61039e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Sun, 26 Jan 2020 23:12:15 +0100 Subject: [PATCH 32/48] fix(layered-storage): remove cyclic dep --- src/layered-storage/layered-storage.ts | 5 ++--- src/layered-storage/segment.ts | 9 ++++----- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/layered-storage/layered-storage.ts b/src/layered-storage/layered-storage.ts index d5a1f2ae2..e4a2d903a 100644 --- a/src/layered-storage/layered-storage.ts +++ b/src/layered-storage/layered-storage.ts @@ -34,7 +34,6 @@ export class LayeredStorage< private readonly _core = new LayeredStorageCore(); public readonly global = new LayeredStorageSegment( - this, this._core, this._core.globalSegment ); @@ -47,7 +46,7 @@ export class LayeredStorage< * @returns A new segmented instance permanently bound to this instance. */ public openSegment(segment: Segment): LayeredStorageSegment { - return new LayeredStorageSegment(this, this._core, segment); + return new LayeredStorageSegment(this._core, segment); } /** @@ -66,7 +65,7 @@ export class LayeredStorage< targetSegment: Segment ): LayeredStorageSegment { this._core.cloneSegmentData(sourceSegment, targetSegment); - return new LayeredStorageSegment(this, this._core, targetSegment); + return new LayeredStorageSegment(this._core, targetSegment); } /** diff --git a/src/layered-storage/segment.ts b/src/layered-storage/segment.ts index 6889e14e1..7f6886372 100644 --- a/src/layered-storage/segment.ts +++ b/src/layered-storage/segment.ts @@ -1,6 +1,6 @@ import { KeyValueLookup, LayerRange, Segment, KeyRange } from "./common"; -import { LayeredStorage, LayeredStorageTransaction } from "./layered-storage"; import { LayeredStorageCore } from "./core"; +import { LayeredStorageTransaction } from "./transactions"; /** * This is similar as `LayeredStorage` except that it is permanently bound to @@ -21,12 +21,10 @@ export class LayeredStorageSegment< /** * Create a new storage instance for given segment. * - * @param _layeredStorage - The storage that this instance will be bound to. * @param _core - The core of the Layered Storage instance. * @param segment - The segment this instance will manage. */ public constructor( - private readonly _layeredStorage: LayeredStorage, private readonly _core: LayeredStorageCore, public readonly segment: Segment ) {} @@ -91,7 +89,8 @@ export class LayeredStorageSegment< public cloneSegment( targetSegment: Segment ): LayeredStorageSegment { - return this._layeredStorage.cloneSegment(this.segment, targetSegment); + this._core.cloneSegmentData(this.segment, targetSegment); + return new LayeredStorageSegment(this._core, targetSegment); } /** @@ -137,6 +136,6 @@ export class LayeredStorageSegment< * Delete all data belonging to this segment. */ public close(): void { - this._layeredStorage.deleteSegmentData(this.segment); + this._core.deleteSegmentData(this.segment); } } From 763c703a895e6d86cfd0863a6360e9b697dbde54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Sun, 24 May 2020 15:22:16 +0200 Subject: [PATCH 33/48] style: reformat --- .eslintrc.js | 2 +- src/layered-storage/core.ts | 2 +- src/layered-storage/layered-storage.ts | 2 +- test/layered-storage/all-combined.ts | 20 +++++++++---------- test/layered-storage/cloning.ts | 14 ++++++------- test/layered-storage/expanders.ts | 24 +++++++++++------------ test/layered-storage/index.test.ts | 2 +- test/layered-storage/multiple-keys.ts | 10 +++++----- test/layered-storage/multiple-layers.ts | 18 ++++++++--------- test/layered-storage/other.ts | 10 +++++----- test/layered-storage/segmented-layer.ts | 24 +++++++++++------------ test/layered-storage/single-layer.ts | 16 +++++++-------- test/layered-storage/validation.ts | 26 ++++++++++++------------- 13 files changed, 85 insertions(+), 85 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 34530ba0a..dda980cbb 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -85,7 +85,7 @@ module.exports = { files: ["test/**/*.ts"], rules: { // This is useful to ignore private property access in a test. - "@typescript-eslint/ban-ts-ignore": "off" + "@typescript-eslint/ban-ts-ignore": "off", }, }, ], diff --git a/src/layered-storage/core.ts b/src/layered-storage/core.ts index 3a71aef99..871d3d101 100644 --- a/src/layered-storage/core.ts +++ b/src/layered-storage/core.ts @@ -3,7 +3,7 @@ import { KeyValueEntry, KeyValueLookup, LayerRange, - Segment + Segment, } from "./common"; const entriesByKeyPriority = ( diff --git a/src/layered-storage/layered-storage.ts b/src/layered-storage/layered-storage.ts index e4a2d903a..84da44dd6 100644 --- a/src/layered-storage/layered-storage.ts +++ b/src/layered-storage/layered-storage.ts @@ -3,7 +3,7 @@ import { KeyValueLookup, LayerRange, Segment, - KeyValueEntry + KeyValueEntry, } from "./common"; import { LayeredStorageCore } from "./core"; import { LayeredStorageSegment } from "./segment"; diff --git a/test/layered-storage/all-combined.ts b/test/layered-storage/all-combined.ts index 795020995..518552482 100644 --- a/test/layered-storage/all-combined.ts +++ b/test/layered-storage/all-combined.ts @@ -8,51 +8,51 @@ const expectedResult = deepFreeze({ global: { "test.value1": 5, "test.value2": undefined, - "test.value3": undefined + "test.value3": undefined, }, a: { "test.value1": 5, "test.value2": 2, - "test.value3": undefined + "test.value3": undefined, }, b: { "test.value1": 5, "test.value2": 8, - "test.value3": 9 + "test.value3": 9, }, c: { "test.value1": 3, "test.value2": 7, - "test.value3": undefined - } + "test.value3": undefined, + }, }); const expectedResultMinusC = deepFreeze({ global: expectedResult.global, a: expectedResult.a, b: expectedResult.b, - c: expectedResult.global + c: expectedResult.global, }); const expectedResultMinusAC = deepFreeze({ global: expectedResult.global, a: expectedResult.global, b: expectedResult.b, - c: expectedResult.global + c: expectedResult.global, }); const expectedResultMinusABC = deepFreeze({ global: expectedResult.global, a: expectedResult.global, b: expectedResult.global, - c: expectedResult.global + c: expectedResult.global, }); /** * Test all mutatins including segmented mutations with Layered Storage. */ export function allCombined(): void { - it("All combined", function(): void { + it("All combined", function (): void { const ls = new LayeredStorage<1 | 4 | 9, KV, keyof KV>(); const a = ls.openSegment("a"); @@ -66,7 +66,7 @@ export function allCombined(): void { "global" as const, "a" as const, "b" as const, - "c" as const + "c" as const, ]) { data[segment] = {}; for (const key of ["test.value1", "test.value2", "test.value3"]) { diff --git a/test/layered-storage/cloning.ts b/test/layered-storage/cloning.ts index 4462fcaa0..adfa5e415 100644 --- a/test/layered-storage/cloning.ts +++ b/test/layered-storage/cloning.ts @@ -1,6 +1,6 @@ import { LayeredStorage, - LayeredStorageSegment + LayeredStorageSegment, } from "../../src/layered-storage"; import { expect } from "chai"; @@ -12,7 +12,7 @@ interface KV { * Test that segments can be cloned. */ export function cloning(): void { - describe("Cloning", function(): void { + describe("Cloning", function (): void { const configs: { name: string; clone( @@ -23,17 +23,17 @@ export function cloning(): void { { name: "From main instance", clone: (ls): LayeredStorageSegment<0 | 1 | 2, KV, keyof KV> => - ls.cloneSegment(1, 2) + ls.cloneSegment(1, 2), }, { name: "From segment instance", clone: (_ls, s1): LayeredStorageSegment<0 | 1 | 2, KV, keyof KV> => - s1.cloneSegment(2) - } + s1.cloneSegment(2), + }, ]; configs.forEach(({ name, clone }): void => { - it(name, function(): void { + it(name, function (): void { const ls = new LayeredStorage<0 | 1 | 2, KV, keyof KV>(); const s1 = ls.openSegment(1); @@ -70,7 +70,7 @@ export function cloning(): void { }); }); - it("Cloning into existing segment", function(): void { + it("Cloning into existing segment", function (): void { const ls = new LayeredStorage<1, KV, keyof KV>(); const s1 = ls.openSegment(1); diff --git a/test/layered-storage/expanders.ts b/test/layered-storage/expanders.ts index 8549c023d..aae9dbbb2 100644 --- a/test/layered-storage/expanders.ts +++ b/test/layered-storage/expanders.ts @@ -12,11 +12,11 @@ interface KV { * Test that values can be set and retrieved from single global layer. */ export function expanders(): void { - describe("Expanders", function(): void { + describe("Expanders", function (): void { const expanderAffects = [ "test.boolean", "test.number", - "test.string" + "test.string", ] as const; const expander = ( input: string @@ -28,14 +28,14 @@ export function expanders(): void { return [ ["test.boolean", boolean === "true" ? true : false], ["test.number", +number], - ["test.string", string] + ["test.string", string], ] as const; }; const invalidHandler = (): never => { throw new Error("Invalid input."); }; - it("Without validation", function(): void { + it("Without validation", function (): void { const ls = new LayeredStorage<0, KV, keyof KV>(); ls.setExpander("test", expanderAffects, expander); @@ -51,18 +51,18 @@ export function expanders(): void { [ ls.global.get("test.boolean"), ls.global.get("test.number"), - ls.global.get("test.string") + ls.global.get("test.string"), ], "The expanded values from the expander should be returned." ).to.deep.equal([false, 7, "seven"]); }); - it("Invalid short value", function(): void { + it("Invalid short value", function (): void { const ls = new LayeredStorage<0, KV, keyof KV>(); ls.setValidators("test", [ (value): true | string => - /^(true|false) \d+ .*$/.test(value) || "Invalid." + /^(true|false) \d+ .*$/.test(value) || "Invalid.", ]); ls.setInvalidHandler(invalidHandler); ls.setExpander("test", expanderAffects, expander); @@ -75,11 +75,11 @@ export function expanders(): void { ).to.throw(); }); - it("Invalid expanded value", function(): void { + it("Invalid expanded value", function (): void { const ls = new LayeredStorage<0, KV, keyof KV>(); ls.setValidators("test.number", [ - (value): true | string => value < 7 || "Invalid input." + (value): true | string => value < 7 || "Invalid input.", ]); ls.setInvalidHandler(invalidHandler); ls.setExpander("test", expanderAffects, expander); @@ -92,7 +92,7 @@ export function expanders(): void { ).to.throw(); }); - it("Delete expanded values", function(): void { + it("Delete expanded values", function (): void { const ls = new LayeredStorage<0, KV, keyof KV>(); ls.setExpander("test", expanderAffects, expander); @@ -104,7 +104,7 @@ export function expanders(): void { [ ls.global.has("test.boolean"), ls.global.has("test.number"), - ls.global.has("test.string") + ls.global.has("test.string"), ], "All expanded values should be set." ).deep.equal([true, true, true]); @@ -114,7 +114,7 @@ export function expanders(): void { [ ls.global.has("test.boolean"), ls.global.has("test.number"), - ls.global.has("test.string") + ls.global.has("test.string"), ], "All expanded values should be deleted." ).deep.equal([false, false, false]); diff --git a/test/layered-storage/index.test.ts b/test/layered-storage/index.test.ts index 4b7f118b0..f51d125a5 100644 --- a/test/layered-storage/index.test.ts +++ b/test/layered-storage/index.test.ts @@ -8,7 +8,7 @@ import { segmentedLayer } from "./segmented-layer"; import { singleLayer } from "./single-layer"; import { validation } from "./validation"; -describe("Layered storage", function(): void { +describe("Layered storage", function (): void { allCombined(); cloning(); expanders(); diff --git a/test/layered-storage/multiple-keys.ts b/test/layered-storage/multiple-keys.ts index bbd664f9d..5c38abe85 100644 --- a/test/layered-storage/multiple-keys.ts +++ b/test/layered-storage/multiple-keys.ts @@ -12,12 +12,12 @@ interface KV { * it's own key. */ export function multipleKeys(): void { - describe("Multiple keys", function(): void { + describe("Multiple keys", function (): void { const testValue1: KV["test.value1"] = false; const testValue2: KV["test.value2"] = 4; const testValue3: KV["test.value3"] = "abc"; - it("Set and get", function(): void { + it("Set and get", function (): void { const ls = new LayeredStorage<3, KV, keyof KV>(); ls.global.set(3, "test.value1", testValue1); @@ -38,7 +38,7 @@ export function multipleKeys(): void { ).to.equal(testValue3); }); - it("Set and has", function(): void { + it("Set and has", function (): void { const ls = new LayeredStorage<3, KV, keyof KV>(); ls.global.set(3, "test.value1", testValue1); @@ -59,7 +59,7 @@ export function multipleKeys(): void { ).to.be.true; }); - it("Set, delete and get", function(): void { + it("Set, delete and get", function (): void { const ls = new LayeredStorage<3, KV, keyof KV>(); expect( @@ -86,7 +86,7 @@ export function multipleKeys(): void { ).to.be.undefined; }); - it("Set, delete and has", function(): void { + it("Set, delete and has", function (): void { const ls = new LayeredStorage<3, KV, keyof KV>(); expect( diff --git a/test/layered-storage/multiple-layers.ts b/test/layered-storage/multiple-layers.ts index e0a6892b7..c87e9130c 100644 --- a/test/layered-storage/multiple-layers.ts +++ b/test/layered-storage/multiple-layers.ts @@ -11,25 +11,25 @@ interface KV { * they should. */ export function multipleLayers(): void { - describe("Multiple layers", function(): void { + describe("Multiple layers", function (): void { const testValue1: KV["test.value"] = deepFreeze({ number: 1, - value: { string: "test" } + value: { string: "test" }, }); const testValue2: KV["test.value"] = deepFreeze({ number: 2, - value: { string: "test" } + value: { string: "test" }, }); const testValue3: KV["test.value"] = deepFreeze({ number: 3, - value: { string: "test" } + value: { string: "test" }, }); const testValue4: KV["test.value"] = deepFreeze({ number: 4, - value: { string: "test" } + value: { string: "test" }, }); - it("Set and get", function(): void { + it("Set and get", function (): void { const ls = new LayeredStorage<1 | 2 | 3 | 4, KV, keyof KV>(); ls.global.set(1, "test.value", testValue1); @@ -51,7 +51,7 @@ export function multipleLayers(): void { ).to.equal(testValue4); }); - it("Set and has", function(): void { + it("Set and has", function (): void { const ls = new LayeredStorage<1 | 2 | 3 | 4, KV, keyof KV>(); expect( @@ -72,7 +72,7 @@ export function multipleLayers(): void { ).to.be.true; }); - it("Set, delete and get", function(): void { + it("Set, delete and get", function (): void { const ls = new LayeredStorage<1 | 2 | 3 | 4, KV, keyof KV>(); expect( @@ -105,7 +105,7 @@ export function multipleLayers(): void { ).to.be.undefined; }); - it("Set, delete and has", function(): void { + it("Set, delete and has", function (): void { const ls = new LayeredStorage<1 | 2 | 3 | 4, KV, keyof KV>(); expect( diff --git a/test/layered-storage/other.ts b/test/layered-storage/other.ts index abb237753..092a645b7 100644 --- a/test/layered-storage/other.ts +++ b/test/layered-storage/other.ts @@ -14,7 +14,7 @@ export function other(): void { // Ignore private property access errors. It's no big deal since this // is a unit test. // @ts-ignore - ...ls._core._data.values() + ...ls._core._data.values(), ].reduce((acc, lData): number => { return ( acc + @@ -31,7 +31,7 @@ export function other(): void { // @ts-ignore ls._core._topLevelCache.size; - it("Empty data structure purging", function(): void { + it("Empty data structure purging", function (): void { const ls = new LayeredStorage<1 | 4 | 9, KV, keyof KV>(); ([1, 4, 9] as const).forEach((layer): void => { @@ -86,7 +86,7 @@ export function other(): void { ); }); - it("Cache purging", function(): void { + it("Cache purging", function (): void { const ls = new LayeredStorage<1, KV, keyof KV>(); expect(getCacheSize(ls)).to.equal(0); @@ -121,7 +121,7 @@ export function other(): void { expect(getCacheSize(ls)).to.equal(0); }); - it("Empty data structure creation", function(): void { + it("Empty data structure creation", function (): void { const ls = new LayeredStorage<1 | 4 | 9, KV, keyof KV>(); ls.openSegment("c").set(4, "test.value1", 1); @@ -136,7 +136,7 @@ export function other(): void { ); }); - it("Segment storage reports it's segment", function(): void { + it("Segment storage reports it's segment", function (): void { const ls = new LayeredStorage<1 | 4 | 9, KV, keyof KV>(); expect( diff --git a/test/layered-storage/segmented-layer.ts b/test/layered-storage/segmented-layer.ts index d7943c8ff..e09e5452f 100644 --- a/test/layered-storage/segmented-layer.ts +++ b/test/layered-storage/segmented-layer.ts @@ -11,25 +11,25 @@ interface KV { * Test that values can be set accross segments and later retrieved. */ export function segmentedLayer(): void { - describe("Segmented layer", function(): void { + describe("Segmented layer", function (): void { const testValueA: KV["test.value"] = deepFreeze({ number: 1, - value: { string: "A" } + value: { string: "A" }, }); const testValueB: KV["test.value"] = deepFreeze({ number: 2, - value: { string: "B" } + value: { string: "B" }, }); const testValueC: KV["test.value"] = deepFreeze({ number: 3, - value: { string: "C" } + value: { string: "C" }, }); const a = Symbol("A"); const b = Symbol("B"); const c = Symbol("C"); - it("Get without set", function(): void { + it("Get without set", function (): void { const ls = new LayeredStorage<7, KV, keyof KV>(); ls.global.set(7, "test.value", testValueA); @@ -40,7 +40,7 @@ export function segmentedLayer(): void { ).to.equal(testValueA); }); - it("Get without set after unrelated set", function(): void { + it("Get without set after unrelated set", function (): void { const ls = new LayeredStorage<7, KV, keyof KV>(); ls.global.set(7, "test.value", testValueA); @@ -52,7 +52,7 @@ export function segmentedLayer(): void { ).to.equal(testValueA); }); - it("Set and get", function(): void { + it("Set and get", function (): void { const ls = new LayeredStorage<7, KV, keyof KV>(); ls.openSegment(a).set(7, "test.value", testValueA); @@ -78,7 +78,7 @@ export function segmentedLayer(): void { ).to.equal(testValueC); }); - it("Set and has", function(): void { + it("Set and has", function (): void { const ls = new LayeredStorage<7, KV, keyof KV>(); ls.openSegment(b).set(7, "test.value", testValueB); @@ -102,7 +102,7 @@ export function segmentedLayer(): void { ).to.be.false; }); - it("Set, delete and get", function(): void { + it("Set, delete and get", function (): void { const ls = new LayeredStorage<7, KV, keyof KV>(); expect( @@ -123,7 +123,7 @@ export function segmentedLayer(): void { ).to.be.undefined; }); - it("Set, delete and has", function(): void { + it("Set, delete and has", function (): void { const ls = new LayeredStorage<7, KV, keyof KV>(); expect( @@ -144,10 +144,10 @@ export function segmentedLayer(): void { ).to.be.false; }); - describe("Invalid layer names", function(): void { + describe("Invalid layer names", function (): void { [undefined, null, "string", true, false, {}].forEach( (layer: any): void => { - it("" + layer, function(): void { + it("" + layer, function (): void { const ls = new LayeredStorage<0, KV, keyof KV>(); expect( diff --git a/test/layered-storage/single-layer.ts b/test/layered-storage/single-layer.ts index 2dafaeda5..d8190a590 100644 --- a/test/layered-storage/single-layer.ts +++ b/test/layered-storage/single-layer.ts @@ -10,13 +10,13 @@ interface KV { * Test that values can be set and retrieved from single global layer. */ export function singleLayer(): void { - describe("Single layer", function(): void { + describe("Single layer", function (): void { const testValue: KV["test.value"] = deepFreeze({ number: 7, - value: { string: "test" } + value: { string: "test" }, }); - it("Set and get", function(): void { + it("Set and get", function (): void { const ls = new LayeredStorage<0, KV, keyof KV>(); ls.global.set(0, "test.value", testValue); @@ -26,7 +26,7 @@ export function singleLayer(): void { ).to.equal(testValue); }); - it("Set and has", function(): void { + it("Set and has", function (): void { const ls = new LayeredStorage<0, KV, keyof KV>(); ls.global.set(0, "test.value", testValue); @@ -36,7 +36,7 @@ export function singleLayer(): void { ).to.be.true; }); - it("Set, delete and get", function(): void { + it("Set, delete and get", function (): void { const ls = new LayeredStorage<0, KV, keyof KV>(); expect( @@ -57,7 +57,7 @@ export function singleLayer(): void { ).to.be.undefined; }); - it("Set, delete and has", function(): void { + it("Set, delete and has", function (): void { const ls = new LayeredStorage<0, KV, keyof KV>(); expect( @@ -78,10 +78,10 @@ export function singleLayer(): void { ).to.be.false; }); - describe("Invalid layer names", function(): void { + describe("Invalid layer names", function (): void { [undefined, null, "string", true, false, {}].forEach( (layer: any): void => { - it("" + layer, function(): void { + it("" + layer, function (): void { const ls = new LayeredStorage<0, KV, keyof KV>(); expect( diff --git a/test/layered-storage/validation.ts b/test/layered-storage/validation.ts index 3c2e21a84..a3b80a770 100644 --- a/test/layered-storage/validation.ts +++ b/test/layered-storage/validation.ts @@ -14,7 +14,7 @@ interface KV { * Test that values can be set and retrieved from single global layer. */ export function validation(): void { - describe("Validation", function(): void { + describe("Validation", function (): void { [ // No handler. ["Default", null, null] as const, @@ -26,10 +26,10 @@ export function validation(): void { TypeError, (key: string, value: unknown, message: string): void => { throw new TypeError(`${key}: ${value} (${message})`); - } - ] as const + }, + ] as const, ].forEach(([name, throws, handler]): void => { - describe(name, function(): void { + describe(name, function (): void { [ [false, "test.boolean", 77] as const, [false, "test.fail", null] as const, @@ -41,9 +41,9 @@ export function validation(): void { [true, "test.number", 3.5] as const, [true, "test.number", 77] as const, [true, "test.pass", null] as const, - [true, "test.string", "test"] as const + [true, "test.string", "test"] as const, ].forEach(([valid, key, value]): void => { - it(`${key}: ${value}`, function(): void { + it(`${key}: ${value}`, function (): void { const ls = new LayeredStorage<0, KV, keyof KV>(); // Add handler. @@ -54,10 +54,10 @@ export function validation(): void { // Add validators. ls.setValidators("test.boolean", [ (value: unknown): true | string => - typeof value === "boolean" || "it's not valid" + typeof value === "boolean" || "it's not valid", ]); ls.setValidators("test.fail", [ - (): true | string => false || "it's not valid" + (): true | string => false || "it's not valid", ]); ls.setValidators("test.integer", [ // This tests multiple validators. @@ -65,16 +65,16 @@ export function validation(): void { typeof value === "number" || "it's not valid", (value: unknown): true | string => (typeof value === "number" && value % 1 === 0) || - "it's not valid" + "it's not valid", ]); ls.setValidators("test.number", [ (value: unknown): true | string => - typeof value === "number" || "it's not valid" + typeof value === "number" || "it's not valid", ]); ls.setValidators("test.pass", [(): true | string => true]); ls.setValidators("test.string", [ (value: unknown): true | string => - typeof value === "string" || "it's not valid" + typeof value === "string" || "it's not valid", ]); if (valid) { @@ -108,12 +108,12 @@ export function validation(): void { }); }); - it("Setting validators twice", function(): void { + it("Setting validators twice", function (): void { const ls = new LayeredStorage<0, KV, keyof KV>(); expect((): void => { ls.setValidators("test.fail", [ - (): true | string => false || "it's not valid" + (): true | string => false || "it's not valid", ]); ls.setValidators("test.fail", [(): true | string => true]); }, "Setting validators repeatedly without replace shoudn't be allowed.").to.throw(); From 28a1240ef0a01bb7bd39174669b7ad01b66d991f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Sun, 24 May 2020 15:23:09 +0200 Subject: [PATCH 34/48] style: fix typo in config --- .eslintrc.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.eslintrc.js b/.eslintrc.js index dda980cbb..3330a6beb 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -85,7 +85,7 @@ module.exports = { files: ["test/**/*.ts"], rules: { // This is useful to ignore private property access in a test. - "@typescript-eslint/ban-ts-ignore": "off", + "@typescript-eslint/ban-ts-comment": "off", }, }, ], From 1153f4a972ec12b8e4bf0161f71d4f30b5d447fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Sun, 24 May 2020 15:32:40 +0200 Subject: [PATCH 35/48] chore: restore package* from master --- package-lock.json | 8398 +++++++++++++++++++++++++-------------------- package.json | 104 +- 2 files changed, 4727 insertions(+), 3775 deletions(-) diff --git a/package-lock.json b/package-lock.json index f16da0632..aaaf6c9cf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2254,271 +2254,6 @@ "lazy-ass": "1.6.0" } }, - "@commitlint/cli": { - "version": "8.3.5", - "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-8.3.5.tgz", - "integrity": "sha512-6+L0vbw55UEdht71pgWOE55SRgb+8OHcEwGDB234VlIBFGK9P2QOBU7MHiYJ5cjdjCQ0rReNrGjOHmJ99jwf0w==", - "dev": true, - "requires": { - "@commitlint/format": "^8.3.4", - "@commitlint/lint": "^8.3.5", - "@commitlint/load": "^8.3.5", - "@commitlint/read": "^8.3.4", - "babel-polyfill": "6.26.0", - "chalk": "2.4.2", - "get-stdin": "7.0.0", - "lodash": "4.17.15", - "meow": "5.0.0", - "resolve-from": "5.0.0", - "resolve-global": "1.0.0" - }, - "dependencies": { - "get-stdin": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz", - "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==", - "dev": true - }, - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } - } - }, - "@commitlint/config-conventional": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-8.3.4.tgz", - "integrity": "sha512-w0Yc5+aVAjZgjYqx29igBOnVCj8O22gy3Vo6Fyp7PwoS7+AYS1x3sN7IBq6i7Ae15Mv5P+rEx1pkxXo5zOMe4g==", - "dev": true, - "requires": { - "conventional-changelog-conventionalcommits": "4.2.1" - } - }, - "@commitlint/ensure": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-8.3.4.tgz", - "integrity": "sha512-8NW77VxviLhD16O3EUd02lApMFnrHexq10YS4F4NftNoErKbKaJ0YYedktk2boKrtNRf/gQHY/Qf65edPx4ipw==", - "dev": true, - "requires": { - "lodash": "4.17.15" - }, - "dependencies": { - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true - } - } - }, - "@commitlint/execute-rule": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-8.3.4.tgz", - "integrity": "sha512-f4HigYjeIBn9f7OuNv5zh2y5vWaAhNFrfeul8CRJDy82l3Y+09lxOTGxfF3uMXKrZq4LmuK6qvvRCZ8mUrVvzQ==", - "dev": true - }, - "@commitlint/format": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-8.3.4.tgz", - "integrity": "sha512-809wlQ/ND6CLZON+w2Rb3YM2TLNDfU2xyyqpZeqzf2reJNpySMSUAeaO/fNDJSOKIsOsR3bI01rGu6hv28k+Nw==", - "dev": true, - "requires": { - "chalk": "^2.0.1" - } - }, - "@commitlint/is-ignored": { - "version": "8.3.5", - "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-8.3.5.tgz", - "integrity": "sha512-Zo+8a6gJLFDTqyNRx53wQi/XTiz8mncvmWf/4oRG+6WRcBfjSSHY7KPVj5Y6UaLy2EgZ0WQ2Tt6RdTDeQiQplA==", - "dev": true, - "requires": { - "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 - } - } - }, - "@commitlint/lint": { - "version": "8.3.5", - "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-8.3.5.tgz", - "integrity": "sha512-02AkI0a6PU6rzqUvuDkSi6rDQ2hUgkq9GpmdJqfai5bDbxx2939mK4ZO+7apbIh4H6Pae7EpYi7ffxuJgm+3hQ==", - "dev": true, - "requires": { - "@commitlint/is-ignored": "^8.3.5", - "@commitlint/parse": "^8.3.4", - "@commitlint/rules": "^8.3.4", - "babel-runtime": "^6.23.0", - "lodash": "4.17.15" - }, - "dependencies": { - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true - } - } - }, - "@commitlint/load": { - "version": "8.3.5", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-8.3.5.tgz", - "integrity": "sha512-poF7R1CtQvIXRmVIe63FjSQmN9KDqjRtU5A6hxqXBga87yB2VUJzic85TV6PcQc+wStk52cjrMI+g0zFx+Zxrw==", - "dev": true, - "requires": { - "@commitlint/execute-rule": "^8.3.4", - "@commitlint/resolve-extends": "^8.3.5", - "babel-runtime": "^6.23.0", - "chalk": "2.4.2", - "cosmiconfig": "^5.2.0", - "lodash": "4.17.15", - "resolve-from": "^5.0.0" - }, - "dependencies": { - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } - } - }, - "@commitlint/message": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-8.3.4.tgz", - "integrity": "sha512-nEj5tknoOKXqBsaQtCtgPcsAaf5VCg3+fWhss4Vmtq40633xLq0irkdDdMEsYIx8rGR0XPBTukqzln9kAWCkcA==", - "dev": true - }, - "@commitlint/parse": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-8.3.4.tgz", - "integrity": "sha512-b3uQvpUQWC20EBfKSfMRnyx5Wc4Cn778bVeVOFErF/cXQK725L1bYFvPnEjQO/GT8yGVzq2wtLaoEqjm1NJ/Bw==", - "dev": true, - "requires": { - "conventional-changelog-angular": "^1.3.3", - "conventional-commits-parser": "^3.0.0", - "lodash": "^4.17.11" - } - }, - "@commitlint/read": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-8.3.4.tgz", - "integrity": "sha512-FKv1kHPrvcAG5j+OSbd41IWexsbLhfIXpxVC/YwQZO+FR0EHmygxQNYs66r+GnhD1EfYJYM4WQIqd5bJRx6OIw==", - "dev": true, - "requires": { - "@commitlint/top-level": "^8.3.4", - "@marionebl/sander": "^0.6.0", - "babel-runtime": "^6.23.0", - "git-raw-commits": "^2.0.0" - } - }, - "@commitlint/resolve-extends": { - "version": "8.3.5", - "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-8.3.5.tgz", - "integrity": "sha512-nHhFAK29qiXNe6oH6uG5wqBnCR+BQnxlBW/q5fjtxIaQALgfoNLHwLS9exzbIRFqwJckpR6yMCfgMbmbAOtklQ==", - "dev": true, - "requires": { - "import-fresh": "^3.0.0", - "lodash": "4.17.15", - "resolve-from": "^5.0.0", - "resolve-global": "^1.0.0" - }, - "dependencies": { - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } - } - }, - "@commitlint/rules": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-8.3.4.tgz", - "integrity": "sha512-xuC9dlqD5xgAoDFgnbs578cJySvwOSkMLQyZADb1xD5n7BNcUJfP8WjT9W1Aw8K3Wf8+Ym/ysr9FZHXInLeaRg==", - "dev": true, - "requires": { - "@commitlint/ensure": "^8.3.4", - "@commitlint/message": "^8.3.4", - "@commitlint/to-lines": "^8.3.4", - "babel-runtime": "^6.23.0" - } - }, - "@commitlint/to-lines": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-8.3.4.tgz", - "integrity": "sha512-5AvcdwRsMIVq0lrzXTwpbbG5fKRTWcHkhn/hCXJJ9pm1JidsnidS1y0RGkb3O50TEHGewhXwNoavxW9VToscUA==", - "dev": true - }, - "@commitlint/top-level": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-8.3.4.tgz", - "integrity": "sha512-nOaeLBbAqSZNpKgEtO6NAxmui1G8ZvLG+0wb4rvv6mWhPDzK1GNZkCd8FUZPahCoJ1iHDoatw7F8BbJLg4nDjg==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - } - } - }, "@istanbuljs/load-nyc-config": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.0.0.tgz", @@ -2930,28 +2665,6 @@ "regenerator-runtime": "^0.13.3" } }, - "@marionebl/sander": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/@marionebl/sander/-/sander-0.6.1.tgz", - "integrity": "sha1-GViWWHTyS8Ub5Ih1/rUNZC/EH3s=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.3", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.2" - }, - "dependencies": { - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, "@microsoft/tsdoc": { "version": "0.12.20", "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.12.20.tgz", @@ -3008,12 +2721,26 @@ } }, "@octokit/auth-token": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.1.tgz", - "integrity": "sha512-NB81O5h39KfHYGtgfWr2booRxp2bWOJoqbWwbyUg2hw6h35ArWYlAST5B3XwAkbdcx13yt84hFXyFP5X0QToWA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.0.tgz", + "integrity": "sha512-eoOVMjILna7FVQf96iWc3+ZtE/ZT6y8ob8ZzcqKY1ibSQCnu4O/B7pJvzMx5cyZ/RjAff6DAdEb0O0Cjcxidkg==", + "dev": true, + "requires": { + "@octokit/types": "^2.0.0" + } + }, + "@octokit/core": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-2.5.0.tgz", + "integrity": "sha512-uvzmkemQrBgD8xuGbjhxzJN1darJk9L2cS+M99cHrDG2jlSVpxNJVhoV86cXdYBqdHCc9Z995uLCczaaHIYA6Q==", "dev": true, "requires": { - "@octokit/types": "^4.0.1" + "@octokit/auth-token": "^2.4.0", + "@octokit/graphql": "^4.3.1", + "@octokit/request": "^5.4.0", + "@octokit/types": "^2.0.0", + "before-after-hook": "^2.1.0", + "universal-user-agent": "^5.0.0" } }, "@octokit/endpoint": { @@ -3025,36 +2752,23 @@ "@octokit/types": "^2.11.1", "is-plain-object": "^3.0.0", "universal-user-agent": "^5.0.0" + } + }, + "@octokit/graphql": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.3.1.tgz", + "integrity": "sha512-hCdTjfvrK+ilU2keAdqNBWOk+gm1kai1ZcdjRfB30oA3/T6n53UVJb7w0L5cR3/rhU91xT3HSqCd+qbvH06yxA==", + "dev": true, + "requires": { + "@octokit/request": "^5.3.0", + "@octokit/types": "^2.0.0", + "universal-user-agent": "^4.0.0" }, "dependencies": { - "@octokit/types": { - "version": "2.16.2", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.16.2.tgz", - "integrity": "sha512-O75k56TYvJ8WpAakWwYRN8Bgu60KrmX0z1KqFp1kNiFNkgW+JW+9EBKZ+S33PU6SLvbihqd+3drvPxKK68Ee8Q==", - "dev": true, - "requires": { - "@types/node": ">= 8" - } - }, - "is-plain-object": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.0.tgz", - "integrity": "sha512-tZIpofR+P05k8Aocp7UI/2UTa9lTJSebCXpFFoR9aibpokDj/uXBsJ8luUu0tTVYKkMU6URDUuOfJZ7koewXvg==", - "dev": true, - "requires": { - "isobject": "^4.0.0" - } - }, - "isobject": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-4.0.0.tgz", - "integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==", - "dev": true - }, "universal-user-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-5.0.0.tgz", - "integrity": "sha512-B5TPtzZleXyPrUMKCpEHFmVhMN6EhmJYjG5PQna9s7mXeSqGTLap4OpqLl5FCEFUI3UBmllkETwKf/db66Y54Q==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-4.0.1.tgz", + "integrity": "sha512-LnST3ebHwVL2aNe4mejI9IQh2HfZ1RLo8Io2HugSif8ekzD1TlWpHpColOB/eh8JHMLkGH3Akqf040I+4ylNxg==", "dev": true, "requires": { "os-name": "^3.1.0" @@ -3063,23 +2777,12 @@ } }, "@octokit/plugin-paginate-rest": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-1.1.2.tgz", - "integrity": "sha512-jbsSoi5Q1pj63sC16XIUboklNw+8tL9VOnJsWycWYR78TKss5PVpIPb1TUUcMQ+bBh7cY579cVAWmf5qG+dw+Q==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.1.0.tgz", + "integrity": "sha512-7+/7urDH8cy6DmTwkewysf7/Or9dFtwZK7aQOc/IImjyeHJy+C8CEKOPo7L5Qb+66HyAr/4p/zV76LMVMuiRtA==", "dev": true, "requires": { - "@octokit/types": "^2.0.1" - }, - "dependencies": { - "@octokit/types": { - "version": "2.16.2", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.16.2.tgz", - "integrity": "sha512-O75k56TYvJ8WpAakWwYRN8Bgu60KrmX0z1KqFp1kNiFNkgW+JW+9EBKZ+S33PU6SLvbihqd+3drvPxKK68Ee8Q==", - "dev": true, - "requires": { - "@types/node": ">= 8" - } - } + "@octokit/types": "^2.9.0" } }, "@octokit/plugin-request-log": { @@ -3089,30 +2792,19 @@ "dev": true }, "@octokit/plugin-rest-endpoint-methods": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-2.4.0.tgz", - "integrity": "sha512-EZi/AWhtkdfAYi01obpX0DF7U6b1VRr30QNQ5xSFPITMdLSfhcBqjamE3F+sKcxPbD7eZuMHu3Qkk2V+JGxBDQ==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-3.7.1.tgz", + "integrity": "sha512-YOlcE3bbk2ohaOVdRj9ww7AUYfmnS9hwJJGSj3/rFlNfMGOId4G8dLlhghXpdNSn05H0FRoI94UlFUKnn30Cyw==", "dev": true, "requires": { - "@octokit/types": "^2.0.1", + "@octokit/types": "^2.11.1", "deprecation": "^2.3.1" - }, - "dependencies": { - "@octokit/types": { - "version": "2.16.2", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.16.2.tgz", - "integrity": "sha512-O75k56TYvJ8WpAakWwYRN8Bgu60KrmX0z1KqFp1kNiFNkgW+JW+9EBKZ+S33PU6SLvbihqd+3drvPxKK68Ee8Q==", - "dev": true, - "requires": { - "@types/node": ">= 8" - } - } } }, "@octokit/request": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.3.tgz", - "integrity": "sha512-RtqMzF3mhqxmWoqVD84x2gdtbqn2inTBU/HPkWf5u0R5r7fBTaLPAcCBgukeI2gjTwD9ChL9Cu0MlTBs7B/tSw==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.2.tgz", + "integrity": "sha512-zKdnGuQ2TQ2vFk9VU8awFT4+EYf92Z/v3OlzRaSh4RIP0H6cvW1BFPXq4XYvNez+TPQjqN+0uSkCYnMFFhcFrw==", "dev": true, "requires": { "@octokit/endpoint": "^6.0.1", @@ -3123,118 +2815,132 @@ "node-fetch": "^2.3.0", "once": "^1.4.0", "universal-user-agent": "^5.0.0" - }, - "dependencies": { - "@octokit/request-error": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.0.1.tgz", - "integrity": "sha512-5lqBDJ9/TOehK82VvomQ6zFiZjPeSom8fLkFVLuYL3sKiIb5RB8iN/lenLkY7oBmyQcGP7FBMGiIZTO8jufaRQ==", - "dev": true, - "requires": { - "@octokit/types": "^4.0.1", - "deprecation": "^2.0.0", - "once": "^1.4.0" - }, - "dependencies": { - "@octokit/types": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-4.0.1.tgz", - "integrity": "sha512-Ho6h7w2h9y8RRE8r656hIj1oiSbwbIHJGF5r9G5FOwS2VdDPq8QLGvsG4x6pKHpvyGK7j+43sAc2cJKMiFoIJw==", - "dev": true, - "requires": { - "@types/node": ">= 8" - } - } - } - }, - "@octokit/types": { - "version": "2.16.2", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.16.2.tgz", - "integrity": "sha512-O75k56TYvJ8WpAakWwYRN8Bgu60KrmX0z1KqFp1kNiFNkgW+JW+9EBKZ+S33PU6SLvbihqd+3drvPxKK68Ee8Q==", - "dev": true, - "requires": { - "@types/node": ">= 8" - } - }, - "is-plain-object": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.0.tgz", - "integrity": "sha512-tZIpofR+P05k8Aocp7UI/2UTa9lTJSebCXpFFoR9aibpokDj/uXBsJ8luUu0tTVYKkMU6URDUuOfJZ7koewXvg==", - "dev": true, - "requires": { - "isobject": "^4.0.0" - } - }, - "isobject": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-4.0.0.tgz", - "integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==", - "dev": true - }, - "universal-user-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-5.0.0.tgz", - "integrity": "sha512-B5TPtzZleXyPrUMKCpEHFmVhMN6EhmJYjG5PQna9s7mXeSqGTLap4OpqLl5FCEFUI3UBmllkETwKf/db66Y54Q==", - "dev": true, - "requires": { - "os-name": "^3.1.0" - } - } } }, "@octokit/request-error": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-1.2.1.tgz", - "integrity": "sha512-+6yDyk1EES6WK+l3viRDElw96MvwfJxCt45GvmjDUKWjYIb3PJZQkq3i46TwGwoPD4h8NmTrENmtyA1FwbmhRA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.0.0.tgz", + "integrity": "sha512-rtYicB4Absc60rUv74Rjpzek84UbVHGHJRu4fNVlZ1mCcyUPPuzFfG9Rn6sjHrd95DEsmjSt1Axlc699ZlbDkw==", "dev": true, "requires": { "@octokit/types": "^2.0.0", "deprecation": "^2.0.0", "once": "^1.4.0" + } + }, + "@octokit/rest": { + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-17.5.1.tgz", + "integrity": "sha512-0rGY7eo0cw8FYX7jAtUgfy3j+05zhs9JvkPFegx00HAaayodM1ixlHhCOB5yirGbsVOxbRIWVkvKc2yY9367gg==", + "dev": true, + "requires": { + "@octokit/core": "^2.4.3", + "@octokit/plugin-paginate-rest": "^2.1.0", + "@octokit/plugin-request-log": "^1.0.0", + "@octokit/plugin-rest-endpoint-methods": "3.7.1" + } + }, + "@octokit/types": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.11.1.tgz", + "integrity": "sha512-QaLoLkmFdfoNbk3eOzPv7vKrUY0nRJIYmZDoz/pTer4ICpqu80aSQTVHnnUxEFuURCiidig76CcxUOYC/bY3RQ==", + "dev": true, + "requires": { + "@types/node": ">= 8" + } + }, + "@rollup/plugin-commonjs": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-12.0.0.tgz", + "integrity": "sha512-8+mDQt1QUmN+4Y9D3yCG8AJNewuTSLYPJVzKKUZ+lGeQrI+bV12Tc5HCyt2WdlnG6ihIL/DPbKRJlB40DX40mw==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.0.8", + "commondir": "^1.0.1", + "estree-walker": "^1.0.1", + "glob": "^7.1.2", + "is-reference": "^1.1.2", + "magic-string": "^0.25.2", + "resolve": "^1.11.0" + }, + "dependencies": { + "estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true + } + } + }, + "@rollup/plugin-json": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.0.3.tgz", + "integrity": "sha512-QMUT0HZNf4CX17LMdwaslzlYHUKTYGuuk34yYIgZrNdu+pMEfqMS55gck7HEeHBKXHM4cz5Dg1OVwythDdbbuQ==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.0.8" + } + }, + "@rollup/plugin-node-resolve": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-8.0.0.tgz", + "integrity": "sha512-5poJCChrkVggXXND/sQ7yNqwjUNT4fP31gpRWCnSNnlXuUXTCMHT33xZrTGxgjm5Rl18MHj7iEzlCT8rYWwQSA==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.0.8", + "@types/resolve": "0.0.8", + "builtin-modules": "^3.1.0", + "deep-freeze": "^0.0.1", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.14.2" }, "dependencies": { - "@octokit/types": { - "version": "2.16.2", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.16.2.tgz", - "integrity": "sha512-O75k56TYvJ8WpAakWwYRN8Bgu60KrmX0z1KqFp1kNiFNkgW+JW+9EBKZ+S33PU6SLvbihqd+3drvPxKK68Ee8Q==", + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", "dev": true, "requires": { - "@types/node": ">= 8" + "path-parse": "^1.0.6" } } } }, - "@octokit/rest": { - "version": "16.43.1", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-16.43.1.tgz", - "integrity": "sha512-gfFKwRT/wFxq5qlNjnW2dh+qh74XgTQ2B179UX5K1HYCluioWj8Ndbgqw2PVqa1NnVJkGHp2ovMpVn/DImlmkw==", + "@rollup/plugin-strip": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-strip/-/plugin-strip-1.3.3.tgz", + "integrity": "sha512-jBZYNi9Wa5lSv8wXUepgqLFcv5PMJiP2VcWSIqjAzYOwZiQA09e3vwtar9EYHSYfIONyc1hG0IkSDz2VvGBZcA==", "dev": true, "requires": { - "@octokit/auth-token": "^2.4.0", - "@octokit/plugin-paginate-rest": "^1.1.1", - "@octokit/plugin-request-log": "^1.0.0", - "@octokit/plugin-rest-endpoint-methods": "2.4.0", - "@octokit/request": "^5.2.0", - "@octokit/request-error": "^1.0.2", - "atob-lite": "^2.0.0", - "before-after-hook": "^2.0.0", - "btoa-lite": "^1.0.0", - "deprecation": "^2.0.0", - "lodash.get": "^4.4.2", - "lodash.set": "^4.3.2", - "lodash.uniq": "^4.5.0", - "octokit-pagination-methods": "^1.1.0", - "once": "^1.4.0", - "universal-user-agent": "^4.0.0" + "@rollup/pluginutils": "^3.0.4", + "estree-walker": "^1.0.1", + "magic-string": "^0.25.5" + }, + "dependencies": { + "estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true + } } }, - "@octokit/types": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-4.0.1.tgz", - "integrity": "sha512-Ho6h7w2h9y8RRE8r656hIj1oiSbwbIHJGF5r9G5FOwS2VdDPq8QLGvsG4x6pKHpvyGK7j+43sAc2cJKMiFoIJw==", + "@rollup/pluginutils": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.0.8.tgz", + "integrity": "sha512-rYGeAc4sxcZ+kPG/Tw4/fwJODC3IXHYDH4qusdN/b6aLw5LPUbzpecYbEJh4sVQGPFJxd2dBU4kc1H3oy9/bnw==", "dev": true, "requires": { - "@types/node": ">= 8" + "estree-walker": "^1.0.1" + }, + "dependencies": { + "estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true + } } }, "@samverschueren/stream-to-observable": { @@ -3247,9 +2953,9 @@ } }, "@semantic-release/commit-analyzer": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-7.0.0.tgz", - "integrity": "sha512-t5wMGByv+SknjP2m3rhWN4vmXoQ16g5VFY8iC4/tcbLPvzxK+35xsTIeUsrVFZv3ymdgAQKIr5J3lKjhF/VZZQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-8.0.1.tgz", + "integrity": "sha512-5bJma/oB7B4MtwUkZC2Bf7O1MHfi4gWe4mA+MIQ3lsEV0b422Bvl1z5HRpplDnMLHH3EXMoRdEng6Ds5wUqA3A==", "dev": true, "requires": { "conventional-changelog-angular": "^5.0.0", @@ -3258,127 +2964,18 @@ "debug": "^4.0.0", "import-from": "^3.0.0", "lodash": "^4.17.4", - "micromatch": "^3.1.10" + "micromatch": "^4.0.2" }, "dependencies": { - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, "conventional-changelog-angular": { - "version": "5.0.10", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.10.tgz", - "integrity": "sha512-k7RPPRs0vp8+BtPsM9uDxRl6KcgqtCJmzRD1wRtgqmhQ96g8ifBGo9O/TZBG23jqlXS/rg8BKRDELxfnQQGiaA==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.6.tgz", + "integrity": "sha512-QDEmLa+7qdhVIv8sFZfVxU1VSyVvnXPsxq8Vam49mKUcO1Z8VTLEJk9uI21uiJUsnmm0I4Hrsdc9TgkOQo9WSA==", "dev": true, "requires": { "compare-func": "^1.3.1", "q": "^1.5.1" } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } } } }, @@ -3389,56 +2986,134 @@ "dev": true }, "@semantic-release/github": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-6.0.2.tgz", - "integrity": "sha512-tBE8duwyOB+FXetHucl5wCOlZhNPHN1ipQENxN6roCz22AYYRLRaVYNPjo78F+KNJpb+Gy8DdudH78Qc8VhKtQ==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-7.0.5.tgz", + "integrity": "sha512-1nJCMeomspRIXKiFO3VXtkUMbIBEreYLFNBdWoLjvlUNcEK0/pEbupEZJA3XHfJuSzv43u3OLpPhF/JBrMuv+A==", "dev": true, "requires": { - "@octokit/rest": "^16.27.0", + "@octokit/rest": "^17.0.0", "@semantic-release/error": "^2.2.0", "aggregate-error": "^3.0.0", "bottleneck": "^2.18.1", "debug": "^4.0.0", "dir-glob": "^3.0.0", - "fs-extra": "^8.0.0", - "globby": "^10.0.0", + "fs-extra": "^9.0.0", + "globby": "^11.0.0", "http-proxy-agent": "^4.0.0", - "https-proxy-agent": "^4.0.0", + "https-proxy-agent": "^5.0.0", "issue-parser": "^6.0.0", "lodash": "^4.17.4", "mime": "^2.4.3", "p-filter": "^2.0.0", "p-retry": "^4.0.0", "url-join": "^4.0.0" + }, + "dependencies": { + "fs-extra": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.0.tgz", + "integrity": "sha512-pmEYSk3vYsG/bF651KPUXZ+hvjpgWYw/Gc7W9NFUe3ZVLczKKWIij3IKpOrQcdw4TILtibFslZ0UmR8Vvzig4g==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^1.0.0" + } + }, + "globby": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.0.tgz", + "integrity": "sha512-iuehFnR3xu5wBBtm4xi0dMe92Ob87ufyu/dHwpDYfbcpYpIbrO5OnS8M1vWvrBhSGEJ3/Ecj7gnX76P8YxpPEg==", + "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" + } + }, + "ignore": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz", + "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==", + "dev": true + }, + "jsonfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz", + "integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^1.0.0" + } + }, + "universalify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", + "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==", + "dev": true + } } }, "@semantic-release/npm": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-6.0.0.tgz", - "integrity": "sha512-aqODzbtWpVHO/keinbBMnZEaN/TkdwQvyDWcT0oNbKFpZwLjNjn+QVItoLekF62FLlXXziu2y6V4wnl9FDnujA==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-7.0.5.tgz", + "integrity": "sha512-D+oEmsx9aHE1q806NFQwSC9KdBO8ri/VO99eEz0wWbX2jyLqVyWr7t0IjKC8aSnkkQswg/4KN/ZjfF6iz1XOpw==", "dev": true, "requires": { "@semantic-release/error": "^2.2.0", "aggregate-error": "^3.0.0", "execa": "^4.0.0", - "fs-extra": "^8.0.0", + "fs-extra": "^9.0.0", "lodash": "^4.17.15", "nerf-dart": "^1.0.0", - "normalize-url": "^4.0.0", + "normalize-url": "^5.0.0", "npm": "^6.10.3", "rc": "^1.2.8", "read-pkg": "^5.0.0", "registry-auth-token": "^4.0.0", - "semver": "^6.3.0", - "tempy": "^0.3.0" + "semver": "^7.1.2", + "tempy": "^0.5.0" }, "dependencies": { + "fs-extra": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.0.tgz", + "integrity": "sha512-pmEYSk3vYsG/bF651KPUXZ+hvjpgWYw/Gc7W9NFUe3ZVLczKKWIij3IKpOrQcdw4TILtibFslZ0UmR8Vvzig4g==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^1.0.0" + } + }, + "jsonfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz", + "integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^1.0.0" + } + }, "lodash": { "version": "4.17.15", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "dev": true }, + "normalize-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-5.0.0.tgz", + "integrity": "sha512-bAEm2fx8Dq/a35Z6PIRkkBBJvR56BbEJvhpNtvCZ4W9FyORSna77fn+xtYFjqk5JpBS+fMnAOG/wFgkQBmB7hw==", + "dev": true + }, "parse-json": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", @@ -3464,9 +3139,9 @@ } }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", "dev": true }, "type-fest": { @@ -3474,13 +3149,19 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", "dev": true + }, + "universalify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", + "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==", + "dev": true } } }, "@semantic-release/release-notes-generator": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-7.3.5.tgz", - "integrity": "sha512-LGjgPBGjjmjap/76O0Md3wc04Y7IlLnzZceLsAkcYRwGQdRPTTFUJKqDQTuieWTs7zfHzQoZqsqPfFxEN+g2+Q==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-9.0.1.tgz", + "integrity": "sha512-bOoTiH6SiiR0x2uywSNR7uZcRDl22IpZhj+Q5Bn0v+98MFtOMhCxFhbrKQjhbYoZw7vps1mvMRmFkp/g6R9cvQ==", "dev": true, "requires": { "conventional-changelog-angular": "^5.0.0", @@ -3496,227 +3177,149 @@ }, "dependencies": { "conventional-changelog-angular": { - "version": "5.0.10", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.10.tgz", - "integrity": "sha512-k7RPPRs0vp8+BtPsM9uDxRl6KcgqtCJmzRD1wRtgqmhQ96g8ifBGo9O/TZBG23jqlXS/rg8BKRDELxfnQQGiaA==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.6.tgz", + "integrity": "sha512-QDEmLa+7qdhVIv8sFZfVxU1VSyVvnXPsxq8Vam49mKUcO1Z8VTLEJk9uI21uiJUsnmm0I4Hrsdc9TgkOQo9WSA==", "dev": true, "requires": { "compare-func": "^1.3.1", "q": "^1.5.1" } - } - } - }, - "@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", - "dev": true - }, - "@sinonjs/commons": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.0.tgz", - "integrity": "sha512-wEj54PfsZ5jGSwMX68G8ZXFawcSglQSXqCftWX3ec8MDUzQdHgcKvw97awHbY0efQEL5iKUOAmmVtoYgmrSG4Q==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "@sinonjs/formatio": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-4.0.1.tgz", - "integrity": "sha512-asIdlLFrla/WZybhm0C8eEzaDNNrzymiTqHMeJl6zPW2881l3uuVRpm0QlRQEjqYWv6CcKMGYME3LbrLJsORBw==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1", - "@sinonjs/samsam": "^4.2.0" - } - }, - "@sinonjs/samsam": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-4.2.2.tgz", - "integrity": "sha512-z9o4LZUzSD9Hl22zV38aXNykgFeVj8acqfFabCY6FY83n/6s/XwNJyYYldz6/9lBJanpno9h+oL6HTISkviweA==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.6.0", - "lodash.get": "^4.4.2", - "type-detect": "^4.0.8" - } - }, - "@sinonjs/text-encoding": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", - "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", - "dev": true - }, - "@stryker-mutator/api": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@stryker-mutator/api/-/api-2.5.0.tgz", - "integrity": "sha512-6z2AZeGcI+ZzqZEBX6h+vWt11uBzLfAg24kV0b/CJZ69zNELRLkjJnLaE4aU1o5uE6OyFGKJJ0OVxtZrnvZSuQ==", - "dev": true, - "requires": { - "mutation-testing-report-schema": "^1.1.0", - "tslib": "~1.10.0" - } - }, - "@stryker-mutator/babel-transpiler": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@stryker-mutator/babel-transpiler/-/babel-transpiler-2.5.0.tgz", - "integrity": "sha512-vIe0Jlw30q3zGQPYuoW+vqMiTE/nxvjUCizRk8oJwhgOMYeZcoVVw4eKxa1PdydZFPXrU9McOZcJ3O+y/JQyew==", - "dev": true, - "requires": { - "@stryker-mutator/api": "^2.5.0", - "@stryker-mutator/util": "^2.5.0", - "minimatch": "~3.0.4" - } - }, - "@stryker-mutator/core": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@stryker-mutator/core/-/core-2.5.0.tgz", - "integrity": "sha512-pafJ0FSQl5dJAte8/CGq+/X/kfVGRtLuf3M4aJ4YeHW+2fFOpCYhXOsEuJ66i9SVd2Ia9ItCKPk0CaOFSFE02g==", - "dev": true, - "requires": { - "@stryker-mutator/api": "^2.5.0", - "@stryker-mutator/util": "^2.5.0", - "chalk": "~3.0.0", - "commander": "~4.1.0", - "get-port": "~5.0.0", - "glob": "~7.1.2", - "inquirer": "~7.0.0", - "istanbul-lib-instrument": "~3.3.0", - "lodash.flatmap": "^4.5.0", - "lodash.groupby": "^4.6.0", - "log4js": "~6.1.0", - "mkdirp": "~0.5.1", - "mutation-testing-metrics": "^1.1.1", - "progress": "~2.0.0", - "rimraf": "~3.0.0", - "rxjs": "~6.5.1", - "source-map": "~0.7.3", - "surrial": "~1.0.0", - "tree-kill": "~1.2.0", - "tslib": "~1.10.0", - "typed-inject": "~2.1.1", - "typed-rest-client": "~1.7.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" } }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "p-locate": "^4.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==", + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "requires": { - "color-name": "~1.1.4" + "p-limit": "^2.2.0" } }, - "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 + "parse-json": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", + "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1", + "lines-and-columns": "^1.1.6" + } }, - "has-flag": { + "path-exists": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true }, - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true + } + } }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", "dev": true, "requires": { - "has-flag": "^4.0.0" + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" } + }, + "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 } } }, - "@stryker-mutator/html-reporter": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@stryker-mutator/html-reporter/-/html-reporter-2.5.0.tgz", - "integrity": "sha512-QB83lsYnaG7AtaMCpcSigw4Db0TqaThDonA7XrlOC6aaAyQIf+4/eyp7wMrFBELSs4TFcQFtI3+LBZuKZTAkXw==", + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "dev": true + }, + "@sinonjs/commons": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.7.2.tgz", + "integrity": "sha512-+DUO6pnp3udV/v2VfUWgaY5BIE1IfT7lLfeDzPVeMT1XKkaAp9LgSI9x5RtrFQoZ9Oi0PgXQQHPaoKu7dCjVxw==", "dev": true, "requires": { - "@stryker-mutator/api": "^2.5.0", - "@stryker-mutator/util": "^2.5.0", - "file-url": "~3.0.0", - "mkdirp": "~0.5.1", - "mutation-testing-elements": "^1.0.2", - "rimraf": "~3.0.0" + "type-detect": "4.0.8" } }, - "@stryker-mutator/mocha-framework": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@stryker-mutator/mocha-framework/-/mocha-framework-2.5.0.tgz", - "integrity": "sha512-Hg1R1v1exkuYF9AJZJU7hmhDyM26LQqIe2SkIVGBAnxbHHAsPs17zmKqFrry3wHXesHVCmGXDKnuRtqK2u/svw==", + "@sinonjs/fake-timers": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", + "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", "dev": true, "requires": { - "@stryker-mutator/api": "^2.5.0" + "@sinonjs/commons": "^1.7.0" } }, - "@stryker-mutator/mocha-runner": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@stryker-mutator/mocha-runner/-/mocha-runner-2.5.0.tgz", - "integrity": "sha512-pq4JpFfqiyYAEXo/7mz/BRr5b7c9MDCfAMSpBygncse22BQV329zc0V/xgDzkJ2hkNrFUL2I72N2FkwaLMPY3A==", + "@sinonjs/formatio": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-5.0.1.tgz", + "integrity": "sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==", "dev": true, "requires": { - "@stryker-mutator/api": "^2.5.0", - "multimatch": "~4.0.0", - "tslib": "~1.10.0" + "@sinonjs/commons": "^1", + "@sinonjs/samsam": "^5.0.2" } }, - "@stryker-mutator/typescript": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@stryker-mutator/typescript/-/typescript-2.5.0.tgz", - "integrity": "sha512-y7NrmkTdvoS+Ef+6K8Z1WBRmQ5+Fh66ThWayCJrGBzd0PbNZEcSmv72ZtaYdWbAFwS46lg2hzwPd+q6E63QgLw==", + "@sinonjs/samsam": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.0.3.tgz", + "integrity": "sha512-QucHkc2uMJ0pFGjJUDP3F9dq5dx8QIaqISl9QgwLOh6P9yv877uONPGXh/OH/0zmM3tW1JjuJltAZV2l7zU+uQ==", "dev": true, "requires": { - "@stryker-mutator/api": "^2.5.0", - "@stryker-mutator/util": "^2.5.0", - "lodash.flatmap": "~4.5.0", - "semver": "~6.3.0", - "tslib": "~1.10.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 - } + "@sinonjs/commons": "^1.6.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" } }, - "@stryker-mutator/util": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@stryker-mutator/util/-/util-2.5.0.tgz", - "integrity": "sha512-l3bTvN2YbhwPPO0F6WBbUkgY6NC/34/jxpVQGlw0rZn72MPuRQBJtrfAH7KFN0OBG4QmIA6PC6c4z0X5IaWfow==", + "@sinonjs/text-encoding": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", "dev": true }, "@szmarczak/http-timer": { @@ -3764,6 +3367,15 @@ "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", "dev": true }, + "@types/fs-extra": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.0.1.tgz", + "integrity": "sha512-J00cVDALmi/hJOYsunyT52Hva5TnJeKP5yd1r+mH/ZU0mbYZflR0Z5kw5kITtKTRYMhm1JMClOFYdHnQszEvqw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/glob": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", @@ -3794,9 +3406,9 @@ "dev": true }, "@types/mocha": { - "version": "5.2.7", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", - "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-7.0.2.tgz", + "integrity": "sha512-ZvO2tAcjmMi8V/5Z3JsyofMe3hasRcaw88cto5etSVMwVQfeivGAlEYmaQgceUSVYFofVjT+ioHsATjdWcFt1w==", "dev": true }, "@types/node": { @@ -3817,6 +3429,12 @@ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", "dev": true }, + "@types/q": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz", + "integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==", + "dev": true + }, "@types/resolve": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz", @@ -3833,51 +3451,69 @@ "dev": true }, "@types/sinon": { - "version": "7.5.2", - "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-7.5.2.tgz", - "integrity": "sha512-T+m89VdXj/eidZyejvmoP9jivXgBDdkOSBVQjU9kF349NEx10QdPNGxHeZUaj1IlJ32/ewdyXJjnJxyxJroYwg==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-9.0.4.tgz", + "integrity": "sha512-sJmb32asJZY6Z2u09bl0G2wglSxDlROlAejCjsnor+LzBMz17gu8IU7vKC/vWDnv9zEq2wqADHVXFjf4eE8Gdw==", + "dev": true, + "requires": { + "@types/sinonjs__fake-timers": "*" + } + }, + "@types/sinonjs__fake-timers": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.1.tgz", + "integrity": "sha512-yYezQwGWty8ziyYLdZjwxyMb0CZR49h8JALHGrxjQHWlqGgc8kLdHEgWrgL0uZ29DMvEVBDnHU2Wg36zKSIUtA==", "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "2.34.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.34.0.tgz", - "integrity": "sha512-4zY3Z88rEE99+CNvTbXSyovv2z9PNOVffTWD2W8QF5s2prBQtwN2zadqERcrHpcR7O/+KMI3fcTAmUUhK/iQcQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.0.0.tgz", + "integrity": "sha512-lcZ0M6jD4cqGccYOERKdMtg+VWpoq3NSnWVxpc/AwAy0zhkUYVioOUZmfNqiNH8/eBNGhCn6HXd6mKIGRgNc1Q==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "2.34.0", + "@typescript-eslint/experimental-utils": "3.0.0", "functional-red-black-tree": "^1.0.1", "regexpp": "^3.0.0", + "semver": "^7.3.2", "tsutils": "^3.17.1" + }, + "dependencies": { + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true + } } }, "@typescript-eslint/experimental-utils": { - "version": "2.34.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz", - "integrity": "sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-3.0.0.tgz", + "integrity": "sha512-BN0vmr9N79M9s2ctITtChRuP1+Dls0x/wlg0RXW1yQ7WJKPurg6X3Xirv61J2sjPif4F8SLsFMs5Nzte0WYoTQ==", "dev": true, "requires": { "@types/json-schema": "^7.0.3", - "@typescript-eslint/typescript-estree": "2.34.0", + "@typescript-eslint/typescript-estree": "3.0.0", "eslint-scope": "^5.0.0", "eslint-utils": "^2.0.0" } }, "@typescript-eslint/parser": { - "version": "2.34.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.34.0.tgz", - "integrity": "sha512-03ilO0ucSD0EPTw2X4PntSIRFtDPWjrVq7C3/Z3VQHRC7+13YB55rcJI3Jt+YgeHbjUdJPcPa7b23rXCBokuyA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-3.0.0.tgz", + "integrity": "sha512-8RRCA9KLxoFNO0mQlrLZA0reGPd/MsobxZS/yPFj+0/XgMdS8+mO8mF3BDj2ZYQj03rkayhSJtF1HAohQ3iylw==", "dev": true, "requires": { "@types/eslint-visitor-keys": "^1.0.0", - "@typescript-eslint/experimental-utils": "2.34.0", - "@typescript-eslint/typescript-estree": "2.34.0", + "@typescript-eslint/experimental-utils": "3.0.0", + "@typescript-eslint/typescript-estree": "3.0.0", "eslint-visitor-keys": "^1.1.0" } }, "@typescript-eslint/typescript-estree": { - "version": "2.34.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz", - "integrity": "sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-3.0.0.tgz", + "integrity": "sha512-nevQvHyNghsfLrrByzVIH4ZG3NROgJ8LZlfh3ddwPPH4CH7W4GAiSx5qu+xHuX5pWsq6q/eqMc1io840ZhAnUg==", "dev": true, "requires": { "debug": "^4.1.1", @@ -4000,6 +3636,12 @@ "uri-js": "^4.2.2" } }, + "alphanum-sort": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", + "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", + "dev": true + }, "ansi-align": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", @@ -4145,24 +3787,6 @@ "integrity": "sha1-oMoMvCmltz6Dbuvhy/bF4OTrgvk=", "dev": true }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true - }, "array-differ": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz", @@ -4221,12 +3845,6 @@ "integrity": "sha512-bdHxtev7FN6+MXI1YFW0Q8mQ8dTJc2S8AMfju+ZR77pbg2yAdVyDlwkaUI7Har0LyOMRFPHrJ9lYdyjZZswdlQ==", "dev": true }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, "arrify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", @@ -4296,12 +3914,6 @@ } } }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true - }, "astral-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", @@ -4335,16 +3947,10 @@ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", "dev": true }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true - }, - "atob-lite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/atob-lite/-/atob-lite-2.0.0.tgz", - "integrity": "sha1-D+9a1G8b16hQLGVyfwNn1e5D1pY=", + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", "dev": true }, "aws-sign2": { @@ -4359,6 +3965,16 @@ "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==", "dev": true }, + "babel-plugin-css-modules-transform": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/babel-plugin-css-modules-transform/-/babel-plugin-css-modules-transform-1.6.2.tgz", + "integrity": "sha512-zBsI54N5n979vfYpqFzQ6oRwEiVcmLH5REyaincNW+Ecl52nvRsQPYIbDcJzHePrXI20YSRUw6G/qbPwZZDgfg==", + "dev": true, + "requires": { + "css-modules-require-hook": "^4.0.6", + "mkdirp": "^0.5.1" + } + }, "babel-plugin-dynamic-import-node": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", @@ -4518,125 +4134,12 @@ } } }, - "babel-polyfill": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz", - "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=", - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "core-js": "^2.5.0", - "regenerator-runtime": "^0.10.5" - }, - "dependencies": { - "core-js": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", - "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==", - "dev": true - }, - "regenerator-runtime": { - "version": "0.10.5", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", - "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=", - "dev": true - } - } - }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "dev": true, - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - }, - "dependencies": { - "core-js": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", - "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==", - "dev": true - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", - "dev": true - } - } - }, - "backbone": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/backbone/-/backbone-1.4.0.tgz", - "integrity": "sha512-RLmDrRXkVdouTg38jcgHhyQ/2zjg7a8E6sz2zxfz21Hh17xDJYUHBZimVIt5fUyS8vbfpeSmTL3gUjTEvUV3qQ==", - "dev": true, - "requires": { - "underscore": ">=1.8.3" - } - }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, "base64-js": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", @@ -4658,6 +4161,12 @@ "integrity": "sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A==", "dev": true }, + "big.js": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", + "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", + "dev": true + }, "binary-extensions": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", @@ -4851,12 +4360,6 @@ "node-releases": "^1.1.50" } }, - "btoa-lite": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz", - "integrity": "sha1-M3dm2hWAEhD92VbCLpxokaudAzc=", - "dev": true - }, "buffer": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", @@ -4891,23 +4394,6 @@ "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==", "dev": true }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, "cacheable-request": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", @@ -5069,6 +4555,18 @@ "quick-lru": "^4.0.1" } }, + "caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, "caniuse-lite": { "version": "1.0.30001031", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001031.tgz", @@ -5226,29 +4724,6 @@ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", "dev": true }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, "clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -5277,65 +4752,96 @@ "dev": true, "requires": { "colors": "1.0.3" - }, - "dependencies": { - "colors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", - "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", - "dev": true - } } }, "cli-truncate": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", - "integrity": "sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", "dev": true, "requires": { - "slice-ansi": "0.0.4", - "string-width": "^1.0.1" + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" }, "dependencies": { "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", "dev": true }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", "dev": true, "requires": { - "number-is-nan": "^1.0.0" + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" } }, - "slice-ansi": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", - "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, + "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 + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, + "slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } + }, "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", "dev": true, "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" } }, "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "^5.0.0" } } } @@ -5397,6 +4903,12 @@ } } }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "dev": true + }, "clone-response": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", @@ -5406,20 +4918,25 @@ "mimic-response": "^1.0.0" } }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true + "coa": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", + "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", + "dev": true, + "requires": { + "@types/q": "^1.5.1", + "chalk": "^2.4.1", + "q": "^1.1.2" + } }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "color": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/color/-/color-3.1.2.tgz", + "integrity": "sha512-vXTJhHebByxZn3lDvDJYw4lR5+uB3vuoHsuYA5AKuxRVn5wzzIfQKGLBmgdVRHKTJYeK5rvJcHnrd0Li49CFpg==", "dev": true, "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" + "color-convert": "^1.9.1", + "color-string": "^1.5.2" } }, "color-convert": { @@ -5437,10 +4954,26 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, + "color-string": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", + "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", + "dev": true, + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "colorette": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.1.0.tgz", + "integrity": "sha512-6S062WDQUXi6hOfkO/sBPVwE5ASXY4G2+b4atvhJfSsuUUhIaUKlkjLe9692Ipyt5/a+IPF5aVTu3V5gvXq5cg==", + "dev": true + }, "colors": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz", - "integrity": "sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", "dev": true }, "combined-stream": { @@ -5453,9 +4986,9 @@ } }, "commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, "comment-parser": { @@ -5477,9 +5010,9 @@ "dev": true }, "compare-func": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-1.3.4.tgz", - "integrity": "sha512-sq2sWtrqKPkEXAC8tEJA1+BqAH9GbFkGBtUOqrUX57VSfwp8xyktctk+uLoRy5eccTdxzDcVIztlYDpKs3Jv1Q==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-1.3.2.tgz", + "integrity": "sha1-md0LpFfh+bxyKxLAjsM+6rMfpkg=", "dev": true, "requires": { "array-ify": "^1.0.0", @@ -5503,12 +5036,6 @@ "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==", "dev": true }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -5527,6 +5054,23 @@ "typedarray": "^0.0.6" } }, + "concat-with-sourcemaps": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz", + "integrity": "sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg==", + "dev": true, + "requires": { + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "configstore": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", @@ -5558,27 +5102,6 @@ } } }, - "conventional-changelog-angular": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-1.6.6.tgz", - "integrity": "sha512-suQnFSqCxRwyBxY68pYTsFkG0taIdinHLNEAX5ivtw8bCRnIgnpvcHmlR/yjUyZIrNPYAoXlY1WiEKWgSE4BNg==", - "dev": true, - "requires": { - "compare-func": "^1.3.1", - "q": "^1.5.1" - } - }, - "conventional-changelog-conventionalcommits": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.2.1.tgz", - "integrity": "sha512-vC02KucnkNNap+foDKFm7BVUSDAXktXrUJqGszUuYnt6T0J2azsbYz/w9TDc3VsrW2v6JOtiQWVcgZnporHr4Q==", - "dev": true, - "requires": { - "compare-func": "^1.3.1", - "lodash": "^4.2.1", - "q": "^1.5.1" - } - }, "conventional-changelog-writer": { "version": "4.0.16", "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.0.16.tgz", @@ -5597,11 +5120,15 @@ "through2": "^3.0.0" }, "dependencies": { - "camelcase": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.0.0.tgz", - "integrity": "sha512-8KMDF1Vz2gzOq54ONPJS65IvTUaB1cHJ2DMM7MbPmLZljDH1qpzzLsWdiN9pHh6qvkRVDTi/07+eNGch/oLU4w==", - "dev": true + "conventional-commits-filter": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.6.tgz", + "integrity": "sha512-4g+sw8+KA50/Qwzfr0hL5k5NWxqtrOVw4DDk3/h6L85a9Gz0/Eqp3oP+CWCNfesBvZZZEFHF7OTEbRe+yYSyKw==", + "dev": true, + "requires": { + "lodash.ismatch": "^4.4.0", + "modify-values": "^1.0.0" + } }, "lodash": { "version": "4.17.15", @@ -5609,45 +5136,27 @@ "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "dev": true }, - "meow": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/meow/-/meow-7.0.1.tgz", - "integrity": "sha512-tBKIQqVrAHqwit0vfuFPY3LlzJYkEOFyKa3bPgxzNl6q/RtN8KQ+ALYEASYuFayzSAsjlhXj/JZ10rH85Q6TUw==", - "dev": true, - "requires": { - "@types/minimist": "^1.2.0", - "arrify": "^2.0.1", - "camelcase": "^6.0.0", - "camelcase-keys": "^6.2.2", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "^4.0.2", - "normalize-package-data": "^2.5.0", - "read-pkg-up": "^7.0.1", - "redent": "^3.0.0", - "trim-newlines": "^3.0.0", - "type-fest": "^0.13.1", - "yargs-parser": "^18.1.3" - } - }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, - "type-fest": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", - "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", - "dev": true + "through2": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", + "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", + "dev": true, + "requires": { + "readable-stream": "2 || 3" + } } } }, "conventional-commits-filter": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.6.tgz", - "integrity": "sha512-4g+sw8+KA50/Qwzfr0hL5k5NWxqtrOVw4DDk3/h6L85a9Gz0/Eqp3oP+CWCNfesBvZZZEFHF7OTEbRe+yYSyKw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.2.tgz", + "integrity": "sha512-WpGKsMeXfs21m1zIw4s9H5sys2+9JccTzpN6toXtxhpw2VNF2JUXwIakthKBy+LN4DvJm+TzWhxOMWOs1OFCFQ==", "dev": true, "requires": { "lodash.ismatch": "^4.4.0", @@ -5669,18 +5178,80 @@ "trim-off-newlines": "^1.0.0" }, "dependencies": { + "arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "dev": true + }, "camelcase": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.0.0.tgz", "integrity": "sha512-8KMDF1Vz2gzOq54ONPJS65IvTUaB1cHJ2DMM7MbPmLZljDH1qpzzLsWdiN9pHh6qvkRVDTi/07+eNGch/oLU4w==", "dev": true }, + "camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + } + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, "lodash": { "version": "4.17.15", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "dev": true }, + "map-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.1.0.tgz", + "integrity": "sha512-glc9y00wgtwcDmp7GaE/0b0OnxpNJsVf3ael/An6Fe2Q51LLwN1er6sdomLRzz5h0+yMpiYLhWYF5R7HeqVd4g==", + "dev": true + }, "meow": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/meow/-/meow-7.0.1.tgz", @@ -5702,45 +5273,170 @@ "yargs-parser": "^18.1.3" } }, - "type-fest": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", - "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", - "dev": true - } - } - }, - "convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, - "core-js-compat": { - "version": "3.6.5", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.6.5.tgz", - "integrity": "sha512-7ItTKOhOZbznhXAQ2g/slGg1PJV5zDO/WdkTwi7UEOJmkvsE32PWvx6mKtDjiMpjnR2CNf6BAD6sSxIlv7ptng==", - "dev": true, - "requires": { - "browserslist": "^4.8.5", - "semver": "7.0.0" - }, - "dependencies": { - "semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "dev": true - } + "minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + }, + "dependencies": { + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + } + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "parse-json": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", + "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1", + "lines-and-columns": "^1.1.6" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "dev": true + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true + } + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "dependencies": { + "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 + } + } + }, + "redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "requires": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + } + }, + "strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "requires": { + "min-indent": "^1.0.0" + } + }, + "through2": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", + "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", + "dev": true, + "requires": { + "readable-stream": "2 || 3" + } + }, + "trim-newlines": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.0.tgz", + "integrity": "sha512-C4+gOpvmxaSMKuEf9Qc134F1ZuOHVXKRbtEflf4NTtuuJDEIJ9p5PXsalL8SkeRw+qit1Mo+yuvMPAKwWg/1hA==", + "dev": true + }, + "type-fest": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", + "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", + "dev": true + } + } + }, + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "core-js": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz", + "integrity": "sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==", + "dev": true + }, + "core-js-compat": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.6.5.tgz", + "integrity": "sha512-7ItTKOhOZbznhXAQ2g/slGg1PJV5zDO/WdkTwi7UEOJmkvsE32PWvx6mKtDjiMpjnR2CNf6BAD6sSxIlv7ptng==", + "dev": true, + "requires": { + "browserslist": "^4.8.5", + "semver": "7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true + } } }, "core-js-pure": { @@ -5813,892 +5509,1101 @@ "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", "dev": true }, - "css-select": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", - "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", - "dev": true, - "requires": { - "boolbase": "~1.0.0", - "css-what": "2.1", - "domutils": "1.5.1", - "nth-check": "~1.0.1" - } - }, - "css-what": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", - "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==", - "dev": true - }, - "cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "css-color-names": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", + "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", "dev": true }, - "cssstyle": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.2.0.tgz", - "integrity": "sha512-sEb3XFPx3jNnCAMtqrXPDeSgQr+jojtCeNf8cvMNMh1cG970+lljssvQDzPq6lmmJu2Vhqood/gtEomBiHOGnA==", + "css-declaration-sorter": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", + "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", "dev": true, "requires": { - "cssom": "~0.3.6" + "postcss": "^7.0.1", + "timsort": "^0.3.0" }, "dependencies": { - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } } } }, - "currently-unhandled": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", - "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", - "dev": true, - "requires": { - "array-find-index": "^1.0.1" - } - }, - "dargs": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz", - "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", - "dev": true - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "css-modules-loader-core": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/css-modules-loader-core/-/css-modules-loader-core-1.1.0.tgz", + "integrity": "sha1-WQhmgpShvs0mGuCkziGwtVHyHRY=", "dev": true, "requires": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" - } - }, - "date-fns": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.14.0.tgz", - "integrity": "sha512-1zD+68jhFgDIM0rF05rcwYO8cExdNqxjq4xP1QKM60Q45mnO6zaMWB4tOzrIr4M4GSLntsKeE4c9Bdl2jhL/yw==", - "dev": true - }, - "date-format": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-3.0.0.tgz", - "integrity": "sha512-eyTcpKOcamdhWJXj56DpQMo1ylSQpcGtGKXcU0Tb97+K56/CF5amAqqqNj0+KvA0iw2ynxtHWFsPDSClCxe48w==", - "dev": true - }, - "dateformat": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", - "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", - "dev": true - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, - "decamelize-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", - "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", - "dev": true, - "requires": { - "decamelize": "^1.1.0", - "map-obj": "^1.0.0" + "icss-replace-symbols": "1.1.0", + "postcss": "6.0.1", + "postcss-modules-extract-imports": "1.1.0", + "postcss-modules-local-by-default": "1.2.0", + "postcss-modules-scope": "1.1.0", + "postcss-modules-values": "1.3.0" }, "dependencies": { - "map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", "dev": true + }, + "postcss": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.1.tgz", + "integrity": "sha1-AA29H47vIXqjaLmiEsX8QLKo8/I=", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" + } + }, + "postcss-modules-extract-imports": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.1.0.tgz", + "integrity": "sha1-thTJcgvmgW6u41+zpfqh26agXds=", + "dev": true, + "requires": { + "postcss": "^6.0.1" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } } } }, - "decimal.js": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.0.tgz", - "integrity": "sha512-vDPw+rDgn3bZe1+F/pyEwb1oMG2XTlRVgAa6B4KccTEpYgF8w6eQllVbQcfIJnZyvzFtFpxnpGtx8dd7DJp/Rw==", - "dev": true - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true - }, - "decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", - "dev": true, - "requires": { - "mimic-response": "^1.0.0" - } - }, - "dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", - "dev": true - }, - "deep-eql": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "css-modules-require-hook": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/css-modules-require-hook/-/css-modules-require-hook-4.2.3.tgz", + "integrity": "sha1-Z5LKQSsV4j5vm+agfc739Xf/kE0=", "dev": true, "requires": { - "type-detect": "^4.0.0" + "debug": "^2.2.0", + "generic-names": "^1.0.1", + "glob-to-regexp": "^0.3.0", + "icss-replace-symbols": "^1.0.2", + "lodash": "^4.3.0", + "postcss": "^6.0.1", + "postcss-modules-extract-imports": "^1.0.0", + "postcss-modules-local-by-default": "^1.0.1", + "postcss-modules-resolve-imports": "^1.3.0", + "postcss-modules-scope": "^1.0.0", + "postcss-modules-values": "^1.1.1", + "seekout": "^1.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } } }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "default-require-extensions": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz", - "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==", + "css-select": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", "dev": true, "requires": { - "strip-bom": "^4.0.0" + "boolbase": "~1.0.0", + "css-what": "2.1", + "domutils": "1.5.1", + "nth-check": "~1.0.1" } }, - "defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", + "css-select-base-adapter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", + "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==", "dev": true }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "requires": { - "object-keys": "^1.0.12" - } - }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "css-selector-tokenizer": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.1.tgz", + "integrity": "sha512-xYL0AMZJ4gFzJQsHUKa5jiWWi2vH77WVNg7JYRyewwj6oPh4yb/y6Y9ZCw9dsj/9UauMhtuxR+ogQd//EdEVNA==", "dev": true, "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" + "cssesc": "^0.1.0", + "fastparse": "^1.1.1", + "regexpu-core": "^1.0.0" }, "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true }, - "is-data-descriptor": { + "regexpu-core": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz", + "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=", "dev": true, "requires": { - "kind-of": "^6.0.0" + "regenerate": "^1.2.1", + "regjsgen": "^0.2.0", + "regjsparser": "^0.1.4" } }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "regjsgen": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", + "dev": true + }, + "regjsparser": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "jsesc": "~0.5.0" } } } }, - "del": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/del/-/del-5.1.0.tgz", - "integrity": "sha512-wH9xOVHnczo9jN2IW68BabcecVPxacIA3g/7z6vhSU/4stOKQzeCRK0yD0A24WiAAUJmmVpWqrERcTxnLo3AnA==", + "css-tree": { + "version": "1.0.0-alpha.37", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", + "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", "dev": true, "requires": { - "globby": "^10.0.1", - "graceful-fs": "^4.2.2", - "is-glob": "^4.0.1", - "is-path-cwd": "^2.2.0", - "is-path-inside": "^3.0.1", - "p-map": "^3.0.0", - "rimraf": "^3.0.0", - "slash": "^3.0.0" + "mdn-data": "2.0.4", + "source-map": "^0.6.1" }, "dependencies": { - "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==", + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } } }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true - }, - "deprecation": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", - "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", - "dev": true - }, - "detect-indent": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.0.0.tgz", - "integrity": "sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA==", + "css-what": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", + "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==", "dev": true }, - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "cssesc": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-0.1.0.tgz", + "integrity": "sha1-yBSQPkViM3GgR3tAEJqq++6t27Q=", "dev": true }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "cssnano": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.10.tgz", + "integrity": "sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ==", "dev": true, "requires": { - "path-type": "^4.0.0" + "cosmiconfig": "^5.0.0", + "cssnano-preset-default": "^4.0.7", + "is-resolvable": "^1.0.0", + "postcss": "^7.0.0" }, "dependencies": { - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } } } }, - "disparity": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/disparity/-/disparity-3.0.0.tgz", - "integrity": "sha512-n94Rzbv2ambRaFzrnBf34IEiyOdIci7maRpMkoQWB6xFYGA7Nbs0Z5YQzMfTeyQeelv23nayqOcssBoc6rKrgw==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "diff": "^4.0.1" + "cssnano-preset-default": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz", + "integrity": "sha512-x0YHHx2h6p0fCl1zY9L9roD7rnlltugGu7zXSKQx6k2rYw0Hi3IqxcoAGF7u9Q5w1nt7vK0ulxV8Lo+EvllGsA==", + "dev": true, + "requires": { + "css-declaration-sorter": "^4.0.1", + "cssnano-util-raw-cache": "^4.0.1", + "postcss": "^7.0.0", + "postcss-calc": "^7.0.1", + "postcss-colormin": "^4.0.3", + "postcss-convert-values": "^4.0.1", + "postcss-discard-comments": "^4.0.2", + "postcss-discard-duplicates": "^4.0.2", + "postcss-discard-empty": "^4.0.1", + "postcss-discard-overridden": "^4.0.1", + "postcss-merge-longhand": "^4.0.11", + "postcss-merge-rules": "^4.0.3", + "postcss-minify-font-values": "^4.0.2", + "postcss-minify-gradients": "^4.0.2", + "postcss-minify-params": "^4.0.2", + "postcss-minify-selectors": "^4.0.2", + "postcss-normalize-charset": "^4.0.1", + "postcss-normalize-display-values": "^4.0.2", + "postcss-normalize-positions": "^4.0.2", + "postcss-normalize-repeat-style": "^4.0.2", + "postcss-normalize-string": "^4.0.2", + "postcss-normalize-timing-functions": "^4.0.2", + "postcss-normalize-unicode": "^4.0.1", + "postcss-normalize-url": "^4.0.1", + "postcss-normalize-whitespace": "^4.0.2", + "postcss-ordered-values": "^4.1.2", + "postcss-reduce-initial": "^4.0.3", + "postcss-reduce-transforms": "^4.0.2", + "postcss-svgo": "^4.0.2", + "postcss-unique-selectors": "^4.0.1" }, "dependencies": { - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", "dev": true, "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.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==", + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", "dev": true, "requires": { - "color-name": "~1.1.4" + "has-flag": "^3.0.0" } - }, - "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 - }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true } } }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "dom-serializer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", - "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", - "dev": true, - "requires": { - "domelementtype": "^1.3.0", - "entities": "^1.1.1" - } - }, - "dom-walk": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", - "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==", + "cssnano-util-get-arguments": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz", + "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=", "dev": true }, - "domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "cssnano-util-get-match": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz", + "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=", "dev": true }, - "domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "cssnano-util-raw-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz", + "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", "dev": true, "requires": { - "webidl-conversions": "^5.0.0" + "postcss": "^7.0.0" }, "dependencies": { - "webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } } } }, - "domhandler": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", - "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", - "dev": true, - "requires": { - "domelementtype": "1" - } + "cssnano-util-same-parent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz", + "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==", + "dev": true }, - "domutils": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", - "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "csso": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.0.3.tgz", + "integrity": "sha512-NL3spysxUkcrOgnpsT4Xdl2aiEiBG6bXswAABQVHcMrfjjBisFOKwLDOmf4wf32aPdcJws1zds2B0Rg+jqMyHQ==", "dev": true, "requires": { - "dom-serializer": "0", - "domelementtype": "1" + "css-tree": "1.0.0-alpha.39" + }, + "dependencies": { + "css-tree": { + "version": "1.0.0-alpha.39", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.39.tgz", + "integrity": "sha512-7UvkEYgBAHRG9Nt980lYxjsTrCyHFN53ky3wVsDkiMdVqylqRt+Zc+jm5qw7/qyOvN2dHSYtX0e4MbCCExSvnA==", + "dev": true, + "requires": { + "mdn-data": "2.0.6", + "source-map": "^0.6.1" + } + }, + "mdn-data": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.6.tgz", + "integrity": "sha512-rQvjv71olwNHgiTbfPZFkJtjNMciWgswYeciZhtvWLO8bmX3TnhyA62I6sTWOyZssWHJJjY6/KiWwqQsWWsqOA==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } } }, - "dot-prop": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.2.0.tgz", - "integrity": "sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A==", + "cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "dev": true + }, + "cssstyle": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.2.0.tgz", + "integrity": "sha512-sEb3XFPx3jNnCAMtqrXPDeSgQr+jojtCeNf8cvMNMh1cG970+lljssvQDzPq6lmmJu2Vhqood/gtEomBiHOGnA==", "dev": true, "requires": { - "is-obj": "^2.0.0" + "cssom": "~0.3.6" }, "dependencies": { - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", "dev": true } } }, - "duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", "dev": true, "requires": { - "readable-stream": "^2.0.2" + "array-find-index": "^1.0.1" } }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", - "dev": true + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", "dev": true, "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" } }, - "electron-to-chromium": { - "version": "1.3.367", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.367.tgz", - "integrity": "sha512-GCHQreWs4zhKA48FNXCjvpV4kTnKoLu2PSAfKX394g34NPvTs2pPh1+jzWitNwhmOYI8zIqt36ulRVRZUgqlfA==", + "date-fns": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.14.0.tgz", + "integrity": "sha512-1zD+68jhFgDIM0rF05rcwYO8cExdNqxjq4xP1QKM60Q45mnO6zaMWB4tOzrIr4M4GSLntsKeE4c9Bdl2jhL/yw==", "dev": true }, - "elegant-spinner": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", - "integrity": "sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=", + "dateformat": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", "dev": true }, - "email-regex": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/email-regex/-/email-regex-4.0.0.tgz", - "integrity": "sha512-OxR2NqoYS3ZikqOkju2krRTyxngwjJ5Wh4yalpTqbBnUOr+LLwwjY2x5Sksruw6TieyQDswE5Pc83Eh6RQj3GA==", - "dev": true + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "decamelize-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", + "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", "dev": true, "requires": { - "once": "^1.4.0" + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "dependencies": { + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + } } }, - "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", + "decimal.js": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.0.tgz", + "integrity": "sha512-vDPw+rDgn3bZe1+F/pyEwb1oMG2XTlRVgAa6B4KccTEpYgF8w6eQllVbQcfIJnZyvzFtFpxnpGtx8dd7DJp/Rw==", "dev": true }, - "env-ci": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-5.0.2.tgz", - "integrity": "sha512-Xc41mKvjouTXD3Oy9AqySz1IeyvJvHZ20Twf5ZLYbNpPPIuCnL/qHCmNlD01LoNy0JTunw9HPYVptD19Ac7Mbw==", + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", "dev": true, "requires": { - "execa": "^4.0.0", - "java-properties": "^1.0.0" + "mimic-response": "^1.0.0" } }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true }, - "es-abstract": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", - "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", "dev": true, "requires": { - "es-to-primitive": "^1.2.0", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "is-callable": "^1.1.4", - "is-regex": "^1.0.4", - "object-keys": "^1.0.12" + "type-detect": "^4.0.0" } }, - "es-to-primitive": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", - "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true }, - "es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "deep-freeze": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/deep-freeze/-/deep-freeze-0.0.1.tgz", + "integrity": "sha1-OgsABd4YZygZ39OM0x+RF5yJPoQ=", "dev": true }, - "es6-object-assign": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", - "integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=", + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, - "es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", "dev": true }, - "es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "default-require-extensions": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz", + "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==", "dev": true, "requires": { - "es6-promise": "^4.0.3" + "strip-bom": "^4.0.0" } }, - "escape-goat": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", - "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "dev": true, + "requires": { + "clone": "^1.0.2" + } + }, + "defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", "dev": true }, - "escape-quotes": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/escape-quotes/-/escape-quotes-1.0.2.tgz", - "integrity": "sha1-tIltSmz4LdWzP0m3E0CMY4D2zZc=", + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", "dev": true, "requires": { - "escape-string-regexp": "^1.0.5" + "object-keys": "^1.0.12" } }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", "dev": true }, - "escodegen": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.1.tgz", - "integrity": "sha512-Bmt7NcRySdIfNPfU2ZoXDrrXsG9ZjvDxcAlMfDUgRBjLOWTuIACXPBFJH7Z+cLb40JeQco5toikyc9t9P8E9SQ==", + "deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", + "dev": true + }, + "detect-indent": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.0.0.tgz", + "integrity": "sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA==", + "dev": true + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, "requires": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" + "path-type": "^4.0.0" }, "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true } } }, - "eslint": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", - "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "disparity": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/disparity/-/disparity-3.0.0.tgz", + "integrity": "sha512-n94Rzbv2ambRaFzrnBf34IEiyOdIci7maRpMkoQWB6xFYGA7Nbs0Z5YQzMfTeyQeelv23nayqOcssBoc6rKrgw==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.10.0", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^1.4.3", - "eslint-visitor-keys": "^1.1.0", - "espree": "^6.1.2", - "esquery": "^1.0.1", - "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "inquirer": "^7.0.0", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.14", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.3", - "progress": "^2.0.0", - "regexpp": "^2.0.1", - "semver": "^6.1.2", - "strip-ansi": "^5.2.0", - "strip-json-comments": "^3.0.1", - "table": "^5.2.3", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "ansi-styles": "^4.1.0", + "diff": "^4.0.1" }, "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "eslint-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", - "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - } - }, - "globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", "dev": true, "requires": { - "type-fest": "^0.8.1" + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" } }, - "regexpp": { + "color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", - "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 - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "requires": { - "ansi-regex": "^4.1.0" + "color-name": "~1.1.4" } }, - "strip-json-comments": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.0.tgz", - "integrity": "sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w==", + "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 }, - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true } } }, - "eslint-config-prettier": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.11.0.tgz", - "integrity": "sha512-oB8cpLWSAjOVFEJhhyMZh6NOEOtBVziaqdDQ86+qhDHFbZXoRTM7pNSvFRfW/W/L/LrQ38C99J5CGuRBBzBsdA==", + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, "requires": { - "get-stdin": "^6.0.0" - }, - "dependencies": { - "get-stdin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", - "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", - "dev": true - } + "esutils": "^2.0.2" } }, - "eslint-plugin-jsdoc": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-21.0.0.tgz", - "integrity": "sha512-CdLGe2oyw5YAX9rxq9bVz7H2PK+r8PVwdGuvYGMBstpbVD/66yUAgRFQRsJwAsRKLmReo58Lw1jFdNcxdOc4eg==", + "dom-serializer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", + "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", "dev": true, "requires": { - "comment-parser": "^0.7.2", - "debug": "^4.1.1", - "jsdoctypeparser": "^6.1.0", - "lodash": "^4.17.15", - "regextras": "^0.7.0", - "semver": "^6.3.0", - "spdx-expression-parse": "^3.0.0" + "domelementtype": "^1.3.0", + "entities": "^1.1.1" + } + }, + "dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==", + "dev": true + }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "dev": true + }, + "domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "dev": true, + "requires": { + "webidl-conversions": "^5.0.0" }, "dependencies": { - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", "dev": true } } }, - "eslint-plugin-prettier": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.3.tgz", - "integrity": "sha512-+HG5jmu/dN3ZV3T6eCD7a4BlAySdN7mLIbJYo0z1cFQuI+r2DiTJEFeF68ots93PsnrMxbzIZ2S/ieX+mkrBeQ==", + "domhandler": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", "dev": true, "requires": { - "prettier-linter-helpers": "^1.0.0" + "domelementtype": "1" } }, - "eslint-plugin-tsdoc": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-tsdoc/-/eslint-plugin-tsdoc-0.2.5.tgz", - "integrity": "sha512-KXquQlf/3u2U7A3LebYdcmAMtMxmUW3HN4JtOluq+iRuRPbBNVeUlg4SOXrnqSuQCOpSITHlPhP418IwjExA+w==", + "domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", "dev": true, "requires": { - "@microsoft/tsdoc": "0.12.20", - "@microsoft/tsdoc-config": "0.13.4" + "dom-serializer": "0", + "domelementtype": "1" } }, - "eslint-scope": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", - "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "dot-prop": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.2.0.tgz", + "integrity": "sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A==", "dev": true, "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" + "is-obj": "^2.0.0" + }, + "dependencies": { + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true + } } }, - "eslint-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.0.0.tgz", - "integrity": "sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA==", + "duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", "dev": true, "requires": { - "eslint-visitor-keys": "^1.1.0" + "readable-stream": "^2.0.2" } }, - "eslint-visitor-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", - "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", "dev": true }, - "espree": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", - "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", "dev": true, "requires": { - "acorn": "^7.1.1", - "acorn-jsx": "^5.2.0", - "eslint-visitor-keys": "^1.1.0" + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" } }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "electron-to-chromium": { + "version": "1.3.367", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.367.tgz", + "integrity": "sha512-GCHQreWs4zhKA48FNXCjvpV4kTnKoLu2PSAfKX394g34NPvTs2pPh1+jzWitNwhmOYI8zIqt36ulRVRZUgqlfA==", "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==", + "elegant-spinner": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-2.0.0.tgz", + "integrity": "sha512-5YRYHhvhYzV/FC4AiMdeSIg3jAYGq9xFvbhZMpPlJoBsfYgrw2DSCYeXfat6tYBu45PWiyRr3+flaCPPmviPaA==", + "dev": true + }, + "email-regex": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/email-regex/-/email-regex-4.0.0.tgz", + "integrity": "sha512-OxR2NqoYS3ZikqOkju2krRTyxngwjJ5Wh4yalpTqbBnUOr+LLwwjY2x5Sksruw6TieyQDswE5Pc83Eh6RQj3GA==", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dev": true, "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz", - "integrity": "sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw==", - "dev": true - } + "once": "^1.4.0" } }, - "esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "enquirer": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.5.tgz", + "integrity": "sha512-BNT1C08P9XD0vNg3J475yIUG+mVdp9T6towYFHUv897X0KoHBjB1shyrNmhmtHWKP17iSWgo7Gqh7BBuzLZMSA==", "dev": true, "requires": { - "estraverse": "^4.1.0" + "ansi-colors": "^3.2.1" } }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", "dev": true }, - "estree-walker": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", - "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "env-ci": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-5.0.2.tgz", + "integrity": "sha512-Xc41mKvjouTXD3Oy9AqySz1IeyvJvHZ20Twf5ZLYbNpPPIuCnL/qHCmNlD01LoNy0JTunw9HPYVptD19Ac7Mbw==", + "dev": true, + "requires": { + "execa": "^4.0.0", + "java-properties": "^1.0.0" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", + "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-keys": "^1.0.12" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", "dev": true }, - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "es6-object-assign": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", + "integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=", "dev": true }, - "execa": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.0.0.tgz", - "integrity": "sha512-JbDUxwV3BoT5ZVXQrSVbAiaXhXUkIwvbhPIwZ0N13kX+5yCzOhUNdocxB/UQRuYOHRYYwAxKYwJYc0T4D12pDA==", + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", "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" - }, - "dependencies": { - "cross-spawn": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz", - "integrity": "sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==", + "es6-promise": "^4.0.3" + } + }, + "escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "dev": true + }, + "escape-quotes": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/escape-quotes/-/escape-quotes-1.0.2.tgz", + "integrity": "sha1-tIltSmz4LdWzP0m3E0CMY4D2zZc=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "escodegen": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.1.tgz", + "integrity": "sha512-Bmt7NcRySdIfNPfU2ZoXDrrXsG9ZjvDxcAlMfDUgRBjLOWTuIACXPBFJH7Z+cLb40JeQco5toikyc9t9P8E9SQ==", + "dev": true, + "requires": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + } + } + }, + "eslint": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.1.0.tgz", + "integrity": "sha512-DfS3b8iHMK5z/YLSme8K5cge168I8j8o1uiVmFCgnnjxZQbCGyraF8bMl7Ju4yfBmCuxD7shOF7eqGkcuIHfsA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0", + "eslint-visitor-keys": "^1.1.0", + "espree": "^7.0.0", + "esquery": "^1.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz", + "integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==", + "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 + }, + "cross-spawn": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.2.tgz", + "integrity": "sha512-PD6G8QG3S4FK/XCGFbEQrDqO2AnMMsy0meR7lerlIOHAAbkuavGU/pOqprrlvfTNjvowivTeBsjebAL0NSoMxw==", "dev": true, "requires": { "path-key": "^3.1.0", @@ -6706,25 +6611,43 @@ "which": "^2.0.1" } }, - "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", - "dev": true + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "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 }, - "onetime": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", - "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "requires": { - "mimic-fn": "^2.1.0" + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" } }, "path-key": { @@ -6733,6 +6656,18 @@ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -6748,195 +6683,346 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", "dev": true, "requires": { - "isexe": "^2.0.0" + "ansi-regex": "^5.0.0" } - } - } - }, - "exif-parser": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/exif-parser/-/exif-parser-0.1.12.tgz", - "integrity": "sha1-WKnS1ywCwfbwKg70qRZicrd2CSI=", - "dev": true - }, - "exists-file": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/exists-file/-/exists-file-3.0.2.tgz", - "integrity": "sha512-0mO5ZIWiJl35mTCkyyh/cU1ucn+17fOn7/P+QzNCby+/OLKOKKH9fR5kh+riKlNutxYTbZG+OHyYqFfQfpweGw==", - "dev": true, - "requires": { - "cb2promise": "~1.1.0" - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + }, + "strip-json-comments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.0.tgz", + "integrity": "sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w==", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", "dev": true, "requires": { - "ms": "2.0.0" + "has-flag": "^4.0.0" } }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "prelude-ls": "^1.2.1" } }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "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 + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "isexe": "^2.0.0" } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true } } }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "eslint-config-prettier": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.11.0.tgz", + "integrity": "sha512-oB8cpLWSAjOVFEJhhyMZh6NOEOtBVziaqdDQ86+qhDHFbZXoRTM7pNSvFRfW/W/L/LrQ38C99J5CGuRBBzBsdA==", "dev": true, "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "get-stdin": "^6.0.0" }, "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } + "get-stdin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "dev": true } } }, - "extended-emitter": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/extended-emitter/-/extended-emitter-1.0.3.tgz", - "integrity": "sha512-gdaWWszJmr2oq6rKSxPmuclQtEwfzt4JwmGrEqTnE89GQHqZyvPZ/NWj6fBgK3IKufvRyJDnLZviUFPrrJf36Q==", + "eslint-plugin-jsdoc": { + "version": "25.4.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-25.4.2.tgz", + "integrity": "sha512-IFZnxBBt2fGYZ9yaLt+KP/jHa6u8LQPwH9QzRlhbU+WKBq7ou6XTXoxG0EZVn9ohcbJ0sM8X70iRRX/J3Wu37w==", "dev": true, "requires": { - "sift": "*", - "wolfy87-eventemitter": "*" + "comment-parser": "^0.7.4", + "debug": "^4.1.1", + "jsdoctypeparser": "^6.1.0", + "lodash": "^4.17.15", + "regextras": "^0.7.1", + "semver": "^6.3.0", + "spdx-expression-parse": "^3.0.1" + }, + "dependencies": { + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "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 + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + } } }, - "external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "eslint-plugin-prettier": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.3.tgz", + "integrity": "sha512-+HG5jmu/dN3ZV3T6eCD7a4BlAySdN7mLIbJYo0z1cFQuI+r2DiTJEFeF68ots93PsnrMxbzIZ2S/ieX+mkrBeQ==", "dev": true, "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" + "prettier-linter-helpers": "^1.0.0" } }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "eslint-plugin-tsdoc": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-tsdoc/-/eslint-plugin-tsdoc-0.2.5.tgz", + "integrity": "sha512-KXquQlf/3u2U7A3LebYdcmAMtMxmUW3HN4JtOluq+iRuRPbBNVeUlg4SOXrnqSuQCOpSITHlPhP418IwjExA+w==", + "dev": true, + "requires": { + "@microsoft/tsdoc": "0.12.20", + "@microsoft/tsdoc-config": "0.13.4" + } + }, + "eslint-scope": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", + "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.0.0.tgz", + "integrity": "sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", + "dev": true + }, + "espree": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.0.0.tgz", + "integrity": "sha512-/r2XEx5Mw4pgKdyb7GNLQNsu++asx/dltf/CI8RFi9oGHxmQFgvLbc5Op4U6i8Oaj+kdslhJtVlEZeAqH5qOTw==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "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==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" }, "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "estraverse": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz", + "integrity": "sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "eventemitter3": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz", + "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==", + "dev": true + }, + "execa": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.0.0.tgz", + "integrity": "sha512-JbDUxwV3BoT5ZVXQrSVbAiaXhXUkIwvbhPIwZ0N13kX+5yCzOhUNdocxB/UQRuYOHRYYwAxKYwJYc0T4D12pDA==", + "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" + }, + "dependencies": { + "cross-spawn": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz", + "integrity": "sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==", "dev": true, "requires": { - "is-descriptor": "^1.0.0" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" } }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "dev": true }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "onetime": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "mimic-fn": "^2.1.0" } }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "shebang-regex": "^3.0.0" } }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "isexe": "^2.0.0" } } } }, + "exif-parser": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/exif-parser/-/exif-parser-0.1.12.tgz", + "integrity": "sha1-WKnS1ywCwfbwKg70qRZicrd2CSI=", + "dev": true + }, + "exists-file": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/exists-file/-/exists-file-3.0.2.tgz", + "integrity": "sha512-0mO5ZIWiJl35mTCkyyh/cU1ucn+17fOn7/P+QzNCby+/OLKOKKH9fR5kh+riKlNutxYTbZG+OHyYqFfQfpweGw==", + "dev": true, + "requires": { + "cb2promise": "~1.1.0" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extended-emitter": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/extended-emitter/-/extended-emitter-1.0.3.tgz", + "integrity": "sha512-gdaWWszJmr2oq6rKSxPmuclQtEwfzt4JwmGrEqTnE89GQHqZyvPZ/NWj6fBgK3IKufvRyJDnLZviUFPrrJf36Q==", + "dev": true, + "requires": { + "sift": "*", + "wolfy87-eventemitter": "*" + } + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, "extract-zip": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz", @@ -7009,6 +7095,12 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "fastparse": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", + "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==", + "dev": true + }, "fastq": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.6.0.tgz", @@ -7028,9 +7120,9 @@ } }, "figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", "dev": true, "requires": { "escape-string-regexp": "^1.0.5" @@ -7184,12 +7276,6 @@ "integrity": "sha512-+8GbtQBwEqutP0v3uajDDoN64K2ehmHd0cjlghhxh0WpcfPzAIjPA03e1VvHlxL02FVGR0A6lwXsNQKn3H1RNQ==", "dev": true }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, "foreground-child": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", @@ -7260,15 +7346,6 @@ "mime-types": "^2.1.12" } }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, "from2": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", @@ -7321,6 +7398,15 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "generic-names": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/generic-names/-/generic-names-1.0.3.tgz", + "integrity": "sha1-LXhqEhruUIh2eWk56OO/+DbCCRc=", + "dev": true, + "requires": { + "loader-utils": "^0.2.16" + } + }, "gensync": { "version": "1.0.0-beta.1", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", @@ -7345,23 +7431,6 @@ "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", "dev": true }, - "get-port": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.0.0.tgz", - "integrity": "sha512-imzMU0FjsZqNa6BqOjbbW6w5BivHIuQKopjpPqcnx0AVHJQKCxK1O+Ab3OrVXhrekqfVMjwA9ZYu062R+KcIsQ==", - "dev": true, - "requires": { - "type-fest": "^0.3.0" - }, - "dependencies": { - "type-fest": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", - "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", - "dev": true - } - } - }, "get-res": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/get-res/-/get-res-3.0.0.tgz", @@ -7551,12 +7620,6 @@ "pump": "^3.0.0" } }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true - }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", @@ -7884,64 +7947,6 @@ "requires": { "through2": "~2.0.0" } - }, - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - } - } - }, - "git-raw-commits": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.7.tgz", - "integrity": "sha512-SkwrTqrDxw8y0G1uGJ9Zw13F7qu3LF8V4BifyDeiJCxSnjRGZD9SaoMiMqUvvXMXh6S3sOQ1DsBN7L2fMUZW/g==", - "dev": true, - "requires": { - "dargs": "^7.0.0", - "lodash.template": "^4.0.2", - "meow": "^7.0.0", - "split2": "^2.0.0", - "through2": "^3.0.0" - }, - "dependencies": { - "camelcase": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.0.0.tgz", - "integrity": "sha512-8KMDF1Vz2gzOq54ONPJS65IvTUaB1cHJ2DMM7MbPmLZljDH1qpzzLsWdiN9pHh6qvkRVDTi/07+eNGch/oLU4w==", - "dev": true - }, - "meow": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/meow/-/meow-7.0.1.tgz", - "integrity": "sha512-tBKIQqVrAHqwit0vfuFPY3LlzJYkEOFyKa3bPgxzNl6q/RtN8KQ+ALYEASYuFayzSAsjlhXj/JZ10rH85Q6TUw==", - "dev": true, - "requires": { - "@types/minimist": "^1.2.0", - "arrify": "^2.0.1", - "camelcase": "^6.0.0", - "camelcase-keys": "^6.2.2", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "^4.0.2", - "normalize-package-data": "^2.5.0", - "read-pkg-up": "^7.0.1", - "redent": "^3.0.0", - "trim-newlines": "^3.0.0", - "type-fest": "^0.13.1", - "yargs-parser": "^18.1.3" - } - }, - "type-fest": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", - "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", - "dev": true } } }, @@ -8078,6 +8083,12 @@ "wordwrap": "^1.0.0" }, "dependencies": { + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -8152,64 +8163,6 @@ "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", "dev": true }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "has-yarn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", @@ -8246,10 +8199,16 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, + "hex-color-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", + "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==", + "dev": true + }, "highlight.js": { - "version": "9.18.1", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.1.tgz", - "integrity": "sha512-OrVKYz70LHsnCgmbXctv/bfuvntIKDz177h0Co37DQ5jamGZLVmoCVMtjMtNZY3X9DrCcKfklHPNeA0uPZhSJg==", + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.0.3.tgz", + "integrity": "sha512-9FG7SSzv9yOY5CGGxfI6NDm7xLYtMOjKtPBxw7Zff3t5UcRcUNTGEeS8lNjhceL34KeetLMoGMFTGoaa83HwyQ==", "dev": true }, "hook-std": { @@ -8264,6 +8223,24 @@ "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", "dev": true }, + "hsl-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz", + "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=", + "dev": true + }, + "hsla-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz", + "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=", + "dev": true + }, + "html-comment-regex": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz", + "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==", + "dev": true + }, "html-encoding-sniffer": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", @@ -8346,20 +8323,23 @@ } }, "https-proxy-agent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz", - "integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", "dev": true, "requires": { - "agent-base": "5", + "agent-base": "6", "debug": "4" }, "dependencies": { "agent-base": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz", - "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==", - "dev": true + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.0.tgz", + "integrity": "sha512-j1Q7cSCqN+AwrmDd+pzgqc0/NpC655x2bUf5ZjRIO77DcNBFmh+OgRNzF6OKdCC9RSCb19fGd99+bhXFdkRNqw==", + "dev": true, + "requires": { + "debug": "4" + } } } }, @@ -8567,6 +8547,21 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "icss-replace-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", + "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=", + "dev": true + }, + "icss-utils": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-3.0.1.tgz", + "integrity": "sha1-7nDTroysOMa+XtkehRsn7tNDrQ8=", + "dev": true, + "requires": { + "postcss": "^6.0.2" + } + }, "ieee754": { "version": "1.1.13", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", @@ -8579,6 +8574,15 @@ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, + "import-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-3.0.0.tgz", + "integrity": "sha512-4pnzH16plW+hgvRECbDWpQl3cqtvSofHWh44met7ESfZ8UZOWWddm8hEyDTqREJ9RbYHY8gi8DqmaelApoOGMg==", + "dev": true, + "requires": { + "import-from": "^3.0.0" + } + }, "import-fresh": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", @@ -8624,6 +8628,12 @@ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true }, + "indexes-of": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", + "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -8647,9 +8657,9 @@ "dev": true }, "inquirer": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.7.tgz", - "integrity": "sha512-+lV+BE+M3bDVi6Vtejd7sA572D8gJI5qQUciWDqGKvy6Q6GjuEeJAoHRdOSwqtHUvZlNZssnVvTqQyEXKzki/g==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.1.0.tgz", + "integrity": "sha512-5fJMWEmikSYu0nv/flMc475MhGbB7TSPd/2IpFV4I4rMklboCH2rQjYY5kKiYGHqUF9gvaambupcJFFG9dvReg==", "dev": true, "requires": { "ansi-escapes": "^4.2.1", @@ -8714,6 +8724,15 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -8800,31 +8819,11 @@ "integrity": "sha512-Y75zBYLkh0lJ9qxeHlMjQ7bSbyiSqNW/UOPWDmzC7cXskL1hekSITh1Oc6JV0XCWWZ9DE8VYSB71xocLk3gmGw==", "dev": true }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } + "is-absolute-url": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", + "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=", + "dev": true }, "is-arguments": { "version": "1.0.4", @@ -8868,30 +8867,18 @@ "ci-info": "^2.0.0" } }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "is-color-stop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz", + "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=", "dev": true, "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } + "css-color-names": "^0.0.4", + "hex-color-regex": "^1.1.0", + "hsl-regex": "^1.0.0", + "hsla-regex": "^1.0.0", + "rgb-regex": "^1.0.1", + "rgba-regex": "^1.0.0" } }, "is-date-object": { @@ -8900,37 +8887,12 @@ "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", "dev": true }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, "is-directory": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", "dev": true }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -9013,21 +8975,6 @@ "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", "dev": true }, - "is-observable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-1.1.0.tgz", - "integrity": "sha512-NqCa4Sa2d+u7BWc6CukaObG3Fh+CU9bvixbpcXYhy2VvYS7vVGIdAgnIS5Ks3A/cqk4rebLJ9s8zBstT2aKnIA==", - "dev": true, - "requires": { - "symbol-observable": "^1.1.0" - } - }, - "is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", - "dev": true - }, "is-path-inside": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.2.tgz", @@ -9041,12 +8988,12 @@ "dev": true }, "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.0.tgz", + "integrity": "sha512-tZIpofR+P05k8Aocp7UI/2UTa9lTJSebCXpFFoR9aibpokDj/uXBsJ8luUu0tTVYKkMU6URDUuOfJZ7koewXvg==", "dev": true, "requires": { - "isobject": "^3.0.1" + "isobject": "^4.0.0" } }, "is-potential-custom-element-name": { @@ -9091,6 +9038,12 @@ "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", "dev": true }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", + "dev": true + }, "is-retry-allowed": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", @@ -9103,6 +9056,15 @@ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, + "is-svg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-3.0.0.tgz", + "integrity": "sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ==", + "dev": true, + "requires": { + "html-comment-regex": "^1.1.0" + } + }, "is-symbol": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", @@ -9158,9 +9120,9 @@ "dev": true }, "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-4.0.0.tgz", + "integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==", "dev": true }, "isstream": { @@ -9182,12 +9144,6 @@ "lodash.uniqby": "^4.7.0" } }, - "istanbul-lib-coverage": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", - "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", - "dev": true - }, "istanbul-lib-hook": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", @@ -9197,29 +9153,6 @@ "append-transform": "^2.0.0" } }, - "istanbul-lib-instrument": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", - "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", - "dev": true, - "requires": { - "@babel/generator": "^7.4.0", - "@babel/parser": "^7.4.3", - "@babel/template": "^7.4.0", - "@babel/traverse": "^7.4.3", - "@babel/types": "^7.4.0", - "istanbul-lib-coverage": "^2.0.5", - "semver": "^6.0.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 - } - } - }, "istanbul-lib-processinfo": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz", @@ -9396,22 +9329,28 @@ "dev": true }, "jest-worker": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", - "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.0.0.tgz", + "integrity": "sha512-pPaYa2+JnwmiZjK9x7p9BoZht+47ecFCDFA/CJxspHzeDvQcfVBLWzCiWyo+EGrSiQMWZtCFo9iSvMZnAAo8vw==", "dev": true, "requires": { "merge-stream": "^2.0.0", - "supports-color": "^6.1.0" + "supports-color": "^7.0.0" }, "dependencies": { + "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": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" } } } @@ -9441,12 +9380,6 @@ "integrity": "sha512-960VHmtN1vTpasX/1LupLohdP5odwAT7oK/VSm6mW0M58LbrBnowLAPWAZhWGhDAGjzbMnPXZxzB/QYgBwkN0w==", "dev": true }, - "jquery": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.5.1.tgz", - "integrity": "sha512-XwIBPqcMn57FxfT+Go5pzySnm4KWkT1Tv7gjrpT1srtf8Weynl6R273VJ5GjkRb51IzMp5nbaPjJXMWeju2MKg==", - "dev": true - }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -9692,32 +9625,80 @@ "dev": true }, "lint-staged": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-9.5.0.tgz", - "integrity": "sha512-nawMob9cb/G1J98nb8v3VC/E8rcX1rryUYXVZ69aT9kde6YWX+uvNOEHY5yf2gcWcTJGiD0kqXmCnS3oD75GIA==", + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-10.2.6.tgz", + "integrity": "sha512-2oEBWyPZHkdyjKcIv2U6ay80Q52ZMlZZrUnfsV0WTVcgzPlt3o2t5UFy2v8ETUTsIDZ0xSJVnffWCgD3LF6xTQ==", "dev": true, "requires": { - "chalk": "^2.4.2", - "commander": "^2.20.0", - "cosmiconfig": "^5.2.1", + "chalk": "^4.0.0", + "cli-truncate": "2.1.0", + "commander": "^5.1.0", + "cosmiconfig": "^6.0.0", "debug": "^4.1.1", "dedent": "^0.7.0", - "del": "^5.0.0", - "execa": "^2.0.3", - "listr": "^0.14.3", - "log-symbols": "^3.0.0", + "execa": "^4.0.1", + "listr2": "^2.0.2", + "log-symbols": "^4.0.0", "micromatch": "^4.0.2", "normalize-path": "^3.0.0", - "please-upgrade-node": "^3.1.1", - "string-argv": "^0.3.0", + "please-upgrade-node": "^3.2.0", + "string-argv": "0.3.1", "stringify-object": "^3.3.0" }, "dependencies": { - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz", + "integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==", + "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 + }, + "commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "dev": true + }, + "cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "dev": true, + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + } }, "cross-spawn": { "version": "7.0.2", @@ -9731,35 +9712,53 @@ } }, "execa": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-2.1.0.tgz", - "integrity": "sha512-Y/URAVapfbYy2Xp/gb6A0E7iR8xeqOCXsuuaoMn7A5PzrXUK84E1gyiEfq0wQd/GHA6GsoHWwhNq8anb0mleIw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.0.1.tgz", + "integrity": "sha512-SCjM/zlBdOK8Q5TIjOn6iEHZaPHFsMoTxXQ2nvUvtPnuohz3H2dIozSg+etNR98dGoYUp2ENSKLL/XaMmbxVgw==", "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": "^3.0.0", + "npm-run-path": "^4.0.0", "onetime": "^5.1.0", - "p-finally": "^2.0.0", "signal-exit": "^3.0.2", "strip-final-newline": "^2.0.0" } }, + "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 + }, "is-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", "dev": true }, - "npm-run-path": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-3.1.0.tgz", - "integrity": "sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg==", + "log-symbols": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", + "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", + "dev": true, + "requires": { + "chalk": "^4.0.0" + } + }, + "parse-json": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", + "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", "dev": true, "requires": { - "path-key": "^3.0.0" + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1", + "lines-and-columns": "^1.1.6" } }, "path-key": { @@ -9768,6 +9767,12 @@ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -9783,6 +9788,15 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -9794,186 +9808,101 @@ } } }, - "listr": { - "version": "0.14.3", - "resolved": "https://registry.npmjs.org/listr/-/listr-0.14.3.tgz", - "integrity": "sha512-RmAl7su35BFd/xoMamRjpIE4j3v+L28o8CT5YhAXQJm1fD+1l9ngXY8JAQRJ+tFK2i5njvi0iRUKV09vPwA0iA==", + "listr2": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-2.0.4.tgz", + "integrity": "sha512-oJaAcplPsa72rKW0eg4P4LbEJjhH+UO2I8uqR/I2wzHrVg16ohSfUy0SlcHS21zfYXxtsUpL8YXGHjyfWMR0cg==", "dev": true, "requires": { "@samverschueren/stream-to-observable": "^0.3.0", - "is-observable": "^1.1.0", - "is-promise": "^2.1.0", - "is-stream": "^1.1.0", - "listr-silent-renderer": "^1.1.1", - "listr-update-renderer": "^0.5.0", - "listr-verbose-renderer": "^0.5.0", - "p-map": "^2.0.0", - "rxjs": "^6.3.3" - }, - "dependencies": { - "is-promise": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", - "dev": true - }, - "p-map": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", - "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", - "dev": true - } - } - }, - "listr-silent-renderer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz", - "integrity": "sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4=", - "dev": true - }, - "listr-update-renderer": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.5.0.tgz", - "integrity": "sha512-tKRsZpKz8GSGqoI/+caPmfrypiaq+OQCbd+CovEC24uk1h952lVj5sC7SqyFUm+OaJ5HN/a1YLt5cit2FMNsFA==", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "cli-truncate": "^0.2.1", - "elegant-spinner": "^1.0.1", - "figures": "^1.7.0", - "indent-string": "^3.0.0", - "log-symbols": "^1.0.2", - "log-update": "^2.3.0", - "strip-ansi": "^3.0.1" + "chalk": "^4.0.0", + "cli-cursor": "^3.1.0", + "cli-truncate": "^2.1.0", + "elegant-spinner": "^2.0.0", + "enquirer": "^2.3.5", + "figures": "^3.2.0", + "indent-string": "^4.0.0", + "log-update": "^4.0.0", + "p-map": "^4.0.0", + "pad": "^3.2.0", + "rxjs": "^6.5.5", + "through": "^2.3.8", + "uuid": "^7.0.2" }, "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" - } - }, - "indent-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", - "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", - "dev": true - }, - "log-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", - "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", "dev": true, "requires": { - "chalk": "^1.0.0" + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" } }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "chalk": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz", + "integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, - "listr-verbose-renderer": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.5.0.tgz", - "integrity": "sha512-04PDPqSlsqIOaaaGZ+41vq5FejI9auqTInicFRndCBgE3bXG8D6W1I+mWhk+1nqbHmyhla/6BUrd5OSiHwKRXw==", - "dev": true, - "requires": { - "chalk": "^2.4.1", - "cli-cursor": "^2.1.0", - "date-fns": "^1.27.2", - "figures": "^2.0.0" - }, - "dependencies": { - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "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": { - "restore-cursor": "^2.0.0" + "color-name": "~1.1.4" } }, - "date-fns": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", - "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==", + "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 }, "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", "dev": true, "requires": { "escape-string-regexp": "^1.0.5" } }, - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "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 }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", "dev": true, "requires": { - "mimic-fn": "^1.0.0" + "aggregate-error": "^3.0.0" } }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", "dev": true, "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" + "has-flag": "^4.0.0" } + }, + "uuid": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz", + "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==", + "dev": true } } }, @@ -10013,6 +9942,26 @@ "type-fest": "^0.5.2" } }, + "loader-utils": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", + "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", + "dev": true, + "requires": { + "big.js": "^3.1.3", + "emojis-list": "^2.0.0", + "json5": "^0.5.0", + "object-assign": "^4.0.1" + }, + "dependencies": { + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + } + } + }, "locate-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", @@ -10035,6 +9984,12 @@ "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", "dev": true }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=", + "dev": true + }, "lodash.capitalize": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz", @@ -10047,12 +10002,6 @@ "integrity": "sha1-ZHYsSGGAglGKw99Mz11YhtriA0c=", "dev": true }, - "lodash.flatmap": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.flatmap/-/lodash.flatmap-4.5.0.tgz", - "integrity": "sha1-74y/QI9uSCaGYzRTBcaswLd4cC4=", - "dev": true - }, "lodash.flattendeep": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", @@ -10065,12 +10014,6 @@ "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", "dev": true }, - "lodash.groupby": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz", - "integrity": "sha1-Cwih3PaDl8OXhVwyOXg4Mt90A9E=", - "dev": true - }, "lodash.ismatch": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", @@ -10089,10 +10032,10 @@ "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=", "dev": true }, - "lodash.set": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", - "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=", + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", "dev": true }, "lodash.sortby": { @@ -10148,90 +10091,67 @@ } }, "log-update": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-2.3.0.tgz", - "integrity": "sha1-iDKP19HOeTiykoN0bwsbwSayRwg=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", + "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", "dev": true, "requires": { - "ansi-escapes": "^3.0.0", - "cli-cursor": "^2.0.0", - "wrap-ansi": "^3.0.1" + "ansi-escapes": "^4.3.0", + "cli-cursor": "^3.1.0", + "slice-ansi": "^4.0.0", + "wrap-ansi": "^6.2.0" }, "dependencies": { - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", "dev": true, "requires": { - "restore-cursor": "^2.0.0" + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" } }, - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true }, - "onetime": { + "color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "requires": { - "mimic-fn": "^1.0.0" + "color-name": "~1.1.4" } }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } + "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 }, - "wrap-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-3.0.1.tgz", - "integrity": "sha1-KIoE2H7aXChuBg3+jxNc6NAH+Lo=", + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0" + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" } } } }, - "log4js": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.1.2.tgz", - "integrity": "sha512-knS4Y30pC1e0n7rfx3VxcLOdBCsEo0o6/C7PVTGxdVK+5b1TYOSGQPn9FDcrhkoQBV29qwmA2mtkznPAQKnxQg==", - "dev": true, - "requires": { - "date-format": "^3.0.0", - "debug": "^4.1.1", - "flatted": "^2.0.1", - "rfdc": "^1.1.4", - "streamroller": "^2.2.3" - } - }, - "lolex": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-5.1.2.tgz", - "integrity": "sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.0" - } - }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -10306,55 +10226,105 @@ "p-defer": "^1.0.0" } }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true - }, "map-obj": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.1.0.tgz", "integrity": "sha512-glc9y00wgtwcDmp7GaE/0b0OnxpNJsVf3ael/An6Fe2Q51LLwN1er6sdomLRzz5h0+yMpiYLhWYF5R7HeqVd4g==", "dev": true }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "requires": { - "object-visit": "^1.0.0" - } - }, "marked": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/marked/-/marked-0.8.2.tgz", - "integrity": "sha512-EGwzEeCcLniFX51DhTpmTom+dSA/MG/OBUDjnWtHbEnjAH180VzUeAw+oE4+Zv+CoYBWyRlYOTR0N8SO9R1PVw==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-1.0.0.tgz", + "integrity": "sha512-Wo+L1pWTVibfrSr+TTtMuiMfNzmZWiOPeO7rZsQUY5bgsxpHesBEcIWJloWVTFnrMXnf/TL30eTFSGJddmQAng==", "dev": true }, "marked-terminal": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-3.3.0.tgz", - "integrity": "sha512-+IUQJ5VlZoAFsM5MHNT7g3RHSkA3eETqhRCdXv4niUMAKHQ7lb1yvAcuGPmm4soxhmtX13u4Li6ZToXtvSEH+A==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-4.0.0.tgz", + "integrity": "sha512-mzU3VD7aVz12FfGoKFAceijehA6Ocjfg3rVimvJbFAB/NOYCsuzRVtq3PSFdPmWI5mhdGeEh3/aMJ5DSxAz94Q==", "dev": true, "requires": { - "ansi-escapes": "^3.1.0", + "ansi-escapes": "^4.3.0", "cardinal": "^2.1.1", - "chalk": "^2.4.1", + "chalk": "^3.0.0", "cli-table": "^0.3.1", - "node-emoji": "^1.4.1", - "supports-hyperlinks": "^1.0.1" + "node-emoji": "^1.10.0", + "supports-hyperlinks": "^2.0.0" }, "dependencies": { "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", + "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "dev": true, + "requires": { + "type-fest": "^0.11.0" + } + }, + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "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.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "type-fest": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", + "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", "dev": true } } }, + "mdn-data": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", + "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==", + "dev": true + }, "mem": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", @@ -10381,162 +10351,37 @@ "dev": true }, "meow": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-5.0.0.tgz", - "integrity": "sha512-CbTqYU17ABaLefO8vCU153ZZlprKYWDljcndKKDCFcYQITzWCXZAVk4QMFZPgvzrnUQ3uItnIE/LoUOwrT15Ig==", - "dev": true, - "requires": { - "camelcase-keys": "^4.0.0", - "decamelize-keys": "^1.0.0", - "loud-rejection": "^1.0.0", - "minimist-options": "^3.0.1", - "normalize-package-data": "^2.3.4", - "read-pkg-up": "^3.0.0", - "redent": "^2.0.0", - "trim-newlines": "^2.0.0", - "yargs-parser": "^10.0.0" + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-7.0.1.tgz", + "integrity": "sha512-tBKIQqVrAHqwit0vfuFPY3LlzJYkEOFyKa3bPgxzNl6q/RtN8KQ+ALYEASYuFayzSAsjlhXj/JZ10rH85Q6TUw==", + "dev": true, + "requires": { + "@types/minimist": "^1.2.0", + "arrify": "^2.0.1", + "camelcase": "^6.0.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "^4.0.2", + "normalize-package-data": "^2.5.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.13.1", + "yargs-parser": "^18.1.3" }, "dependencies": { - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "dev": true - }, "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "dev": true - }, - "camelcase-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-4.2.0.tgz", - "integrity": "sha1-oqpfsa9oh1glnDLBQUJteJI7m3c=", - "dev": true, - "requires": { - "camelcase": "^4.1.0", - "map-obj": "^2.0.0", - "quick-lru": "^1.0.0" - } - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "indent-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", - "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", - "dev": true - }, - "is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", - "dev": true - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "map-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz", - "integrity": "sha1-plzSkIepJZi4eRJXpSPgISIqwfk=", - "dev": true - }, - "minimist-options": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-3.0.2.tgz", - "integrity": "sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ==", - "dev": true, - "requires": { - "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0" - } - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, - "quick-lru": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz", - "integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=", - "dev": true - }, - "read-pkg-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", - "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", - "dev": true, - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^3.0.0" - } - }, - "redent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-2.0.0.tgz", - "integrity": "sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo=", - "dev": true, - "requires": { - "indent-string": "^3.0.0", - "strip-indent": "^2.0.0" - } - }, - "strip-indent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", - "integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.0.0.tgz", + "integrity": "sha512-8KMDF1Vz2gzOq54ONPJS65IvTUaB1cHJ2DMM7MbPmLZljDH1qpzzLsWdiN9pHh6qvkRVDTi/07+eNGch/oLU4w==", "dev": true }, - "trim-newlines": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-2.0.0.tgz", - "integrity": "sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA=", + "type-fest": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", + "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", "dev": true - }, - "yargs-parser": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", - "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", - "dev": true, - "requires": { - "camelcase": "^4.1.0" - } } } }, @@ -10650,27 +10495,6 @@ } } }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, "mkdirp": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", @@ -10846,65 +10670,12 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "multimatch": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-4.0.0.tgz", - "integrity": "sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==", - "dev": true, - "requires": { - "@types/minimatch": "^3.0.3", - "array-differ": "^3.0.0", - "array-union": "^2.1.0", - "arrify": "^2.0.1", - "minimatch": "^3.0.4" - } - }, - "mutation-testing-elements": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/mutation-testing-elements/-/mutation-testing-elements-1.3.1.tgz", - "integrity": "sha512-XXP/enxyOd8X6lK/lu4nlPGLmwH3wfMwj9eatxLp4er0zrmv0p5gGZVkj4KnuuGfp7rnlVNBI/5EZShPJgK3HA==", - "dev": true - }, - "mutation-testing-metrics": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/mutation-testing-metrics/-/mutation-testing-metrics-1.3.0.tgz", - "integrity": "sha512-T7UkUGljyCLMEWGK6YtRTjt4fxqi5+052gjDBkKBR6T5Po6DbwwIx6DAvFyBYzjBzUx6wUhXt7UaxB/wy+JyEg==", - "dev": true, - "requires": { - "mutation-testing-report-schema": "^1.3.0" - } - }, - "mutation-testing-report-schema": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/mutation-testing-report-schema/-/mutation-testing-report-schema-1.3.1.tgz", - "integrity": "sha512-2T2A5qBg+2SZ7CtAvW5m4W95VJxZ/UsSWVwzv3VZpm7c2VoGgIWZGPiTC76a+gorxJobyCzkWv0902UNs4Wl5Q==", - "dev": true - }, "mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - } - }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -10930,16 +10701,15 @@ "dev": true }, "nise": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/nise/-/nise-3.0.1.tgz", - "integrity": "sha512-fYcH9y0drBGSoi88kvhpbZEsenX58Yr+wOJ4/Mi1K4cy+iGP/a73gNoyNhu5E9QxPdgTlVChfIaAlnyOy/gHUA==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nise/-/nise-4.0.3.tgz", + "integrity": "sha512-EGlhjm7/4KvmmE6B/UFsKh7eHykRl9VH+au8dduHLCyWUO/hr7+N+WtTvDUwc9zHuM1IaIJs/0lQ6Ag1jDkQSg==", "dev": true, "requires": { "@sinonjs/commons": "^1.7.0", - "@sinonjs/formatio": "^4.0.1", + "@sinonjs/fake-timers": "^6.0.0", "@sinonjs/text-encoding": "^0.7.1", "just-extend": "^4.0.2", - "lolex": "^5.0.1", "path-to-regexp": "^1.7.0" } }, @@ -11035,9 +10805,9 @@ "dev": true }, "npm": { - "version": "6.14.5", - "resolved": "https://registry.npmjs.org/npm/-/npm-6.14.5.tgz", - "integrity": "sha512-CDwa3FJd0XJpKDbWCST484H+mCNjF26dPrU+xnREW+upR0UODjMEfXPl3bxWuAwZIX6c2ASg1plLO7jP8ehWeA==", + "version": "6.14.4", + "resolved": "https://registry.npmjs.org/npm/-/npm-6.14.4.tgz", + "integrity": "sha512-B8UDDbWvdkW6RgXFn8/h2cHJP/u/FPa4HWeGzW23aNEBARN3QPrRaHqPIZW2NSN3fW649gtgUDNZpaRs0zTMPw==", "dev": true, "requires": { "JSONStream": "^1.3.5", @@ -11069,7 +10839,7 @@ "fs-write-stream-atomic": "~1.0.10", "gentle-fs": "^2.3.0", "glob": "^7.1.6", - "graceful-fs": "^4.2.4", + "graceful-fs": "^4.2.3", "has-unicode": "~2.0.1", "hosted-git-info": "^2.8.8", "iferr": "^1.0.2", @@ -11106,10 +10876,10 @@ "lru-cache": "^5.1.1", "meant": "~1.0.1", "mississippi": "^3.0.0", - "mkdirp": "^0.5.5", + "mkdirp": "^0.5.4", "move-concurrently": "^1.0.1", "node-gyp": "^5.1.0", - "nopt": "^4.0.3", + "nopt": "~4.0.1", "normalize-package-data": "^2.5.0", "npm-audit-report": "^1.3.2", "npm-cache-filename": "~1.0.2", @@ -11119,7 +10889,7 @@ "npm-packlist": "^1.4.8", "npm-pick-manifest": "^3.0.2", "npm-profile": "^4.0.4", - "npm-registry-fetch": "^4.0.4", + "npm-registry-fetch": "^4.0.3", "npm-user-validate": "~1.0.0", "npmlog": "~4.1.2", "once": "~1.4.0", @@ -12292,7 +12062,7 @@ } }, "graceful-fs": { - "version": "4.2.4", + "version": "4.2.3", "bundled": true, "dev": true }, @@ -13055,7 +12825,7 @@ } }, "mkdirp": { - "version": "0.5.5", + "version": "0.5.4", "bundled": true, "dev": true, "requires": { @@ -13133,7 +12903,7 @@ } }, "nopt": { - "version": "4.0.3", + "version": "4.0.1", "bundled": true, "dev": true, "requires": { @@ -13259,7 +13029,7 @@ } }, "npm-registry-fetch": { - "version": "4.0.4", + "version": "4.0.3", "bundled": true, "dev": true, "requires": { @@ -14618,12 +14388,6 @@ "boolbase": "~1.0.0" } }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true - }, "nwsapi": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", @@ -14788,43 +14552,6 @@ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "object-inspect": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", @@ -14843,15 +14570,6 @@ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "requires": { - "isobject": "^3.0.0" - } - }, "object.assign": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", @@ -14939,21 +14657,71 @@ } } }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "object.values": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", + "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", "dev": true, "requires": { - "isobject": "^3.0.1" + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "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.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "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==", + "dev": true + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + } } }, - "octokit-pagination-methods": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/octokit-pagination-methods/-/octokit-pagination-methods-1.1.0.tgz", - "integrity": "sha512-fZ4qZdQ2nxJvtcasX7Ghl+WlWS/d9IgnBIwFZXVNNZUmzpno91SX5bc5vuxiuKoCtK78XxGGNuSCrDC7xYB3OQ==", - "dev": true - }, "omggif": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/omggif/-/omggif-1.0.10.tgz", @@ -15050,9 +14818,9 @@ } }, "p-finally": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz", - "integrity": "sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", "dev": true }, "p-is-promise": { @@ -15098,6 +14866,16 @@ "mimic-fn": "^2.1.0" } }, + "p-queue": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.3.0.tgz", + "integrity": "sha512-fg5dJlFpd5+3CgG3/0ogpVZUeJbjiyXFg0nu53hrOYsybqSiDyxyOpad0Rm6tAiGjgztAwkyvhlYHC53OiAJOA==", + "dev": true, + "requires": { + "eventemitter3": "^4.0.0", + "p-timeout": "^3.1.0" + } + }, "p-reduce": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-2.1.0.tgz", @@ -15114,6 +14892,15 @@ "retry": "^0.12.0" } }, + "p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "dev": true, + "requires": { + "p-finally": "^1.0.0" + } + }, "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -15152,6 +14939,15 @@ } } }, + "pad": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/pad/-/pad-3.2.0.tgz", + "integrity": "sha512-2u0TrjcGbOjBTJpyewEl4hBO3OeX5wWue7eIFPzQTg6wFSvoaHcBTTUY5m+n0hd04gmTCPuY0kCpVIVuw5etwg==", + "dev": true, + "requires": { + "wcwidth": "^1.0.1" + } + }, "pageres": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/pageres/-/pageres-5.2.0.tgz", @@ -15250,12 +15046,6 @@ "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", "dev": true }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true - }, "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -15395,221 +15185,1493 @@ "integrity": "sha1-ISZRTKbyq/69FoWW3xi6V4Z/AFg=", "dev": true, "requires": { - "find-up": "^2.0.0", - "load-json-file": "^4.0.0" + "find-up": "^2.0.0", + "load-json-file": "^4.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } + } + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + } + } + }, + "please-upgrade-node": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", + "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", + "dev": true, + "requires": { + "semver-compare": "^1.0.0" + } + }, + "plur": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/plur/-/plur-3.1.1.tgz", + "integrity": "sha512-t1Ax8KUvV3FFII8ltczPn2tJdjqbd1sIzu6t4JL7nQ3EyeL/lTrj5PWKb06ic5/6XYDr65rQ4uzQEGN70/6X5w==", + "dev": true, + "requires": { + "irregular-plurals": "^2.0.0" + } + }, + "pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true + }, + "pngjs": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", + "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==", + "dev": true + }, + "postcss": { + "version": "6.0.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", + "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "postcss-assets": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-assets/-/postcss-assets-5.0.0.tgz", + "integrity": "sha1-9yHQfTOWBftYQU6fac8FQBxU5wk=", + "dev": true, + "requires": { + "assets": "^3.0.0", + "bluebird": "^3.5.0", + "postcss": "^6.0.10", + "postcss-functions": "^3.0.0" + } + }, + "postcss-calc": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.2.tgz", + "integrity": "sha512-rofZFHUg6ZIrvRwPeFktv06GdbDYLcGqh9EwiMutZg+a0oePCCw1zHOEiji6LCpyRcjTREtPASuUqeAvYlEVvQ==", + "dev": true, + "requires": { + "postcss": "^7.0.27", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.0.2" + }, + "dependencies": { + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-value-parser": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.0.3.tgz", + "integrity": "sha512-N7h4pG+Nnu5BEIzyeaaIYWs0LI5XC40OrRh5L60z0QjFsqGWcHcbkBvpe1WYpcIS9yQ8sOi/vIPt1ejQCrMVrg==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-colormin": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz", + "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "color": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-convert-values": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz", + "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", + "dev": true, + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-discard-comments": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz", + "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-discard-duplicates": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz", + "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-discard-empty": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz", + "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-discard-overridden": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz", + "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-functions": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-functions/-/postcss-functions-3.0.0.tgz", + "integrity": "sha1-DpTQFERwCkgd4g3k1V+yZAVkJQ4=", + "dev": true, + "requires": { + "glob": "^7.1.2", + "object-assign": "^4.1.1", + "postcss": "^6.0.9", + "postcss-value-parser": "^3.3.0" + } + }, + "postcss-load-config": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.0.tgz", + "integrity": "sha512-4pV3JJVPLd5+RueiVVB+gFOAa7GWc25XQcMp86Zexzke69mKf6Nx9LRcQywdz7yZI9n1udOxmLuAwTBypypF8Q==", + "dev": true, + "requires": { + "cosmiconfig": "^5.0.0", + "import-cwd": "^2.0.0" + }, + "dependencies": { + "import-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", + "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=", + "dev": true, + "requires": { + "import-from": "^2.1.0" + } + }, + "import-from": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz", + "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + } + } + }, + "postcss-merge-longhand": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz", + "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==", + "dev": true, + "requires": { + "css-color-names": "0.0.4", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "stylehacks": "^4.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-merge-rules": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz", + "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "cssnano-util-same-parent": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0", + "vendors": "^1.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "dev": true, + "requires": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-minify-font-values": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz", + "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", + "dev": true, + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-minify-gradients": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz", + "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "is-color-stop": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-minify-params": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz", + "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==", + "dev": true, + "requires": { + "alphanum-sort": "^1.0.0", + "browserslist": "^4.0.0", + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "uniqs": "^2.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-minify-selectors": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz", + "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==", + "dev": true, + "requires": { + "alphanum-sort": "^1.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "dev": true, + "requires": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-2.0.0.tgz", + "integrity": "sha512-eqp+Bva+U2cwQO7dECJ8/V+X+uH1HduNeITB0CPPFAu6d/8LKQ32/j+p9rQ2YL1QytVcrNU0X+fBqgGmQIA1Rw==", + "dev": true, + "requires": { + "css-modules-loader-core": "^1.1.0", + "generic-names": "^2.0.1", + "lodash.camelcase": "^4.3.0", + "postcss": "^7.0.1", + "string-hash": "^1.1.1" + }, + "dependencies": { + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true + }, + "generic-names": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generic-names/-/generic-names-2.0.1.tgz", + "integrity": "sha512-kPCHWa1m9wGG/OwQpeweTwM/PYiQLrUIxXbt/P4Nic3LbGjCP0YwrALHW1uNLKZ0LIMg+RF+XRlj2ekT9ZlZAQ==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0" + } + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + }, + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-modules-extract-imports": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.1.tgz", + "integrity": "sha512-6jt9XZwUhwmRUhb/CkyJY020PYaPJsCyt3UjbaWo6XEbH/94Hmv6MP7fG2C5NDU/BcHzyGYxNtHvM+LTf9HrYw==", + "dev": true, + "requires": { + "postcss": "^6.0.1" + } + }, + "postcss-modules-local-by-default": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz", + "integrity": "sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk=", + "dev": true, + "requires": { + "css-selector-tokenizer": "^0.7.0", + "postcss": "^6.0.1" + } + }, + "postcss-modules-resolve-imports": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/postcss-modules-resolve-imports/-/postcss-modules-resolve-imports-1.3.0.tgz", + "integrity": "sha1-OY0wALla6WlCDN9M2D+oBn8cXq4=", + "dev": true, + "requires": { + "css-selector-tokenizer": "^0.7.0", + "icss-utils": "^3.0.1", + "minimist": "^1.2.0" + } + }, + "postcss-modules-scope": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz", + "integrity": "sha1-1upkmUx5+XtipytCb75gVqGUu5A=", + "dev": true, + "requires": { + "css-selector-tokenizer": "^0.7.0", + "postcss": "^6.0.1" + } + }, + "postcss-modules-values": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz", + "integrity": "sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA=", + "dev": true, + "requires": { + "icss-replace-symbols": "^1.1.0", + "postcss": "^6.0.1" + } + }, + "postcss-normalize-charset": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz", + "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-normalize-display-values": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz", + "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==", + "dev": true, + "requires": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-normalize-positions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz", + "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-normalize-repeat-style": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz", + "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==", + "dev": true, + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-normalize-string": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz", + "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==", + "dev": true, + "requires": { + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-normalize-timing-functions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz", + "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==", + "dev": true, + "requires": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-normalize-unicode": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz", + "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" }, "dependencies": { - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", "dev": true, "requires": { - "locate-path": "^2.0.0" + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" } }, - "load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" + "has-flag": "^3.0.0" } + } + } + }, + "postcss-normalize-url": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz", + "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", + "dev": true, + "requires": { + "is-absolute-url": "^2.0.0", + "normalize-url": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "normalize-url": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", + "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==", + "dev": true }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", "dev": true, "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" } }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", "dev": true, "requires": { - "p-try": "^1.0.0" + "has-flag": "^3.0.0" } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + } + } + }, + "postcss-normalize-whitespace": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz", + "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==", + "dev": true, + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", "dev": true, "requires": { - "p-limit": "^1.1.0" + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" } }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } } } }, - "pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "postcss-ordered-values": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz", + "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==", "dev": true, "requires": { - "find-up": "^3.0.0" + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, - "pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", - "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "postcss-reduce-initial": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz", + "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==", "dev": true, "requires": { - "find-up": "^2.1.0" + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0" }, "dependencies": { - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", "dev": true, "requires": { - "locate-path": "^2.0.0" + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" } }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", "dev": true, "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" + "has-flag": "^3.0.0" } - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + } + } + }, + "postcss-reduce-transforms": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz", + "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==", + "dev": true, + "requires": { + "cssnano-util-get-match": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", "dev": true, "requires": { - "p-try": "^1.0.0" + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" } }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", "dev": true, "requires": { - "p-limit": "^1.1.0" + "has-flag": "^3.0.0" } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true } } }, - "please-upgrade-node": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", - "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", + "postcss-selector-parser": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz", + "integrity": "sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg==", "dev": true, "requires": { - "semver-compare": "^1.0.0" + "cssesc": "^3.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + }, + "dependencies": { + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true + } } }, - "plur": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/plur/-/plur-3.1.1.tgz", - "integrity": "sha512-t1Ax8KUvV3FFII8ltczPn2tJdjqbd1sIzu6t4JL7nQ3EyeL/lTrj5PWKb06ic5/6XYDr65rQ4uzQEGN70/6X5w==", + "postcss-svgo": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.2.tgz", + "integrity": "sha512-C6wyjo3VwFm0QgBy+Fu7gCYOkCmgmClghO+pjcxvrcBKtiKt0uCF+hvbMO1fyv5BMImRK90SMb+dwUnfbGd+jw==", "dev": true, "requires": { - "irregular-plurals": "^2.0.0" - } - }, - "pluralize": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", - "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", - "dev": true - }, - "pngjs": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", - "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==", - "dev": true - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true - }, - "postcss": { - "version": "6.0.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", - "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", + "is-svg": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "svgo": "^1.0.0" + }, + "dependencies": { + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-unique-selectors": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz", + "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", "dev": true, "requires": { - "chalk": "^2.4.1", - "source-map": "^0.6.1", - "supports-color": "^5.4.0" + "alphanum-sort": "^1.0.0", + "postcss": "^7.0.0", + "uniqs": "^2.0.0" }, "dependencies": { + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } } } }, - "postcss-assets": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-assets/-/postcss-assets-5.0.0.tgz", - "integrity": "sha1-9yHQfTOWBftYQU6fac8FQBxU5wk=", - "dev": true, - "requires": { - "assets": "^3.0.0", - "bluebird": "^3.5.0", - "postcss": "^6.0.10", - "postcss-functions": "^3.0.0" - } - }, - "postcss-functions": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-functions/-/postcss-functions-3.0.0.tgz", - "integrity": "sha1-DpTQFERwCkgd4g3k1V+yZAVkJQ4=", - "dev": true, - "requires": { - "glob": "^7.1.2", - "object-assign": "^4.1.1", - "postcss": "^6.0.9", - "postcss-value-parser": "^3.3.0" - } - }, "postcss-value-parser": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", @@ -15629,9 +16691,9 @@ "dev": true }, "prettier": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", - "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.0.5.tgz", + "integrity": "sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg==", "dev": true }, "prettier-linter-helpers": { @@ -15685,6 +16747,12 @@ "is-promise": "~1" } }, + "promise.series": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/promise.series/-/promise.series-0.2.0.tgz", + "integrity": "sha1-LMfr6Vn8OmYZwEq029yeRS2GS70=", + "dev": true + }, "proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -15785,12 +16853,6 @@ "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", "dev": true }, - "qs": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", - "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==", - "dev": true - }, "query-string": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", @@ -16047,16 +17109,6 @@ "private": "^0.1.8" } }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, "regexpp": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", @@ -16133,18 +17185,6 @@ "es6-error": "^4.0.1" } }, - "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true - }, "repeating": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", @@ -16267,32 +17307,6 @@ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, - "resolve-global": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-global/-/resolve-global-1.0.0.tgz", - "integrity": "sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw==", - "dev": true, - "requires": { - "global-dirs": "^0.1.1" - }, - "dependencies": { - "global-dirs": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", - "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", - "dev": true, - "requires": { - "ini": "^1.3.4" - } - } - } - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true - }, "responselike": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", @@ -16312,12 +17326,6 @@ "signal-exit": "^3.0.2" } }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true - }, "retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", @@ -16330,10 +17338,16 @@ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true }, - "rfdc": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.1.4.tgz", - "integrity": "sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug==", + "rgb-regex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz", + "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=", + "dev": true + }, + "rgba-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz", + "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=", "dev": true }, "rimraf": { @@ -16346,16 +17360,20 @@ } }, "rollup": { - "version": "1.32.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.32.1.tgz", - "integrity": "sha512-/2HA0Ec70TvQnXdzynFffkjA6XN+1e2pEv/uKS5Ulca40g2L7KuOE3riasHoNVHOsFD5KKZgDsMk1CP3Tw9s+A==", + "version": "2.10.8", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.10.8.tgz", + "integrity": "sha512-lbowcWxla8CNBNvCVnmZnoZzugM1g9yd7fd7oc5eWIdI4wECzpIpEJLBoeD+9UITwnnt1X3b9bt7gdZHC+rRAg==", "dev": true, "requires": { - "@types/estree": "*", - "@types/node": "*", - "acorn": "^7.1.0" + "fsevents": "~2.1.2" } }, + "rollup-plugin-analyzer": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/rollup-plugin-analyzer/-/rollup-plugin-analyzer-3.2.3.tgz", + "integrity": "sha512-Oq5GtofTCIGhW4mDNtnxH106gvPKQcdAKTLujWekAiLiTmstXX9Fmye7uMG7NaZVBHgKPPsIWCtPj04ci/YXmg==", + "dev": true + }, "rollup-plugin-babel": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/rollup-plugin-babel/-/rollup-plugin-babel-4.4.0.tgz", @@ -16366,82 +17384,224 @@ "rollup-pluginutils": "^2.8.1" } }, - "rollup-plugin-commonjs": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-commonjs/-/rollup-plugin-commonjs-10.1.0.tgz", - "integrity": "sha512-jlXbjZSQg8EIeAAvepNwhJj++qJWNJw1Cl0YnOqKtP5Djx+fFGkp3WRh+W0ASCaFG5w1jhmzDxgu3SJuVxPF4Q==", + "rollup-plugin-copy": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-copy/-/rollup-plugin-copy-3.3.0.tgz", + "integrity": "sha512-euDjCUSBXZa06nqnwCNADbkAcYDfzwowfZQkto9K/TFhiH+QG7I4PUsEMwM9tDgomGWJc//z7KLW8t+tZwxADA==", "dev": true, "requires": { - "estree-walker": "^0.6.1", - "is-reference": "^1.1.2", - "magic-string": "^0.25.2", - "resolve": "^1.11.0", - "rollup-pluginutils": "^2.8.1" + "@types/fs-extra": "^8.0.1", + "colorette": "^1.1.0", + "fs-extra": "^8.1.0", + "globby": "10.0.1", + "is-plain-object": "^3.0.0" + }, + "dependencies": { + "is-plain-object": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.0.tgz", + "integrity": "sha512-tZIpofR+P05k8Aocp7UI/2UTa9lTJSebCXpFFoR9aibpokDj/uXBsJ8luUu0tTVYKkMU6URDUuOfJZ7koewXvg==", + "dev": true, + "requires": { + "isobject": "^4.0.0" + } + }, + "isobject": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-4.0.0.tgz", + "integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==", + "dev": true + } } }, - "rollup-plugin-copy-glob": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/rollup-plugin-copy-glob/-/rollup-plugin-copy-glob-0.3.1.tgz", - "integrity": "sha512-W/M2oVts6Sri/1/kSvDrBD0oWjrxcPu8w8E+jJ9QtPxBjqOHirljn3A38qREzXg4Vy69xhR3CZyQlZgqzL1UDA==", + "rollup-plugin-postcss": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-postcss/-/rollup-plugin-postcss-3.1.1.tgz", + "integrity": "sha512-4/FO5/2O5kv2uWRd7PPTN4mBCWoHwwFTnpEGokfPKfj6kygvTORqkBWNgVPXi7bBefNKtMA3FqQ10se6/J8kKw==", "dev": true, "requires": { - "chokidar": "3.0.2", - "colors": "1.3.3", - "glob": "7.1.4", - "glob-parent": "5.0.0" + "chalk": "^4.0.0", + "concat-with-sourcemaps": "^1.1.0", + "cssnano": "^4.1.10", + "import-cwd": "^3.0.0", + "p-queue": "^6.3.0", + "pify": "^5.0.0", + "postcss": "^7.0.27", + "postcss-load-config": "^2.1.0", + "postcss-modules": "^2.0.0", + "promise.series": "^0.2.0", + "resolve": "^1.16.1", + "rollup-pluginutils": "^2.8.2", + "safe-identifier": "^0.4.1", + "style-inject": "^0.3.0" }, "dependencies": { - "chokidar": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.0.2.tgz", - "integrity": "sha512-c4PR2egjNjI1um6bamCQ6bUNPDiyofNQruHvKgHQ4gDUP/ITSVSzNsiI5OWtHOsX323i5ha/kk4YmOZ1Ktg7KA==", + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz", + "integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==", + "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": { - "anymatch": "^3.0.1", - "braces": "^3.0.2", - "fsevents": "^2.0.6", - "glob-parent": "^5.0.0", - "is-binary-path": "^2.1.0", - "is-glob": "^4.0.1", - "normalize-path": "^3.0.0", - "readdirp": "^3.1.1" + "color-name": "~1.1.4" } }, - "glob-parent": { + "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 + }, + "pify": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.0.0.tgz", - "integrity": "sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg==", + "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz", + "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", + "dev": true + }, + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "rollup-pluginutils": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", + "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", + "dev": true, + "requires": { + "estree-walker": "^0.6.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", "dev": true, "requires": { - "is-glob": "^4.0.1" + "has-flag": "^4.0.0" } } } }, - "rollup-plugin-node-resolve": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz", - "integrity": "sha512-jUlyaDXts7TW2CqQ4GaO5VJ4PwwaV8VUGA7+km3n6k6xtOEacf61u0VXwN80phY/evMcaS+9eIeJ9MOyDxt5Zw==", - "dev": true, - "requires": { - "@types/resolve": "0.0.8", - "builtin-modules": "^3.1.0", - "is-module": "^1.0.0", - "resolve": "^1.11.1", - "rollup-pluginutils": "^2.8.1" - } - }, "rollup-plugin-terser": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-5.3.0.tgz", - "integrity": "sha512-XGMJihTIO3eIBsVGq7jiNYOdDMb3pVxuzY0uhOE/FM4x/u9nQgr3+McsjzqBn3QfHIpNSZmFnpoKAwHBEcsT7g==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-6.0.1.tgz", + "integrity": "sha512-XUPB2wwtgQV0A1eq4HXavfkOYL8MqX2ghU3uxvjRQYbUo0QEE3Tjupk7d7hNd1Yfm91xrpQHlbnVI01sf2s3bA==", "dev": true, "requires": { - "@babel/code-frame": "^7.5.5", - "jest-worker": "^24.9.0", - "rollup-pluginutils": "^2.8.2", - "serialize-javascript": "^2.1.2", - "terser": "^4.6.2" + "@babel/code-frame": "^7.8.3", + "jest-worker": "^26.0.0", + "serialize-javascript": "^3.0.0", + "terser": "^4.7.0" }, "dependencies": { "@babel/code-frame": { @@ -16463,29 +17623,20 @@ "chalk": "^2.0.0", "js-tokens": "^4.0.0" } - }, - "rollup-pluginutils": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", - "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", - "dev": true, - "requires": { - "estree-walker": "^0.6.1" - } } } }, "rollup-plugin-typescript2": { - "version": "0.25.3", - "resolved": "https://registry.npmjs.org/rollup-plugin-typescript2/-/rollup-plugin-typescript2-0.25.3.tgz", - "integrity": "sha512-ADkSaidKBovJmf5VBnZBZe+WzaZwofuvYdzGAKTN/J4hN7QJCFYAq7IrH9caxlru6T5qhX41PNFS1S4HqhsGQg==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-typescript2/-/rollup-plugin-typescript2-0.27.1.tgz", + "integrity": "sha512-RJl77Bbj1EunAQDC3dK/O2HWuSUX3oJbRGzyLoS5o9W4Hs1Nix3Gavqj1Lzs5Y6Ff4H2xXfmZ1WWUQCYocSbzQ==", "dev": true, "requires": { - "find-cache-dir": "^3.0.0", + "@rollup/pluginutils": "^3.0.8", + "find-cache-dir": "^3.3.1", "fs-extra": "8.1.0", - "resolve": "1.12.0", - "rollup-pluginutils": "2.8.1", - "tslib": "1.10.0" + "resolve": "1.15.1", + "tslib": "1.11.2" }, "dependencies": { "find-cache-dir": { @@ -16552,9 +17703,9 @@ } }, "resolve": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", - "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", + "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", "dev": true, "requires": { "path-parse": "^1.0.6" @@ -16565,6 +17716,12 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true + }, + "tslib": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.2.tgz", + "integrity": "sha512-tTSkux6IGPnUGUd1XAZHcpu85MOkIl5zX49pO+jfsie3eP0B6pyhOlLXm3cAC6T7s+euSDDUUV+Acop5WmtkVg==", + "dev": true } } }, @@ -16604,14 +17761,11 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "requires": { - "ret": "~0.1.10" - } + "safe-identifier": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/safe-identifier/-/safe-identifier-0.4.1.tgz", + "integrity": "sha512-73tOz5TXsq3apuCc3vC8c9QRhhdNZGiBhHmPPjqpH4TO5oCDqk8UIsDcSs/RG6dYcFAkOOva0pqHS3u7hh7XXA==", + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -16634,17 +17788,23 @@ "xmlchars": "^2.2.0" } }, + "seekout": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/seekout/-/seekout-1.0.2.tgz", + "integrity": "sha1-CbqfG9W0b7sTRxjrGaaDgsuxuck=", + "dev": true + }, "semantic-release": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-16.0.4.tgz", - "integrity": "sha512-qiYHTNStxUs0UUb45ImRIid0Z8HsXwMNbpZXLvABs725SrxtZBgfuemaABnHdKDg7KBsuQMlSdZENaYLvkMqUg==", + "version": "17.0.7", + "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-17.0.7.tgz", + "integrity": "sha512-F6FzJI1yiGavzCTXir4yPthK/iozZPJ4myUYndiHhSHbmOcCSJ2m7V+P6sFwVpDpQKQp1Q31M68sTJ/Q/27Bow==", "dev": true, "requires": { - "@semantic-release/commit-analyzer": "^7.0.0", + "@semantic-release/commit-analyzer": "^8.0.0", "@semantic-release/error": "^2.2.0", - "@semantic-release/github": "^6.0.0", - "@semantic-release/npm": "^6.0.0", - "@semantic-release/release-notes-generator": "^7.1.2", + "@semantic-release/github": "^7.0.0", + "@semantic-release/npm": "^7.0.0", + "@semantic-release/release-notes-generator": "^9.0.0", "aggregate-error": "^3.0.0", "cosmiconfig": "^6.0.0", "debug": "^4.0.0", @@ -16657,14 +17817,14 @@ "hook-std": "^2.0.0", "hosted-git-info": "^3.0.0", "lodash": "^4.17.15", - "marked": "^0.8.0", - "marked-terminal": "^3.2.0", + "marked": "^1.0.0", + "marked-terminal": "^4.0.0", "micromatch": "^4.0.2", "p-each-series": "^2.1.0", "p-reduce": "^2.0.0", "read-pkg-up": "^7.0.0", "resolve-from": "^5.0.0", - "semver": "^7.1.1", + "semver": "^7.3.2", "semver-diff": "^3.1.1", "signale": "^1.2.1", "yargs": "^15.0.1" @@ -16683,6 +17843,25 @@ "yaml": "^1.7.2" } }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, "hosted-git-info": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.4.tgz", @@ -16692,12 +17871,30 @@ "lru-cache": "^5.1.1" } }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, "lodash": { "version": "4.17.15", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "dev": true }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, "parse-json": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", @@ -16710,12 +17907,49 @@ "lines-and-columns": "^1.1.6" } }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true + } + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + } + }, "resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -16727,6 +17961,12 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", "dev": true + }, + "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 } } }, @@ -16766,9 +18006,9 @@ "dev": true }, "serialize-javascript": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz", - "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-3.0.0.tgz", + "integrity": "sha512-skZcHYw2vEX4bw90nAr2iTTsz6x2SrHEnfxgKYmZlvJYBEZrvbKtobJWlQ20zczKb3bsHHXXTYt48zBA7ni9cw==", "dev": true }, "set-blocking": { @@ -16777,29 +18017,6 @@ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -16859,31 +18076,37 @@ "chalk": "^2.3.2", "figures": "^2.0.0", "pkg-conf": "^2.1.0" + } + }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "dev": true, + "requires": { + "is-arrayish": "^0.3.1" }, "dependencies": { - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "dev": true } } }, "sinon": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-8.1.1.tgz", - "integrity": "sha512-E+tWr3acRdoe1nXbHMu86SSqA1WGM7Yw3jZRLvlCMnXwTHP8lgFFVn5BnKnF26uc5SfZ3D7pA9sN7S3Y2jG4Ew==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.0.2.tgz", + "integrity": "sha512-0uF8Q/QHkizNUmbK3LRFqx5cpTttEVXudywY9Uwzy8bTfZUhljZ7ARzSxnRHWYWtVTeh4Cw+tTb3iU21FQVO9A==", "dev": true, "requires": { - "@sinonjs/commons": "^1.7.0", - "@sinonjs/formatio": "^4.0.1", - "@sinonjs/samsam": "^4.2.2", + "@sinonjs/commons": "^1.7.2", + "@sinonjs/fake-timers": "^6.0.1", + "@sinonjs/formatio": "^5.0.1", + "@sinonjs/samsam": "^5.0.3", "diff": "^4.0.2", - "lolex": "^5.1.2", - "nise": "^3.0.1", + "nise": "^4.0.1", "supports-color": "^7.1.0" }, "dependencies": { @@ -17028,134 +18251,6 @@ "snap-shot-core": "10.2.0" } }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "requires": { - "kind-of": "^3.2.0" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "sort-keys": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-3.0.0.tgz", @@ -17171,19 +18266,6 @@ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true }, - "source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "dev": true, - "requires": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, "source-map-support": { "version": "0.5.16", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", @@ -17202,12 +18284,6 @@ } } }, - "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", - "dev": true - }, "sourcemap-codec": { "version": "1.4.6", "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.6.tgz", @@ -17301,15 +18377,6 @@ "through": "2" } }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.0" - } - }, "split2": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-2.2.0.tgz", @@ -17317,18 +18384,6 @@ "dev": true, "requires": { "through2": "^2.0.2" - }, - "dependencies": { - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - } } }, "sprintf-js": { @@ -17354,26 +18409,11 @@ "tweetnacl": "~0.14.0" } }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } + "stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "dev": true }, "stealthy-require": { "version": "1.1.1", @@ -17391,25 +18431,6 @@ "readable-stream": "^2.0.2" } }, - "streamroller": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-2.2.4.tgz", - "integrity": "sha512-OG79qm3AujAM9ImoqgWEY1xG4HX+Lw+yY6qZj9R1K2mhF5bEmQ849wvrb+4vt4jLMLzwXttJlQbOdPOQVRv7DQ==", - "dev": true, - "requires": { - "date-format": "^2.1.0", - "debug": "^4.1.1", - "fs-extra": "^8.1.0" - }, - "dependencies": { - "date-format": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz", - "integrity": "sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA==", - "dev": true - } - } - }, "strict-uri-encode": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", @@ -17422,6 +18443,12 @@ "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==", "dev": true }, + "string-hash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", + "integrity": "sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs=", + "dev": true + }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", @@ -17540,106 +18567,58 @@ "integrity": "sha1-IrD6OkE4WzO+PzMVUbu4N/oM164=", "dev": true }, - "stryker-cli": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stryker-cli/-/stryker-cli-1.0.0.tgz", - "integrity": "sha512-PTeMKADJXNH1hEXd4OeqPbOKD/now6mepABuDkUyA/0OQpT02hBZ06JZEWz5LoTWZmefxMlERfEHWBmgaZvRlQ==", + "style-inject": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/style-inject/-/style-inject-0.3.0.tgz", + "integrity": "sha512-IezA2qp+vcdlhJaVm5SOdPPTUu0FCEqfNSli2vRuSIBbu5Nq5UvygTk/VzeCqfLz2Atj3dVII5QBKGZRZ0edzw==", + "dev": true + }, + "stylehacks": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz", + "integrity": "sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==", "dev": true, "requires": { - "chalk": "^2.4.2", - "inquirer": "^6.2.2", - "resolve": "^1.10.0" + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" }, "dependencies": { - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true - }, - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "inquirer": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", - "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", "dev": true, "requires": { - "ansi-escapes": "^3.2.0", "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^2.0.0", - "lodash": "^4.17.12", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^6.4.0", - "string-width": "^2.1.0", - "strip-ansi": "^5.1.0", - "through": "^2.3.6" + "source-map": "^0.6.1", + "supports-color": "^6.1.0" } }, - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true - }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", - "dev": true - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", "dev": true, "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" } }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", "dev": true, "requires": { - "ansi-regex": "^4.1.0" + "has-flag": "^3.0.0" } } } @@ -17654,34 +18633,82 @@ } }, "supports-hyperlinks": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-1.0.1.tgz", - "integrity": "sha512-HHi5kVSefKaJkGYXbDuKbUGRVxqnWGn3J2e39CYcNJEfWciGq2zYtOhXLTlvrOZW1QU7VX67w7fMmWafHX9Pfw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz", + "integrity": "sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA==", "dev": true, "requires": { - "has-flag": "^2.0.0", - "supports-color": "^5.0.0" + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" }, "dependencies": { "has-flag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "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.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } } } }, - "surrial": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/surrial/-/surrial-1.0.0.tgz", - "integrity": "sha512-dkvhz3QvgraMeFWI9V+BinpNCNoaSNxKcxb0umRpkWeFlZ0WSbIfeTm9YtLA6a4kv/Q2pOMQOtMlcv/b5h6qpg==", - "dev": true - }, - "symbol-observable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", - "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", - "dev": true + "svgo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", + "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "coa": "^2.0.2", + "css-select": "^2.0.0", + "css-select-base-adapter": "^0.1.1", + "css-tree": "1.0.0-alpha.37", + "csso": "^4.0.2", + "js-yaml": "^3.13.1", + "mkdirp": "~0.5.1", + "object.values": "^1.1.0", + "sax": "~1.2.4", + "stable": "^0.1.8", + "unquote": "~1.1.1", + "util.promisify": "~1.0.0" + }, + "dependencies": { + "css-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", + "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^3.2.1", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" + } + }, + "css-what": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.2.1.tgz", + "integrity": "sha512-WwOrosiQTvyms+Ti5ZC5vGEK0Vod3FTt1ca+payZqvKuGJF+dq7bG63DstxtN0dpm6FxY27a/zS3Wten+gEtGw==", + "dev": true + }, + "domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "dev": true, + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + } + } }, "symbol-tree": { "version": "3.2.4", @@ -17730,42 +18757,34 @@ } }, "temp-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz", - "integrity": "sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", "dev": true }, "tempy": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.3.0.tgz", - "integrity": "sha512-WrH/pui8YCwmeiAoxV+lpRH9HpRtgBhSR2ViBPgpGb/wnYDzp21R4MN45fsCGvLROvY67o3byhJRYRONJyImVQ==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.5.0.tgz", + "integrity": "sha512-VEY96x7gbIRfsxqsafy2l5yVxxp3PhwAGoWMyC2D2Zt5DmEv+2tGiPOrquNRpf21hhGnKLVEsuqleqiZmKG/qw==", "dev": true, "requires": { - "temp-dir": "^1.0.0", - "type-fest": "^0.3.1", - "unique-string": "^1.0.0" + "is-stream": "^2.0.0", + "temp-dir": "^2.0.0", + "type-fest": "^0.12.0", + "unique-string": "^2.0.0" }, "dependencies": { - "crypto-random-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", - "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", "dev": true }, "type-fest": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", - "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.12.0.tgz", + "integrity": "sha512-53RyidyjvkGpnWPMF9bQgFtWp+Sl8O2Rp13VavmJgfAP9WWG6q6TkrKU8iyJdnwnfgHI6k2hTlgqH4aSdjoTbg==", "dev": true - }, - "unique-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", - "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", - "dev": true, - "requires": { - "crypto-random-string": "^1.0.0" - } } } }, @@ -17786,12 +18805,6 @@ "source-map-support": "~0.5.12" }, "dependencies": { - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -17830,12 +18843,13 @@ "dev": true }, "through2": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", - "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", "dev": true, "requires": { - "readable-stream": "2 || 3" + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" } }, "timed-out": { @@ -17850,6 +18864,12 @@ "integrity": "sha512-IH3DYDL1wMUwmIlVmMrmesw5lZD6N+ZOAFWEyLrtpoL9Bcrs9u7M/vyOnHzDD2SMs4irLkVjqxZbHrXStS/Nmw==", "dev": true }, + "timsort": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", + "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", + "dev": true + }, "tinycolor2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.1.tgz", @@ -17871,50 +18891,12 @@ "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", "dev": true }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "to-readable-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", "dev": true }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -17950,12 +18932,6 @@ "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=", "dev": true }, - "tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "dev": true - }, "trim-newlines": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.0.tgz", @@ -17992,12 +18968,6 @@ "tslib": "^1.8.1" } }, - "tunnel": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", - "dev": true - }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -18034,26 +19004,6 @@ "integrity": "sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw==", "dev": true }, - "typed-inject": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/typed-inject/-/typed-inject-2.1.1.tgz", - "integrity": "sha512-TaQrNsYjGTMmgfEwKtjP9+qyZu//H1RJ0RYNvvQ/rcAnpQGZLxHajb+O6TnyFZGfLaK/9319VYaG4PFXGjImug==", - "dev": true, - "requires": { - "typescript": "^3.6.3" - } - }, - "typed-rest-client": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.7.3.tgz", - "integrity": "sha512-CwTpx/TkRHGZoHkJhBcp4X8K3/WtlzSHVQR0OIFnt10j4tgy4ypgq/SrrgVpA1s6tAL49Q6J3R5C0Cgfh2ddqA==", - "dev": true, - "requires": { - "qs": "^6.9.1", - "tunnel": "0.0.6", - "underscore": "1.8.3" - } - }, "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", @@ -18070,22 +19020,21 @@ } }, "typedoc": { - "version": "0.16.11", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.16.11.tgz", - "integrity": "sha512-YEa5i0/n0yYmLJISJ5+po6seYfJQJ5lQYcHCPF9ffTF92DB/TAZO/QrazX5skPHNPtmlIht5FdTXCM2kC7jQFQ==", + "version": "0.17.7", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.17.7.tgz", + "integrity": "sha512-PEnzjwQAGjb0O8a6VDE0lxyLAadqNujN5LltsTUhZETolRMiIJv6Ox+Toa8h0XhKHqAOh8MOmB0eBVcWz6nuAw==", "dev": true, "requires": { - "@types/minimatch": "3.0.3", "fs-extra": "^8.1.0", - "handlebars": "^4.7.2", - "highlight.js": "^9.17.1", + "handlebars": "^4.7.6", + "highlight.js": "^10.0.0", "lodash": "^4.17.15", - "marked": "^0.8.0", + "lunr": "^2.3.8", + "marked": "1.0.0", "minimatch": "^3.0.0", "progress": "^2.0.3", - "shelljs": "^0.8.3", - "typedoc-default-themes": "^0.7.2", - "typescript": "3.7.x" + "shelljs": "^0.8.4", + "typedoc-default-themes": "^0.10.1" }, "dependencies": { "lodash": { @@ -18093,33 +19042,16 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "dev": true - }, - "typescript": { - "version": "3.7.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.5.tgz", - "integrity": "sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==", - "dev": true } } }, "typedoc-default-themes": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.7.2.tgz", - "integrity": "sha512-fiFKlFO6VTqjcno8w6WpTsbCgXmfPHVjnLfYkmByZE7moaz+E2DSpAT+oHtDHv7E0BM5kAhPrHJELP2J2Y2T9A==", + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.10.1.tgz", + "integrity": "sha512-SuqAQI0CkwhqSJ2kaVTgl37cWs733uy9UGUqwtcds8pkFK8oRF4rZmCq+FXTGIb9hIUOu40rf5Kojg0Ha6akeg==", "dev": true, "requires": { - "backbone": "^1.4.0", - "jquery": "^3.4.1", - "lunr": "^2.3.8", - "underscore": "^1.9.1" - }, - "dependencies": { - "underscore": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.10.2.tgz", - "integrity": "sha512-N4P+Q/BuyuEKFJ43B9gYuOj4TQUHXX+j2FqguVOpjkssLUUrnJofCcBccJSCoeturDoZU6GorDTHSvUDlSQbTg==", - "dev": true - } + "lunr": "^2.3.8" } }, "typescript": { @@ -18129,13 +19061,14 @@ "dev": true }, "uglify-js": { - "version": "3.9.3", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.9.3.tgz", - "integrity": "sha512-r5ImcL6QyzQGVimQoov3aL2ZScywrOgBXGndbWrdehKoSvGe/RmiE5Jpw/v+GvxODt6l2tpBXwA7n+qZVlHBMA==", + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.8.0.tgz", + "integrity": "sha512-ugNSTT8ierCsDHso2jkBHXYrU8Y5/fY2ZUprfrJUiD7YpuFvV4jODLFmb3h4btQjqr5Nh4TX4XtgDfCU1WdioQ==", "dev": true, "optional": true, "requires": { - "commander": "~2.20.3" + "commander": "~2.20.3", + "source-map": "~0.6.1" }, "dependencies": { "commander": { @@ -18144,15 +19077,16 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true, "optional": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true } } }, - "underscore": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", - "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=", - "dev": true - }, "unicode-canonical-property-names-ecmascript": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", @@ -18181,17 +19115,17 @@ "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==", "dev": true }, - "union-value": { + "uniq": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - } + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", + "dev": true + }, + "uniqs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", + "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=", + "dev": true }, "unique-string": { "version": "2.0.0", @@ -18203,9 +19137,9 @@ } }, "universal-user-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-4.0.1.tgz", - "integrity": "sha512-LnST3ebHwVL2aNe4mejI9IQh2HfZ1RLo8Io2HugSif8ekzD1TlWpHpColOB/eh8JHMLkGH3Akqf040I+4ylNxg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-5.0.0.tgz", + "integrity": "sha512-B5TPtzZleXyPrUMKCpEHFmVhMN6EhmJYjG5PQna9s7mXeSqGTLap4OpqLl5FCEFUI3UBmllkETwKf/db66Y54Q==", "dev": true, "requires": { "os-name": "^3.1.0" @@ -18217,45 +19151,11 @@ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - } - } + "unquote": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", + "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", + "dev": true }, "unused-filename": { "version": "2.1.0", @@ -18363,12 +19263,6 @@ "punycode": "^2.1.0" } }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true - }, "url-join": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", @@ -18384,12 +19278,6 @@ "prepend-http": "^2.0.0" } }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true - }, "utif": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/utif/-/utif-2.0.1.tgz", @@ -18418,6 +19306,71 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, + "util.promisify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", + "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.2", + "has-symbols": "^1.0.1", + "object.getownpropertydescriptors": "^2.1.0" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "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.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "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==", + "dev": true + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + } + } + }, "uuid": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", @@ -18492,6 +19445,12 @@ } } }, + "vendors": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz", + "integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==", + "dev": true + }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", @@ -18582,12 +19541,6 @@ } } }, - "vis-uuid": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/vis-uuid/-/vis-uuid-1.1.4.tgz", - "integrity": "sha512-ODyfCeFSzVQtLzS7d8NEoWoLK1YJKNcpNEek3ZyorSd0QCm0w8rSnsB18IUmauXbBpTB5AN8xTREW/rgnUf31w==", - "dev": true - }, "w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", @@ -18931,6 +19884,15 @@ } } }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "dev": true, + "requires": { + "defaults": "^1.0.3" + } + }, "webidl-conversions": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.0.0.tgz", @@ -19091,12 +20053,6 @@ "requires": { "path-key": "^2.0.0" } - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true } } }, diff --git a/package.json b/package.json index a6950df3d..69e0ef81d 100644 --- a/package.json +++ b/package.json @@ -80,59 +80,55 @@ "url": "https://opencollective.com/visjs" }, "devDependencies": { - "@babel/core": "^7.7.7", - "@babel/plugin-proposal-class-properties": "^7.7.4", - "@babel/plugin-transform-runtime": "^7.7.6", - "@babel/preset-env": "^7.7.7", - "@babel/preset-typescript": "^7.7.7", - "@babel/register": "^7.7.7", - "@babel/runtime-corejs3": "^7.7.7", - "@commitlint/cli": "^8.2.0", - "@commitlint/config-conventional": "^8.2.0", - "@stryker-mutator/babel-transpiler": "^2.4.0", - "@stryker-mutator/core": "^2.4.0", - "@stryker-mutator/html-reporter": "^2.4.0", - "@stryker-mutator/mocha-framework": "^2.4.0", - "@stryker-mutator/mocha-runner": "^2.4.0", - "@stryker-mutator/typescript": "^2.4.0", - "@types/chai": "^4.2.7", - "@types/mocha": "^5.2.7", - "@types/node": "^13.1.1", - "@types/sinon": "^7.5.1", - "@typescript-eslint/eslint-plugin": "^2.13.0", - "@typescript-eslint/parser": "^2.13.0", - "assert": "^2.0.0", - "babel-plugin-istanbul": "^6.0.0", - "chai": "^4.2.0", - "eslint": "^6.8.0", - "eslint-config-prettier": "^6.9.0", - "eslint-plugin-jsdoc": "^21.0.0", - "eslint-plugin-prettier": "^3.1.2", - "eslint-plugin-tsdoc": "^0.2.0", - "git-authors-cli": "^1.0.18", - "husky": "^4.0.2", - "jsdom": "^16.0.1", - "jsdom-global": "^3.0.2", - "lint-staged": "^9.5.0", - "mocha": "^7.0.1", - "npm-run-all": "^4.1.5", - "nyc": "^15.0.0", - "prettier": "^1.19.1", - "rimraf": "^3.0.0", - "rollup": "^1.27.14", - "rollup-plugin-babel": "^4.3.3", - "rollup-plugin-commonjs": "^10.1.0", - "rollup-plugin-copy-glob": "^0.3.1", - "rollup-plugin-node-resolve": "^5.2.0", - "rollup-plugin-terser": "^5.1.3", - "rollup-plugin-typescript2": "^0.25.3", - "semantic-release": "^16.0.0", - "sinon": "^8.0.1", - "snap-shot-it": "^7.9.1", - "stryker-cli": "^1.0.0", - "typedoc": "^0.16.0", - "typescript": "^3.7.4", - "vis-dev-utils": "^2.1.0", - "vis-uuid": "1.1.4" + "@babel/core": "7.9.6", + "@babel/plugin-proposal-class-properties": "7.8.3", + "@babel/plugin-transform-runtime": "7.9.6", + "@babel/preset-env": "7.9.6", + "@babel/preset-typescript": "7.9.0", + "@babel/register": "7.9.0", + "@babel/runtime-corejs3": "7.9.6", + "@rollup/plugin-commonjs": "12.0.0", + "@rollup/plugin-json": "4.0.3", + "@rollup/plugin-node-resolve": "8.0.0", + "@rollup/plugin-strip": "1.3.3", + "@types/chai": "4.2.11", + "@types/mocha": "7.0.2", + "@types/node": "13.13.9", + "@types/sinon": "9.0.4", + "@typescript-eslint/eslint-plugin": "3.0.0", + "@typescript-eslint/parser": "3.0.0", + "assert": "2.0.0", + "babel-plugin-css-modules-transform": "1.6.2", + "babel-plugin-istanbul": "6.0.0", + "chai": "4.2.0", + "core-js": "3.6.5", + "eslint": "7.1.0", + "eslint-config-prettier": "6.11.0", + "eslint-plugin-jsdoc": "25.4.2", + "eslint-plugin-prettier": "3.1.3", + "eslint-plugin-tsdoc": "0.2.5", + "git-authors-cli": "1.0.26", + "husky": "4.2.5", + "jsdom": "16.2.2", + "jsdom-global": "3.0.2", + "lint-staged": "10.2.6", + "mocha": "7.2.0", + "npm-run-all": "4.1.5", + "nyc": "15.0.1", + "prettier": "2.0.5", + "rimraf": "3.0.2", + "rollup": "2.10.8", + "rollup-plugin-analyzer": "3.2.3", + "rollup-plugin-babel": "4.4.0", + "rollup-plugin-copy": "3.3.0", + "rollup-plugin-postcss": "3.1.1", + "rollup-plugin-terser": "6.0.1", + "rollup-plugin-typescript2": "0.27.1", + "semantic-release": "17.0.7", + "sinon": "9.0.2", + "snap-shot-it": "7.9.3", + "typedoc": "0.17.7", + "typescript": "3.9.3", + "vis-dev-utils": "2.3.0" } } From 41195bdb6f4de393890da0921f3f36bc2387f03f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Sun, 24 May 2020 16:33:05 +0200 Subject: [PATCH 36/48] feat(layered-storage): add export to object This will make integrating this into existing codebase much easier. We'll be able to mostly contain the changes into .setOptions() methods. --- src/layered-storage/core.ts | 37 +++++++++++++++++ src/layered-storage/segment.ts | 16 ++++++++ test/layered-storage/segmented-layer.ts | 53 +++++++++++++++++++++++++ test/layered-storage/single-layer.ts | 36 +++++++++++++++++ 4 files changed, 142 insertions(+) diff --git a/src/layered-storage/core.ts b/src/layered-storage/core.ts index 871d3d101..4916be1e6 100644 --- a/src/layered-storage/core.ts +++ b/src/layered-storage/core.ts @@ -355,6 +355,43 @@ export class LayeredStorageCore< this._cleanCache(segment, key); } + /** + * Export data in an object format. + * + * @remarks + * All values will be fully expanded, all defaults will be applied etc. It's + * like fetching all of them through .get(). + * + * @param segment - Which segment's data to export. + * @param compoundKeys - The keys to export. + * + * @returns Object representation of given segments' current data for given + * keys. + */ + public exportToObject(segment: Segment, compoundKeys: Keys[]): any { + const result: any = {}; + + for (const compoundKey of compoundKeys) { + if (typeof compoundKey === "string") { + let obj = result; + + const keyParts = compoundKey.split("."); + const key = keyParts.pop()!; // String.split() will always have at leas one member. + + for (const keyPart of keyParts) { + obj[keyPart] = obj[keyPart] || {}; + obj = obj[keyPart]; + } + + obj[key] = this.get(segment, compoundKey); + } else { + result[compoundKey] = this.get(segment, compoundKey); + } + } + + return result; + } + /** * Clone all data from one segment to another. * diff --git a/src/layered-storage/segment.ts b/src/layered-storage/segment.ts index 7f6886372..f85275222 100644 --- a/src/layered-storage/segment.ts +++ b/src/layered-storage/segment.ts @@ -132,6 +132,22 @@ export class LayeredStorageSegment< transaction.commit(); } + /** + * Export data in an object format. + * + * @remarks + * All values will be fully expanded, all defaults will be applied etc. It's + * like fetching all of them through .get(). + * + * @param keys - The keys to export. + * + * @returns Object representation of given segments current data for + * given keys. + */ + public exportToObject(keys: Keys[]): void { + return this._core.exportToObject(this.segment, keys); + } + /** * Delete all data belonging to this segment. */ diff --git a/test/layered-storage/segmented-layer.ts b/test/layered-storage/segmented-layer.ts index e09e5452f..8796acb75 100644 --- a/test/layered-storage/segmented-layer.ts +++ b/test/layered-storage/segmented-layer.ts @@ -144,6 +144,59 @@ export function segmentedLayer(): void { ).to.be.false; }); + it("Export", function (): void { + interface LocalKV { + "test.deeply.nested.value": string; + "test.deeply.not-exported-value": string; + "test.deeply.value": string; + "test.value1": string; + "test.value2": string; + } + + const ls = new LayeredStorage<0 | 2, LocalKV, keyof LocalKV>(); + + ls.global.runTransaction((transaction): void => { + transaction.set(0, "test.value1", "a value from global segment"); + transaction.set(0, "test.value2", "a value from global segment"); + }); + + ls.openSegment(a).runTransaction((transaction): void => { + transaction.set(2, "test.value1", "a value from different segment"); + transaction.set(2, "test.value2", "a value from different segment"); + }); + + ls.openSegment(c).runTransaction((transaction): void => { + transaction.set(0, "test.deeply.nested.value", "0tdnv"); + transaction.set(2, "test.deeply.nested.value", "2tdnv"); + transaction.set(2, "test.deeply.not-exported-value", "2tdn"); + transaction.set(2, "test.deeply.value", "2tdv"); + transaction.set(2, "test.value1", "2tv"); + }); + + expect( + ls + .openSegment(c) + .exportToObject([ + "test.deeply.nested.value", + "test.deeply.value", + "test.value1", + "test.value2", + ]), + "All requested values should be exported." + ).to.deep.equal({ + test: { + value1: "2tv", + value2: "a value from global segment", + deeply: { + nested: { + value: "2tdnv", + }, + value: "2tdv", + }, + }, + }); + }); + describe("Invalid layer names", function (): void { [undefined, null, "string", true, false, {}].forEach( (layer: any): void => { diff --git a/test/layered-storage/single-layer.ts b/test/layered-storage/single-layer.ts index d8190a590..c2cbff0fa 100644 --- a/test/layered-storage/single-layer.ts +++ b/test/layered-storage/single-layer.ts @@ -78,6 +78,42 @@ export function singleLayer(): void { ).to.be.false; }); + it("Export", function (): void { + interface LocalKV { + "test.deeply.nested.value": string; + "test.deeply.not-exported-value": string; + "test.deeply.value": string; + "test.value": string; + } + + const ls = new LayeredStorage<0 | 2, LocalKV, keyof LocalKV>(); + + ls.global.set(0, "test.value", "0tv"); + ls.global.set(2, "test.deeply.nested.value", "2tdnv"); + ls.global.set(2, "test.deeply.value", "2tdv"); + ls.global.set(2, "test.deeply.not-exported-value", "2tdn"); + ls.global.set(0, "test.deeply.nested.value", "0tdnv"); + + expect( + ls.global.exportToObject([ + "test.deeply.nested.value", + "test.deeply.value", + "test.value", + ]), + "All requested values should be exported." + ).to.deep.equal({ + test: { + value: "0tv", + deeply: { + nested: { + value: "2tdnv", + }, + value: "2tdv", + }, + }, + }); + }); + describe("Invalid layer names", function (): void { [undefined, null, "string", true, false, {}].forEach( (layer: any): void => { From 6b3785ba797bb410ba31957acc82d23543ec32f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Sun, 24 May 2020 16:54:17 +0200 Subject: [PATCH 37/48] fix(layered-storage): throw right away in transactions Prior to this only the commit would fail. --- src/layered-storage/core.ts | 39 ++++++++++++---- src/layered-storage/transactions.ts | 11 +++-- test/layered-storage/index.test.ts | 2 + test/layered-storage/transactions.ts | 68 ++++++++++++++++++++++++++++ 4 files changed, 108 insertions(+), 12 deletions(-) create mode 100644 test/layered-storage/transactions.ts diff --git a/src/layered-storage/core.ts b/src/layered-storage/core.ts index 4916be1e6..f04cec365 100644 --- a/src/layered-storage/core.ts +++ b/src/layered-storage/core.ts @@ -282,19 +282,21 @@ export class LayeredStorageCore< } /** - * Save a value. + * Validate the value now and set it later. * * @param layer - Which layer to save the value into. * @param segment - Which segment to save the value into. * @param key - Key that can be used to retrieve or overwrite this value later. * @param value - The value to be saved. + * + * @returns Function that actually sets the validated value. */ - public set( + public twoPartSet( layer: Layer, segment: Segment, key: Key, value: KV[Key] - ): void { + ): () => void { if (typeof layer !== "number") { throw new TypeError("Layers have to be numbers."); } @@ -309,18 +311,37 @@ export class LayeredStorageCore< continue; } else { // The value is invalid. Call the invalid value handler and, if the - // handler didn't throw, stop execution of this function to prevent - // the value from being saved into the storage. + // handler didn't throw, return empty function to prevent the value + // from being saved into the storage. this._invalidHandler(key, value, message); - return; + return (): void => {}; } } } - const { segmentData } = this._getLSData(layer, segment); - segmentData.set(key, value); + return (): void => { + const { segmentData } = this._getLSData(layer, segment); + segmentData.set(key, value); - this._cleanCache(segment, key); + this._cleanCache(segment, key); + }; + } + + /** + * Save a value. + * + * @param layer - Which layer to save the value into. + * @param segment - Which segment to save the value into. + * @param key - Key that can be used to retrieve or overwrite this value later. + * @param value - The value to be saved. + */ + public set( + layer: Layer, + segment: Segment, + key: Key, + value: KV[Key] + ): void { + this.twoPartSet(layer, segment, key, value)(); } /** diff --git a/src/layered-storage/transactions.ts b/src/layered-storage/transactions.ts index 5d8efa07a..df3da005d 100644 --- a/src/layered-storage/transactions.ts +++ b/src/layered-storage/transactions.ts @@ -44,9 +44,14 @@ export class LayeredStorageTransaction< public set(layer: Layer, key: Key, value: KV[Key]): void { const expandedPairs = this._storageCore.expandSet(key, value); for (const expanded of expandedPairs) { - this._actions.push((): void => { - this._storageCore.set(layer, this._segment, expanded[0], expanded[1]); - }); + this._actions.push( + this._storageCore.twoPartSet( + layer, + this._segment, + expanded[0], + expanded[1] + ) + ); } } diff --git a/test/layered-storage/index.test.ts b/test/layered-storage/index.test.ts index f51d125a5..0d95289d4 100644 --- a/test/layered-storage/index.test.ts +++ b/test/layered-storage/index.test.ts @@ -6,6 +6,7 @@ import { multipleLayers } from "./multiple-layers"; import { other } from "./other"; import { segmentedLayer } from "./segmented-layer"; import { singleLayer } from "./single-layer"; +import { transactions } from "./transactions"; import { validation } from "./validation"; describe("Layered storage", function (): void { @@ -17,5 +18,6 @@ describe("Layered storage", function (): void { other(); segmentedLayer(); singleLayer(); + transactions(); validation(); }); diff --git a/test/layered-storage/transactions.ts b/test/layered-storage/transactions.ts new file mode 100644 index 000000000..9c046ddab --- /dev/null +++ b/test/layered-storage/transactions.ts @@ -0,0 +1,68 @@ +import { LayeredStorage } from "../../src/layered-storage"; +import { expect } from "chai"; + +interface KV { + "test.value": string; + "test.value1": string; + "test.value2": string; + "unrelated.value": string; +} + +/** + * Test that values can be set accross segments and later retrieved. + */ +export function transactions(): void { + describe("Transactions", function (): void { + it("Transaction shouldn't save anything before commit", function (): void { + const ls = new LayeredStorage<7, KV, keyof KV>(); + + const transaction = ls.global.openTransaction(); + + transaction.set(7, "test.value", "Hi!"); + + expect( + ls.global.has("test.value"), + "The value shouldn't be set before commit" + ).to.be.false; + + transaction.commit(); + + expect(ls.global.has("test.value"), "The value shoud be set after commit") + .to.be.true; + }); + + it("Transaction shouldn't save anything before commit", function (): void { + const ls = new LayeredStorage<7, KV, keyof KV>(); + + ls.setInvalidHandler((key, value, message): void => { + throw new TypeError( + "Invalid value was supplied: " + + JSON.parse(JSON.stringify({ key, value, message })) + ); + }); + + ls.setValidators("test.value1", [ + (value): true | string => + value.length < 4 ? "Minimum of 4 characters required" : true, + ]); + ls.setValidators("test.value2", [ + (value): true | string => + value.length < 4 ? "Minimum of 4 characters required" : true, + ]); + + const transaction = ls.global.openTransaction(); + + expect((): void => { + transaction.set(7, "test.value1", "Hi!"); + }, "The value should be validated right away").to.throw(); + transaction.set(7, "test.value2", "Hi there!"); + + transaction.commit(); + + expect( + ls.global.has("test.value1"), + "Invalid values shouldn't be committed if commit is called" + ).to.be.false; + }); + }); +} From d229669d2268eeb752a3ab2751be1ad335bf083f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Sun, 24 May 2020 17:49:57 +0200 Subject: [PATCH 38/48] test(layered-storage): fix copy paste error --- test/layered-storage/transactions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/layered-storage/transactions.ts b/test/layered-storage/transactions.ts index 9c046ddab..7884c0f8f 100644 --- a/test/layered-storage/transactions.ts +++ b/test/layered-storage/transactions.ts @@ -9,7 +9,7 @@ interface KV { } /** - * Test that values can be set accross segments and later retrieved. + * Test transactions. */ export function transactions(): void { describe("Transactions", function (): void { From d1c16b9fada00da95fb9e1383760f66ad6d83a8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Sun, 24 May 2020 17:50:35 +0200 Subject: [PATCH 39/48] feat(layered-storage): add inheritance This can be used to implement groups from Vis Network. It actually allows for multiple groups per single node which is already a wanted feature that would be extremely difficult to implement using the (anti)pattern that's currently in Vis Network for options. --- src/layered-storage/core.ts | 88 +++++++++----- src/layered-storage/segment.ts | 10 ++ test/layered-storage/index.test.ts | 2 + test/layered-storage/inheritance.ts | 171 ++++++++++++++++++++++++++++ 4 files changed, 245 insertions(+), 26 deletions(-) create mode 100644 test/layered-storage/inheritance.ts diff --git a/src/layered-storage/core.ts b/src/layered-storage/core.ts index f04cec365..db1220b96 100644 --- a/src/layered-storage/core.ts +++ b/src/layered-storage/core.ts @@ -71,6 +71,15 @@ export class LayeredStorageCore< */ private readonly _segments = new Set(); + /** + * Segment inheritance chains. + * + * @remarks + * The first element always has to be the segment itself: + * [this segment, ...ancestors, global segment] + */ + private readonly _inheritance = new Map(); + /** * A list of validators for each key. */ @@ -204,29 +213,35 @@ export class LayeredStorageCore< /** * Retrieve a value. * - * @param segment - Which segment to search through in addition to the global + * @param thisSegment - Which segment to search through in addition to the global * segment which is used as the fallback on each level. * @param key - The key corresponding to the requested value. * * @returns The value or undefined if it wasn't found. */ public get( - segment: Segment, + thisSegment: Segment, key: Key ): KV[Key] | undefined { - let segmentCache = this._topLevelCache.get(segment); - if (typeof segmentCache === "undefined") { - segmentCache = new Map(); - this._topLevelCache.set(segment, segmentCache); + let thisSegmentCache = this._topLevelCache.get(thisSegment); + if (typeof thisSegmentCache === "undefined") { + thisSegmentCache = new Map(); + this._topLevelCache.set(thisSegment, thisSegmentCache); } // Return cached value if it exists. - const cached = segmentCache.get(key); + const cached = thisSegmentCache.get(key); if (typeof cached !== "undefined") { // TODO: The non null assertion shouldn't be necessary. return cached === null ? void 0 : cached!; } + // Fetch the inheritance chain. + const segments = this._inheritance.get(thisSegment) ?? [ + thisSegment, + this.globalSegment, + ]; + // Search the layers from highest to lowest priority. for (const layerData of this._layerDatas) { if (typeof layerData === "undefined") { @@ -234,35 +249,32 @@ export class LayeredStorageCore< continue; } - // Check the segment and quit if found. - const segmentData = layerData.get(segment); - if (typeof segmentData !== "undefined") { - const value = segmentData.get(key); - if (typeof value !== "undefined") { - // Save to the cache. - segmentCache.set(key, value); + // Search the inheritance chain. + for (const segment of segments) { + // Check the segment and quit if found. + const segmentData = layerData.get(segment); + if (typeof segmentData === "undefined") { + // Empty segment on this layer. + continue; + } - return value; + const value = segmentData.get(key); + if (typeof value === "undefined") { + // No value for this segment on this layer. + continue; } - } - // Check the global segment and quit if found. - const globalData = layerData.get(this.globalSegment); - if (typeof globalData !== "undefined") { - const value = globalData.get(key); - if (typeof value !== "undefined") { - // Save to the cache. - segmentCache.set(key, value); + // Save to the cache. + thisSegmentCache.set(key, value); - return value; - } + return value; } } // If nothing was found by now there are no values for the key. // Save to the cache. - segmentCache.set(key, null); + thisSegmentCache.set(key, null); // Return the empty value. return; @@ -376,6 +388,29 @@ export class LayeredStorageCore< this._cleanCache(segment, key); } + /** + * Set the inherance chain of given segment. + * + * @param segment - The segment that will inherit. + * @param segments - The segments from which will be inherited. + * @param global - Whether to inherit from global (as is the default) or not. + */ + public setInheritance( + segment: Segment, + segments: Segment[], + global = true + ): void { + this._inheritance.set( + segment, + global + ? [segment, ...segments, this.globalSegment] + : [segment, ...segments] + ); + + // Inheritance can affect anything, delete the whole cache for this segment. + this._topLevelCache.delete(segment); + } + /** * Export data in an object format. * @@ -461,6 +496,7 @@ export class LayeredStorageCore< } this._topLevelCache.delete(segment); this._segments.delete(segment); + this._inheritance.delete(segment); } /** diff --git a/src/layered-storage/segment.ts b/src/layered-storage/segment.ts index f85275222..0f473b875 100644 --- a/src/layered-storage/segment.ts +++ b/src/layered-storage/segment.ts @@ -76,6 +76,16 @@ export class LayeredStorageSegment< }); } + /** + * Set the inherance chain of this segment. + * + * @param segments - The segments from which this segment will inherit. + * @param global - Whether to inherit from global (as is the default) or not. + */ + public setInheritance(segments: Segment[], global = true): void { + this._core.setInheritance(this.segment, segments, global); + } + /** * Create a new segmented instance for working with a single segment with a * copy of another segments data. diff --git a/test/layered-storage/index.test.ts b/test/layered-storage/index.test.ts index 0d95289d4..bbafe30b3 100644 --- a/test/layered-storage/index.test.ts +++ b/test/layered-storage/index.test.ts @@ -1,6 +1,7 @@ import { allCombined } from "./all-combined"; import { cloning } from "./cloning"; import { expanders } from "./expanders"; +import { inheritance } from "./inheritance"; import { multipleKeys } from "./multiple-keys"; import { multipleLayers } from "./multiple-layers"; import { other } from "./other"; @@ -13,6 +14,7 @@ describe("Layered storage", function (): void { allCombined(); cloning(); expanders(); + inheritance(); multipleKeys(); multipleLayers(); other(); diff --git a/test/layered-storage/inheritance.ts b/test/layered-storage/inheritance.ts new file mode 100644 index 000000000..09e45703a --- /dev/null +++ b/test/layered-storage/inheritance.ts @@ -0,0 +1,171 @@ +import { LayeredStorage } from "../../src/layered-storage"; +import { expect } from "chai"; + +interface KV { + "test.value": string; + "test.value1": string; + "test.value2": string; + "test.value3": string; + "test.value4": string; + "test.value5": string; + "test.value6": string; + "test.value7": string; + "unrelated.value": string; +} + +/** + * Test that segments inherit from other segments. + */ +export function inheritance(): void { + describe("Inheritance", function (): void { + const a = Symbol("A"); + const b = Symbol("B"); + const c = Symbol("C"); + const d = Symbol("D"); + const e = Symbol("E"); + const f = Symbol("F"); + + it("Default inheritance", function (): void { + const ls = new LayeredStorage<7, KV, keyof KV>(); + + ls.global.set(7, "test.value", "global"); + ls.openSegment(a).set(7, "test.value", "A"); + ls.openSegment(b).set(7, "test.value", "B"); + + expect( + ls.openSegment(c).get("test.value"), + "By default segments should inherit from the global segment" + ).to.equal("global"); + }); + + it("Disable global inheritance", function (): void { + const ls = new LayeredStorage<7, KV, keyof KV>(); + + ls.global.set(7, "test.value", "global"); + ls.openSegment(a).set(7, "test.value", "A"); + ls.openSegment(b).set(7, "test.value", "B"); + ls.openSegment(c).setInheritance([], false); + + expect( + ls.openSegment(c).has("test.value"), + "Nothing should be inherited if inheritance chain is empty and global disabled" + ).to.be.false; + }); + + it("Other segment without global", function (): void { + const ls = new LayeredStorage<3 | 7, KV, keyof KV>(); + + ls.global.set(7, "test.value", "global"); + ls.openSegment(a).set(7, "test.value", "A"); + ls.openSegment(b).set(7, "test.value", "B"); + ls.openSegment(c).setInheritance([a], false); + + expect( + ls.openSegment(c).get("test.value"), + "The value should be inherited from A since C has none of it's own and global inheritance (even though global has higher priority in this case) is disabled" + ).to.equal("A"); + }); + + it("Other segment with global", function (): void { + const ls = new LayeredStorage<3 | 7, KV, keyof KV>(); + + ls.global.set(7, "test.value", "global"); + ls.openSegment(a).set(3, "test.value", "A"); + ls.openSegment(b).set(7, "test.value", "B"); + ls.openSegment(c).setInheritance([a]); + + expect( + ls.openSegment(c).get("test.value"), + "The value should be inherited from global since C has none of it's own (A has lower priority than global)" + ).to.equal("global"); + }); + + it("Multiple inheritance", function (): void { + const ls = new LayeredStorage<3 | 7, KV, keyof KV>(); + + ls.openSegment(f).setInheritance([e, d, c, b, a]); + + ls.global.set(7, "test.value1", "global"); + ls.openSegment(a).set(7, "test.value1", "A"); + ls.openSegment(b).set(7, "test.value1", "B"); + ls.openSegment(c).set(7, "test.value1", "C"); + ls.openSegment(d).set(7, "test.value1", "D"); + ls.openSegment(e).set(7, "test.value1", "E"); + ls.openSegment(f).set(7, "test.value1", "F"); + + ls.global.set(7, "test.value2", "global"); + ls.openSegment(a).set(7, "test.value2", "A"); + ls.openSegment(b).set(7, "test.value2", "B"); + ls.openSegment(c).set(7, "test.value2", "C"); + ls.openSegment(d).set(7, "test.value2", "D"); + ls.openSegment(e).set(7, "test.value2", "E"); + + ls.global.set(7, "test.value3", "global"); + ls.openSegment(a).set(7, "test.value3", "A"); + ls.openSegment(b).set(7, "test.value3", "B"); + ls.openSegment(c).set(7, "test.value3", "C"); + ls.openSegment(d).set(7, "test.value3", "D"); + + ls.global.set(7, "test.value4", "global"); + ls.openSegment(a).set(7, "test.value4", "A"); + ls.openSegment(b).set(7, "test.value4", "B"); + ls.openSegment(c).set(7, "test.value4", "C"); + + ls.global.set(7, "test.value5", "global"); + ls.openSegment(a).set(7, "test.value5", "A"); + ls.openSegment(b).set(7, "test.value5", "B"); + + ls.global.set(7, "test.value6", "global"); + ls.openSegment(a).set(7, "test.value6", "A"); + + ls.global.set(7, "test.value7", "global"); + + expect(ls.openSegment(f).get("test.value1")).to.equal("F"); + expect(ls.openSegment(f).get("test.value2")).to.equal("E"); + expect(ls.openSegment(f).get("test.value3")).to.equal("D"); + expect(ls.openSegment(f).get("test.value4")).to.equal("C"); + expect(ls.openSegment(f).get("test.value5")).to.equal("B"); + expect(ls.openSegment(f).get("test.value6")).to.equal("A"); + expect(ls.openSegment(f).get("test.value7")).to.equal("global"); + }); + + it("Change inheritance", function (): void { + const ls = new LayeredStorage<3 | 7, KV, keyof KV>(); + + ls.global.set(7, "test.value", "global"); + ls.openSegment(a).set(7, "test.value", "A"); + ls.openSegment(b).set(7, "test.value", "B"); + + expect( + ls.openSegment(c).get("test.value"), + "C should follow default inheritance rules" + ).to.equal("global"); + + ls.openSegment(c).setInheritance([a, b]); + + expect( + ls.openSegment(c).get("test.value"), + "C should inherit from A then B then global" + ).to.equal("A"); + + ls.openSegment(c).setInheritance([b]); + + expect( + ls.openSegment(c).get("test.value"), + "C should inherit from B then global" + ).to.equal("B"); + + ls.openSegment(c).setInheritance([]); + + expect( + ls.openSegment(c).get("test.value"), + "C should inherit from global" + ).to.equal("global"); + + ls.openSegment(c).setInheritance([], false); + + expect(ls.openSegment(c).has("test.value"), "C should not inherit at all") + .to.be.false; + }); + }); +} From 10367bb66dc8cf054a9939a6164b23614db060b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Sun, 24 May 2020 21:20:42 +0200 Subject: [PATCH 40/48] feat(layered-storage): add a basic library of validators This also includes a tweak to the way validating is done. --- src/layered-storage/core.ts | 132 ++++++++++-------- src/layered-storage/index.ts | 1 + src/layered-storage/layered-storage.ts | 13 +- src/layered-storage/transactions.ts | 2 +- .../validator-library/boolean.ts | 12 ++ .../validator-library/index.ts | 7 + .../validator-library/number.ts | 111 +++++++++++++++ .../validator-library/operators.ts | 65 +++++++++ .../validator-library/other.ts | 50 +++++++ .../validator-library/public-util.ts | 39 ++++++ .../validator-library/string.ts | 106 ++++++++++++++ src/layered-storage/validator-library/util.ts | 24 ++++ test/layered-storage/expanders.ts | 16 +-- test/layered-storage/transactions.ts | 12 +- test/layered-storage/validation.ts | 61 ++++---- 15 files changed, 529 insertions(+), 122 deletions(-) create mode 100644 src/layered-storage/validator-library/boolean.ts create mode 100644 src/layered-storage/validator-library/index.ts create mode 100644 src/layered-storage/validator-library/number.ts create mode 100644 src/layered-storage/validator-library/operators.ts create mode 100644 src/layered-storage/validator-library/other.ts create mode 100644 src/layered-storage/validator-library/public-util.ts create mode 100644 src/layered-storage/validator-library/string.ts create mode 100644 src/layered-storage/validator-library/util.ts diff --git a/src/layered-storage/core.ts b/src/layered-storage/core.ts index db1220b96..989073cd6 100644 --- a/src/layered-storage/core.ts +++ b/src/layered-storage/core.ts @@ -5,6 +5,7 @@ import { LayerRange, Segment, } from "./common"; +import { LayeredStorageValidator } from "./validator-library"; const entriesByKeyPriority = ( a: [number, unknown], @@ -33,6 +34,12 @@ interface TypedMap< set(key: Key, value: KV[Key]): this; } +export type LayeredStorageInvalidValueHandler = ( + key: Keys, + value: unknown, + messages: string[] +) => void; + /** * Internal core to handle simple data storage, mutation and retrieval. Also * handles the special global segment. @@ -85,7 +92,7 @@ export class LayeredStorageCore< */ private readonly _validators: TypedMap< { - [Key in Keys]: ((value: KV[Key]) => true | string)[]; + [Key in Keys]: LayeredStorageValidator[]; }, Keys > = new Map(); @@ -110,14 +117,14 @@ export class LayeredStorageCore< * * @param key - The key of the invalid value. * @param value - The invalid value itself. - * @param message - The message returned by the validator that failed. + * @param messages - All the message returned by the validators that failed. */ - private _invalidHandler: ( - key: Key, - value: KV[Key], - message: string - ) => void = (key, value, message): void => { - console.error("Invalid value was ignored.", { key, value, message }); + private _invalidHandler: LayeredStorageInvalidValueHandler = ( + key, + value, + messages + ): void => { + console.error("Invalid value was ignored.", { key, value, messages }); }; /** @@ -313,30 +320,21 @@ export class LayeredStorageCore< throw new TypeError("Layers have to be numbers."); } - const validators = this._validators.get(key); - if (validators) { - for (const validator of validators) { - const message = validator(value); - if (message === true) { - // The value is valid. Proceed with another test or save the value - // into the storage if this was the last one. - continue; - } else { - // The value is invalid. Call the invalid value handler and, if the - // handler didn't throw, return empty function to prevent the value - // from being saved into the storage. - this._invalidHandler(key, value, message); - return (): void => {}; - } - } - } - - return (): void => { - const { segmentData } = this._getLSData(layer, segment); - segmentData.set(key, value); + const valid = this._validate(key, value); + if (valid) { + // The value is valid. It can be safely saved into the storage. + return (): void => { + const { segmentData } = this._getLSData(layer, segment); + segmentData.set(key, value); - this._cleanCache(segment, key); - }; + this._cleanCache(segment, key); + }; + } else { + // The value is invalid. If the invalid value handler didn't throw, + // return empty function to prevent the value from being saved into + // the storage. + return (): void => {}; + } } /** @@ -506,11 +504,7 @@ export class LayeredStorageCore< * value and a message from the failed validator. */ public setInvalidHandler( - handler: ( - key: Key, - value: KV[Key], - message: string - ) => void + handler: LayeredStorageInvalidValueHandler ): void { this._invalidHandler = handler; } @@ -526,7 +520,7 @@ export class LayeredStorageCore< */ public setValidators( key: Key, - validators: ((value: KV[Key]) => true | string)[], + validators: LayeredStorageValidator[], replace: boolean ): void { if (!replace && this._validators.has(key)) { @@ -536,6 +530,37 @@ export class LayeredStorageCore< this._validators.set(key, validators); } + /** + * Validate given value for given key. + * + * @param key - The key whose validators should be used. + * @param value - The value to be validated. + * + * @returns True if valid, false otherwise. + */ + public _validate(key: Key, value: KV[Key]): boolean { + const messages = []; + + const validators = this._validators.get(key); + if (validators) { + for (const validator of validators) { + const message = validator(value) || validator.description; + if (message !== true) { + // The value is invalid. Call the invalid value handler and, if the + // handler didn't throw, return empty function to prevent the value + // from being saved into the storage. + messages.push(message); + } + } + } + + if (messages.length) { + this._invalidHandler(key, value, messages); + } + + return !messages.length; + } + /** * Set an expander for given key. * @@ -578,33 +603,22 @@ export class LayeredStorageCore< * * @returns Expanded key value pairs or empty array for invalid input. */ - public expandSet( + public expandValue( key: Key, value: KV[Key] ): readonly KeyValueEntry[] { - const validators = this._validators.get(key); - if (validators) { - for (const validator of validators) { - const message = validator(value); - if (message === true) { - // The value is valid. Proceed with another test or save the value - // into the storage if this was the last one. - continue; - } else { - // The value is invalid. Call the invalid value handler and, if the - // handler didn't throw, stop execution of this function to prevent - // the value from being saved into the storage. - this._invalidHandler(key, value, message); - return []; - } + const valid = this._validate(key, value); + if (valid) { + const expand = this._setExpanders.get(key); + if (expand) { + return expand(value); + } else { + return [[key, value]]; } - } - - const expand = this._setExpanders.get(key); - if (expand) { - return expand(value); } else { - return [[key, value]]; + // The value is invalid. If the invalid value handler didn't throw, return + // empty entry to prevent the value from being saved into the storage. + return []; } } diff --git a/src/layered-storage/index.ts b/src/layered-storage/index.ts index 588561c4f..8928b447c 100644 --- a/src/layered-storage/index.ts +++ b/src/layered-storage/index.ts @@ -1,3 +1,4 @@ export { LayeredStorage, LayeredStorageTransaction } from "./layered-storage"; export { LayeredStorageSegment } from "./segment"; export * from "./common"; +export * from "./validator-library"; diff --git a/src/layered-storage/layered-storage.ts b/src/layered-storage/layered-storage.ts index 84da44dd6..d7639836f 100644 --- a/src/layered-storage/layered-storage.ts +++ b/src/layered-storage/layered-storage.ts @@ -1,13 +1,14 @@ import { KeyRange, + KeyValueEntry, KeyValueLookup, LayerRange, Segment, - KeyValueEntry, } from "./common"; -import { LayeredStorageCore } from "./core"; +import { LayeredStorageCore, LayeredStorageInvalidValueHandler } from "./core"; import { LayeredStorageSegment } from "./segment"; import { LayeredStorageTransaction } from "./transactions"; +import { LayeredStorageValidator } from "./validator-library"; export { LayeredStorageTransaction }; @@ -84,11 +85,7 @@ export class LayeredStorage< * value and a message from the failed validator. */ public setInvalidHandler( - handler: ( - key: Key, - value: KV[Key], - message: string - ) => void + handler: LayeredStorageInvalidValueHandler ): void { this._core.setInvalidHandler(handler); } @@ -104,7 +101,7 @@ export class LayeredStorage< */ public setValidators( key: Key, - validators: ((value: KV[Key]) => true | string)[], + validators: LayeredStorageValidator[], replace = false ): void { this._core.setValidators(key, validators, replace); diff --git a/src/layered-storage/transactions.ts b/src/layered-storage/transactions.ts index df3da005d..a4a7e50ef 100644 --- a/src/layered-storage/transactions.ts +++ b/src/layered-storage/transactions.ts @@ -42,7 +42,7 @@ export class LayeredStorageTransaction< * @param value - The value to be saved. */ public set(layer: Layer, key: Key, value: KV[Key]): void { - const expandedPairs = this._storageCore.expandSet(key, value); + const expandedPairs = this._storageCore.expandValue(key, value); for (const expanded of expandedPairs) { this._actions.push( this._storageCore.twoPartSet( diff --git a/src/layered-storage/validator-library/boolean.ts b/src/layered-storage/validator-library/boolean.ts new file mode 100644 index 000000000..992e5f592 --- /dev/null +++ b/src/layered-storage/validator-library/boolean.ts @@ -0,0 +1,12 @@ +import { + LayeredStorageValidator, + LayeredStorageValidatorResult, + createValidator, +} from "./util"; + +export const boolean: LayeredStorageValidator = createValidator( + "value has to be a boolean", + function boolean(value: unknown): LayeredStorageValidatorResult { + return typeof value === "boolean"; + } +); diff --git a/src/layered-storage/validator-library/index.ts b/src/layered-storage/validator-library/index.ts new file mode 100644 index 000000000..b0d54c5c2 --- /dev/null +++ b/src/layered-storage/validator-library/index.ts @@ -0,0 +1,7 @@ +export * from "./public-util"; + +export * from "./boolean"; +export * from "./number"; +export * from "./operators"; +export * from "./other"; +export * from "./string"; diff --git a/src/layered-storage/validator-library/number.ts b/src/layered-storage/validator-library/number.ts new file mode 100644 index 000000000..56be4edb1 --- /dev/null +++ b/src/layered-storage/validator-library/number.ts @@ -0,0 +1,111 @@ +import { + LayeredStorageValidator, + LayeredStorageValidatorResult, + createValidator, +} from "./util"; + +export const number: LayeredStorageValidator = createValidator( + "value has to be a number", + function numberValidator(value: unknown): LayeredStorageValidatorResult { + return typeof value === "number"; + } +); + +export const numberOdd: LayeredStorageValidator = createValidator( + "value has to be an odd number", + function numberOddValidator(value: unknown): LayeredStorageValidatorResult { + return typeof value === "number" && value % 2 === 1; + } +); + +export const numberEven: LayeredStorageValidator = createValidator( + "value has to be an even number", + function numberEvenValidator(value: unknown): LayeredStorageValidatorResult { + return typeof value === "number" && value % 2 === 0; + } +); + +export const numberInteger: LayeredStorageValidator = createValidator( + "value has to be an integer number", + function numberIntegerValidator( + value: unknown + ): LayeredStorageValidatorResult { + return typeof value === "number" && value % 1 === 0; + } +); + +/** + * Check that given value is higher than given boundary (value \> min). + * + * @param min - The boundary that the value will be checked against. + * + * @returns Validator curried with given boundary. + */ +export function numberHigherThan(min: number): LayeredStorageValidator { + return createValidator( + `value has to a number higher than ${min}`, + + function numberHigherThanValidator( + value: unknown + ): LayeredStorageValidatorResult { + return typeof value === "number" && value > min; + } + ); +} + +/** + * Check that given value is lower than given boundary (value \< max). + * + * @param max - The boundary that the value will be checked against. + * + * @returns Validator curried with given boundary. + */ +export function numberLowerThan(max: number): LayeredStorageValidator { + return createValidator( + `value has to a number lower than ${max}`, + + function numberLowerThanValidator( + value: unknown + ): LayeredStorageValidatorResult { + return typeof value === "number" && value < max; + } + ); +} + +/** + * Check that given value is at least at given boundary (value \>= min). + * + * @param min - The boundary that the value will be checked against. + * + * @returns Validator curried with given boundary. + */ +export function numberAtLeast(min: number): LayeredStorageValidator { + return createValidator( + `value has to a number no lower than ${min}`, + + function numberAtLeastValidator( + value: unknown + ): LayeredStorageValidatorResult { + return typeof value === "number" && value >= min; + } + ); +} + +/** + * Check that given value is at most at given boundary (value \<= max). + * + * @param max - The boundary that the value will be checked against. + * + * @returns Validator curried with given boundary. + */ +export function numberAtMost(max: number): LayeredStorageValidator { + return createValidator( + `value has to a number no higher than ${max}`, + + function numberAtMostValidator( + value: unknown + ): LayeredStorageValidatorResult { + return typeof value === "number" && value <= max; + } + ); +} diff --git a/src/layered-storage/validator-library/operators.ts b/src/layered-storage/validator-library/operators.ts new file mode 100644 index 000000000..dec54addf --- /dev/null +++ b/src/layered-storage/validator-library/operators.ts @@ -0,0 +1,65 @@ +import { + LayeredStorageValidator, + LayeredStorageValidatorResult, + createValidator, + sublistDescriptions, +} from "./util"; + +/** + * Combine multiple validators using and operator. + * + * @param validators - Validators to be combined. + * + * @returns New validator that combines all of them. + */ +export function and( + ...validators: LayeredStorageValidator[] +): LayeredStorageValidator { + return createValidator( + sublistDescriptions("value has satisfy all of", validators), + function andValidator(value: unknown): LayeredStorageValidatorResult { + return validators.every( + (validator): boolean => validator(value) === true + ); + } + ); +} + +/** + * Combine multiple validators using or operator. + * + * @param validators - Validators to be combined. + * + * @returns New validator that combines all of them. + */ +export function or( + ...validators: LayeredStorageValidator[] +): LayeredStorageValidator { + return createValidator( + sublistDescriptions("value has satisfy at least one of", validators), + function orValidator(value: unknown): LayeredStorageValidatorResult { + return validators.some((validator): boolean => validator(value) === true); + } + ); +} + +/** + * Combine multiple validators using xor operator. + * + * @param validators - Validators to be combined. + * + * @returns New validator that combines all of them. + */ +export function xor( + ...validators: LayeredStorageValidator[] +): LayeredStorageValidator { + return createValidator( + sublistDescriptions("value has satisfy exactly one of", validators), + function xorValidator(value: unknown): LayeredStorageValidatorResult { + return ( + validators.filter((validator): boolean => validator(value) === true) + .length === 1 + ); + } + ); +} diff --git a/src/layered-storage/validator-library/other.ts b/src/layered-storage/validator-library/other.ts new file mode 100644 index 000000000..12d25fa32 --- /dev/null +++ b/src/layered-storage/validator-library/other.ts @@ -0,0 +1,50 @@ +import { + LayeredStorageValidator, + LayeredStorageValidatorResult, + createValidator, +} from "./util"; + +/** + * Check that given value is equal (===) to one of the values listed. + * + * @param validValues - Specific allowed values. + * + * @returns New validator validating against given values. + */ +export function oneOf( + validValues: unknown[] | Set +): LayeredStorageValidator { + const valid = new Set(validValues); + + return createValidator( + "value has to be one of: " + + [...validValues.values()] + .map((validValue): string => { + try { + return JSON.stringify(validValue) ?? ""; + } catch (error) { + return `<${error.message}>`; + } + }) + .join(", "), + function oneOfValidator(value: unknown): LayeredStorageValidatorResult { + return valid.has(value); + } + ); +} + +export const fail: LayeredStorageValidator = createValidator( + "all values will fail", + // eslint-disable-next-line @typescript-eslint/no-unused-vars + function fail(_value: unknown): LayeredStorageValidatorResult { + return false; + } +); + +export const pass: LayeredStorageValidator = createValidator( + "all values will pass", + // eslint-disable-next-line @typescript-eslint/no-unused-vars + function pass(_value: unknown): LayeredStorageValidatorResult { + return true; + } +); diff --git a/src/layered-storage/validator-library/public-util.ts b/src/layered-storage/validator-library/public-util.ts new file mode 100644 index 000000000..994a1a900 --- /dev/null +++ b/src/layered-storage/validator-library/public-util.ts @@ -0,0 +1,39 @@ +export type LayeredStorageValidatorResult = boolean | string; +export interface LayeredStorageValidator { + (value: unknown): LayeredStorageValidatorResult; + description: string; +} + +/** + * Helper function for validator creation. + * + * @remarks + * It's use is optional. It's basically a wrapper around Object.assign() with a + * few checks thrown in. + * + * @param description - The description of the validator (should be in the + * format “value has to be a string”, that is starting with lowercase letter and + * ending without a period). + * @param func - The function that will do the validation itself (preferably + * should return boolean, can return string with addition info if necessary). + * + * @returns Given function enriched by description property (aka validator). + */ +export function createValidator( + description: string, + func: (value: unknown) => LayeredStorageValidatorResult +): LayeredStorageValidator { + if (typeof description !== "string" || description.length === 0) { + throw new TypeError("A description has to be provided for a validator."); + } + + if (typeof func !== "function") { + throw new TypeError("Validator function has to be a function."); + } + + if (func.length !== 1) { + throw new TypeError("Validator function has take exactly one argument."); + } + + return Object.assign(func, { description }); +} diff --git a/src/layered-storage/validator-library/string.ts b/src/layered-storage/validator-library/string.ts new file mode 100644 index 000000000..a1df647c8 --- /dev/null +++ b/src/layered-storage/validator-library/string.ts @@ -0,0 +1,106 @@ +import { + LayeredStorageValidator, + LayeredStorageValidatorResult, + createValidator, +} from "./util"; + +export const string: LayeredStorageValidator = createValidator( + "value has to be a string", + function string(value: unknown): LayeredStorageValidatorResult { + return typeof value === "string"; + } +); + +/** + * Check that given value is a string that is longer than given amount of + * characters. + * + * @param minLength - The boundary that the value will be checked against. + * + * @returns Validator curried with given boundary. + */ +export function stringLongerThan(minLength: number): LayeredStorageValidator { + return createValidator( + `value has to a string longer than ${minLength} characters`, + function stringLongerThanValidator( + value: unknown + ): LayeredStorageValidatorResult { + return typeof value === "string" && value.length > minLength; + } + ); +} + +/** + * Check that given value is a string that is shorter than given amount of + * characters. + * + * @param maxLength - The boundary that the value will be checked against. + * + * @returns Validator curried with given boundary. + */ +export function stringShorterThan(maxLength: number): LayeredStorageValidator { + return createValidator( + `value has to a string shorter than ${maxLength} characters`, + function stringShorterThanValidator( + value: unknown + ): LayeredStorageValidatorResult { + return typeof value === "string" && value.length < maxLength; + } + ); +} + +/** + * Check that given value is a string that is at least given amount of + * characters long. + * + * @param minLength - The boundary that the value will be checked against. + * + * @returns Validator curried with given boundary. + */ +export function stringAtLeast(minLength: number): LayeredStorageValidator { + return createValidator( + `value has to a string no shorter than ${minLength} characters`, + function stringAtLeastValidator( + value: unknown + ): LayeredStorageValidatorResult { + return typeof value === "string" && value.length >= minLength; + } + ); +} + +/** + * Check that given value is a string that is at most given amount of + * characters long. + * + * @param maxLength - The boundary that the value will be checked against. + * + * @returns Validator curried with given boundary. + */ +export function stringAtMost(maxLength: number): LayeredStorageValidator { + return createValidator( + `value has to a string no longer than ${maxLength} characters`, + function stringAtMostValidator( + value: unknown + ): LayeredStorageValidatorResult { + return typeof value === "string" && value.length <= maxLength; + } + ); +} + +/** + * Check that given values is a string that matches given RE. + * + * @param re - The regular expression that will be used for testing. + * + * @returns Validator validating against given RE. + */ +export function match(re: RegExp): LayeredStorageValidator { + return createValidator( + "value has to be a string and match: " + re.source, + function stringMatchValidator( + value: unknown + ): LayeredStorageValidatorResult { + return typeof value === "string" && re.test(value); + } + ); +} diff --git a/src/layered-storage/validator-library/util.ts b/src/layered-storage/validator-library/util.ts new file mode 100644 index 000000000..c2b9cdf79 --- /dev/null +++ b/src/layered-storage/validator-library/util.ts @@ -0,0 +1,24 @@ +import { LayeredStorageValidator } from "./public-util"; + +export * from "./public-util"; + +/** + * Create human readable sublist with header from multiple validators. + * + * @param header - The text that will be used as header (followed by colon). + * @param validators - The validators that will be used as bullets in the + * sublist. + * + * @returns Ready to use sublist with header. + */ +export function sublistDescriptions( + header: string, + validators: LayeredStorageValidator[] +): string { + return [ + `${header}:`, + ...[...validators.values()].map( + (validator): string => ` - ${validator.description}` + ), + ].join("\n"); +} diff --git a/test/layered-storage/expanders.ts b/test/layered-storage/expanders.ts index aae9dbbb2..f9240f100 100644 --- a/test/layered-storage/expanders.ts +++ b/test/layered-storage/expanders.ts @@ -1,4 +1,9 @@ -import { KeyValueEntry, LayeredStorage } from "../../src/layered-storage"; +import { + KeyValueEntry, + LayeredStorage, + match, + numberLowerThan, +} from "../../src/layered-storage"; import { expect } from "chai"; interface KV { @@ -60,10 +65,7 @@ export function expanders(): void { it("Invalid short value", function (): void { const ls = new LayeredStorage<0, KV, keyof KV>(); - ls.setValidators("test", [ - (value): true | string => - /^(true|false) \d+ .*$/.test(value) || "Invalid.", - ]); + ls.setValidators("test", [match(/^(true|false) \d+ .*$/)]); ls.setInvalidHandler(invalidHandler); ls.setExpander("test", expanderAffects, expander); @@ -78,9 +80,7 @@ export function expanders(): void { it("Invalid expanded value", function (): void { const ls = new LayeredStorage<0, KV, keyof KV>(); - ls.setValidators("test.number", [ - (value): true | string => value < 7 || "Invalid input.", - ]); + ls.setValidators("test.number", [numberLowerThan(7)]); ls.setInvalidHandler(invalidHandler); ls.setExpander("test", expanderAffects, expander); diff --git a/test/layered-storage/transactions.ts b/test/layered-storage/transactions.ts index 7884c0f8f..aa4812a8b 100644 --- a/test/layered-storage/transactions.ts +++ b/test/layered-storage/transactions.ts @@ -1,4 +1,4 @@ -import { LayeredStorage } from "../../src/layered-storage"; +import { LayeredStorage, stringAtLeast } from "../../src/layered-storage"; import { expect } from "chai"; interface KV { @@ -41,14 +41,8 @@ export function transactions(): void { ); }); - ls.setValidators("test.value1", [ - (value): true | string => - value.length < 4 ? "Minimum of 4 characters required" : true, - ]); - ls.setValidators("test.value2", [ - (value): true | string => - value.length < 4 ? "Minimum of 4 characters required" : true, - ]); + ls.setValidators("test.value1", [stringAtLeast(4)]); + ls.setValidators("test.value2", [stringAtLeast(4)]); const transaction = ls.global.openTransaction(); diff --git a/test/layered-storage/validation.ts b/test/layered-storage/validation.ts index a3b80a770..37a2a6227 100644 --- a/test/layered-storage/validation.ts +++ b/test/layered-storage/validation.ts @@ -1,4 +1,12 @@ -import { LayeredStorage } from "../../src/layered-storage"; +import { + LayeredStorage, + boolean, + fail, + number, + numberInteger, + pass, + string, +} from "../../src/layered-storage"; import { expect } from "chai"; interface KV { @@ -17,15 +25,15 @@ export function validation(): void { describe("Validation", function (): void { [ // No handler. - ["Default", null, null] as const, + ["Default", false, null] as const, // Handler that does nothing. - ["Ignore", null, (): void => {}] as const, + ["Ignore", false, (): void => {}] as const, // Handler that throws. [ "Throw", - TypeError, - (key: string, value: unknown, message: string): void => { - throw new TypeError(`${key}: ${value} (${message})`); + true, + (key: string, value: unknown, messages: string[]): void => { + throw new TypeError(`${key}: ${value} (${messages.join(", ")})`); }, ] as const, ].forEach(([name, throws, handler]): void => { @@ -52,30 +60,12 @@ export function validation(): void { } // Add validators. - ls.setValidators("test.boolean", [ - (value: unknown): true | string => - typeof value === "boolean" || "it's not valid", - ]); - ls.setValidators("test.fail", [ - (): true | string => false || "it's not valid", - ]); - ls.setValidators("test.integer", [ - // This tests multiple validators. - (value: unknown): true | string => - typeof value === "number" || "it's not valid", - (value: unknown): true | string => - (typeof value === "number" && value % 1 === 0) || - "it's not valid", - ]); - ls.setValidators("test.number", [ - (value: unknown): true | string => - typeof value === "number" || "it's not valid", - ]); - ls.setValidators("test.pass", [(): true | string => true]); - ls.setValidators("test.string", [ - (value: unknown): true | string => - typeof value === "string" || "it's not valid", - ]); + ls.setValidators("test.boolean", [boolean]); + ls.setValidators("test.fail", [fail]); + ls.setValidators("test.integer", [number, numberInteger]); + ls.setValidators("test.number", [number]); + ls.setValidators("test.pass", [pass]); + ls.setValidators("test.string", [string]); if (valid) { expect((): void => { @@ -86,12 +76,11 @@ export function validation(): void { "Valid values should be saved in the storage." ).to.equal(value); } else { - if (throws != null) { + if (throws) { expect((): void => { ls.global.set(0, key, value); }, "If the handler throws the set should throw too.").to.throw( - TypeError, - `${key}: ${value} (it's not valid)` + TypeError ); } else { expect((): void => { @@ -112,10 +101,8 @@ export function validation(): void { const ls = new LayeredStorage<0, KV, keyof KV>(); expect((): void => { - ls.setValidators("test.fail", [ - (): true | string => false || "it's not valid", - ]); - ls.setValidators("test.fail", [(): true | string => true]); + ls.setValidators("test.fail", [fail]); + ls.setValidators("test.fail", [pass]); }, "Setting validators repeatedly without replace shoudn't be allowed.").to.throw(); }); }); From 9175f38d7823d99731b90f2aecc469159f971a5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Sun, 31 May 2020 18:43:53 +0200 Subject: [PATCH 41/48] feat(layered-storage)!: use sepparate input and output types BREAKING CHANGE: The types are different, though the code is pretty much the same on the outside. This allows for typesafe expanding of values or transforming them (expanders allow both at the same time). --- src/layered-storage/common.ts | 9 +- src/layered-storage/core.ts | 246 +++++++++++------------- src/layered-storage/layered-storage.ts | 36 ++-- src/layered-storage/segment.ts | 38 ++-- src/layered-storage/transactions.ts | 51 ++--- test/layered-storage/all-combined.ts | 2 +- test/layered-storage/cloning.ts | 14 +- test/layered-storage/expanders.ts | 8 +- test/layered-storage/inheritance.ts | 12 +- test/layered-storage/multiple-keys.ts | 8 +- test/layered-storage/multiple-layers.ts | 8 +- test/layered-storage/other.ts | 14 +- test/layered-storage/segmented-layer.ts | 16 +- test/layered-storage/single-layer.ts | 12 +- test/layered-storage/transactions.ts | 4 +- test/layered-storage/validation.ts | 4 +- 16 files changed, 216 insertions(+), 266 deletions(-) diff --git a/src/layered-storage/common.ts b/src/layered-storage/common.ts index 267456867..4508d23aa 100644 --- a/src/layered-storage/common.ts +++ b/src/layered-storage/common.ts @@ -2,13 +2,12 @@ export type KeyRange = number | string | symbol; export type LayerRange = number; export type Segment = boolean | number | object | string | symbol; -export type KeyValueLookup = Record< - Keys, - boolean | number | object | string | symbol ->; +export type KeyValueLookup = { + [Key in KeyRange]: any; +}; export type KeyValueEntry< - KV extends object, + KV extends KeyValueLookup, Key extends keyof KV = keyof KV > = { [Key in keyof KV]: readonly [Key, KV[Key]]; diff --git a/src/layered-storage/core.ts b/src/layered-storage/core.ts index 989073cd6..058daafbc 100644 --- a/src/layered-storage/core.ts +++ b/src/layered-storage/core.ts @@ -12,26 +12,17 @@ const entriesByKeyPriority = ( b: [number, unknown] ): number => b[0] - a[0]; -type SegmentData< - KV extends KeyValueLookup, - Keys extends KeyRange = keyof KV -> = TypedMap; -type LayerData, Keys extends KeyRange> = Map< - Segment, - SegmentData +type SegmentData = TypedMap; +type LayerData = Map>; +type Data = Map< + Layer, + LayerData >; -type Data< - Layer extends LayerRange, - KV extends KeyValueLookup, - Keys extends KeyRange = keyof KV -> = Map>; - -interface TypedMap< - KV extends Record, - Keys extends KeyRange = keyof KV -> extends Map { - get(key: Key): undefined | KV[Key]; - set(key: Key, value: KV[Key]): this; + +interface TypedMap> + extends Map { + get(key: Key): undefined | KV[Key]; + set(key: Key, value: KV[Key]): this; } export type LayeredStorageInvalidValueHandler = ( @@ -45,16 +36,14 @@ export type LayeredStorageInvalidValueHandler = ( * handles the special global segment. * * @typeParam Layer - The allowed layers. - * (TS only, ignored in JS). - * @typeParam KV - The value types associeated with their keys. - * (TS only, ignored in JS). - * @typeParam Keys - The allowed keys. - * (TS only, ignored in JS). + * @typeParam IKV - The value types associeated with their keys on input (set). + * @typeParam OKV - The value types associeated with their keys on output (get, + * export). */ export class LayeredStorageCore< Layer extends LayerRange, - KV extends KeyValueLookup, - Keys extends KeyRange = keyof KV + IKV extends OKV, + OKV extends KeyValueLookup > { /** * This is a special segment that is used as fallback if the requested @@ -65,13 +54,13 @@ export class LayeredStorageCore< /** * Data stored as layer → segment → key → value. */ - private readonly _data: Data = new Map(); + private readonly _data: Data = new Map(); /** * An ordered list of layer datas. The highest priority (equals highest * number) layer is first. */ - private _layerDatas: LayerData[] = []; + private _layerDatas: LayerData[] = []; /** * A set of segments that keeps track what segments have data in the storage. @@ -92,9 +81,8 @@ export class LayeredStorageCore< */ private readonly _validators: TypedMap< { - [Key in Keys]: LayeredStorageValidator[]; - }, - Keys + [Key in keyof IKV]: LayeredStorageValidator[]; + } > = new Map(); /** @@ -102,15 +90,19 @@ export class LayeredStorageCore< */ private readonly _setExpanders: TypedMap< { - [Key in Keys]: (value: KV[Key]) => readonly KeyValueEntry[]; - }, - Keys + [Key in keyof IKV]: ( + value: IKV[Key] + ) => readonly KeyValueEntry[]; + } > = new Map(); /** * An expander for each key. */ - private readonly _deleteExpanders: Map = new Map(); + private readonly _deleteExpanders: Map< + keyof IKV, + readonly (keyof OKV)[] + > = new Map(); /** * This is called whenever a validity test fails. @@ -119,7 +111,7 @@ export class LayeredStorageCore< * @param value - The invalid value itself. * @param messages - All the message returned by the validators that failed. */ - private _invalidHandler: LayeredStorageInvalidValueHandler = ( + private _invalidHandler: LayeredStorageInvalidValueHandler = ( key, value, messages @@ -136,7 +128,7 @@ export class LayeredStorageCore< */ private readonly _topLevelCache = new Map< Segment, - TypedMap<{ [Key in Keys]: KV[Key] | null }, Keys> + TypedMap<{ [Key in keyof OKV]: OKV[Key] | null }> >(); /** @@ -145,7 +137,7 @@ export class LayeredStorageCore< * @param segment - Which segment to clean. * @param key - The key that was subject to the mutation. */ - private _cleanCache(segment: Segment, key: Keys): void { + private _cleanCache(segment: Segment, key: keyof OKV): void { if (segment === this.globalSegment) { // Run the search for each cached segment to clean the cached top level // value for each of them. The reason for this is that the global segment @@ -193,7 +185,7 @@ export class LayeredStorageCore< private _getLSData( layer: Layer, segment: Segment - ): { layerData: LayerData; segmentData: SegmentData } { + ): { layerData: LayerData; segmentData: SegmentData } { // Get or create the requested layer. let layerData = this._data.get(layer); if (typeof layerData === "undefined") { @@ -202,7 +194,7 @@ export class LayeredStorageCore< this._layerDatas = [...this._data.entries()] .sort(entriesByKeyPriority) - .map((pair): LayerData => pair[1]); + .map((pair): LayerData => pair[1]); } // Get or create the requested segment on the layer. @@ -226,10 +218,10 @@ export class LayeredStorageCore< * * @returns The value or undefined if it wasn't found. */ - public get( + public get( thisSegment: Segment, key: Key - ): KV[Key] | undefined { + ): OKV[Key] | undefined { let thisSegmentCache = this._topLevelCache.get(thisSegment); if (typeof thisSegmentCache === "undefined") { thisSegmentCache = new Map(); @@ -244,7 +236,7 @@ export class LayeredStorageCore< } // Fetch the inheritance chain. - const segments = this._inheritance.get(thisSegment) ?? [ + const segments = this._inheritance.get(thisSegment) || [ thisSegment, this.globalSegment, ]; @@ -296,62 +288,52 @@ export class LayeredStorageCore< * * @returns True if found, false otherwise. */ - public has(segment: Segment, key: Key): boolean { + public has(segment: Segment, key: Key): boolean { return typeof this.get(segment, key) !== "undefined"; } /** - * Validate the value now and set it later. + * Validate and expand the value now and set it later. * * @param layer - Which layer to save the value into. * @param segment - Which segment to save the value into. * @param key - Key that can be used to retrieve or overwrite this value later. * @param value - The value to be saved. * - * @returns Function that actually sets the validated value. + * @returns Function that actually sets the validated and expanded value. */ - public twoPartSet( + public twoPartSet( layer: Layer, segment: Segment, key: Key, - value: KV[Key] + value: IKV[Key] ): () => void { if (typeof layer !== "number") { throw new TypeError("Layers have to be numbers."); } - const valid = this._validate(key, value); - if (valid) { - // The value is valid. It can be safely saved into the storage. - return (): void => { - const { segmentData } = this._getLSData(layer, segment); - segmentData.set(key, value); - - this._cleanCache(segment, key); - }; - } else { - // The value is invalid. If the invalid value handler didn't throw, - // return empty function to prevent the value from being saved into - // the storage. + if (!this._validate(key, value)) { + // The value is invalid. If the invalid value handler didn't throw, return + // empty function to prevent the value from being saved into the storage. return (): void => {}; } - } - /** - * Save a value. - * - * @param layer - Which layer to save the value into. - * @param segment - Which segment to save the value into. - * @param key - Key that can be used to retrieve or overwrite this value later. - * @param value - The value to be saved. - */ - public set( - layer: Layer, - segment: Segment, - key: Key, - value: KV[Key] - ): void { - this.twoPartSet(layer, segment, key, value)(); + const expandedEntries = this._expand(key, value) + // The invalid value handler may throw here and abort everything otherwise + // skip just the invalid ones. + .filter((expandedEntry): boolean => + this._validate(expandedEntry[0], expandedEntry[1]) + ); + + // The value is valid. It can be safely saved into the storage. + return (): void => { + const { segmentData } = this._getLSData(layer, segment); + + for (const expandedEntry of expandedEntries) { + segmentData.set(expandedEntry[0], expandedEntry[1]); + this._cleanCache(segment, expandedEntry[0]); + } + }; } /** @@ -360,30 +342,40 @@ export class LayeredStorageCore< * @param layer - Which layer to delete from. * @param segment - Which segment to delete from. * @param key - The key that identifies the value to be deleted. + * + * @returns Function that actually deletes the values. */ - public delete( + public twoPartDelete( layer: Layer, segment: Segment, key: Key - ): void { + ): () => void { if (typeof layer !== "number") { throw new TypeError("Layers have to be numbers."); } - const { layerData, segmentData } = this._getLSData(layer, segment); - segmentData.delete(key); + return (): void => { + const { layerData, segmentData } = this._getLSData(layer, segment); - // Purge the segment if empty. - if (segmentData.size === 0) { - layerData.delete(segment); - } + const expandedKeys = this._deleteExpanders.get(key) || [key]; + for (const expandedKey of expandedKeys) { + segmentData.delete(expandedKey); + } - // Purge the layer if empty. - if (layerData.size === 0) { - this._data.delete(layer); - } + // Purge the segment if empty. + if (segmentData.size === 0) { + layerData.delete(segment); + } - this._cleanCache(segment, key); + // Purge the layer if empty. + if (layerData.size === 0) { + this._data.delete(layer); + } + + for (const expandedKey of expandedKeys) { + this._cleanCache(segment, expandedKey); + } + }; } /** @@ -422,7 +414,7 @@ export class LayeredStorageCore< * @returns Object representation of given segments' current data for given * keys. */ - public exportToObject(segment: Segment, compoundKeys: Keys[]): any { + public exportToObject(segment: Segment, compoundKeys: (keyof OKV)[]): any { const result: any = {}; for (const compoundKey of compoundKeys) { @@ -467,7 +459,7 @@ export class LayeredStorageCore< for (const layerData of this._data.values()) { const sourceSegmentData = layerData.get(sourceSegment); if (sourceSegmentData) { - const sourceSegmentCopy: SegmentData = new Map(); + const sourceSegmentCopy: SegmentData = new Map(); for (const entry of sourceSegmentData.entries()) { sourceSegmentCopy.set(entry[0], entry[1]); } @@ -504,7 +496,7 @@ export class LayeredStorageCore< * value and a message from the failed validator. */ public setInvalidHandler( - handler: LayeredStorageInvalidValueHandler + handler: LayeredStorageInvalidValueHandler ): void { this._invalidHandler = handler; } @@ -518,7 +510,7 @@ export class LayeredStorageCore< * @param replace - If true existing validators will be replaced, if false an * error will be thrown if some validators already exist for given key. */ - public setValidators( + public setValidators( key: Key, validators: LayeredStorageValidator[], replace: boolean @@ -538,7 +530,7 @@ export class LayeredStorageCore< * * @returns True if valid, false otherwise. */ - public _validate(key: Key, value: KV[Key]): boolean { + public _validate(key: Key, value: IKV[Key]): boolean { const messages = []; const validators = this._validators.get(key); @@ -561,6 +553,26 @@ export class LayeredStorageCore< return !messages.length; } + /** + * Expand given value. + * + * @param key - Which key this value belongs to. + * @param value - The value to be expanded. + * + * @returns Expanded key value pairs or empty array for invalid input. + */ + private _expand( + key: Key, + value: IKV[Key] + ): readonly KeyValueEntry[] { + const expand = this._setExpanders.get(key); + if (typeof expand === "undefined") { + return [[key, value]]; + } else { + return expand(value); + } + } + /** * Set an expander for given key. * @@ -576,10 +588,10 @@ export class LayeredStorageCore< * @param replace - If true existing expander will be replaced, if false an * error will be thrown if an expander already exists for given key. */ - public setExpander( + public setExpander( key: Key, affects: readonly Affects[], - expander: (value: KV[Key]) => readonly KeyValueEntry[], + expander: (value: IKV[Key]) => readonly KeyValueEntry[], replace: boolean ): void { if ( @@ -593,46 +605,6 @@ export class LayeredStorageCore< this._deleteExpanders.set(key, affects); } - /** - * Expand given value. - * - * @param key - Which key this value belongs to. - * @param value - The value to be expanded. - * - * @throws If the value is invalid and the invalid handler throws. - * - * @returns Expanded key value pairs or empty array for invalid input. - */ - public expandValue( - key: Key, - value: KV[Key] - ): readonly KeyValueEntry[] { - const valid = this._validate(key, value); - if (valid) { - const expand = this._setExpanders.get(key); - if (expand) { - return expand(value); - } else { - return [[key, value]]; - } - } else { - // The value is invalid. If the invalid value handler didn't throw, return - // empty entry to prevent the value from being saved into the storage. - return []; - } - } - - /** - * Expand given value. - * - * @param key - Which key this value belongs to. - * - * @returns Expanded key value pairs or empty array for invalid input. - */ - public expandDelete(key: Key): readonly Keys[] { - return this._deleteExpanders.get(key) || [key]; - } - /** * Log the content of the storage into the console. */ diff --git a/src/layered-storage/layered-storage.ts b/src/layered-storage/layered-storage.ts index d7639836f..e45492f22 100644 --- a/src/layered-storage/layered-storage.ts +++ b/src/layered-storage/layered-storage.ts @@ -1,10 +1,4 @@ -import { - KeyRange, - KeyValueEntry, - KeyValueLookup, - LayerRange, - Segment, -} from "./common"; +import { KeyValueEntry, KeyValueLookup, LayerRange, Segment } from "./common"; import { LayeredStorageCore, LayeredStorageInvalidValueHandler } from "./core"; import { LayeredStorageSegment } from "./segment"; import { LayeredStorageTransaction } from "./transactions"; @@ -21,20 +15,18 @@ export { LayeredStorageTransaction }; * - Segmented value overrides global (nonsegmented) value. * * @typeParam Layer - The allowed layers. - * (TS only, ignored in JS). - * @typeParam KV - The value types associeated with their keys. - * (TS only, ignored in JS). - * @typeParam Keys - The allowed keys. - * (TS only, ignored in JS). + * @typeParam IKV - The value types associeated with their keys on input (set). + * @typeParam OKV - The value types associeated with their keys on output (get, + * export). */ export class LayeredStorage< Layer extends LayerRange, - KV extends KeyValueLookup, - Keys extends KeyRange = keyof KV + IKV extends OKV, + OKV extends KeyValueLookup > { - private readonly _core = new LayeredStorageCore(); + private readonly _core = new LayeredStorageCore(); - public readonly global = new LayeredStorageSegment( + public readonly global = new LayeredStorageSegment( this._core, this._core.globalSegment ); @@ -46,7 +38,7 @@ export class LayeredStorage< * * @returns A new segmented instance permanently bound to this instance. */ - public openSegment(segment: Segment): LayeredStorageSegment { + public openSegment(segment: Segment): LayeredStorageSegment { return new LayeredStorageSegment(this._core, segment); } @@ -64,7 +56,7 @@ export class LayeredStorage< public cloneSegment( sourceSegment: Segment, targetSegment: Segment - ): LayeredStorageSegment { + ): LayeredStorageSegment { this._core.cloneSegmentData(sourceSegment, targetSegment); return new LayeredStorageSegment(this._core, targetSegment); } @@ -85,7 +77,7 @@ export class LayeredStorage< * value and a message from the failed validator. */ public setInvalidHandler( - handler: LayeredStorageInvalidValueHandler + handler: LayeredStorageInvalidValueHandler ): void { this._core.setInvalidHandler(handler); } @@ -99,7 +91,7 @@ export class LayeredStorage< * @param replace - If true existing validators will be replaced, if false an * error will be thrown if some validators already exist for given key. */ - public setValidators( + public setValidators( key: Key, validators: LayeredStorageValidator[], replace = false @@ -118,10 +110,10 @@ export class LayeredStorage< * @param replace - If true existing expander will be relaced, if false an * error will be thrown if an expander already exists for given key. */ - public setExpander( + public setExpander( key: Key, affects: readonly Affects[], - expander: (value: KV[Key]) => readonly KeyValueEntry[], + expander: (value: IKV[Key]) => readonly KeyValueEntry[], replace = false ): void { this._core.setExpander(key, affects, expander, replace); diff --git a/src/layered-storage/segment.ts b/src/layered-storage/segment.ts index 0f473b875..dbb8a944b 100644 --- a/src/layered-storage/segment.ts +++ b/src/layered-storage/segment.ts @@ -1,4 +1,4 @@ -import { KeyValueLookup, LayerRange, Segment, KeyRange } from "./common"; +import { KeyValueLookup, LayerRange, Segment } from "./common"; import { LayeredStorageCore } from "./core"; import { LayeredStorageTransaction } from "./transactions"; @@ -7,16 +7,14 @@ import { LayeredStorageTransaction } from "./transactions"; * given `LayeredStorage` and can only access a single `Segment`. * * @typeParam Layer - The allowed layers. - * (TS only, ignored in JS). - * @typeParam KV - The value types associeated with their keys. - * (TS only, ignored in JS). - * @typeParam Keys - The allowed keys. - * (TS only, ignored in JS). + * @typeParam IKV - The value types associeated with their keys on input (set). + * @typeParam OKV - The value types associeated with their keys on output (get, + * export). */ export class LayeredStorageSegment< Layer extends LayerRange, - KV extends KeyValueLookup, - Keys extends KeyRange = keyof KV + IKV extends OKV, + OKV extends KeyValueLookup > { /** * Create a new storage instance for given segment. @@ -25,7 +23,7 @@ export class LayeredStorageSegment< * @param segment - The segment this instance will manage. */ public constructor( - private readonly _core: LayeredStorageCore, + private readonly _core: LayeredStorageCore, public readonly segment: Segment ) {} @@ -36,7 +34,7 @@ export class LayeredStorageSegment< * * @returns The value or undefined if not found. */ - public get(key: Key): KV[Key] | undefined { + public get(key: Key): OKV[Key] | undefined { return this._core.get(this.segment, key); } @@ -47,7 +45,7 @@ export class LayeredStorageSegment< * * @returns True if found, false otherwise. */ - public has(key: Key): boolean { + public has(key: keyof OKV): boolean { return this._core.has(this.segment, key); } @@ -58,7 +56,11 @@ export class LayeredStorageSegment< * @param key - Key that can be used to retrieve or overwrite this value later. * @param value - The value to be saved. */ - public set(layer: Layer, key: Key, value: KV[Key]): void { + public set( + layer: Layer, + key: Key, + value: IKV[Key] + ): void { this.runTransaction((transaction): void => { transaction.set(layer, key, value); }); @@ -70,7 +72,7 @@ export class LayeredStorageSegment< * @param layer - Which layer to delete from. * @param key - The key that identifies the value to be deleted. */ - public delete(layer: Layer, key: Key): void { + public delete(layer: Layer, key: keyof IKV): void { this.runTransaction((transaction): void => { transaction.delete(layer, key); }); @@ -98,7 +100,7 @@ export class LayeredStorageSegment< */ public cloneSegment( targetSegment: Segment - ): LayeredStorageSegment { + ): LayeredStorageSegment { this._core.cloneSegmentData(this.segment, targetSegment); return new LayeredStorageSegment(this._core, targetSegment); } @@ -112,8 +114,8 @@ export class LayeredStorageSegment< * * @returns The new transaction that can be used to set or delete values. */ - public openTransaction(): LayeredStorageTransaction { - return new LayeredStorageTransaction( + public openTransaction(): LayeredStorageTransaction { + return new LayeredStorageTransaction( this._core, this.segment ); @@ -131,7 +133,7 @@ export class LayeredStorageSegment< * it's sole argument. */ public runTransaction( - callback: (transaction: LayeredStorageTransaction) => void + callback: (transaction: LayeredStorageTransaction) => void ): void { const transaction = this.openTransaction(); @@ -154,7 +156,7 @@ export class LayeredStorageSegment< * @returns Object representation of given segments current data for * given keys. */ - public exportToObject(keys: Keys[]): void { + public exportToObject(keys: (keyof OKV)[]): void { return this._core.exportToObject(this.segment, keys); } diff --git a/src/layered-storage/transactions.ts b/src/layered-storage/transactions.ts index a4a7e50ef..2e5c8afb1 100644 --- a/src/layered-storage/transactions.ts +++ b/src/layered-storage/transactions.ts @@ -1,20 +1,18 @@ -import { KeyValueLookup, LayerRange, Segment, KeyRange } from "./common"; +import { KeyValueLookup, LayerRange, Segment } from "./common"; import { LayeredStorageCore } from "./core"; /** * A transaction working with a single segment. * * @typeParam Layer - The allowed layers. - * (TS only, ignored in JS). - * @typeParam KV - The value types associeated with their keys. - * (TS only, ignored in JS). - * @typeParam Keys - The allowed keys. - * (TS only, ignored in JS). + * @typeParam IKV - The value types associeated with their keys on input (set). + * @typeParam OKV - The value types associeated with their keys on output (get, + * export). */ export class LayeredStorageTransaction< Layer extends LayerRange, - KV extends KeyValueLookup, - Keys extends KeyRange = keyof KV + IKV extends OKV, + OKV extends KeyValueLookup > { /** * Functions that perform requested mutations when executed without any @@ -30,7 +28,7 @@ export class LayeredStorageTransaction< * @param _segment - The segment this instance will manage. */ public constructor( - private readonly _storageCore: LayeredStorageCore, + private readonly _storageCore: LayeredStorageCore, private readonly _segment: Segment ) {} @@ -41,18 +39,14 @@ export class LayeredStorageTransaction< * @param key - Key that can be used to retrieve or overwrite this value later. * @param value - The value to be saved. */ - public set(layer: Layer, key: Key, value: KV[Key]): void { - const expandedPairs = this._storageCore.expandValue(key, value); - for (const expanded of expandedPairs) { - this._actions.push( - this._storageCore.twoPartSet( - layer, - this._segment, - expanded[0], - expanded[1] - ) - ); - } + public set( + layer: Layer, + key: Key, + value: IKV[Key] + ): void { + this._actions.push( + this._storageCore.twoPartSet(layer, this._segment, key, value) + ); } /** @@ -61,17 +55,10 @@ export class LayeredStorageTransaction< * @param layer - Which layer to delete from. * @param key - The key that identifies the value to be deleted. */ - public delete(layer: Layer, key: Key): void { - for (const expandedKey of this._storageCore.expandDelete(key)) { - this._actions.push( - this._storageCore.delete.bind( - this._storageCore, - layer, - this._segment, - expandedKey - ) - ); - } + public delete(layer: Layer, key: keyof IKV): void { + this._actions.push( + this._storageCore.twoPartDelete(layer, this._segment, key) + ); } /** diff --git a/test/layered-storage/all-combined.ts b/test/layered-storage/all-combined.ts index 518552482..1df34f986 100644 --- a/test/layered-storage/all-combined.ts +++ b/test/layered-storage/all-combined.ts @@ -53,7 +53,7 @@ const expectedResultMinusABC = deepFreeze({ */ export function allCombined(): void { it("All combined", function (): void { - const ls = new LayeredStorage<1 | 4 | 9, KV, keyof KV>(); + const ls = new LayeredStorage<1 | 4 | 9, KV, KV>(); const a = ls.openSegment("a"); const b = ls.openSegment("b"); diff --git a/test/layered-storage/cloning.ts b/test/layered-storage/cloning.ts index adfa5e415..795bf9234 100644 --- a/test/layered-storage/cloning.ts +++ b/test/layered-storage/cloning.ts @@ -16,25 +16,25 @@ export function cloning(): void { const configs: { name: string; clone( - ls: LayeredStorage<0 | 1 | 2, KV, keyof KV>, - s1: LayeredStorageSegment<0 | 1 | 2, KV, keyof KV> - ): LayeredStorageSegment<0 | 1 | 2, KV, keyof KV>; + ls: LayeredStorage<0 | 1 | 2, KV, KV>, + s1: LayeredStorageSegment<0 | 1 | 2, KV, KV> + ): LayeredStorageSegment<0 | 1 | 2, KV, KV>; }[] = [ { name: "From main instance", - clone: (ls): LayeredStorageSegment<0 | 1 | 2, KV, keyof KV> => + clone: (ls): LayeredStorageSegment<0 | 1 | 2, KV, KV> => ls.cloneSegment(1, 2), }, { name: "From segment instance", - clone: (_ls, s1): LayeredStorageSegment<0 | 1 | 2, KV, keyof KV> => + clone: (_ls, s1): LayeredStorageSegment<0 | 1 | 2, KV, KV> => s1.cloneSegment(2), }, ]; configs.forEach(({ name, clone }): void => { it(name, function (): void { - const ls = new LayeredStorage<0 | 1 | 2, KV, keyof KV>(); + const ls = new LayeredStorage<0 | 1 | 2, KV, KV>(); const s1 = ls.openSegment(1); @@ -71,7 +71,7 @@ export function cloning(): void { }); it("Cloning into existing segment", function (): void { - const ls = new LayeredStorage<1, KV, keyof KV>(); + const ls = new LayeredStorage<1, KV, KV>(); const s1 = ls.openSegment(1); const s2 = ls.openSegment(2); diff --git a/test/layered-storage/expanders.ts b/test/layered-storage/expanders.ts index f9240f100..0b4aa1fec 100644 --- a/test/layered-storage/expanders.ts +++ b/test/layered-storage/expanders.ts @@ -41,7 +41,7 @@ export function expanders(): void { }; it("Without validation", function (): void { - const ls = new LayeredStorage<0, KV, keyof KV>(); + const ls = new LayeredStorage<0, KV, KV>(); ls.setExpander("test", expanderAffects, expander); @@ -63,7 +63,7 @@ export function expanders(): void { }); it("Invalid short value", function (): void { - const ls = new LayeredStorage<0, KV, keyof KV>(); + const ls = new LayeredStorage<0, KV, KV>(); ls.setValidators("test", [match(/^(true|false) \d+ .*$/)]); ls.setInvalidHandler(invalidHandler); @@ -78,7 +78,7 @@ export function expanders(): void { }); it("Invalid expanded value", function (): void { - const ls = new LayeredStorage<0, KV, keyof KV>(); + const ls = new LayeredStorage<0, KV, KV>(); ls.setValidators("test.number", [numberLowerThan(7)]); ls.setInvalidHandler(invalidHandler); @@ -93,7 +93,7 @@ export function expanders(): void { }); it("Delete expanded values", function (): void { - const ls = new LayeredStorage<0, KV, keyof KV>(); + const ls = new LayeredStorage<0, KV, KV>(); ls.setExpander("test", expanderAffects, expander); diff --git a/test/layered-storage/inheritance.ts b/test/layered-storage/inheritance.ts index 09e45703a..e13704807 100644 --- a/test/layered-storage/inheritance.ts +++ b/test/layered-storage/inheritance.ts @@ -26,7 +26,7 @@ export function inheritance(): void { const f = Symbol("F"); it("Default inheritance", function (): void { - const ls = new LayeredStorage<7, KV, keyof KV>(); + const ls = new LayeredStorage<7, KV, KV>(); ls.global.set(7, "test.value", "global"); ls.openSegment(a).set(7, "test.value", "A"); @@ -39,7 +39,7 @@ export function inheritance(): void { }); it("Disable global inheritance", function (): void { - const ls = new LayeredStorage<7, KV, keyof KV>(); + const ls = new LayeredStorage<7, KV, KV>(); ls.global.set(7, "test.value", "global"); ls.openSegment(a).set(7, "test.value", "A"); @@ -53,7 +53,7 @@ export function inheritance(): void { }); it("Other segment without global", function (): void { - const ls = new LayeredStorage<3 | 7, KV, keyof KV>(); + const ls = new LayeredStorage<3 | 7, KV, KV>(); ls.global.set(7, "test.value", "global"); ls.openSegment(a).set(7, "test.value", "A"); @@ -67,7 +67,7 @@ export function inheritance(): void { }); it("Other segment with global", function (): void { - const ls = new LayeredStorage<3 | 7, KV, keyof KV>(); + const ls = new LayeredStorage<3 | 7, KV, KV>(); ls.global.set(7, "test.value", "global"); ls.openSegment(a).set(3, "test.value", "A"); @@ -81,7 +81,7 @@ export function inheritance(): void { }); it("Multiple inheritance", function (): void { - const ls = new LayeredStorage<3 | 7, KV, keyof KV>(); + const ls = new LayeredStorage<3 | 7, KV, KV>(); ls.openSegment(f).setInheritance([e, d, c, b, a]); @@ -130,7 +130,7 @@ export function inheritance(): void { }); it("Change inheritance", function (): void { - const ls = new LayeredStorage<3 | 7, KV, keyof KV>(); + const ls = new LayeredStorage<3 | 7, KV, KV>(); ls.global.set(7, "test.value", "global"); ls.openSegment(a).set(7, "test.value", "A"); diff --git a/test/layered-storage/multiple-keys.ts b/test/layered-storage/multiple-keys.ts index 5c38abe85..65e6c2667 100644 --- a/test/layered-storage/multiple-keys.ts +++ b/test/layered-storage/multiple-keys.ts @@ -18,7 +18,7 @@ export function multipleKeys(): void { const testValue3: KV["test.value3"] = "abc"; it("Set and get", function (): void { - const ls = new LayeredStorage<3, KV, keyof KV>(); + const ls = new LayeredStorage<3, KV, KV>(); ls.global.set(3, "test.value1", testValue1); ls.global.set(3, "test.value2", testValue2); @@ -39,7 +39,7 @@ export function multipleKeys(): void { }); it("Set and has", function (): void { - const ls = new LayeredStorage<3, KV, keyof KV>(); + const ls = new LayeredStorage<3, KV, KV>(); ls.global.set(3, "test.value1", testValue1); ls.global.set(3, "test.value2", testValue2); @@ -60,7 +60,7 @@ export function multipleKeys(): void { }); it("Set, delete and get", function (): void { - const ls = new LayeredStorage<3, KV, keyof KV>(); + const ls = new LayeredStorage<3, KV, KV>(); expect( ls.global.get("test.value2"), @@ -87,7 +87,7 @@ export function multipleKeys(): void { }); it("Set, delete and has", function (): void { - const ls = new LayeredStorage<3, KV, keyof KV>(); + const ls = new LayeredStorage<3, KV, KV>(); expect( ls.global.has("test.value2"), diff --git a/test/layered-storage/multiple-layers.ts b/test/layered-storage/multiple-layers.ts index c87e9130c..1d4fa6e02 100644 --- a/test/layered-storage/multiple-layers.ts +++ b/test/layered-storage/multiple-layers.ts @@ -30,7 +30,7 @@ export function multipleLayers(): void { }); it("Set and get", function (): void { - const ls = new LayeredStorage<1 | 2 | 3 | 4, KV, keyof KV>(); + const ls = new LayeredStorage<1 | 2 | 3 | 4, KV, KV>(); ls.global.set(1, "test.value", testValue1); expect( @@ -52,7 +52,7 @@ export function multipleLayers(): void { }); it("Set and has", function (): void { - const ls = new LayeredStorage<1 | 2 | 3 | 4, KV, keyof KV>(); + const ls = new LayeredStorage<1 | 2 | 3 | 4, KV, KV>(); expect( ls.global.has("test.value"), @@ -73,7 +73,7 @@ export function multipleLayers(): void { }); it("Set, delete and get", function (): void { - const ls = new LayeredStorage<1 | 2 | 3 | 4, KV, keyof KV>(); + const ls = new LayeredStorage<1 | 2 | 3 | 4, KV, KV>(); expect( ls.global.get("test.value"), @@ -106,7 +106,7 @@ export function multipleLayers(): void { }); it("Set, delete and has", function (): void { - const ls = new LayeredStorage<1 | 2 | 3 | 4, KV, keyof KV>(); + const ls = new LayeredStorage<1 | 2 | 3 | 4, KV, KV>(); expect( ls.global.has("test.value"), diff --git a/test/layered-storage/other.ts b/test/layered-storage/other.ts index 092a645b7..acaf21038 100644 --- a/test/layered-storage/other.ts +++ b/test/layered-storage/other.ts @@ -7,9 +7,7 @@ type KV = Record; * Other tests that don't fit elsewhere. */ export function other(): void { - const getStructCount = ( - ls: LayeredStorage<1 | 4 | 9, KV, keyof KV> - ): number => + const getStructCount = (ls: LayeredStorage<1 | 4 | 9, KV, KV>): number => [ // Ignore private property access errors. It's no big deal since this // is a unit test. @@ -25,14 +23,14 @@ export function other(): void { ); }, 0); - const getCacheSize = (ls: LayeredStorage<1 | 4 | 9, KV, keyof KV>): number => + const getCacheSize = (ls: LayeredStorage<1 | 4 | 9, KV, KV>): number => // Ignore private property access errors. It's no big deal since this // is a unit test. // @ts-ignore ls._core._topLevelCache.size; it("Empty data structure purging", function (): void { - const ls = new LayeredStorage<1 | 4 | 9, KV, keyof KV>(); + const ls = new LayeredStorage<1 | 4 | 9, KV, KV>(); ([1, 4, 9] as const).forEach((layer): void => { ls.global.set(layer, "test.value1", 1); @@ -87,7 +85,7 @@ export function other(): void { }); it("Cache purging", function (): void { - const ls = new LayeredStorage<1, KV, keyof KV>(); + const ls = new LayeredStorage<1, KV, KV>(); expect(getCacheSize(ls)).to.equal(0); @@ -122,7 +120,7 @@ export function other(): void { }); it("Empty data structure creation", function (): void { - const ls = new LayeredStorage<1 | 4 | 9, KV, keyof KV>(); + const ls = new LayeredStorage<1 | 4 | 9, KV, KV>(); ls.openSegment("c").set(4, "test.value1", 1); @@ -137,7 +135,7 @@ export function other(): void { }); it("Segment storage reports it's segment", function (): void { - const ls = new LayeredStorage<1 | 4 | 9, KV, keyof KV>(); + const ls = new LayeredStorage<1 | 4 | 9, KV, KV>(); expect( ls.openSegment("$"), diff --git a/test/layered-storage/segmented-layer.ts b/test/layered-storage/segmented-layer.ts index 8796acb75..a31fcda6c 100644 --- a/test/layered-storage/segmented-layer.ts +++ b/test/layered-storage/segmented-layer.ts @@ -30,7 +30,7 @@ export function segmentedLayer(): void { const c = Symbol("C"); it("Get without set", function (): void { - const ls = new LayeredStorage<7, KV, keyof KV>(); + const ls = new LayeredStorage<7, KV, KV>(); ls.global.set(7, "test.value", testValueA); @@ -41,7 +41,7 @@ export function segmentedLayer(): void { }); it("Get without set after unrelated set", function (): void { - const ls = new LayeredStorage<7, KV, keyof KV>(); + const ls = new LayeredStorage<7, KV, KV>(); ls.global.set(7, "test.value", testValueA); ls.openSegment(b).set(7, "unrelated.value", testValueB); @@ -53,7 +53,7 @@ export function segmentedLayer(): void { }); it("Set and get", function (): void { - const ls = new LayeredStorage<7, KV, keyof KV>(); + const ls = new LayeredStorage<7, KV, KV>(); ls.openSegment(a).set(7, "test.value", testValueA); ls.openSegment(b).set(7, "test.value", testValueB); @@ -79,7 +79,7 @@ export function segmentedLayer(): void { }); it("Set and has", function (): void { - const ls = new LayeredStorage<7, KV, keyof KV>(); + const ls = new LayeredStorage<7, KV, KV>(); ls.openSegment(b).set(7, "test.value", testValueB); @@ -103,7 +103,7 @@ export function segmentedLayer(): void { }); it("Set, delete and get", function (): void { - const ls = new LayeredStorage<7, KV, keyof KV>(); + const ls = new LayeredStorage<7, KV, KV>(); expect( ls.openSegment(c).get("test.value"), @@ -124,7 +124,7 @@ export function segmentedLayer(): void { }); it("Set, delete and has", function (): void { - const ls = new LayeredStorage<7, KV, keyof KV>(); + const ls = new LayeredStorage<7, KV, KV>(); expect( ls.openSegment(c).get("test.value"), @@ -153,7 +153,7 @@ export function segmentedLayer(): void { "test.value2": string; } - const ls = new LayeredStorage<0 | 2, LocalKV, keyof LocalKV>(); + const ls = new LayeredStorage<0 | 2, LocalKV, LocalKV>(); ls.global.runTransaction((transaction): void => { transaction.set(0, "test.value1", "a value from global segment"); @@ -201,7 +201,7 @@ export function segmentedLayer(): void { [undefined, null, "string", true, false, {}].forEach( (layer: any): void => { it("" + layer, function (): void { - const ls = new LayeredStorage<0, KV, keyof KV>(); + const ls = new LayeredStorage<0, KV, KV>(); expect( (): void => diff --git a/test/layered-storage/single-layer.ts b/test/layered-storage/single-layer.ts index c2cbff0fa..9401a224d 100644 --- a/test/layered-storage/single-layer.ts +++ b/test/layered-storage/single-layer.ts @@ -17,7 +17,7 @@ export function singleLayer(): void { }); it("Set and get", function (): void { - const ls = new LayeredStorage<0, KV, keyof KV>(); + const ls = new LayeredStorage<0, KV, KV>(); ls.global.set(0, "test.value", testValue); expect( @@ -27,7 +27,7 @@ export function singleLayer(): void { }); it("Set and has", function (): void { - const ls = new LayeredStorage<0, KV, keyof KV>(); + const ls = new LayeredStorage<0, KV, KV>(); ls.global.set(0, "test.value", testValue); expect( @@ -37,7 +37,7 @@ export function singleLayer(): void { }); it("Set, delete and get", function (): void { - const ls = new LayeredStorage<0, KV, keyof KV>(); + const ls = new LayeredStorage<0, KV, KV>(); expect( ls.global.get("test.value"), @@ -58,7 +58,7 @@ export function singleLayer(): void { }); it("Set, delete and has", function (): void { - const ls = new LayeredStorage<0, KV, keyof KV>(); + const ls = new LayeredStorage<0, KV, KV>(); expect( ls.global.has("test.value"), @@ -86,7 +86,7 @@ export function singleLayer(): void { "test.value": string; } - const ls = new LayeredStorage<0 | 2, LocalKV, keyof LocalKV>(); + const ls = new LayeredStorage<0 | 2, LocalKV, LocalKV>(); ls.global.set(0, "test.value", "0tv"); ls.global.set(2, "test.deeply.nested.value", "2tdnv"); @@ -118,7 +118,7 @@ export function singleLayer(): void { [undefined, null, "string", true, false, {}].forEach( (layer: any): void => { it("" + layer, function (): void { - const ls = new LayeredStorage<0, KV, keyof KV>(); + const ls = new LayeredStorage<0, KV, KV>(); expect( (): void => void ls.global.set(layer, "test.value", testValue), diff --git a/test/layered-storage/transactions.ts b/test/layered-storage/transactions.ts index aa4812a8b..64c60849b 100644 --- a/test/layered-storage/transactions.ts +++ b/test/layered-storage/transactions.ts @@ -14,7 +14,7 @@ interface KV { export function transactions(): void { describe("Transactions", function (): void { it("Transaction shouldn't save anything before commit", function (): void { - const ls = new LayeredStorage<7, KV, keyof KV>(); + const ls = new LayeredStorage<7, KV, KV>(); const transaction = ls.global.openTransaction(); @@ -32,7 +32,7 @@ export function transactions(): void { }); it("Transaction shouldn't save anything before commit", function (): void { - const ls = new LayeredStorage<7, KV, keyof KV>(); + const ls = new LayeredStorage<7, KV, KV>(); ls.setInvalidHandler((key, value, message): void => { throw new TypeError( diff --git a/test/layered-storage/validation.ts b/test/layered-storage/validation.ts index 37a2a6227..9f9645dee 100644 --- a/test/layered-storage/validation.ts +++ b/test/layered-storage/validation.ts @@ -52,7 +52,7 @@ export function validation(): void { [true, "test.string", "test"] as const, ].forEach(([valid, key, value]): void => { it(`${key}: ${value}`, function (): void { - const ls = new LayeredStorage<0, KV, keyof KV>(); + const ls = new LayeredStorage<0, KV, KV>(); // Add handler. if (handler != null) { @@ -98,7 +98,7 @@ export function validation(): void { }); it("Setting validators twice", function (): void { - const ls = new LayeredStorage<0, KV, keyof KV>(); + const ls = new LayeredStorage<0, KV, KV>(); expect((): void => { ls.setValidators("test.fail", [fail]); From 9089b807d05d0bc2064906a8699cfc0d1bfc7d54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Sun, 31 May 2020 21:24:34 +0200 Subject: [PATCH 42/48] fix(layered-storage): expand keys recursively --- src/layered-storage/core.ts | 93 ++++++++++++++------------ src/layered-storage/layered-storage.ts | 6 +- src/layered-storage/segment.ts | 2 +- src/layered-storage/transactions.ts | 6 +- test/layered-storage/expanders.ts | 47 +++++++++++++ 5 files changed, 104 insertions(+), 50 deletions(-) diff --git a/src/layered-storage/core.ts b/src/layered-storage/core.ts index 058daafbc..70eda2d80 100644 --- a/src/layered-storage/core.ts +++ b/src/layered-storage/core.ts @@ -101,7 +101,7 @@ export class LayeredStorageCore< */ private readonly _deleteExpanders: Map< keyof IKV, - readonly (keyof OKV)[] + readonly (keyof IKV)[] > = new Map(); /** @@ -288,7 +288,7 @@ export class LayeredStorageCore< * * @returns True if found, false otherwise. */ - public has(segment: Segment, key: Key): boolean { + public has(segment: Segment, key: keyof OKV): boolean { return typeof this.get(segment, key) !== "undefined"; } @@ -318,22 +318,27 @@ export class LayeredStorageCore< return (): void => {}; } - const expandedEntries = this._expand(key, value) - // The invalid value handler may throw here and abort everything otherwise - // skip just the invalid ones. - .filter((expandedEntry): boolean => - this._validate(expandedEntry[0], expandedEntry[1]) - ); + const expandedEntries = this._expand(key, value); + if (typeof expandedEntries === "undefined") { + // This is the final key, save it. + return (): void => { + const { segmentData } = this._getLSData(layer, segment); - // The value is valid. It can be safely saved into the storage. - return (): void => { - const { segmentData } = this._getLSData(layer, segment); + segmentData.set(key, value); + this._cleanCache(segment, key); + }; + } else { + // There are some expansions for this key, process them. + const funcs = expandedEntries.map((entry): (() => void) => + this.twoPartSet(layer, segment, entry[0], entry[1]) + ); - for (const expandedEntry of expandedEntries) { - segmentData.set(expandedEntry[0], expandedEntry[1]); - this._cleanCache(segment, expandedEntry[0]); - } - }; + return (): void => { + for (const func of funcs) { + func(); + } + }; + } } /** @@ -342,25 +347,18 @@ export class LayeredStorageCore< * @param layer - Which layer to delete from. * @param segment - Which segment to delete from. * @param key - The key that identifies the value to be deleted. - * - * @returns Function that actually deletes the values. */ - public twoPartDelete( - layer: Layer, - segment: Segment, - key: Key - ): () => void { + public delete(layer: Layer, segment: Segment, key: keyof IKV): void { if (typeof layer !== "number") { throw new TypeError("Layers have to be numbers."); } - return (): void => { + const expandedKeys = this._deleteExpanders.get(key); + if (typeof expandedKeys === "undefined") { + // This is the final key, delete it. const { layerData, segmentData } = this._getLSData(layer, segment); - const expandedKeys = this._deleteExpanders.get(key) || [key]; - for (const expandedKey of expandedKeys) { - segmentData.delete(expandedKey); - } + segmentData.delete(key); // Purge the segment if empty. if (segmentData.size === 0) { @@ -372,10 +370,13 @@ export class LayeredStorageCore< this._data.delete(layer); } + this._cleanCache(segment, key); + } else { + // There are some expansions for this key, process them. for (const expandedKey of expandedKeys) { - this._cleanCache(segment, expandedKey); + this.delete(layer, segment, expandedKey); } - }; + } } /** @@ -387,7 +388,7 @@ export class LayeredStorageCore< */ public setInheritance( segment: Segment, - segments: Segment[], + segments: readonly Segment[], global = true ): void { this._inheritance.set( @@ -414,7 +415,10 @@ export class LayeredStorageCore< * @returns Object representation of given segments' current data for given * keys. */ - public exportToObject(segment: Segment, compoundKeys: (keyof OKV)[]): any { + public exportToObject( + segment: Segment, + compoundKeys: readonly (keyof OKV)[] + ): any { const result: any = {}; for (const compoundKey of compoundKeys) { @@ -510,8 +514,8 @@ export class LayeredStorageCore< * @param replace - If true existing validators will be replaced, if false an * error will be thrown if some validators already exist for given key. */ - public setValidators( - key: Key, + public setValidators( + key: keyof IKV, validators: LayeredStorageValidator[], replace: boolean ): void { @@ -564,11 +568,9 @@ export class LayeredStorageCore< private _expand( key: Key, value: IKV[Key] - ): readonly KeyValueEntry[] { + ): readonly KeyValueEntry[] | undefined { const expand = this._setExpanders.get(key); - if (typeof expand === "undefined") { - return [[key, value]]; - } else { + if (typeof expand !== "undefined") { return expand(value); } } @@ -588,10 +590,10 @@ export class LayeredStorageCore< * @param replace - If true existing expander will be replaced, if false an * error will be thrown if an expander already exists for given key. */ - public setExpander( + public setExpander( key: Key, - affects: readonly Affects[], - expander: (value: IKV[Key]) => readonly KeyValueEntry[], + affects: readonly (keyof IKV)[], + expander: (value: IKV[Key]) => readonly KeyValueEntry[], replace: boolean ): void { if ( @@ -601,8 +603,13 @@ export class LayeredStorageCore< throw new Error("An expander for this key already exists."); } - this._setExpanders.set(key, expander); - this._deleteExpanders.set(key, affects); + if (affects.length) { + this._setExpanders.set(key, expander); + this._deleteExpanders.set(key, affects.slice()); + } else { + this._setExpanders.delete(key); + this._deleteExpanders.delete(key); + } } /** diff --git a/src/layered-storage/layered-storage.ts b/src/layered-storage/layered-storage.ts index e45492f22..5e8a52625 100644 --- a/src/layered-storage/layered-storage.ts +++ b/src/layered-storage/layered-storage.ts @@ -110,10 +110,10 @@ export class LayeredStorage< * @param replace - If true existing expander will be relaced, if false an * error will be thrown if an expander already exists for given key. */ - public setExpander( + public setExpander( key: Key, - affects: readonly Affects[], - expander: (value: IKV[Key]) => readonly KeyValueEntry[], + affects: readonly (keyof IKV)[], + expander: (value: IKV[Key]) => readonly KeyValueEntry[], replace = false ): void { this._core.setExpander(key, affects, expander, replace); diff --git a/src/layered-storage/segment.ts b/src/layered-storage/segment.ts index dbb8a944b..97cbb2239 100644 --- a/src/layered-storage/segment.ts +++ b/src/layered-storage/segment.ts @@ -156,7 +156,7 @@ export class LayeredStorageSegment< * @returns Object representation of given segments current data for * given keys. */ - public exportToObject(keys: (keyof OKV)[]): void { + public exportToObject(keys: readonly (keyof OKV)[]): void { return this._core.exportToObject(this.segment, keys); } diff --git a/src/layered-storage/transactions.ts b/src/layered-storage/transactions.ts index 2e5c8afb1..6be6d1535 100644 --- a/src/layered-storage/transactions.ts +++ b/src/layered-storage/transactions.ts @@ -56,9 +56,9 @@ export class LayeredStorageTransaction< * @param key - The key that identifies the value to be deleted. */ public delete(layer: Layer, key: keyof IKV): void { - this._actions.push( - this._storageCore.twoPartDelete(layer, this._segment, key) - ); + this._actions.push((): void => { + this._storageCore.delete(layer, this._segment, key); + }); } /** diff --git a/test/layered-storage/expanders.ts b/test/layered-storage/expanders.ts index 0b4aa1fec..a34760d7b 100644 --- a/test/layered-storage/expanders.ts +++ b/test/layered-storage/expanders.ts @@ -119,5 +119,52 @@ export function expanders(): void { "All expanded values should be deleted." ).deep.equal([false, false, false]); }); + + it("Recursive expands (set and delete)", function (): void { + interface IKV { + a: { + b: { + c: "value"; + }; + }; + "a.b": { + c: "value"; + }; + "a.b.c": "value"; + } + interface OKV { + "a.b.c": "value"; + } + + const ls = new LayeredStorage<0, IKV, OKV>(); + + ls.setExpander("a", ["a.b"], ({ b }): KeyValueEntry[] => [ + ["a.b", b], + ]); + ls.setExpander("a.b", ["a.b.c"], ({ c }): KeyValueEntry< + IKV, + "a.b.c" + >[] => [["a.b.c", c]]); + + ls.global.set(0, "a", { b: { c: "value" } }); + expect( + [ + ls.global.has("a" as any), + ls.global.has("a.b" as any), + ls.global.has("a.b.c"), + ], + "The expanders should recursively expand the value into the final a.b.c and set it's value." + ).deep.equal([false, false, true]); + + ls.global.delete(0, "a"); + expect( + [ + ls.global.has("a" as any), + ls.global.has("a.b" as any), + ls.global.has("a.b.c"), + ], + "The expanders should recursively expand the value into the final a.b.c and delete it." + ).deep.equal([false, false, false]); + }); }); } From fb0fc8b6419e1f1d817d22ee99c3e5922981e08a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Sun, 31 May 2020 21:53:09 +0200 Subject: [PATCH 43/48] feat(layered-storage)!: add DELETE keyword to delete values through set BREAKING CHANGE: This completely prevents null from being used as a value. We could change it to a symbol if this turns out to be a problem. --- src/layered-storage/common.ts | 2 ++ src/layered-storage/core.ts | 12 ++++++++++-- src/layered-storage/segment.ts | 6 +++--- src/layered-storage/transactions.ts | 6 +++--- test/layered-storage/single-layer.ts | 23 ++++++++++++++++++++++- test/layered-storage/validation.ts | 4 ++-- 6 files changed, 42 insertions(+), 11 deletions(-) diff --git a/src/layered-storage/common.ts b/src/layered-storage/common.ts index 4508d23aa..52d34b07a 100644 --- a/src/layered-storage/common.ts +++ b/src/layered-storage/common.ts @@ -1,3 +1,5 @@ +export const LS_DELETE = null; + export type KeyRange = number | string | symbol; export type LayerRange = number; export type Segment = boolean | number | object | string | symbol; diff --git a/src/layered-storage/core.ts b/src/layered-storage/core.ts index 70eda2d80..d6074670f 100644 --- a/src/layered-storage/core.ts +++ b/src/layered-storage/core.ts @@ -1,4 +1,5 @@ import { + LS_DELETE, KeyRange, KeyValueEntry, KeyValueLookup, @@ -298,7 +299,7 @@ export class LayeredStorageCore< * @param layer - Which layer to save the value into. * @param segment - Which segment to save the value into. * @param key - Key that can be used to retrieve or overwrite this value later. - * @param value - The value to be saved. + * @param value - The value to be saved or the LS_DELETE constant to delete the key. * * @returns Function that actually sets the validated and expanded value. */ @@ -306,12 +307,19 @@ export class LayeredStorageCore< layer: Layer, segment: Segment, key: Key, - value: IKV[Key] + value: typeof LS_DELETE | IKV[Key] ): () => void { if (typeof layer !== "number") { throw new TypeError("Layers have to be numbers."); } + // If it is the LS_DELETE constant, delete the key instead. + if (value === LS_DELETE) { + return (): void => { + this.delete(layer, segment, key); + }; + } + if (!this._validate(key, value)) { // The value is invalid. If the invalid value handler didn't throw, return // empty function to prevent the value from being saved into the storage. diff --git a/src/layered-storage/segment.ts b/src/layered-storage/segment.ts index 97cbb2239..fa2bcfae1 100644 --- a/src/layered-storage/segment.ts +++ b/src/layered-storage/segment.ts @@ -1,4 +1,4 @@ -import { KeyValueLookup, LayerRange, Segment } from "./common"; +import { LS_DELETE, KeyValueLookup, LayerRange, Segment } from "./common"; import { LayeredStorageCore } from "./core"; import { LayeredStorageTransaction } from "./transactions"; @@ -54,12 +54,12 @@ export class LayeredStorageSegment< * * @param layer - Which layer to save the value into. * @param key - Key that can be used to retrieve or overwrite this value later. - * @param value - The value to be saved. + * @param value - The value to be saved or the LS_DELETE constant to delete the key. */ public set( layer: Layer, key: Key, - value: IKV[Key] + value: typeof LS_DELETE | IKV[Key] ): void { this.runTransaction((transaction): void => { transaction.set(layer, key, value); diff --git a/src/layered-storage/transactions.ts b/src/layered-storage/transactions.ts index 6be6d1535..9bb65d3ab 100644 --- a/src/layered-storage/transactions.ts +++ b/src/layered-storage/transactions.ts @@ -1,4 +1,4 @@ -import { KeyValueLookup, LayerRange, Segment } from "./common"; +import { LS_DELETE, KeyValueLookup, LayerRange, Segment } from "./common"; import { LayeredStorageCore } from "./core"; /** @@ -37,12 +37,12 @@ export class LayeredStorageTransaction< * * @param layer - Which layer to save the value into. * @param key - Key that can be used to retrieve or overwrite this value later. - * @param value - The value to be saved. + * @param value - The value to be saved or the LS_DELETE constant to delete the key. */ public set( layer: Layer, key: Key, - value: IKV[Key] + value: typeof LS_DELETE | IKV[Key] ): void { this._actions.push( this._storageCore.twoPartSet(layer, this._segment, key, value) diff --git a/test/layered-storage/single-layer.ts b/test/layered-storage/single-layer.ts index 9401a224d..4a9177bc7 100644 --- a/test/layered-storage/single-layer.ts +++ b/test/layered-storage/single-layer.ts @@ -1,4 +1,4 @@ -import { LayeredStorage } from "../../src/layered-storage"; +import { LS_DELETE, LayeredStorage } from "../../src/layered-storage"; import { deepFreeze } from "../helpers"; import { expect } from "chai"; @@ -78,6 +78,27 @@ export function singleLayer(): void { ).to.be.false; }); + it("LS_DELETE constant", function (): void { + const ls = new LayeredStorage<0, KV, KV>(); + + expect( + ls.global.has("test.value"), + "There is no value yet so it should be reported as empty." + ).to.be.false; + + ls.global.set(0, "test.value", testValue); + expect( + ls.global.has("test.value"), + "The value should be reported as present after being set." + ).to.be.true; + + ls.global.set(0, "test.value", LS_DELETE); + expect( + ls.global.has("test.value"), + "The value should be reported as not present after being deleted via the LS_DELETE constant." + ).to.be.false; + }); + it("Export", function (): void { interface LocalKV { "test.deeply.nested.value": string; diff --git a/test/layered-storage/validation.ts b/test/layered-storage/validation.ts index 9f9645dee..62defea07 100644 --- a/test/layered-storage/validation.ts +++ b/test/layered-storage/validation.ts @@ -40,7 +40,7 @@ export function validation(): void { describe(name, function (): void { [ [false, "test.boolean", 77] as const, - [false, "test.fail", null] as const, + [false, "test.fail", "fail"] as const, [false, "test.integer", "3.5"] as const, [false, "test.integer", 3.5] as const, [false, "test.string", undefined] as const, @@ -48,7 +48,7 @@ export function validation(): void { [true, "test.integer", 77] as const, [true, "test.number", 3.5] as const, [true, "test.number", 77] as const, - [true, "test.pass", null] as const, + [true, "test.pass", "pass"] as const, [true, "test.string", "test"] as const, ].forEach(([valid, key, value]): void => { it(`${key}: ${value}`, function (): void { From edb0996d5ffdfb1267d34b029137f46716f8f3ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Sun, 9 Aug 2020 09:52:59 +0200 Subject: [PATCH 44/48] style(layered-storage): fix linting issues --- .eslintrc.js | 7 ++++++- src/layered-storage/core.ts | 10 +++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index f579f8cbc..c26b7a108 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -52,7 +52,12 @@ module.exports = { ], // Disable console log. - "no-console": ["error", { allow: ["info", "warn", "error"] }], + "no-console": [ + "error", + { + allow: ["error", "group", "groupCollapsed", "groupEnd", "info", "warn"], + }, + ], // This would be a breaking change for little gain. Though there definitely // is some merit in this. diff --git a/src/layered-storage/core.ts b/src/layered-storage/core.ts index d6074670f..115efff9b 100644 --- a/src/layered-storage/core.ts +++ b/src/layered-storage/core.ts @@ -630,15 +630,15 @@ export class LayeredStorageCore< .sort(entriesByKeyPriority) .map((pair): Layer => pair[0]); - console.log("Time:", new Date()); - console.log("Layers:", layers); - console.log("Segments:", [...this._segments.values()]); + console.info("Time:", new Date()); + console.info("Layers:", layers); + console.info("Segments:", [...this._segments.values()]); console.groupCollapsed("Cache"); for (const [segment, cacheData] of this._topLevelCache.entries()) { console.groupCollapsed(`Segment: ${String(segment)}`); for (const [key, value] of cacheData.entries()) { - console.log([key, value]); + console.info([key, value]); } console.groupEnd(); } @@ -651,7 +651,7 @@ export class LayeredStorageCore< for (const [segment, segmentData] of lData.entries()) { console.groupCollapsed(`Segment: ${String(segment)}`); for (const [key, value] of [...segmentData.entries()].sort()) { - console.log([key, value]); + console.info([key, value]); } console.groupEnd(); } From 4d41b96f5e058f9fcc9ec5b983eea65ed5da7fe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Sun, 9 Aug 2020 10:32:37 +0200 Subject: [PATCH 45/48] feat(layered-storage): add delete single layer from segment --- __snapshots__/test/package.test.ts.js | 28 ++++++++ src/layered-storage/core.ts | 27 ++++++++ src/layered-storage/segment.ts | 11 ++++ src/layered-storage/transactions.ts | 11 ++++ test/layered-storage/multiple-layers.ts | 86 +++++++++++++++++++++++++ 5 files changed, 163 insertions(+) diff --git a/__snapshots__/test/package.test.ts.js b/__snapshots__/test/package.test.ts.js index e516d4174..422599e90 100644 --- a/__snapshots__/test/package.test.ts.js +++ b/__snapshots__/test/package.test.ts.js @@ -14,6 +14,34 @@ exports['Package Exported files 1'] = { " declarations/entry-standalone.d.ts.map", " declarations/index.d.ts", " declarations/index.d.ts.map", + " declarations/layered-storage/common.d.ts", + " declarations/layered-storage/common.d.ts.map", + " declarations/layered-storage/core.d.ts", + " declarations/layered-storage/core.d.ts.map", + " declarations/layered-storage/index.d.ts", + " declarations/layered-storage/index.d.ts.map", + " declarations/layered-storage/layered-storage.d.ts", + " declarations/layered-storage/layered-storage.d.ts.map", + " declarations/layered-storage/segment.d.ts", + " declarations/layered-storage/segment.d.ts.map", + " declarations/layered-storage/transactions.d.ts", + " declarations/layered-storage/transactions.d.ts.map", + " declarations/layered-storage/validator-library/boolean.d.ts", + " declarations/layered-storage/validator-library/boolean.d.ts.map", + " declarations/layered-storage/validator-library/index.d.ts", + " declarations/layered-storage/validator-library/index.d.ts.map", + " declarations/layered-storage/validator-library/number.d.ts", + " declarations/layered-storage/validator-library/number.d.ts.map", + " declarations/layered-storage/validator-library/operators.d.ts", + " declarations/layered-storage/validator-library/operators.d.ts.map", + " declarations/layered-storage/validator-library/other.d.ts", + " declarations/layered-storage/validator-library/other.d.ts.map", + " declarations/layered-storage/validator-library/public-util.d.ts", + " declarations/layered-storage/validator-library/public-util.d.ts.map", + " declarations/layered-storage/validator-library/string.d.ts", + " declarations/layered-storage/validator-library/string.d.ts.map", + " declarations/layered-storage/validator-library/util.d.ts", + " declarations/layered-storage/validator-library/util.d.ts.map", " declarations/random/alea.d.ts", " declarations/random/alea.d.ts.map", " declarations/random/index.d.ts", diff --git a/src/layered-storage/core.ts b/src/layered-storage/core.ts index 115efff9b..f689017a1 100644 --- a/src/layered-storage/core.ts +++ b/src/layered-storage/core.ts @@ -387,6 +387,33 @@ export class LayeredStorageCore< } } + /** + * Delete all the data on given layer associeated with given segment. + * + * @param layer - The layer whose data should be deleted. + * @param segment - The segment whose data should be deleted. + */ + public deleteLayer(layer: Layer, segment: Segment): void { + const layerData = this._data.get(layer); + if (layerData == null) { + // No data on given layer, nothing to do. + return; + } + + const deleted = layerData.delete(segment); + if (deleted === false) { + // There was no data associeated with given segment on given layer, + // nothing was changed. + return; + } + + if (segment === this.globalSegment) { + this._topLevelCache.clear(); + } else { + this._topLevelCache.delete(segment); + } + } + /** * Set the inherance chain of given segment. * diff --git a/src/layered-storage/segment.ts b/src/layered-storage/segment.ts index fa2bcfae1..fe60400fd 100644 --- a/src/layered-storage/segment.ts +++ b/src/layered-storage/segment.ts @@ -78,6 +78,17 @@ export class LayeredStorageSegment< }); } + /** + * Delete all the data on given layer from the storage. + * + * @param layer - Which layer to delete. + */ + public deleteLayer(layer: Layer): void { + this.runTransaction((transaction): void => { + transaction.deleteLayer(layer); + }); + } + /** * Set the inherance chain of this segment. * diff --git a/src/layered-storage/transactions.ts b/src/layered-storage/transactions.ts index 9bb65d3ab..1d2dfe126 100644 --- a/src/layered-storage/transactions.ts +++ b/src/layered-storage/transactions.ts @@ -61,6 +61,17 @@ export class LayeredStorageTransaction< }); } + /** + * Queue a layer to be deleted. + * + * @param layer - Which layer to delete. + */ + public deleteLayer(layer: Layer): void { + this._actions.push((): void => { + this._storageCore.deleteLayer(layer, this._segment); + }); + } + /** * Commit all queued operations. */ diff --git a/test/layered-storage/multiple-layers.ts b/test/layered-storage/multiple-layers.ts index 1d4fa6e02..9dcc94177 100644 --- a/test/layered-storage/multiple-layers.ts +++ b/test/layered-storage/multiple-layers.ts @@ -137,5 +137,91 @@ export function multipleLayers(): void { "There isn't any value anymore so it should be reported as empty." ).to.be.false; }); + + describe("Delete layer", function (): void { + it("Segment layer", function (): void { + const ls = new LayeredStorage< + 1 | 2 | 3, + { test: string }, + { test: string } + >(); + + const a = ls.openSegment("A"); + a.set(1, "test", "A1"); + a.set(2, "test", "A2"); + a.set(3, "test", "A3"); + + const b = ls.openSegment("B"); + b.set(1, "test", "B1"); + b.set(2, "test", "B2"); + b.set(3, "test", "B3"); + + expect(a.get("test"), "The initial data should be set.").to.equal("A3"); + expect(b.get("test"), "The initial data should be set.").to.equal("B3"); + + b.deleteLayer(2); + + expect(a.get("test"), "Other segments shouldn't be affected.").to.equal( + "A3" + ); + expect( + b.get("test"), + "The 2nd layer is gone but the 3rd is still in place and should be returned." + ).to.equal("B3"); + + b.deleteLayer(3); + + expect(a.get("test"), "Other segments shouldn't be affected.").to.equal( + "A3" + ); + expect( + b.get("test"), + "The 3rd and 2nd layers has been deleted, the 1st layer should be returned." + ).to.equal("B1"); + }); + + it("Global layer", function (): void { + const ls = new LayeredStorage< + 1 | 2 | 3, + { test: string }, + { test: string } + >(); + + ls.global.set(1, "test", "g1"); + ls.global.set(2, "test", "g2"); + ls.global.set(3, "test", "g3"); + + const a = ls.openSegment("A"); + a.set(1, "test", "A1"); + + expect( + ls.global.get("test"), + "The initial data should be set." + ).to.equal("g3"); + expect(a.get("test"), "The initial data should be set.").to.equal("g3"); + + ls.global.deleteLayer(2); + + expect( + ls.global.get("test"), + "The 2nd global layer is gone but the 3rd is still in place and should be returned." + ).to.equal("g3"); + expect( + a.get("test"), + "The 2nd global layer is gone but the 3rd is still in place and should be returned." + ).to.equal("g3"); + + ls.global.deleteLayer(3); + + expect( + ls.global.get("test"), + "The 3rd and 2nd global layers are gone, the global 1st layer value should be returned." + ).to.equal("g1"); + expect( + a.get("test"), + "The 3rd and 2nd global layers are gone, this segment has it's own 1st layer value which should be returned." + ).to.equal("A1"); + }); + }); }); } From 15603e8ba10d82b3ecf06fe772d22c60d2f1d6eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Sun, 9 Aug 2020 12:32:43 +0200 Subject: [PATCH 46/48] test: disable DTS testing for now Since it's not possible to use custom tsconfig.json it only works with what the authors configured it to work with. There's an issue on their repo tracking this. It doesn't work with layered storage because it uses iterables other than arrays and that's not configured in check-dts. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8dc0e2b5f..2da7500c6 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "test:coverage": "BABEL_ENV=test-cov nyc mocha", "test:interop": "node interop.js", "test:interop:debug": "npm run test:interop -- --fail-command \"$SHELL\"", - "test:types:check-dts": "cd test && check-dts", + "test:types:check-dts": "echo disabled for now because tsconfig.json cannot be configured", "test:types:tsc": "tsc --noemit --project tsconfig.check.json", "test:unit": "BABEL_ENV=test mocha", "type-check": "run-s test:types:*", From 97deb9b14edc77fc1a31680e4d9d3853ca8221c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Sun, 9 Aug 2020 13:44:36 +0200 Subject: [PATCH 47/48] style(eslint): fix automerging error --- .eslintrc.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index c26b7a108..4eea6680c 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -92,13 +92,7 @@ module.exports = { "@typescript-eslint/no-var-requires": "off", }, }, - ], - settings: { - jsdoc: { - mode: "typescript", - }, - }, - overrides: [ + // TypeScript files { files: ["test/**/*.ts"], rules: { @@ -107,4 +101,9 @@ module.exports = { }, }, ], + settings: { + jsdoc: { + mode: "typescript", + }, + }, }; From 501926e1d4ea5ef9ac6800c693e3c9c95fe24c3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vy=C4=8D=C3=ADtal?= Date: Fri, 14 Aug 2020 20:30:04 +0200 Subject: [PATCH 48/48] fix(layered-storage): export it --- src/entry-esnext.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/entry-esnext.ts b/src/entry-esnext.ts index 243ac2c86..131dbe9d3 100644 --- a/src/entry-esnext.ts +++ b/src/entry-esnext.ts @@ -1,3 +1,4 @@ export * from "./deep-object-assign"; +export * from "./layered-storage"; export * from "./random"; export * from "./util";