diff --git a/.gitignore b/.gitignore index c56c6e5..31e46d1 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ pnpm-debug.log yarn-error.log GPUCache/ updux-2.0.0.tgz +pnpm-lock.yaml diff --git a/Taskfile.yaml b/Taskfile.yaml index e97b9a2..a9d7b7c 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -2,7 +2,27 @@ version: '3' +vars: + PARENT_BRANCH: main + tasks: + build: tsc + + checks: + deps: [lint, test, build] + + integrate: + deps: [checks] + cmds: + - git is-clean + # did we had tests? + - git diff-ls {{.PARENT_BRANCH}} | grep test + - git checkout {{.PARENT_BRANCH}} + - git weld - + + test: vitest run src + test:dev: vitest src + lint:fix:delta: vars: FILES: diff --git a/docs/recipes.md b/docs/recipes.md index 3dd308d..ef7369d 100644 --- a/docs/recipes.md +++ b/docs/recipes.md @@ -4,7 +4,7 @@ Say you have a `todos` state that is an array of `todo` sub-states, with some actions that should percolate to all todos, and some that should only -percolate to one. One way to model this is via updux's splat subduxes +percolate to one. One way to model this is via updux's splat subduxes (backed by `updeep`'s own '*'-key behavior). ``` @@ -55,7 +55,7 @@ const updux = new Updux({ add: (inc=1) => state => ({ counter: state.counter + inc }) } }); - + ``` Converting it to Immer would look like: @@ -68,10 +68,10 @@ import { produce } from 'immer'; const updux = new Updux({ initial: { counter: 0 }, mutations: { - add: (inc=1) => produce( draft => draft.counter += inc ) } + add: (inc=1) => produce( draft => draft.counter += inc ) } } }); - + ``` But since typing `produce` over and over is no fun, `groomMutations` @@ -86,11 +86,8 @@ const updux = new Updux({ initial: { counter: 0 }, groomMutations: mutation => (...args) => produce( mutation(...args) ), mutations: { - add: (inc=1) => draft => draft.counter += inc + add: (inc=1) => draft => draft.counter += inc } }); - + ``` - - - diff --git a/docs/recipes.test.js b/docs/recipes.test.js index 8560675..ef0a13a 100644 --- a/docs/recipes.test.js +++ b/docs/recipes.test.js @@ -51,4 +51,3 @@ test( "tutorial", async () => { ]); }); - diff --git a/docs/tutorial-reactions.test.js b/docs/tutorial-reactions.test.js index 61dfe85..cdba1d9 100644 --- a/docs/tutorial-reactions.test.js +++ b/docs/tutorial-reactions.test.js @@ -37,4 +37,3 @@ test( "basic tests", async () => { expect(store.getState().nbrTodos).toEqual(2); }); - diff --git a/docs/tutorial.md b/docs/tutorial.md index 6ecb348..387200e 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -4,22 +4,23 @@ This tutorial walks you through the features of `Updux` using the time-honored example of the implementation of Todo list store. We'll be using -[updeep](https://www.npmjs.com/package/updeep) to +[@yanick/updeep-remeda](https://www.npmjs.com/package/@yanick/updeep-remeda) to help with immutability and deep merging, but that's totally optional. If `updeep` is not your bag, -it can easily be substitued with, say, [immer][], [lodash][], or even +it can easily be substitued with, say, [immer][], +[remeda][], +[lodash][], or even plain JavaScript. ## Definition of the state To begin with, let's define that has nothing but an initial state. - ```js -import { Updux } from 'updux'; +import Updux from 'updux'; const todosDux = new Updux({ initial: { - next_id: 1, + nextId: 1, todos: [], } }); @@ -32,22 +33,26 @@ initial state will be automatically set: ```js const store = todosDux.createStore(); -console.log(store.getState()); // prints { next_id: 1, todos: [] } +console.log(store.getState()); // prints { nextId: 1, todos: [] } ``` ## Add actions This is all good, but a little static. Let's add actions! - ```js +import { createAction } from 'updux'; + +const addTodo = createAction('addTodo'); +const todoDone = createAction('todoDone'); + const todosDux = new Updux({ initial: { - next_id: 1, + nextId: 1, todos: [], }, - { - addTodo: null, - todoDone: null, + actions: { + addTodo, + todoDone, } }); ``` @@ -55,22 +60,22 @@ const todosDux = new Updux({ ### Accessing actions Once an action is defined, its creator is accessible via the `actions` accessor. - +This is not yet terribly exciting, but it'll get better once we begin using +subduxes. ```js console.log( todosDux.actions.addTodo('write tutorial') ); - // prints { type: 'addTodo', payload: 'write tutorial' } + // => { type: 'addTodo', payload: 'write tutorial' } ``` ### Adding a mutation Mutations are the reducing functions associated to actions. They -are defined via the `setMutation` method: +are defined via the `mutation` method: - - ```js -todosDux.setMutation( 'addTodo', description => ({next_id: id, todos}) => ({ - next_id: 1 + id, - todos: [...todos, { description, id, done: false }] -})); +```js + dux.mutation(addTodo, (state, description) => { + state.todos.unshift({ description, id: state.nextId, done: false }); + state.nextId++; + }); ``` ## Effects @@ -158,9 +163,9 @@ todosDux.setSelector('getTodoById', getTodoById); ### Accessing selectors -The `getState` method of a dux store is augmented +The `getState` method of a dux store is augmented with its selectors, with the first call for the state already -called in for you. +called in for you. ```js const store = todosDux.createStore(); @@ -204,7 +209,7 @@ const todosDux = new Updux({ addTodoWithId: todo => u.updateIn( 'todos', todos => [ ...todos, todo] ), incrementNextId: () => u({ nextId: fp.add(1) }), - todoDone: (id) => u.updateIn('todos', + todoDone: (id) => u.updateIn('todos', u.map( u.if( fp.matches({id}), todo => u({done: true}, todo) ) ) ), }, @@ -404,4 +409,4 @@ const myDux = new Updux({ [immer]: https://www.npmjs.com/package/immer [lodash]: https://www.npmjs.com/package/lodash [ts-action]: https://www.npmjs.com/package/ts-action - +[remeda]: remedajs.com/ diff --git a/out/Updux.html b/out/Updux.html index 44126a5..c1e8090 100644 --- a/out/Updux.html +++ b/out/Updux.html @@ -19,7 +19,7 @@

Class: Updux

- + @@ -27,24 +27,24 @@
- +

Updux()

- - + +
- - - - + + + +

new Updux()

- - + + @@ -62,42 +62,42 @@
- - - - - - - - - - - - - + + + + + + + + + + + + +
Source:
- - - - + + + +
@@ -119,33 +119,33 @@ - +
- - - + + +

Classes

Updux
- - - - - + + + + +

Members

- - + +

actions

@@ -159,42 +159,42 @@
- - - - - - - - - - - - - + + + + + + + + + + + + +
Source:
- - - - + + + +
@@ -202,8 +202,8 @@ - - + +

initial

@@ -217,42 +217,42 @@
- - - - - - - - - - - - - + + + + + + + + + + + + +
Source:
- - - - + + + +
@@ -260,14 +260,14 @@ - - - - - + + + + +
@@ -290,4 +290,4 @@ - \ No newline at end of file + diff --git a/out/Updux.js.html b/out/Updux.js.html index 3541151..7456b35 100644 --- a/out/Updux.js.html +++ b/out/Updux.js.html @@ -19,11 +19,11 @@

Source: Updux.js

- - + +
/* TODO change * for leftovers to +, change subscriptions to reactions */
diff --git a/out/fonts/OpenSans-Bold-webfont.svg b/out/fonts/OpenSans-Bold-webfont.svg
index 3ed7be4..8ad2a60 100644
--- a/out/fonts/OpenSans-Bold-webfont.svg
+++ b/out/fonts/OpenSans-Bold-webfont.svg
@@ -1827,4 +1827,4 @@
 
 
 
- 
\ No newline at end of file
+
diff --git a/out/fonts/OpenSans-BoldItalic-webfont.svg b/out/fonts/OpenSans-BoldItalic-webfont.svg
index 6a2607b..d4f4960 100644
--- a/out/fonts/OpenSans-BoldItalic-webfont.svg
+++ b/out/fonts/OpenSans-BoldItalic-webfont.svg
@@ -1827,4 +1827,4 @@
 
 
 
- 
\ No newline at end of file
+
diff --git a/out/fonts/OpenSans-Italic-webfont.svg b/out/fonts/OpenSans-Italic-webfont.svg
index e1075dc..2ee9499 100644
--- a/out/fonts/OpenSans-Italic-webfont.svg
+++ b/out/fonts/OpenSans-Italic-webfont.svg
@@ -1827,4 +1827,4 @@
 
 
 
- 
\ No newline at end of file
+
diff --git a/out/fonts/OpenSans-Light-webfont.svg b/out/fonts/OpenSans-Light-webfont.svg
index 11a472c..42152bc 100644
--- a/out/fonts/OpenSans-Light-webfont.svg
+++ b/out/fonts/OpenSans-Light-webfont.svg
@@ -1828,4 +1828,4 @@
 
 
 
- 
\ No newline at end of file
+
diff --git a/out/fonts/OpenSans-LightItalic-webfont.svg b/out/fonts/OpenSans-LightItalic-webfont.svg
index 431d7e3..e9bfbc3 100644
--- a/out/fonts/OpenSans-LightItalic-webfont.svg
+++ b/out/fonts/OpenSans-LightItalic-webfont.svg
@@ -1832,4 +1832,4 @@
 
 
 
- 
\ No newline at end of file
+
diff --git a/out/fonts/OpenSans-Regular-webfont.svg b/out/fonts/OpenSans-Regular-webfont.svg
index 25a3952..bad5cca 100644
--- a/out/fonts/OpenSans-Regular-webfont.svg
+++ b/out/fonts/OpenSans-Regular-webfont.svg
@@ -1828,4 +1828,4 @@
 
 
 
- 
\ No newline at end of file
+
diff --git a/out/index.html b/out/index.html
index 790e731..d623206 100644
--- a/out/index.html
+++ b/out/index.html
@@ -19,11 +19,11 @@
 
     

Home

- - + +

@@ -37,7 +37,7 @@ - + @@ -62,4 +62,4 @@ - \ No newline at end of file + diff --git a/package.json b/package.json index 2b14539..ea2b77c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "type": "module", "dependencies": { + "@yanick/updeep-remeda": "^2.1.0", "immer": "^9.0.15", "json-schema-shorthand": "^2.0.0", "redux": "^4.2.0", @@ -29,6 +30,7 @@ }, "homepage": "https://github.com/yanick/updux#readme", "devDependencies": { + "@reduxjs/toolkit": "^1.9.3", "@vitest/browser": "^0.23.1", "@vitest/ui": "^0.23.1", "eslint": "^8.22.0", @@ -36,6 +38,9 @@ "eslint-plugin-todo-plz": "^1.2.1", "jsdoc-to-markdown": "^7.1.1", "prettier": "^2.7.1", + "redux-toolkit": "^1.1.2", + "typescript": "^4.9.5", + "vite": "^4.2.1", "vitest": "0.23.1" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml deleted file mode 100644 index f5ea925..0000000 --- a/pnpm-lock.yaml +++ /dev/null @@ -1,2197 +0,0 @@ -lockfileVersion: 5.4 - -specifiers: - '@vitest/browser': ^0.23.1 - '@vitest/ui': ^0.23.1 - eslint: ^8.22.0 - eslint-plugin-no-only-tests: ^3.0.0 - eslint-plugin-todo-plz: ^1.2.1 - immer: ^9.0.15 - jsdoc-to-markdown: ^7.1.1 - json-schema-shorthand: ^2.0.0 - prettier: ^2.7.1 - redux: ^4.2.0 - remeda: ^1.0.1 - updeep: ^1.2.1 - vitest: 0.23.1 - -dependencies: - immer: 9.0.15 - json-schema-shorthand: 2.0.0 - redux: 4.2.0 - remeda: 1.0.1 - updeep: 1.2.1 - -devDependencies: - '@vitest/browser': 0.23.1 - '@vitest/ui': 0.23.1 - eslint: 8.22.0 - eslint-plugin-no-only-tests: 3.0.0 - eslint-plugin-todo-plz: 1.2.1_eslint@8.22.0 - jsdoc-to-markdown: 7.1.1 - prettier: 2.7.1 - vitest: 0.23.1_kkczkm7y7wgspdnr2rpymavxge - -packages: - - /@babel/helper-string-parser/7.18.10: - resolution: {integrity: sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helper-validator-identifier/7.18.6: - resolution: {integrity: sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/parser/7.18.13: - resolution: {integrity: sha512-dgXcIfMuQ0kgzLB2b9tRZs7TTFFaGM2AbtA4fJgUUYukzGH4jwsS7hzQHEGs67jdehpm22vkgKwvbU+aEflgwg==} - engines: {node: '>=6.0.0'} - hasBin: true - dependencies: - '@babel/types': 7.18.13 - dev: true - - /@babel/runtime/7.18.9: - resolution: {integrity: sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==} - engines: {node: '>=6.9.0'} - dependencies: - regenerator-runtime: 0.13.9 - dev: false - - /@babel/types/7.18.13: - resolution: {integrity: sha512-ePqfTihzW0W6XAU+aMw2ykilisStJfDnsejDCXRchCcMJ4O0+8DhPXf2YUbZ6wjBlsEmZwLK/sPweWtu8hcJYQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-string-parser': 7.18.10 - '@babel/helper-validator-identifier': 7.18.6 - to-fast-properties: 2.0.0 - dev: true - - /@esbuild/linux-loong64/0.14.54: - resolution: {integrity: sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-loong64/0.15.7: - resolution: {integrity: sha512-IKznSJOsVUuyt7cDzzSZyqBEcZe+7WlBqTVXiF1OXP/4Nm387ToaXZ0fyLwI1iBlI/bzpxVq411QE2/Bt2XWWw==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@eslint/eslintrc/1.3.0: - resolution: {integrity: sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - ajv: 6.12.6 - debug: 4.3.4 - espree: 9.3.3 - globals: 13.17.0 - ignore: 5.2.0 - import-fresh: 3.3.0 - js-yaml: 4.1.0 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - dev: true - - /@humanwhocodes/config-array/0.10.4: - resolution: {integrity: sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==} - engines: {node: '>=10.10.0'} - dependencies: - '@humanwhocodes/object-schema': 1.2.1 - debug: 4.3.4 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - dev: true - - /@humanwhocodes/gitignore-to-minimatch/1.0.2: - resolution: {integrity: sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==} - dev: true - - /@humanwhocodes/object-schema/1.2.1: - resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} - dev: true - - /@jspm/core/2.0.0-beta.24: - resolution: {integrity: sha512-a4Bo/80Z6CoJNor5ldgs6002utmmbttP4JYd/FJ0Ob2fVdf6O6ha5SORBCqrnDnBvMc1TlrHY7dCfat5+H0a6A==} - dev: true - - /@nodelib/fs.scandir/2.1.5: - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - dev: true - - /@nodelib/fs.stat/2.0.5: - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - dev: true - - /@nodelib/fs.walk/1.2.8: - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.13.0 - dev: true - - /@polka/url/1.0.0-next.21: - resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==} - dev: true - - /@rollup/plugin-inject/4.0.4_rollup@2.77.3: - resolution: {integrity: sha512-4pbcU4J/nS+zuHk+c+OL3WtmEQhqxlZ9uqfjQMQDOHOPld7PsCd8k5LWs8h5wjwJN7MgnAn768F2sDxEP4eNFQ==} - peerDependencies: - rollup: ^1.20.0 || ^2.0.0 - dependencies: - '@rollup/pluginutils': 3.1.0_rollup@2.77.3 - estree-walker: 2.0.2 - magic-string: 0.25.9 - rollup: 2.77.3 - dev: true - - /@rollup/pluginutils/3.1.0_rollup@2.77.3: - resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==} - engines: {node: '>= 8.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0 - dependencies: - '@types/estree': 0.0.39 - estree-walker: 1.0.1 - picomatch: 2.3.1 - rollup: 2.77.3 - dev: true - - /@types/chai-subset/1.3.3: - resolution: {integrity: sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==} - dependencies: - '@types/chai': 4.3.3 - dev: true - - /@types/chai/4.3.3: - resolution: {integrity: sha512-hC7OMnszpxhZPduX+m+nrx+uFoLkWOMiR4oa/AZF3MuSETYTZmFfJAHqZEM8MVlvfG7BEUcgvtwoCTxBp6hm3g==} - dev: true - - /@types/estree/0.0.39: - resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==} - dev: true - - /@types/linkify-it/3.0.2: - resolution: {integrity: sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==} - dev: true - - /@types/markdown-it/12.2.3: - resolution: {integrity: sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==} - dependencies: - '@types/linkify-it': 3.0.2 - '@types/mdurl': 1.0.2 - dev: true - - /@types/mdurl/1.0.2: - resolution: {integrity: sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==} - dev: true - - /@types/node/18.7.15: - resolution: {integrity: sha512-XnjpaI8Bgc3eBag2Aw4t2Uj/49lLBSStHWfqKvIuXD7FIrZyMLWp8KuAFHAqxMZYTF9l08N1ctUn9YNybZJVmQ==} - dev: true - - /@vitest/browser/0.23.1: - resolution: {integrity: sha512-8QLrMSlBjiRLbANid/hPmtkYViyuxLgqt1jCXvD6dnBIhghdxu5uZyg0x7xUPzDQDNts+9o+yq1WPDZbar7KNg==} - dependencies: - local-pkg: 0.4.2 - mlly: 0.5.14 - modern-node-polyfills: 0.0.9 - rollup-plugin-node-polyfills: 0.2.1 - sirv: 2.0.2 - dev: true - - /@vitest/ui/0.23.1: - resolution: {integrity: sha512-W1ygPK4aTyLTPsf6NX3gZFbH0X1ipNzlHhxTRnZ4/HpQXs/qKw5NDY45/U2yC66Fevj5kXHI1tdrNfN00NouFQ==} - dependencies: - sirv: 2.0.2 - dev: true - - /acorn-jsx/5.3.2_acorn@8.8.0: - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - dependencies: - acorn: 8.8.0 - dev: true - - /acorn/8.8.0: - resolution: {integrity: sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==} - engines: {node: '>=0.4.0'} - hasBin: true - dev: true - - /ajv/6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - dev: true - - /ansi-escape-sequences/4.1.0: - resolution: {integrity: sha512-dzW9kHxH011uBsidTXd14JXgzye/YLb2LzeKZ4bsgl/Knwx8AtbSFkkGxagdNOoh0DlqHCmfiEjWKBaqjOanVw==} - engines: {node: '>=8.0.0'} - dependencies: - array-back: 3.1.0 - dev: true - - /ansi-regex/5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - dev: true - - /ansi-styles/4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - dependencies: - color-convert: 2.0.1 - dev: true - - /argparse/2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - dev: true - - /array-back/1.0.4: - resolution: {integrity: sha512-1WxbZvrmyhkNoeYcizokbmh5oiOCIfyvGtcqbK3Ls1v1fKcquzxnQSceOx6tzq7jmai2kFLWIpGND2cLhH6TPw==} - engines: {node: '>=0.12.0'} - dependencies: - typical: 2.6.1 - dev: true - - /array-back/2.0.0: - resolution: {integrity: sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==} - engines: {node: '>=4'} - dependencies: - typical: 2.6.1 - dev: true - - /array-back/3.1.0: - resolution: {integrity: sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==} - engines: {node: '>=6'} - dev: true - - /array-back/4.0.2: - resolution: {integrity: sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==} - engines: {node: '>=8'} - dev: true - - /array-back/5.0.0: - resolution: {integrity: sha512-kgVWwJReZWmVuWOQKEOohXKJX+nD02JAZ54D1RRWlv8L0NebauKAaFxACKzB74RTclt1+WNz5KHaLRDAPZbDEw==} - engines: {node: '>=10'} - dev: true - - /array-back/6.2.2: - resolution: {integrity: sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==} - engines: {node: '>=12.17'} - dev: true - - /array-union/2.1.0: - resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} - engines: {node: '>=8'} - dev: true - - /assertion-error/1.1.0: - resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} - dev: true - - /balanced-match/1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: true - - /bluebird/3.7.2: - resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} - dev: true - - /brace-expansion/1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - dev: true - - /braces/3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} - engines: {node: '>=8'} - dependencies: - fill-range: 7.0.1 - dev: true - - /cache-point/2.0.0: - resolution: {integrity: sha512-4gkeHlFpSKgm3vm2gJN5sPqfmijYRFYCQ6tv5cLw0xVmT6r1z1vd4FNnpuOREco3cBs1G709sZ72LdgddKvL5w==} - engines: {node: '>=8'} - dependencies: - array-back: 4.0.2 - fs-then-native: 2.0.0 - mkdirp2: 1.0.5 - dev: true - - /callsites/3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - dev: true - - /catharsis/0.9.0: - resolution: {integrity: sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==} - engines: {node: '>= 10'} - dependencies: - lodash: 4.17.21 - dev: true - - /chai/4.3.6: - resolution: {integrity: sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==} - engines: {node: '>=4'} - dependencies: - assertion-error: 1.1.0 - check-error: 1.0.2 - deep-eql: 3.0.1 - get-func-name: 2.0.0 - loupe: 2.3.4 - pathval: 1.1.1 - type-detect: 4.0.8 - dev: true - - /chalk/4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - dev: true - - /check-error/1.0.2: - resolution: {integrity: sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==} - dev: true - - /collect-all/1.0.4: - resolution: {integrity: sha512-RKZhRwJtJEP5FWul+gkSMEnaK6H3AGPTTWOiRimCcs+rc/OmQE3Yhy1Q7A7KsdkG3ZXVdZq68Y6ONSdvkeEcKA==} - engines: {node: '>=0.10.0'} - dependencies: - stream-connect: 1.0.2 - stream-via: 1.0.4 - dev: true - - /color-convert/2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - dependencies: - color-name: 1.1.4 - dev: true - - /color-name/1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: true - - /command-line-args/5.2.1: - resolution: {integrity: sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==} - engines: {node: '>=4.0.0'} - dependencies: - array-back: 3.1.0 - find-replace: 3.0.0 - lodash.camelcase: 4.3.0 - typical: 4.0.0 - dev: true - - /command-line-tool/0.8.0: - resolution: {integrity: sha512-Xw18HVx/QzQV3Sc5k1vy3kgtOeGmsKIqwtFFoyjI4bbcpSgnw2CWVULvtakyw4s6fhyAdI6soQQhXc2OzJy62g==} - engines: {node: '>=4.0.0'} - dependencies: - ansi-escape-sequences: 4.1.0 - array-back: 2.0.0 - command-line-args: 5.2.1 - command-line-usage: 4.1.0 - typical: 2.6.1 - dev: true - - /command-line-usage/4.1.0: - resolution: {integrity: sha512-MxS8Ad995KpdAC0Jopo/ovGIroV/m0KHwzKfXxKag6FHOkGsH8/lv5yjgablcRxCJJC0oJeUMuO/gmaq+Wq46g==} - engines: {node: '>=4.0.0'} - dependencies: - ansi-escape-sequences: 4.1.0 - array-back: 2.0.0 - table-layout: 0.4.5 - typical: 2.6.1 - dev: true - - /common-sequence/2.0.2: - resolution: {integrity: sha512-jAg09gkdkrDO9EWTdXfv80WWH3yeZl5oT69fGfedBNS9pXUKYInVJ1bJ+/ht2+Moeei48TmSbQDYMc8EOx9G0g==} - engines: {node: '>=8'} - dev: true - - /concat-map/0.0.1: - resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} - dev: true - - /config-master/3.1.0: - resolution: {integrity: sha512-n7LBL1zBzYdTpF1mx5DNcZnZn05CWIdsdvtPL4MosvqbBUK3Rq6VWEtGUuF3Y0s9/CIhMejezqlSkP6TnCJ/9g==} - dependencies: - walk-back: 2.0.1 - dev: true - - /cross-spawn/7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} - engines: {node: '>= 8'} - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - dev: true - - /debug/4.3.4: - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.2 - dev: true - - /deep-eql/3.0.1: - resolution: {integrity: sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==} - engines: {node: '>=0.12'} - dependencies: - type-detect: 4.0.8 - dev: true - - /deep-extend/0.6.0: - resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} - engines: {node: '>=4.0.0'} - dev: true - - /deep-is/0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - dev: true - - /dir-glob/3.0.1: - resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} - engines: {node: '>=8'} - dependencies: - path-type: 4.0.0 - dev: true - - /dmd/6.1.0: - resolution: {integrity: sha512-0zQIJ873gay1scCTFZvHPWM9mVJBnaylB2NQDI8O9u8O32m00Jb6uxDKexZm8hjTRM7RiWe0FJ32pExHoXdwoQ==} - engines: {node: '>=12'} - dependencies: - array-back: 6.2.2 - cache-point: 2.0.0 - common-sequence: 2.0.2 - file-set: 4.0.2 - handlebars: 4.7.7 - marked: 4.1.0 - object-get: 2.1.1 - reduce-flatten: 3.0.1 - reduce-unique: 2.0.1 - reduce-without: 1.0.1 - test-value: 3.0.0 - walk-back: 5.1.0 - dev: true - - /doctrine/3.0.0: - resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} - engines: {node: '>=6.0.0'} - dependencies: - esutils: 2.0.3 - dev: true - - /entities/2.1.0: - resolution: {integrity: sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==} - dev: true - - /esbuild-android-64/0.14.54: - resolution: {integrity: sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /esbuild-android-64/0.15.7: - resolution: {integrity: sha512-p7rCvdsldhxQr3YHxptf1Jcd86dlhvc3EQmQJaZzzuAxefO9PvcI0GLOa5nCWem1AJ8iMRu9w0r5TG8pHmbi9w==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /esbuild-android-arm64/0.14.54: - resolution: {integrity: sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /esbuild-android-arm64/0.15.7: - resolution: {integrity: sha512-L775l9ynJT7rVqRM5vo+9w5g2ysbOCfsdLV4CWanTZ1k/9Jb3IYlQ06VCI1edhcosTYJRECQFJa3eAvkx72eyQ==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /esbuild-darwin-64/0.14.54: - resolution: {integrity: sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /esbuild-darwin-64/0.15.7: - resolution: {integrity: sha512-KGPt3r1c9ww009t2xLB6Vk0YyNOXh7hbjZ3EecHoVDxgtbUlYstMPDaReimKe6eOEfyY4hBEEeTvKwPsiH5WZg==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /esbuild-darwin-arm64/0.14.54: - resolution: {integrity: sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /esbuild-darwin-arm64/0.15.7: - resolution: {integrity: sha512-kBIHvtVqbSGajN88lYMnR3aIleH3ABZLLFLxwL2stiuIGAjGlQW741NxVTpUHQXUmPzxi6POqc9npkXa8AcSZQ==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /esbuild-freebsd-64/0.14.54: - resolution: {integrity: sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /esbuild-freebsd-64/0.15.7: - resolution: {integrity: sha512-hESZB91qDLV5MEwNxzMxPfbjAhOmtfsr9Wnuci7pY6TtEh4UDuevmGmkUIjX/b+e/k4tcNBMf7SRQ2mdNuK/HQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /esbuild-freebsd-arm64/0.14.54: - resolution: {integrity: sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /esbuild-freebsd-arm64/0.15.7: - resolution: {integrity: sha512-dLFR0ChH5t+b3J8w0fVKGvtwSLWCv7GYT2Y2jFGulF1L5HftQLzVGN+6pi1SivuiVSmTh28FwUhi9PwQicXI6Q==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-32/0.14.54: - resolution: {integrity: sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-32/0.15.7: - resolution: {integrity: sha512-v3gT/LsONGUZcjbt2swrMjwxo32NJzk+7sAgtxhGx1+ZmOFaTRXBAi1PPfgpeo/J//Un2jIKm/I+qqeo4caJvg==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-64/0.14.54: - resolution: {integrity: sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-64/0.15.7: - resolution: {integrity: sha512-LxXEfLAKwOVmm1yecpMmWERBshl+Kv5YJ/1KnyAr6HRHFW8cxOEsEfisD3sVl/RvHyW//lhYUVSuy9jGEfIRAQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-arm/0.14.54: - resolution: {integrity: sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-arm/0.15.7: - resolution: {integrity: sha512-JKgAHtMR5f75wJTeuNQbyznZZa+pjiUHV7sRZp42UNdyXC6TiUYMW/8z8yIBAr2Fpad8hM1royZKQisqPABPvQ==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-arm64/0.14.54: - resolution: {integrity: sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-arm64/0.15.7: - resolution: {integrity: sha512-P3cfhudpzWDkglutWgXcT2S7Ft7o2e3YDMrP1n0z2dlbUZghUkKCyaWw0zhp4KxEEzt/E7lmrtRu/pGWnwb9vw==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-mips64le/0.14.54: - resolution: {integrity: sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-mips64le/0.15.7: - resolution: {integrity: sha512-T7XKuxl0VpeFLCJXub6U+iybiqh0kM/bWOTb4qcPyDDwNVhLUiPcGdG2/0S7F93czUZOKP57YiLV8YQewgLHKw==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-ppc64le/0.14.54: - resolution: {integrity: sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-ppc64le/0.15.7: - resolution: {integrity: sha512-6mGuC19WpFN7NYbecMIJjeQgvDb5aMuvyk0PDYBJrqAEMkTwg3Z98kEKuCm6THHRnrgsdr7bp4SruSAxEM4eJw==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-riscv64/0.14.54: - resolution: {integrity: sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-riscv64/0.15.7: - resolution: {integrity: sha512-uUJsezbswAYo/X7OU/P+PuL/EI9WzxsEQXDekfwpQ23uGiooxqoLFAPmXPcRAt941vjlY9jtITEEikWMBr+F/g==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-s390x/0.14.54: - resolution: {integrity: sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-linux-s390x/0.15.7: - resolution: {integrity: sha512-+tO+xOyTNMc34rXlSxK7aCwJgvQyffqEM5MMdNDEeMU3ss0S6wKvbBOQfgd5jRPblfwJ6b+bKiz0g5nABpY0QQ==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /esbuild-netbsd-64/0.14.54: - resolution: {integrity: sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - requiresBuild: true - dev: true - optional: true - - /esbuild-netbsd-64/0.15.7: - resolution: {integrity: sha512-yVc4Wz+Pu3cP5hzm5kIygNPrjar/v5WCSoRmIjCPWfBVJkZNb5brEGKUlf+0Y759D48BCWa0WHrWXaNy0DULTQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - requiresBuild: true - dev: true - optional: true - - /esbuild-openbsd-64/0.14.54: - resolution: {integrity: sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - requiresBuild: true - dev: true - optional: true - - /esbuild-openbsd-64/0.15.7: - resolution: {integrity: sha512-GsimbwC4FSR4lN3wf8XmTQ+r8/0YSQo21rWDL0XFFhLHKlzEA4SsT1Tl8bPYu00IU6UWSJ+b3fG/8SB69rcuEQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - requiresBuild: true - dev: true - optional: true - - /esbuild-sunos-64/0.14.54: - resolution: {integrity: sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - requiresBuild: true - dev: true - optional: true - - /esbuild-sunos-64/0.15.7: - resolution: {integrity: sha512-8CDI1aL/ts0mDGbWzjEOGKXnU7p3rDzggHSBtVryQzkSOsjCHRVe0iFYUuhczlxU1R3LN/E7HgUO4NXzGGP/Ag==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - requiresBuild: true - dev: true - optional: true - - /esbuild-windows-32/0.14.54: - resolution: {integrity: sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /esbuild-windows-32/0.15.7: - resolution: {integrity: sha512-cOnKXUEPS8EGCzRSFa1x6NQjGhGsFlVgjhqGEbLTPsA7x4RRYiy2RKoArNUU4iR2vHmzqS5Gr84MEumO/wxYKA==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /esbuild-windows-64/0.14.54: - resolution: {integrity: sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /esbuild-windows-64/0.15.7: - resolution: {integrity: sha512-7MI08Ec2sTIDv+zH6StNBKO+2hGUYIT42GmFyW6MBBWWtJhTcQLinKS6ldIN1d52MXIbiJ6nXyCJ+LpL4jBm3Q==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /esbuild-windows-arm64/0.14.54: - resolution: {integrity: sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /esbuild-windows-arm64/0.15.7: - resolution: {integrity: sha512-R06nmqBlWjKHddhRJYlqDd3Fabx9LFdKcjoOy08YLimwmsswlFBJV4rXzZCxz/b7ZJXvrZgj8DDv1ewE9+StMw==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /esbuild/0.14.54: - resolution: {integrity: sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==} - engines: {node: '>=12'} - hasBin: true - requiresBuild: true - optionalDependencies: - '@esbuild/linux-loong64': 0.14.54 - esbuild-android-64: 0.14.54 - esbuild-android-arm64: 0.14.54 - esbuild-darwin-64: 0.14.54 - esbuild-darwin-arm64: 0.14.54 - esbuild-freebsd-64: 0.14.54 - esbuild-freebsd-arm64: 0.14.54 - esbuild-linux-32: 0.14.54 - esbuild-linux-64: 0.14.54 - esbuild-linux-arm: 0.14.54 - esbuild-linux-arm64: 0.14.54 - esbuild-linux-mips64le: 0.14.54 - esbuild-linux-ppc64le: 0.14.54 - esbuild-linux-riscv64: 0.14.54 - esbuild-linux-s390x: 0.14.54 - esbuild-netbsd-64: 0.14.54 - esbuild-openbsd-64: 0.14.54 - esbuild-sunos-64: 0.14.54 - esbuild-windows-32: 0.14.54 - esbuild-windows-64: 0.14.54 - esbuild-windows-arm64: 0.14.54 - dev: true - - /esbuild/0.15.7: - resolution: {integrity: sha512-7V8tzllIbAQV1M4QoE52ImKu8hT/NLGlGXkiDsbEU5PS6K8Mn09ZnYoS+dcmHxOS9CRsV4IRAMdT3I67IyUNXw==} - engines: {node: '>=12'} - hasBin: true - requiresBuild: true - optionalDependencies: - '@esbuild/linux-loong64': 0.15.7 - esbuild-android-64: 0.15.7 - esbuild-android-arm64: 0.15.7 - esbuild-darwin-64: 0.15.7 - esbuild-darwin-arm64: 0.15.7 - esbuild-freebsd-64: 0.15.7 - esbuild-freebsd-arm64: 0.15.7 - esbuild-linux-32: 0.15.7 - esbuild-linux-64: 0.15.7 - esbuild-linux-arm: 0.15.7 - esbuild-linux-arm64: 0.15.7 - esbuild-linux-mips64le: 0.15.7 - esbuild-linux-ppc64le: 0.15.7 - esbuild-linux-riscv64: 0.15.7 - esbuild-linux-s390x: 0.15.7 - esbuild-netbsd-64: 0.15.7 - esbuild-openbsd-64: 0.15.7 - esbuild-sunos-64: 0.15.7 - esbuild-windows-32: 0.15.7 - esbuild-windows-64: 0.15.7 - esbuild-windows-arm64: 0.15.7 - dev: true - - /escape-string-regexp/2.0.0: - resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} - engines: {node: '>=8'} - dev: true - - /escape-string-regexp/4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - dev: true - - /eslint-plugin-no-only-tests/3.0.0: - resolution: {integrity: sha512-I0PeXMs1vu21ap45hey4HQCJRqpcoIvGcNTPJe+UhUm8TwjQ6//mCrDqF8q0WS6LgmRDwQ4ovQej0AQsAHb5yg==} - engines: {node: '>=5.0.0'} - dev: true - - /eslint-plugin-todo-plz/1.2.1_eslint@8.22.0: - resolution: {integrity: sha512-yhmbfrAOvSupcoWcfm9V6tOXihPNAGp9NiUD4xiMgxUyARSIQRBpi0cOFgcmj1GXC9KCoxFX7oMAGfdSovY60A==} - engines: {node: '>=12'} - peerDependencies: - eslint: '>=7.3.0' - dependencies: - eslint: 8.22.0 - dev: true - - /eslint-scope/7.1.1: - resolution: {integrity: sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 - dev: true - - /eslint-utils/3.0.0_eslint@8.22.0: - resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} - engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} - peerDependencies: - eslint: '>=5' - dependencies: - eslint: 8.22.0 - eslint-visitor-keys: 2.1.0 - dev: true - - /eslint-visitor-keys/2.1.0: - resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} - engines: {node: '>=10'} - dev: true - - /eslint-visitor-keys/3.3.0: - resolution: {integrity: sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true - - /eslint/8.22.0: - resolution: {integrity: sha512-ci4t0sz6vSRKdmkOGmprBo6fmI4PrphDFMy5JEq/fNS0gQkJM3rLmrqcp8ipMcdobH3KtUP40KniAE9W19S4wA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - hasBin: true - dependencies: - '@eslint/eslintrc': 1.3.0 - '@humanwhocodes/config-array': 0.10.4 - '@humanwhocodes/gitignore-to-minimatch': 1.0.2 - ajv: 6.12.6 - chalk: 4.1.2 - cross-spawn: 7.0.3 - debug: 4.3.4 - doctrine: 3.0.0 - escape-string-regexp: 4.0.0 - eslint-scope: 7.1.1 - eslint-utils: 3.0.0_eslint@8.22.0 - eslint-visitor-keys: 3.3.0 - espree: 9.3.3 - esquery: 1.4.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 6.0.1 - find-up: 5.0.0 - functional-red-black-tree: 1.0.1 - glob-parent: 6.0.2 - globals: 13.17.0 - globby: 11.1.0 - grapheme-splitter: 1.0.4 - ignore: 5.2.0 - import-fresh: 3.3.0 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - js-yaml: 4.1.0 - json-stable-stringify-without-jsonify: 1.0.1 - levn: 0.4.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 - natural-compare: 1.4.0 - optionator: 0.9.1 - regexpp: 3.2.0 - strip-ansi: 6.0.1 - strip-json-comments: 3.1.1 - text-table: 0.2.0 - v8-compile-cache: 2.3.0 - transitivePeerDependencies: - - supports-color - dev: true - - /espree/9.3.3: - resolution: {integrity: sha512-ORs1Rt/uQTqUKjDdGCyrtYxbazf5umATSf/K4qxjmZHORR6HJk+2s/2Pqe+Kk49HHINC/xNIrGfgh8sZcll0ng==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - acorn: 8.8.0 - acorn-jsx: 5.3.2_acorn@8.8.0 - eslint-visitor-keys: 3.3.0 - dev: true - - /esquery/1.4.0: - resolution: {integrity: sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==} - engines: {node: '>=0.10'} - dependencies: - estraverse: 5.3.0 - dev: true - - /esrecurse/4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} - dependencies: - estraverse: 5.3.0 - dev: true - - /estraverse/5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - dev: true - - /estree-walker/0.6.1: - resolution: {integrity: sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==} - dev: true - - /estree-walker/1.0.1: - resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==} - dev: true - - /estree-walker/2.0.2: - resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} - dev: true - - /esutils/2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - dev: true - - /fast-deep-equal/3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - dev: true - - /fast-glob/3.2.11: - resolution: {integrity: sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==} - engines: {node: '>=8.6.0'} - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.5 - dev: true - - /fast-json-stable-stringify/2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - dev: true - - /fast-levenshtein/2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - dev: true - - /fastq/1.13.0: - resolution: {integrity: sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==} - dependencies: - reusify: 1.0.4 - dev: true - - /file-entry-cache/6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} - dependencies: - flat-cache: 3.0.4 - dev: true - - /file-set/4.0.2: - resolution: {integrity: sha512-fuxEgzk4L8waGXaAkd8cMr73Pm0FxOVkn8hztzUW7BAHhOGH90viQNXbiOsnecCWmfInqU6YmAMwxRMdKETceQ==} - engines: {node: '>=10'} - dependencies: - array-back: 5.0.0 - glob: 7.2.3 - dev: true - - /fill-range/7.0.1: - resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} - engines: {node: '>=8'} - dependencies: - to-regex-range: 5.0.1 - dev: true - - /find-replace/3.0.0: - resolution: {integrity: sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==} - engines: {node: '>=4.0.0'} - dependencies: - array-back: 3.1.0 - dev: true - - /find-up/5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - dev: true - - /flat-cache/3.0.4: - resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} - engines: {node: ^10.12.0 || >=12.0.0} - dependencies: - flatted: 3.2.7 - rimraf: 3.0.2 - dev: true - - /flatted/3.2.7: - resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} - dev: true - - /fs-then-native/2.0.0: - resolution: {integrity: sha512-X712jAOaWXkemQCAmWeg5rOT2i+KOpWz1Z/txk/cW0qlOu2oQ9H61vc5w3X/iyuUEfq/OyaFJ78/cZAQD1/bgA==} - engines: {node: '>=4.0.0'} - dev: true - - /fs.realpath/1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - dev: true - - /fsevents/2.3.2: - resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /function-bind/1.1.1: - resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} - dev: true - - /functional-red-black-tree/1.0.1: - resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} - dev: true - - /get-func-name/2.0.0: - resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==} - dev: true - - /glob-parent/5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} - dependencies: - is-glob: 4.0.3 - dev: true - - /glob-parent/6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} - dependencies: - is-glob: 4.0.3 - dev: true - - /glob/7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - dev: true - - /globals/13.17.0: - resolution: {integrity: sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==} - engines: {node: '>=8'} - dependencies: - type-fest: 0.20.2 - dev: true - - /globby/11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} - engines: {node: '>=10'} - dependencies: - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.2.11 - ignore: 5.2.0 - merge2: 1.4.1 - slash: 3.0.0 - dev: true - - /graceful-fs/4.2.10: - resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} - dev: true - - /grapheme-splitter/1.0.4: - resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} - dev: true - - /handlebars/4.7.7: - resolution: {integrity: sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==} - engines: {node: '>=0.4.7'} - hasBin: true - dependencies: - minimist: 1.2.6 - neo-async: 2.6.2 - source-map: 0.6.1 - wordwrap: 1.0.0 - optionalDependencies: - uglify-js: 3.17.0 - dev: true - - /has-flag/4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - dev: true - - /has/1.0.3: - resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} - engines: {node: '>= 0.4.0'} - dependencies: - function-bind: 1.1.1 - dev: true - - /ignore/5.2.0: - resolution: {integrity: sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==} - engines: {node: '>= 4'} - dev: true - - /immer/9.0.15: - resolution: {integrity: sha512-2eB/sswms9AEUSkOm4SbV5Y7Vmt/bKRwByd52jfLkW4OLYeaTP3EEiJ9agqU0O/tq6Dk62Zfj+TJSqfm1rLVGQ==} - dev: false - - /import-fresh/3.3.0: - resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} - engines: {node: '>=6'} - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - dev: true - - /imurmurhash/0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - dev: true - - /inflight/1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - dev: true - - /inherits/2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - dev: true - - /is-core-module/2.10.0: - resolution: {integrity: sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==} - dependencies: - has: 1.0.3 - dev: true - - /is-extglob/2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - dev: true - - /is-glob/4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - dependencies: - is-extglob: 2.1.1 - dev: true - - /is-number/7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - dev: true - - /isexe/2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - dev: true - - /js-yaml/4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} - hasBin: true - dependencies: - argparse: 2.0.1 - dev: true - - /js2xmlparser/4.0.2: - resolution: {integrity: sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==} - dependencies: - xmlcreate: 2.0.4 - dev: true - - /jsdoc-api/7.1.1: - resolution: {integrity: sha512-0pkuPCzVXiqsDAsVrNFXCkHzlyNepBIDVtwwehry4RJAnZmXtlAz7rh8F9FRz53u3NeynGbex+bpYWwi8lE66A==} - engines: {node: '>=12.17'} - dependencies: - array-back: 6.2.2 - cache-point: 2.0.0 - collect-all: 1.0.4 - file-set: 4.0.2 - fs-then-native: 2.0.0 - jsdoc: 3.6.11 - object-to-spawn-args: 2.0.1 - temp-path: 1.0.0 - walk-back: 5.1.0 - dev: true - - /jsdoc-parse/6.1.0: - resolution: {integrity: sha512-n/hDGQJa69IBun1yZAjqzV4gVR41+flZ3bIlm9fKvNe2Xjsd1/+zCo2+R9ls8LxtePgIWbpA1jU7xkB2lRdLLg==} - engines: {node: '>=12'} - dependencies: - array-back: 6.2.2 - lodash.omit: 4.5.0 - lodash.pick: 4.4.0 - reduce-extract: 1.0.0 - sort-array: 4.1.5 - test-value: 3.0.0 - dev: true - - /jsdoc-to-markdown/7.1.1: - resolution: {integrity: sha512-CI86d63xAVNO+ENumWwmJ034lYe5iGU5GwjtTA11EuphP9tpnoi4hrKgR/J8uME0D+o4KUpVfwX1fjZhc8dEtg==} - engines: {node: '>=12.17'} - hasBin: true - dependencies: - array-back: 6.2.2 - command-line-tool: 0.8.0 - config-master: 3.1.0 - dmd: 6.1.0 - jsdoc-api: 7.1.1 - jsdoc-parse: 6.1.0 - walk-back: 5.1.0 - dev: true - - /jsdoc/3.6.11: - resolution: {integrity: sha512-8UCU0TYeIYD9KeLzEcAu2q8N/mx9O3phAGl32nmHlE0LpaJL71mMkP4d+QE5zWfNt50qheHtOZ0qoxVrsX5TUg==} - engines: {node: '>=12.0.0'} - hasBin: true - dependencies: - '@babel/parser': 7.18.13 - '@types/markdown-it': 12.2.3 - bluebird: 3.7.2 - catharsis: 0.9.0 - escape-string-regexp: 2.0.0 - js2xmlparser: 4.0.2 - klaw: 3.0.0 - markdown-it: 12.3.2 - markdown-it-anchor: 8.6.4_2zb4u3vubltivolgu556vv4aom - marked: 4.1.0 - mkdirp: 1.0.4 - requizzle: 0.2.3 - strip-json-comments: 3.1.1 - taffydb: 2.6.2 - underscore: 1.13.4 - dev: true - - /json-schema-shorthand/2.0.0: - resolution: {integrity: sha512-tA1EoSDLDdQEv396fLdlzU3WPSVdN2MVMivfNX0Fdm6woEH4mNX3nRGj//wi/VvWDDOpLiN5w9TSlKIXbItiHg==} - dependencies: - lodash: 4.17.21 - updeep: 1.2.1 - dev: false - - /json-schema-traverse/0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - dev: true - - /json-stable-stringify-without-jsonify/1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - dev: true - - /jsonc-parser/3.2.0: - resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} - dev: true - - /klaw/3.0.0: - resolution: {integrity: sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==} - dependencies: - graceful-fs: 4.2.10 - dev: true - - /levn/0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 - dev: true - - /linkify-it/3.0.3: - resolution: {integrity: sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==} - dependencies: - uc.micro: 1.0.6 - dev: true - - /local-pkg/0.4.2: - resolution: {integrity: sha512-mlERgSPrbxU3BP4qBqAvvwlgW4MTg78iwJdGGnv7kibKjWcJksrG3t6LB5lXI93wXRDvG4NpUgJFmTG4T6rdrg==} - engines: {node: '>=14'} - dev: true - - /locate-path/6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} - dependencies: - p-locate: 5.0.0 - dev: true - - /lodash.camelcase/4.3.0: - resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} - dev: true - - /lodash.merge/4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - dev: true - - /lodash.omit/4.5.0: - resolution: {integrity: sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg==} - dev: true - - /lodash.padend/4.6.1: - resolution: {integrity: sha512-sOQs2aqGpbl27tmCS1QNZA09Uqp01ZzWfDUoD+xzTii0E7dSQfRKcRetFwa+uXaxaqL+TKm7CgD2JdKP7aZBSw==} - dev: true - - /lodash.pick/4.4.0: - resolution: {integrity: sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q==} - dev: true - - /lodash/4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - - /loupe/2.3.4: - resolution: {integrity: sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==} - dependencies: - get-func-name: 2.0.0 - dev: true - - /magic-string/0.25.9: - resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} - dependencies: - sourcemap-codec: 1.4.8 - dev: true - - /markdown-it-anchor/8.6.4_2zb4u3vubltivolgu556vv4aom: - resolution: {integrity: sha512-Ul4YVYZNxMJYALpKtu+ZRdrryYt/GlQ5CK+4l1bp/gWXOG2QWElt6AqF3Mih/wfUKdZbNAZVXGR73/n6U/8img==} - peerDependencies: - '@types/markdown-it': '*' - markdown-it: '*' - dependencies: - '@types/markdown-it': 12.2.3 - markdown-it: 12.3.2 - dev: true - - /markdown-it/12.3.2: - resolution: {integrity: sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==} - hasBin: true - dependencies: - argparse: 2.0.1 - entities: 2.1.0 - linkify-it: 3.0.3 - mdurl: 1.0.1 - uc.micro: 1.0.6 - dev: true - - /marked/4.1.0: - resolution: {integrity: sha512-+Z6KDjSPa6/723PQYyc1axYZpYYpDnECDaU6hkaf5gqBieBkMKYReL5hteF2QizhlMbgbo8umXl/clZ67+GlsA==} - engines: {node: '>= 12'} - hasBin: true - dev: true - - /mdurl/1.0.1: - resolution: {integrity: sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==} - dev: true - - /merge2/1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - dev: true - - /micromatch/4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} - engines: {node: '>=8.6'} - dependencies: - braces: 3.0.2 - picomatch: 2.3.1 - dev: true - - /minimatch/3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - dependencies: - brace-expansion: 1.1.11 - dev: true - - /minimist/1.2.6: - resolution: {integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==} - dev: true - - /mkdirp/1.0.4: - resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} - engines: {node: '>=10'} - hasBin: true - dev: true - - /mkdirp2/1.0.5: - resolution: {integrity: sha512-xOE9xbICroUDmG1ye2h4bZ8WBie9EGmACaco8K8cx6RlkJJrxGIqjGqztAI+NMhexXBcdGbSEzI6N3EJPevxZw==} - dev: true - - /mlly/0.5.14: - resolution: {integrity: sha512-DgRgNUSX9NIxxCxygX4Xeg9C7GX7OUx1wuQ8cXx9o9LE0e9wrH+OZ9fcnrlEedsC/rtqry3ZhUddC759XD/L0w==} - dependencies: - acorn: 8.8.0 - pathe: 0.3.7 - pkg-types: 0.3.5 - ufo: 0.8.5 - dev: true - - /modern-node-polyfills/0.0.9: - resolution: {integrity: sha512-Z7sFaWAHCEAw44Ww1L0JEt4BaQ7/LVTbbqTtm3bNSfdWs0ZW7QwRN7Xy8RjSPOlZ9ZSkoXAa54neuvAC6KGRFg==} - dependencies: - '@jspm/core': 2.0.0-beta.24 - '@rollup/plugin-inject': 4.0.4_rollup@2.77.3 - acorn: 8.8.0 - esbuild: 0.14.54 - local-pkg: 0.4.2 - rollup: 2.77.3 - dev: true - - /mrmime/1.0.1: - resolution: {integrity: sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==} - engines: {node: '>=10'} - dev: true - - /ms/2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - dev: true - - /nanoid/3.3.4: - resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - dev: true - - /natural-compare/1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - dev: true - - /neo-async/2.6.2: - resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - dev: true - - /object-get/2.1.1: - resolution: {integrity: sha512-7n4IpLMzGGcLEMiQKsNR7vCe+N5E9LORFrtNUVy4sO3dj9a3HedZCxEL2T7QuLhcHN1NBuBsMOKaOsAYI9IIvg==} - dev: true - - /object-to-spawn-args/2.0.1: - resolution: {integrity: sha512-6FuKFQ39cOID+BMZ3QaphcC8Y4cw6LXBLyIgPU+OhIYwviJamPAn+4mITapnSBQrejB+NNp+FMskhD8Cq+Ys3w==} - engines: {node: '>=8.0.0'} - dev: true - - /once/1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - dependencies: - wrappy: 1.0.2 - dev: true - - /optionator/0.9.1: - resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==} - engines: {node: '>= 0.8.0'} - dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.4.1 - prelude-ls: 1.2.1 - type-check: 0.4.0 - word-wrap: 1.2.3 - dev: true - - /p-limit/3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - dependencies: - yocto-queue: 0.1.0 - dev: true - - /p-locate/5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} - dependencies: - p-limit: 3.1.0 - dev: true - - /parent-module/1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} - dependencies: - callsites: 3.1.0 - dev: true - - /path-exists/4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - dev: true - - /path-is-absolute/1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - dev: true - - /path-key/3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - dev: true - - /path-parse/1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - dev: true - - /path-type/4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} - dev: true - - /pathe/0.3.7: - resolution: {integrity: sha512-yz7GK+kSsS27x727jtXpd5VT4dDfP/JDIQmaowfxyWCnFjOWtE1VIh7i6TzcSfzW0n4+bRQztj1VdKnITNq/MA==} - dev: true - - /pathval/1.1.1: - resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} - dev: true - - /picocolors/1.0.0: - resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} - dev: true - - /picomatch/2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - dev: true - - /pkg-types/0.3.5: - resolution: {integrity: sha512-VkxCBFVgQhNHYk9subx+HOhZ4jzynH11ah63LZsprTKwPCWG9pfWBlkElWFbvkP9BVR0dP1jS9xPdhaHQNK74Q==} - dependencies: - jsonc-parser: 3.2.0 - mlly: 0.5.14 - pathe: 0.3.7 - dev: true - - /postcss/8.4.16: - resolution: {integrity: sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==} - engines: {node: ^10 || ^12 || >=14} - dependencies: - nanoid: 3.3.4 - picocolors: 1.0.0 - source-map-js: 1.0.2 - dev: true - - /prelude-ls/1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - dev: true - - /prettier/2.7.1: - resolution: {integrity: sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==} - engines: {node: '>=10.13.0'} - hasBin: true - dev: true - - /punycode/2.1.1: - resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==} - engines: {node: '>=6'} - dev: true - - /queue-microtask/1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - dev: true - - /reduce-extract/1.0.0: - resolution: {integrity: sha512-QF8vjWx3wnRSL5uFMyCjDeDc5EBMiryoT9tz94VvgjKfzecHAVnqmXAwQDcr7X4JmLc2cjkjFGCVzhMqDjgR9g==} - engines: {node: '>=0.10.0'} - dependencies: - test-value: 1.1.0 - dev: true - - /reduce-flatten/1.0.1: - resolution: {integrity: sha512-j5WfFJfc9CoXv/WbwVLHq74i/hdTUpy+iNC534LxczMRP67vJeK3V9JOdnL0N1cIRbn9mYhE2yVjvvKXDxvNXQ==} - engines: {node: '>=0.10.0'} - dev: true - - /reduce-flatten/3.0.1: - resolution: {integrity: sha512-bYo+97BmUUOzg09XwfkwALt4PQH1M5L0wzKerBt6WLm3Fhdd43mMS89HiT1B9pJIqko/6lWx3OnV4J9f2Kqp5Q==} - engines: {node: '>=8'} - dev: true - - /reduce-unique/2.0.1: - resolution: {integrity: sha512-x4jH/8L1eyZGR785WY+ePtyMNhycl1N2XOLxhCbzZFaqF4AXjLzqSxa2UHgJ2ZVR/HHyPOvl1L7xRnW8ye5MdA==} - engines: {node: '>=6'} - dev: true - - /reduce-without/1.0.1: - resolution: {integrity: sha512-zQv5y/cf85sxvdrKPlfcRzlDn/OqKFThNimYmsS3flmkioKvkUGn2Qg9cJVoQiEvdxFGLE0MQER/9fZ9sUqdxg==} - engines: {node: '>=0.10.0'} - dependencies: - test-value: 2.1.0 - dev: true - - /redux/4.2.0: - resolution: {integrity: sha512-oSBmcKKIuIR4ME29/AeNUnl5L+hvBq7OaJWzaptTQJAntaPvxIJqfnjbaEiCzzaIz+XmVILfqAM3Ob0aXLPfjA==} - dependencies: - '@babel/runtime': 7.18.9 - dev: false - - /regenerator-runtime/0.13.9: - resolution: {integrity: sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==} - dev: false - - /regexpp/3.2.0: - resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} - engines: {node: '>=8'} - dev: true - - /remeda/1.0.1: - resolution: {integrity: sha512-W/YDzHzIDDFnD9g5fKmvKSnV7uFvDV6EnM+dfd2iCQdhTyttvhcBkK3YTaxIikefr9UkAsxHyxdZWjhbWZ7x8g==} - dev: false - - /requizzle/0.2.3: - resolution: {integrity: sha512-YanoyJjykPxGHii0fZP0uUPEXpvqfBDxWV7s6GKAiiOsiqhX6vHNyW3Qzdmqp/iq/ExbhaGbVrjB4ruEVSM4GQ==} - dependencies: - lodash: 4.17.21 - dev: true - - /resolve-from/4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - dev: true - - /resolve/1.22.1: - resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} - hasBin: true - dependencies: - is-core-module: 2.10.0 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - dev: true - - /reusify/1.0.4: - resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - dev: true - - /rimraf/3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - hasBin: true - dependencies: - glob: 7.2.3 - dev: true - - /rollup-plugin-inject/3.0.2: - resolution: {integrity: sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==} - deprecated: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-inject. - dependencies: - estree-walker: 0.6.1 - magic-string: 0.25.9 - rollup-pluginutils: 2.8.2 - dev: true - - /rollup-plugin-node-polyfills/0.2.1: - resolution: {integrity: sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==} - dependencies: - rollup-plugin-inject: 3.0.2 - dev: true - - /rollup-pluginutils/2.8.2: - resolution: {integrity: sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==} - dependencies: - estree-walker: 0.6.1 - dev: true - - /rollup/2.77.3: - resolution: {integrity: sha512-/qxNTG7FbmefJWoeeYJFbHehJ2HNWnjkAFRKzWN/45eNBBF/r8lo992CwcJXEzyVxs5FmfId+vTSTQDb+bxA+g==} - engines: {node: '>=10.0.0'} - hasBin: true - optionalDependencies: - fsevents: 2.3.2 - dev: true - - /rollup/2.78.1: - resolution: {integrity: sha512-VeeCgtGi4P+o9hIg+xz4qQpRl6R401LWEXBmxYKOV4zlF82lyhgh2hTZnheFUbANE8l2A41F458iwj2vEYaXJg==} - engines: {node: '>=10.0.0'} - hasBin: true - optionalDependencies: - fsevents: 2.3.2 - dev: true - - /run-parallel/1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - dependencies: - queue-microtask: 1.2.3 - dev: true - - /shebang-command/2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - dependencies: - shebang-regex: 3.0.0 - dev: true - - /shebang-regex/3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - dev: true - - /sirv/2.0.2: - resolution: {integrity: sha512-4Qog6aE29nIjAOKe/wowFTxOdmbEZKb+3tsLljaBRzJwtqto0BChD2zzH0LhgCSXiI+V7X+Y45v14wBZQ1TK3w==} - engines: {node: '>= 10'} - dependencies: - '@polka/url': 1.0.0-next.21 - mrmime: 1.0.1 - totalist: 3.0.0 - dev: true - - /slash/3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} - dev: true - - /sort-array/4.1.5: - resolution: {integrity: sha512-Ya4peoS1fgFN42RN1REk2FgdNOeLIEMKFGJvs7VTP3OklF8+kl2SkpVliZ4tk/PurWsrWRsdNdU+tgyOBkB9sA==} - engines: {node: '>=10'} - dependencies: - array-back: 5.0.0 - typical: 6.0.1 - dev: true - - /source-map-js/1.0.2: - resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} - engines: {node: '>=0.10.0'} - dev: true - - /source-map/0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - dev: true - - /sourcemap-codec/1.4.8: - resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} - dev: true - - /stream-connect/1.0.2: - resolution: {integrity: sha512-68Kl+79cE0RGKemKkhxTSg8+6AGrqBt+cbZAXevg2iJ6Y3zX4JhA/sZeGzLpxW9cXhmqAcE7KnJCisUmIUfnFQ==} - engines: {node: '>=0.10.0'} - dependencies: - array-back: 1.0.4 - dev: true - - /stream-via/1.0.4: - resolution: {integrity: sha512-DBp0lSvX5G9KGRDTkR/R+a29H+Wk2xItOF+MpZLLNDWbEV9tGPnqLPxHEYjmiz8xGtJHRIqmI+hCjmNzqoA4nQ==} - engines: {node: '>=0.10.0'} - dev: true - - /strip-ansi/6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - dependencies: - ansi-regex: 5.0.1 - dev: true - - /strip-json-comments/3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - dev: true - - /strip-literal/0.4.0: - resolution: {integrity: sha512-ql/sBDoJOybTKSIOWrrh8kgUEMjXMwRAkZTD0EwiwxQH/6tTPkZvMIEjp0CRlpi6V5FMiJyvxeRkEi1KrGISoA==} - dependencies: - acorn: 8.8.0 - dev: true - - /supports-color/7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - dependencies: - has-flag: 4.0.0 - dev: true - - /supports-preserve-symlinks-flag/1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - dev: true - - /table-layout/0.4.5: - resolution: {integrity: sha512-zTvf0mcggrGeTe/2jJ6ECkJHAQPIYEwDoqsiqBjI24mvRmQbInK5jq33fyypaCBxX08hMkfmdOqj6haT33EqWw==} - engines: {node: '>=4.0.0'} - dependencies: - array-back: 2.0.0 - deep-extend: 0.6.0 - lodash.padend: 4.6.1 - typical: 2.6.1 - wordwrapjs: 3.0.0 - dev: true - - /taffydb/2.6.2: - resolution: {integrity: sha1-fLy2S1oUG2ou/CxdLGe04VCyomg=} - dev: true - - /temp-path/1.0.0: - resolution: {integrity: sha512-TvmyH7kC6ZVTYkqCODjJIbgvu0FKiwQpZ4D1aknE7xpcDf/qEOB8KZEK5ef2pfbVoiBhNWs3yx4y+ESMtNYmlg==} - dev: true - - /test-value/1.1.0: - resolution: {integrity: sha512-wrsbRo7qP+2Je8x8DsK8ovCGyxe3sYfQwOraIY/09A2gFXU9DYKiTF14W4ki/01AEh56kMzAmlj9CaHGDDUBJA==} - engines: {node: '>=0.10.0'} - dependencies: - array-back: 1.0.4 - typical: 2.6.1 - dev: true - - /test-value/2.1.0: - resolution: {integrity: sha512-+1epbAxtKeXttkGFMTX9H42oqzOTufR1ceCF+GYA5aOmvaPq9wd4PUS8329fn2RRLGNeUkgRLnVpycjx8DsO2w==} - engines: {node: '>=0.10.0'} - dependencies: - array-back: 1.0.4 - typical: 2.6.1 - dev: true - - /test-value/3.0.0: - resolution: {integrity: sha512-sVACdAWcZkSU9x7AOmJo5TqE+GyNJknHaHsMrR6ZnhjVlVN9Yx6FjHrsKZ3BjIpPCT68zYesPWkakrNupwfOTQ==} - engines: {node: '>=4.0.0'} - dependencies: - array-back: 2.0.0 - typical: 2.6.1 - dev: true - - /text-table/0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - dev: true - - /tinybench/2.1.5: - resolution: {integrity: sha512-ak+PZZEuH3mw6CCFOgf5S90YH0MARnZNhxjhjguAmoJimEMAJuNip/rJRd6/wyylHItomVpKTzZk9zrhTrQCoQ==} - dev: true - - /tinypool/0.2.4: - resolution: {integrity: sha512-Vs3rhkUH6Qq1t5bqtb816oT+HeJTXfwt2cbPH17sWHIYKTotQIFPk3tf2fgqRrVyMDVOc1EnPgzIxfIulXVzwQ==} - engines: {node: '>=14.0.0'} - dev: true - - /tinyspy/1.0.2: - resolution: {integrity: sha512-bSGlgwLBYf7PnUsQ6WOc6SJ3pGOcd+d8AA6EUnLDDM0kWEstC1JIlSZA3UNliDXhd9ABoS7hiRBDCu+XP/sf1Q==} - engines: {node: '>=14.0.0'} - dev: true - - /to-fast-properties/2.0.0: - resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} - engines: {node: '>=4'} - dev: true - - /to-regex-range/5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - dependencies: - is-number: 7.0.0 - dev: true - - /totalist/3.0.0: - resolution: {integrity: sha512-eM+pCBxXO/njtF7vdFsHuqb+ElbxqtI4r5EAvk6grfAFyJ6IvWlSkfZ5T9ozC6xWw3Fj1fGoSmrl0gUs46JVIw==} - engines: {node: '>=6'} - dev: true - - /type-check/0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} - dependencies: - prelude-ls: 1.2.1 - dev: true - - /type-detect/4.0.8: - resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} - engines: {node: '>=4'} - dev: true - - /type-fest/0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} - dev: true - - /typical/2.6.1: - resolution: {integrity: sha512-ofhi8kjIje6npGozTip9Fr8iecmYfEbS06i0JnIg+rh51KakryWF4+jX8lLKZVhy6N+ID45WYSFCxPOdTWCzNg==} - dev: true - - /typical/4.0.0: - resolution: {integrity: sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==} - engines: {node: '>=8'} - dev: true - - /typical/6.0.1: - resolution: {integrity: sha512-+g3NEp7fJLe9DPa1TArHm9QAA7YciZmWnfAqEaFrBihQ7epOv9i99rjtgb6Iz0wh3WuQDjsCTDfgRoGnmHN81A==} - engines: {node: '>=10'} - dev: true - - /uc.micro/1.0.6: - resolution: {integrity: sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==} - dev: true - - /ufo/0.8.5: - resolution: {integrity: sha512-e4+UtA5IRO+ha6hYklwj6r7BjiGMxS0O+UaSg9HbaTefg4kMkzj4tXzEBajRR+wkxf+golgAWKzLbytCUDMJAA==} - dev: true - - /uglify-js/3.17.0: - resolution: {integrity: sha512-aTeNPVmgIMPpm1cxXr2Q/nEbvkmV8yq66F3om7X3P/cvOXQ0TMQ64Wk63iyT1gPlmdmGzjGpyLh1f3y8MZWXGg==} - engines: {node: '>=0.8.0'} - hasBin: true - requiresBuild: true - dev: true - optional: true - - /underscore/1.13.4: - resolution: {integrity: sha512-BQFnUDuAQ4Yf/cYY5LNrK9NCJFKriaRbD9uR1fTeXnBeoa97W0i41qkZfGO9pSo8I5KzjAcSY2XYtdf0oKd7KQ==} - dev: true - - /updeep/1.2.1: - resolution: {integrity: sha512-cqWsgE1DVNkUeKW+1OfnftBNtSXnxep4aj8GS5oI0dkSfOIU1T6N3vADLhp9EtFPpmmCBHKMQAtsr2b2KY9Lyg==} - dependencies: - lodash: 4.17.21 - dev: false - - /uri-js/4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - dependencies: - punycode: 2.1.1 - dev: true - - /v8-compile-cache/2.3.0: - resolution: {integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==} - dev: true - - /vite/3.1.0: - resolution: {integrity: sha512-YBg3dUicDpDWFCGttmvMbVyS9ydjntwEjwXRj2KBFwSB8SxmGcudo1yb8FW5+M/G86aS8x828ujnzUVdsLjs9g==} - engines: {node: ^14.18.0 || >=16.0.0} - hasBin: true - peerDependencies: - less: '*' - sass: '*' - stylus: '*' - terser: ^5.4.0 - peerDependenciesMeta: - less: - optional: true - sass: - optional: true - stylus: - optional: true - terser: - optional: true - dependencies: - esbuild: 0.15.7 - postcss: 8.4.16 - resolve: 1.22.1 - rollup: 2.78.1 - optionalDependencies: - fsevents: 2.3.2 - dev: true - - /vitest/0.23.1_kkczkm7y7wgspdnr2rpymavxge: - resolution: {integrity: sha512-kn9pG+h6VA3yj/xRvwgLKEd33rOlzMqJEg3tl5HSm3WUPlkY1Lr1FK8RN1uIqVKvFxmz6HGU3EQW+xW2kazRkQ==} - engines: {node: '>=v14.16.0'} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@vitest/browser': '*' - '@vitest/ui': '*' - happy-dom: '*' - jsdom: '*' - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@vitest/browser': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true - dependencies: - '@types/chai': 4.3.3 - '@types/chai-subset': 1.3.3 - '@types/node': 18.7.15 - '@vitest/browser': 0.23.1 - '@vitest/ui': 0.23.1 - chai: 4.3.6 - debug: 4.3.4 - local-pkg: 0.4.2 - strip-literal: 0.4.0 - tinybench: 2.1.5 - tinypool: 0.2.4 - tinyspy: 1.0.2 - vite: 3.1.0 - transitivePeerDependencies: - - less - - sass - - stylus - - supports-color - - terser - dev: true - - /walk-back/2.0.1: - resolution: {integrity: sha512-Nb6GvBR8UWX1D+Le+xUq0+Q1kFmRBIWVrfLnQAOmcpEzA9oAxwJ9gIr36t9TWYfzvWRvuMtjHiVsJYEkXWaTAQ==} - engines: {node: '>=0.10.0'} - dev: true - - /walk-back/5.1.0: - resolution: {integrity: sha512-Uhxps5yZcVNbLEAnb+xaEEMdgTXl9qAQDzKYejG2AZ7qPwRQ81lozY9ECDbjLPNWm7YsO1IK5rsP1KoQzXAcGA==} - engines: {node: '>=12.17'} - dev: true - - /which/2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - dependencies: - isexe: 2.0.0 - dev: true - - /word-wrap/1.2.3: - resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==} - engines: {node: '>=0.10.0'} - dev: true - - /wordwrap/1.0.0: - resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} - dev: true - - /wordwrapjs/3.0.0: - resolution: {integrity: sha512-mO8XtqyPvykVCsrwj5MlOVWvSnCdT+C+QVbm6blradR7JExAhbkZ7hZ9A+9NUtwzSqrlUo9a67ws0EiILrvRpw==} - engines: {node: '>=4.0.0'} - dependencies: - reduce-flatten: 1.0.1 - typical: 2.6.1 - dev: true - - /wrappy/1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - dev: true - - /xmlcreate/2.0.4: - resolution: {integrity: sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==} - dev: true - - /yocto-queue/0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - dev: true diff --git a/src/Updux.original b/src/Updux.original new file mode 100644 index 0000000..51ca3b9 --- /dev/null +++ b/src/Updux.original @@ -0,0 +1,457 @@ +/* TODO change * for leftovers to +, change subscriptions to reactions */ +import moize from 'moize'; +import u from 'updeep'; +import { createStore as reduxCreateStore, applyMiddleware } from 'redux'; +import { get, map, mapValues, merge, difference } from 'lodash-es'; + +import { buildInitial } from './buildInitial/index.js'; +import { buildActions } from './buildActions/index.js'; +import { buildSelectors } from './buildSelectors/index.js'; +import { action } from './actions.js'; +import { buildUpreducer } from './buildUpreducer.js'; +import { + buildMiddleware, + augmentMiddlewareApi, + effectToMiddleware, +} from './buildMiddleware/index.js'; + +import { + AggregateDuxActions, + AggregateDuxState, + Dict, + ItemsOf, + Reducer, + Upreducer, +} from './types.js'; + +type Mutation = (payload:TAction['payload'], action:TAction) => (state: TState) => TState; + +/** + * Configuration object typically passed to the constructor of the class Updux. + */ +export interface UpduxConfig< + TState = any, + TActions = {}, + TSelectors = {}, + TSubduxes = {} +> { + /** + * Local initialState state. + * @default {} + */ + initialState?: TState; + + /** + * Subduxes to be merged to this dux. + */ + subduxes?: TSubduxes; + + /** + * Local actions. + */ + actions?: TActions; + + /** + * Local selectors. + */ + selectors?: Record; + + /** + * Local mutations + */ + mutations?: Record; + + /** + * Selectors to apply to the mapped subduxes. Only + * applicable if the dux is a mapping dux. + */ + mappedSelectors?: Record; + + /** + * Local effects. + */ + effects?: Record; + + /** + * Local reactions. + */ + reactions?: Function[]; + + /** + * If true, enables mapped reactions. Additionally, it can be + * a reaction function, which will treated as a regular + * reaction for the mapped dux. + */ + mappedReaction?: Function | boolean; + + /** + * Wrapping function for the upreducer to provides full customization. + * @example + * // if an action has the 'dontDoIt' meta flag, don't do anything + * const dux = new Updux({ + * ..., + * upreducerWrapper: (upreducer) => action => { + * if( action?.meta?.dontDoIt ) return state => state; + * return upreducer(action); + * } + * }) + */ + upreducerWrapper?: ( + upreducer: Upreducer< + AggregateDuxState, + ItemsOf> + > + ) => Upreducer< + AggregateDuxState, + ItemsOf> + >; + + middlewareWrapper?: Function; +} + +export class Updux< + TState extends any = {}, + TActions extends object = {}, + TSelectors = {}, + TSubduxes extends object = {} +> { + /** @type { unknown } */ + #initialState = {}; + #subduxes = {}; + + /** @type Record */ + #actions = {}; + #selectors = {}; + #mutations = {}; + #effects = []; + #reactions = []; + #mappedSelectors = undefined; + #mappedReaction = undefined; + #upreducerWrapper = undefined; + + #middlewareWrapper = undefined; + + constructor( + config: UpduxConfig + ) { + this.#initialState = config.initialState ?? {}; + this.#subduxes = config.subduxes ?? {}; + + if (config.subduxes) { + this.#subduxes = mapValues(config.subduxes, (sub) => + sub instanceof Updux ? sub : new Updux(sub) + ); + } + + if (config.actions) { + for (const [type, actionArg] of Object.entries(config.actions)) { + if (typeof actionArg === 'function' && actionArg.type) { + this.#actions[type] = actionArg; + } else { + const args = Array.isArray(actionArg) + ? actionArg + : [actionArg]; + this.#actions[type] = action(type, ...args); + } + } + } + + this.#selectors = config.selectors ?? {}; + this.#mappedSelectors = config.mappedSelectors; + + this.#mutations = config.mutations ?? {}; + + Object.keys(this.#mutations) + .filter((action) => action !== '+') + .filter((action) => !this.actions.hasOwnProperty(action)) + .forEach((action) => { + throw new Error(`action '${action}' is not defined`); + }); + + if (config.effects) { + this.#effects = Object.entries(config.effects); + } + + this.#reactions = config.reactions ?? []; + + this.#mappedReaction = config.mappedReaction; + + this.#upreducerWrapper = config.upreducerWrapper; + + this.#middlewareWrapper = config.middlewareWrapper; + } + + #memoInitial = moize(buildInitial); + #memoActions = moize(buildActions); + #memoSelectors = moize(buildSelectors); + #memoUpreducer = moize(buildUpreducer); + #memoMiddleware = moize(buildMiddleware); + + setMappedSelector(name, f) { + this.#mappedSelectors = { + ...this.#mappedSelectors, + [name]: f, + }; + } + + get middleware() { + return this.#memoMiddleware( + this.#effects, + this.actions, + this.selectors, + this.#subduxes, + this.#middlewareWrapper, + this + ); + } + + setMiddlewareWrapper(wrapper: Function) { + this.#middlewareWrapper = wrapper; + } + + /** @member { unknown } */ + get initialState(): AggregateDuxState { + return this.#memoInitial(this.#initialState, this.#subduxes); + } + + get actions(): AggregateDuxActions { + return this.#memoActions(this.#actions, this.#subduxes) as any; + } + + get selectors() { + return this.#memoSelectors( + this.#selectors, + this.#mappedSelectors, + this.#subduxes + ); + } + + get subduxes() { return this.#subduxes } + + get upreducer(): Upreducer< + AggregateDuxState, + ItemsOf> + > { + return this.#memoUpreducer( + this.initialState, + this.#mutations, + this.#subduxes, + this.#upreducerWrapper + ); + } + + get reducer(): Reducer< + AggregateDuxState, + ItemsOf> + > { + return (state, action) => this.upreducer(action)(state); + } + + addSubscription(subscription) { + this.#reactions = [...this.#reactions, subscription]; + } + + addReaction(reaction) { + this.#reactions = [...this.#reactions, reaction]; + } + + + setAction(type, payloadFunc?: (...args: any) => any) { + const theAction = action(type, payloadFunc); + + this.#actions = { ...this.#actions, [type]: theAction }; + + return theAction; + } + + setSelector(name, func) { + // TODO selector already exists? Complain! + this.#selectors = { + ...this.#selectors, + [name]: func, + }; + return func; + } + + setMutation>(name: TAction, mutation: Mutation, + ReturnType[TAction]>>) { + if (typeof name === 'function') name = name.type; + + this.#mutations = { + ...this.#mutations, + [name]: mutation, + }; + + return mutation; + } + + addEffect(action: TType, effect: E): E { + this.#effects = [...this.#effects, [action, effect]]; + return effect; + } + + augmentMiddlewareApi(api) { + return augmentMiddlewareApi(api, this.actions, this.selectors); + } + + splatSubscriber(store, inner, splatReaction) { + const cache = {}; + + return () => (state, previous, unsub) => { + const cacheKeys = Object.keys(cache); + + const newKeys = difference(Object.keys(state), cacheKeys); + + for (const slice of newKeys) { + let localStore = { + ...store, + getState: () => store.getState()[slice], + }; + + cache[slice] = []; + + if (typeof splatReaction === 'function') { + localStore = { + ...localStore, + ...splatReaction(localStore, slice), + }; + } + + const { unsub, subscriber, subscriberRaw } = + inner.subscribeAll(localStore); + + cache[slice].push({ unsub, subscriber, subscriberRaw }); + subscriber(); + } + + const deletedKeys = difference(cacheKeys, Object.keys(state)); + + for (const deleted of deletedKeys) { + for (const inner of cache[deleted]) { + inner.subscriber(); + inner.unsub(); + } + delete cache[deleted]; + } + }; + } + + subscribeTo(store, subscription, setupArgs = []) { + const localStore = augmentMiddlewareApi( + { + ...store, + subscribe: (subscriber) => + this.subscribeTo(store, () => subscriber), + }, + this.actions, + this.selectors + ); + + const subscriber = subscription(localStore, ...setupArgs); + + let previous; + + const memoSub = () => { + const state = store.getState(); + if (state === previous) return; + let p = previous; + previous = state; + subscriber(state, p, unsub); + }; + + let ret = store.subscribe(memoSub); + const unsub = typeof ret === 'function' ? ret : ret.unsub; + return { + unsub, + subscriber: memoSub, + subscriberRaw: subscriber, + }; + } + + subscribeAll(store) { + let results = this.#reactions.map((sub) => + this.subscribeTo(store, sub) + ); + + for (const subdux in this.#subduxes) { + if (subdux !== '*') { + const localStore = { + ...store, + getState: () => get(store.getState(), subdux), + }; + results.push(this.#subduxes[subdux].subscribeAll(localStore)); + } + } + + if (this.#mappedReaction) { + results.push( + this.subscribeTo( + store, + this.splatSubscriber( + store, + this.#subduxes['*'], + this.#mappedReaction + ) + ) + ); + } + + return { + unsub: () => results.forEach(({ unsub }) => unsub()), + subscriber: () => + results.forEach(({ subscriber }) => subscriber()), + subscriberRaw: (...args) => + results.forEach(({ subscriberRaw }) => + subscriberRaw(...args) + ), + }; + } + + createStore(initialState?: unknown, enhancerGenerator?: Function) { + const enhancer = (enhancerGenerator ?? applyMiddleware)( + this.middleware + ); + + const store: { + getState: Function & Record; + dispatch: Function & Record; + selectors: Record; + actions: AggregateDuxActions; + } = reduxCreateStore( + this.reducer as any, + initialState ?? this.initialState, + enhancer + ) as any; + + store.actions = this.actions; + + store.selectors = this.selectors; + + merge( + store.getState, + mapValues(this.selectors, (selector) => { + return (...args) => { + let result = selector(store.getState()); + + if (typeof result === 'function') return result(...args); + + return result; + }; + }) + ); + + for (const action in this.actions) { + store.dispatch[action] = (...args) => { + return store.dispatch(this.actions[action](...(args as any))); + }; + } + + this.subscribeAll(store); + + return store; + } + + effectToMiddleware(effect) { + return effectToMiddleware(effect, this.actions, this.selectors); + } +} diff --git a/src/Updux.test.ts b/src/Updux.test.ts new file mode 100644 index 0000000..4aab369 --- /dev/null +++ b/src/Updux.test.ts @@ -0,0 +1,13 @@ +import { test, expect } from 'vitest'; +import Updux from './Updux.js'; + +test('subdux idempotency', () => { + const foo = new Updux({ + subduxes: { + a: new Updux({ initialState: 2 }), + }, + }); + + let fooState = foo.reducer(undefined, { type: 'noop' }); + expect(foo.reducer(fooState, { type: 'noop' })).toBe(fooState); +}); diff --git a/src/Updux.js b/src/Updux.todo similarity index 94% rename from src/Updux.js rename to src/Updux.todo index d36f395..dd22be2 100644 --- a/src/Updux.js +++ b/src/Updux.todo @@ -35,7 +35,7 @@ export class Updux { this.#middlewareWrapper = config.middlewareWrapper; - this.#localInitial = config.initial; + this.#localInitial = config.initialState; this.#subduxes = config.subduxes ?? {}; this.#actions = R.mapValues(config.actions ?? {}, (arg, name) => @@ -89,7 +89,7 @@ export class Updux { return this.#actions; } - get initial() { + get initialState() { if (Object.keys(this.#subduxes).length === 0) return this.#localInitial ?? {}; @@ -101,7 +101,7 @@ export class Updux { return Object.assign( {}, this.#localInitial ?? {}, - R.mapValues(this.#subduxes, ({ initial }) => initial), + R.mapValues(this.#subduxes, ({ initialState }) => initialState), ); } @@ -167,14 +167,14 @@ export class Updux { ); } - createStore(initial = undefined, enhancerGenerator = undefined) { + createStore(initialState = undefined, enhancerGenerator = undefined) { const enhancer = (enhancerGenerator ?? applyMiddleware)( this.middleware, ); const store = reduxCreateStore( this.reducer, - initial ?? this.initial, + initialState ?? this.initialState, enhancer, ); @@ -247,13 +247,16 @@ export class Updux { return (state, previousState, unsubscribe) => { const gone = { ...cache }; - // TODO assuming object here - for (const key in state) { + const mappedState = Array.isArray(state)? Object.fromEntries( + state.map( s => [ mapper(s), s ] ) + ) : state; + + for (const key in mappedState) { if (cache[key]) { delete gone[key]; } else { const dux = new Updux({ - initial: null, + initialState: null, actions: { update: null }, mutations: { update: (payload) => () => payload, diff --git a/src/Updux.ts b/src/Updux.ts new file mode 100644 index 0000000..baa5a6e --- /dev/null +++ b/src/Updux.ts @@ -0,0 +1,383 @@ +import * as R from 'remeda'; +import { + createStore as reduxCreateStore, + applyMiddleware, + DeepPartial, + Action, + MiddlewareAPI, + AnyAction, + Middleware, + Dispatch, +} from 'redux'; +import { + configureStore, + Reducer, + ActionCreator, + ActionCreatorWithoutPayload, + ActionCreatorWithPreparedPayload, +} from '@reduxjs/toolkit'; +import { AggregateActions, AggregateSelectors, Dux } from './types.js'; +import { buildActions } from './buildActions.js'; +import { buildInitial, AggregateState } from './initial.js'; +import { buildReducer, MutationCase } from './reducer.js'; +import { + augmentGetState, + augmentMiddlewareApi, + buildEffectsMiddleware, + EffectMiddleware, +} from './effects.js'; +import { ToolkitStore } from '@reduxjs/toolkit/dist/configureStore.js'; +import { produce } from 'immer'; + +type MyActionCreator = { type: string } & ((...args: any) => any); + +type XSel = R extends Function ? R : () => R; +type CurriedSelector = S extends (...args: any) => infer R ? XSel : never; + +type CurriedSelectors = { + [key in keyof S]: CurriedSelector; +}; + +type ResolveAction< + ActionType extends string, + ActionArg extends any, +> = ActionArg extends MyActionCreator + ? ActionArg + : ActionArg extends (...args: any) => any + ? ActionCreatorWithPreparedPayload< + Parameters, + ReturnType, + ActionType + > + : ActionCreatorWithoutPayload; + +type ResolveActions< + A extends { + [key: string]: any; + }, +> = { + [ActionType in keyof A]: ActionType extends string + ? ResolveAction + : never; +}; + +type Reaction = ( + api: M, +) => (state: S, previousState: S, unsubscribe: () => void) => any; + +type AugmentedMiddlewareAPI = MiddlewareAPI< + Dispatch, + S +> & { + dispatch: A; + getState: CurriedSelectors; + actions: A; + selectors: SELECTORS; +}; + +export type Mutation = Action, S = any> = ( + payload: A extends { + payload: infer P; + } + ? P + : undefined, + action: A, +) => (state: S) => S | void; + +type SelectorForState = (state: S) => unknown; +type SelectorsForState = { + [key: string]: SelectorForState; +}; + +export default class Updux< + T_LocalState = Record, + T_LocalActions extends { + [actionType: string]: any; + } = {}, + T_Subduxes extends Record = {}, + T_LocalSelectors extends SelectorsForState< + AggregateState + > = {}, +> { + #localInitial: T_LocalState; + #localActions: T_LocalActions; + #localMutations: MutationCase[] = []; + #defaultMutation: Omit; + #subduxes: T_Subduxes; + + #name: string; + + #actions: AggregateActions, T_Subduxes>; + + #initialState: AggregateState; + + #localSelectors: Record< + string, + (state: AggregateState) => any + >; + #selectors: any; + + #localEffects: Middleware[] = []; + + constructor( + config: Partial<{ + initialState: T_LocalState; + actions: T_LocalActions; + subduxes: T_Subduxes; + selectors: T_LocalSelectors; + }>, + ) { + // TODO check that we can't alter the initialState after the fact + this.#localInitial = config.initialState ?? ({} as T_LocalState); + this.#localActions = config.actions ?? ({} as T_LocalActions); + this.#subduxes = config.subduxes ?? ({} as T_Subduxes); + + this.#actions = buildActions(this.#localActions, this.#subduxes); + + this.#initialState = buildInitial(this.#localInitial, this.#subduxes); + this.#localSelectors = config.selectors; + + const basedSelectors = R.mergeAll( + Object.entries(this.#subduxes) + .filter(([slice, { selectors }]) => selectors) + .map(([slice, { selectors }]) => + R.mapValues(selectors, (s) => (state = {}) => { + return s(state?.[slice]); + }), + ), + ); + + this.#selectors = R.merge(basedSelectors, this.#localSelectors); + } + + get actions() { + return this.#actions; + } + + // TODO memoize? + get initialState() { + return this.#initialState; + } + + get effects() { + return [ + ...this.#localEffects, + ...Object.entries(this.#subduxes).flatMap( + ([slice, { effects }]) => { + if (!effects) return []; + return effects.map( + (effect) => (api) => + effect({ + ...api, + getState: () => api.getState()[slice], + }), + ); + }, + ), + ]; + } + + get reactions(): any { + return [ + ...this.#localReactions, + ...Object.entries(this.#subduxes).flatMap( + ([slice, { reactions }]) => + reactions.map( + (r) => (api, unsub) => + r( + { + ...api, + getState: () => api.getState()[slice], + }, + unsub, + ), + ), + ), + ]; + } + + createStore( + options: Partial<{ + initialState: T_LocalState; + }> = {}, + ) { + const preloadedState: any = options.initialState ?? this.initialState; + + const effects = buildEffectsMiddleware( + this.effects, + this.actions, + this.selectors, + ); + + const store = configureStore({ + reducer: this.reducer as Reducer< + AggregateState, + AnyAction + >, + preloadedState, + middleware: [effects], + }); + + const dispatch: any = store.dispatch; + for (const a in this.actions) { + dispatch[a] = (...args) => { + const action = (this.actions as any)[a](...args); + dispatch(action); + return action; + }; + } + + store.getState = augmentGetState(store.getState, this.selectors); + + for (const reaction of this.reactions) { + let unsub; + const r = reaction(store); + + unsub = store.subscribe(() => r(unsub)); + } + + (store as any).actions = this.actions; + (store as any).selectors = this.selectors; + + return store as ToolkitStore> & + AugmentedMiddlewareAPI< + AggregateState, + AggregateActions, T_Subduxes>, + AggregateSelectors< + T_LocalSelectors, + T_Subduxes, + AggregateState + > + >; + } + + get selectors(): AggregateSelectors< + T_LocalSelectors, + T_Subduxes, + AggregateState + > { + return this.#selectors as any; + } + + // TODO memoize this sucker + get reducer() { + return buildReducer( + this.initialState, + this.#localMutations, + this.#defaultMutation, + this.#subduxes, + ) as any as ( + state: undefined | typeof this.initialState, + action: Action, + ) => typeof this.initialState; + } + + // TODO be smarter with the guard? + addMutation>( + matcher: (action: A) => boolean, + mutation: Mutation>, + terminal?: boolean, + ); + addMutation>( + actionCreator: A, + mutation: Mutation< + ReturnType, + AggregateState + >, + terminal?: boolean, + ); + addMutation(matcher, mutation, terminal = false) { + if (typeof matcher === 'function' && matcher.match) { + // matcher, matcher man... + matcher = matcher.match; + } + + const immerMutation = (...args) => produce(mutation(...args)); + + this.#localMutations.push({ + terminal, + matcher, + mutation: immerMutation, + }); + } + + addDefaultMutation( + mutation: Mutation< + Action, + AggregateState + >, + terminal = false, + ) { + this.#defaultMutation = { mutation, terminal }; + } + + addEffect(effect: EffectMiddleware) { + this.#localEffects.push(effect); + } + + get effectsMiddleware() { + return buildEffectsMiddleware( + this.effects, + this.actions, + this.selectors, + ); + } + + #localReactions: any[] = []; + addReaction( + reaction: Reaction< + AggregateState, + AugmentedMiddlewareAPI< + AggregateState, + AggregateActions, T_Subduxes>, + AggregateSelectors< + T_LocalSelectors, + T_Subduxes, + AggregateState + > + > + >, + ) { + let previous: any; + + const memoized = (api: any) => { + api = augmentMiddlewareApi(api, this.actions, this.selectors); + const r = reaction(api); + return (unsub: () => void) => { + const state = api.getState(); + if (state === previous) return; + let p = previous; + previous = state; + r(state, p, unsub); + }; + }; + this.#localReactions.push(memoized); + } + + // internal method REMOVE + subscribeTo(store, subscription) { + const localStore = augmentMiddlewareApi( + { + ...store, + subscribe: (subscriber) => this.subscribeTo(store, subscriber), // TODO not sure + }, + this.actions, + this.selectors, + ); + + const subscriber = subscription(localStore); + + let previous; + let unsub; + + const memoSub = () => { + const state = store.getState(); + if (state === previous) return; + let p = previous; + previous = state; + subscriber(state, p, unsub); + }; + + return store.subscribe(memoSub); + } +} diff --git a/src/actions.js b/src/actions.js deleted file mode 100644 index 51ad508..0000000 --- a/src/actions.js +++ /dev/null @@ -1,26 +0,0 @@ -export function isActionGen(action) { - return typeof action === 'function' && action.type; -} - -export function action(type, payloadFunction, transformer) { - let generator = function (...payloadArg) { - const result = { type }; - - if (payloadFunction) { - result.payload = payloadFunction(...payloadArg); - } else { - if (payloadArg[0] !== undefined) result.payload = payloadArg[0]; - } - - return result; - }; - - if (transformer) { - const orig = generator; - generator = (...args) => transformer(orig(...args), args); - } - - generator.type = type; - - return generator; -} diff --git a/src/actions.test.js b/src/actions.test.js deleted file mode 100644 index eb6e22f..0000000 --- a/src/actions.test.js +++ /dev/null @@ -1,86 +0,0 @@ -import { test, expect } from 'vitest'; - -import { action } from './actions.js'; - -import { Updux } from './Updux.js'; - -test('basic action', () => { - const foo = action('foo', (thing) => ({ thing })); - - expect(foo('bar')).toEqual({ - type: 'foo', - payload: { - thing: 'bar', - }, - }); -}); - -test('Updux config accepts actions', () => { - const foo = new Updux({ - actions: { - one: action('one', (x) => ({ x })), - two: action('two', (x) => x), - }, - }); - - expect(Object.keys(foo.actions)).toHaveLength(2); - - expect(foo.actions.one).toBeTypeOf('function'); - expect(foo.actions.one('potato')).toEqual({ - type: 'one', - payload: { - x: 'potato', - }, - }); -}); - -test('subduxes actions', () => { - const foo = new Updux({ - actions: { - foo: null, - }, - subduxes: { - beta: { - actions: { - bar: null, - }, - }, - }, - }); - - expect(foo.actions).toHaveProperty('foo'); - expect(foo.actions).toHaveProperty('bar'); -}); - -test('throw if double action', () => { - expect( - () => - new Updux({ - actions: { - foo: action('foo'), - }, - subduxes: { - beta: { - actions: { - foo: action('foo'), - }, - }, - }, - }), - ).toThrow(/action 'foo' already defined/); -}); - -test('action definition shortcut', () => { - const foo = new Updux({ - actions: { - foo: null, - bar: (x) => ({ x }), - }, - }); - - expect(foo.actions.foo('hello')).toEqual({ type: 'foo', payload: 'hello' }); - expect(foo.actions.bar('hello')).toEqual({ - type: 'bar', - payload: { x: 'hello' }, - }); -}); diff --git a/src/actions.test.ts b/src/actions.test.ts new file mode 100644 index 0000000..34651d0 --- /dev/null +++ b/src/actions.test.ts @@ -0,0 +1,122 @@ +import Updux, { createAction, withPayload } from './index.js'; + +test('basic action', () => { + const foo = createAction( + 'foo', + withPayload((thing: string) => ({ thing })), + ); + + expect(foo('bar')).toEqual({ + type: 'foo', + payload: { + thing: 'bar', + }, + }); +}); + +test('subduxes actions', () => { + const bar = createAction('bar'); + const baz = createAction('baz'); + + const foo = new Updux({ + actions: { + bar, + }, + subduxes: { + beta: { + actions: { + baz, + }, + }, + // to check if we can deal with empty actions + gamma: {}, + }, + }); + + expect(foo.actions).toHaveProperty('bar'); + expect(foo.actions).toHaveProperty('baz'); + + expect(foo.actions.bar(2)).toHaveProperty('type', 'bar'); + expect(foo.actions.baz()).toHaveProperty('type', 'baz'); +}); + +test('Updux config accepts actions', () => { + const foo = new Updux({ + actions: { + one: createAction( + 'one', + withPayload((x) => ({ x })), + ), + two: createAction( + 'two', + withPayload((x) => x), + ), + }, + }); + + expect(Object.keys(foo.actions)).toHaveLength(2); + + expect(foo.actions.one).toBeTypeOf('function'); + expect(foo.actions.one('potato')).toEqual({ + type: 'one', + payload: { + x: 'potato', + }, + }); +}); + +test('throw if double action', () => { + expect( + () => + new Updux({ + actions: { + foo: createAction('foo'), + }, + subduxes: { + beta: { + actions: { + foo: createAction('foo'), + }, + }, + }, + }), + ).toThrow(/action 'foo' defined both locally and in subdux 'beta'/); + + expect( + () => + new Updux({ + subduxes: { + gamma: { + actions: { + foo: createAction('foo'), + }, + }, + beta: { + actions: { + foo: createAction('foo'), + }, + }, + }, + }), + ).toThrow(/action 'foo' defined both in subduxes 'gamma' and 'beta'/); +}); + +test('action definition shortcut', () => { + const foo = new Updux({ + actions: { + foo: 0, + bar: (x: number) => ({ x }), + baz: createAction('baz', withPayload()), + }, + }); + + expect(foo.actions.foo()).toEqual({ type: 'foo', payload: undefined }); + expect(foo.actions.baz(false)).toEqual({ + type: 'baz', + payload: false, + }); + expect(foo.actions.bar(2)).toEqual({ + type: 'bar', + payload: { x: 2 }, + }); +}); diff --git a/src/actions.ts b/src/actions.ts new file mode 100644 index 0000000..5712b0a --- /dev/null +++ b/src/actions.ts @@ -0,0 +1,29 @@ +import { createAction } from '@reduxjs/toolkit'; + +export { createAction } from '@reduxjs/toolkit'; + +interface WithPayload { +

(): (input: P) => { payload: P }; + (prepare: (...args: A) => P): (...input: A) => { + payload: P; + }; +} + +export const withPayload: WithPayload = ((prepare) => + (...input) => ({ + payload: prepare ? prepare(...input) : input[0], + })) as any; + +const id = (x) => x; +export const createPayloadAction = < + P extends any = any, + T extends string = string, + F extends (...args: any[]) => P = (input: P) => P, +>( + type: T, + prepare?: F, +) => + createAction( + type, + withPayload, Parameters>(prepare ?? (id as any)), + ); diff --git a/src/buildActions.ts b/src/buildActions.ts new file mode 100644 index 0000000..f93ac42 --- /dev/null +++ b/src/buildActions.ts @@ -0,0 +1,45 @@ +import { createAction } from '@reduxjs/toolkit'; +import * as R from 'remeda'; +import { withPayload } from './actions.js'; + +function resolveActions(configActions) { + return R.mapValues(configActions, (prepare, type: string) => { + if (typeof prepare === 'function' && prepare.type) return prepare; + + return createAction(type, withPayload(prepare)); + }); +} + +export function buildActions(localActions, subduxes) { + localActions = resolveActions(localActions); + + let actions: Record = {}; + + for (const slice in subduxes) { + const subdux = subduxes[slice].actions; + + if (!subdux) continue; + + for (const a in subdux) { + if (actions[a] && subduxes[actions[a]].actions[a] !== subdux[a]) { + throw new Error( + `action '${a}' defined both in subduxes '${actions[a]}' and '${slice}'`, + ); + } + actions[a] = slice; + } + } + + for (const a in localActions) { + if (actions[a]) { + throw new Error( + `action '${a}' defined both locally and in subdux '${actions[a]}'`, + ); + } + } + + return R.mergeAll([ + localActions, + ...Object.values(subduxes).map(R.pathOr(['actions'], {})), + ]) as any; +} diff --git a/src/buildInitial.test.ts b/src/buildInitial.test.ts new file mode 100644 index 0000000..8cc1d15 --- /dev/null +++ b/src/buildInitial.test.ts @@ -0,0 +1,21 @@ +import { test, expect } from 'vitest'; +import { buildInitial } from './initial.js'; + +test('basic', () => { + expect( + buildInitial( + { a: 1 }, + { b: { initialState: { c: 2 } }, d: { initialState: 'e' } }, + ), + ).toEqual({ + a: 1, + b: { c: 2 }, + d: 'e', + }); +}); + +test('throw if subduxes and initialState is not an object', () => { + expect(() => { + buildInitial(3, { bar: 'foo' }); + }).toThrow(); +}); diff --git a/src/buildMiddleware/index.js b/src/buildMiddleware/index.js new file mode 100644 index 0000000..4e2d78d --- /dev/null +++ b/src/buildMiddleware/index.js @@ -0,0 +1,70 @@ +import { mapValues, map, get } from 'lodash-es'; +const middlewareFor = (type, middleware) => (api) => (next) => (action) => { + if (type !== '*' && action.type !== type) return next(action); + return middleware(api)(next)(action); +}; +const sliceMw = (slice, mw) => (api) => { + const getSliceState = () => get(api.getState(), slice); + return mw( + Object.assign(Object.assign({}, api), { getState: getSliceState }), + ); +}; + +export const augmentGetState = (getState, selectors) => + Object.assign( + getState, + mapValues(selectors, (selector) => { + return (...args) => { + let result = selector(api.getState()); + if (typeof result === 'function') return result(...args); + return result; + }; + }), + ); + +export function augmentMiddlewareApi(api, actions, selectors) { + const getState = augmentGetState(() => api.getState(), selectors); + const dispatch = (action) => api.dispatch(action); + Object.assign( + dispatch, + mapValues(actions, (action) => { + return (...args) => api.dispatch(action(...args)); + }), + ); + return Object.assign(Object.assign({}, api), { + getState, + dispatch, + actions, + selectors, + }); +} +export const effectToMiddleware = (effect, actions, selectors) => { + let mw = effect; + let action = '*'; + if (Array.isArray(effect)) { + action = effect[0]; + mw = effect[1]; + mw = middlewareFor(action, mw); + } + return (api) => mw(augmentMiddlewareApi(api, actions, selectors)); +}; +const composeMw = (mws) => (api) => (original_next) => + mws.reduceRight((next, mw) => mw(api)(next), original_next); +export function buildMiddleware( + effects = [], + actions = {}, + selectors = {}, + sub = {}, + wrapper = undefined, + dux = undefined, +) { + let inner = map(sub, ({ middleware }, slice) => + slice !== '*' && middleware ? sliceMw(slice, middleware) : undefined, + ).filter((x) => x); + const local = effects.map((effect) => + effectToMiddleware(effect, actions, selectors), + ); + let mws = [...local, ...inner]; + if (wrapper) mws = wrapper(mws, dux); + return composeMw(mws); +} diff --git a/src/buildMiddleware/index.ts.todo b/src/buildMiddleware/index.ts.todo new file mode 100644 index 0000000..e1a2bd1 --- /dev/null +++ b/src/buildMiddleware/index.ts.todo @@ -0,0 +1,85 @@ +import u from 'updeep'; +import { mapValues, map, get } from 'lodash-es'; + +const middlewareFor = (type, middleware) => (api) => (next) => (action) => { + if (type !== '*' && action.type !== type) return next(action); + + return middleware(api)(next)(action); +}; + +const sliceMw = (slice, mw) => (api) => { + const getSliceState = () => get(api.getState(), slice); + return mw({ ...api, getState: getSliceState }); +}; + +export function augmentMiddlewareApi(api, actions, selectors) { + const getState = () => api.getState(); + const dispatch = (action) => api.dispatch(action); + + Object.assign( + getState, + mapValues(selectors, (selector) => { + return (...args) => { + let result = selector(api.getState()); + + if (typeof result === 'function') return result(...args); + + return result; + }; + }), + ); + + Object.assign( + dispatch, + mapValues(actions, (action) => { + return (...args) => api.dispatch(action(...args)); + }), + ); + + return { + ...api, + getState, + dispatch, + actions, + selectors, + }; +} + +export const effectToMiddleware = (effect, actions, selectors) => { + let mw = effect; + let action = '*'; + + if (Array.isArray(effect)) { + action = effect[0]; + mw = effect[1]; + mw = middlewareFor(action, mw); + } + + return (api) => mw(augmentMiddlewareApi(api, actions, selectors)); +}; + +const composeMw = (mws) => (api) => (original_next) => + mws.reduceRight((next, mw) => mw(api)(next), original_next); + +export function buildMiddleware( + effects = [], + actions = {}, + selectors = {}, + sub = {}, + wrapper = undefined, + dux = undefined, +) { + let inner = map(sub, ({ middleware }, slice) => + slice !== '*' && middleware ? sliceMw(slice, middleware) : undefined, + ).filter((x) => x); + + const local = effects.map((effect) => + effectToMiddleware(effect, actions, selectors), + ); + + let mws = [...local, ...inner]; + + if (wrapper) mws = wrapper(mws, dux); + + return composeMw(mws); +} diff --git a/src/buildSelectors/index.js b/src/buildSelectors/index.js new file mode 100644 index 0000000..ff489f7 --- /dev/null +++ b/src/buildSelectors/index.js @@ -0,0 +1,29 @@ +import { map, mapValues, merge } from 'lodash-es'; +export function buildSelectors( + localSelectors, + splatSelector = {}, + subduxes = {}, +) { + const subSelectors = map(subduxes, ({ selectors }, slice) => { + if (!selectors) return {}; + if (slice === '*') return {}; + return mapValues(selectors, (func) => (state) => func(state[slice])); + }); + let splat = {}; + for (const name in splatSelector) { + splat[name] = + (state) => + (...args) => { + const value = splatSelector[name](state)(...args); + const res = () => value; + return merge( + res, + mapValues( + subduxes['*'].selectors, + (selector) => () => selector(value), + ), + ); + }; + } + return merge({}, ...subSelectors, localSelectors, splat); +} diff --git a/src/buildSelectors/index.ts.todo b/src/buildSelectors/index.ts.todo new file mode 100644 index 0000000..2fba5f8 --- /dev/null +++ b/src/buildSelectors/index.ts.todo @@ -0,0 +1,38 @@ +import { map, mapValues, merge } from 'lodash-es'; + +export function buildSelectors( + localSelectors, + splatSelector = {}, + subduxes = {}, +) { + const subSelectors = map(subduxes, ({ selectors }, slice) => { + if (!selectors) return {}; + if (slice === '*') return {}; + + return mapValues( + selectors, + (func: Function) => (state) => func(state[slice]), + ); + }); + + let splat = {}; + + for (const name in splatSelector) { + splat[name] = + (state) => + (...args) => { + const value = splatSelector[name](state)(...args); + + const res = () => value; + return merge( + res, + mapValues( + subduxes['*'].selectors, + (selector) => () => selector(value), + ), + ); + }; + } + + return merge({}, ...subSelectors, localSelectors, splat); +} diff --git a/src/buildUpreducer.js b/src/buildUpreducer.js deleted file mode 100644 index 39672ac..0000000 --- a/src/buildUpreducer.js +++ /dev/null @@ -1,45 +0,0 @@ -import u from 'updeep'; -import { mapValues } from 'lodash-es'; - -export function buildUpreducer( - initial, - mutations, - subduxes = {}, - wrapper = undefined, -) { - const subReducers = - Object.keys(subduxes).length > 0 - ? mapValues(subduxes, ({ upreducer }) => upreducer) - : null; - - const upreducer = (action) => (state) => { - if (!action?.type) - throw new Error('upreducer called with a bad action'); - - let newState = state ?? initial; - - if (subReducers) { - if (subduxes['*']) { - newState = u.updateIn( - '*', - subduxes['*'].upreducer(action), - newState, - ); - } else { - const update = mapValues(subReducers, (upReducer) => - upReducer(action), - ); - - newState = u(update, newState); - } - } - - const a = mutations[action.type] || mutations['+']; - - if (!a) return newState; - - return a(action.payload, action)(newState); - }; - - return wrapper ? wrapper(upreducer) : upreducer; -} diff --git a/src/createStore.test.js b/src/createStore.test.js deleted file mode 100644 index 286de5e..0000000 --- a/src/createStore.test.js +++ /dev/null @@ -1,18 +0,0 @@ -import { test, expect } from 'vitest'; -import { Updux } from './Updux.js'; - -test('basic createStore', async () => { - const foo = new Updux({ - initial: { a: 1 }, - actions: { - a1: null, - }, - }); - - const store = foo.createStore(); - - expect(store.getState).toBeTypeOf('function'); - expect(store.getState()).toEqual({ a: 1 }); - - expect(store.actions.a1).toBeTypeOf('function'); -}); diff --git a/src/dux-selectors.test.js b/src/dux-selectors.test.todo similarity index 92% rename from src/dux-selectors.test.js rename to src/dux-selectors.test.todo index 011b796..c6f659d 100644 --- a/src/dux-selectors.test.js +++ b/src/dux-selectors.test.todo @@ -6,7 +6,7 @@ import { matches } from './utils.js'; test('basic selectors', () => { const foo = dux({ - initial: { + initialState: { x: 1, }, selectors: { @@ -14,7 +14,7 @@ test('basic selectors', () => { }, subduxes: { bar: { - initial: { y: 2 }, + initialState: { y: 2 }, selectors: { getY: ({ y }) => y, }, @@ -27,7 +27,7 @@ test('basic selectors', () => { test('splat selector', async () => { const bar = new Updux({ - initial: { id: 0, label: '' }, + initialState: { id: 0, label: '' }, selectors: { getLabel: R.prop('label'), getLabelAppended: (state) => (suffix) => state.label + ' ' + suffix, @@ -35,7 +35,7 @@ test('splat selector', async () => { }); const foo = new Updux({ - initial: [], + initialState: [], findSelectors: { getBar: (state) => (id) => { return state.find(matches({ id })); diff --git a/src/effects.test.ts b/src/effects.test.ts new file mode 100644 index 0000000..007abb4 --- /dev/null +++ b/src/effects.test.ts @@ -0,0 +1,110 @@ +import { buildEffectsMiddleware } from './effects.js'; +import Updux, { createAction } from './index.js'; + +test('buildEffectsMiddleware', () => { + let seen = 0; + + const mw = buildEffectsMiddleware( + [ + (api) => (next) => (action) => { + seen++; + expect(api).toHaveProperty('getState'); + expect(api.getState).toBeTypeOf('function'); + + expect(api.getState()).toEqual('the state'); + + expect(action).toHaveProperty('type'); + expect(next).toBeTypeOf('function'); + + expect(api).toHaveProperty('actions'); + expect(api.actions.action1()).toHaveProperty('type', 'action1'); + + api.dispatch.action1(); + + expect(api.selectors.getFoo(2)).toBe(2); + expect(api.getState.getFoo()).toBe('the state'); + expect(api.getState.getBar(2)).toBe('the state2'); + + next(action); + }, + ], + { + action1: createAction('action1'), + }, + { + getFoo: (state) => state, + getBar: (state) => (i) => state + i, + }, + ); + + expect(seen).toEqual(0); + const dispatch = vi.fn(); + mw({ getState: () => 'the state', dispatch })(() => {})({ + type: 'noop', + }); + expect(seen).toEqual(1); + expect(dispatch).toHaveBeenCalledWith({ type: 'action1' }); +}); + +test('basic', () => { + const dux = new Updux({ + initialState: { + loaded: true, + }, + actions: { + foo: 0, + }, + }); + + let seen = 0; + dux.addEffect((api) => (next) => (action) => { + seen++; + expect(api).toHaveProperty('getState'); + expect(api.getState()).toHaveProperty('loaded'); + expect(action).toHaveProperty('type'); + expect(next).toBeTypeOf('function'); + next(action); + }); + + const store = dux.createStore(); + + expect(seen).toEqual(0); + + store.dispatch.foo(); + + expect(seen).toEqual(1); +}); + +test('subdux', () => { + const bar = new Updux({ + initialState: 'bar state', + actions: { foo: 0 }, + }); + + let seen = 0; + bar.addEffect((api) => (next) => (action) => { + seen++; + expect(api.getState()).toBe('bar state'); + next(action); + }); + + const dux = new Updux({ + initialState: { + loaded: true, + }, + subduxes: { + bar, + }, + }); + + const store = dux.createStore(); + + expect(seen).toEqual(0); + + store.dispatch.foo(); + + expect(seen).toEqual(1); +}); + +// TODO subdux effects +// TODO allow to subscribe / unsubscribe effects? diff --git a/src/effects.ts b/src/effects.ts new file mode 100644 index 0000000..59cad76 --- /dev/null +++ b/src/effects.ts @@ -0,0 +1,59 @@ +import { AnyAction } from '@reduxjs/toolkit'; +import { MiddlewareAPI } from '@reduxjs/toolkit'; +import { Dispatch } from '@reduxjs/toolkit'; + +export interface EffectMiddleware { + (api: MiddlewareAPI): ( + next: Dispatch, + ) => (action: AnyAction) => any; +} + +const composeMw = (mws) => (api) => (originalNext) => + mws.reduceRight((next, mw) => mw(api)(next), originalNext); + +export const augmentGetState = (originalGetState, selectors) => { + const getState = () => originalGetState(); + for (const s in selectors) { + getState[s] = (...args) => { + let result = selectors[s](originalGetState()); + if (typeof result === 'function') return result(...args); + return result; + }; + } + return getState; +}; + +const augmentDispatch = (originalDispatch, actions) => { + const dispatch = (action) => originalDispatch(action); + + for (const a in actions) { + dispatch[a] = (...args) => dispatch(actions[a](...args)); + } + return dispatch; +}; + +export const augmentMiddlewareApi = (api, actions, selectors) => { + return { + ...api, + getState: augmentGetState(api.getState, selectors), + dispatch: augmentDispatch(api.dispatch, actions), + actions, + selectors, + }; +}; + +export function buildEffectsMiddleware( + effects = [], + actions = {}, + selectors = {}, +) { + return (api) => { + const newApi = augmentMiddlewareApi(api, actions, selectors); + + let mws = effects.map((e) => e(newApi)); + + return (originalNext) => { + return mws.reduceRight((next, mw) => mw(next), originalNext); + }; + }; +} diff --git a/src/index.js b/src/index.todo similarity index 100% rename from src/index.js rename to src/index.todo diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..6e14d5a --- /dev/null +++ b/src/index.ts @@ -0,0 +1,5 @@ +import Updux from './Updux.js'; + +export { withPayload, createAction, createPayloadAction } from './actions.js'; + +export default Updux; diff --git a/src/initial.test.js b/src/initial.test.js deleted file mode 100644 index 0aa2a85..0000000 --- a/src/initial.test.js +++ /dev/null @@ -1,46 +0,0 @@ -import { test, expect } from 'vitest'; - -import { Updux } from './Updux.js'; - -const bar = new Updux({ initial: 123 }); - -const foo = new Updux({ - initial: { root: 'abc' }, - subduxes: { - bar, - }, -}); - -test('single dux', () => { - const foo = new Updux({ - initial: { a: 1 }, - }); - - expect(foo.initial).toEqual({ a: 1 }); -}); - -test('initial value', () => { - expect(foo.initial).toEqual({ - root: 'abc', - bar: 123, - }); -}); - -test('splat initial', async () => { - const bar = new Updux({ - initial: { id: 0 }, - }); - - const foo = new Updux({ - subduxes: { '*': bar }, - }); - - expect(foo.initial).toEqual([]); - - expect( - new Updux({ - initial: 'overriden', - subduxes: { '*': bar }, - }).initial, - ).toEqual('overriden'); -}); diff --git a/src/initial.test.ts b/src/initial.test.ts new file mode 100644 index 0000000..5dc76b2 --- /dev/null +++ b/src/initial.test.ts @@ -0,0 +1,100 @@ +import { expectType } from './tutorial.test.js'; +import Updux from './Updux.js'; + +const bar = new Updux({ initialState: 123 }); + +const foo = new Updux({ + initialState: { root: 'abc' }, + subduxes: { + bar, + }, +}); + +test('default', () => { + const { initialState } = new Updux({}); + + expect(initialState).toBeTypeOf('object'); + expect(initialState).toEqual({}); +}); + +test('number', () => { + const { initialState } = new Updux({ initialState: 3 }); + + expect(initialState).toBeTypeOf('number'); + expect(initialState).toEqual(3); +}); + +test('initialState to createStore', () => { + const initialState = { + a: 1, + b: 2, + }; + + const dux = new Updux({ + initialState, + }); + + expect( + dux.createStore({ initialState: { a: 3, b: 4 } }).getState(), + ).toEqual({ + a: 3, + b: 4, + }); +}); + +test('single dux', () => { + const foo = new Updux({ + initialState: { a: 1 }, + }); + + expect(foo.initialState).toEqual({ a: 1 }); +}); + +// TODO add 'check for no todo eslint rule' +test('initialState value', () => { + expect(foo.initialState).toEqual({ + root: 'abc', + bar: 123, + }); + + expectType<{ + root: string; + bar: number; + }>(foo.initialState); +}); + +test('no initialState', () => { + const dux = new Updux({}); + expectType<{}>(dux.initialState); + expect(dux.initialState).toEqual({}); +}); + +test('no initialState for subdux', () => { + const dux = new Updux({ + subduxes: { + bar: new Updux({}), + baz: new Updux({ initialState: 'potato' }), + }, + }); + expectType<{ bar: {}; baz: string }>(dux.initialState); + expect(dux.initialState).toEqual({ bar: {}, baz: 'potato' }); +}); + +test.todo('splat initialState', async () => { + const bar = new Updux({ + initialState: { id: 0 }, + }); + + const foo = new Updux({ + subduxes: { '*': bar }, + }); + + expect(foo.initialState).toEqual([]); + + expect( + new Updux({ + initialState: 'overriden', + subduxes: { '*': bar }, + }).initialState, + ).toEqual('overriden'); +}); diff --git a/src/initial.ts b/src/initial.ts new file mode 100644 index 0000000..91aa451 --- /dev/null +++ b/src/initial.ts @@ -0,0 +1,26 @@ +import u from '@yanick/updeep-remeda'; +import * as R from 'remeda'; + +type SubduxState = 'initialState' extends keyof S ? S['initialState'] : {}; + +export type AggregateState> = LOCAL & + (keyof SUBDUXES extends never + ? {} + : { + [Slice in keyof SUBDUXES]: Slice extends string + ? SubduxState + : never; + }); + +export function buildInitial(localInitial, subduxes) { + if (Object.keys(subduxes).length > 0 && typeof localInitial !== 'object') { + throw new Error( + "can't have subduxes when the initialState value is not an object", + ); + } + + return u( + localInitial, + R.mapValues(subduxes, R.pathOr(['initialState'], {})), + ); +} diff --git a/src/middleware.test.js b/src/middleware.test.js deleted file mode 100644 index 8e11cfa..0000000 --- a/src/middleware.test.js +++ /dev/null @@ -1,48 +0,0 @@ -import { test, expect, vi } from 'vitest'; - -import { buildMiddleware } from './middleware.js'; -import { action } from './actions.js'; - -test('buildMiddleware, effects', async () => { - const effectMock = vi.fn(); - - const mw = buildMiddleware([ - ['*', (api) => (next) => (action) => effectMock()], - ]); - - mw({})(() => {})({}); - - expect(effectMock).toHaveBeenCalledOnce(); -}); - -test('buildMiddleware, augmented api', async () => { - const myAction = action('myAction'); - - const mw = buildMiddleware( - [ - [ - '*', - (api) => (next) => (action) => { - expect(api.getState.mySelector()).toEqual(13); - api.dispatch(myAction()); - next(); - }, - ], - ], - { - myAction, - }, - { - mySelector: (state) => state?.selected, - }, - ); - - const dispatch = vi.fn(); - const getState = vi.fn(() => ({ selected: 13 })); - const next = vi.fn(); - - mw({ dispatch, getState })(next)(myAction()); - - expect(next).toHaveBeenCalledOnce(); - expect(dispatch).toHaveBeenCalledWith(myAction()); -}); diff --git a/src/middleware.js b/src/middleware.todo similarity index 100% rename from src/middleware.js rename to src/middleware.todo diff --git a/src/mutations.test.js b/src/mutations.test.js deleted file mode 100644 index da6fb13..0000000 --- a/src/mutations.test.js +++ /dev/null @@ -1,90 +0,0 @@ -import { test, expect } from 'vitest'; -import schema from 'json-schema-shorthand'; -import u from 'updeep'; - -import { action } from './actions.js'; - -import { Updux, dux } from './Updux.js'; - -test('set a mutation', () => { - const dux = new Updux({ - initial: { - x: 'potato', - }, - actions: { - foo: action('foo', (x) => ({ x })), - bar: action('bar'), - }, - }); - - dux.setMutation(dux.actions.foo, (payload, action) => { - expect(payload).toEqual({ x: 'hello ' }); - expect(action).toEqual(dux.actions.foo('hello ')); - return u({ - x: payload.x + action.type, - }); - }); - - const result = dux.reducer(undefined, dux.actions.foo('hello ')); - expect(result).toEqual({ - x: 'hello foo', - }); -}); - -test('mutation of a subdux', async () => { - const bar = dux({ - actions: { - baz: null, - }, - }); - bar.setMutation('baz', () => (state) => ({ ...state, x: 1 })); - - const foo = dux({ - subduxes: { bar }, - }); - - const store = foo.createStore(); - store.dispatch.baz(); - expect(store.getState()).toMatchObject({ bar: { x: 1 } }); -}); - -test('strings and generators', async () => { - const actionA = action('a'); - - const foo = dux({ - actions: { - b: null, - a: actionA, - }, - }); - - // as a string and defined - expect(() => foo.setMutation('a', () => {})).not.toThrow(); - - // as a generator and defined - expect(() => foo.setMutation(actionA, () => {})).not.toThrow(); - - // as a string, not defined - expect(() => foo.setMutation('c', () => {})).toThrow(); - - foo.setMutation(action('d'), () => {}); - - expect(foo.actions.d).toBeTypeOf('function'); -}); - -test('splat mutation', () => { - const myDux = new Updux({ - initial: [], - actions: { one: null, two: null }, - mutations: { - '*': (payload) => (state) => payload ? [...state, payload] : state, - }, - }); - const store = myDux.createStore(); - expect(store.getState()).toEqual([]); - - store.dispatch.one(11); - store.dispatch.two(22); - - expect(store.getState()).toEqual([11, 22]); -}); diff --git a/src/mutations.test.ts b/src/mutations.test.ts new file mode 100644 index 0000000..73ae207 --- /dev/null +++ b/src/mutations.test.ts @@ -0,0 +1,80 @@ +import { test, expect } from 'vitest'; + +import Updux, { createAction } from './index.js'; + +test('set a mutation', () => { + const dux = new Updux({ + initialState: 'potato', + actions: { + foo: (x) => ({ x }), + bar: 0, + }, + }); + + let didIt = false; + + dux.addMutation(dux.actions.foo, (payload, action) => () => { + didIt = true; + expect(payload).toEqual({ x: 'hello ' }); + expect(action).toEqual(dux.actions.foo('hello ')); + return payload.x + action.type; + }); + + const result = dux.reducer(undefined, dux.actions.foo('hello ')); + expect(didIt).toBeTruthy(); + expect(result).toEqual('hello foo'); +}); + +test('catch-all mutation', () => { + const dux = new Updux({ + initialState: '', + }); + + dux.addMutation( + () => true, + (payload, action) => () => 'got it', + ); + + expect(dux.reducer(undefined, { type: 'foo' })).toEqual('got it'); +}); + +test('default mutation', () => { + const dux = new Updux({ + initialState: '', + actions: { + foo: 0, + }, + }); + + dux.addMutation(dux.actions.foo, () => () => 'got it'); + + dux.addDefaultMutation((_payload, action) => () => action.type); + + expect(dux.reducer(undefined, { type: 'foo' })).toEqual('got it'); + expect(dux.reducer(undefined, { type: 'bar' })).toEqual('bar'); +}); + +test('mutation of a subdux', () => { + const baz = createAction('baz'); + const noop = createAction('noop'); + const stopit = createAction('stopit'); + + const bar = new Updux({ + initialState: 0, + actions: { + baz, + stopit, + }, + }); + bar.addMutation(baz, () => () => 1); + bar.addMutation(stopit, () => () => 2); + + const foo = new Updux({ + subduxes: { bar }, + }); + foo.addMutation(stopit, () => (state) => state, true); + + expect(foo.reducer(undefined, noop())).toHaveProperty('bar', 0); + expect(foo.reducer(undefined, baz())).toHaveProperty('bar', 1); + expect(foo.reducer(undefined, stopit())).toHaveProperty('bar', 0); +}); diff --git a/src/reactions.test.js b/src/reactions.test.js deleted file mode 100644 index 8b17efb..0000000 --- a/src/reactions.test.js +++ /dev/null @@ -1,50 +0,0 @@ -import { test, expect, vi } from 'vitest'; - -import { Updux } from './Updux.js'; - -test('basic reactions', async () => { - const spyA = vi.fn(); - const spyB = vi.fn(); - const foo = new Updux({ - initial: { i: 0 }, - reactions: [() => spyA], - actions: { inc: null }, - mutations: { - inc: () => (state) => ({ ...state, i: state.i + 1 }), - }, - }); - - foo.addReaction((api) => spyB); - - const store = foo.createStore(); - store.dispatch.inc(); - - expect(spyA).toHaveBeenCalledOnce(); - expect(spyB).toHaveBeenCalledOnce(); -}); - -test('subduxes reactions', async () => { - const spyA = vi.fn(); - const spyB = vi.fn(); - const foo = new Updux({ - subduxes: { - a: new Updux({ - initial: 1, - reactions: [() => (state) => spyA(state)], - actions: { inc: null }, - mutations: { - inc: () => (state) => state + 1, - }, - }), - b: new Updux({ initial: 10, reactions: [() => spyB] }), - }, - }); - - const store = foo.createStore(); - store.dispatch.inc(); - store.dispatch.inc(); - - expect(spyA).toHaveBeenCalledTimes(2); - expect(spyA).toHaveBeenCalledWith(3); - expect(spyB).toHaveBeenCalledOnce(); // the original inc initialized the state -}); diff --git a/src/reactions.test.ts b/src/reactions.test.ts new file mode 100644 index 0000000..b807f8a --- /dev/null +++ b/src/reactions.test.ts @@ -0,0 +1,82 @@ +import { test, expect, vi } from 'vitest'; +import Updux from './index.js'; + +test('basic reactions', () => { + const foo = new Updux({ + initialState: 0, + actions: { inc: 0, reset: 0 }, + }); + + // TODO immer that stuff + foo.addMutation(foo.actions.inc, () => (state) => state + 1); + foo.addMutation(foo.actions.reset, () => (state) => 0); + + foo.addReaction((api) => (state, _previous, unsubscribe) => { + if (state < 3) return; + unsubscribe(); + api.dispatch.reset(); + }); + + // TODO + //reaction: (api) => (state,previous,unsubscribe) + + const store = foo.createStore(); + + store.dispatch.inc(); + expect(store.getState()).toEqual(1); + store.dispatch.inc(); + store.dispatch.inc(); + + expect(store.getState()).toEqual(0); // we've been reset + + store.dispatch.inc(); + store.dispatch.inc(); + store.dispatch.inc(); + store.dispatch.inc(); + + expect(store.getState()).toEqual(4); // we've unsubscribed +}); + +test('subdux reactions', () => { + const bar = new Updux({ + initialState: 0, + actions: { inc: 0, reset: 0 }, + selectors: { + getIt: (x) => x, + }, + }); + + const foo = new Updux({ actions: { notInBar: 0 }, subduxes: { bar } }); + + // TODO immer that stuff + bar.addMutation(foo.actions.inc, () => (state) => state + 1); + bar.addMutation(foo.actions.reset, () => (state) => 0); + + let seen = 0; + bar.addReaction((api) => (state, _previous, unsubscribe) => { + seen++; + expect(api.actions).not.toHaveProperty('notInBar'); + expect(state).toBeTypeOf('number'); + if (state < 3) return; + unsubscribe(); + api.dispatch.reset(); + }); + + const store = foo.createStore(); + + store.dispatch.inc(); + expect(seen).toEqual(1); + expect(store.getState()).toEqual({ bar: 1 }); + expect(store.getState.getIt()).toEqual(1); + store.dispatch.inc(); + store.dispatch.inc(); + + expect(store.getState.getIt()).toEqual(0); // we've been reset + + store.dispatch.inc(); + store.dispatch.inc(); + store.dispatch.inc(); + store.dispatch.inc(); + + expect(store.getState.getIt()).toEqual(4); // we've unsubscribed +}); diff --git a/src/reducer.test.js b/src/reducer.test.js deleted file mode 100644 index 2b5ff18..0000000 --- a/src/reducer.test.js +++ /dev/null @@ -1,19 +0,0 @@ -import { test, expect } from 'vitest'; - -import { Updux } from './Updux.js'; - -test('basic reducer', () => { - const dux = new Updux({ initial: { a: 3 } }); - - expect(dux.reducer).toBeTypeOf('function'); - - expect(dux.reducer({ a: 1 }, { type: 'foo' })).toMatchObject({ a: 1 }); // noop -}); - -test('basic upreducer', () => { - const dux = new Updux({ initial: { a: 3 } }); - - expect(dux.upreducer).toBeTypeOf('function'); - - expect(dux.upreducer({ type: 'foo' })({ a: 1 })).toMatchObject({ a: 1 }); // noop -}); diff --git a/src/reducer.test.ts b/src/reducer.test.ts new file mode 100644 index 0000000..7e7b36c --- /dev/null +++ b/src/reducer.test.ts @@ -0,0 +1,31 @@ +import { test, expect } from 'vitest'; + +import { buildReducer } from './reducer.js'; +import Updux from './Updux.js'; + +test('buildReducer, initialState state', () => { + const reducer = buildReducer({ a: 1 }); + + expect(reducer(undefined, { type: 'foo' })).toEqual({ a: 1 }); +}); + +test('buildReducer, mutation', () => { + const reducer = buildReducer(1, [ + { + matcher: ({ type }) => type === 'inc', + mutation: () => (state) => state + 1, + terminal: false, + }, + ]); + + expect(reducer(undefined, { type: 'foo' })).toEqual(1); + expect(reducer(undefined, { type: 'inc' })).toEqual(2); +}); + +test.todo('basic reducer', () => { + const dux = new Updux({ initialState: { a: 3 } }); + + expect(dux.reducer).toBeTypeOf('function'); + + expect(dux.reducer({ a: 1 }, { type: 'foo' })).toMatchObject({ a: 1 }); // noop +}); diff --git a/src/reducer.ts b/src/reducer.ts new file mode 100644 index 0000000..c592d86 --- /dev/null +++ b/src/reducer.ts @@ -0,0 +1,95 @@ +import { Action, ActionCreator, createAction } from '@reduxjs/toolkit'; +import { BaseActionCreator } from '@reduxjs/toolkit/dist/createAction.js'; +import * as R from 'remeda'; +import { Dux } from './types.js'; +import { Mutation } from './Updux.js'; +import u from '@yanick/updeep-remeda'; +import { produce } from 'immer'; + +export type MutationCase = { + matcher: (action: Action) => boolean; + mutation: Mutation; + terminal: boolean; +}; + +export function buildReducer( + initialStateState: any, + mutations: MutationCase[] = [], + defaultMutation?: Omit, + subduxes: Record = {}, +) { + const subReducers = R.mapValues(subduxes, R.prop('reducer')); + + // TODO matcherMutation + // TODO defaultMutation + // + const reducer = (state = initialStateState, action: Action) => { + const orig = state; + if (!action?.type) + throw new Error('upreducer called with a bad action'); + + let terminal = false; + let didSomething = false; + + mutations + .filter(({ matcher }) => matcher(action)) + .forEach(({ mutation, terminal: t }) => { + if (t) terminal = true; + didSomething = true; + state = produce( + state, + mutation((action as any).payload, action), + ); + }); + + if (!didSomething && defaultMutation) { + if (defaultMutation.terminal) terminal = true; + + state = defaultMutation.mutation( + (action as any).payload, + action, + )(state); + } + + if (!terminal && Object.keys(subduxes).length > 0) { + // subduxes + state = u.update( + state, + R.mapValues(subReducers, (reducer, slice) => + (reducer as any)(state[slice], action), + ), + ); + } + + return state; + }; + + return reducer; + + /* + if (subReducers) { + if (subduxes['*']) { + newState = u.updateIn( + '*', + subduxes['*'].upreducer(action), + newState, + ); + } else { + const update = mapValues(subReducers, (upReducer) => + upReducer(action), + ); + + newState = u(update, newState); + } + } + + const a = mutations[action.type] || mutations['+']; + + if (!a) return newState; + + return a(action.payload, action)(newState); + }; + + return wrapper ? wrapper(upreducer) : upreducer; + */ +} diff --git a/src/selectors.js b/src/selectors.js deleted file mode 100644 index e90b4e9..0000000 --- a/src/selectors.js +++ /dev/null @@ -1,43 +0,0 @@ -import R from 'remeda'; - -export function buildSelectors( - localSelectors, - findSelectors = {}, - subduxes = {}, -) { - const subSelectors = Object.entries(subduxes).map( - ([slice, { selectors }]) => { - if (!selectors) return {}; - if (slice === '*') return {}; - - return R.mapValues( - selectors, - (func) => (state) => func(state[slice]), - ); - }, - ); - - let splat = {}; - - for (const name in findSelectors) { - splat[name] = - (mainState) => - (...args) => { - const state = findSelectors[name](mainState)(...args); - - return R.merge( - { state }, - R.mapValues( - subduxes['*']?.selectors ?? {}, - (selector) => - (...args) => { - let value = selector(state); - if (typeof value !== 'function') return value; - return value(...args); - }, - ), - ); - }; - } - return R.mergeAll([...subSelectors, localSelectors, splat]); -} diff --git a/src/selectors.test.ts b/src/selectors.test.ts new file mode 100644 index 0000000..f637c88 --- /dev/null +++ b/src/selectors.test.ts @@ -0,0 +1,42 @@ +import { test, expect } from 'vitest'; + +import Updux, { createAction } from './index.js'; + +test('basic selectors', () => { + type State = { x: number }; + + const foo = new Updux({ + initialState: { + x: 1, + }, + selectors: { + getX: ({ x }: State) => x, + }, + subduxes: { + bar: new Updux({ + initialState: { y: 2 }, + selectors: { + getY: ({ y }: { y: number }) => y, + getYPlus: + ({ y }) => + (incr: number) => + (y + incr) as number, + }, + }), + }, + }); + + const sample = { + x: 4, + bar: { y: 3 }, + }; + + expect(foo.selectors.getY(sample)).toBe(3); + expect(foo.selectors.getX(sample)).toBe(4); + + expect(foo.selectors.getYPlus(sample)(3)).toBe(6); + + const store = foo.createStore(); + expect(store.getState.getY()).toBe(2); + expect(store.getState.getYPlus(3)).toBe(5); +}); diff --git a/src/splatReactions.test.js b/src/splatReactions.test.todo similarity index 97% rename from src/splatReactions.test.js rename to src/splatReactions.test.todo index 7fbe918..11da9a1 100644 --- a/src/splatReactions.test.js +++ b/src/splatReactions.test.todo @@ -9,7 +9,7 @@ const thingReactionSnitch = vi.fn(); const subThing = new Updux({ name: 'subThing', - initial: 0, + initialState: 0, }); subThing.addReaction((api) => (state, previousState, unsubscribe) => { @@ -18,7 +18,7 @@ subThing.addReaction((api) => (state, previousState, unsubscribe) => { const thing = new Updux({ name: 'thing', - initial: {}, + initialState: {}, subduxes: { '*': subThing, }, @@ -41,11 +41,11 @@ const things = new Updux({ subduxes: { '*': thing, }, - initial: {}, + initialState: {}, actions: { newThing: (id) => id }, splatReactionMapper: ({ id }) => id, mutations: { - newThing: (id) => (state) => ({ ...state, [id]: thing.initial }), + newThing: (id) => (state) => ({ ...state, [id]: thing.initialState }), }, }); diff --git a/src/tutorial.test.ts b/src/tutorial.test.ts new file mode 100644 index 0000000..67c5c48 --- /dev/null +++ b/src/tutorial.test.ts @@ -0,0 +1,61 @@ +import Updux, { createAction, withPayload } from './index.js'; +import u from '@yanick/updeep-remeda'; + +export const expectType = (value: T) => value; + +test('initialState state', () => { + const initialState = { + next_id: 1, + todos: [], + }; + const dux = new Updux({ + initialState, + }); + + expectType<{ + next_id: number; + todos: unknown[]; + }>(dux.initialState); + + expect(dux.initialState).toEqual(initialState); + + const store = dux.createStore(); + + expect(store.getState()).toEqual(initialState); +}); + +test('actions', () => { + const addTodo = createAction('addTodo', withPayload()); + const todoDone = createAction('todoDone'); + + const todosDux = new Updux({ + actions: { + addTodo, + todoDone, + }, + }); + + expect(todosDux.actions.addTodo('write tutorial')).toEqual({ + type: 'addTodo', + payload: 'write tutorial', + }); +}); + +test('mutation', () => { + const addTodo = createAction('addTodo', withPayload()); + + type Todo = { + description: string; + id: number; + done: boolean; + }; + + const dux = new Updux({ + initialState: { nextId: 0, todos: [] as Todo[] }, + }); + + dux.addMutation(addTodo, (description) => (state) => { + state.todos.unshift({ description, id: state.nextId, done: false }); + state.nextId++; + }); +}); diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..87f93a2 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,46 @@ +import { Action, ActionCreator, Middleware, Reducer } from 'redux'; + +export type Dux< + STATE = any, + ACTIONS extends Record> = {}, +> = Partial<{ + initialState: STATE; + actions: ACTIONS; + selectors: Record any>; + reducer: ( + state: STATE, + action: ReturnType, + ) => STATE; + effects: Middleware[]; + reactions: ((...args: any[]) => void)[]; +}>; + +type ActionsOf = DUX extends { actions: infer A } ? A : {}; +type SelectorsOf = DUX extends { selectors: infer A } ? A : {}; + +export type AggregateActions = UnionToIntersection< + ActionsOf | A +>; + +type BaseSelector any, STATE> = ( + state: STATE, +) => ReturnType; + +type BaseSelectors, STATE> = { + [key in keyof S]: BaseSelector; +}; + +export type AggregateSelectors< + S extends Record any>, + SUBS extends Record, + STATE = {}, +> = BaseSelectors< + UnionToIntersection | S>, + STATE +>; + +export type UnionToIntersection = ( + U extends any ? (k: U) => void : never +) extends (k: infer I) => void + ? I + : never; diff --git a/src/upreducer.js b/src/upreducer.todo similarity index 100% rename from src/upreducer.js rename to src/upreducer.todo diff --git a/src/utils.js b/src/utils.js deleted file mode 100644 index 956a5ff..0000000 --- a/src/utils.js +++ /dev/null @@ -1,6 +0,0 @@ -export const matches = (conditions) => (target) => - Object.entries(conditions).every(([key, value]) => - typeof value === 'function' - ? value(target[key]) - : target[key] === value, - ); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..4baa5e4 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,105 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "nodenext" /* Specify what module code is generated. */, + "rootDir": "./src" /* Specify the root folder within your source files. */, + "moduleResolution": "nodenext" /* Specify how TypeScript looks up a file from a given module specifier. */, + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + "types": [ + "vitest/globals" + ] /* Specify type package names to be included without being referenced in a source file. */, + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + "outDir": "./dist" /* Specify an output folder for all emitted files. */, + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, + + /* Type Checking */ + "strict": false /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} diff --git a/vitest.config.js b/vitest.config.js new file mode 100644 index 0000000..1c015a0 --- /dev/null +++ b/vitest.config.js @@ -0,0 +1,8 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + globals: true, + isolate: false, + }, +});