├── .eslintrc.js ├── .gitattributes ├── .github └── workflows │ ├── CI.yml │ └── Docs.yml ├── .gitignore ├── .npmignore ├── .prettierrc.js ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── examples └── todomvc │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── .npmrc │ ├── .prettierignore │ ├── .prettierrc │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── src │ ├── app.html │ ├── global.d.ts │ └── routes │ │ └── index.svelte │ ├── static │ └── favicon.ico │ ├── svelte.config.cjs │ └── tsconfig.json ├── package-lock.json ├── package.json ├── rollup.config.js ├── scripts └── move-type-declarations.js ├── src ├── entity-store.ts ├── index.ts ├── internal │ ├── get-entities.ts │ ├── normalize.ts │ ├── remove-entities.ts │ ├── set-entities.ts │ └── update-entities.ts └── shared.ts ├── tests ├── entity-store.ts ├── index.ts └── internal │ ├── get-entities.ts │ ├── normalize.ts │ ├── remove-entities.ts │ ├── set-entities.ts │ └── update-entities.ts ├── tsconfig.json └── typedoc.json /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: '@typescript-eslint/parser', 4 | plugins: ['@typescript-eslint'], 5 | extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'], 6 | } 7 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf -------------------------------------------------------------------------------- /.github/workflows/CI.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | paths-ignore: 6 | - 'docs/**' 7 | - 'bench/**' 8 | - 'examples/**' 9 | - 'shots/**' 10 | branches: 11 | - main 12 | pull_request: 13 | paths-ignore: 14 | - 'docs/**' 15 | - 'bench/**' 16 | - 'examples/**' 17 | - 'shots/**' 18 | branches: 19 | - main 20 | 21 | jobs: 22 | test: 23 | name: Node.js v${{ matrix.nodejs }} (${{ matrix.os }}) 24 | runs-on: ${{ matrix.os }} 25 | timeout-minutes: 3 26 | strategy: 27 | matrix: 28 | nodejs: [10, 12, 14] 29 | os: [ubuntu-latest, windows-latest] 30 | steps: 31 | - uses: actions/checkout@v2 32 | # https://github.com/actions/setup-node 33 | - uses: actions/setup-node@v2-beta 34 | with: 35 | node-version: ${{ matrix.nodejs }} 36 | 37 | - name: Install 38 | run: npm install 39 | 40 | - name: Lint 41 | run: npm run lint 42 | 43 | - name: Test w/ Coverage 44 | run: npm run test:coverage 45 | 46 | - name: Report 47 | if: matrix.nodejs >= 14 && matrix.os == 'ubuntu-latest' 48 | run: | 49 | npm run test:report 50 | bash <(curl -s https://codecov.io/bash) 51 | env: 52 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} -------------------------------------------------------------------------------- /.github/workflows/Docs.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Docs 2 | on: 3 | workflow_run: 4 | workflows: [CI] 5 | branches: [main] 6 | types: [completed] 7 | jobs: 8 | build-and-deploy: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout 🛎️ 12 | uses: actions/checkout@v2.3.1 13 | 14 | - name: Install and Build 🔧 # This example project is built using npm and outputs the result to the 'build' folder. Replace with the commands required to build your project, or remove this step entirely if your site is pre-built. 15 | run: | 16 | npm install 17 | npm run doc 18 | 19 | - name: Deploy 🚀 20 | uses: JamesIves/github-pages-deploy-action@4.1.1 21 | with: 22 | branch: gh-pages # The branch the action should deploy to. 23 | folder: docs # The folder the action should deploy. -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | /build/ 3 | /lib/ 4 | /dist/ 5 | /dist-*/ 6 | /docs/ 7 | /tmp/ 8 | /mnt/ 9 | /package/ 10 | .idea/* 11 | 12 | /coverage 13 | /coverage.* 14 | *.log 15 | 16 | package-lock.json 17 | /*.tgz 18 | /tmp* 19 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /.github/ 2 | /.vscode/ 3 | /node_modules/ 4 | /build/ 5 | /tmp/ 6 | .idea/* 7 | /docs/ 8 | 9 | /coverage 10 | /coverage.* 11 | *.log 12 | 13 | package-lock.json 14 | /*.tgz 15 | /tmp* 16 | /mnt/ 17 | /package/ -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | semi: false, 3 | trailingComma: "all", 4 | singleQuote: true, 5 | printWidth: 120, 6 | tabWidth: 4 7 | }; -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.codeActionsOnSave": { 3 | "source.fixAll.eslint": true 4 | }, 5 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Tony Sullivan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | version 4 | 5 | 6 | CI 7 | 8 | 9 | codecov 10 | 11 |
12 | 13 | # Svelte Entity Store 14 | 15 | A (**w**ork-**i**n-**p**rogress) generic entity store for Svelte projects. 16 | 17 | Check out the [full docs](https://tony-sull.github.io/svelte-entity-store/) for details. 18 | 19 | ## Why? 20 | 21 | This is ultimately just a [custom store](https://svelte.dev/examples#custom-stores) built on top of [svelte/store](https://svelte.dev/docs#svelte_store). Like the rest of Svelte, the built in stores are excellent building blocks that aim to give you all the tools you need without trying to solve every single scenario out of the box. 22 | 23 | The goal with `svelte-entity-store` is to provide a simple, generic solution for storing collections of entity objects. Throwing an array of items into a basic `writeble` store doesn't scale well if you have a lot of items and need to quickly find or update one item in the store. 24 | 25 | ## Install 26 | 27 | ``` 28 | npm i -s svelte-entity-store 29 | ``` 30 | 31 | ## Usage 32 | 33 | > Check out ['/examples'](/examples) for a working TodoMVC demo based on SvelteKit. More to come! 34 | 35 | ```ts 36 | 68 | 69 | {#each $activeTodos as todo (todo.id) } 70 | // ... render your UI as usual 71 | {/each} 72 | ``` 73 | 74 | ## API 75 | 76 | ### entityStore.get 77 | 78 | Gets a [derived store](https://svelte.dev/docs#derived) to subscribe to one or more entity in the store. 79 | 80 | Be careful with how many derived stores you create. It's best to use `entityStore.get` at the page or view level and pass state down to *dumb* components. 81 | 82 | i.e. If the TodoMVC app has 10,000 todos in it and each list item is a separate component calling `entityStore.get(id)` the performance and memory use will be a nightmare. Just don't do it. You've been warned! 83 | 84 | #### get() 85 | 86 | Gets an array with every entity in the store. 87 | 88 | #### get(id: ID) 89 | 90 | Gets the entity by ID, or undefined if it isn't found. 91 | 92 | #### get(ids: ID[]) 93 | 94 | Gets an array of specific entities by ID. IDs will be ignored if they aren't found in the store - the array of entities returned may not be the same length as the `ids` array provided. 95 | 96 | #### get(pred: Predicate) 97 | 98 | Gets every entity that matches the predicate - the equivalent of `Array.prototype.filter()` 99 | 100 | ### entityStore.remove 101 | 102 | Removes one or more entities from the store. 103 | 104 | #### remove(id: ID) 105 | 106 | Removes a specific entity by ID, if it exists 107 | 108 | #### remove(ids: ID[]) 109 | 110 | Removes one or more entity by ID 111 | 112 | #### remove(pred: Predicate) 113 | 114 | Removes every entity that matches the predicate. Note that this removes an entity if the predicate returns **true**! 115 | 116 | ### reset 117 | 118 | Removes all entities, resetting the entity store to it's original default state 119 | 120 | ### entityStore.set 121 | 122 | Adds or replaces entities in the store. Note that `set` will override any old state of an entity if it already existed in the store. Use `entityStore.update` if you want to modify the entity instead. 123 | 124 | #### set(entity: T) 125 | 126 | Adds entity to the store, or replaces the old state if it already exists. 127 | 128 | #### set(entities: T[]) 129 | 130 | Works just like `set(entity: T)`, but for each item in the array. This is useful when you ened to update more than one entity and don't want to trigger subscribers until all entities are added. 131 | 132 | ### entityStore.subscribe 133 | 134 | The `subscribe` method for the entire store, see [Svelte's docs](https://svelte.dev/docs#svelte_store) for more details on the subscribe API. 135 | 136 | You really shouldn't need to use this subscribe method unless you're tying the entire store into `devtools` or logging. 137 | 138 | ### entityStore.update 139 | 140 | Updates one or more entity in the store. 141 | 142 | This follows the same basic design as [writable stores](https://svelte.dev/examples#writable-stores) - rather than providing the new entity state you give a callback function that will be given the old entity and returns the new, updated entity. 143 | 144 | #### update(updater: (entity:T ) => T) 145 | 146 | Runs every entity in the store through the `updater` callback. Check out the ('/examples/todomvc')[/examples/todomvc] project, this is used for the "toggle all todos" feature. 147 | 148 | #### update(updater: (entity: T) => T, id: ID) 149 | 150 | Runs a specific entity through the updater callback. `updater` will never be called if the entity isn't found in the store. 151 | 152 | #### update(updater: (entity: T) => T, ids: ID[]) 153 | 154 | Runs multiple entities through the updater function. This is useful when you ened to update more than one entity and don't want to trigger subscribers until all entities are updated. 155 | 156 | #### update(updater: (entity: T) => T, entity: T) 157 | 158 | Convenience override in case your code is already using the entire entity, avoids having to do something like `update(toggle, todo.id)`. 159 | 160 | #### update(updater: (entity: T) => T, entities: T[]) 161 | 162 | Works just like `update(updater, entities: T[])`, but for each item in the array. This is useful when you ened to update more than one entity and don't want to trigger subscribers until all entities are added. 163 | 164 | #### update(updater: (entity: T) => T, pred: Predicate) 165 | 166 | Runs every entity that matches the predicate through the `updater` callback. The predicate works just like `Array.prototype.filter`, every entity is run through the predicate and if it returns **true** the entity is updated. 167 | -------------------------------------------------------------------------------- /examples/todomvc/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: '@typescript-eslint/parser', 4 | extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'], 5 | plugins: ['svelte3', '@typescript-eslint'], 6 | ignorePatterns: ['*.cjs'], 7 | overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }], 8 | settings: { 9 | 'svelte3/typescript': () => require('typescript') 10 | }, 11 | parserOptions: { 12 | sourceType: 'module', 13 | ecmaVersion: 2019 14 | }, 15 | env: { 16 | browser: true, 17 | es2017: true, 18 | node: true 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /examples/todomvc/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /.svelte 4 | /build 5 | /functions 6 | -------------------------------------------------------------------------------- /examples/todomvc/.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /examples/todomvc/.prettierignore: -------------------------------------------------------------------------------- 1 | .svelte/** 2 | static/** 3 | build/** 4 | node_modules/** 5 | -------------------------------------------------------------------------------- /examples/todomvc/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": true, 3 | "singleQuote": true, 4 | "trailingComma": "none", 5 | "printWidth": 100 6 | } 7 | -------------------------------------------------------------------------------- /examples/todomvc/README.md: -------------------------------------------------------------------------------- 1 | # create-svelte 2 | 3 | Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte); 4 | 5 | ## Creating a project 6 | 7 | If you're seeing this, you've probably already done this step. Congrats! 8 | 9 | ```bash 10 | # create a new project in the current directory 11 | npm init svelte@next 12 | 13 | # create a new project in my-app 14 | npm init svelte@next my-app 15 | ``` 16 | 17 | > Note: the `@next` is temporary 18 | 19 | ## Developing 20 | 21 | Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server: 22 | 23 | ```bash 24 | npm run dev 25 | 26 | # or start the server and open the app in a new browser tab 27 | npm run dev -- --open 28 | ``` 29 | 30 | ## Building 31 | 32 | Before creating a production version of your app, install an [adapter](https://kit.svelte.dev/docs#adapters) for your target environment. Then: 33 | 34 | ```bash 35 | npm run build 36 | ``` 37 | 38 | > You can preview the built app with `npm run preview`, regardless of whether you installed an adapter. This should _not_ be used to serve your app in production. 39 | -------------------------------------------------------------------------------- /examples/todomvc/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "todomvc", 3 | "version": "0.0.1", 4 | "scripts": { 5 | "dev": "svelte-kit dev", 6 | "build": "svelte-kit build", 7 | "preview": "svelte-kit preview", 8 | "lint": "prettier --check . && eslint --ignore-path .gitignore .", 9 | "format": "prettier --write ." 10 | }, 11 | "devDependencies": { 12 | "@sveltejs/adapter-static": "^1.0.0-next.7", 13 | "@sveltejs/kit": "next", 14 | "@typescript-eslint/eslint-plugin": "^4.19.0", 15 | "@typescript-eslint/parser": "^4.19.0", 16 | "eslint": "^7.22.0", 17 | "eslint-config-prettier": "^8.1.0", 18 | "eslint-plugin-svelte3": "^3.2.0", 19 | "prettier": "~2.2.1", 20 | "prettier-plugin-svelte": "^2.2.0", 21 | "svelte": "^3.34.0", 22 | "svelte-preprocess": "^4.0.0", 23 | "todomvc-app-css": "^2.4.0", 24 | "todomvc-common": "^1.0.5", 25 | "tslib": "^2.0.0", 26 | "typescript": "^4.0.0", 27 | "vite": "^2.2.3" 28 | }, 29 | "type": "module", 30 | "dependencies": { 31 | "svelte-entity-store": "file:../.." 32 | } 33 | } -------------------------------------------------------------------------------- /examples/todomvc/src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %svelte.head% 8 | 9 | 10 |
%svelte.body%
11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/todomvc/src/global.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | -------------------------------------------------------------------------------- /examples/todomvc/src/routes/index.svelte: -------------------------------------------------------------------------------- 1 | 94 | 95 | 96 | 97 | 98 | 99 |
100 |

todos

101 | 102 |
103 | 104 | {#if $allTodos.length > 0} 105 |
106 | 113 | 114 | 115 |
    116 | {#each $filtered as item, index (item.id)} 117 |
  • 118 |
    119 | toggle(item.id)} 124 | /> 125 | 126 |
    128 | 129 | {#if editing === index} 130 | submit(event, item.id)} 136 | autofocus 137 | /> 138 | {/if} 139 |
  • 140 | {/each} 141 |
142 | 143 |
144 | 145 | {numActive} 146 | {numActive === 1 ? 'item' : 'items'} left 147 | 148 | 149 | 157 | 158 | {#if numCompleted} 159 | 160 | {/if} 161 |
162 |
163 | {/if} 164 | -------------------------------------------------------------------------------- /examples/todomvc/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tony-sull/svelte-entity-store/5028b0ea82efbe5cb9a1123da5e16e73ca4ad098/examples/todomvc/static/favicon.ico -------------------------------------------------------------------------------- /examples/todomvc/svelte.config.cjs: -------------------------------------------------------------------------------- 1 | const preprocess = require('svelte-preprocess'); 2 | const static = require('@sveltejs/adapter-static'); 3 | 4 | /** @type {import('@sveltejs/kit').Config} */ 5 | module.exports = { 6 | // Consult https://github.com/sveltejs/svelte-preprocess 7 | // for more information about preprocessors 8 | preprocess: preprocess(), 9 | 10 | kit: { 11 | adapter: static(), 12 | 13 | // hydrate the
element in src/app.html 14 | target: '#svelte' 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /examples/todomvc/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "moduleResolution": "node", 4 | "module": "es2020", 5 | "lib": ["es2020"], 6 | "target": "es2019", 7 | /** 8 | svelte-preprocess cannot figure out whether you have a value or a type, so tell TypeScript 9 | to enforce using \`import type\` instead of \`import\` for Types. 10 | */ 11 | "importsNotUsedAsValues": "error", 12 | "isolatedModules": true, 13 | "resolveJsonModule": true, 14 | /** 15 | To have warnings/errors of the Svelte compiler at the correct position, 16 | enable source maps by default. 17 | */ 18 | "sourceMap": true, 19 | "esModuleInterop": true, 20 | "skipLibCheck": true, 21 | "forceConsistentCasingInFileNames": true, 22 | "baseUrl": ".", 23 | "allowJs": true, 24 | "checkJs": true, 25 | "paths": { 26 | "$lib/*": ["src/lib/*"] 27 | } 28 | }, 29 | "include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.ts", "src/**/*.svelte"] 30 | } 31 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "svelte-entity-store", 3 | "version": "1.0.3", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@babel/code-frame": { 8 | "version": "7.12.11", 9 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", 10 | "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", 11 | "dev": true, 12 | "requires": { 13 | "@babel/highlight": "^7.10.4" 14 | } 15 | }, 16 | "@babel/helper-validator-identifier": { 17 | "version": "7.14.0", 18 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz", 19 | "integrity": "sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A==", 20 | "dev": true 21 | }, 22 | "@babel/highlight": { 23 | "version": "7.14.0", 24 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.0.tgz", 25 | "integrity": "sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg==", 26 | "dev": true, 27 | "requires": { 28 | "@babel/helper-validator-identifier": "^7.14.0", 29 | "chalk": "^2.0.0", 30 | "js-tokens": "^4.0.0" 31 | }, 32 | "dependencies": { 33 | "chalk": { 34 | "version": "2.4.2", 35 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 36 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 37 | "dev": true, 38 | "requires": { 39 | "ansi-styles": "^3.2.1", 40 | "escape-string-regexp": "^1.0.5", 41 | "supports-color": "^5.3.0" 42 | } 43 | } 44 | } 45 | }, 46 | "@bcoe/v8-coverage": { 47 | "version": "0.2.3", 48 | "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", 49 | "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", 50 | "dev": true 51 | }, 52 | "@eslint/eslintrc": { 53 | "version": "0.4.0", 54 | "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz", 55 | "integrity": "sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog==", 56 | "dev": true, 57 | "requires": { 58 | "ajv": "^6.12.4", 59 | "debug": "^4.1.1", 60 | "espree": "^7.3.0", 61 | "globals": "^12.1.0", 62 | "ignore": "^4.0.6", 63 | "import-fresh": "^3.2.1", 64 | "js-yaml": "^3.13.1", 65 | "minimatch": "^3.0.4", 66 | "strip-json-comments": "^3.1.1" 67 | }, 68 | "dependencies": { 69 | "globals": { 70 | "version": "12.4.0", 71 | "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", 72 | "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", 73 | "dev": true, 74 | "requires": { 75 | "type-fest": "^0.8.1" 76 | } 77 | }, 78 | "ignore": { 79 | "version": "4.0.6", 80 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", 81 | "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", 82 | "dev": true 83 | } 84 | } 85 | }, 86 | "@istanbuljs/schema": { 87 | "version": "0.1.3", 88 | "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", 89 | "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", 90 | "dev": true 91 | }, 92 | "@nodelib/fs.scandir": { 93 | "version": "2.1.4", 94 | "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", 95 | "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==", 96 | "dev": true, 97 | "requires": { 98 | "@nodelib/fs.stat": "2.0.4", 99 | "run-parallel": "^1.1.9" 100 | } 101 | }, 102 | "@nodelib/fs.stat": { 103 | "version": "2.0.4", 104 | "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz", 105 | "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==", 106 | "dev": true 107 | }, 108 | "@nodelib/fs.walk": { 109 | "version": "1.2.6", 110 | "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz", 111 | "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==", 112 | "dev": true, 113 | "requires": { 114 | "@nodelib/fs.scandir": "2.1.4", 115 | "fastq": "^1.6.0" 116 | } 117 | }, 118 | "@rollup/plugin-node-resolve": { 119 | "version": "11.2.1", 120 | "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", 121 | "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==", 122 | "dev": true, 123 | "requires": { 124 | "@rollup/pluginutils": "^3.1.0", 125 | "@types/resolve": "1.17.1", 126 | "builtin-modules": "^3.1.0", 127 | "deepmerge": "^4.2.2", 128 | "is-module": "^1.0.0", 129 | "resolve": "^1.19.0" 130 | } 131 | }, 132 | "@rollup/pluginutils": { 133 | "version": "3.1.0", 134 | "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", 135 | "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", 136 | "dev": true, 137 | "requires": { 138 | "@types/estree": "0.0.39", 139 | "estree-walker": "^1.0.1", 140 | "picomatch": "^2.2.2" 141 | } 142 | }, 143 | "@types/estree": { 144 | "version": "0.0.39", 145 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", 146 | "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", 147 | "dev": true 148 | }, 149 | "@types/is-windows": { 150 | "version": "1.0.0", 151 | "resolved": "https://registry.npmjs.org/@types/is-windows/-/is-windows-1.0.0.tgz", 152 | "integrity": "sha512-tJ1rq04tGKuIJoWIH0Gyuwv4RQ3+tIu7wQrC0MV47raQ44kIzXSSFKfrxFUOWVRvesoF7mrTqigXmqoZJsXwTg==", 153 | "dev": true 154 | }, 155 | "@types/istanbul-lib-coverage": { 156 | "version": "2.0.3", 157 | "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", 158 | "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", 159 | "dev": true 160 | }, 161 | "@types/json-schema": { 162 | "version": "7.0.7", 163 | "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", 164 | "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", 165 | "dev": true 166 | }, 167 | "@types/node": { 168 | "version": "15.0.1", 169 | "resolved": "https://registry.npmjs.org/@types/node/-/node-15.0.1.tgz", 170 | "integrity": "sha512-TMkXt0Ck1y0KKsGr9gJtWGjttxlZnnvDtphxUOSd0bfaR6Q1jle+sPvrzNR1urqYTWMinoKvjKfXUGsumaO1PA==", 171 | "dev": true 172 | }, 173 | "@types/resolve": { 174 | "version": "1.17.1", 175 | "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", 176 | "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", 177 | "dev": true, 178 | "requires": { 179 | "@types/node": "*" 180 | } 181 | }, 182 | "@typescript-eslint/eslint-plugin": { 183 | "version": "4.22.0", 184 | "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.22.0.tgz", 185 | "integrity": "sha512-U8SP9VOs275iDXaL08Ln1Fa/wLXfj5aTr/1c0t0j6CdbOnxh+TruXu1p4I0NAvdPBQgoPjHsgKn28mOi0FzfoA==", 186 | "dev": true, 187 | "requires": { 188 | "@typescript-eslint/experimental-utils": "4.22.0", 189 | "@typescript-eslint/scope-manager": "4.22.0", 190 | "debug": "^4.1.1", 191 | "functional-red-black-tree": "^1.0.1", 192 | "lodash": "^4.17.15", 193 | "regexpp": "^3.0.0", 194 | "semver": "^7.3.2", 195 | "tsutils": "^3.17.1" 196 | } 197 | }, 198 | "@typescript-eslint/experimental-utils": { 199 | "version": "4.22.0", 200 | "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.22.0.tgz", 201 | "integrity": "sha512-xJXHHl6TuAxB5AWiVrGhvbGL8/hbiCQ8FiWwObO3r0fnvBdrbWEDy1hlvGQOAWc6qsCWuWMKdVWlLAEMpxnddg==", 202 | "dev": true, 203 | "requires": { 204 | "@types/json-schema": "^7.0.3", 205 | "@typescript-eslint/scope-manager": "4.22.0", 206 | "@typescript-eslint/types": "4.22.0", 207 | "@typescript-eslint/typescript-estree": "4.22.0", 208 | "eslint-scope": "^5.0.0", 209 | "eslint-utils": "^2.0.0" 210 | } 211 | }, 212 | "@typescript-eslint/parser": { 213 | "version": "4.22.0", 214 | "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.22.0.tgz", 215 | "integrity": "sha512-z/bGdBJJZJN76nvAY9DkJANYgK3nlRstRRi74WHm3jjgf2I8AglrSY+6l7ogxOmn55YJ6oKZCLLy+6PW70z15Q==", 216 | "dev": true, 217 | "requires": { 218 | "@typescript-eslint/scope-manager": "4.22.0", 219 | "@typescript-eslint/types": "4.22.0", 220 | "@typescript-eslint/typescript-estree": "4.22.0", 221 | "debug": "^4.1.1" 222 | } 223 | }, 224 | "@typescript-eslint/scope-manager": { 225 | "version": "4.22.0", 226 | "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.22.0.tgz", 227 | "integrity": "sha512-OcCO7LTdk6ukawUM40wo61WdeoA7NM/zaoq1/2cs13M7GyiF+T4rxuA4xM+6LeHWjWbss7hkGXjFDRcKD4O04Q==", 228 | "dev": true, 229 | "requires": { 230 | "@typescript-eslint/types": "4.22.0", 231 | "@typescript-eslint/visitor-keys": "4.22.0" 232 | } 233 | }, 234 | "@typescript-eslint/types": { 235 | "version": "4.22.0", 236 | "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.22.0.tgz", 237 | "integrity": "sha512-sW/BiXmmyMqDPO2kpOhSy2Py5w6KvRRsKZnV0c4+0nr4GIcedJwXAq+RHNK4lLVEZAJYFltnnk1tJSlbeS9lYA==", 238 | "dev": true 239 | }, 240 | "@typescript-eslint/typescript-estree": { 241 | "version": "4.22.0", 242 | "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.22.0.tgz", 243 | "integrity": "sha512-TkIFeu5JEeSs5ze/4NID+PIcVjgoU3cUQUIZnH3Sb1cEn1lBo7StSV5bwPuJQuoxKXlzAObjYTilOEKRuhR5yg==", 244 | "dev": true, 245 | "requires": { 246 | "@typescript-eslint/types": "4.22.0", 247 | "@typescript-eslint/visitor-keys": "4.22.0", 248 | "debug": "^4.1.1", 249 | "globby": "^11.0.1", 250 | "is-glob": "^4.0.1", 251 | "semver": "^7.3.2", 252 | "tsutils": "^3.17.1" 253 | } 254 | }, 255 | "@typescript-eslint/visitor-keys": { 256 | "version": "4.22.0", 257 | "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.22.0.tgz", 258 | "integrity": "sha512-nnMu4F+s4o0sll6cBSsTeVsT4cwxB7zECK3dFxzEjPBii9xLpq4yqqsy/FU5zMfan6G60DKZSCXAa3sHJZrcYw==", 259 | "dev": true, 260 | "requires": { 261 | "@typescript-eslint/types": "4.22.0", 262 | "eslint-visitor-keys": "^2.0.0" 263 | } 264 | }, 265 | "acorn": { 266 | "version": "7.4.1", 267 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", 268 | "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", 269 | "dev": true 270 | }, 271 | "acorn-jsx": { 272 | "version": "5.3.1", 273 | "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", 274 | "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", 275 | "dev": true 276 | }, 277 | "ajv": { 278 | "version": "6.12.6", 279 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", 280 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", 281 | "dev": true, 282 | "requires": { 283 | "fast-deep-equal": "^3.1.1", 284 | "fast-json-stable-stringify": "^2.0.0", 285 | "json-schema-traverse": "^0.4.1", 286 | "uri-js": "^4.2.2" 287 | } 288 | }, 289 | "ansi-colors": { 290 | "version": "4.1.1", 291 | "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", 292 | "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", 293 | "dev": true 294 | }, 295 | "ansi-regex": { 296 | "version": "5.0.0", 297 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", 298 | "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", 299 | "dev": true 300 | }, 301 | "ansi-styles": { 302 | "version": "3.2.1", 303 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 304 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 305 | "dev": true, 306 | "requires": { 307 | "color-convert": "^1.9.0" 308 | } 309 | }, 310 | "any-promise": { 311 | "version": "1.3.0", 312 | "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", 313 | "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=", 314 | "dev": true 315 | }, 316 | "arg": { 317 | "version": "4.1.3", 318 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", 319 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", 320 | "dev": true 321 | }, 322 | "argparse": { 323 | "version": "1.0.10", 324 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 325 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 326 | "dev": true, 327 | "requires": { 328 | "sprintf-js": "~1.0.2" 329 | } 330 | }, 331 | "array-union": { 332 | "version": "2.1.0", 333 | "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", 334 | "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", 335 | "dev": true 336 | }, 337 | "astral-regex": { 338 | "version": "2.0.0", 339 | "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", 340 | "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", 341 | "dev": true 342 | }, 343 | "at-least-node": { 344 | "version": "1.0.0", 345 | "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", 346 | "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", 347 | "dev": true 348 | }, 349 | "balanced-match": { 350 | "version": "1.0.2", 351 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 352 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 353 | "dev": true 354 | }, 355 | "brace-expansion": { 356 | "version": "1.1.11", 357 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 358 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 359 | "dev": true, 360 | "requires": { 361 | "balanced-match": "^1.0.0", 362 | "concat-map": "0.0.1" 363 | } 364 | }, 365 | "braces": { 366 | "version": "3.0.2", 367 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 368 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 369 | "dev": true, 370 | "requires": { 371 | "fill-range": "^7.0.1" 372 | } 373 | }, 374 | "buffer-from": { 375 | "version": "1.1.1", 376 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", 377 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", 378 | "dev": true 379 | }, 380 | "builtin-modules": { 381 | "version": "3.2.0", 382 | "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz", 383 | "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==", 384 | "dev": true 385 | }, 386 | "c8": { 387 | "version": "7.7.1", 388 | "resolved": "https://registry.npmjs.org/c8/-/c8-7.7.1.tgz", 389 | "integrity": "sha512-OO9KpDGv1iTd/MBNUForJH7vPKt9XnRPWSBKeRJGma4xfTaKBObA0zWAplFpFRuf/qRmATFqGFrzxqDk51LXsw==", 390 | "dev": true, 391 | "requires": { 392 | "@bcoe/v8-coverage": "^0.2.3", 393 | "@istanbuljs/schema": "^0.1.2", 394 | "find-up": "^5.0.0", 395 | "foreground-child": "^2.0.0", 396 | "furi": "^2.0.0", 397 | "istanbul-lib-coverage": "^3.0.0", 398 | "istanbul-lib-report": "^3.0.0", 399 | "istanbul-reports": "^3.0.2", 400 | "rimraf": "^3.0.0", 401 | "test-exclude": "^6.0.0", 402 | "v8-to-istanbul": "^7.1.0", 403 | "yargs": "^16.2.0", 404 | "yargs-parser": "^20.2.7" 405 | }, 406 | "dependencies": { 407 | "rimraf": { 408 | "version": "3.0.2", 409 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", 410 | "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", 411 | "dev": true, 412 | "requires": { 413 | "glob": "^7.1.3" 414 | } 415 | } 416 | } 417 | }, 418 | "callsites": { 419 | "version": "3.1.0", 420 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", 421 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", 422 | "dev": true 423 | }, 424 | "chalk": { 425 | "version": "4.1.1", 426 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", 427 | "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", 428 | "dev": true, 429 | "requires": { 430 | "ansi-styles": "^4.1.0", 431 | "supports-color": "^7.1.0" 432 | }, 433 | "dependencies": { 434 | "ansi-styles": { 435 | "version": "4.3.0", 436 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 437 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 438 | "dev": true, 439 | "requires": { 440 | "color-convert": "^2.0.1" 441 | } 442 | }, 443 | "color-convert": { 444 | "version": "2.0.1", 445 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 446 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 447 | "dev": true, 448 | "requires": { 449 | "color-name": "~1.1.4" 450 | } 451 | }, 452 | "color-name": { 453 | "version": "1.1.4", 454 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 455 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 456 | "dev": true 457 | }, 458 | "has-flag": { 459 | "version": "4.0.0", 460 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 461 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 462 | "dev": true 463 | }, 464 | "supports-color": { 465 | "version": "7.2.0", 466 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 467 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 468 | "dev": true, 469 | "requires": { 470 | "has-flag": "^4.0.0" 471 | } 472 | } 473 | } 474 | }, 475 | "cliui": { 476 | "version": "7.0.4", 477 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", 478 | "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", 479 | "dev": true, 480 | "requires": { 481 | "string-width": "^4.2.0", 482 | "strip-ansi": "^6.0.0", 483 | "wrap-ansi": "^7.0.0" 484 | } 485 | }, 486 | "color-convert": { 487 | "version": "1.9.3", 488 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 489 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 490 | "dev": true, 491 | "requires": { 492 | "color-name": "1.1.3" 493 | } 494 | }, 495 | "color-name": { 496 | "version": "1.1.3", 497 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 498 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", 499 | "dev": true 500 | }, 501 | "colors": { 502 | "version": "1.4.0", 503 | "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", 504 | "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", 505 | "dev": true 506 | }, 507 | "commander": { 508 | "version": "4.1.1", 509 | "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", 510 | "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", 511 | "dev": true 512 | }, 513 | "concat-map": { 514 | "version": "0.0.1", 515 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 516 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 517 | "dev": true 518 | }, 519 | "convert-source-map": { 520 | "version": "1.7.0", 521 | "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", 522 | "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", 523 | "dev": true, 524 | "requires": { 525 | "safe-buffer": "~5.1.1" 526 | } 527 | }, 528 | "create-require": { 529 | "version": "1.1.1", 530 | "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", 531 | "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", 532 | "dev": true 533 | }, 534 | "cross-spawn": { 535 | "version": "7.0.3", 536 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", 537 | "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", 538 | "dev": true, 539 | "requires": { 540 | "path-key": "^3.1.0", 541 | "shebang-command": "^2.0.0", 542 | "which": "^2.0.1" 543 | } 544 | }, 545 | "debug": { 546 | "version": "4.3.1", 547 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", 548 | "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", 549 | "dev": true, 550 | "requires": { 551 | "ms": "2.1.2" 552 | } 553 | }, 554 | "deep-is": { 555 | "version": "0.1.3", 556 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", 557 | "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", 558 | "dev": true 559 | }, 560 | "deepmerge": { 561 | "version": "4.2.2", 562 | "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", 563 | "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", 564 | "dev": true 565 | }, 566 | "dequal": { 567 | "version": "2.0.2", 568 | "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.2.tgz", 569 | "integrity": "sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug==", 570 | "dev": true 571 | }, 572 | "diff": { 573 | "version": "4.0.2", 574 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", 575 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", 576 | "dev": true 577 | }, 578 | "dir-glob": { 579 | "version": "3.0.1", 580 | "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", 581 | "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", 582 | "dev": true, 583 | "requires": { 584 | "path-type": "^4.0.0" 585 | } 586 | }, 587 | "doctrine": { 588 | "version": "3.0.0", 589 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", 590 | "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", 591 | "dev": true, 592 | "requires": { 593 | "esutils": "^2.0.2" 594 | } 595 | }, 596 | "emoji-regex": { 597 | "version": "8.0.0", 598 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 599 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 600 | "dev": true 601 | }, 602 | "enquirer": { 603 | "version": "2.3.6", 604 | "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", 605 | "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", 606 | "dev": true, 607 | "requires": { 608 | "ansi-colors": "^4.1.1" 609 | } 610 | }, 611 | "escalade": { 612 | "version": "3.1.1", 613 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", 614 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", 615 | "dev": true 616 | }, 617 | "escape-string-regexp": { 618 | "version": "1.0.5", 619 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 620 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 621 | "dev": true 622 | }, 623 | "eslint": { 624 | "version": "7.25.0", 625 | "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.25.0.tgz", 626 | "integrity": "sha512-TVpSovpvCNpLURIScDRB6g5CYu/ZFq9GfX2hLNIV4dSBKxIWojeDODvYl3t0k0VtMxYeR8OXPCFE5+oHMlGfhw==", 627 | "dev": true, 628 | "requires": { 629 | "@babel/code-frame": "7.12.11", 630 | "@eslint/eslintrc": "^0.4.0", 631 | "ajv": "^6.10.0", 632 | "chalk": "^4.0.0", 633 | "cross-spawn": "^7.0.2", 634 | "debug": "^4.0.1", 635 | "doctrine": "^3.0.0", 636 | "enquirer": "^2.3.5", 637 | "eslint-scope": "^5.1.1", 638 | "eslint-utils": "^2.1.0", 639 | "eslint-visitor-keys": "^2.0.0", 640 | "espree": "^7.3.1", 641 | "esquery": "^1.4.0", 642 | "esutils": "^2.0.2", 643 | "file-entry-cache": "^6.0.1", 644 | "functional-red-black-tree": "^1.0.1", 645 | "glob-parent": "^5.0.0", 646 | "globals": "^13.6.0", 647 | "ignore": "^4.0.6", 648 | "import-fresh": "^3.0.0", 649 | "imurmurhash": "^0.1.4", 650 | "is-glob": "^4.0.0", 651 | "js-yaml": "^3.13.1", 652 | "json-stable-stringify-without-jsonify": "^1.0.1", 653 | "levn": "^0.4.1", 654 | "lodash": "^4.17.21", 655 | "minimatch": "^3.0.4", 656 | "natural-compare": "^1.4.0", 657 | "optionator": "^0.9.1", 658 | "progress": "^2.0.0", 659 | "regexpp": "^3.1.0", 660 | "semver": "^7.2.1", 661 | "strip-ansi": "^6.0.0", 662 | "strip-json-comments": "^3.1.0", 663 | "table": "^6.0.4", 664 | "text-table": "^0.2.0", 665 | "v8-compile-cache": "^2.0.3" 666 | }, 667 | "dependencies": { 668 | "ignore": { 669 | "version": "4.0.6", 670 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", 671 | "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", 672 | "dev": true 673 | } 674 | } 675 | }, 676 | "eslint-config-prettier": { 677 | "version": "8.3.0", 678 | "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", 679 | "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", 680 | "dev": true 681 | }, 682 | "eslint-plugin-prettier": { 683 | "version": "3.4.0", 684 | "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.0.tgz", 685 | "integrity": "sha512-UDK6rJT6INSfcOo545jiaOwB701uAIt2/dR7WnFQoGCVl1/EMqdANBmwUaqqQ45aXprsTGzSa39LI1PyuRBxxw==", 686 | "dev": true, 687 | "requires": { 688 | "prettier-linter-helpers": "^1.0.0" 689 | } 690 | }, 691 | "eslint-scope": { 692 | "version": "5.1.1", 693 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", 694 | "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", 695 | "dev": true, 696 | "requires": { 697 | "esrecurse": "^4.3.0", 698 | "estraverse": "^4.1.1" 699 | } 700 | }, 701 | "eslint-utils": { 702 | "version": "2.1.0", 703 | "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", 704 | "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", 705 | "dev": true, 706 | "requires": { 707 | "eslint-visitor-keys": "^1.1.0" 708 | }, 709 | "dependencies": { 710 | "eslint-visitor-keys": { 711 | "version": "1.3.0", 712 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", 713 | "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", 714 | "dev": true 715 | } 716 | } 717 | }, 718 | "eslint-visitor-keys": { 719 | "version": "2.0.0", 720 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", 721 | "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", 722 | "dev": true 723 | }, 724 | "espree": { 725 | "version": "7.3.1", 726 | "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", 727 | "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", 728 | "dev": true, 729 | "requires": { 730 | "acorn": "^7.4.0", 731 | "acorn-jsx": "^5.3.1", 732 | "eslint-visitor-keys": "^1.3.0" 733 | }, 734 | "dependencies": { 735 | "eslint-visitor-keys": { 736 | "version": "1.3.0", 737 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", 738 | "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", 739 | "dev": true 740 | } 741 | } 742 | }, 743 | "esprima": { 744 | "version": "4.0.1", 745 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 746 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 747 | "dev": true 748 | }, 749 | "esquery": { 750 | "version": "1.4.0", 751 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", 752 | "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", 753 | "dev": true, 754 | "requires": { 755 | "estraverse": "^5.1.0" 756 | }, 757 | "dependencies": { 758 | "estraverse": { 759 | "version": "5.2.0", 760 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", 761 | "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", 762 | "dev": true 763 | } 764 | } 765 | }, 766 | "esrecurse": { 767 | "version": "4.3.0", 768 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", 769 | "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", 770 | "dev": true, 771 | "requires": { 772 | "estraverse": "^5.2.0" 773 | }, 774 | "dependencies": { 775 | "estraverse": { 776 | "version": "5.2.0", 777 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", 778 | "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", 779 | "dev": true 780 | } 781 | } 782 | }, 783 | "estraverse": { 784 | "version": "4.3.0", 785 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", 786 | "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", 787 | "dev": true 788 | }, 789 | "estree-walker": { 790 | "version": "1.0.1", 791 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", 792 | "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", 793 | "dev": true 794 | }, 795 | "esutils": { 796 | "version": "2.0.3", 797 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", 798 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", 799 | "dev": true 800 | }, 801 | "fast-deep-equal": { 802 | "version": "3.1.3", 803 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 804 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", 805 | "dev": true 806 | }, 807 | "fast-diff": { 808 | "version": "1.2.0", 809 | "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", 810 | "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", 811 | "dev": true 812 | }, 813 | "fast-glob": { 814 | "version": "3.2.5", 815 | "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", 816 | "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", 817 | "dev": true, 818 | "requires": { 819 | "@nodelib/fs.stat": "^2.0.2", 820 | "@nodelib/fs.walk": "^1.2.3", 821 | "glob-parent": "^5.1.0", 822 | "merge2": "^1.3.0", 823 | "micromatch": "^4.0.2", 824 | "picomatch": "^2.2.1" 825 | } 826 | }, 827 | "fast-json-stable-stringify": { 828 | "version": "2.1.0", 829 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", 830 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", 831 | "dev": true 832 | }, 833 | "fast-levenshtein": { 834 | "version": "2.0.6", 835 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 836 | "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", 837 | "dev": true 838 | }, 839 | "fastq": { 840 | "version": "1.11.0", 841 | "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", 842 | "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", 843 | "dev": true, 844 | "requires": { 845 | "reusify": "^1.0.4" 846 | } 847 | }, 848 | "file-entry-cache": { 849 | "version": "6.0.1", 850 | "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", 851 | "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", 852 | "dev": true, 853 | "requires": { 854 | "flat-cache": "^3.0.4" 855 | } 856 | }, 857 | "fill-range": { 858 | "version": "7.0.1", 859 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 860 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 861 | "dev": true, 862 | "requires": { 863 | "to-regex-range": "^5.0.1" 864 | } 865 | }, 866 | "find-up": { 867 | "version": "5.0.0", 868 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", 869 | "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", 870 | "dev": true, 871 | "requires": { 872 | "locate-path": "^6.0.0", 873 | "path-exists": "^4.0.0" 874 | } 875 | }, 876 | "flat-cache": { 877 | "version": "3.0.4", 878 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", 879 | "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", 880 | "dev": true, 881 | "requires": { 882 | "flatted": "^3.1.0", 883 | "rimraf": "^3.0.2" 884 | }, 885 | "dependencies": { 886 | "rimraf": { 887 | "version": "3.0.2", 888 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", 889 | "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", 890 | "dev": true, 891 | "requires": { 892 | "glob": "^7.1.3" 893 | } 894 | } 895 | } 896 | }, 897 | "flatted": { 898 | "version": "3.1.1", 899 | "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", 900 | "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", 901 | "dev": true 902 | }, 903 | "foreground-child": { 904 | "version": "2.0.0", 905 | "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", 906 | "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", 907 | "dev": true, 908 | "requires": { 909 | "cross-spawn": "^7.0.0", 910 | "signal-exit": "^3.0.2" 911 | } 912 | }, 913 | "fs-extra": { 914 | "version": "9.1.0", 915 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", 916 | "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", 917 | "dev": true, 918 | "requires": { 919 | "at-least-node": "^1.0.0", 920 | "graceful-fs": "^4.2.0", 921 | "jsonfile": "^6.0.1", 922 | "universalify": "^2.0.0" 923 | } 924 | }, 925 | "fs.realpath": { 926 | "version": "1.0.0", 927 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 928 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 929 | "dev": true 930 | }, 931 | "fsevents": { 932 | "version": "2.3.2", 933 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 934 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 935 | "dev": true, 936 | "optional": true 937 | }, 938 | "function-bind": { 939 | "version": "1.1.1", 940 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 941 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 942 | "dev": true 943 | }, 944 | "functional-red-black-tree": { 945 | "version": "1.0.1", 946 | "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", 947 | "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", 948 | "dev": true 949 | }, 950 | "furi": { 951 | "version": "2.0.0", 952 | "resolved": "https://registry.npmjs.org/furi/-/furi-2.0.0.tgz", 953 | "integrity": "sha512-uKuNsaU0WVaK/vmvj23wW1bicOFfyqSsAIH71bRZx8kA4Xj+YCHin7CJKJJjkIsmxYaPFLk9ljmjEyB7xF7WvQ==", 954 | "dev": true, 955 | "requires": { 956 | "@types/is-windows": "^1.0.0", 957 | "is-windows": "^1.0.2" 958 | } 959 | }, 960 | "get-caller-file": { 961 | "version": "2.0.5", 962 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 963 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 964 | "dev": true 965 | }, 966 | "glob": { 967 | "version": "7.1.6", 968 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", 969 | "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", 970 | "dev": true, 971 | "requires": { 972 | "fs.realpath": "^1.0.0", 973 | "inflight": "^1.0.4", 974 | "inherits": "2", 975 | "minimatch": "^3.0.4", 976 | "once": "^1.3.0", 977 | "path-is-absolute": "^1.0.0" 978 | } 979 | }, 980 | "glob-parent": { 981 | "version": "5.1.2", 982 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 983 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 984 | "dev": true, 985 | "requires": { 986 | "is-glob": "^4.0.1" 987 | } 988 | }, 989 | "globals": { 990 | "version": "13.8.0", 991 | "resolved": "https://registry.npmjs.org/globals/-/globals-13.8.0.tgz", 992 | "integrity": "sha512-rHtdA6+PDBIjeEvA91rpqzEvk/k3/i7EeNQiryiWuJH0Hw9cpyJMAt2jtbAwUaRdhD+573X4vWw6IcjKPasi9Q==", 993 | "dev": true, 994 | "requires": { 995 | "type-fest": "^0.20.2" 996 | }, 997 | "dependencies": { 998 | "type-fest": { 999 | "version": "0.20.2", 1000 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", 1001 | "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", 1002 | "dev": true 1003 | } 1004 | } 1005 | }, 1006 | "globalyzer": { 1007 | "version": "0.1.0", 1008 | "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", 1009 | "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==", 1010 | "dev": true 1011 | }, 1012 | "globby": { 1013 | "version": "11.0.3", 1014 | "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz", 1015 | "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==", 1016 | "dev": true, 1017 | "requires": { 1018 | "array-union": "^2.1.0", 1019 | "dir-glob": "^3.0.1", 1020 | "fast-glob": "^3.1.1", 1021 | "ignore": "^5.1.4", 1022 | "merge2": "^1.3.0", 1023 | "slash": "^3.0.0" 1024 | } 1025 | }, 1026 | "globrex": { 1027 | "version": "0.1.2", 1028 | "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", 1029 | "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", 1030 | "dev": true 1031 | }, 1032 | "graceful-fs": { 1033 | "version": "4.2.6", 1034 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", 1035 | "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", 1036 | "dev": true 1037 | }, 1038 | "handlebars": { 1039 | "version": "4.7.7", 1040 | "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", 1041 | "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", 1042 | "dev": true, 1043 | "requires": { 1044 | "minimist": "^1.2.5", 1045 | "neo-async": "^2.6.0", 1046 | "source-map": "^0.6.1", 1047 | "uglify-js": "^3.1.4", 1048 | "wordwrap": "^1.0.0" 1049 | } 1050 | }, 1051 | "has": { 1052 | "version": "1.0.3", 1053 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 1054 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 1055 | "dev": true, 1056 | "requires": { 1057 | "function-bind": "^1.1.1" 1058 | } 1059 | }, 1060 | "has-flag": { 1061 | "version": "3.0.0", 1062 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 1063 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 1064 | "dev": true 1065 | }, 1066 | "html-escaper": { 1067 | "version": "2.0.2", 1068 | "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", 1069 | "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", 1070 | "dev": true 1071 | }, 1072 | "ignore": { 1073 | "version": "5.1.8", 1074 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", 1075 | "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", 1076 | "dev": true 1077 | }, 1078 | "import-fresh": { 1079 | "version": "3.3.0", 1080 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", 1081 | "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", 1082 | "dev": true, 1083 | "requires": { 1084 | "parent-module": "^1.0.0", 1085 | "resolve-from": "^4.0.0" 1086 | } 1087 | }, 1088 | "imurmurhash": { 1089 | "version": "0.1.4", 1090 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 1091 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", 1092 | "dev": true 1093 | }, 1094 | "inflight": { 1095 | "version": "1.0.6", 1096 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 1097 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 1098 | "dev": true, 1099 | "requires": { 1100 | "once": "^1.3.0", 1101 | "wrappy": "1" 1102 | } 1103 | }, 1104 | "inherits": { 1105 | "version": "2.0.4", 1106 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 1107 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 1108 | "dev": true 1109 | }, 1110 | "interpret": { 1111 | "version": "1.4.0", 1112 | "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", 1113 | "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", 1114 | "dev": true 1115 | }, 1116 | "is-core-module": { 1117 | "version": "2.3.0", 1118 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.3.0.tgz", 1119 | "integrity": "sha512-xSphU2KG9867tsYdLD4RWQ1VqdFl4HTO9Thf3I/3dLEfr0dbPTWKsuCKrgqMljg4nPE+Gq0VCnzT3gr0CyBmsw==", 1120 | "dev": true, 1121 | "requires": { 1122 | "has": "^1.0.3" 1123 | } 1124 | }, 1125 | "is-extglob": { 1126 | "version": "2.1.1", 1127 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 1128 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", 1129 | "dev": true 1130 | }, 1131 | "is-fullwidth-code-point": { 1132 | "version": "3.0.0", 1133 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 1134 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 1135 | "dev": true 1136 | }, 1137 | "is-glob": { 1138 | "version": "4.0.1", 1139 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", 1140 | "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", 1141 | "dev": true, 1142 | "requires": { 1143 | "is-extglob": "^2.1.1" 1144 | } 1145 | }, 1146 | "is-module": { 1147 | "version": "1.0.0", 1148 | "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", 1149 | "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", 1150 | "dev": true 1151 | }, 1152 | "is-number": { 1153 | "version": "7.0.0", 1154 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 1155 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 1156 | "dev": true 1157 | }, 1158 | "is-windows": { 1159 | "version": "1.0.2", 1160 | "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", 1161 | "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", 1162 | "dev": true 1163 | }, 1164 | "isexe": { 1165 | "version": "2.0.0", 1166 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 1167 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 1168 | "dev": true 1169 | }, 1170 | "istanbul-lib-coverage": { 1171 | "version": "3.0.0", 1172 | "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", 1173 | "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", 1174 | "dev": true 1175 | }, 1176 | "istanbul-lib-report": { 1177 | "version": "3.0.0", 1178 | "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", 1179 | "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", 1180 | "dev": true, 1181 | "requires": { 1182 | "istanbul-lib-coverage": "^3.0.0", 1183 | "make-dir": "^3.0.0", 1184 | "supports-color": "^7.1.0" 1185 | }, 1186 | "dependencies": { 1187 | "has-flag": { 1188 | "version": "4.0.0", 1189 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 1190 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 1191 | "dev": true 1192 | }, 1193 | "supports-color": { 1194 | "version": "7.2.0", 1195 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 1196 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 1197 | "dev": true, 1198 | "requires": { 1199 | "has-flag": "^4.0.0" 1200 | } 1201 | } 1202 | } 1203 | }, 1204 | "istanbul-reports": { 1205 | "version": "3.0.2", 1206 | "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", 1207 | "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", 1208 | "dev": true, 1209 | "requires": { 1210 | "html-escaper": "^2.0.0", 1211 | "istanbul-lib-report": "^3.0.0" 1212 | } 1213 | }, 1214 | "js-tokens": { 1215 | "version": "4.0.0", 1216 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 1217 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", 1218 | "dev": true 1219 | }, 1220 | "js-yaml": { 1221 | "version": "3.14.1", 1222 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", 1223 | "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", 1224 | "dev": true, 1225 | "requires": { 1226 | "argparse": "^1.0.7", 1227 | "esprima": "^4.0.0" 1228 | } 1229 | }, 1230 | "json-schema-traverse": { 1231 | "version": "0.4.1", 1232 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 1233 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", 1234 | "dev": true 1235 | }, 1236 | "json-stable-stringify-without-jsonify": { 1237 | "version": "1.0.1", 1238 | "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", 1239 | "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", 1240 | "dev": true 1241 | }, 1242 | "jsonfile": { 1243 | "version": "6.1.0", 1244 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", 1245 | "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", 1246 | "dev": true, 1247 | "requires": { 1248 | "graceful-fs": "^4.1.6", 1249 | "universalify": "^2.0.0" 1250 | } 1251 | }, 1252 | "kleur": { 1253 | "version": "4.1.4", 1254 | "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.4.tgz", 1255 | "integrity": "sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA==", 1256 | "dev": true 1257 | }, 1258 | "levn": { 1259 | "version": "0.4.1", 1260 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", 1261 | "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", 1262 | "dev": true, 1263 | "requires": { 1264 | "prelude-ls": "^1.2.1", 1265 | "type-check": "~0.4.0" 1266 | } 1267 | }, 1268 | "lines-and-columns": { 1269 | "version": "1.1.6", 1270 | "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", 1271 | "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", 1272 | "dev": true 1273 | }, 1274 | "locate-path": { 1275 | "version": "6.0.0", 1276 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", 1277 | "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", 1278 | "dev": true, 1279 | "requires": { 1280 | "p-locate": "^5.0.0" 1281 | } 1282 | }, 1283 | "lodash": { 1284 | "version": "4.17.21", 1285 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 1286 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", 1287 | "dev": true 1288 | }, 1289 | "lodash.clonedeep": { 1290 | "version": "4.5.0", 1291 | "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", 1292 | "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", 1293 | "dev": true 1294 | }, 1295 | "lodash.flatten": { 1296 | "version": "4.4.0", 1297 | "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", 1298 | "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=", 1299 | "dev": true 1300 | }, 1301 | "lodash.truncate": { 1302 | "version": "4.4.2", 1303 | "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", 1304 | "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", 1305 | "dev": true 1306 | }, 1307 | "lru-cache": { 1308 | "version": "6.0.0", 1309 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", 1310 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", 1311 | "dev": true, 1312 | "requires": { 1313 | "yallist": "^4.0.0" 1314 | } 1315 | }, 1316 | "lunr": { 1317 | "version": "2.3.9", 1318 | "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", 1319 | "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", 1320 | "dev": true 1321 | }, 1322 | "make-dir": { 1323 | "version": "3.1.0", 1324 | "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", 1325 | "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", 1326 | "dev": true, 1327 | "requires": { 1328 | "semver": "^6.0.0" 1329 | }, 1330 | "dependencies": { 1331 | "semver": { 1332 | "version": "6.3.0", 1333 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", 1334 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", 1335 | "dev": true 1336 | } 1337 | } 1338 | }, 1339 | "make-error": { 1340 | "version": "1.3.6", 1341 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", 1342 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", 1343 | "dev": true 1344 | }, 1345 | "marked": { 1346 | "version": "2.0.3", 1347 | "resolved": "https://registry.npmjs.org/marked/-/marked-2.0.3.tgz", 1348 | "integrity": "sha512-5otztIIcJfPc2qGTN8cVtOJEjNJZ0jwa46INMagrYfk0EvqtRuEHLsEe0LrFS0/q+ZRKT0+kXK7P2T1AN5lWRA==", 1349 | "dev": true 1350 | }, 1351 | "merge2": { 1352 | "version": "1.4.1", 1353 | "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", 1354 | "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", 1355 | "dev": true 1356 | }, 1357 | "micromatch": { 1358 | "version": "4.0.4", 1359 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", 1360 | "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", 1361 | "dev": true, 1362 | "requires": { 1363 | "braces": "^3.0.1", 1364 | "picomatch": "^2.2.3" 1365 | } 1366 | }, 1367 | "minimatch": { 1368 | "version": "3.0.4", 1369 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 1370 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 1371 | "dev": true, 1372 | "requires": { 1373 | "brace-expansion": "^1.1.7" 1374 | } 1375 | }, 1376 | "minimist": { 1377 | "version": "1.2.5", 1378 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", 1379 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", 1380 | "dev": true 1381 | }, 1382 | "mkdirp": { 1383 | "version": "0.5.5", 1384 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", 1385 | "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", 1386 | "dev": true, 1387 | "requires": { 1388 | "minimist": "^1.2.5" 1389 | } 1390 | }, 1391 | "mri": { 1392 | "version": "1.1.6", 1393 | "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.6.tgz", 1394 | "integrity": "sha512-oi1b3MfbyGa7FJMP9GmLTttni5JoICpYBRlq+x5V16fZbLsnL9N3wFqqIm/nIG43FjUFkFh9Epzp/kzUGUnJxQ==", 1395 | "dev": true 1396 | }, 1397 | "ms": { 1398 | "version": "2.1.2", 1399 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 1400 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 1401 | "dev": true 1402 | }, 1403 | "mz": { 1404 | "version": "2.7.0", 1405 | "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", 1406 | "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", 1407 | "dev": true, 1408 | "requires": { 1409 | "any-promise": "^1.0.0", 1410 | "object-assign": "^4.0.1", 1411 | "thenify-all": "^1.0.0" 1412 | } 1413 | }, 1414 | "natural-compare": { 1415 | "version": "1.4.0", 1416 | "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", 1417 | "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", 1418 | "dev": true 1419 | }, 1420 | "neo-async": { 1421 | "version": "2.6.2", 1422 | "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", 1423 | "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", 1424 | "dev": true 1425 | }, 1426 | "node-modules-regexp": { 1427 | "version": "1.0.0", 1428 | "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", 1429 | "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", 1430 | "dev": true 1431 | }, 1432 | "object-assign": { 1433 | "version": "4.1.1", 1434 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 1435 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", 1436 | "dev": true 1437 | }, 1438 | "once": { 1439 | "version": "1.4.0", 1440 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1441 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 1442 | "dev": true, 1443 | "requires": { 1444 | "wrappy": "1" 1445 | } 1446 | }, 1447 | "onigasm": { 1448 | "version": "2.2.5", 1449 | "resolved": "https://registry.npmjs.org/onigasm/-/onigasm-2.2.5.tgz", 1450 | "integrity": "sha512-F+th54mPc0l1lp1ZcFMyL/jTs2Tlq4SqIHKIXGZOR/VkHkF9A7Fr5rRr5+ZG/lWeRsyrClLYRq7s/yFQ/XhWCA==", 1451 | "dev": true, 1452 | "requires": { 1453 | "lru-cache": "^5.1.1" 1454 | }, 1455 | "dependencies": { 1456 | "lru-cache": { 1457 | "version": "5.1.1", 1458 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", 1459 | "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", 1460 | "dev": true, 1461 | "requires": { 1462 | "yallist": "^3.0.2" 1463 | } 1464 | }, 1465 | "yallist": { 1466 | "version": "3.1.1", 1467 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", 1468 | "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", 1469 | "dev": true 1470 | } 1471 | } 1472 | }, 1473 | "optionator": { 1474 | "version": "0.9.1", 1475 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", 1476 | "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", 1477 | "dev": true, 1478 | "requires": { 1479 | "deep-is": "^0.1.3", 1480 | "fast-levenshtein": "^2.0.6", 1481 | "levn": "^0.4.1", 1482 | "prelude-ls": "^1.2.1", 1483 | "type-check": "^0.4.0", 1484 | "word-wrap": "^1.2.3" 1485 | } 1486 | }, 1487 | "p-limit": { 1488 | "version": "3.1.0", 1489 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", 1490 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", 1491 | "dev": true, 1492 | "requires": { 1493 | "yocto-queue": "^0.1.0" 1494 | } 1495 | }, 1496 | "p-locate": { 1497 | "version": "5.0.0", 1498 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", 1499 | "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", 1500 | "dev": true, 1501 | "requires": { 1502 | "p-limit": "^3.0.2" 1503 | } 1504 | }, 1505 | "parent-module": { 1506 | "version": "1.0.1", 1507 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", 1508 | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", 1509 | "dev": true, 1510 | "requires": { 1511 | "callsites": "^3.0.0" 1512 | } 1513 | }, 1514 | "path-exists": { 1515 | "version": "4.0.0", 1516 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 1517 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", 1518 | "dev": true 1519 | }, 1520 | "path-is-absolute": { 1521 | "version": "1.0.1", 1522 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1523 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 1524 | "dev": true 1525 | }, 1526 | "path-key": { 1527 | "version": "3.1.1", 1528 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 1529 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", 1530 | "dev": true 1531 | }, 1532 | "path-parse": { 1533 | "version": "1.0.6", 1534 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", 1535 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", 1536 | "dev": true 1537 | }, 1538 | "path-type": { 1539 | "version": "4.0.0", 1540 | "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", 1541 | "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", 1542 | "dev": true 1543 | }, 1544 | "picomatch": { 1545 | "version": "2.2.3", 1546 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz", 1547 | "integrity": "sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==", 1548 | "dev": true 1549 | }, 1550 | "pirates": { 1551 | "version": "4.0.1", 1552 | "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", 1553 | "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", 1554 | "dev": true, 1555 | "requires": { 1556 | "node-modules-regexp": "^1.0.0" 1557 | } 1558 | }, 1559 | "prelude-ls": { 1560 | "version": "1.2.1", 1561 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", 1562 | "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", 1563 | "dev": true 1564 | }, 1565 | "prettier": { 1566 | "version": "2.2.1", 1567 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", 1568 | "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", 1569 | "dev": true 1570 | }, 1571 | "prettier-linter-helpers": { 1572 | "version": "1.0.0", 1573 | "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", 1574 | "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", 1575 | "dev": true, 1576 | "requires": { 1577 | "fast-diff": "^1.1.2" 1578 | } 1579 | }, 1580 | "progress": { 1581 | "version": "2.0.3", 1582 | "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", 1583 | "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", 1584 | "dev": true 1585 | }, 1586 | "punycode": { 1587 | "version": "2.1.1", 1588 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 1589 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", 1590 | "dev": true 1591 | }, 1592 | "queue-microtask": { 1593 | "version": "1.2.3", 1594 | "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", 1595 | "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", 1596 | "dev": true 1597 | }, 1598 | "rechoir": { 1599 | "version": "0.6.2", 1600 | "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", 1601 | "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", 1602 | "dev": true, 1603 | "requires": { 1604 | "resolve": "^1.1.6" 1605 | } 1606 | }, 1607 | "regexpp": { 1608 | "version": "3.1.0", 1609 | "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", 1610 | "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", 1611 | "dev": true 1612 | }, 1613 | "require-directory": { 1614 | "version": "2.1.1", 1615 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 1616 | "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", 1617 | "dev": true 1618 | }, 1619 | "require-from-string": { 1620 | "version": "2.0.2", 1621 | "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", 1622 | "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", 1623 | "dev": true 1624 | }, 1625 | "resolve": { 1626 | "version": "1.20.0", 1627 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", 1628 | "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", 1629 | "dev": true, 1630 | "requires": { 1631 | "is-core-module": "^2.2.0", 1632 | "path-parse": "^1.0.6" 1633 | } 1634 | }, 1635 | "resolve-from": { 1636 | "version": "4.0.0", 1637 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", 1638 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", 1639 | "dev": true 1640 | }, 1641 | "reusify": { 1642 | "version": "1.0.4", 1643 | "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", 1644 | "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", 1645 | "dev": true 1646 | }, 1647 | "rimraf": { 1648 | "version": "2.7.1", 1649 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", 1650 | "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", 1651 | "dev": true, 1652 | "requires": { 1653 | "glob": "^7.1.3" 1654 | } 1655 | }, 1656 | "rollup": { 1657 | "version": "2.46.0", 1658 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.46.0.tgz", 1659 | "integrity": "sha512-qPGoUBNl+Z8uNu0z7pD3WPTABWRbcOwIrO/5ccDJzmrtzn0LVf6Lj91+L5CcWhXl6iWf23FQ6m8Jkl2CmN1O7Q==", 1660 | "dev": true, 1661 | "requires": { 1662 | "fsevents": "~2.3.1" 1663 | } 1664 | }, 1665 | "rollup-plugin-sucrase": { 1666 | "version": "2.1.0", 1667 | "resolved": "https://registry.npmjs.org/rollup-plugin-sucrase/-/rollup-plugin-sucrase-2.1.0.tgz", 1668 | "integrity": "sha512-chdA3OruR1FH/IIKrzZCpGKLXAx3DOHoK24RIPtlVccK0wbTpHE0HpGEQYCxte1XaB17NgRe/frFyKR7g45qxQ==", 1669 | "dev": true, 1670 | "requires": { 1671 | "rollup-pluginutils": "^2.3.0", 1672 | "sucrase": "3.x" 1673 | } 1674 | }, 1675 | "rollup-pluginutils": { 1676 | "version": "2.8.2", 1677 | "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", 1678 | "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", 1679 | "dev": true, 1680 | "requires": { 1681 | "estree-walker": "^0.6.1" 1682 | }, 1683 | "dependencies": { 1684 | "estree-walker": { 1685 | "version": "0.6.1", 1686 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", 1687 | "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", 1688 | "dev": true 1689 | } 1690 | } 1691 | }, 1692 | "run-parallel": { 1693 | "version": "1.2.0", 1694 | "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", 1695 | "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", 1696 | "dev": true, 1697 | "requires": { 1698 | "queue-microtask": "^1.2.2" 1699 | } 1700 | }, 1701 | "sade": { 1702 | "version": "1.7.4", 1703 | "resolved": "https://registry.npmjs.org/sade/-/sade-1.7.4.tgz", 1704 | "integrity": "sha512-y5yauMD93rX840MwUJr7C1ysLFBgMspsdTo4UVrDg3fXDvtwOyIqykhVAAm6fk/3au77773itJStObgK+LKaiA==", 1705 | "dev": true, 1706 | "requires": { 1707 | "mri": "^1.1.0" 1708 | } 1709 | }, 1710 | "safe-buffer": { 1711 | "version": "5.1.2", 1712 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 1713 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", 1714 | "dev": true 1715 | }, 1716 | "sander": { 1717 | "version": "0.6.0", 1718 | "resolved": "https://registry.npmjs.org/sander/-/sander-0.6.0.tgz", 1719 | "integrity": "sha1-rxYkzX+2362Y6+9WUxn5IAeNqSU=", 1720 | "dev": true, 1721 | "requires": { 1722 | "graceful-fs": "^4.1.3", 1723 | "mkdirp": "^0.5.1", 1724 | "rimraf": "^2.5.2" 1725 | } 1726 | }, 1727 | "semver": { 1728 | "version": "7.3.5", 1729 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", 1730 | "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", 1731 | "dev": true, 1732 | "requires": { 1733 | "lru-cache": "^6.0.0" 1734 | } 1735 | }, 1736 | "shebang-command": { 1737 | "version": "2.0.0", 1738 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 1739 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 1740 | "dev": true, 1741 | "requires": { 1742 | "shebang-regex": "^3.0.0" 1743 | } 1744 | }, 1745 | "shebang-regex": { 1746 | "version": "3.0.0", 1747 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", 1748 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", 1749 | "dev": true 1750 | }, 1751 | "shelljs": { 1752 | "version": "0.8.4", 1753 | "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz", 1754 | "integrity": "sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==", 1755 | "dev": true, 1756 | "requires": { 1757 | "glob": "^7.0.0", 1758 | "interpret": "^1.0.0", 1759 | "rechoir": "^0.6.2" 1760 | } 1761 | }, 1762 | "shiki": { 1763 | "version": "0.9.3", 1764 | "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.9.3.tgz", 1765 | "integrity": "sha512-NEjg1mVbAUrzRv2eIcUt3TG7X9svX7l3n3F5/3OdFq+/BxUdmBOeKGiH4icZJBLHy354Shnj6sfBTemea2e7XA==", 1766 | "dev": true, 1767 | "requires": { 1768 | "onigasm": "^2.2.5", 1769 | "vscode-textmate": "^5.2.0" 1770 | } 1771 | }, 1772 | "signal-exit": { 1773 | "version": "3.0.3", 1774 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", 1775 | "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", 1776 | "dev": true 1777 | }, 1778 | "slash": { 1779 | "version": "3.0.0", 1780 | "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", 1781 | "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", 1782 | "dev": true 1783 | }, 1784 | "slice-ansi": { 1785 | "version": "4.0.0", 1786 | "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", 1787 | "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", 1788 | "dev": true, 1789 | "requires": { 1790 | "ansi-styles": "^4.0.0", 1791 | "astral-regex": "^2.0.0", 1792 | "is-fullwidth-code-point": "^3.0.0" 1793 | }, 1794 | "dependencies": { 1795 | "ansi-styles": { 1796 | "version": "4.3.0", 1797 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 1798 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 1799 | "dev": true, 1800 | "requires": { 1801 | "color-convert": "^2.0.1" 1802 | } 1803 | }, 1804 | "color-convert": { 1805 | "version": "2.0.1", 1806 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 1807 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 1808 | "dev": true, 1809 | "requires": { 1810 | "color-name": "~1.1.4" 1811 | } 1812 | }, 1813 | "color-name": { 1814 | "version": "1.1.4", 1815 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 1816 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 1817 | "dev": true 1818 | } 1819 | } 1820 | }, 1821 | "source-map": { 1822 | "version": "0.6.1", 1823 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 1824 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 1825 | "dev": true 1826 | }, 1827 | "source-map-support": { 1828 | "version": "0.5.19", 1829 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", 1830 | "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", 1831 | "dev": true, 1832 | "requires": { 1833 | "buffer-from": "^1.0.0", 1834 | "source-map": "^0.6.0" 1835 | } 1836 | }, 1837 | "sprintf-js": { 1838 | "version": "1.0.3", 1839 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 1840 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 1841 | "dev": true 1842 | }, 1843 | "string-width": { 1844 | "version": "4.2.2", 1845 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", 1846 | "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", 1847 | "dev": true, 1848 | "requires": { 1849 | "emoji-regex": "^8.0.0", 1850 | "is-fullwidth-code-point": "^3.0.0", 1851 | "strip-ansi": "^6.0.0" 1852 | } 1853 | }, 1854 | "strip-ansi": { 1855 | "version": "6.0.0", 1856 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", 1857 | "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", 1858 | "dev": true, 1859 | "requires": { 1860 | "ansi-regex": "^5.0.0" 1861 | } 1862 | }, 1863 | "strip-json-comments": { 1864 | "version": "3.1.1", 1865 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", 1866 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", 1867 | "dev": true 1868 | }, 1869 | "sucrase": { 1870 | "version": "3.18.1", 1871 | "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.18.1.tgz", 1872 | "integrity": "sha512-TRyO38wwOPhLLlM8QLOG3TgMj0FKk+arlTrS9pRAanF8cAcHvgRPKIYWGO25mPSp/Rj87zMMTjFfkqIZGI6ZdA==", 1873 | "dev": true, 1874 | "requires": { 1875 | "commander": "^4.0.0", 1876 | "glob": "7.1.6", 1877 | "lines-and-columns": "^1.1.6", 1878 | "mz": "^2.7.0", 1879 | "pirates": "^4.0.1", 1880 | "ts-interface-checker": "^0.1.9" 1881 | } 1882 | }, 1883 | "supports-color": { 1884 | "version": "5.5.0", 1885 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 1886 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 1887 | "dev": true, 1888 | "requires": { 1889 | "has-flag": "^3.0.0" 1890 | } 1891 | }, 1892 | "svelte": { 1893 | "version": "3.37.0", 1894 | "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.37.0.tgz", 1895 | "integrity": "sha512-TRF30F4W4+d+Jr2KzUUL1j8Mrpns/WM/WacxYlo5MMb2E5Qy2Pk1Guj6GylxsW9OnKQl1tnF8q3hG/hQ3h6VUA==", 1896 | "dev": true 1897 | }, 1898 | "table": { 1899 | "version": "6.6.0", 1900 | "resolved": "https://registry.npmjs.org/table/-/table-6.6.0.tgz", 1901 | "integrity": "sha512-iZMtp5tUvcnAdtHpZTWLPF0M7AgiQsURR2DwmxnJwSy8I3+cY+ozzVvYha3BOLG2TB+L0CqjIz+91htuj6yCXg==", 1902 | "dev": true, 1903 | "requires": { 1904 | "ajv": "^8.0.1", 1905 | "lodash.clonedeep": "^4.5.0", 1906 | "lodash.flatten": "^4.4.0", 1907 | "lodash.truncate": "^4.4.2", 1908 | "slice-ansi": "^4.0.0", 1909 | "string-width": "^4.2.0", 1910 | "strip-ansi": "^6.0.0" 1911 | }, 1912 | "dependencies": { 1913 | "ajv": { 1914 | "version": "8.2.0", 1915 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.2.0.tgz", 1916 | "integrity": "sha512-WSNGFuyWd//XO8n/m/EaOlNLtO0yL8EXT/74LqT4khdhpZjP7lkj/kT5uwRmGitKEVp/Oj7ZUHeGfPtgHhQ5CA==", 1917 | "dev": true, 1918 | "requires": { 1919 | "fast-deep-equal": "^3.1.1", 1920 | "json-schema-traverse": "^1.0.0", 1921 | "require-from-string": "^2.0.2", 1922 | "uri-js": "^4.2.2" 1923 | } 1924 | }, 1925 | "json-schema-traverse": { 1926 | "version": "1.0.0", 1927 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", 1928 | "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", 1929 | "dev": true 1930 | } 1931 | } 1932 | }, 1933 | "test-exclude": { 1934 | "version": "6.0.0", 1935 | "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", 1936 | "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", 1937 | "dev": true, 1938 | "requires": { 1939 | "@istanbuljs/schema": "^0.1.2", 1940 | "glob": "^7.1.4", 1941 | "minimatch": "^3.0.4" 1942 | } 1943 | }, 1944 | "text-table": { 1945 | "version": "0.2.0", 1946 | "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", 1947 | "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", 1948 | "dev": true 1949 | }, 1950 | "thenify": { 1951 | "version": "3.3.1", 1952 | "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", 1953 | "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", 1954 | "dev": true, 1955 | "requires": { 1956 | "any-promise": "^1.0.0" 1957 | } 1958 | }, 1959 | "thenify-all": { 1960 | "version": "1.6.0", 1961 | "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", 1962 | "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", 1963 | "dev": true, 1964 | "requires": { 1965 | "thenify": ">= 3.1.0 < 4" 1966 | } 1967 | }, 1968 | "tiny-glob": { 1969 | "version": "0.2.8", 1970 | "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.8.tgz", 1971 | "integrity": "sha512-vkQP7qOslq63XRX9kMswlby99kyO5OvKptw7AMwBVMjXEI7Tb61eoI5DydyEMOseyGS5anDN1VPoVxEvH01q8w==", 1972 | "dev": true, 1973 | "requires": { 1974 | "globalyzer": "0.1.0", 1975 | "globrex": "^0.1.2" 1976 | } 1977 | }, 1978 | "to-regex-range": { 1979 | "version": "5.0.1", 1980 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1981 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1982 | "dev": true, 1983 | "requires": { 1984 | "is-number": "^7.0.0" 1985 | } 1986 | }, 1987 | "totalist": { 1988 | "version": "2.0.0", 1989 | "resolved": "https://registry.npmjs.org/totalist/-/totalist-2.0.0.tgz", 1990 | "integrity": "sha512-+Y17F0YzxfACxTyjfhnJQEe7afPA0GSpYlFkl2VFMxYP7jshQf9gXV7cH47EfToBumFThfKBvfAcoUn6fdNeRQ==", 1991 | "dev": true 1992 | }, 1993 | "ts-interface-checker": { 1994 | "version": "0.1.13", 1995 | "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", 1996 | "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", 1997 | "dev": true 1998 | }, 1999 | "ts-node": { 2000 | "version": "9.1.1", 2001 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz", 2002 | "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==", 2003 | "dev": true, 2004 | "requires": { 2005 | "arg": "^4.1.0", 2006 | "create-require": "^1.1.0", 2007 | "diff": "^4.0.1", 2008 | "make-error": "^1.1.1", 2009 | "source-map-support": "^0.5.17", 2010 | "yn": "3.1.1" 2011 | } 2012 | }, 2013 | "tslib": { 2014 | "version": "1.14.1", 2015 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", 2016 | "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", 2017 | "dev": true 2018 | }, 2019 | "tsutils": { 2020 | "version": "3.21.0", 2021 | "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", 2022 | "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", 2023 | "dev": true, 2024 | "requires": { 2025 | "tslib": "^1.8.1" 2026 | } 2027 | }, 2028 | "type-check": { 2029 | "version": "0.4.0", 2030 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", 2031 | "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", 2032 | "dev": true, 2033 | "requires": { 2034 | "prelude-ls": "^1.2.1" 2035 | } 2036 | }, 2037 | "type-fest": { 2038 | "version": "0.8.1", 2039 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", 2040 | "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", 2041 | "dev": true 2042 | }, 2043 | "typedoc": { 2044 | "version": "0.20.36", 2045 | "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.20.36.tgz", 2046 | "integrity": "sha512-qFU+DWMV/hifQ9ZAlTjdFO9wbUIHuUBpNXzv68ZyURAP9pInjZiO4+jCPeAzHVcaBCHER9WL/+YzzTt6ZlN/Nw==", 2047 | "dev": true, 2048 | "requires": { 2049 | "colors": "^1.4.0", 2050 | "fs-extra": "^9.1.0", 2051 | "handlebars": "^4.7.7", 2052 | "lodash": "^4.17.21", 2053 | "lunr": "^2.3.9", 2054 | "marked": "^2.0.3", 2055 | "minimatch": "^3.0.0", 2056 | "progress": "^2.0.3", 2057 | "shelljs": "^0.8.4", 2058 | "shiki": "^0.9.3", 2059 | "typedoc-default-themes": "^0.12.10" 2060 | } 2061 | }, 2062 | "typedoc-default-themes": { 2063 | "version": "0.12.10", 2064 | "resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.12.10.tgz", 2065 | "integrity": "sha512-fIS001cAYHkyQPidWXmHuhs8usjP5XVJjWB8oZGqkTowZaz3v7g3KDZeeqE82FBrmkAnIBOY3jgy7lnPnqATbA==", 2066 | "dev": true 2067 | }, 2068 | "typescript": { 2069 | "version": "4.2.4", 2070 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz", 2071 | "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==", 2072 | "dev": true 2073 | }, 2074 | "uglify-js": { 2075 | "version": "3.13.5", 2076 | "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.5.tgz", 2077 | "integrity": "sha512-xtB8yEqIkn7zmOyS2zUNBsYCBRhDkvlNxMMY2smuJ/qA8NCHeQvKCF3i9Z4k8FJH4+PJvZRtMrPynfZ75+CSZw==", 2078 | "dev": true, 2079 | "optional": true 2080 | }, 2081 | "universalify": { 2082 | "version": "2.0.0", 2083 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", 2084 | "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", 2085 | "dev": true 2086 | }, 2087 | "uri-js": { 2088 | "version": "4.4.1", 2089 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", 2090 | "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", 2091 | "dev": true, 2092 | "requires": { 2093 | "punycode": "^2.1.0" 2094 | } 2095 | }, 2096 | "uvu": { 2097 | "version": "0.5.1", 2098 | "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.1.tgz", 2099 | "integrity": "sha512-JGxttnOGDFs77FaZ0yMUHIzczzQ5R1IlDeNW6Wymw6gAscwMdAffVOP6TlxLIfReZyK8tahoGwWZaTCJzNFDkg==", 2100 | "dev": true, 2101 | "requires": { 2102 | "dequal": "^2.0.0", 2103 | "diff": "^5.0.0", 2104 | "kleur": "^4.0.3", 2105 | "sade": "^1.7.3", 2106 | "totalist": "^2.0.0" 2107 | }, 2108 | "dependencies": { 2109 | "diff": { 2110 | "version": "5.0.0", 2111 | "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", 2112 | "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", 2113 | "dev": true 2114 | } 2115 | } 2116 | }, 2117 | "v8-compile-cache": { 2118 | "version": "2.3.0", 2119 | "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", 2120 | "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", 2121 | "dev": true 2122 | }, 2123 | "v8-to-istanbul": { 2124 | "version": "7.1.1", 2125 | "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.1.tgz", 2126 | "integrity": "sha512-p0BB09E5FRjx0ELN6RgusIPsSPhtgexSRcKETybEs6IGOTXJSZqfwxp7r//55nnu0f1AxltY5VvdVqy2vZf9AA==", 2127 | "dev": true, 2128 | "requires": { 2129 | "@types/istanbul-lib-coverage": "^2.0.1", 2130 | "convert-source-map": "^1.6.0", 2131 | "source-map": "^0.7.3" 2132 | }, 2133 | "dependencies": { 2134 | "source-map": { 2135 | "version": "0.7.3", 2136 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", 2137 | "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", 2138 | "dev": true 2139 | } 2140 | } 2141 | }, 2142 | "vscode-textmate": { 2143 | "version": "5.4.0", 2144 | "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.4.0.tgz", 2145 | "integrity": "sha512-c0Q4zYZkcLizeYJ3hNyaVUM2AA8KDhNCA3JvXY8CeZSJuBdAy3bAvSbv46RClC4P3dSO9BdwhnKEx2zOo6vP/w==", 2146 | "dev": true 2147 | }, 2148 | "which": { 2149 | "version": "2.0.2", 2150 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 2151 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 2152 | "dev": true, 2153 | "requires": { 2154 | "isexe": "^2.0.0" 2155 | } 2156 | }, 2157 | "word-wrap": { 2158 | "version": "1.2.3", 2159 | "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", 2160 | "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", 2161 | "dev": true 2162 | }, 2163 | "wordwrap": { 2164 | "version": "1.0.0", 2165 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", 2166 | "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", 2167 | "dev": true 2168 | }, 2169 | "wrap-ansi": { 2170 | "version": "7.0.0", 2171 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 2172 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 2173 | "dev": true, 2174 | "requires": { 2175 | "ansi-styles": "^4.0.0", 2176 | "string-width": "^4.1.0", 2177 | "strip-ansi": "^6.0.0" 2178 | }, 2179 | "dependencies": { 2180 | "ansi-styles": { 2181 | "version": "4.3.0", 2182 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 2183 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 2184 | "dev": true, 2185 | "requires": { 2186 | "color-convert": "^2.0.1" 2187 | } 2188 | }, 2189 | "color-convert": { 2190 | "version": "2.0.1", 2191 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 2192 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 2193 | "dev": true, 2194 | "requires": { 2195 | "color-name": "~1.1.4" 2196 | } 2197 | }, 2198 | "color-name": { 2199 | "version": "1.1.4", 2200 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 2201 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 2202 | "dev": true 2203 | } 2204 | } 2205 | }, 2206 | "wrappy": { 2207 | "version": "1.0.2", 2208 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 2209 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 2210 | "dev": true 2211 | }, 2212 | "y18n": { 2213 | "version": "5.0.8", 2214 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", 2215 | "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", 2216 | "dev": true 2217 | }, 2218 | "yallist": { 2219 | "version": "4.0.0", 2220 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", 2221 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", 2222 | "dev": true 2223 | }, 2224 | "yargs": { 2225 | "version": "16.2.0", 2226 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", 2227 | "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", 2228 | "dev": true, 2229 | "requires": { 2230 | "cliui": "^7.0.2", 2231 | "escalade": "^3.1.1", 2232 | "get-caller-file": "^2.0.5", 2233 | "require-directory": "^2.1.1", 2234 | "string-width": "^4.2.0", 2235 | "y18n": "^5.0.5", 2236 | "yargs-parser": "^20.2.2" 2237 | } 2238 | }, 2239 | "yargs-parser": { 2240 | "version": "20.2.7", 2241 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.7.tgz", 2242 | "integrity": "sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==", 2243 | "dev": true 2244 | }, 2245 | "yn": { 2246 | "version": "3.1.1", 2247 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", 2248 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", 2249 | "dev": true 2250 | }, 2251 | "yocto-queue": { 2252 | "version": "0.1.0", 2253 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", 2254 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", 2255 | "dev": true 2256 | } 2257 | } 2258 | } 2259 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "svelte-entity-store", 3 | "version": "1.0.3", 4 | "description": "Normalized entity store for Svelte projects", 5 | "main": "dist/index.js", 6 | "module": "dist/index.mjs", 7 | "types": "dist/index.d.ts", 8 | "files": [ 9 | "dist" 10 | ], 11 | "keywords": [ 12 | "svelte", 13 | "store", 14 | "state", 15 | "entity", 16 | "reactive" 17 | ], 18 | "engines": { 19 | "node": ">= 10" 20 | }, 21 | "scripts": { 22 | "doc": "typedoc", 23 | "lint": "eslint src/ --ext .ts", 24 | "build-declarations": "tsc -d && node scripts/move-type-declarations.js", 25 | "build": "npm run build-declarations && rollup -c", 26 | "dev": "rollup -cw", 27 | "test": "uvu -r ts-node/register tests", 28 | "test:coverage": "c8 --include=src npm test", 29 | "test:report": "c8 report --reporter=text-lcov > coverage.lcov", 30 | "prepublishOnly": "npm run build" 31 | }, 32 | "repository": { 33 | "type": "git", 34 | "url": "git+https://github.com/tony-sull/svelte-entity-store.git" 35 | }, 36 | "author": "Tony Sullivan", 37 | "license": "MIT", 38 | "bugs": { 39 | "url": "https://github.com/tony-sull/svelte-entity-store/issues" 40 | }, 41 | "homepage": "https://github.com/tony-sull/svelte-entity-store#readme", 42 | "devDependencies": { 43 | "@rollup/plugin-node-resolve": "^11.2.1", 44 | "@typescript-eslint/eslint-plugin": "^4.22.0", 45 | "@typescript-eslint/parser": "^4.22.0", 46 | "c8": "^7.7.1", 47 | "eslint": "^7.25.0", 48 | "eslint-config-prettier": "^8.3.0", 49 | "eslint-plugin-prettier": "^3.4.0", 50 | "prettier": "^2.2.1", 51 | "rollup": "^2.46.0", 52 | "rollup-plugin-sucrase": "^2.1.0", 53 | "sander": "^0.6.0", 54 | "svelte": "^3.37.0", 55 | "tiny-glob": "^0.2.8", 56 | "ts-node": "^9.1.1", 57 | "typedoc": "^0.20.36", 58 | "typescript": "^4.2.4", 59 | "uvu": "^0.5.1" 60 | }, 61 | "dependencies": {} 62 | } 63 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import sucrase from 'rollup-plugin-sucrase' 2 | import resolve from '@rollup/plugin-node-resolve' 3 | import pkg from './package.json' 4 | 5 | export default { 6 | input: 'src/index.ts', 7 | output: [ 8 | { file: pkg.main, format: 'cjs' }, 9 | { file: pkg.module, format: 'esm' }, 10 | ], 11 | plugins: [ 12 | resolve(), 13 | sucrase({ 14 | transforms: ['typescript'], 15 | }), 16 | ], 17 | } 18 | -------------------------------------------------------------------------------- /scripts/move-type-declarations.js: -------------------------------------------------------------------------------- 1 | const sander = require('sander'); 2 | const glob = require('tiny-glob/sync'); 3 | 4 | for (const file of glob('src/**/*.js')) { 5 | sander.unlinkSync(file); 6 | } 7 | 8 | sander.rimrafSync('types'); 9 | for (const file of glob('src/**/*.d.ts')) { 10 | sander.renameSync(file).to(file.replace(/^src/, 'types')); 11 | } -------------------------------------------------------------------------------- /src/entity-store.ts: -------------------------------------------------------------------------------- 1 | import { derived, Updater, writable } from 'svelte/store' 2 | import { getEntities } from './internal/get-entities' 3 | import { normalize } from './internal/normalize' 4 | import { removeEntities } from './internal/remove-entities' 5 | import { setEntities } from './internal/set-entities' 6 | import { updateEntities } from './internal/update-entities' 7 | import type { Readable, Subscriber, Unsubscriber } from 'svelte/store' 8 | import type { Normalized } from './internal/normalize' 9 | import type { ID, GetID, Predicate } from './shared' 10 | 11 | declare type Invalidator = (value?: T) => void 12 | declare type Subscribe = (this: void, run: Subscriber, invalidate?: Invalidator) => Unsubscriber 13 | 14 | /** 15 | * Simple Svelte store that normalized data by ID and provides helpers for common data access patterns. 16 | */ 17 | export type EntityStore = { 18 | /** 19 | * Gets a derived store containing every entity in the store. 20 | * 21 | * @returns Array of all entities 22 | */ 23 | get(): Readable 24 | 25 | /** 26 | * Gets a derived store containing the entity if the ID is found, or undefined otherwise. 27 | * 28 | * @param id ID of the entity to find 29 | * @returns Entity object if found, undefined otherwise 30 | */ 31 | get(id: ID): Readable 32 | 33 | /** 34 | * Gets a derived store containing a list of all entities found by ID. 35 | * IDs that aren't found in the store are ignored. The list of entities is not guaranteed to be the same length as the list of IDs. 36 | * 37 | * @param ids Array of IDs to find 38 | * @returns Array of found entities 39 | */ 40 | get(ids: ID[]): Readable 41 | 42 | /** 43 | * Gets a derived store containing a list of all entities in the store that match 44 | * the filter function. 45 | * 46 | * @param pred Filter function 47 | * @returns Array of all entities matching the filter function 48 | */ 49 | get(pred: Predicate): Readable 50 | 51 | /** 52 | * Removes the entity from the store, if found. 53 | * 54 | * @param id {ID} ID of the entity to remove 55 | */ 56 | remove(id: ID): void 57 | 58 | /** 59 | * Removes the given entities from the store, if found. 60 | * 61 | * @param ids Array of IDs to remove from the store 62 | */ 63 | remove(ids: ID[]): void 64 | 65 | /** 66 | * Removes an entity from the store, if found. 67 | * 68 | * @param entity The entity to remove 69 | */ 70 | remove(entity: T): void 71 | 72 | /** 73 | * Removes multiple entities from the store, if found. 74 | * 75 | * @param entities Array of entities to remove 76 | */ 77 | remove(entities: T[]): void 78 | 79 | /** 80 | * Removes all entities that match the filter function. 81 | * 82 | * @param pred Filter function which returns true for each entity to be removed 83 | */ 84 | remove(pred: Predicate): void 85 | 86 | /** 87 | * Removes all entities from the store. 88 | */ 89 | reset(): void 90 | 91 | /** 92 | * Adds the given entity to the store. If the entity is already in the store, their old value is replaced. 93 | * 94 | * @param entity Entity to be added or updated 95 | */ 96 | set(entity: T): void 97 | 98 | /** 99 | * Adds the given entities to the store. For entities that are already in the store, their old value is replaced. 100 | * 101 | * @param entities Entity or entities to be added or updated 102 | */ 103 | set(entities: T | T[]): void 104 | 105 | /** 106 | * See (Svelte's docs)[https://svelte.dev/docs#svelte_store] for details on the Store contract and `subscribe` function. 107 | */ 108 | subscribe: Subscribe> 109 | 110 | /** 111 | * Runs every entity through the updater function and stores the new state. 112 | * 113 | * @param updater Callback to update the entity 114 | */ 115 | update(updater: Updater): void 116 | 117 | /** 118 | * If found, runs the entity through the updater function and stores the new state. 119 | * 120 | * @param updater Callback to update the entity 121 | * @param id ID of the entity to update 122 | */ 123 | update(updater: Updater, id: ID): void 124 | 125 | /** 126 | * Runs the matching entity through the updater function and stores the new state. 127 | * 128 | * @param updater Callback to update each entity 129 | * @param ids IDs of the entities to update 130 | */ 131 | update(updater: Updater, ids: ID[]): void 132 | 133 | /** 134 | * If found, runs the entity through the updater function and stores the new state. 135 | * 136 | * @param updater Callback to update the entity 137 | * @param entity The entity to update 138 | */ 139 | update(updater: Updater, entity: T): void 140 | 141 | /** 142 | * Runs each existing entity through the updater function and stores the new state. 143 | * 144 | * @param updater Callback to update each entity 145 | * @param entities Array of the entities to update 146 | */ 147 | update(updater: Updater, entities: T[]): void 148 | 149 | /** 150 | * Runs each matching entity through the updater function and stores the new state. 151 | * 152 | * @param updater Callback to update each entity 153 | * @param pred Filter function that returns true for each entity to update 154 | */ 155 | update(updater: Updater, pred: Predicate): void 156 | } 157 | 158 | /** 159 | * Creates a new entity store. 160 | * 161 | * @typeParam T Entity type being stored 162 | * @param getID Function that returns the ID of an entity 163 | * @param initial (optional) Initial array of items to be stored 164 | */ 165 | export function entityStore(getID: GetID, initial: T[] = []): EntityStore { 166 | const normalizeT = normalize(getID) 167 | const removeEntitiesT = removeEntities(getID) 168 | const setEntitiesT = setEntities(getID) 169 | const updateEntitiesT = updateEntities(getID) 170 | 171 | const store = writable(normalizeT(initial)) 172 | 173 | const reset = () => store.set(normalizeT([])) 174 | 175 | const set = (entities: T | T[]) => { 176 | const toAdd = [].concat(entities) 177 | 178 | if (toAdd.length > 0) { 179 | store.update(setEntitiesT(toAdd)) 180 | } 181 | } 182 | 183 | function get(): Readable 184 | function get(id: ID): Readable 185 | function get(ids: ID[]): Readable 186 | function get(pred: Predicate): Readable 187 | function get(input?: ID | ID[] | Predicate): Readable | Readable { 188 | if (!input) { 189 | return derived(store, getEntities()) 190 | } else if (Array.isArray(input)) { 191 | return derived(store, getEntities(input)) 192 | } else if (input instanceof Function) { 193 | return derived(store, getEntities(input)) 194 | } else { 195 | return derived(store, getEntities(input)) 196 | } 197 | } 198 | 199 | function remove(id: ID): void 200 | function remove(ids: ID[]): void 201 | function remove(entity: T): void 202 | function remove(entity: T[]): void 203 | function remove(pred: Predicate): void 204 | function remove(input: ID | ID[] | T | T[] | Predicate): void { 205 | store.update(removeEntitiesT(input)) 206 | } 207 | 208 | function update(updater: Updater): void 209 | function update(updater: Updater, id: ID): void 210 | function update(updater: Updater, ids: ID[]): void 211 | function update(updater: Updater, entity: T): void 212 | function update(updater: Updater, entiites: T[]): void 213 | function update(updater: Updater, pred: Predicate): void 214 | function update(updater: Updater, input?: ID | ID[] | T | T[] | Predicate): void { 215 | store.update(updateEntitiesT(updater)(input)) 216 | } 217 | 218 | return { 219 | get, 220 | remove, 221 | reset, 222 | set, 223 | subscribe: store.subscribe, 224 | update, 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export { entityStore } from './entity-store' 2 | -------------------------------------------------------------------------------- /src/internal/get-entities.ts: -------------------------------------------------------------------------------- 1 | import type { Normalized } from './normalize' 2 | import type { ID, Predicate } from '../shared' 3 | 4 | /** 5 | * Gets an array of all entities in the state 6 | */ 7 | export function getEntities(): (state: Normalized) => T[] 8 | 9 | /** 10 | * Finds an entity by ID 11 | * 12 | * @param id ID of the entity to find 13 | * @returns Entity object if found, undefined otherwise 14 | */ 15 | export function getEntities(id: ID): (state: Normalized) => T | undefined 16 | 17 | /** 18 | * Finds multiple entities by ID. Note that IDs will be ignored if the entity isn't found, 19 | * the array returned may not be the same length as the input array. 20 | * 21 | * @param ids Array of IDs to find 22 | * @returns Array of found entities 23 | */ 24 | export function getEntities(ids: ID[]): (state: Normalized) => T[] 25 | 26 | /** 27 | * Finds all entities that match the filter function. 28 | * 29 | * @param pred Filter function 30 | * @returns Array of entities matching the filter function 31 | */ 32 | export function getEntities(pred: Predicate): (state: Normalized) => T[] 33 | 34 | export function getEntities(input?: ID | ID[] | Predicate) { 35 | return function (state: Normalized): T | T[] { 36 | if (!input) { 37 | return state.allIds.map((id) => state.byId[id]) 38 | } else if (Array.isArray(input)) { 39 | return input.map((id) => state.byId[id]).filter(Boolean) 40 | } else if (input instanceof Function) { 41 | return state.allIds.map((id) => state.byId[id]).filter(input) 42 | } else { 43 | return state.byId[input] 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/internal/normalize.ts: -------------------------------------------------------------------------------- 1 | import { GetID, ID } from '../shared' 2 | 3 | /** 4 | * Normalized state tracking entities by ID 5 | */ 6 | export type Normalized = { 7 | /** 8 | * Map of entities by ID. EntityStore supports `string` and `number` ID types 9 | */ 10 | byId: { 11 | [id: string]: T 12 | [id: number]: T 13 | } 14 | /** 15 | * List of all entities IDs, sorted in the order they were added 16 | */ 17 | allIds: ID[] 18 | } 19 | 20 | /** 21 | * Takes a list of elements and normalizes them by ID 22 | * 23 | * @typeParam T Entity type being stored 24 | * @param getID Function that returns the ID of an entity 25 | * @returns Noramlized state holding the given items 26 | */ 27 | export const normalize = (getID: GetID) => (items: T[]): Normalized => { 28 | return items.reduce( 29 | ({ byId, allIds }, next) => { 30 | const id = getID(next) 31 | 32 | byId[id] = next 33 | allIds.push(id) 34 | 35 | return { byId, allIds } 36 | }, 37 | { byId: {}, allIds: [] } as Normalized, 38 | ) 39 | } 40 | -------------------------------------------------------------------------------- /src/internal/remove-entities.ts: -------------------------------------------------------------------------------- 1 | import { getEntities } from './get-entities' 2 | import type { Normalized } from './normalize' 3 | import { GetID, ID, isID, Predicate } from '../shared' 4 | 5 | export function removeEntities( 6 | getId: GetID, 7 | ): (input: ID | ID[] | T | T[] | Predicate) => (state: Normalized) => Normalized { 8 | /** 9 | * Removes an entity by ID, if found. 10 | * 11 | * @param id ID of the entity to remove 12 | */ 13 | function withInput(id: ID): (state: Normalized) => Normalized 14 | 15 | /** 16 | * Removes one or more entities from the state, if found. 17 | * 18 | * @param ids Array of IDs to remove 19 | */ 20 | function withInput(ids: ID[]): (state: Normalized) => Normalized 21 | 22 | /** 23 | * Removes an entity object from the store, if found. 24 | * 25 | * @param entity Entity object to be removed 26 | */ 27 | function withInput(entity: T): (state: Normalized) => Normalized 28 | 29 | /** 30 | * Removes multiple entities from the store, if found. 31 | * 32 | * @param entities Array of entity objects to be removed 33 | */ 34 | function withInput(entities: T[]): (state: Normalized) => Normalized 35 | 36 | /** 37 | * Removes all entities that match the filter function. 38 | * 39 | * @param pred Filter function that returns true for every entity that should be removed 40 | */ 41 | function withInput(pred: Predicate): (state: Normalized) => Normalized 42 | 43 | function withInput(input: ID | ID[] | T | T[] | Predicate) { 44 | return function fromState(state: Normalized): Normalized { 45 | let toRemove: T[] 46 | 47 | if (Array.isArray(input)) { 48 | const ids = input.map((i: ID | T) => (isID(i) ? i : getId(i))) 49 | toRemove = getEntities(ids)(state) 50 | } else if (input instanceof Function) { 51 | toRemove = getEntities(input)(state) 52 | } else { 53 | const id = isID(input) ? input : getId(input) 54 | toRemove = [getEntities(id)(state)].filter(Boolean) 55 | } 56 | 57 | return toRemove.reduce( 58 | ({ byId, allIds }, next) => { 59 | const id = getId(next) 60 | delete byId[id] 61 | 62 | return { 63 | byId, 64 | allIds: allIds.filter((i) => i !== id), 65 | } 66 | }, 67 | { 68 | byId: { ...state.byId }, 69 | allIds: [...state.allIds], 70 | }, 71 | ) 72 | } 73 | } 74 | 75 | return withInput 76 | } 77 | -------------------------------------------------------------------------------- /src/internal/set-entities.ts: -------------------------------------------------------------------------------- 1 | import type { Normalized } from './normalize' 2 | import type { GetID } from '../shared' 3 | 4 | /** 5 | * Adds or updates the given entities to the normalized state. Entities already in the state or replaced, new entities are added. 6 | */ 7 | export const setEntities = (getId: GetID) => (items: T | T[]) => (state: Normalized): Normalized => { 8 | return [].concat(items).reduce(({ byId, allIds }, next) => { 9 | const id = getId(next) 10 | const exists = id in byId 11 | 12 | return { 13 | byId: { ...byId, [id]: next }, 14 | allIds: exists ? allIds : allIds.concat(id), 15 | } 16 | }, state) 17 | } 18 | -------------------------------------------------------------------------------- /src/internal/update-entities.ts: -------------------------------------------------------------------------------- 1 | import { getEntities } from './get-entities' 2 | import { isID } from '../shared' 3 | import type { Updater } from 'svelte/store' 4 | import type { Normalized } from './normalize' 5 | import type { GetID, ID, Predicate } from '../shared' 6 | 7 | export function updateEntities( 8 | getId: GetID, 9 | ): (updater: Updater) => (input?: ID | ID[] | T | T[] | Predicate) => (state: Normalized) => Normalized { 10 | return function withUpdater(updater: Updater) { 11 | function withInput(): (state: Normalized) => Normalized 12 | function withInput(id: ID): (state: Normalized) => Normalized 13 | function withInput(ids: ID[]): (state: Normalized) => Normalized 14 | function withInput(entity: T): (state: Normalized) => Normalized 15 | function withInput(entities: T[]): (state: Normalized) => Normalized 16 | function withInput(pred: Predicate): (state: Normalized) => Normalized 17 | 18 | function withInput(input?: ID | ID[] | T | T[] | Predicate) { 19 | return function fromState(state: Normalized): Normalized { 20 | let toUpdate: T[] 21 | 22 | if (!input) { 23 | toUpdate = getEntities()(state) 24 | } else if (Array.isArray(input)) { 25 | const ids = input.map((i: ID | T) => (isID(i) ? i : getId(i))) 26 | toUpdate = getEntities(ids)(state) 27 | } else if (input instanceof Function) { 28 | toUpdate = getEntities(input)(state) 29 | } else { 30 | const id = isID(input) ? input : getId(input) 31 | toUpdate = [].concat(getEntities(id)(state)) 32 | } 33 | 34 | return toUpdate.reduce(({ byId, allIds }, next) => { 35 | const id = getId(next) 36 | 37 | return { 38 | byId: { 39 | ...byId, 40 | [id]: updater(next), 41 | }, 42 | allIds, 43 | } 44 | }, state) 45 | } 46 | } 47 | 48 | return withInput 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/shared.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * EntityStore supports `string` and `number` values for unique IDs 3 | */ 4 | export type ID = string | number 5 | 6 | /** 7 | * Type guard used to check if any value is a valid entity ID 8 | * 9 | * @param value {unknown} 10 | * @returns {boolean} true if the value is an ID (string or number), false otherwise 11 | */ 12 | export function isID(value: unknown): value is ID { 13 | const type = typeof value 14 | 15 | return type === 'string' || type === 'number' 16 | } 17 | 18 | /** 19 | * Function used to get the unique ID of an entity 20 | */ 21 | export type GetID = (t: T) => ID 22 | 23 | /** 24 | * Predicate used for filtering entities 25 | */ 26 | export type Predicate = (t: T) => boolean 27 | -------------------------------------------------------------------------------- /tests/entity-store.ts: -------------------------------------------------------------------------------- 1 | import { get as svelteGet } from 'svelte/store' 2 | import { suite } from 'uvu' 3 | import * as assert from 'uvu/assert' 4 | import { entityStore } from '../src/entity-store' 5 | import { Normalized } from '../src/internal/normalize' 6 | 7 | type Entity = { 8 | id: string 9 | description: string 10 | completed: boolean 11 | } 12 | 13 | const getID = (e: Entity) => e.id 14 | const isCompleted = (e: Entity) => e.completed 15 | const toggle = (e: Entity) => ({ ...e, completed: !e.completed }) 16 | 17 | // --- 18 | 19 | const constructor = suite('constructor') 20 | 21 | constructor('is a function', () => { 22 | assert.type(entityStore, 'function') 23 | }) 24 | 25 | constructor('returns a subscriber function', () => { 26 | const store = entityStore(getID) 27 | 28 | assert.type(store, 'object') 29 | assert.type(store.subscribe, 'function') 30 | }) 31 | 32 | constructor("doesn't require initial state", () => { 33 | const store = entityStore(getID) 34 | const state = svelteGet(store) 35 | 36 | assert.equal(state, { 37 | byId: {}, 38 | allIds: [], 39 | }) 40 | }) 41 | 42 | constructor('normalizes initial items array', () => { 43 | const items: Entity[] = [ 44 | { id: 'abc', description: 'item 1', completed: false }, 45 | { id: 'def', description: 'item 2', completed: true }, 46 | ] 47 | const store = entityStore(getID, items) 48 | const state = svelteGet(store) 49 | 50 | assert.equal(state, { 51 | byId: { 52 | abc: items[0], 53 | def: items[1], 54 | }, 55 | allIds: ['abc', 'def'], 56 | }) 57 | }) 58 | 59 | constructor.run() 60 | 61 | // --- 62 | 63 | const reset = suite('reset') 64 | 65 | reset('is a function', () => { 66 | const { reset } = entityStore(getID) 67 | assert.type(reset, 'function') 68 | }) 69 | 70 | reset('noop for an empty store', () => { 71 | const store = entityStore(getID) 72 | store.reset() 73 | 74 | const state = svelteGet(store) 75 | 76 | assert.equal(state, { byId: {}, allIds: [] }) 77 | }) 78 | 79 | reset('removes all existing entities', () => { 80 | const items: Entity[] = [ 81 | { id: 'abc', description: 'item 1', completed: false }, 82 | { id: 'def', description: 'item 2', completed: true }, 83 | ] 84 | const store = entityStore(getID, items) 85 | store.reset() 86 | 87 | const state = svelteGet(store) 88 | 89 | assert.equal(state, { byId: {}, allIds: [] }) 90 | }) 91 | 92 | reset("doesn't trigger subscribers for empty store", () => { 93 | const store = entityStore(getID) 94 | 95 | let states: Normalized[] 96 | const unsubscribe = store.subscribe((state) => states.push(state)) 97 | 98 | store.reset() 99 | 100 | assert.is(states.length, 1) 101 | 102 | unsubscribe() 103 | }) 104 | 105 | // --- 106 | 107 | const set = suite('set') 108 | 109 | set('is a function', () => { 110 | const { set } = entityStore(getID) 111 | assert.type(set, 'function') 112 | }) 113 | 114 | set('accepts a single entity', () => { 115 | const store = entityStore(getID) 116 | const entity: Entity = { id: 'abc', description: 'item 1', completed: false } 117 | 118 | store.set(entity) 119 | 120 | const state = svelteGet(store) 121 | 122 | assert.equal(state, { 123 | byId: { 124 | abc: entity, 125 | }, 126 | allIds: ['abc'], 127 | }) 128 | }) 129 | 130 | set('accepts an array of entities', () => { 131 | const store = entityStore(getID) 132 | const entities: Entity[] = [ 133 | { id: 'abc', description: 'item 1', completed: false }, 134 | { id: 'def', description: 'item 2', completed: true }, 135 | ] 136 | 137 | store.set(entities) 138 | 139 | const state = svelteGet(store) 140 | 141 | assert.equal(state, { 142 | byId: { 143 | abc: entities[0], 144 | def: entities[1], 145 | }, 146 | allIds: ['abc', 'def'], 147 | }) 148 | }) 149 | 150 | set('updates an existing entity', () => { 151 | const entities: Entity[] = [ 152 | { id: 'abc', description: 'item 1', completed: false }, 153 | { id: 'def', description: 'item 2', completed: true }, 154 | ] 155 | const store = entityStore(getID, entities) 156 | 157 | store.set({ ...entities[0], completed: true }) 158 | 159 | const state = svelteGet(store) 160 | 161 | assert.equal(state, { 162 | byId: { 163 | abc: { ...entities[0], completed: true }, 164 | def: entities[1], 165 | }, 166 | allIds: ['abc', 'def'], 167 | }) 168 | }) 169 | 170 | set('handles a combination of new and existing entities', () => { 171 | const entities: Entity[] = [ 172 | { id: 'abc', description: 'item 1', completed: false }, 173 | { id: 'def', description: 'item 2', completed: true }, 174 | ] 175 | const store = entityStore(getID, entities) 176 | 177 | const input: Entity[] = [ 178 | { ...entities[0], completed: true }, 179 | { id: 'ghi', description: 'item 3', completed: false }, 180 | ] 181 | 182 | store.set(input) 183 | 184 | const state = svelteGet(store) 185 | 186 | assert.equal(state, { 187 | byId: { 188 | abc: { ...entities[0], completed: true }, 189 | def: entities[1], 190 | ghi: input[1], 191 | }, 192 | allIds: ['abc', 'def', 'ghi'], 193 | }) 194 | }) 195 | 196 | set('calls subscribers once after all entities are updated', () => { 197 | const entities: Entity[] = [ 198 | { id: 'abc', description: 'item 1', completed: false }, 199 | { id: 'def', description: 'item 2', completed: true }, 200 | ] 201 | const store = entityStore(getID, entities) 202 | 203 | const input: Entity[] = [ 204 | { ...entities[0], completed: true }, 205 | { id: 'ghi', description: 'item 3', completed: false }, 206 | ] 207 | 208 | const states: Normalized[] = [] 209 | const unsubscribe = store.subscribe((state) => states.push(state)) 210 | 211 | store.set(input) 212 | 213 | assert.equal(states, [ 214 | { 215 | byId: { 216 | abc: entities[0], 217 | def: entities[1], 218 | }, 219 | allIds: ['abc', 'def'], 220 | }, 221 | { 222 | byId: { 223 | abc: { ...entities[0], completed: true }, 224 | def: entities[1], 225 | ghi: input[1], 226 | }, 227 | allIds: ['abc', 'def', 'ghi'], 228 | }, 229 | ]) 230 | 231 | unsubscribe() 232 | }) 233 | 234 | set("doesn't call subscribers if an empty array was provided", () => { 235 | const entities: Entity[] = [ 236 | { id: 'abc', description: 'item 1', completed: false }, 237 | { id: 'def', description: 'item 2', completed: true }, 238 | ] 239 | const store = entityStore(getID, entities) 240 | 241 | const states: Normalized[] = [] 242 | const unsubscribe = store.subscribe((state) => states.push(state)) 243 | 244 | store.set([]) 245 | 246 | assert.equal(states, [ 247 | { 248 | byId: { 249 | abc: entities[0], 250 | def: entities[1], 251 | }, 252 | allIds: ['abc', 'def'], 253 | }, 254 | ]) 255 | 256 | unsubscribe() 257 | }) 258 | 259 | set.run() 260 | 261 | // --- 262 | 263 | const get = suite('get') 264 | 265 | get('is a function', () => { 266 | const { get } = entityStore(getID) 267 | assert.type(get, 'function') 268 | }) 269 | 270 | get('accepts no params', () => { 271 | const entities: Entity[] = [ 272 | { id: 'abc', description: 'item 1', completed: false }, 273 | { id: 'def', description: 'item 2', completed: true }, 274 | { id: 'ghi', description: 'item 3', completed: false }, 275 | ] 276 | const { get } = entityStore(getID, entities) 277 | 278 | const $entities = get() 279 | const state = svelteGet($entities) 280 | 281 | assert.equal(state, entities) 282 | }) 283 | 284 | get('accepts a single ID', () => { 285 | const { get } = entityStore(getID) 286 | const $entity = get('abc') 287 | 288 | const state = svelteGet($entity) 289 | 290 | assert.type($entity.subscribe, 'function') 291 | assert.type(state, 'undefined') 292 | }) 293 | 294 | get('accepts an array of IDs', () => { 295 | const { get } = entityStore(getID) 296 | const $entities = get(['abc', 'def']) 297 | 298 | const state = svelteGet($entities) 299 | 300 | assert.type($entities.subscribe, 'function') 301 | assert.ok(Array.isArray(state)) 302 | }) 303 | 304 | get('accepts a filter function', () => { 305 | const { get } = entityStore(getID) 306 | const $entities = get(isCompleted) 307 | 308 | const state = svelteGet($entities) 309 | 310 | assert.type($entities.subscribe, 'function') 311 | assert.ok(Array.isArray(state)) 312 | }) 313 | 314 | get('returns a known entity by ID', () => { 315 | const entity: Entity = { id: 'abc', description: 'item 1', completed: false } 316 | const { get } = entityStore(getID, [entity]) 317 | 318 | const $entity = get(entity.id) 319 | const state = svelteGet($entity) 320 | 321 | assert.equal(state, entity) 322 | }) 323 | 324 | get('returns all known entities for given IDs', () => { 325 | const entities: Entity[] = [ 326 | { id: 'abc', description: 'item 1', completed: false }, 327 | { id: 'def', description: 'item 2', completed: true }, 328 | { id: 'ghi', description: 'item 3', completed: false }, 329 | ] 330 | const { get } = entityStore(getID, entities) 331 | 332 | const $entities = get(['abc', 'ghi']) 333 | const state = svelteGet($entities) 334 | 335 | assert.equal(state, [entities[0], entities[2]]) 336 | }) 337 | 338 | get('ignores unknown IDs', () => { 339 | const entities: Entity[] = [ 340 | { id: 'abc', description: 'item 1', completed: false }, 341 | { id: 'def', description: 'item 2', completed: true }, 342 | { id: 'ghi', description: 'item 3', completed: false }, 343 | ] 344 | const { get } = entityStore(getID, entities) 345 | 346 | const $entities = get(['abc', 'jkl', 'ghi']) 347 | const state = svelteGet($entities) 348 | 349 | assert.equal(state, [entities[0], entities[2]]) 350 | }) 351 | 352 | get('returns all entities matching the filter', () => { 353 | const entities: Entity[] = [ 354 | { id: 'abc', description: 'item 1', completed: false }, 355 | { id: 'def', description: 'item 2', completed: true }, 356 | { id: 'ghi', description: 'item 3', completed: false }, 357 | ] 358 | const { get } = entityStore(getID, entities) 359 | 360 | const $entities = get(isCompleted) 361 | const state = svelteGet($entities) 362 | 363 | assert.equal(state, [entities[1]]) 364 | }) 365 | 366 | get('returns an empty array if no entities match the filter', () => { 367 | const entities: Entity[] = [ 368 | { id: 'abc', description: 'item 1', completed: false }, 369 | { id: 'def', description: 'item 2', completed: false }, 370 | { id: 'ghi', description: 'item 3', completed: false }, 371 | ] 372 | const { get } = entityStore(getID, entities) 373 | 374 | const $entities = get(isCompleted) 375 | const state = svelteGet($entities) 376 | 377 | assert.equal(state, []) 378 | }) 379 | 380 | get('updates subscribers when entity is removed', () => { 381 | const entities: Entity[] = [ 382 | { id: 'abc', description: 'item 1', completed: false }, 383 | { id: 'def', description: 'item 2', completed: true }, 384 | { id: 'ghi', description: 'item 3', completed: false }, 385 | ] 386 | const store = entityStore(getID, entities) 387 | 388 | const $entity = store.get('abc') 389 | 390 | const states: Array = [] 391 | const unsubscribe = $entity.subscribe((state) => states.push(state)) 392 | 393 | store.reset() 394 | 395 | assert.equal(states, [entities[0], undefined]) 396 | 397 | unsubscribe() 398 | }) 399 | 400 | get.run() 401 | 402 | // --- 403 | 404 | const remove = suite('remove') 405 | 406 | remove('is a function', () => { 407 | const { remove } = entityStore(getID) 408 | assert.type(remove, 'function') 409 | }) 410 | 411 | remove('accepts a single ID', () => { 412 | const entity: Entity = { id: 'abc', description: 'item 1', completed: false } 413 | const store = entityStore(getID, [entity]) 414 | 415 | store.remove('abc') 416 | 417 | const state = svelteGet(store) 418 | 419 | assert.equal(state, { byId: {}, allIds: [] }) 420 | }) 421 | 422 | remove('accepts an array of IDs', () => { 423 | const entities: Entity[] = [ 424 | { id: 'abc', description: 'item 1', completed: false }, 425 | { id: 'def', description: 'item 2', completed: false }, 426 | { id: 'ghi', description: 'item 3', completed: false }, 427 | ] 428 | const store = entityStore(getID, entities) 429 | 430 | store.remove(['abc']) 431 | 432 | const state = svelteGet(store) 433 | 434 | assert.equal(state, { 435 | byId: { 436 | def: entities[1], 437 | ghi: entities[2], 438 | }, 439 | allIds: ['def', 'ghi'], 440 | }) 441 | }) 442 | 443 | remove('accepts a single entity', () => { 444 | const entity: Entity = { id: 'abc', description: 'item 1', completed: false } 445 | const store = entityStore(getID, [entity]) 446 | 447 | store.remove(entity) 448 | 449 | const state = svelteGet(store) 450 | 451 | assert.equal(state, { byId: {}, allIds: [] }) 452 | }) 453 | 454 | remove('accepts an array of entities', () => { 455 | const entities: Entity[] = [ 456 | { id: 'abc', description: 'item 1', completed: false }, 457 | { id: 'def', description: 'item 2', completed: false }, 458 | { id: 'ghi', description: 'item 3', completed: false }, 459 | ] 460 | const store = entityStore(getID, entities) 461 | 462 | store.remove([entities[0]]) 463 | 464 | const state = svelteGet(store) 465 | 466 | assert.equal(state, { 467 | byId: { 468 | def: entities[1], 469 | ghi: entities[2], 470 | }, 471 | allIds: ['def', 'ghi'], 472 | }) 473 | }) 474 | 475 | remove('accepts a filter function', () => { 476 | const entities: Entity[] = [ 477 | { id: 'abc', description: 'item 1', completed: true }, 478 | { id: 'def', description: 'item 2', completed: false }, 479 | { id: 'ghi', description: 'item 3', completed: false }, 480 | ] 481 | const store = entityStore(getID, entities) 482 | 483 | store.remove(isCompleted) 484 | 485 | const state = svelteGet(store) 486 | 487 | assert.equal(state, { 488 | byId: { 489 | def: entities[1], 490 | ghi: entities[2], 491 | }, 492 | allIds: ['def', 'ghi'], 493 | }) 494 | }) 495 | 496 | remove('updates subscribers once', () => { 497 | const entities: Entity[] = [ 498 | { id: 'abc', description: 'item 1', completed: true }, 499 | { id: 'def', description: 'item 2', completed: false }, 500 | { id: 'ghi', description: 'item 3', completed: false }, 501 | ] 502 | const store = entityStore(getID, entities) 503 | 504 | const states: Normalized[] = [] 505 | const unsubscribe = store.subscribe((state) => states.push(state)) 506 | 507 | store.remove(isCompleted) 508 | 509 | assert.equal(states, [ 510 | { 511 | byId: { 512 | abc: entities[0], 513 | def: entities[1], 514 | ghi: entities[2], 515 | }, 516 | allIds: ['abc', 'def', 'ghi'], 517 | }, 518 | { 519 | byId: { 520 | def: entities[1], 521 | ghi: entities[2], 522 | }, 523 | allIds: ['def', 'ghi'], 524 | }, 525 | ]) 526 | 527 | unsubscribe() 528 | }) 529 | 530 | remove.run() 531 | 532 | // --- 533 | 534 | const update = suite('update') 535 | 536 | update('is a function', () => { 537 | const { update } = entityStore(getID) 538 | assert.type(update, 'function') 539 | }) 540 | 541 | update('accepts no parameters', () => { 542 | const entities: Entity[] = [ 543 | { id: 'abc', description: 'item 1', completed: false }, 544 | { id: 'def', description: 'item 2', completed: false }, 545 | { id: 'ghi', description: 'item 3', completed: false }, 546 | ] 547 | const store = entityStore(getID, entities) 548 | 549 | store.update(toggle) 550 | 551 | const state = svelteGet(store) 552 | 553 | assert.equal(state, { 554 | byId: { 555 | abc: { id: 'abc', description: 'item 1', completed: true }, 556 | def: { id: 'def', description: 'item 2', completed: true }, 557 | ghi: { id: 'ghi', description: 'item 3', completed: true }, 558 | }, 559 | allIds: ['abc', 'def', 'ghi'], 560 | }) 561 | }) 562 | 563 | update('accepts a single ID', () => { 564 | const entities: Entity[] = [ 565 | { id: 'abc', description: 'item 1', completed: false }, 566 | { id: 'def', description: 'item 2', completed: false }, 567 | { id: 'ghi', description: 'item 3', completed: false }, 568 | ] 569 | const store = entityStore(getID, entities) 570 | 571 | store.update(toggle, 'abc') 572 | 573 | const state = svelteGet(store) 574 | 575 | assert.equal(state, { 576 | byId: { 577 | abc: { id: 'abc', description: 'item 1', completed: true }, 578 | def: entities[1], 579 | ghi: entities[2], 580 | }, 581 | allIds: ['abc', 'def', 'ghi'], 582 | }) 583 | }) 584 | 585 | update('accepts a single entity', () => { 586 | const entities: Entity[] = [ 587 | { id: 'abc', description: 'item 1', completed: false }, 588 | { id: 'def', description: 'item 2', completed: false }, 589 | { id: 'ghi', description: 'item 3', completed: false }, 590 | ] 591 | const store = entityStore(getID, entities) 592 | 593 | store.update(toggle, entities[0]) 594 | 595 | const state = svelteGet(store) 596 | 597 | assert.equal(state, { 598 | byId: { 599 | abc: { id: 'abc', description: 'item 1', completed: true }, 600 | def: entities[1], 601 | ghi: entities[2], 602 | }, 603 | allIds: ['abc', 'def', 'ghi'], 604 | }) 605 | }) 606 | 607 | update('accepts an array of IDs', () => { 608 | const entities: Entity[] = [ 609 | { id: 'abc', description: 'item 1', completed: false }, 610 | { id: 'def', description: 'item 2', completed: false }, 611 | { id: 'ghi', description: 'item 3', completed: false }, 612 | ] 613 | const store = entityStore(getID, entities) 614 | 615 | store.update(toggle, ['abc', 'ghi']) 616 | 617 | const state = svelteGet(store) 618 | 619 | assert.equal(state, { 620 | byId: { 621 | abc: { id: 'abc', description: 'item 1', completed: true }, 622 | def: entities[1], 623 | ghi: { id: 'ghi', description: 'item 3', completed: true }, 624 | }, 625 | allIds: ['abc', 'def', 'ghi'], 626 | }) 627 | }) 628 | 629 | update('accepts an array of entities', () => { 630 | const entities: Entity[] = [ 631 | { id: 'abc', description: 'item 1', completed: false }, 632 | { id: 'def', description: 'item 2', completed: false }, 633 | { id: 'ghi', description: 'item 3', completed: false }, 634 | ] 635 | const store = entityStore(getID, entities) 636 | 637 | store.update(toggle, [entities[0], entities[2]]) 638 | 639 | const state = svelteGet(store) 640 | 641 | assert.equal(state, { 642 | byId: { 643 | abc: { id: 'abc', description: 'item 1', completed: true }, 644 | def: entities[1], 645 | ghi: { id: 'ghi', description: 'item 3', completed: true }, 646 | }, 647 | allIds: ['abc', 'def', 'ghi'], 648 | }) 649 | }) 650 | 651 | update('accepts a filter function', () => { 652 | const entities: Entity[] = [ 653 | { id: 'abc', description: 'item 1', completed: false }, 654 | { id: 'def', description: 'item 2', completed: true }, 655 | { id: 'ghi', description: 'item 3', completed: true }, 656 | ] 657 | const store = entityStore(getID, entities) 658 | 659 | store.update(toggle, isCompleted) 660 | 661 | const state = svelteGet(store) 662 | 663 | assert.equal(state, { 664 | byId: { 665 | abc: entities[0], 666 | def: { id: 'def', description: 'item 2', completed: false }, 667 | ghi: { id: 'ghi', description: 'item 3', completed: false }, 668 | }, 669 | allIds: ['abc', 'def', 'ghi'], 670 | }) 671 | }) 672 | 673 | update('updates subscribers once', () => { 674 | const entities: Entity[] = [ 675 | { id: 'abc', description: 'item 1', completed: false }, 676 | { id: 'def', description: 'item 2', completed: true }, 677 | { id: 'ghi', description: 'item 3', completed: true }, 678 | ] 679 | const store = entityStore(getID, entities) 680 | 681 | const states: Normalized[] = [] 682 | const unsubscribe = store.subscribe((state) => states.push(state)) 683 | 684 | store.update(toggle, isCompleted) 685 | 686 | assert.equal(states, [ 687 | { 688 | byId: { 689 | abc: entities[0], 690 | def: entities[1], 691 | ghi: entities[2], 692 | }, 693 | allIds: ['abc', 'def', 'ghi'], 694 | }, 695 | { 696 | byId: { 697 | abc: entities[0], 698 | def: { id: 'def', description: 'item 2', completed: false }, 699 | ghi: { id: 'ghi', description: 'item 3', completed: false }, 700 | }, 701 | allIds: ['abc', 'def', 'ghi'], 702 | }, 703 | ]) 704 | 705 | unsubscribe() 706 | }) 707 | 708 | update.run() 709 | 710 | // --- 711 | -------------------------------------------------------------------------------- /tests/index.ts: -------------------------------------------------------------------------------- 1 | import { test } from 'uvu' 2 | import * as assert from 'uvu/assert' 3 | import { entityStore } from '../src' 4 | 5 | test('exports the entityStore constructor', () => { 6 | assert.type(entityStore, 'function') 7 | }) 8 | 9 | test.run() 10 | -------------------------------------------------------------------------------- /tests/internal/get-entities.ts: -------------------------------------------------------------------------------- 1 | import { test } from 'uvu' 2 | import * as assert from 'uvu/assert' 3 | import { getEntities } from '../../src/internal/get-entities' 4 | import { Normalized } from '../../src/internal/normalize' 5 | 6 | type Entity = { 7 | id: string 8 | description: string 9 | completed: boolean 10 | } 11 | 12 | const isCompleted = (e: Entity) => e.completed 13 | 14 | test('is a function', () => { 15 | assert.type(getEntities, 'function') 16 | }) 17 | 18 | test('returns all entities if given no parameters', () => { 19 | const state: Normalized = { 20 | byId: { 21 | abc: { id: 'abc', description: 'item 1', completed: false }, 22 | def: { id: 'def', description: 'item 2', completed: true }, 23 | ghi: { id: 'ghi', description: 'item 3', completed: false }, 24 | }, 25 | allIds: ['abc', 'def', 'ghi'], 26 | } 27 | 28 | const result = getEntities()(state) 29 | 30 | assert.equal(result, [state.byId.abc, state.byId.def, state.byId.ghi]) 31 | }) 32 | 33 | test('accepts a single ID', () => { 34 | const state: Normalized = { 35 | byId: { 36 | abc: { id: 'abc', description: 'item 1', completed: false }, 37 | }, 38 | allIds: ['abc'], 39 | } 40 | 41 | const result = getEntities('abc')(state) 42 | 43 | assert.equal(result, state.byId.abc) 44 | }) 45 | 46 | test('returns undefined for an unknown ID', () => { 47 | const state: Normalized = { 48 | byId: { 49 | abc: { id: 'abc', description: 'item 1', completed: false }, 50 | }, 51 | allIds: ['abc'], 52 | } 53 | 54 | const result = getEntities('def')(state) 55 | 56 | assert.is(result, undefined) 57 | }) 58 | 59 | test('accepts an array of IDs', () => { 60 | const state: Normalized = { 61 | byId: { 62 | abc: { id: 'abc', description: 'item 1', completed: false }, 63 | def: { id: 'def', description: 'item 2', completed: true }, 64 | ghi: { id: 'ghi', description: 'item 3', completed: false }, 65 | }, 66 | allIds: ['abc', 'def', 'ghi'], 67 | } 68 | 69 | const result = getEntities(['abc', 'ghi'])(state) 70 | 71 | assert.equal(result, [state.byId.abc, state.byId.ghi]) 72 | }) 73 | 74 | test('ignores unknown IDs from an array', () => { 75 | const state: Normalized = { 76 | byId: { 77 | abc: { id: 'abc', description: 'item 1', completed: false }, 78 | def: { id: 'def', description: 'item 2', completed: true }, 79 | ghi: { id: 'ghi', description: 'item 3', completed: false }, 80 | }, 81 | allIds: ['abc', 'def', 'ghi'], 82 | } 83 | 84 | const result = getEntities(['abc', 'jkl'])(state) 85 | 86 | assert.equal(result, [state.byId.abc]) 87 | }) 88 | 89 | test('accepts a filter function', () => { 90 | const state: Normalized = { 91 | byId: { 92 | abc: { id: 'abc', description: 'item 1', completed: false }, 93 | def: { id: 'def', description: 'item 2', completed: true }, 94 | ghi: { id: 'ghi', description: 'item 3', completed: true }, 95 | }, 96 | allIds: ['abc', 'def', 'ghi'], 97 | } 98 | 99 | const result = getEntities(isCompleted)(state) 100 | 101 | assert.equal(result, [state.byId.def, state.byId.ghi]) 102 | }) 103 | 104 | test('returns an empty array if no entities match filter', () => { 105 | const state: Normalized = { 106 | byId: { 107 | abc: { id: 'abc', description: 'item 1', completed: false }, 108 | def: { id: 'def', description: 'item 2', completed: false }, 109 | ghi: { id: 'ghi', description: 'item 3', completed: false }, 110 | }, 111 | allIds: ['abc', 'def', 'ghi'], 112 | } 113 | 114 | const result = getEntities(isCompleted)(state) 115 | 116 | assert.equal(result, []) 117 | }) 118 | 119 | test.run() 120 | -------------------------------------------------------------------------------- /tests/internal/normalize.ts: -------------------------------------------------------------------------------- 1 | import { test } from 'uvu' 2 | import * as assert from 'uvu/assert' 3 | import { normalize } from '../../src/internal/normalize' 4 | 5 | type Entity = { 6 | id: string 7 | description: string 8 | } 9 | 10 | const getID = (e: Entity) => e.id 11 | 12 | test('is a function', () => { 13 | assert.type(normalize, 'function') 14 | }) 15 | 16 | test('handles an empty array', () => { 17 | const state = normalize(getID)([]) 18 | 19 | assert.equal(state, { 20 | byId: {}, 21 | allIds: [], 22 | }) 23 | }) 24 | 25 | test('handles an array of one item', () => { 26 | const item: Entity = { id: 'abc', description: 'item 1' } 27 | 28 | const state = normalize(getID)([item]) 29 | 30 | assert.equal(state, { 31 | byId: { 32 | abc: item, 33 | }, 34 | allIds: ['abc'], 35 | }) 36 | }) 37 | 38 | test('maintains item order', () => { 39 | const items: Entity[] = [ 40 | { id: 'abc', description: 'item 1' }, 41 | { id: 'def', description: 'item 2' }, 42 | ] 43 | 44 | const state = normalize(getID)(items) 45 | 46 | assert.equal(state, { 47 | byId: { 48 | abc: items[0], 49 | def: items[1], 50 | }, 51 | allIds: ['abc', 'def'], 52 | }) 53 | }) 54 | 55 | test.run() 56 | -------------------------------------------------------------------------------- /tests/internal/remove-entities.ts: -------------------------------------------------------------------------------- 1 | import { test } from 'uvu' 2 | import * as assert from 'uvu/assert' 3 | import { removeEntities } from '../../src/internal/remove-entities' 4 | import { Normalized } from '../../src/internal/normalize' 5 | 6 | type Entity = { 7 | id: string 8 | description: string 9 | completed: boolean 10 | } 11 | 12 | const getId = (e: Entity) => e.id 13 | const isCompleted = (e: Entity) => e.completed 14 | 15 | const removeEntitiesT = removeEntities(getId) 16 | 17 | test('is a function', () => { 18 | assert.type(removeEntities, 'function') 19 | }) 20 | 21 | test('accepts a single ID', () => { 22 | const state: Normalized = { 23 | byId: { 24 | abc: { id: 'abc', description: 'item 1', completed: false }, 25 | }, 26 | allIds: ['abc'], 27 | } 28 | const result = removeEntitiesT('abc')(state) 29 | 30 | assert.equal(result, { byId: {}, allIds: [] }) 31 | }) 32 | 33 | test('accepts an array of IDs', () => { 34 | const state: Normalized = { 35 | byId: { 36 | abc: { id: 'abc', description: 'item 1', completed: false }, 37 | def: { id: 'def', description: 'item 2', completed: false }, 38 | ghi: { id: 'ghi', description: 'item 3', completed: true }, 39 | }, 40 | allIds: ['abc', 'def', 'ghi'], 41 | } 42 | const result = removeEntitiesT(['abc', 'ghi'])(state) 43 | 44 | assert.equal(result, { 45 | byId: { 46 | def: state.byId.def, 47 | }, 48 | allIds: ['def'], 49 | }) 50 | }) 51 | 52 | test('accepts an entity object', () => { 53 | const state: Normalized = { 54 | byId: { 55 | abc: { id: 'abc', description: 'item 1', completed: false }, 56 | def: { id: 'def', description: 'item 2', completed: false }, 57 | ghi: { id: 'ghi', description: 'item 3', completed: true }, 58 | }, 59 | allIds: ['abc', 'def', 'ghi'], 60 | } 61 | const result = removeEntitiesT(state.byId.abc)(state) 62 | 63 | assert.equal(result, { 64 | byId: { 65 | def: state.byId.def, 66 | ghi: state.byId.ghi, 67 | }, 68 | allIds: ['def', 'ghi'], 69 | }) 70 | }) 71 | 72 | test('accepts an array of entity objects', () => { 73 | const state: Normalized = { 74 | byId: { 75 | abc: { id: 'abc', description: 'item 1', completed: false }, 76 | def: { id: 'def', description: 'item 2', completed: false }, 77 | ghi: { id: 'ghi', description: 'item 3', completed: true }, 78 | }, 79 | allIds: ['abc', 'def', 'ghi'], 80 | } 81 | const result = removeEntitiesT([state.byId.abc, state.byId.ghi])(state) 82 | 83 | assert.equal(result, { 84 | byId: { 85 | def: state.byId.def, 86 | }, 87 | allIds: ['def'], 88 | }) 89 | }) 90 | 91 | test('accepts a filter function', () => { 92 | const state: Normalized = { 93 | byId: { 94 | abc: { id: 'abc', description: 'item 1', completed: true }, 95 | def: { id: 'def', description: 'item 2', completed: false }, 96 | ghi: { id: 'ghi', description: 'item 3', completed: true }, 97 | }, 98 | allIds: ['abc', 'def', 'ghi'], 99 | } 100 | const result = removeEntitiesT(isCompleted)(state) 101 | 102 | assert.equal(result, { 103 | byId: { 104 | def: state.byId.def, 105 | }, 106 | allIds: ['def'], 107 | }) 108 | }) 109 | 110 | test('ignores unknown ID', () => { 111 | const state: Normalized = { 112 | byId: { 113 | abc: { id: 'abc', description: 'item 1', completed: false }, 114 | }, 115 | allIds: ['abc'], 116 | } 117 | const result = removeEntitiesT('def')(state) 118 | 119 | assert.equal(result, state) 120 | }) 121 | 122 | test('ignores unknown IDs in an array', () => { 123 | const state: Normalized = { 124 | byId: { 125 | abc: { id: 'abc', description: 'item 1', completed: false }, 126 | def: { id: 'def', description: 'item 2', completed: false }, 127 | ghi: { id: 'ghi', description: 'item 3', completed: true }, 128 | }, 129 | allIds: ['abc', 'def', 'ghi'], 130 | } 131 | const result = removeEntitiesT(['jkl', 'ghi'])(state) 132 | 133 | assert.equal(result, { 134 | byId: { 135 | abc: state.byId.abc, 136 | def: state.byId.def, 137 | }, 138 | allIds: ['abc', 'def'], 139 | }) 140 | }) 141 | 142 | test('ignores an unknown entity', () => { 143 | const state: Normalized = { 144 | byId: { 145 | abc: { id: 'abc', description: 'item 1', completed: false }, 146 | }, 147 | allIds: ['abc'], 148 | } 149 | const result = removeEntitiesT({ 150 | id: 'def', 151 | description: 'item 2', 152 | completed: false, 153 | })(state) 154 | 155 | assert.equal(result, state) 156 | }) 157 | 158 | test('ignores unknown entities in an array', () => { 159 | const state: Normalized = { 160 | byId: { 161 | abc: { id: 'abc', description: 'item 1', completed: false }, 162 | def: { id: 'def', description: 'item 2', completed: false }, 163 | ghi: { id: 'ghi', description: 'item 3', completed: true }, 164 | }, 165 | allIds: ['abc', 'def', 'ghi'], 166 | } 167 | const result = removeEntitiesT([ 168 | { 169 | id: 'jkl', 170 | description: 'item 4', 171 | completed: false, 172 | }, 173 | state.byId.ghi, 174 | ])(state) 175 | 176 | assert.equal(result, { 177 | byId: { 178 | abc: state.byId.abc, 179 | def: state.byId.def, 180 | }, 181 | allIds: ['abc', 'def'], 182 | }) 183 | }) 184 | 185 | test.run() 186 | -------------------------------------------------------------------------------- /tests/internal/set-entities.ts: -------------------------------------------------------------------------------- 1 | import { test } from 'uvu' 2 | import * as assert from 'uvu/assert' 3 | import { setEntities } from '../../src/internal/set-entities' 4 | 5 | type Entity = { 6 | id: string 7 | description: string 8 | } 9 | 10 | const getId = (e: Entity) => e.id 11 | 12 | const setEntitiesT = setEntities(getId) 13 | 14 | test('is a function', () => { 15 | assert.type(setEntities, 'function') 16 | }) 17 | 18 | test('accepts a single entity', () => { 19 | const initial = { byId: {}, allIds: [] } 20 | const entity: Entity = { id: 'abc', description: 'item 1' } 21 | 22 | const result = setEntitiesT(entity)(initial) 23 | 24 | assert.equal(result, { byId: { abc: entity }, allIds: ['abc'] }) 25 | }) 26 | 27 | test('accepts an array of entities', () => { 28 | const initial = { byId: {}, allIds: [] } 29 | const entities: Entity[] = [ 30 | { id: 'abc', description: 'item 1' }, 31 | { id: 'def', description: 'item 2' }, 32 | ] 33 | 34 | const result = setEntitiesT(entities)(initial) 35 | 36 | assert.equal(result, { 37 | byId: { 38 | abc: entities[0], 39 | def: entities[1], 40 | }, 41 | allIds: ['abc', 'def'], 42 | }) 43 | }) 44 | 45 | test('replaces existing entities', () => { 46 | const initial = { 47 | byId: { 48 | abc: { id: 'abc', description: 'item 1' }, 49 | def: { id: 'def', description: 'item 2' }, 50 | }, 51 | allIds: ['abc', 'def'], 52 | } 53 | const entity: Entity = { id: 'abc', description: 'item 10' } 54 | 55 | const result = setEntitiesT(entity)(initial) 56 | 57 | assert.equal(result, { 58 | byId: { 59 | abc: entity, 60 | def: initial.byId.def, 61 | }, 62 | allIds: initial.allIds, 63 | }) 64 | }) 65 | 66 | test('handles a mix of existing and new entities', () => { 67 | const initial = { 68 | byId: { 69 | abc: { id: 'abc', description: 'item 1' }, 70 | def: { id: 'def', description: 'item 2' }, 71 | }, 72 | allIds: ['abc', 'def'], 73 | } 74 | const entities: Entity[] = [ 75 | { id: 'abc', description: 'item 10' }, 76 | { id: 'ghi', description: 'item 3' }, 77 | ] 78 | 79 | const result = setEntitiesT(entities)(initial) 80 | 81 | assert.equal(result, { 82 | byId: { 83 | abc: entities[0], 84 | def: initial.byId.def, 85 | ghi: entities[1], 86 | }, 87 | allIds: initial.allIds.concat(entities[1].id), 88 | }) 89 | }) 90 | 91 | test('noop for an empty array', () => { 92 | const initial = { 93 | byId: { 94 | abc: { id: 'abc', description: 'item 1' }, 95 | def: { id: 'def', description: 'item 2' }, 96 | }, 97 | allIds: ['abc', 'def'], 98 | } 99 | 100 | const result = setEntitiesT([])(initial) 101 | 102 | assert.equal(initial, result) 103 | }) 104 | 105 | test.run() 106 | -------------------------------------------------------------------------------- /tests/internal/update-entities.ts: -------------------------------------------------------------------------------- 1 | import { test } from 'uvu' 2 | import * as assert from 'uvu/assert' 3 | import { updateEntities } from '../../src/internal/update-entities' 4 | import type { Normalized } from '../../src/internal/normalize' 5 | 6 | type Entity = { 7 | id: string 8 | description: string 9 | completed: boolean 10 | } 11 | 12 | const getId = (e: Entity) => e.id 13 | const isCompleted = (e: Entity) => e.completed 14 | const toggle = (e: Entity) => ({ ...e, completed: !e.completed }) 15 | 16 | const updateEntitiesT = updateEntities(getId) 17 | 18 | test('is a function', () => { 19 | assert.type(updateEntities, 'function') 20 | }) 21 | 22 | test('accepts no parameters', () => { 23 | const state: Normalized = { 24 | byId: { 25 | abc: { id: 'abc', description: 'item 1', completed: false }, 26 | def: { id: 'def', description: 'item 2', completed: false }, 27 | ghi: { id: 'ghi', description: 'item 3', completed: false }, 28 | }, 29 | allIds: ['abc', 'def', 'ghi'], 30 | } 31 | 32 | const result = updateEntitiesT(toggle)()(state) 33 | 34 | assert.equal(result, { 35 | byId: { 36 | abc: { id: 'abc', description: 'item 1', completed: true }, 37 | def: { id: 'def', description: 'item 2', completed: true }, 38 | ghi: { id: 'ghi', description: 'item 3', completed: true }, 39 | }, 40 | allIds: ['abc', 'def', 'ghi'], 41 | }) 42 | }) 43 | 44 | test('accepts a single ID', () => { 45 | const state: Normalized = { 46 | byId: { 47 | abc: { id: 'abc', description: 'item 1', completed: false }, 48 | def: { id: 'def', description: 'item 2', completed: false }, 49 | ghi: { id: 'ghi', description: 'item 3', completed: false }, 50 | }, 51 | allIds: ['abc', 'def', 'ghi'], 52 | } 53 | 54 | const result = updateEntitiesT(toggle)('abc')(state) 55 | 56 | assert.equal(result, { 57 | byId: { 58 | abc: { id: 'abc', description: 'item 1', completed: true }, 59 | def: { id: 'def', description: 'item 2', completed: false }, 60 | ghi: { id: 'ghi', description: 'item 3', completed: false }, 61 | }, 62 | allIds: ['abc', 'def', 'ghi'], 63 | }) 64 | }) 65 | 66 | test('accepts a single entity', () => { 67 | const state: Normalized = { 68 | byId: { 69 | abc: { id: 'abc', description: 'item 1', completed: false }, 70 | def: { id: 'def', description: 'item 2', completed: false }, 71 | ghi: { id: 'ghi', description: 'item 3', completed: false }, 72 | }, 73 | allIds: ['abc', 'def', 'ghi'], 74 | } 75 | 76 | const result = updateEntitiesT(toggle)(state.byId.abc)(state) 77 | 78 | assert.equal(result, { 79 | byId: { 80 | abc: { id: 'abc', description: 'item 1', completed: true }, 81 | def: { id: 'def', description: 'item 2', completed: false }, 82 | ghi: { id: 'ghi', description: 'item 3', completed: false }, 83 | }, 84 | allIds: ['abc', 'def', 'ghi'], 85 | }) 86 | }) 87 | 88 | test('accepts an array of IDs', () => { 89 | const state: Normalized = { 90 | byId: { 91 | abc: { id: 'abc', description: 'item 1', completed: false }, 92 | def: { id: 'def', description: 'item 2', completed: false }, 93 | ghi: { id: 'ghi', description: 'item 3', completed: false }, 94 | }, 95 | allIds: ['abc', 'def', 'ghi'], 96 | } 97 | 98 | const result = updateEntitiesT(toggle)(['abc', 'ghi'])(state) 99 | 100 | assert.equal(result, { 101 | byId: { 102 | abc: { id: 'abc', description: 'item 1', completed: true }, 103 | def: { id: 'def', description: 'item 2', completed: false }, 104 | ghi: { id: 'ghi', description: 'item 3', completed: true }, 105 | }, 106 | allIds: ['abc', 'def', 'ghi'], 107 | }) 108 | }) 109 | 110 | test('accepts an array of entities', () => { 111 | const state: Normalized = { 112 | byId: { 113 | abc: { id: 'abc', description: 'item 1', completed: false }, 114 | def: { id: 'def', description: 'item 2', completed: false }, 115 | ghi: { id: 'ghi', description: 'item 3', completed: false }, 116 | }, 117 | allIds: ['abc', 'def', 'ghi'], 118 | } 119 | 120 | const result = updateEntitiesT(toggle)([state.byId.abc, state.byId.ghi])(state) 121 | 122 | assert.equal(result, { 123 | byId: { 124 | abc: { id: 'abc', description: 'item 1', completed: true }, 125 | def: { id: 'def', description: 'item 2', completed: false }, 126 | ghi: { id: 'ghi', description: 'item 3', completed: true }, 127 | }, 128 | allIds: ['abc', 'def', 'ghi'], 129 | }) 130 | }) 131 | 132 | test('accepts a filter function', () => { 133 | const state: Normalized = { 134 | byId: { 135 | abc: { id: 'abc', description: 'item 1', completed: false }, 136 | def: { id: 'def', description: 'item 2', completed: true }, 137 | ghi: { id: 'ghi', description: 'item 3', completed: true }, 138 | }, 139 | allIds: ['abc', 'def', 'ghi'], 140 | } 141 | 142 | const result = updateEntitiesT(toggle)(isCompleted)(state) 143 | 144 | assert.equal(result, { 145 | byId: { 146 | abc: { id: 'abc', description: 'item 1', completed: false }, 147 | def: { id: 'def', description: 'item 2', completed: false }, 148 | ghi: { id: 'ghi', description: 'item 3', completed: false }, 149 | }, 150 | allIds: ['abc', 'def', 'ghi'], 151 | }) 152 | }) 153 | 154 | test.run() 155 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "ts-node": { 3 | "transpileOnly": true, 4 | "compilerOptions": { 5 | "module": "commonjs" 6 | }, 7 | "include": [ 8 | "tests/**/*" 9 | ] 10 | }, 11 | "compilerOptions": { 12 | "noImplicitAny": true, 13 | "noImplicitThis": true, 14 | "noEmitOnError": true, 15 | "diagnostics": true, 16 | "outDir": "dist", 17 | "target": "esnext", 18 | "module": "esnext", 19 | "declaration": true, 20 | "moduleResolution": "node", 21 | "forceConsistentCasingInFileNames": true 22 | }, 23 | "include": [ 24 | "@types/**/*", 25 | "src/**/*" 26 | ], 27 | "exclude": [ 28 | "node_modules" 29 | ] 30 | } -------------------------------------------------------------------------------- /typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "entryPoints": [ 3 | "src/" 4 | ], 5 | "out": "docs" 6 | } --------------------------------------------------------------------------------