├── .gitignore ├── .npmignore ├── .prettierrc.json ├── LICENSE ├── README.md ├── package.json ├── pnpm-lock.yaml ├── src ├── index.ts ├── lib │ ├── parameterized-query.ts │ ├── parameterized-value.ts │ └── parameterizer.ts ├── tests │ ├── delete-params.test.ts │ ├── insert-params.test.ts │ ├── select-params.test.ts │ └── update-params.test.ts └── utils │ ├── test-setup.ts │ ├── test-tables.ts │ └── test-utils.ts ├── tsconfig.cjs.json ├── tsconfig.json └── vitest.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | lerna-debug.log* 10 | 11 | # Diagnostic reports (https://nodejs.org/api/report.html) 12 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 13 | 14 | # Runtime data 15 | pids 16 | *.pid 17 | *.seed 18 | *.pid.lock 19 | 20 | # Directory for instrumented libs generated by jscoverage/JSCover 21 | lib-cov 22 | 23 | # Coverage directory used by tools like istanbul 24 | coverage 25 | *.lcov 26 | 27 | # nyc test coverage 28 | .nyc_output 29 | 30 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 31 | .grunt 32 | 33 | # Bower dependency directory (https://bower.io/) 34 | bower_components 35 | 36 | # node-waf configuration 37 | .lock-wscript 38 | 39 | # Compiled binary addons (https://nodejs.org/api/addons.html) 40 | build/Release 41 | 42 | # Dependency directories 43 | node_modules/ 44 | jspm_packages/ 45 | 46 | # TypeScript v1 declaration files 47 | typings/ 48 | 49 | # TypeScript cache 50 | *.tsbuildinfo 51 | 52 | # Optional npm cache directory 53 | .npm 54 | 55 | # Optional eslint cache 56 | .eslintcache 57 | 58 | # Microbundle cache 59 | .rpt2_cache/ 60 | .rts2_cache_cjs/ 61 | .rts2_cache_es/ 62 | .rts2_cache_umd/ 63 | 64 | # Optional REPL history 65 | .node_repl_history 66 | 67 | # Output of 'npm pack' 68 | *.tgz 69 | 70 | # Yarn Integrity file 71 | .yarn-integrity 72 | 73 | # dotenv environment variables file 74 | .env 75 | .env.test 76 | 77 | # parcel-bundler cache (https://parceljs.org/) 78 | .cache 79 | 80 | # Next.js build output 81 | .next 82 | 83 | # Nuxt.js build / generate output 84 | .nuxt 85 | dist 86 | 87 | # Gatsby files 88 | .cache/ 89 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 90 | # https://nextjs.org/blog/next-9-1#public-directory-support 91 | # public 92 | 93 | # vuepress build output 94 | .vuepress/dist 95 | 96 | # Serverless directories 97 | .serverless/ 98 | 99 | # FuseBox cache 100 | .fusebox/ 101 | 102 | # DynamoDB Local files 103 | .dynamodb/ 104 | 105 | # TernJS port file 106 | .tern-port 107 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # presence keeps NPM from ignoring all .gitignore files (NPM needs dist/) -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Joseph T. Lapp 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 | # kysely-params 2 | 3 | A utility for parameterizing compiled Kysely queries 4 | 5 | ## Introduction 6 | 7 | This utility allows you to parameterize compiled [Kysely](https://github.com/kysely-org/kysely) queries. It provides a `parameterizeQuery` function that allows you to selectively parameterize inserted, updated, and compared values within a Kysely query builder. The function returns a parameterized query that can be repeatedly called to execute or instantiate the query with different values for the parameters. On its first call, the query is compiled and its compilation cached, and the sourcing query builder is discarded to free memory. Subsequent calls use the cached compilation. 8 | 9 | The utility parameterizes values by replacing the values in the parameter list that Kysely passes to the database; values are not inserted into the query. For this reason, the utility should be as safe as providing values to Kysely directly. 10 | 11 | ## Purpose 12 | 13 | Kysely is a highly performant query builder, and you shouldn't need this utility to improve query speed. However, Kysely does use memory, increase garbage collection, and consume clock cycles that could be used elsewhere. This utility allows you to minimize resource usage for the kinds of applications that can benefit. 14 | 15 | Kysely's creator, Sami Koskimäki, maintains a [benchmark](https://github.com/kysely-org/kysely/blob/master/test/node/src/performance.test.ts) that tests the runtime speed of a complex query. Running the query 100,000 times on an M2 Macbook yields an average runtime of [14.6 microseconds](https://discord.com/channels/890118421587578920/1091365779376717945/1093203459454533633). Combine this with the fact that the performance bottleneck in database applications is almost always the database itself, and you can see that for most applications, the present utility is unnecessary and would provide unnecessary additional complication to use. 16 | 17 | This utility exists to help you feel comfortable using Kysely in any application, regardless of performance requirements. Query builders necessarily create many objects, and we may be concerned about using Kysely in memory-intensive applications, in applications that involve compute-bound work, or in real-time applications with response time requirements, which garbage collection could interfere with. It is hard to know in advance of development and testing whether there will be a problem. For this reason, absent the present utility, some people may be inclined to stick with raw SQL just to be safe. The existence of the utility allows you to use Kysely, regardless of application requirements. In the unlikely case that you encounter a problem using vanilla Kysely, you can start using this utility instead of ditching Kysely. 18 | 19 | This utility adds a bit of complication to your queries. It's best to implement the application without this utility until you find that you need it. You may discover that you never needed the additional complication. 20 | 21 | In case you're curious, [wirekang](https://github.com/wirekang) provides [speed and memory benchmarks](https://github.com/wirekang/kysely-params-benchmarks) for the utility. 22 | 23 | ## Installation 24 | 25 | Install both Kysely and the package with your preferred dependency manager: 26 | 27 | ``` 28 | npm install kysely kysely-params 29 | 30 | yarn add kysely kysely-params 31 | 32 | pnpm add kysely kysely-params 33 | ``` 34 | 35 | Then import the `parameterizeQuery` function into each file that needs to parameterize queries: 36 | 37 | ```ts 38 | import { parameterizeQuery } from 'kysely-params'; 39 | ``` 40 | 41 | ## Usage 42 | 43 | First use the utilty function to create a parameterized query. Consider the following example: 44 | 45 | ```ts 46 | interface UserParams { 47 | targetNickname: string; 48 | targetBirthYear: number; 49 | } 50 | 51 | const parameterization = parameterizeQuery( 52 | db.selectFrom('users').selectAll() 53 | ).asFollows(({ qb, param }) => 54 | qb 55 | .where('nickname', '=', param('targetNickname')) 56 | .where('birthYear', '=', param('targetBirthYear')) 57 | .where('state', '=', 'Virginia') 58 | ); 59 | ``` 60 | 61 | This produces a parameterization of the query but does not yet compile or execute the query. The example `UserParams` interface defines the available parameters and their types. `db` is an instance of [`Kysely`](https://kysely-org.github.io/kysely/classes/Kysely.html). `qb` is a regular Kysely query builder — in this case, a [`SelectQueryBuilder`](https://kysely-org.github.io/kysely/classes/SelectQueryBuilder.html). Call `param` with a parameter name where you would like to be able to vary the value. 62 | 63 | When calling `parameterizeQuery`, you must provide a query builder that specifies all selected and returned columns (via `select()`, `selectAll()`, `returning()`, and `returningAll()`) if you wish to be able to access the returned columns by name. Otherwise, TypeScript will not be aware of the returned columns or their types. 64 | 65 | Now execute the parameterized query. You can execute the same parameterized query as many times as you like. The `execute` and `executeTakeFirst` methods are available, as is an `instantiate` method for returning a [`CompiledQuery`](https://github.com/kysely-org/kysely/blob/master/site/docs/recipes/splitting-build-compile-and-execute-code.md#execute-compiled-queries) with all parameters replaced with values: 66 | 67 | ```ts 68 | const result = await parameterization.executeTakeFirst(db, { 69 | targetNickname: 'Joey', 70 | targetBirthYear: 2000, 71 | }); 72 | 73 | const results1 = await parameterization.execute(db, { 74 | targetNickname: 'Johnny', 75 | targetBirthYear: 1980, 76 | }); 77 | 78 | const compiledQuery = parameterization.instantiate({ 79 | targetNickname: 'Susie', 80 | targetBirthYear: 1990, 81 | }); 82 | const results2 = await db.executeQuery(compiledQuery); 83 | ``` 84 | 85 | The query compiles on the first call to `execute`, `executeTakeFirst`, or `instantiate`, and the compilation is used on that and subsequent calls. The first argument is the instance of `Kysely`, and the second is an object that provides the values of the parameters. 86 | 87 | Parameterizing a query requires having an instance of `Kysely`, but we usually don't have this instance in the place where we need to define the parameterization. We can deal with this by defining a function that takes an instance of `Kysely` and returns an object having parameterizations. Then define an instance of this object as the return type of this function: 88 | 89 | ```ts 90 | class MyRepo { 91 | readonly #queries: ReturnType; 92 | 93 | constructor(db: Kysely) { 94 | this.#queries = this.getQueries(db); 95 | } 96 | 97 | getByID(id: number) { 98 | return this.#queries.getByID(id).executeTakeFirst(db, { userID: id }); 99 | } 100 | 101 | getByName(name: number) { 102 | return this.#queries.getByName(name).execute(db, { name }); 103 | } 104 | 105 | private getQueries(db: Kysely) { 106 | return { 107 | getByID: parameterizeQuery(db.selectFrom('users').selectAll()).asFollows<{ 108 | userID: number; 109 | }>(({ qb, param }) => qb.where('id', '=', param('userID'))), 110 | 111 | getByName: parameterizeQuery( 112 | db.selectFrom('users').selectAll() 113 | ).asFollows<{ 114 | name: string; 115 | }>(({ qb, param }) => qb.where('name', '=', param('name'))), 116 | }; 117 | } 118 | } 119 | ``` 120 | 121 | ## Parameters 122 | 123 | Parameters can be of any type allowed by the database dialect in use, and each can only be used in a query where its type is valid. You can use parameters as inserted values, as updated values, and as right-hand-side values in `where` expressions. 124 | 125 | Here's an example parameterized `where` expression: 126 | 127 | ```ts 128 | const parameterization = parameterizeQuery( 129 | db.selectFrom('posts').select(['title', 'authorId']) 130 | ).asFollows<{ postAuthorId: number }>(({ qb, param }) => 131 | qb.where(({ and, cmpr }) => 132 | and([ 133 | cmpr('authorId', '=', param('postAuthorId')), 134 | cmpr('status', '=', 'published'), 135 | ]) 136 | ) 137 | ); 138 | ``` 139 | 140 | Parameters are allowed in SQL expressions, as illustrated in this deletion: 141 | 142 | ```ts 143 | // prettier-ignore 144 | const parameterization = parameterizeQuery( 145 | db.deleteFrom('posts') 146 | ).asFollows<{ postStatus: string }>(({ qb, param }) => 147 | qb.where(sql`status = ${param('postStatus')}`) 148 | ); 149 | ``` 150 | 151 | They can be used in place of values in inserted objects: 152 | 153 | ```ts 154 | const parameterization = parameterizeQuery( 155 | db.insertInto('posts').returning('id') 156 | ).asFollows(({ qb, param }) => 157 | qb.values({ 158 | title: param('postTitle'), 159 | authorId: param('postAuthorId'), 160 | status: 'draft', 161 | }) 162 | ); 163 | ``` 164 | 165 | And in place of values in update objects: 166 | 167 | ```ts 168 | // prettier-ignore 169 | const parameterization = parameterizeQuery( 170 | db.updateTable('posts') 171 | ).asFollows(({ qb, param }) => 172 | qb 173 | .set({ 174 | title: param('postTitle'), 175 | modifiedAt: param('modifiedAt'), 176 | }) 177 | .where('authorId', '=', param('postAuthorId')) 178 | ); 179 | ``` 180 | 181 | However, parameters cannot be arrays, though you can parameterize the individual elements of a array, as in this example: 182 | 183 | ```ts 184 | const parameterization = parameterizeQuery( 185 | db.selectFrom('users').selectAll() 186 | ).asFollows(({ qb, param }) => 187 | qb.where('birthYear', 'in', [param('year1'), param('year2'), 2000]) 188 | ); 189 | ``` 190 | 191 | The type parameter passed to `parameterize` is an object of type `ParametersObject` whose properties are the parameter names, with the type given each property being the parameter's type. In the above examples, `PostParams` would define an object have properties `title` with type `string` and `postAuthorId` with type number, and `YearParams` would define an object having properties `year1` and `year2`, both having type `number`. 192 | 193 | ## Parameterizations 194 | 195 | The `asFollows` method returns an instance of `ParameterizedQuery` having the provided parameterization. Please see the [API for `ParameterizedQuery`](https://github.com/jtlapp/kysely-params/blob/main/src/lib/parameterized-query.ts), which allows for executing and instantiating parameterizations. 196 | 197 | `ParameterizedQuery` is available for import, should you need variables of this type. The following query accepts a `targetId` parameter and returns the `name` column: 198 | 199 | ```ts 200 | import { ParameterizedQuery } from 'kysely-params'; 201 | 202 | interface Params { 203 | targetId: number; 204 | } 205 | 206 | let parameterization: ParameterizedQuery; 207 | 208 | parameterization = parameterizeQuery( 209 | db.selectFrom('users').select('name') 210 | ).asFollows(({ qb, param }) => qb.where('id', '=', param('targetId'))); 211 | ``` 212 | 213 | Be mindful of the type parameter you provide to `parameterize` for defining query parameters. When you execute or instantiate a parameterization, you must provide values for **_all_** of the parameters given in this type, as the execution and instantation methods do not know which parameters were actually used in the query. 214 | 215 | ## License 216 | 217 | MIT License. Copyright © 2023 Joseph T. Lapp 218 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "kysely-params", 3 | "version": "0.3.14", 4 | "author": "Joseph T. Lapp ", 5 | "license": "MIT", 6 | "description": "A utility for parameterizing compiled Kysely queries", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/jtlapp/kysely-params" 10 | }, 11 | "keywords": [ 12 | "kysely", 13 | "compiled", 14 | "cached", 15 | "parameterized", 16 | "parameters" 17 | ], 18 | "type": "module", 19 | "main": "dist/cjs/index.js", 20 | "types": "dist/cjs/index.d.ts", 21 | "source": "src/index.ts", 22 | "files": [ 23 | "dist/**" 24 | ], 25 | "exports": { 26 | ".": { 27 | "import": "./dist/esm/index.js", 28 | "require": "./dist/cjs/index.js" 29 | } 30 | }, 31 | "scripts": { 32 | "build": "rm -rdf dist && tsc && tsc -p tsconfig.cjs.json && pnpm write-packages", 33 | "write-packages": "echo '{\"type\":\"module\"}' > dist/esm/package.json && echo '{\"type\":\"commonjs\"}' > dist/cjs/package.json", 34 | "clean": "rm -rdf dist && rm -rdf node_modules", 35 | "test": "vitest --run" 36 | }, 37 | "devDependencies": { 38 | "@types/better-sqlite3": "^7.6.3", 39 | "@types/node": "20.1.3", 40 | "better-sqlite3": "^8.2.0", 41 | "typescript": "5.1.3", 42 | "vite": "^4.3.6", 43 | "vitest": "^0.32.2" 44 | }, 45 | "dependencies": { 46 | "kysely": "^0.24.2" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: 5.4 2 | 3 | specifiers: 4 | '@types/better-sqlite3': ^7.6.3 5 | '@types/jest': ^29.5.0 6 | '@types/node': ^18.15.5 7 | better-sqlite3: ^8.2.0 8 | jest: ^29.5.0 9 | kysely: ^0.24.2 10 | ts-jest: ^29.0.5 11 | typescript: ^5.0.2 12 | 13 | dependencies: 14 | kysely: 0.24.2 15 | 16 | devDependencies: 17 | '@types/better-sqlite3': 7.6.3 18 | '@types/jest': 29.5.0 19 | '@types/node': 18.15.11 20 | better-sqlite3: 8.2.0 21 | jest: 29.5.0_@types+node@18.15.11 22 | ts-jest: 29.0.5_ntm4xngu7em45lqojwsg6ufzc4 23 | typescript: 5.0.3 24 | 25 | packages: 26 | 27 | /@ampproject/remapping/2.2.0: 28 | resolution: {integrity: sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==} 29 | engines: {node: '>=6.0.0'} 30 | dependencies: 31 | '@jridgewell/gen-mapping': 0.1.1 32 | '@jridgewell/trace-mapping': 0.3.17 33 | dev: true 34 | 35 | /@babel/code-frame/7.21.4: 36 | resolution: {integrity: sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==} 37 | engines: {node: '>=6.9.0'} 38 | dependencies: 39 | '@babel/highlight': 7.18.6 40 | dev: true 41 | 42 | /@babel/compat-data/7.21.4: 43 | resolution: {integrity: sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g==} 44 | engines: {node: '>=6.9.0'} 45 | dev: true 46 | 47 | /@babel/core/7.21.4: 48 | resolution: {integrity: sha512-qt/YV149Jman/6AfmlxJ04LMIu8bMoyl3RB91yTFrxQmgbrSvQMy7cI8Q62FHx1t8wJ8B5fu0UDoLwHAhUo1QA==} 49 | engines: {node: '>=6.9.0'} 50 | dependencies: 51 | '@ampproject/remapping': 2.2.0 52 | '@babel/code-frame': 7.21.4 53 | '@babel/generator': 7.21.4 54 | '@babel/helper-compilation-targets': 7.21.4_@babel+core@7.21.4 55 | '@babel/helper-module-transforms': 7.21.2 56 | '@babel/helpers': 7.21.0 57 | '@babel/parser': 7.21.4 58 | '@babel/template': 7.20.7 59 | '@babel/traverse': 7.21.4 60 | '@babel/types': 7.21.4 61 | convert-source-map: 1.9.0 62 | debug: 4.3.4 63 | gensync: 1.0.0-beta.2 64 | json5: 2.2.3 65 | semver: 6.3.0 66 | transitivePeerDependencies: 67 | - supports-color 68 | dev: true 69 | 70 | /@babel/generator/7.21.4: 71 | resolution: {integrity: sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==} 72 | engines: {node: '>=6.9.0'} 73 | dependencies: 74 | '@babel/types': 7.21.4 75 | '@jridgewell/gen-mapping': 0.3.2 76 | '@jridgewell/trace-mapping': 0.3.17 77 | jsesc: 2.5.2 78 | dev: true 79 | 80 | /@babel/helper-compilation-targets/7.21.4_@babel+core@7.21.4: 81 | resolution: {integrity: sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg==} 82 | engines: {node: '>=6.9.0'} 83 | peerDependencies: 84 | '@babel/core': ^7.0.0 85 | dependencies: 86 | '@babel/compat-data': 7.21.4 87 | '@babel/core': 7.21.4 88 | '@babel/helper-validator-option': 7.21.0 89 | browserslist: 4.21.5 90 | lru-cache: 5.1.1 91 | semver: 6.3.0 92 | dev: true 93 | 94 | /@babel/helper-environment-visitor/7.18.9: 95 | resolution: {integrity: sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==} 96 | engines: {node: '>=6.9.0'} 97 | dev: true 98 | 99 | /@babel/helper-function-name/7.21.0: 100 | resolution: {integrity: sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==} 101 | engines: {node: '>=6.9.0'} 102 | dependencies: 103 | '@babel/template': 7.20.7 104 | '@babel/types': 7.21.4 105 | dev: true 106 | 107 | /@babel/helper-hoist-variables/7.18.6: 108 | resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==} 109 | engines: {node: '>=6.9.0'} 110 | dependencies: 111 | '@babel/types': 7.21.4 112 | dev: true 113 | 114 | /@babel/helper-module-imports/7.21.4: 115 | resolution: {integrity: sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==} 116 | engines: {node: '>=6.9.0'} 117 | dependencies: 118 | '@babel/types': 7.21.4 119 | dev: true 120 | 121 | /@babel/helper-module-transforms/7.21.2: 122 | resolution: {integrity: sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==} 123 | engines: {node: '>=6.9.0'} 124 | dependencies: 125 | '@babel/helper-environment-visitor': 7.18.9 126 | '@babel/helper-module-imports': 7.21.4 127 | '@babel/helper-simple-access': 7.20.2 128 | '@babel/helper-split-export-declaration': 7.18.6 129 | '@babel/helper-validator-identifier': 7.19.1 130 | '@babel/template': 7.20.7 131 | '@babel/traverse': 7.21.4 132 | '@babel/types': 7.21.4 133 | transitivePeerDependencies: 134 | - supports-color 135 | dev: true 136 | 137 | /@babel/helper-plugin-utils/7.20.2: 138 | resolution: {integrity: sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==} 139 | engines: {node: '>=6.9.0'} 140 | dev: true 141 | 142 | /@babel/helper-simple-access/7.20.2: 143 | resolution: {integrity: sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==} 144 | engines: {node: '>=6.9.0'} 145 | dependencies: 146 | '@babel/types': 7.21.4 147 | dev: true 148 | 149 | /@babel/helper-split-export-declaration/7.18.6: 150 | resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==} 151 | engines: {node: '>=6.9.0'} 152 | dependencies: 153 | '@babel/types': 7.21.4 154 | dev: true 155 | 156 | /@babel/helper-string-parser/7.19.4: 157 | resolution: {integrity: sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==} 158 | engines: {node: '>=6.9.0'} 159 | dev: true 160 | 161 | /@babel/helper-validator-identifier/7.19.1: 162 | resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==} 163 | engines: {node: '>=6.9.0'} 164 | dev: true 165 | 166 | /@babel/helper-validator-option/7.21.0: 167 | resolution: {integrity: sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==} 168 | engines: {node: '>=6.9.0'} 169 | dev: true 170 | 171 | /@babel/helpers/7.21.0: 172 | resolution: {integrity: sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==} 173 | engines: {node: '>=6.9.0'} 174 | dependencies: 175 | '@babel/template': 7.20.7 176 | '@babel/traverse': 7.21.4 177 | '@babel/types': 7.21.4 178 | transitivePeerDependencies: 179 | - supports-color 180 | dev: true 181 | 182 | /@babel/highlight/7.18.6: 183 | resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==} 184 | engines: {node: '>=6.9.0'} 185 | dependencies: 186 | '@babel/helper-validator-identifier': 7.19.1 187 | chalk: 2.4.2 188 | js-tokens: 4.0.0 189 | dev: true 190 | 191 | /@babel/parser/7.21.4: 192 | resolution: {integrity: sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==} 193 | engines: {node: '>=6.0.0'} 194 | hasBin: true 195 | dependencies: 196 | '@babel/types': 7.21.4 197 | dev: true 198 | 199 | /@babel/plugin-syntax-async-generators/7.8.4_@babel+core@7.21.4: 200 | resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} 201 | peerDependencies: 202 | '@babel/core': ^7.0.0-0 203 | dependencies: 204 | '@babel/core': 7.21.4 205 | '@babel/helper-plugin-utils': 7.20.2 206 | dev: true 207 | 208 | /@babel/plugin-syntax-bigint/7.8.3_@babel+core@7.21.4: 209 | resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} 210 | peerDependencies: 211 | '@babel/core': ^7.0.0-0 212 | dependencies: 213 | '@babel/core': 7.21.4 214 | '@babel/helper-plugin-utils': 7.20.2 215 | dev: true 216 | 217 | /@babel/plugin-syntax-class-properties/7.12.13_@babel+core@7.21.4: 218 | resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} 219 | peerDependencies: 220 | '@babel/core': ^7.0.0-0 221 | dependencies: 222 | '@babel/core': 7.21.4 223 | '@babel/helper-plugin-utils': 7.20.2 224 | dev: true 225 | 226 | /@babel/plugin-syntax-import-meta/7.10.4_@babel+core@7.21.4: 227 | resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} 228 | peerDependencies: 229 | '@babel/core': ^7.0.0-0 230 | dependencies: 231 | '@babel/core': 7.21.4 232 | '@babel/helper-plugin-utils': 7.20.2 233 | dev: true 234 | 235 | /@babel/plugin-syntax-json-strings/7.8.3_@babel+core@7.21.4: 236 | resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} 237 | peerDependencies: 238 | '@babel/core': ^7.0.0-0 239 | dependencies: 240 | '@babel/core': 7.21.4 241 | '@babel/helper-plugin-utils': 7.20.2 242 | dev: true 243 | 244 | /@babel/plugin-syntax-jsx/7.21.4_@babel+core@7.21.4: 245 | resolution: {integrity: sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ==} 246 | engines: {node: '>=6.9.0'} 247 | peerDependencies: 248 | '@babel/core': ^7.0.0-0 249 | dependencies: 250 | '@babel/core': 7.21.4 251 | '@babel/helper-plugin-utils': 7.20.2 252 | dev: true 253 | 254 | /@babel/plugin-syntax-logical-assignment-operators/7.10.4_@babel+core@7.21.4: 255 | resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} 256 | peerDependencies: 257 | '@babel/core': ^7.0.0-0 258 | dependencies: 259 | '@babel/core': 7.21.4 260 | '@babel/helper-plugin-utils': 7.20.2 261 | dev: true 262 | 263 | /@babel/plugin-syntax-nullish-coalescing-operator/7.8.3_@babel+core@7.21.4: 264 | resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} 265 | peerDependencies: 266 | '@babel/core': ^7.0.0-0 267 | dependencies: 268 | '@babel/core': 7.21.4 269 | '@babel/helper-plugin-utils': 7.20.2 270 | dev: true 271 | 272 | /@babel/plugin-syntax-numeric-separator/7.10.4_@babel+core@7.21.4: 273 | resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} 274 | peerDependencies: 275 | '@babel/core': ^7.0.0-0 276 | dependencies: 277 | '@babel/core': 7.21.4 278 | '@babel/helper-plugin-utils': 7.20.2 279 | dev: true 280 | 281 | /@babel/plugin-syntax-object-rest-spread/7.8.3_@babel+core@7.21.4: 282 | resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} 283 | peerDependencies: 284 | '@babel/core': ^7.0.0-0 285 | dependencies: 286 | '@babel/core': 7.21.4 287 | '@babel/helper-plugin-utils': 7.20.2 288 | dev: true 289 | 290 | /@babel/plugin-syntax-optional-catch-binding/7.8.3_@babel+core@7.21.4: 291 | resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} 292 | peerDependencies: 293 | '@babel/core': ^7.0.0-0 294 | dependencies: 295 | '@babel/core': 7.21.4 296 | '@babel/helper-plugin-utils': 7.20.2 297 | dev: true 298 | 299 | /@babel/plugin-syntax-optional-chaining/7.8.3_@babel+core@7.21.4: 300 | resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} 301 | peerDependencies: 302 | '@babel/core': ^7.0.0-0 303 | dependencies: 304 | '@babel/core': 7.21.4 305 | '@babel/helper-plugin-utils': 7.20.2 306 | dev: true 307 | 308 | /@babel/plugin-syntax-top-level-await/7.14.5_@babel+core@7.21.4: 309 | resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} 310 | engines: {node: '>=6.9.0'} 311 | peerDependencies: 312 | '@babel/core': ^7.0.0-0 313 | dependencies: 314 | '@babel/core': 7.21.4 315 | '@babel/helper-plugin-utils': 7.20.2 316 | dev: true 317 | 318 | /@babel/plugin-syntax-typescript/7.21.4_@babel+core@7.21.4: 319 | resolution: {integrity: sha512-xz0D39NvhQn4t4RNsHmDnnsaQizIlUkdtYvLs8La1BlfjQ6JEwxkJGeqJMW2tAXx+q6H+WFuUTXNdYVpEya0YA==} 320 | engines: {node: '>=6.9.0'} 321 | peerDependencies: 322 | '@babel/core': ^7.0.0-0 323 | dependencies: 324 | '@babel/core': 7.21.4 325 | '@babel/helper-plugin-utils': 7.20.2 326 | dev: true 327 | 328 | /@babel/template/7.20.7: 329 | resolution: {integrity: sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==} 330 | engines: {node: '>=6.9.0'} 331 | dependencies: 332 | '@babel/code-frame': 7.21.4 333 | '@babel/parser': 7.21.4 334 | '@babel/types': 7.21.4 335 | dev: true 336 | 337 | /@babel/traverse/7.21.4: 338 | resolution: {integrity: sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==} 339 | engines: {node: '>=6.9.0'} 340 | dependencies: 341 | '@babel/code-frame': 7.21.4 342 | '@babel/generator': 7.21.4 343 | '@babel/helper-environment-visitor': 7.18.9 344 | '@babel/helper-function-name': 7.21.0 345 | '@babel/helper-hoist-variables': 7.18.6 346 | '@babel/helper-split-export-declaration': 7.18.6 347 | '@babel/parser': 7.21.4 348 | '@babel/types': 7.21.4 349 | debug: 4.3.4 350 | globals: 11.12.0 351 | transitivePeerDependencies: 352 | - supports-color 353 | dev: true 354 | 355 | /@babel/types/7.21.4: 356 | resolution: {integrity: sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==} 357 | engines: {node: '>=6.9.0'} 358 | dependencies: 359 | '@babel/helper-string-parser': 7.19.4 360 | '@babel/helper-validator-identifier': 7.19.1 361 | to-fast-properties: 2.0.0 362 | dev: true 363 | 364 | /@bcoe/v8-coverage/0.2.3: 365 | resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} 366 | dev: true 367 | 368 | /@istanbuljs/load-nyc-config/1.1.0: 369 | resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} 370 | engines: {node: '>=8'} 371 | dependencies: 372 | camelcase: 5.3.1 373 | find-up: 4.1.0 374 | get-package-type: 0.1.0 375 | js-yaml: 3.14.1 376 | resolve-from: 5.0.0 377 | dev: true 378 | 379 | /@istanbuljs/schema/0.1.3: 380 | resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} 381 | engines: {node: '>=8'} 382 | dev: true 383 | 384 | /@jest/console/29.5.0: 385 | resolution: {integrity: sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ==} 386 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 387 | dependencies: 388 | '@jest/types': 29.5.0 389 | '@types/node': 18.15.11 390 | chalk: 4.1.2 391 | jest-message-util: 29.5.0 392 | jest-util: 29.5.0 393 | slash: 3.0.0 394 | dev: true 395 | 396 | /@jest/core/29.5.0: 397 | resolution: {integrity: sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==} 398 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 399 | peerDependencies: 400 | node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 401 | peerDependenciesMeta: 402 | node-notifier: 403 | optional: true 404 | dependencies: 405 | '@jest/console': 29.5.0 406 | '@jest/reporters': 29.5.0 407 | '@jest/test-result': 29.5.0 408 | '@jest/transform': 29.5.0 409 | '@jest/types': 29.5.0 410 | '@types/node': 18.15.11 411 | ansi-escapes: 4.3.2 412 | chalk: 4.1.2 413 | ci-info: 3.8.0 414 | exit: 0.1.2 415 | graceful-fs: 4.2.11 416 | jest-changed-files: 29.5.0 417 | jest-config: 29.5.0_@types+node@18.15.11 418 | jest-haste-map: 29.5.0 419 | jest-message-util: 29.5.0 420 | jest-regex-util: 29.4.3 421 | jest-resolve: 29.5.0 422 | jest-resolve-dependencies: 29.5.0 423 | jest-runner: 29.5.0 424 | jest-runtime: 29.5.0 425 | jest-snapshot: 29.5.0 426 | jest-util: 29.5.0 427 | jest-validate: 29.5.0 428 | jest-watcher: 29.5.0 429 | micromatch: 4.0.5 430 | pretty-format: 29.5.0 431 | slash: 3.0.0 432 | strip-ansi: 6.0.1 433 | transitivePeerDependencies: 434 | - supports-color 435 | - ts-node 436 | dev: true 437 | 438 | /@jest/environment/29.5.0: 439 | resolution: {integrity: sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==} 440 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 441 | dependencies: 442 | '@jest/fake-timers': 29.5.0 443 | '@jest/types': 29.5.0 444 | '@types/node': 18.15.11 445 | jest-mock: 29.5.0 446 | dev: true 447 | 448 | /@jest/expect-utils/29.5.0: 449 | resolution: {integrity: sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==} 450 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 451 | dependencies: 452 | jest-get-type: 29.4.3 453 | dev: true 454 | 455 | /@jest/expect/29.5.0: 456 | resolution: {integrity: sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g==} 457 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 458 | dependencies: 459 | expect: 29.5.0 460 | jest-snapshot: 29.5.0 461 | transitivePeerDependencies: 462 | - supports-color 463 | dev: true 464 | 465 | /@jest/fake-timers/29.5.0: 466 | resolution: {integrity: sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg==} 467 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 468 | dependencies: 469 | '@jest/types': 29.5.0 470 | '@sinonjs/fake-timers': 10.0.2 471 | '@types/node': 18.15.11 472 | jest-message-util: 29.5.0 473 | jest-mock: 29.5.0 474 | jest-util: 29.5.0 475 | dev: true 476 | 477 | /@jest/globals/29.5.0: 478 | resolution: {integrity: sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ==} 479 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 480 | dependencies: 481 | '@jest/environment': 29.5.0 482 | '@jest/expect': 29.5.0 483 | '@jest/types': 29.5.0 484 | jest-mock: 29.5.0 485 | transitivePeerDependencies: 486 | - supports-color 487 | dev: true 488 | 489 | /@jest/reporters/29.5.0: 490 | resolution: {integrity: sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==} 491 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 492 | peerDependencies: 493 | node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 494 | peerDependenciesMeta: 495 | node-notifier: 496 | optional: true 497 | dependencies: 498 | '@bcoe/v8-coverage': 0.2.3 499 | '@jest/console': 29.5.0 500 | '@jest/test-result': 29.5.0 501 | '@jest/transform': 29.5.0 502 | '@jest/types': 29.5.0 503 | '@jridgewell/trace-mapping': 0.3.17 504 | '@types/node': 18.15.11 505 | chalk: 4.1.2 506 | collect-v8-coverage: 1.0.1 507 | exit: 0.1.2 508 | glob: 7.2.3 509 | graceful-fs: 4.2.11 510 | istanbul-lib-coverage: 3.2.0 511 | istanbul-lib-instrument: 5.2.1 512 | istanbul-lib-report: 3.0.0 513 | istanbul-lib-source-maps: 4.0.1 514 | istanbul-reports: 3.1.5 515 | jest-message-util: 29.5.0 516 | jest-util: 29.5.0 517 | jest-worker: 29.5.0 518 | slash: 3.0.0 519 | string-length: 4.0.2 520 | strip-ansi: 6.0.1 521 | v8-to-istanbul: 9.1.0 522 | transitivePeerDependencies: 523 | - supports-color 524 | dev: true 525 | 526 | /@jest/schemas/29.4.3: 527 | resolution: {integrity: sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==} 528 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 529 | dependencies: 530 | '@sinclair/typebox': 0.25.24 531 | dev: true 532 | 533 | /@jest/source-map/29.4.3: 534 | resolution: {integrity: sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w==} 535 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 536 | dependencies: 537 | '@jridgewell/trace-mapping': 0.3.17 538 | callsites: 3.1.0 539 | graceful-fs: 4.2.11 540 | dev: true 541 | 542 | /@jest/test-result/29.5.0: 543 | resolution: {integrity: sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ==} 544 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 545 | dependencies: 546 | '@jest/console': 29.5.0 547 | '@jest/types': 29.5.0 548 | '@types/istanbul-lib-coverage': 2.0.4 549 | collect-v8-coverage: 1.0.1 550 | dev: true 551 | 552 | /@jest/test-sequencer/29.5.0: 553 | resolution: {integrity: sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ==} 554 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 555 | dependencies: 556 | '@jest/test-result': 29.5.0 557 | graceful-fs: 4.2.11 558 | jest-haste-map: 29.5.0 559 | slash: 3.0.0 560 | dev: true 561 | 562 | /@jest/transform/29.5.0: 563 | resolution: {integrity: sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==} 564 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 565 | dependencies: 566 | '@babel/core': 7.21.4 567 | '@jest/types': 29.5.0 568 | '@jridgewell/trace-mapping': 0.3.17 569 | babel-plugin-istanbul: 6.1.1 570 | chalk: 4.1.2 571 | convert-source-map: 2.0.0 572 | fast-json-stable-stringify: 2.1.0 573 | graceful-fs: 4.2.11 574 | jest-haste-map: 29.5.0 575 | jest-regex-util: 29.4.3 576 | jest-util: 29.5.0 577 | micromatch: 4.0.5 578 | pirates: 4.0.5 579 | slash: 3.0.0 580 | write-file-atomic: 4.0.2 581 | transitivePeerDependencies: 582 | - supports-color 583 | dev: true 584 | 585 | /@jest/types/29.5.0: 586 | resolution: {integrity: sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==} 587 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 588 | dependencies: 589 | '@jest/schemas': 29.4.3 590 | '@types/istanbul-lib-coverage': 2.0.4 591 | '@types/istanbul-reports': 3.0.1 592 | '@types/node': 18.15.11 593 | '@types/yargs': 17.0.24 594 | chalk: 4.1.2 595 | dev: true 596 | 597 | /@jridgewell/gen-mapping/0.1.1: 598 | resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==} 599 | engines: {node: '>=6.0.0'} 600 | dependencies: 601 | '@jridgewell/set-array': 1.1.2 602 | '@jridgewell/sourcemap-codec': 1.4.14 603 | dev: true 604 | 605 | /@jridgewell/gen-mapping/0.3.2: 606 | resolution: {integrity: sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==} 607 | engines: {node: '>=6.0.0'} 608 | dependencies: 609 | '@jridgewell/set-array': 1.1.2 610 | '@jridgewell/sourcemap-codec': 1.4.14 611 | '@jridgewell/trace-mapping': 0.3.17 612 | dev: true 613 | 614 | /@jridgewell/resolve-uri/3.1.0: 615 | resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} 616 | engines: {node: '>=6.0.0'} 617 | dev: true 618 | 619 | /@jridgewell/set-array/1.1.2: 620 | resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} 621 | engines: {node: '>=6.0.0'} 622 | dev: true 623 | 624 | /@jridgewell/sourcemap-codec/1.4.14: 625 | resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} 626 | dev: true 627 | 628 | /@jridgewell/trace-mapping/0.3.17: 629 | resolution: {integrity: sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==} 630 | dependencies: 631 | '@jridgewell/resolve-uri': 3.1.0 632 | '@jridgewell/sourcemap-codec': 1.4.14 633 | dev: true 634 | 635 | /@sinclair/typebox/0.25.24: 636 | resolution: {integrity: sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==} 637 | dev: true 638 | 639 | /@sinonjs/commons/2.0.0: 640 | resolution: {integrity: sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==} 641 | dependencies: 642 | type-detect: 4.0.8 643 | dev: true 644 | 645 | /@sinonjs/fake-timers/10.0.2: 646 | resolution: {integrity: sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw==} 647 | dependencies: 648 | '@sinonjs/commons': 2.0.0 649 | dev: true 650 | 651 | /@types/babel__core/7.20.0: 652 | resolution: {integrity: sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==} 653 | dependencies: 654 | '@babel/parser': 7.21.4 655 | '@babel/types': 7.21.4 656 | '@types/babel__generator': 7.6.4 657 | '@types/babel__template': 7.4.1 658 | '@types/babel__traverse': 7.18.3 659 | dev: true 660 | 661 | /@types/babel__generator/7.6.4: 662 | resolution: {integrity: sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==} 663 | dependencies: 664 | '@babel/types': 7.21.4 665 | dev: true 666 | 667 | /@types/babel__template/7.4.1: 668 | resolution: {integrity: sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==} 669 | dependencies: 670 | '@babel/parser': 7.21.4 671 | '@babel/types': 7.21.4 672 | dev: true 673 | 674 | /@types/babel__traverse/7.18.3: 675 | resolution: {integrity: sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==} 676 | dependencies: 677 | '@babel/types': 7.21.4 678 | dev: true 679 | 680 | /@types/better-sqlite3/7.6.3: 681 | resolution: {integrity: sha512-YS64N9SNDT/NAvou3QNdzAu3E2om/W/0dhORimtPGLef+zSK5l1vDzfsWb4xgXOgfhtOI5ZDTRxnvRPb22AIVQ==} 682 | dependencies: 683 | '@types/node': 18.15.11 684 | dev: true 685 | 686 | /@types/graceful-fs/4.1.6: 687 | resolution: {integrity: sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==} 688 | dependencies: 689 | '@types/node': 18.15.11 690 | dev: true 691 | 692 | /@types/istanbul-lib-coverage/2.0.4: 693 | resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==} 694 | dev: true 695 | 696 | /@types/istanbul-lib-report/3.0.0: 697 | resolution: {integrity: sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==} 698 | dependencies: 699 | '@types/istanbul-lib-coverage': 2.0.4 700 | dev: true 701 | 702 | /@types/istanbul-reports/3.0.1: 703 | resolution: {integrity: sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==} 704 | dependencies: 705 | '@types/istanbul-lib-report': 3.0.0 706 | dev: true 707 | 708 | /@types/jest/29.5.0: 709 | resolution: {integrity: sha512-3Emr5VOl/aoBwnWcH/EFQvlSAmjV+XtV9GGu5mwdYew5vhQh0IUZx/60x0TzHDu09Bi7HMx10t/namdJw5QIcg==} 710 | dependencies: 711 | expect: 29.5.0 712 | pretty-format: 29.5.0 713 | dev: true 714 | 715 | /@types/node/18.15.11: 716 | resolution: {integrity: sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==} 717 | dev: true 718 | 719 | /@types/prettier/2.7.2: 720 | resolution: {integrity: sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==} 721 | dev: true 722 | 723 | /@types/stack-utils/2.0.1: 724 | resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==} 725 | dev: true 726 | 727 | /@types/yargs-parser/21.0.0: 728 | resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==} 729 | dev: true 730 | 731 | /@types/yargs/17.0.24: 732 | resolution: {integrity: sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==} 733 | dependencies: 734 | '@types/yargs-parser': 21.0.0 735 | dev: true 736 | 737 | /ansi-escapes/4.3.2: 738 | resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} 739 | engines: {node: '>=8'} 740 | dependencies: 741 | type-fest: 0.21.3 742 | dev: true 743 | 744 | /ansi-regex/5.0.1: 745 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 746 | engines: {node: '>=8'} 747 | dev: true 748 | 749 | /ansi-styles/3.2.1: 750 | resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} 751 | engines: {node: '>=4'} 752 | dependencies: 753 | color-convert: 1.9.3 754 | dev: true 755 | 756 | /ansi-styles/4.3.0: 757 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 758 | engines: {node: '>=8'} 759 | dependencies: 760 | color-convert: 2.0.1 761 | dev: true 762 | 763 | /ansi-styles/5.2.0: 764 | resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} 765 | engines: {node: '>=10'} 766 | dev: true 767 | 768 | /anymatch/3.1.3: 769 | resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} 770 | engines: {node: '>= 8'} 771 | dependencies: 772 | normalize-path: 3.0.0 773 | picomatch: 2.3.1 774 | dev: true 775 | 776 | /argparse/1.0.10: 777 | resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} 778 | dependencies: 779 | sprintf-js: 1.0.3 780 | dev: true 781 | 782 | /babel-jest/29.5.0_@babel+core@7.21.4: 783 | resolution: {integrity: sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==} 784 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 785 | peerDependencies: 786 | '@babel/core': ^7.8.0 787 | dependencies: 788 | '@babel/core': 7.21.4 789 | '@jest/transform': 29.5.0 790 | '@types/babel__core': 7.20.0 791 | babel-plugin-istanbul: 6.1.1 792 | babel-preset-jest: 29.5.0_@babel+core@7.21.4 793 | chalk: 4.1.2 794 | graceful-fs: 4.2.11 795 | slash: 3.0.0 796 | transitivePeerDependencies: 797 | - supports-color 798 | dev: true 799 | 800 | /babel-plugin-istanbul/6.1.1: 801 | resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} 802 | engines: {node: '>=8'} 803 | dependencies: 804 | '@babel/helper-plugin-utils': 7.20.2 805 | '@istanbuljs/load-nyc-config': 1.1.0 806 | '@istanbuljs/schema': 0.1.3 807 | istanbul-lib-instrument: 5.2.1 808 | test-exclude: 6.0.0 809 | transitivePeerDependencies: 810 | - supports-color 811 | dev: true 812 | 813 | /babel-plugin-jest-hoist/29.5.0: 814 | resolution: {integrity: sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==} 815 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 816 | dependencies: 817 | '@babel/template': 7.20.7 818 | '@babel/types': 7.21.4 819 | '@types/babel__core': 7.20.0 820 | '@types/babel__traverse': 7.18.3 821 | dev: true 822 | 823 | /babel-preset-current-node-syntax/1.0.1_@babel+core@7.21.4: 824 | resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} 825 | peerDependencies: 826 | '@babel/core': ^7.0.0 827 | dependencies: 828 | '@babel/core': 7.21.4 829 | '@babel/plugin-syntax-async-generators': 7.8.4_@babel+core@7.21.4 830 | '@babel/plugin-syntax-bigint': 7.8.3_@babel+core@7.21.4 831 | '@babel/plugin-syntax-class-properties': 7.12.13_@babel+core@7.21.4 832 | '@babel/plugin-syntax-import-meta': 7.10.4_@babel+core@7.21.4 833 | '@babel/plugin-syntax-json-strings': 7.8.3_@babel+core@7.21.4 834 | '@babel/plugin-syntax-logical-assignment-operators': 7.10.4_@babel+core@7.21.4 835 | '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3_@babel+core@7.21.4 836 | '@babel/plugin-syntax-numeric-separator': 7.10.4_@babel+core@7.21.4 837 | '@babel/plugin-syntax-object-rest-spread': 7.8.3_@babel+core@7.21.4 838 | '@babel/plugin-syntax-optional-catch-binding': 7.8.3_@babel+core@7.21.4 839 | '@babel/plugin-syntax-optional-chaining': 7.8.3_@babel+core@7.21.4 840 | '@babel/plugin-syntax-top-level-await': 7.14.5_@babel+core@7.21.4 841 | dev: true 842 | 843 | /babel-preset-jest/29.5.0_@babel+core@7.21.4: 844 | resolution: {integrity: sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==} 845 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 846 | peerDependencies: 847 | '@babel/core': ^7.0.0 848 | dependencies: 849 | '@babel/core': 7.21.4 850 | babel-plugin-jest-hoist: 29.5.0 851 | babel-preset-current-node-syntax: 1.0.1_@babel+core@7.21.4 852 | dev: true 853 | 854 | /balanced-match/1.0.2: 855 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 856 | dev: true 857 | 858 | /base64-js/1.5.1: 859 | resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} 860 | dev: true 861 | 862 | /better-sqlite3/8.2.0: 863 | resolution: {integrity: sha512-8eTzxGk9535SB3oSNu0tQ6I4ZffjVCBUjKHN9QeeIFtphBX0sEd0NxAuglBNR9TO5ThnxBB7GqzfcYo9kjadJQ==} 864 | requiresBuild: true 865 | dependencies: 866 | bindings: 1.5.0 867 | prebuild-install: 7.1.1 868 | dev: true 869 | 870 | /bindings/1.5.0: 871 | resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} 872 | dependencies: 873 | file-uri-to-path: 1.0.0 874 | dev: true 875 | 876 | /bl/4.1.0: 877 | resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} 878 | dependencies: 879 | buffer: 5.7.1 880 | inherits: 2.0.4 881 | readable-stream: 3.6.2 882 | dev: true 883 | 884 | /brace-expansion/1.1.11: 885 | resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} 886 | dependencies: 887 | balanced-match: 1.0.2 888 | concat-map: 0.0.1 889 | dev: true 890 | 891 | /braces/3.0.2: 892 | resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} 893 | engines: {node: '>=8'} 894 | dependencies: 895 | fill-range: 7.0.1 896 | dev: true 897 | 898 | /browserslist/4.21.5: 899 | resolution: {integrity: sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==} 900 | engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} 901 | hasBin: true 902 | dependencies: 903 | caniuse-lite: 1.0.30001473 904 | electron-to-chromium: 1.4.347 905 | node-releases: 2.0.10 906 | update-browserslist-db: 1.0.10_browserslist@4.21.5 907 | dev: true 908 | 909 | /bs-logger/0.2.6: 910 | resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} 911 | engines: {node: '>= 6'} 912 | dependencies: 913 | fast-json-stable-stringify: 2.1.0 914 | dev: true 915 | 916 | /bser/2.1.1: 917 | resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} 918 | dependencies: 919 | node-int64: 0.4.0 920 | dev: true 921 | 922 | /buffer-from/1.1.2: 923 | resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} 924 | dev: true 925 | 926 | /buffer/5.7.1: 927 | resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} 928 | dependencies: 929 | base64-js: 1.5.1 930 | ieee754: 1.2.1 931 | dev: true 932 | 933 | /callsites/3.1.0: 934 | resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} 935 | engines: {node: '>=6'} 936 | dev: true 937 | 938 | /camelcase/5.3.1: 939 | resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} 940 | engines: {node: '>=6'} 941 | dev: true 942 | 943 | /camelcase/6.3.0: 944 | resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} 945 | engines: {node: '>=10'} 946 | dev: true 947 | 948 | /caniuse-lite/1.0.30001473: 949 | resolution: {integrity: sha512-ewDad7+D2vlyy+E4UJuVfiBsU69IL+8oVmTuZnH5Q6CIUbxNfI50uVpRHbUPDD6SUaN2o0Lh4DhTrvLG/Tn1yg==} 950 | dev: true 951 | 952 | /chalk/2.4.2: 953 | resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} 954 | engines: {node: '>=4'} 955 | dependencies: 956 | ansi-styles: 3.2.1 957 | escape-string-regexp: 1.0.5 958 | supports-color: 5.5.0 959 | dev: true 960 | 961 | /chalk/4.1.2: 962 | resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} 963 | engines: {node: '>=10'} 964 | dependencies: 965 | ansi-styles: 4.3.0 966 | supports-color: 7.2.0 967 | dev: true 968 | 969 | /char-regex/1.0.2: 970 | resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} 971 | engines: {node: '>=10'} 972 | dev: true 973 | 974 | /chownr/1.1.4: 975 | resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} 976 | dev: true 977 | 978 | /ci-info/3.8.0: 979 | resolution: {integrity: sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==} 980 | engines: {node: '>=8'} 981 | dev: true 982 | 983 | /cjs-module-lexer/1.2.2: 984 | resolution: {integrity: sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==} 985 | dev: true 986 | 987 | /cliui/8.0.1: 988 | resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} 989 | engines: {node: '>=12'} 990 | dependencies: 991 | string-width: 4.2.3 992 | strip-ansi: 6.0.1 993 | wrap-ansi: 7.0.0 994 | dev: true 995 | 996 | /co/4.6.0: 997 | resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} 998 | engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} 999 | dev: true 1000 | 1001 | /collect-v8-coverage/1.0.1: 1002 | resolution: {integrity: sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==} 1003 | dev: true 1004 | 1005 | /color-convert/1.9.3: 1006 | resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} 1007 | dependencies: 1008 | color-name: 1.1.3 1009 | dev: true 1010 | 1011 | /color-convert/2.0.1: 1012 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 1013 | engines: {node: '>=7.0.0'} 1014 | dependencies: 1015 | color-name: 1.1.4 1016 | dev: true 1017 | 1018 | /color-name/1.1.3: 1019 | resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} 1020 | dev: true 1021 | 1022 | /color-name/1.1.4: 1023 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 1024 | dev: true 1025 | 1026 | /concat-map/0.0.1: 1027 | resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} 1028 | dev: true 1029 | 1030 | /convert-source-map/1.9.0: 1031 | resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} 1032 | dev: true 1033 | 1034 | /convert-source-map/2.0.0: 1035 | resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} 1036 | dev: true 1037 | 1038 | /cross-spawn/7.0.3: 1039 | resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} 1040 | engines: {node: '>= 8'} 1041 | dependencies: 1042 | path-key: 3.1.1 1043 | shebang-command: 2.0.0 1044 | which: 2.0.2 1045 | dev: true 1046 | 1047 | /debug/4.3.4: 1048 | resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} 1049 | engines: {node: '>=6.0'} 1050 | peerDependencies: 1051 | supports-color: '*' 1052 | peerDependenciesMeta: 1053 | supports-color: 1054 | optional: true 1055 | dependencies: 1056 | ms: 2.1.2 1057 | dev: true 1058 | 1059 | /decompress-response/6.0.0: 1060 | resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} 1061 | engines: {node: '>=10'} 1062 | dependencies: 1063 | mimic-response: 3.1.0 1064 | dev: true 1065 | 1066 | /dedent/0.7.0: 1067 | resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==} 1068 | dev: true 1069 | 1070 | /deep-extend/0.6.0: 1071 | resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} 1072 | engines: {node: '>=4.0.0'} 1073 | dev: true 1074 | 1075 | /deepmerge/4.3.1: 1076 | resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} 1077 | engines: {node: '>=0.10.0'} 1078 | dev: true 1079 | 1080 | /detect-libc/2.0.1: 1081 | resolution: {integrity: sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==} 1082 | engines: {node: '>=8'} 1083 | dev: true 1084 | 1085 | /detect-newline/3.1.0: 1086 | resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} 1087 | engines: {node: '>=8'} 1088 | dev: true 1089 | 1090 | /diff-sequences/29.4.3: 1091 | resolution: {integrity: sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==} 1092 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1093 | dev: true 1094 | 1095 | /electron-to-chromium/1.4.347: 1096 | resolution: {integrity: sha512-LNi3+/9nV0vT6Bz1OsSoZ/w7IgNuWdefZ7mjKNjZxyRlI/ag6uMXxsxAy5Etvuixq3Q26exw2fc4bNYvYQqXSw==} 1097 | dev: true 1098 | 1099 | /emittery/0.13.1: 1100 | resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} 1101 | engines: {node: '>=12'} 1102 | dev: true 1103 | 1104 | /emoji-regex/8.0.0: 1105 | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} 1106 | dev: true 1107 | 1108 | /end-of-stream/1.4.4: 1109 | resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} 1110 | dependencies: 1111 | once: 1.4.0 1112 | dev: true 1113 | 1114 | /error-ex/1.3.2: 1115 | resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} 1116 | dependencies: 1117 | is-arrayish: 0.2.1 1118 | dev: true 1119 | 1120 | /escalade/3.1.1: 1121 | resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} 1122 | engines: {node: '>=6'} 1123 | dev: true 1124 | 1125 | /escape-string-regexp/1.0.5: 1126 | resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} 1127 | engines: {node: '>=0.8.0'} 1128 | dev: true 1129 | 1130 | /escape-string-regexp/2.0.0: 1131 | resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} 1132 | engines: {node: '>=8'} 1133 | dev: true 1134 | 1135 | /esprima/4.0.1: 1136 | resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} 1137 | engines: {node: '>=4'} 1138 | hasBin: true 1139 | dev: true 1140 | 1141 | /execa/5.1.1: 1142 | resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} 1143 | engines: {node: '>=10'} 1144 | dependencies: 1145 | cross-spawn: 7.0.3 1146 | get-stream: 6.0.1 1147 | human-signals: 2.1.0 1148 | is-stream: 2.0.1 1149 | merge-stream: 2.0.0 1150 | npm-run-path: 4.0.1 1151 | onetime: 5.1.2 1152 | signal-exit: 3.0.7 1153 | strip-final-newline: 2.0.0 1154 | dev: true 1155 | 1156 | /exit/0.1.2: 1157 | resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} 1158 | engines: {node: '>= 0.8.0'} 1159 | dev: true 1160 | 1161 | /expand-template/2.0.3: 1162 | resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} 1163 | engines: {node: '>=6'} 1164 | dev: true 1165 | 1166 | /expect/29.5.0: 1167 | resolution: {integrity: sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==} 1168 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1169 | dependencies: 1170 | '@jest/expect-utils': 29.5.0 1171 | jest-get-type: 29.4.3 1172 | jest-matcher-utils: 29.5.0 1173 | jest-message-util: 29.5.0 1174 | jest-util: 29.5.0 1175 | dev: true 1176 | 1177 | /fast-json-stable-stringify/2.1.0: 1178 | resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} 1179 | dev: true 1180 | 1181 | /fb-watchman/2.0.2: 1182 | resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} 1183 | dependencies: 1184 | bser: 2.1.1 1185 | dev: true 1186 | 1187 | /file-uri-to-path/1.0.0: 1188 | resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} 1189 | dev: true 1190 | 1191 | /fill-range/7.0.1: 1192 | resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} 1193 | engines: {node: '>=8'} 1194 | dependencies: 1195 | to-regex-range: 5.0.1 1196 | dev: true 1197 | 1198 | /find-up/4.1.0: 1199 | resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} 1200 | engines: {node: '>=8'} 1201 | dependencies: 1202 | locate-path: 5.0.0 1203 | path-exists: 4.0.0 1204 | dev: true 1205 | 1206 | /fs-constants/1.0.0: 1207 | resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} 1208 | dev: true 1209 | 1210 | /fs.realpath/1.0.0: 1211 | resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} 1212 | dev: true 1213 | 1214 | /fsevents/2.3.2: 1215 | resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} 1216 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 1217 | os: [darwin] 1218 | requiresBuild: true 1219 | dev: true 1220 | optional: true 1221 | 1222 | /function-bind/1.1.1: 1223 | resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} 1224 | dev: true 1225 | 1226 | /gensync/1.0.0-beta.2: 1227 | resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} 1228 | engines: {node: '>=6.9.0'} 1229 | dev: true 1230 | 1231 | /get-caller-file/2.0.5: 1232 | resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} 1233 | engines: {node: 6.* || 8.* || >= 10.*} 1234 | dev: true 1235 | 1236 | /get-package-type/0.1.0: 1237 | resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} 1238 | engines: {node: '>=8.0.0'} 1239 | dev: true 1240 | 1241 | /get-stream/6.0.1: 1242 | resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} 1243 | engines: {node: '>=10'} 1244 | dev: true 1245 | 1246 | /github-from-package/0.0.0: 1247 | resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} 1248 | dev: true 1249 | 1250 | /glob/7.2.3: 1251 | resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} 1252 | dependencies: 1253 | fs.realpath: 1.0.0 1254 | inflight: 1.0.6 1255 | inherits: 2.0.4 1256 | minimatch: 3.1.2 1257 | once: 1.4.0 1258 | path-is-absolute: 1.0.1 1259 | dev: true 1260 | 1261 | /globals/11.12.0: 1262 | resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} 1263 | engines: {node: '>=4'} 1264 | dev: true 1265 | 1266 | /graceful-fs/4.2.11: 1267 | resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} 1268 | dev: true 1269 | 1270 | /has-flag/3.0.0: 1271 | resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} 1272 | engines: {node: '>=4'} 1273 | dev: true 1274 | 1275 | /has-flag/4.0.0: 1276 | resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} 1277 | engines: {node: '>=8'} 1278 | dev: true 1279 | 1280 | /has/1.0.3: 1281 | resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} 1282 | engines: {node: '>= 0.4.0'} 1283 | dependencies: 1284 | function-bind: 1.1.1 1285 | dev: true 1286 | 1287 | /html-escaper/2.0.2: 1288 | resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} 1289 | dev: true 1290 | 1291 | /human-signals/2.1.0: 1292 | resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} 1293 | engines: {node: '>=10.17.0'} 1294 | dev: true 1295 | 1296 | /ieee754/1.2.1: 1297 | resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} 1298 | dev: true 1299 | 1300 | /import-local/3.1.0: 1301 | resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} 1302 | engines: {node: '>=8'} 1303 | hasBin: true 1304 | dependencies: 1305 | pkg-dir: 4.2.0 1306 | resolve-cwd: 3.0.0 1307 | dev: true 1308 | 1309 | /imurmurhash/0.1.4: 1310 | resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} 1311 | engines: {node: '>=0.8.19'} 1312 | dev: true 1313 | 1314 | /inflight/1.0.6: 1315 | resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} 1316 | dependencies: 1317 | once: 1.4.0 1318 | wrappy: 1.0.2 1319 | dev: true 1320 | 1321 | /inherits/2.0.4: 1322 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} 1323 | dev: true 1324 | 1325 | /ini/1.3.8: 1326 | resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} 1327 | dev: true 1328 | 1329 | /is-arrayish/0.2.1: 1330 | resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} 1331 | dev: true 1332 | 1333 | /is-core-module/2.11.0: 1334 | resolution: {integrity: sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==} 1335 | dependencies: 1336 | has: 1.0.3 1337 | dev: true 1338 | 1339 | /is-fullwidth-code-point/3.0.0: 1340 | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} 1341 | engines: {node: '>=8'} 1342 | dev: true 1343 | 1344 | /is-generator-fn/2.1.0: 1345 | resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} 1346 | engines: {node: '>=6'} 1347 | dev: true 1348 | 1349 | /is-number/7.0.0: 1350 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 1351 | engines: {node: '>=0.12.0'} 1352 | dev: true 1353 | 1354 | /is-stream/2.0.1: 1355 | resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} 1356 | engines: {node: '>=8'} 1357 | dev: true 1358 | 1359 | /isexe/2.0.0: 1360 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 1361 | dev: true 1362 | 1363 | /istanbul-lib-coverage/3.2.0: 1364 | resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==} 1365 | engines: {node: '>=8'} 1366 | dev: true 1367 | 1368 | /istanbul-lib-instrument/5.2.1: 1369 | resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} 1370 | engines: {node: '>=8'} 1371 | dependencies: 1372 | '@babel/core': 7.21.4 1373 | '@babel/parser': 7.21.4 1374 | '@istanbuljs/schema': 0.1.3 1375 | istanbul-lib-coverage: 3.2.0 1376 | semver: 6.3.0 1377 | transitivePeerDependencies: 1378 | - supports-color 1379 | dev: true 1380 | 1381 | /istanbul-lib-report/3.0.0: 1382 | resolution: {integrity: sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==} 1383 | engines: {node: '>=8'} 1384 | dependencies: 1385 | istanbul-lib-coverage: 3.2.0 1386 | make-dir: 3.1.0 1387 | supports-color: 7.2.0 1388 | dev: true 1389 | 1390 | /istanbul-lib-source-maps/4.0.1: 1391 | resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} 1392 | engines: {node: '>=10'} 1393 | dependencies: 1394 | debug: 4.3.4 1395 | istanbul-lib-coverage: 3.2.0 1396 | source-map: 0.6.1 1397 | transitivePeerDependencies: 1398 | - supports-color 1399 | dev: true 1400 | 1401 | /istanbul-reports/3.1.5: 1402 | resolution: {integrity: sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==} 1403 | engines: {node: '>=8'} 1404 | dependencies: 1405 | html-escaper: 2.0.2 1406 | istanbul-lib-report: 3.0.0 1407 | dev: true 1408 | 1409 | /jest-changed-files/29.5.0: 1410 | resolution: {integrity: sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==} 1411 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1412 | dependencies: 1413 | execa: 5.1.1 1414 | p-limit: 3.1.0 1415 | dev: true 1416 | 1417 | /jest-circus/29.5.0: 1418 | resolution: {integrity: sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA==} 1419 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1420 | dependencies: 1421 | '@jest/environment': 29.5.0 1422 | '@jest/expect': 29.5.0 1423 | '@jest/test-result': 29.5.0 1424 | '@jest/types': 29.5.0 1425 | '@types/node': 18.15.11 1426 | chalk: 4.1.2 1427 | co: 4.6.0 1428 | dedent: 0.7.0 1429 | is-generator-fn: 2.1.0 1430 | jest-each: 29.5.0 1431 | jest-matcher-utils: 29.5.0 1432 | jest-message-util: 29.5.0 1433 | jest-runtime: 29.5.0 1434 | jest-snapshot: 29.5.0 1435 | jest-util: 29.5.0 1436 | p-limit: 3.1.0 1437 | pretty-format: 29.5.0 1438 | pure-rand: 6.0.1 1439 | slash: 3.0.0 1440 | stack-utils: 2.0.6 1441 | transitivePeerDependencies: 1442 | - supports-color 1443 | dev: true 1444 | 1445 | /jest-cli/29.5.0_@types+node@18.15.11: 1446 | resolution: {integrity: sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==} 1447 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1448 | hasBin: true 1449 | peerDependencies: 1450 | node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 1451 | peerDependenciesMeta: 1452 | node-notifier: 1453 | optional: true 1454 | dependencies: 1455 | '@jest/core': 29.5.0 1456 | '@jest/test-result': 29.5.0 1457 | '@jest/types': 29.5.0 1458 | chalk: 4.1.2 1459 | exit: 0.1.2 1460 | graceful-fs: 4.2.11 1461 | import-local: 3.1.0 1462 | jest-config: 29.5.0_@types+node@18.15.11 1463 | jest-util: 29.5.0 1464 | jest-validate: 29.5.0 1465 | prompts: 2.4.2 1466 | yargs: 17.7.1 1467 | transitivePeerDependencies: 1468 | - '@types/node' 1469 | - supports-color 1470 | - ts-node 1471 | dev: true 1472 | 1473 | /jest-config/29.5.0_@types+node@18.15.11: 1474 | resolution: {integrity: sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==} 1475 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1476 | peerDependencies: 1477 | '@types/node': '*' 1478 | ts-node: '>=9.0.0' 1479 | peerDependenciesMeta: 1480 | '@types/node': 1481 | optional: true 1482 | ts-node: 1483 | optional: true 1484 | dependencies: 1485 | '@babel/core': 7.21.4 1486 | '@jest/test-sequencer': 29.5.0 1487 | '@jest/types': 29.5.0 1488 | '@types/node': 18.15.11 1489 | babel-jest: 29.5.0_@babel+core@7.21.4 1490 | chalk: 4.1.2 1491 | ci-info: 3.8.0 1492 | deepmerge: 4.3.1 1493 | glob: 7.2.3 1494 | graceful-fs: 4.2.11 1495 | jest-circus: 29.5.0 1496 | jest-environment-node: 29.5.0 1497 | jest-get-type: 29.4.3 1498 | jest-regex-util: 29.4.3 1499 | jest-resolve: 29.5.0 1500 | jest-runner: 29.5.0 1501 | jest-util: 29.5.0 1502 | jest-validate: 29.5.0 1503 | micromatch: 4.0.5 1504 | parse-json: 5.2.0 1505 | pretty-format: 29.5.0 1506 | slash: 3.0.0 1507 | strip-json-comments: 3.1.1 1508 | transitivePeerDependencies: 1509 | - supports-color 1510 | dev: true 1511 | 1512 | /jest-diff/29.5.0: 1513 | resolution: {integrity: sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==} 1514 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1515 | dependencies: 1516 | chalk: 4.1.2 1517 | diff-sequences: 29.4.3 1518 | jest-get-type: 29.4.3 1519 | pretty-format: 29.5.0 1520 | dev: true 1521 | 1522 | /jest-docblock/29.4.3: 1523 | resolution: {integrity: sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==} 1524 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1525 | dependencies: 1526 | detect-newline: 3.1.0 1527 | dev: true 1528 | 1529 | /jest-each/29.5.0: 1530 | resolution: {integrity: sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA==} 1531 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1532 | dependencies: 1533 | '@jest/types': 29.5.0 1534 | chalk: 4.1.2 1535 | jest-get-type: 29.4.3 1536 | jest-util: 29.5.0 1537 | pretty-format: 29.5.0 1538 | dev: true 1539 | 1540 | /jest-environment-node/29.5.0: 1541 | resolution: {integrity: sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==} 1542 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1543 | dependencies: 1544 | '@jest/environment': 29.5.0 1545 | '@jest/fake-timers': 29.5.0 1546 | '@jest/types': 29.5.0 1547 | '@types/node': 18.15.11 1548 | jest-mock: 29.5.0 1549 | jest-util: 29.5.0 1550 | dev: true 1551 | 1552 | /jest-get-type/29.4.3: 1553 | resolution: {integrity: sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==} 1554 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1555 | dev: true 1556 | 1557 | /jest-haste-map/29.5.0: 1558 | resolution: {integrity: sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==} 1559 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1560 | dependencies: 1561 | '@jest/types': 29.5.0 1562 | '@types/graceful-fs': 4.1.6 1563 | '@types/node': 18.15.11 1564 | anymatch: 3.1.3 1565 | fb-watchman: 2.0.2 1566 | graceful-fs: 4.2.11 1567 | jest-regex-util: 29.4.3 1568 | jest-util: 29.5.0 1569 | jest-worker: 29.5.0 1570 | micromatch: 4.0.5 1571 | walker: 1.0.8 1572 | optionalDependencies: 1573 | fsevents: 2.3.2 1574 | dev: true 1575 | 1576 | /jest-leak-detector/29.5.0: 1577 | resolution: {integrity: sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow==} 1578 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1579 | dependencies: 1580 | jest-get-type: 29.4.3 1581 | pretty-format: 29.5.0 1582 | dev: true 1583 | 1584 | /jest-matcher-utils/29.5.0: 1585 | resolution: {integrity: sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==} 1586 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1587 | dependencies: 1588 | chalk: 4.1.2 1589 | jest-diff: 29.5.0 1590 | jest-get-type: 29.4.3 1591 | pretty-format: 29.5.0 1592 | dev: true 1593 | 1594 | /jest-message-util/29.5.0: 1595 | resolution: {integrity: sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==} 1596 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1597 | dependencies: 1598 | '@babel/code-frame': 7.21.4 1599 | '@jest/types': 29.5.0 1600 | '@types/stack-utils': 2.0.1 1601 | chalk: 4.1.2 1602 | graceful-fs: 4.2.11 1603 | micromatch: 4.0.5 1604 | pretty-format: 29.5.0 1605 | slash: 3.0.0 1606 | stack-utils: 2.0.6 1607 | dev: true 1608 | 1609 | /jest-mock/29.5.0: 1610 | resolution: {integrity: sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==} 1611 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1612 | dependencies: 1613 | '@jest/types': 29.5.0 1614 | '@types/node': 18.15.11 1615 | jest-util: 29.5.0 1616 | dev: true 1617 | 1618 | /jest-pnp-resolver/1.2.3_jest-resolve@29.5.0: 1619 | resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} 1620 | engines: {node: '>=6'} 1621 | peerDependencies: 1622 | jest-resolve: '*' 1623 | peerDependenciesMeta: 1624 | jest-resolve: 1625 | optional: true 1626 | dependencies: 1627 | jest-resolve: 29.5.0 1628 | dev: true 1629 | 1630 | /jest-regex-util/29.4.3: 1631 | resolution: {integrity: sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==} 1632 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1633 | dev: true 1634 | 1635 | /jest-resolve-dependencies/29.5.0: 1636 | resolution: {integrity: sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg==} 1637 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1638 | dependencies: 1639 | jest-regex-util: 29.4.3 1640 | jest-snapshot: 29.5.0 1641 | transitivePeerDependencies: 1642 | - supports-color 1643 | dev: true 1644 | 1645 | /jest-resolve/29.5.0: 1646 | resolution: {integrity: sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==} 1647 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1648 | dependencies: 1649 | chalk: 4.1.2 1650 | graceful-fs: 4.2.11 1651 | jest-haste-map: 29.5.0 1652 | jest-pnp-resolver: 1.2.3_jest-resolve@29.5.0 1653 | jest-util: 29.5.0 1654 | jest-validate: 29.5.0 1655 | resolve: 1.22.1 1656 | resolve.exports: 2.0.2 1657 | slash: 3.0.0 1658 | dev: true 1659 | 1660 | /jest-runner/29.5.0: 1661 | resolution: {integrity: sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ==} 1662 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1663 | dependencies: 1664 | '@jest/console': 29.5.0 1665 | '@jest/environment': 29.5.0 1666 | '@jest/test-result': 29.5.0 1667 | '@jest/transform': 29.5.0 1668 | '@jest/types': 29.5.0 1669 | '@types/node': 18.15.11 1670 | chalk: 4.1.2 1671 | emittery: 0.13.1 1672 | graceful-fs: 4.2.11 1673 | jest-docblock: 29.4.3 1674 | jest-environment-node: 29.5.0 1675 | jest-haste-map: 29.5.0 1676 | jest-leak-detector: 29.5.0 1677 | jest-message-util: 29.5.0 1678 | jest-resolve: 29.5.0 1679 | jest-runtime: 29.5.0 1680 | jest-util: 29.5.0 1681 | jest-watcher: 29.5.0 1682 | jest-worker: 29.5.0 1683 | p-limit: 3.1.0 1684 | source-map-support: 0.5.13 1685 | transitivePeerDependencies: 1686 | - supports-color 1687 | dev: true 1688 | 1689 | /jest-runtime/29.5.0: 1690 | resolution: {integrity: sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw==} 1691 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1692 | dependencies: 1693 | '@jest/environment': 29.5.0 1694 | '@jest/fake-timers': 29.5.0 1695 | '@jest/globals': 29.5.0 1696 | '@jest/source-map': 29.4.3 1697 | '@jest/test-result': 29.5.0 1698 | '@jest/transform': 29.5.0 1699 | '@jest/types': 29.5.0 1700 | '@types/node': 18.15.11 1701 | chalk: 4.1.2 1702 | cjs-module-lexer: 1.2.2 1703 | collect-v8-coverage: 1.0.1 1704 | glob: 7.2.3 1705 | graceful-fs: 4.2.11 1706 | jest-haste-map: 29.5.0 1707 | jest-message-util: 29.5.0 1708 | jest-mock: 29.5.0 1709 | jest-regex-util: 29.4.3 1710 | jest-resolve: 29.5.0 1711 | jest-snapshot: 29.5.0 1712 | jest-util: 29.5.0 1713 | slash: 3.0.0 1714 | strip-bom: 4.0.0 1715 | transitivePeerDependencies: 1716 | - supports-color 1717 | dev: true 1718 | 1719 | /jest-snapshot/29.5.0: 1720 | resolution: {integrity: sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==} 1721 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1722 | dependencies: 1723 | '@babel/core': 7.21.4 1724 | '@babel/generator': 7.21.4 1725 | '@babel/plugin-syntax-jsx': 7.21.4_@babel+core@7.21.4 1726 | '@babel/plugin-syntax-typescript': 7.21.4_@babel+core@7.21.4 1727 | '@babel/traverse': 7.21.4 1728 | '@babel/types': 7.21.4 1729 | '@jest/expect-utils': 29.5.0 1730 | '@jest/transform': 29.5.0 1731 | '@jest/types': 29.5.0 1732 | '@types/babel__traverse': 7.18.3 1733 | '@types/prettier': 2.7.2 1734 | babel-preset-current-node-syntax: 1.0.1_@babel+core@7.21.4 1735 | chalk: 4.1.2 1736 | expect: 29.5.0 1737 | graceful-fs: 4.2.11 1738 | jest-diff: 29.5.0 1739 | jest-get-type: 29.4.3 1740 | jest-matcher-utils: 29.5.0 1741 | jest-message-util: 29.5.0 1742 | jest-util: 29.5.0 1743 | natural-compare: 1.4.0 1744 | pretty-format: 29.5.0 1745 | semver: 7.3.8 1746 | transitivePeerDependencies: 1747 | - supports-color 1748 | dev: true 1749 | 1750 | /jest-util/29.5.0: 1751 | resolution: {integrity: sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==} 1752 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1753 | dependencies: 1754 | '@jest/types': 29.5.0 1755 | '@types/node': 18.15.11 1756 | chalk: 4.1.2 1757 | ci-info: 3.8.0 1758 | graceful-fs: 4.2.11 1759 | picomatch: 2.3.1 1760 | dev: true 1761 | 1762 | /jest-validate/29.5.0: 1763 | resolution: {integrity: sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ==} 1764 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1765 | dependencies: 1766 | '@jest/types': 29.5.0 1767 | camelcase: 6.3.0 1768 | chalk: 4.1.2 1769 | jest-get-type: 29.4.3 1770 | leven: 3.1.0 1771 | pretty-format: 29.5.0 1772 | dev: true 1773 | 1774 | /jest-watcher/29.5.0: 1775 | resolution: {integrity: sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA==} 1776 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1777 | dependencies: 1778 | '@jest/test-result': 29.5.0 1779 | '@jest/types': 29.5.0 1780 | '@types/node': 18.15.11 1781 | ansi-escapes: 4.3.2 1782 | chalk: 4.1.2 1783 | emittery: 0.13.1 1784 | jest-util: 29.5.0 1785 | string-length: 4.0.2 1786 | dev: true 1787 | 1788 | /jest-worker/29.5.0: 1789 | resolution: {integrity: sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==} 1790 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1791 | dependencies: 1792 | '@types/node': 18.15.11 1793 | jest-util: 29.5.0 1794 | merge-stream: 2.0.0 1795 | supports-color: 8.1.1 1796 | dev: true 1797 | 1798 | /jest/29.5.0_@types+node@18.15.11: 1799 | resolution: {integrity: sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==} 1800 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1801 | hasBin: true 1802 | peerDependencies: 1803 | node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 1804 | peerDependenciesMeta: 1805 | node-notifier: 1806 | optional: true 1807 | dependencies: 1808 | '@jest/core': 29.5.0 1809 | '@jest/types': 29.5.0 1810 | import-local: 3.1.0 1811 | jest-cli: 29.5.0_@types+node@18.15.11 1812 | transitivePeerDependencies: 1813 | - '@types/node' 1814 | - supports-color 1815 | - ts-node 1816 | dev: true 1817 | 1818 | /js-tokens/4.0.0: 1819 | resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} 1820 | dev: true 1821 | 1822 | /js-yaml/3.14.1: 1823 | resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} 1824 | hasBin: true 1825 | dependencies: 1826 | argparse: 1.0.10 1827 | esprima: 4.0.1 1828 | dev: true 1829 | 1830 | /jsesc/2.5.2: 1831 | resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} 1832 | engines: {node: '>=4'} 1833 | hasBin: true 1834 | dev: true 1835 | 1836 | /json-parse-even-better-errors/2.3.1: 1837 | resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} 1838 | dev: true 1839 | 1840 | /json5/2.2.3: 1841 | resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} 1842 | engines: {node: '>=6'} 1843 | hasBin: true 1844 | dev: true 1845 | 1846 | /kleur/3.0.3: 1847 | resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} 1848 | engines: {node: '>=6'} 1849 | dev: true 1850 | 1851 | /kysely/0.24.2: 1852 | resolution: {integrity: sha512-+7eaTJNUYm2yRq1x+lEOZc+78TO35dTZ9b0dh49+Z9CTt2byMSbMiOKpwPlOyCAaHD4kILkAYWYZNywFlmBwRA==} 1853 | engines: {node: '>=14.0.0'} 1854 | dev: false 1855 | 1856 | /leven/3.1.0: 1857 | resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} 1858 | engines: {node: '>=6'} 1859 | dev: true 1860 | 1861 | /lines-and-columns/1.2.4: 1862 | resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} 1863 | dev: true 1864 | 1865 | /locate-path/5.0.0: 1866 | resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} 1867 | engines: {node: '>=8'} 1868 | dependencies: 1869 | p-locate: 4.1.0 1870 | dev: true 1871 | 1872 | /lodash.memoize/4.1.2: 1873 | resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} 1874 | dev: true 1875 | 1876 | /lru-cache/5.1.1: 1877 | resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} 1878 | dependencies: 1879 | yallist: 3.1.1 1880 | dev: true 1881 | 1882 | /lru-cache/6.0.0: 1883 | resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} 1884 | engines: {node: '>=10'} 1885 | dependencies: 1886 | yallist: 4.0.0 1887 | dev: true 1888 | 1889 | /make-dir/3.1.0: 1890 | resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} 1891 | engines: {node: '>=8'} 1892 | dependencies: 1893 | semver: 6.3.0 1894 | dev: true 1895 | 1896 | /make-error/1.3.6: 1897 | resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} 1898 | dev: true 1899 | 1900 | /makeerror/1.0.12: 1901 | resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} 1902 | dependencies: 1903 | tmpl: 1.0.5 1904 | dev: true 1905 | 1906 | /merge-stream/2.0.0: 1907 | resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} 1908 | dev: true 1909 | 1910 | /micromatch/4.0.5: 1911 | resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} 1912 | engines: {node: '>=8.6'} 1913 | dependencies: 1914 | braces: 3.0.2 1915 | picomatch: 2.3.1 1916 | dev: true 1917 | 1918 | /mimic-fn/2.1.0: 1919 | resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} 1920 | engines: {node: '>=6'} 1921 | dev: true 1922 | 1923 | /mimic-response/3.1.0: 1924 | resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} 1925 | engines: {node: '>=10'} 1926 | dev: true 1927 | 1928 | /minimatch/3.1.2: 1929 | resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} 1930 | dependencies: 1931 | brace-expansion: 1.1.11 1932 | dev: true 1933 | 1934 | /minimist/1.2.8: 1935 | resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} 1936 | dev: true 1937 | 1938 | /mkdirp-classic/0.5.3: 1939 | resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} 1940 | dev: true 1941 | 1942 | /ms/2.1.2: 1943 | resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} 1944 | dev: true 1945 | 1946 | /napi-build-utils/1.0.2: 1947 | resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==} 1948 | dev: true 1949 | 1950 | /natural-compare/1.4.0: 1951 | resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} 1952 | dev: true 1953 | 1954 | /node-abi/3.33.0: 1955 | resolution: {integrity: sha512-7GGVawqyHF4pfd0YFybhv/eM9JwTtPqx0mAanQ146O3FlSh3pA24zf9IRQTOsfTSqXTNzPSP5iagAJ94jjuVog==} 1956 | engines: {node: '>=10'} 1957 | dependencies: 1958 | semver: 7.3.8 1959 | dev: true 1960 | 1961 | /node-int64/0.4.0: 1962 | resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} 1963 | dev: true 1964 | 1965 | /node-releases/2.0.10: 1966 | resolution: {integrity: sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==} 1967 | dev: true 1968 | 1969 | /normalize-path/3.0.0: 1970 | resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} 1971 | engines: {node: '>=0.10.0'} 1972 | dev: true 1973 | 1974 | /npm-run-path/4.0.1: 1975 | resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} 1976 | engines: {node: '>=8'} 1977 | dependencies: 1978 | path-key: 3.1.1 1979 | dev: true 1980 | 1981 | /once/1.4.0: 1982 | resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} 1983 | dependencies: 1984 | wrappy: 1.0.2 1985 | dev: true 1986 | 1987 | /onetime/5.1.2: 1988 | resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} 1989 | engines: {node: '>=6'} 1990 | dependencies: 1991 | mimic-fn: 2.1.0 1992 | dev: true 1993 | 1994 | /p-limit/2.3.0: 1995 | resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} 1996 | engines: {node: '>=6'} 1997 | dependencies: 1998 | p-try: 2.2.0 1999 | dev: true 2000 | 2001 | /p-limit/3.1.0: 2002 | resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} 2003 | engines: {node: '>=10'} 2004 | dependencies: 2005 | yocto-queue: 0.1.0 2006 | dev: true 2007 | 2008 | /p-locate/4.1.0: 2009 | resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} 2010 | engines: {node: '>=8'} 2011 | dependencies: 2012 | p-limit: 2.3.0 2013 | dev: true 2014 | 2015 | /p-try/2.2.0: 2016 | resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} 2017 | engines: {node: '>=6'} 2018 | dev: true 2019 | 2020 | /parse-json/5.2.0: 2021 | resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} 2022 | engines: {node: '>=8'} 2023 | dependencies: 2024 | '@babel/code-frame': 7.21.4 2025 | error-ex: 1.3.2 2026 | json-parse-even-better-errors: 2.3.1 2027 | lines-and-columns: 1.2.4 2028 | dev: true 2029 | 2030 | /path-exists/4.0.0: 2031 | resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} 2032 | engines: {node: '>=8'} 2033 | dev: true 2034 | 2035 | /path-is-absolute/1.0.1: 2036 | resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} 2037 | engines: {node: '>=0.10.0'} 2038 | dev: true 2039 | 2040 | /path-key/3.1.1: 2041 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 2042 | engines: {node: '>=8'} 2043 | dev: true 2044 | 2045 | /path-parse/1.0.7: 2046 | resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} 2047 | dev: true 2048 | 2049 | /picocolors/1.0.0: 2050 | resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} 2051 | dev: true 2052 | 2053 | /picomatch/2.3.1: 2054 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 2055 | engines: {node: '>=8.6'} 2056 | dev: true 2057 | 2058 | /pirates/4.0.5: 2059 | resolution: {integrity: sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==} 2060 | engines: {node: '>= 6'} 2061 | dev: true 2062 | 2063 | /pkg-dir/4.2.0: 2064 | resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} 2065 | engines: {node: '>=8'} 2066 | dependencies: 2067 | find-up: 4.1.0 2068 | dev: true 2069 | 2070 | /prebuild-install/7.1.1: 2071 | resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==} 2072 | engines: {node: '>=10'} 2073 | hasBin: true 2074 | dependencies: 2075 | detect-libc: 2.0.1 2076 | expand-template: 2.0.3 2077 | github-from-package: 0.0.0 2078 | minimist: 1.2.8 2079 | mkdirp-classic: 0.5.3 2080 | napi-build-utils: 1.0.2 2081 | node-abi: 3.33.0 2082 | pump: 3.0.0 2083 | rc: 1.2.8 2084 | simple-get: 4.0.1 2085 | tar-fs: 2.1.1 2086 | tunnel-agent: 0.6.0 2087 | dev: true 2088 | 2089 | /pretty-format/29.5.0: 2090 | resolution: {integrity: sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==} 2091 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 2092 | dependencies: 2093 | '@jest/schemas': 29.4.3 2094 | ansi-styles: 5.2.0 2095 | react-is: 18.2.0 2096 | dev: true 2097 | 2098 | /prompts/2.4.2: 2099 | resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} 2100 | engines: {node: '>= 6'} 2101 | dependencies: 2102 | kleur: 3.0.3 2103 | sisteransi: 1.0.5 2104 | dev: true 2105 | 2106 | /pump/3.0.0: 2107 | resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} 2108 | dependencies: 2109 | end-of-stream: 1.4.4 2110 | once: 1.4.0 2111 | dev: true 2112 | 2113 | /pure-rand/6.0.1: 2114 | resolution: {integrity: sha512-t+x1zEHDjBwkDGY5v5ApnZ/utcd4XYDiJsaQQoptTXgUXX95sDg1elCdJghzicm7n2mbCBJ3uYWr6M22SO19rg==} 2115 | dev: true 2116 | 2117 | /rc/1.2.8: 2118 | resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} 2119 | hasBin: true 2120 | dependencies: 2121 | deep-extend: 0.6.0 2122 | ini: 1.3.8 2123 | minimist: 1.2.8 2124 | strip-json-comments: 2.0.1 2125 | dev: true 2126 | 2127 | /react-is/18.2.0: 2128 | resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} 2129 | dev: true 2130 | 2131 | /readable-stream/3.6.2: 2132 | resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} 2133 | engines: {node: '>= 6'} 2134 | dependencies: 2135 | inherits: 2.0.4 2136 | string_decoder: 1.3.0 2137 | util-deprecate: 1.0.2 2138 | dev: true 2139 | 2140 | /require-directory/2.1.1: 2141 | resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} 2142 | engines: {node: '>=0.10.0'} 2143 | dev: true 2144 | 2145 | /resolve-cwd/3.0.0: 2146 | resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} 2147 | engines: {node: '>=8'} 2148 | dependencies: 2149 | resolve-from: 5.0.0 2150 | dev: true 2151 | 2152 | /resolve-from/5.0.0: 2153 | resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} 2154 | engines: {node: '>=8'} 2155 | dev: true 2156 | 2157 | /resolve.exports/2.0.2: 2158 | resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} 2159 | engines: {node: '>=10'} 2160 | dev: true 2161 | 2162 | /resolve/1.22.1: 2163 | resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} 2164 | hasBin: true 2165 | dependencies: 2166 | is-core-module: 2.11.0 2167 | path-parse: 1.0.7 2168 | supports-preserve-symlinks-flag: 1.0.0 2169 | dev: true 2170 | 2171 | /safe-buffer/5.2.1: 2172 | resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} 2173 | dev: true 2174 | 2175 | /semver/6.3.0: 2176 | resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} 2177 | hasBin: true 2178 | dev: true 2179 | 2180 | /semver/7.3.8: 2181 | resolution: {integrity: sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==} 2182 | engines: {node: '>=10'} 2183 | hasBin: true 2184 | dependencies: 2185 | lru-cache: 6.0.0 2186 | dev: true 2187 | 2188 | /shebang-command/2.0.0: 2189 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 2190 | engines: {node: '>=8'} 2191 | dependencies: 2192 | shebang-regex: 3.0.0 2193 | dev: true 2194 | 2195 | /shebang-regex/3.0.0: 2196 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 2197 | engines: {node: '>=8'} 2198 | dev: true 2199 | 2200 | /signal-exit/3.0.7: 2201 | resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} 2202 | dev: true 2203 | 2204 | /simple-concat/1.0.1: 2205 | resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} 2206 | dev: true 2207 | 2208 | /simple-get/4.0.1: 2209 | resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} 2210 | dependencies: 2211 | decompress-response: 6.0.0 2212 | once: 1.4.0 2213 | simple-concat: 1.0.1 2214 | dev: true 2215 | 2216 | /sisteransi/1.0.5: 2217 | resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} 2218 | dev: true 2219 | 2220 | /slash/3.0.0: 2221 | resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} 2222 | engines: {node: '>=8'} 2223 | dev: true 2224 | 2225 | /source-map-support/0.5.13: 2226 | resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} 2227 | dependencies: 2228 | buffer-from: 1.1.2 2229 | source-map: 0.6.1 2230 | dev: true 2231 | 2232 | /source-map/0.6.1: 2233 | resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} 2234 | engines: {node: '>=0.10.0'} 2235 | dev: true 2236 | 2237 | /sprintf-js/1.0.3: 2238 | resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} 2239 | dev: true 2240 | 2241 | /stack-utils/2.0.6: 2242 | resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} 2243 | engines: {node: '>=10'} 2244 | dependencies: 2245 | escape-string-regexp: 2.0.0 2246 | dev: true 2247 | 2248 | /string-length/4.0.2: 2249 | resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} 2250 | engines: {node: '>=10'} 2251 | dependencies: 2252 | char-regex: 1.0.2 2253 | strip-ansi: 6.0.1 2254 | dev: true 2255 | 2256 | /string-width/4.2.3: 2257 | resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} 2258 | engines: {node: '>=8'} 2259 | dependencies: 2260 | emoji-regex: 8.0.0 2261 | is-fullwidth-code-point: 3.0.0 2262 | strip-ansi: 6.0.1 2263 | dev: true 2264 | 2265 | /string_decoder/1.3.0: 2266 | resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} 2267 | dependencies: 2268 | safe-buffer: 5.2.1 2269 | dev: true 2270 | 2271 | /strip-ansi/6.0.1: 2272 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} 2273 | engines: {node: '>=8'} 2274 | dependencies: 2275 | ansi-regex: 5.0.1 2276 | dev: true 2277 | 2278 | /strip-bom/4.0.0: 2279 | resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} 2280 | engines: {node: '>=8'} 2281 | dev: true 2282 | 2283 | /strip-final-newline/2.0.0: 2284 | resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} 2285 | engines: {node: '>=6'} 2286 | dev: true 2287 | 2288 | /strip-json-comments/2.0.1: 2289 | resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} 2290 | engines: {node: '>=0.10.0'} 2291 | dev: true 2292 | 2293 | /strip-json-comments/3.1.1: 2294 | resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} 2295 | engines: {node: '>=8'} 2296 | dev: true 2297 | 2298 | /supports-color/5.5.0: 2299 | resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} 2300 | engines: {node: '>=4'} 2301 | dependencies: 2302 | has-flag: 3.0.0 2303 | dev: true 2304 | 2305 | /supports-color/7.2.0: 2306 | resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} 2307 | engines: {node: '>=8'} 2308 | dependencies: 2309 | has-flag: 4.0.0 2310 | dev: true 2311 | 2312 | /supports-color/8.1.1: 2313 | resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} 2314 | engines: {node: '>=10'} 2315 | dependencies: 2316 | has-flag: 4.0.0 2317 | dev: true 2318 | 2319 | /supports-preserve-symlinks-flag/1.0.0: 2320 | resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} 2321 | engines: {node: '>= 0.4'} 2322 | dev: true 2323 | 2324 | /tar-fs/2.1.1: 2325 | resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==} 2326 | dependencies: 2327 | chownr: 1.1.4 2328 | mkdirp-classic: 0.5.3 2329 | pump: 3.0.0 2330 | tar-stream: 2.2.0 2331 | dev: true 2332 | 2333 | /tar-stream/2.2.0: 2334 | resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} 2335 | engines: {node: '>=6'} 2336 | dependencies: 2337 | bl: 4.1.0 2338 | end-of-stream: 1.4.4 2339 | fs-constants: 1.0.0 2340 | inherits: 2.0.4 2341 | readable-stream: 3.6.2 2342 | dev: true 2343 | 2344 | /test-exclude/6.0.0: 2345 | resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} 2346 | engines: {node: '>=8'} 2347 | dependencies: 2348 | '@istanbuljs/schema': 0.1.3 2349 | glob: 7.2.3 2350 | minimatch: 3.1.2 2351 | dev: true 2352 | 2353 | /tmpl/1.0.5: 2354 | resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} 2355 | dev: true 2356 | 2357 | /to-fast-properties/2.0.0: 2358 | resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} 2359 | engines: {node: '>=4'} 2360 | dev: true 2361 | 2362 | /to-regex-range/5.0.1: 2363 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 2364 | engines: {node: '>=8.0'} 2365 | dependencies: 2366 | is-number: 7.0.0 2367 | dev: true 2368 | 2369 | /ts-jest/29.0.5_ntm4xngu7em45lqojwsg6ufzc4: 2370 | resolution: {integrity: sha512-PL3UciSgIpQ7f6XjVOmbi96vmDHUqAyqDr8YxzopDqX3kfgYtX1cuNeBjP+L9sFXi6nzsGGA6R3fP3DDDJyrxA==} 2371 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 2372 | hasBin: true 2373 | peerDependencies: 2374 | '@babel/core': '>=7.0.0-beta.0 <8' 2375 | '@jest/types': ^29.0.0 2376 | babel-jest: ^29.0.0 2377 | esbuild: '*' 2378 | jest: ^29.0.0 2379 | typescript: '>=4.3' 2380 | peerDependenciesMeta: 2381 | '@babel/core': 2382 | optional: true 2383 | '@jest/types': 2384 | optional: true 2385 | babel-jest: 2386 | optional: true 2387 | esbuild: 2388 | optional: true 2389 | dependencies: 2390 | bs-logger: 0.2.6 2391 | fast-json-stable-stringify: 2.1.0 2392 | jest: 29.5.0_@types+node@18.15.11 2393 | jest-util: 29.5.0 2394 | json5: 2.2.3 2395 | lodash.memoize: 4.1.2 2396 | make-error: 1.3.6 2397 | semver: 7.3.8 2398 | typescript: 5.0.3 2399 | yargs-parser: 21.1.1 2400 | dev: true 2401 | 2402 | /tunnel-agent/0.6.0: 2403 | resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} 2404 | dependencies: 2405 | safe-buffer: 5.2.1 2406 | dev: true 2407 | 2408 | /type-detect/4.0.8: 2409 | resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} 2410 | engines: {node: '>=4'} 2411 | dev: true 2412 | 2413 | /type-fest/0.21.3: 2414 | resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} 2415 | engines: {node: '>=10'} 2416 | dev: true 2417 | 2418 | /typescript/5.0.3: 2419 | resolution: {integrity: sha512-xv8mOEDnigb/tN9PSMTwSEqAnUvkoXMQlicOb0IUVDBSQCgBSaAAROUZYy2IcUy5qU6XajK5jjjO7TMWqBTKZA==} 2420 | engines: {node: '>=12.20'} 2421 | hasBin: true 2422 | dev: true 2423 | 2424 | /update-browserslist-db/1.0.10_browserslist@4.21.5: 2425 | resolution: {integrity: sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==} 2426 | hasBin: true 2427 | peerDependencies: 2428 | browserslist: '>= 4.21.0' 2429 | dependencies: 2430 | browserslist: 4.21.5 2431 | escalade: 3.1.1 2432 | picocolors: 1.0.0 2433 | dev: true 2434 | 2435 | /util-deprecate/1.0.2: 2436 | resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} 2437 | dev: true 2438 | 2439 | /v8-to-istanbul/9.1.0: 2440 | resolution: {integrity: sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==} 2441 | engines: {node: '>=10.12.0'} 2442 | dependencies: 2443 | '@jridgewell/trace-mapping': 0.3.17 2444 | '@types/istanbul-lib-coverage': 2.0.4 2445 | convert-source-map: 1.9.0 2446 | dev: true 2447 | 2448 | /walker/1.0.8: 2449 | resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} 2450 | dependencies: 2451 | makeerror: 1.0.12 2452 | dev: true 2453 | 2454 | /which/2.0.2: 2455 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 2456 | engines: {node: '>= 8'} 2457 | hasBin: true 2458 | dependencies: 2459 | isexe: 2.0.0 2460 | dev: true 2461 | 2462 | /wrap-ansi/7.0.0: 2463 | resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} 2464 | engines: {node: '>=10'} 2465 | dependencies: 2466 | ansi-styles: 4.3.0 2467 | string-width: 4.2.3 2468 | strip-ansi: 6.0.1 2469 | dev: true 2470 | 2471 | /wrappy/1.0.2: 2472 | resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} 2473 | dev: true 2474 | 2475 | /write-file-atomic/4.0.2: 2476 | resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} 2477 | engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} 2478 | dependencies: 2479 | imurmurhash: 0.1.4 2480 | signal-exit: 3.0.7 2481 | dev: true 2482 | 2483 | /y18n/5.0.8: 2484 | resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} 2485 | engines: {node: '>=10'} 2486 | dev: true 2487 | 2488 | /yallist/3.1.1: 2489 | resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} 2490 | dev: true 2491 | 2492 | /yallist/4.0.0: 2493 | resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} 2494 | dev: true 2495 | 2496 | /yargs-parser/21.1.1: 2497 | resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} 2498 | engines: {node: '>=12'} 2499 | dev: true 2500 | 2501 | /yargs/17.7.1: 2502 | resolution: {integrity: sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==} 2503 | engines: {node: '>=12'} 2504 | dependencies: 2505 | cliui: 8.0.1 2506 | escalade: 3.1.1 2507 | get-caller-file: 2.0.5 2508 | require-directory: 2.1.1 2509 | string-width: 4.2.3 2510 | y18n: 5.0.8 2511 | yargs-parser: 21.1.1 2512 | dev: true 2513 | 2514 | /yocto-queue/0.1.0: 2515 | resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} 2516 | engines: {node: '>=10'} 2517 | dev: true 2518 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/parameterizer.js'; 2 | export * from './lib/parameterized-query.js'; 3 | export * from './lib/parameterized-value.js'; 4 | -------------------------------------------------------------------------------- /src/lib/parameterized-query.ts: -------------------------------------------------------------------------------- 1 | import { CompiledQuery, Compilable, Kysely, QueryResult } from 'kysely'; 2 | 3 | import { ParameterizedValue } from './parameterized-value.js'; 4 | 5 | /** 6 | * Type for an object that defines the query parameters. It disallows the 7 | * object from having array properties. 8 | * @typeparam T Type that is to define the query parameters. 9 | */ 10 | export type ParametersObject

= { 11 | [K in keyof P]: P[K] extends Array ? never : P[K]; 12 | }; 13 | 14 | /** 15 | * Class representing a parameterized compiled query that can be repeatedly 16 | * executed or instantiated with different values for its parameters. 17 | * @paramtype P Record characterizing the parameter names and types. 18 | */ 19 | export class ParameterizedQuery

, O> { 20 | #qb: Compilable | null; 21 | #compiledQuery?: CompiledQuery; 22 | 23 | /** 24 | * Creates a new parameterized query from a query builder whose query 25 | * arguments may contained parameterized values. 26 | */ 27 | constructor(qb: Compilable) { 28 | this.#qb = qb; 29 | } 30 | 31 | /** 32 | * Executes the query with all parameters replaced, returning all results. 33 | * Compiles the query on the first call, caching the compiled query and 34 | * discarding the underlying query builder to reduce memory used. 35 | * @param db The Kysely database instance. 36 | * @param params Object providing values for all parameters. 37 | * @returns Query result. 38 | */ 39 | execute(db: Kysely, params: Readonly

): Promise> { 40 | return db.executeQuery(this.instantiate(params)); 41 | } 42 | 43 | /** 44 | * Executes the query with all parameters replaced, returning the first 45 | * result. Compiles the query on the first call, caching the compiled query 46 | * and discarding the underlying query builder to reduce memory used. 47 | * @param db The Kysely database instance. 48 | * @param params Object providing values for all parameters. 49 | * @returns First query result, or undefined if there are no results. 50 | */ 51 | async executeTakeFirst( 52 | db: Kysely, 53 | params: Readonly

54 | ): Promise { 55 | const result = await db.executeQuery(this.instantiate(params)); 56 | return result.rows.length > 0 ? result.rows[0] : undefined; 57 | } 58 | 59 | /** 60 | * Instantiates the query as a compiled query with all parameters replaced, 61 | * returning the compiled query. Compiles the query on the first call, 62 | * caching the uninstantiated compiled query and discarding the underlying 63 | * query builder to reduce memory used. 64 | * @param params Object providing values for all parameters. 65 | * @returns Compiled query with values replacing all parameters. 66 | */ 67 | instantiate(params: Readonly

): CompiledQuery { 68 | if (this.#compiledQuery === undefined) { 69 | this.#compiledQuery = this.#qb!.compile(); 70 | // Allow the query builder to be garbage collected. 71 | this.#qb = null; 72 | } 73 | return { 74 | query: this.#compiledQuery.query, 75 | sql: this.#compiledQuery.sql, 76 | parameters: this.#compiledQuery.parameters.map((value) => 77 | value instanceof ParameterizedValue 78 | ? params[value.parameterName as keyof P] 79 | : value 80 | ), 81 | }; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/lib/parameterized-value.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Class representing a parameter-specified value. 3 | * @paramtype P Record characterizing the parameter names and types. 4 | */ 5 | export class ParameterizedValue

> { 6 | /** 7 | * Creates a new parameter-specified value. 8 | * @param parameterName Name of the parameter. 9 | */ 10 | constructor(readonly parameterName: keyof P & string) {} 11 | } 12 | -------------------------------------------------------------------------------- /src/lib/parameterizer.ts: -------------------------------------------------------------------------------- 1 | import { Compilable } from 'kysely'; 2 | 3 | import { ParameterizedValue } from './parameterized-value.js'; 4 | import { ParameterizedQuery, ParametersObject } from './parameterized-query.js'; 5 | 6 | type QueryBuilderOutput = QB extends Compilable ? O : never; 7 | 8 | /** 9 | * Creates and returns a parameterizer for the given query builder. The 10 | * provided query builder must designate any selected or returned columns 11 | * that you wish to be able to reference by name, as TypeScript will not 12 | * otherwise be aware of the columns being returned. 13 | * @paramtype O Type of the query result. 14 | * @paramtype QB Type of the source query builder. 15 | * @param qb The source query builder, which should establish any selected 16 | * or returned columns you wish to be able to reference by name. 17 | * @returns Parameterizer for the given query builder, which can be used 18 | * to create parameterized queries. 19 | */ 20 | export function parameterizeQuery< 21 | QB extends Compilable, 22 | O = QueryBuilderOutput 23 | >(qb: QB): QueryParameterizer { 24 | return new QueryParameterizer(qb); 25 | } 26 | 27 | /** 28 | * Class for parameterizing queries. 29 | * @paramtype O Type of the query result. 30 | * @paramtype QB Type of the source query builder. 31 | */ 32 | export class QueryParameterizer< 33 | QB extends Compilable, 34 | O = QueryBuilderOutput 35 | > { 36 | /** 37 | * Creates a new parameterizer for the given query builder. 38 | */ 39 | constructor(readonly qb: QB) {} 40 | 41 | /** 42 | * Creates and returns a parameterized query. 43 | * @paramtype P Record characterizing the available parameter names and types. 44 | * @param factory Function that receives an object of the form { qb, param } 45 | * and returns a query builder that may contain parameterized values. 46 | * @returns Parameterized query. 47 | */ 48 | asFollows

>( 49 | factory: ParameterizedQueryFactory 50 | ): ParameterizedQuery { 51 | const parameterMaker = new QueryParameterMaker

(); 52 | return new ParameterizedQuery( 53 | factory({ qb: this.qb, param: parameterMaker.param.bind(parameterMaker) }) 54 | ); 55 | } 56 | } 57 | 58 | /** 59 | * Factory function for creating a parameterized query. 60 | * @paramtype O Type of the query result. 61 | * @paramtype P Record characterizing the available parameter names and types. 62 | * @paramtype QB Type of the source query builder. 63 | * @param args Object of the form { qb, param }, returning a query builder 64 | * that may contain parameterized values. 65 | */ 66 | export interface ParameterizedQueryFactory< 67 | P extends ParametersObject

, 68 | QB extends Compilable, 69 | O = QueryBuilderOutput 70 | > { 71 | (args: { qb: QB; param: QueryParameterMaker

['param'] }): Compilable; 72 | } 73 | 74 | /** 75 | * Class for making occurrences of parameters within a query. 76 | * @paramtype P Record characterizing the available parameter names and types. 77 | */ 78 | export class QueryParameterMaker

{ 79 | /** 80 | * Returns a parameterized value. 81 | * @param name Parameter name. 82 | * @returns Parameter having the given name and the type assigned to that 83 | * name in P. 84 | */ 85 | param(name: N): P[N] { 86 | return new ParameterizedValue(name) as unknown as P[N]; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/tests/delete-params.test.ts: -------------------------------------------------------------------------------- 1 | import { Kysely } from 'kysely'; 2 | 3 | import { createDB, resetDB, destroyDB } from '../utils/test-setup'; 4 | import { Database } from '../utils/test-tables'; 5 | import { ignore } from '../utils/test-utils'; 6 | import { parameterizeQuery } from '../lib/parameterizer'; 7 | 8 | let db: Kysely; 9 | 10 | beforeAll(async () => { 11 | db = await createDB(); 12 | }); 13 | beforeEach(() => resetDB(db)); 14 | afterAll(() => destroyDB(db)); 15 | 16 | const user1 = { 17 | name: 'John Smith', 18 | nickname: 'Johnny', 19 | handle: 'jsmith', 20 | birthYear: 1980, 21 | }; 22 | const user2 = { 23 | name: 'John McSmith', 24 | nickname: 'Johnny', 25 | handle: 'jmsmith', 26 | birthYear: 1990, 27 | }; 28 | const user3 = { 29 | name: 'Jane Doe', 30 | nickname: 'Jane', 31 | handle: 'jdoe', 32 | birthYear: 1990, 33 | }; 34 | 35 | it('instantiates deletions, with multiple executions', async () => { 36 | interface Params { 37 | targetNickname: string; 38 | targetBirthYear: number; 39 | } 40 | await db.insertInto('users').values([user1, user2, user3]).execute(); 41 | 42 | const parameterization = parameterizeQuery( 43 | db.deleteFrom('users') 44 | ).asFollows(({ qb, param }) => 45 | qb 46 | .where('nickname', '=', param('targetNickname')) 47 | .where('birthYear', '=', param('targetBirthYear')) 48 | ); 49 | 50 | // First execution 51 | 52 | const compiledQuery1 = parameterization.instantiate({ 53 | targetNickname: user2.nickname, 54 | targetBirthYear: user2.birthYear, 55 | }); 56 | const result1 = await db.executeQuery(compiledQuery1); 57 | expect(Number(result1?.numAffectedRows)).toEqual(1); 58 | 59 | // Second execution 60 | 61 | const compiledQuery2 = parameterization.instantiate({ 62 | targetNickname: user3.nickname, 63 | targetBirthYear: user3.birthYear, 64 | }); 65 | const result2 = await db.executeQuery(compiledQuery2); 66 | expect(Number(result2?.numAffectedRows)).toEqual(1); 67 | 68 | // Verify that the correct rows were deleted 69 | 70 | const results = await db.selectFrom('users').selectAll().execute(); 71 | expect(results).toEqual([{ ...user1, id: 1 }]); 72 | }); 73 | 74 | it('parameterizes deletions, with multiple executions', async () => { 75 | interface Params { 76 | targetNickname: string; 77 | targetBirthYear: number; 78 | } 79 | await db.insertInto('users').values([user1, user2, user3]).execute(); 80 | 81 | // First execution 82 | 83 | const parameterization = parameterizeQuery( 84 | db.deleteFrom('users') 85 | ).asFollows(({ qb, param }) => 86 | qb 87 | .where('nickname', '=', param('targetNickname')) 88 | .where('birthYear', '=', param('targetBirthYear')) 89 | ); 90 | const result1 = await parameterization.execute(db, { 91 | targetNickname: user2.nickname, 92 | targetBirthYear: user2.birthYear, 93 | }); 94 | expect(Number(result1?.numAffectedRows)).toEqual(1); 95 | 96 | // Second execution 97 | 98 | const result2 = await parameterization.execute(db, { 99 | targetNickname: user3.nickname, 100 | targetBirthYear: user3.birthYear, 101 | }); 102 | expect(Number(result2?.numAffectedRows)).toEqual(1); 103 | 104 | // Verify that the correct rows were deleted 105 | 106 | const results = await db.selectFrom('users').selectAll().execute(); 107 | expect(results).toEqual([{ ...user1, id: 1 }]); 108 | }); 109 | 110 | it('parameterizes deletions using "in" operator', async () => { 111 | interface Params { 112 | targetNickname: string; 113 | targetBirthYear1: number; 114 | targetBirthYear2: number; 115 | } 116 | await db.insertInto('users').values([user1, user2, user3]).execute(); 117 | 118 | const parameterization = parameterizeQuery( 119 | db.deleteFrom('users') 120 | ).asFollows(({ qb, param }) => 121 | qb 122 | .where('nickname', '=', param('targetNickname')) 123 | .where('birthYear', 'in', [ 124 | param('targetBirthYear1'), 125 | param('targetBirthYear2'), 126 | ]) 127 | ); 128 | const results = await parameterization.execute(db, { 129 | targetNickname: user2.nickname, 130 | targetBirthYear1: 1980, 131 | targetBirthYear2: 1990, 132 | }); 133 | expect(Number(results?.numAffectedRows)).toEqual(2); 134 | 135 | const users = await db.selectFrom('users').selectAll().execute(); 136 | expect(users).toEqual([{ ...user3, id: 3 }]); 137 | }); 138 | 139 | it('parameterizes without defined parameters', async () => { 140 | await db.insertInto('users').values([user1, user2, user3]).execute(); 141 | 142 | const parameterization = parameterizeQuery(db.deleteFrom('users')).asFollows( 143 | ({ qb }) => qb.where('birthYear', '=', 1990) 144 | ); 145 | const results = await parameterization.execute(db, {}); 146 | expect(Number(results?.numAffectedRows)).toEqual(2); 147 | 148 | const users = await db.selectFrom('users').selectAll().execute(); 149 | expect(users).toEqual([{ ...user1, id: 1 }]); 150 | }); 151 | 152 | ignore('array parameters are not allowed', () => { 153 | interface InvalidParams { 154 | targetBirthYears: number[]; 155 | } 156 | // @ts-expect-error - invalid parameter type 157 | parameterizeQuery(db.deleteFrom('users')).asFollows( 158 | ({ qb, param }) => qb.where('birthYear', 'in', param('targetBirthYears')) 159 | ); 160 | }); 161 | 162 | ignore('disallows incompatible parameter types', () => { 163 | interface InvalidParams { 164 | targetHandle: number; 165 | } 166 | parameterizeQuery(db.deleteFrom('users')).asFollows( 167 | // @ts-expect-error - invalid parameter type 168 | ({ qb, param }) => qb.where('handle', '=', param('targetHandle')) 169 | ); 170 | }); 171 | 172 | ignore('restricts provided parameters', async () => { 173 | interface ValidParams { 174 | targetHandle: string; 175 | targetBirthYear: number; 176 | } 177 | 178 | const parameterization = parameterizeQuery( 179 | db.deleteFrom('users') 180 | ).asFollows(({ qb, param }) => 181 | qb 182 | .where('handle', '=', param('targetHandle')) 183 | .where('name', '=', 'John Smith') 184 | .where('birthYear', '=', param('targetBirthYear')) 185 | ); 186 | 187 | await parameterization.execute(db, { 188 | //@ts-expect-error - invalid parameter name 189 | invalidParam: 'invalid', 190 | }); 191 | await parameterization.executeTakeFirst(db, { 192 | //@ts-expect-error - invalid parameter name 193 | invalidParam: 'invalid', 194 | }); 195 | 196 | await parameterization.execute(db, { 197 | //@ts-expect-error - invalid parameter type 198 | targetBirthYear: '2020', 199 | targetHandle: 'jsmith', 200 | }); 201 | await parameterization.executeTakeFirst(db, { 202 | //@ts-expect-error - invalid parameter type 203 | targetBirthYear: '2020', 204 | targetHandle: 'jsmith', 205 | }); 206 | 207 | await parameterization.execute(db, { 208 | //@ts-expect-error - invalid parameter type 209 | targetHandle: null, 210 | }); 211 | await parameterization.executeTakeFirst(db, { 212 | //@ts-expect-error - invalid parameter type 213 | targetHandle: null, 214 | }); 215 | 216 | //@ts-expect-error - missing parameter name 217 | await parameterization.execute(db, { 218 | targetBirthYear: 2020, 219 | }); 220 | //@ts-expect-error - missing parameter name 221 | await parameterization.executeTakeFirst(db, { 222 | targetBirthYear: 2020, 223 | }); 224 | //@ts-expect-error - missing parameter name 225 | await parameterization.execute(db, {}); 226 | //@ts-expect-error - missing parameter name 227 | await parameterization.executeTakeFirst(db, {}); 228 | }); 229 | -------------------------------------------------------------------------------- /src/tests/insert-params.test.ts: -------------------------------------------------------------------------------- 1 | import { Kysely } from 'kysely'; 2 | 3 | import { createDB, resetDB, destroyDB } from '../utils/test-setup'; 4 | import { Database } from '../utils/test-tables'; 5 | import { ignore } from '../utils/test-utils'; 6 | import { parameterizeQuery } from '../lib/parameterizer'; 7 | 8 | let db: Kysely; 9 | 10 | beforeAll(async () => { 11 | db = await createDB(); 12 | }); 13 | beforeEach(() => resetDB(db)); 14 | afterAll(() => destroyDB(db)); 15 | 16 | it('instantiates inserted strings and numbers', async () => { 17 | interface Params { 18 | sourceHandle: string; 19 | sourceBirthYear: number | null; 20 | } 21 | const user = { 22 | name: 'John Smith', 23 | // leave out nickname 24 | handle: 'jsmith', 25 | birthYear: 1990, 26 | }; 27 | 28 | const parameterization = parameterizeQuery( 29 | db.insertInto('users').returning('id') 30 | ).asFollows(({ qb, param }) => 31 | qb.values({ 32 | handle: param('sourceHandle'), 33 | name: user.name, 34 | birthYear: param('sourceBirthYear'), 35 | }) 36 | ); 37 | const compiledQuery = parameterization.instantiate({ 38 | sourceHandle: user.handle, 39 | sourceBirthYear: user.birthYear, 40 | }); 41 | const result = await db.executeQuery(compiledQuery); 42 | expect(result?.rows).toEqual([{ id: 1 }]); 43 | 44 | const readUser = await db 45 | .selectFrom('users') 46 | .selectAll() 47 | .where('handle', '=', user.handle) 48 | .executeTakeFirst(); 49 | expect(readUser).toEqual({ ...user, id: 1, nickname: null }); 50 | }); 51 | 52 | it('parameterizes inserted strings and numbers with non-null values', async () => { 53 | interface Params { 54 | sourceHandle: string; 55 | sourceBirthYear: number | null; 56 | } 57 | const user = { 58 | name: 'John Smith', 59 | // leave out nickname 60 | handle: 'jsmith', 61 | birthYear: 1990, 62 | }; 63 | 64 | const parameterization = parameterizeQuery( 65 | db.insertInto('users').returning('id') 66 | ).asFollows(({ qb, param }) => 67 | qb.values({ 68 | handle: param('sourceHandle'), 69 | name: user.name, 70 | birthYear: param('sourceBirthYear'), 71 | }) 72 | ); 73 | const result = await parameterization.executeTakeFirst(db, { 74 | sourceHandle: user.handle, 75 | sourceBirthYear: user.birthYear, 76 | }); 77 | 78 | expect(result).toEqual({ id: 1 }); 79 | // Make sure we can address properties by name. 80 | expect(result?.id).toBe(1); 81 | 82 | const readUser = await db 83 | .selectFrom('users') 84 | .selectAll() 85 | .where('handle', '=', user.handle) 86 | .executeTakeFirst(); 87 | expect(readUser).toEqual({ ...user, id: 1, nickname: null }); 88 | }); 89 | 90 | it('parameterizes inserted strings and numbers with null values', async () => { 91 | interface Params { 92 | sourceNickname: string | null; 93 | sourceBirthYear: number | null; 94 | } 95 | const user = { 96 | name: 'John Smith', 97 | nickname: null, 98 | handle: 'jsmith', 99 | birthYear: null, 100 | }; 101 | 102 | const parameterization = parameterizeQuery( 103 | db.insertInto('users').returning('id') 104 | ).asFollows(({ qb, param }) => 105 | qb.values({ 106 | handle: user.handle, 107 | name: user.name, 108 | nickname: param('sourceNickname'), 109 | birthYear: param('sourceBirthYear'), 110 | }) 111 | ); 112 | const result = await parameterization.executeTakeFirst(db, { 113 | sourceNickname: user.nickname, 114 | sourceBirthYear: user.birthYear, 115 | }); 116 | 117 | expect(result).toEqual({ id: 1 }); 118 | 119 | const readUser = await db 120 | .selectFrom('users') 121 | .selectAll() 122 | .where('handle', '=', user.handle) 123 | .executeTakeFirst(); 124 | expect(readUser).toEqual({ ...user, id: 1 }); 125 | }); 126 | 127 | it('parameterizes a generated column, with multiple executions', async () => { 128 | interface Params { 129 | sourceId?: number; 130 | } 131 | const user = { 132 | handle: 'jsmith', 133 | name: 'John Smith', 134 | nickname: null, 135 | birthYear: null, 136 | }; 137 | 138 | const parameterization = parameterizeQuery( 139 | db.insertInto('users') 140 | ).asFollows(({ qb, param }) => 141 | qb.values({ 142 | id: param('sourceId'), 143 | name: user.name, 144 | handle: user.handle, 145 | }) 146 | ); 147 | 148 | // First execution not assigning generated column. 149 | 150 | const result1 = await parameterization.executeTakeFirst(db, {}); 151 | expect(result1).toBeUndefined(); 152 | const readUser = await db 153 | .selectFrom('users') 154 | .selectAll() 155 | .where('handle', '=', user.handle) 156 | .executeTakeFirst(); 157 | expect(readUser).toEqual({ ...user, id: 1 }); 158 | 159 | // Second execution assigning generated column. 160 | 161 | const result = await parameterization.executeTakeFirst(db, { sourceId: 100 }); 162 | expect(result).toBeUndefined(); 163 | const readUsers = await db 164 | .selectFrom('users') 165 | .selectAll() 166 | .where('handle', '=', user.handle) 167 | .execute(); 168 | expect(readUsers).toEqual([ 169 | { ...user, id: 1 }, 170 | { ...user, id: 100 }, 171 | ]); 172 | }); 173 | 174 | it('parameterizes single query performing multiple insertions', async () => { 175 | interface Params { 176 | sourceName1and2: string; 177 | sourceNickname1: string; 178 | sourceBirthYear1: number; 179 | sourceBirthYear2: number; 180 | } 181 | const user1 = { 182 | name: 'John Smith', 183 | nickname: 'Johny', 184 | handle: 'jsmith1', 185 | birthYear: 1990, 186 | }; 187 | const user2 = { 188 | name: 'John Smith', 189 | nickname: null, 190 | handle: 'jsmith2', 191 | birthYear: 2000, 192 | }; 193 | 194 | const parameterization = parameterizeQuery( 195 | db.insertInto('users').returning('id') 196 | ).asFollows(({ qb, param }) => 197 | qb.values([ 198 | { 199 | handle: user1.handle, 200 | name: param('sourceName1and2'), 201 | nickname: param('sourceNickname1'), 202 | birthYear: param('sourceBirthYear1'), 203 | }, 204 | { 205 | handle: user2.handle, 206 | name: param('sourceName1and2'), 207 | nickname: user2.nickname, 208 | birthYear: user2.birthYear, 209 | }, 210 | ]) 211 | ); 212 | 213 | const result = await parameterization.execute(db, { 214 | sourceName1and2: user1.name, 215 | sourceNickname1: user1.nickname, 216 | sourceBirthYear1: user1.birthYear, 217 | sourceBirthYear2: user2.birthYear, 218 | }); 219 | 220 | expect(result.rows).toEqual([{ id: 1 }, { id: 2 }]); 221 | // Make sure we can address properties by name. 222 | expect(result?.rows[0].id).toBe(1); 223 | 224 | const readUsers = await db 225 | .selectFrom('users') 226 | .selectAll() 227 | .where('name', '=', user1.name) 228 | .execute(); 229 | expect(readUsers).toEqual([ 230 | { ...user1, id: 1 }, 231 | { ...user2, id: 2 }, 232 | ]); 233 | }); 234 | 235 | it('parameterizes without defined parameters', async () => { 236 | const user = { 237 | name: 'John Smith', 238 | nickname: null, 239 | handle: 'jsmith', 240 | birthYear: null, 241 | }; 242 | 243 | const parameterization = parameterizeQuery( 244 | db.insertInto('users').returning('id') 245 | ).asFollows(({ qb }) => qb.values(user)); 246 | 247 | const result = await parameterization.executeTakeFirst(db, {}); 248 | expect(result).toEqual({ id: 1 }); 249 | 250 | const readUser = await db 251 | .selectFrom('users') 252 | .selectAll() 253 | .where('handle', '=', user.handle) 254 | .executeTakeFirst(); 255 | expect(readUser).toEqual({ ...user, id: 1 }); 256 | }); 257 | 258 | ignore('disallows incompatible parameter types', () => { 259 | interface InvalidParams { 260 | sourceHandle: number; 261 | sourceName: string | null; 262 | } 263 | 264 | parameterizeQuery(db.insertInto('users')).asFollows( 265 | ({ qb, param }) => 266 | qb.values({ 267 | //@ts-expect-error - invalid parameter type 268 | handle: param('sourceHandle'), 269 | name: 'John Smith', 270 | }) 271 | ); 272 | 273 | parameterizeQuery(db.insertInto('users')).asFollows( 274 | ({ qb, param }) => 275 | qb.values({ 276 | handle: 'jsmith', 277 | //@ts-expect-error - invalid parameter type 278 | name: param('sourceName'), 279 | }) 280 | ); 281 | }); 282 | 283 | ignore('restricts a generated column parameter', async () => { 284 | interface InvalidParams { 285 | sourceId?: string; 286 | } 287 | 288 | parameterizeQuery(db.insertInto('users')).asFollows( 289 | ({ qb, param }) => 290 | qb.values({ 291 | //@ts-expect-error - invalid parameter type 292 | id: param('sourceId'), 293 | name: 'John Smith', 294 | handle: 'jsmith', 295 | }) 296 | ); 297 | }); 298 | 299 | ignore('restricts provided parameters', async () => { 300 | interface ValidParams { 301 | sourceHandle: string; 302 | sourceBirthYear: number | null; 303 | } 304 | 305 | const parameterization = parameterizeQuery( 306 | db.insertInto('users') 307 | ).asFollows(({ qb, param }) => 308 | qb.values({ 309 | handle: param('sourceHandle'), 310 | name: 'John Smith', 311 | birthYear: param('sourceBirthYear'), 312 | }) 313 | ); 314 | 315 | await parameterization.execute(db, { 316 | //@ts-expect-error - invalid parameter name 317 | invalidParam: 'invalid', 318 | }); 319 | await parameterization.executeTakeFirst(db, { 320 | //@ts-expect-error - invalid parameter name 321 | invalidParam: 'invalid', 322 | }); 323 | 324 | await parameterization.execute(db, { 325 | //@ts-expect-error - invalid parameter type 326 | sourceBirthYear: '2020', 327 | sourceHandle: 'jsmith', 328 | }); 329 | await parameterization.executeTakeFirst(db, { 330 | //@ts-expect-error - invalid parameter type 331 | sourceBirthYear: '2020', 332 | sourceHandle: 'jsmith', 333 | }); 334 | 335 | await parameterization.execute(db, { 336 | //@ts-expect-error - invalid parameter type 337 | sourceHandle: null, 338 | sourceBirthYear: null, 339 | }); 340 | await parameterization.executeTakeFirst(db, { 341 | //@ts-expect-error - invalid parameter type 342 | sourceHandle: null, 343 | sourceBirthYear: null, 344 | }); 345 | 346 | //@ts-expect-error - missing parameter name 347 | await parameterization.execute(db, { 348 | sourceBirthYear: 2020, 349 | }); 350 | //@ts-expect-error - missing parameter name 351 | await parameterization.executeTakeFirst(db, { 352 | sourceBirthYear: 2020, 353 | }); 354 | //@ts-expect-error - missing parameter name 355 | await parameterization.execute(db, {}); 356 | //@ts-expect-error - missing parameter name 357 | await parameterization.executeTakeFirst(db, {}); 358 | }); 359 | 360 | ignore('restrict returned column names', async () => { 361 | interface ValidParams { 362 | sourceHandle: string; 363 | sourceBirthYear: number | null; 364 | } 365 | 366 | const parameterization = parameterizeQuery( 367 | db.insertInto('users').returning('id') 368 | ).asFollows(({ qb, param }) => 369 | qb.values({ 370 | handle: param('sourceHandle'), 371 | name: 'John Smith', 372 | birthYear: param('sourceBirthYear'), 373 | }) 374 | ); 375 | 376 | const result1 = await parameterization.executeTakeFirst(db, { 377 | sourceHandle: 'jsmith', 378 | sourceBirthYear: 2020, 379 | }); 380 | // @ts-expect-error - invalid column name 381 | result1?.notThere; 382 | 383 | const result2 = await parameterization.execute(db, { 384 | sourceHandle: 'jsmith', 385 | sourceBirthYear: 2020, 386 | }); 387 | // @ts-expect-error - invalid column name 388 | result2.rows[0]?.notThere; 389 | }); 390 | -------------------------------------------------------------------------------- /src/tests/select-params.test.ts: -------------------------------------------------------------------------------- 1 | import { Kysely, sql } from 'kysely'; 2 | 3 | import { createDB, resetDB, destroyDB } from '../utils/test-setup'; 4 | import { Database } from '../utils/test-tables'; 5 | import { ignore } from '../utils/test-utils'; 6 | import { parameterizeQuery } from '../lib/parameterizer'; 7 | 8 | let db: Kysely; 9 | 10 | beforeAll(async () => { 11 | db = await createDB(); 12 | }); 13 | beforeEach(() => resetDB(db)); 14 | afterAll(() => destroyDB(db)); 15 | 16 | const user1 = { 17 | name: 'John Smith', 18 | nickname: 'Johnny', 19 | handle: 'jsmith', 20 | birthYear: 1980, 21 | }; 22 | const user2 = { 23 | name: 'John McSmith', 24 | nickname: 'Johnny', 25 | handle: 'jmsmith', 26 | birthYear: 1990, 27 | }; 28 | const user3 = { 29 | name: 'Jane Doe', 30 | // leave out nickname 31 | handle: 'jdoe', 32 | birthYear: 1990, 33 | }; 34 | 35 | it('instantiates "where" selections, with multiple executions', async () => { 36 | interface Params { 37 | targetNickname: string; 38 | targetBirthYear: number; 39 | } 40 | await db.insertInto('users').values([user1, user2, user3]).execute(); 41 | 42 | const parameterization = parameterizeQuery( 43 | db.selectFrom('users').selectAll() 44 | ).asFollows(({ qb, param }) => 45 | qb 46 | .where('nickname', '=', param('targetNickname')) 47 | .where('birthYear', '=', param('targetBirthYear')) 48 | ); 49 | 50 | // First execution 51 | 52 | const compiledQuery1 = parameterization.instantiate({ 53 | targetNickname: user2.nickname, 54 | targetBirthYear: user2.birthYear, 55 | }); 56 | const result1 = await db.executeQuery(compiledQuery1); 57 | expect(result1?.rows).toEqual([{ ...user2, id: 2 }]); 58 | 59 | // Second execution 60 | 61 | const compiledQuery2 = parameterization.instantiate({ 62 | targetNickname: user2.nickname, 63 | targetBirthYear: 1980, 64 | }); 65 | const result2 = await db.executeQuery(compiledQuery2); 66 | expect(result2?.rows).toEqual([{ ...user1, id: 1 }]); 67 | 68 | // Allows constant parameters 69 | 70 | const params = { 71 | targetNickname: 'Jane' as const, 72 | targetBirthYear: 1990 as const, 73 | } as const; 74 | parameterization.instantiate(params); 75 | }); 76 | 77 | it('parameterizes "where" selections, with multiple executions', async () => { 78 | interface Params { 79 | targetNickname: string; 80 | targetBirthYear: number; 81 | } 82 | await db.insertInto('users').values([user1, user2, user3]).execute(); 83 | 84 | // First execution 85 | 86 | const parameterization = parameterizeQuery( 87 | db.selectFrom('users').selectAll() 88 | ).asFollows(({ qb, param }) => 89 | qb 90 | .where('nickname', '=', param('targetNickname')) 91 | .where('birthYear', '=', param('targetBirthYear')) 92 | ); 93 | const result1 = await parameterization.executeTakeFirst(db, { 94 | targetNickname: user2.nickname, 95 | targetBirthYear: user2.birthYear, 96 | }); 97 | expect(result1).toEqual({ ...user2, id: 2 }); 98 | // Make sure we can address properties by name. 99 | expect(result1?.name).toEqual(user2.name); 100 | 101 | // Second execution 102 | 103 | const result2 = await parameterization.executeTakeFirst(db, { 104 | targetNickname: user2.nickname, 105 | targetBirthYear: 1980, 106 | }); 107 | expect(result2).toEqual({ ...user1, id: 1 }); 108 | 109 | // Allows constant parameters 110 | 111 | const params = { 112 | targetNickname: 'Jane' as const, 113 | targetBirthYear: 1990 as const, 114 | } as const; 115 | parameterization.execute(db, params); 116 | parameterization.executeTakeFirst(db, params); 117 | }); 118 | 119 | it('parameterizes "where" selections for specific columns', async () => { 120 | interface Params { 121 | targetHandle: string; 122 | } 123 | await db.insertInto('users').values([user1, user2, user3]).execute(); 124 | 125 | const parameterization = parameterizeQuery( 126 | db.selectFrom('users').select('name') 127 | ).asFollows(({ qb, param }) => 128 | qb.where('handle', '=', param('targetHandle')) 129 | ); 130 | const result1 = await parameterization.executeTakeFirst(db, { 131 | targetHandle: user3.handle, 132 | }); 133 | expect(result1).toEqual({ name: user3.name }); 134 | }); 135 | 136 | it('parameterizes "where" selections using "in" operator', async () => { 137 | interface Params { 138 | targetNickname: string; 139 | targetBirthYear1: number; 140 | targetBirthYear2: number; 141 | } 142 | await db.insertInto('users').values([user1, user2, user3]).execute(); 143 | 144 | const parameterization = parameterizeQuery( 145 | db.selectFrom('users').selectAll() 146 | ).asFollows(({ qb, param }) => 147 | qb 148 | .where('nickname', '=', param('targetNickname')) 149 | .where('birthYear', 'in', [ 150 | param('targetBirthYear1'), 151 | param('targetBirthYear2'), 152 | ]) 153 | ); 154 | const results = await parameterization.execute(db, { 155 | targetNickname: user2.nickname, 156 | targetBirthYear1: 1980, 157 | targetBirthYear2: 1990, 158 | }); 159 | expect(results.rows).toEqual([ 160 | { ...user1, id: 1 }, 161 | { ...user2, id: 2 }, 162 | ]); 163 | // Make sure we can address properties by name. 164 | expect(results.rows[0].name).toEqual(user1.name); 165 | }); 166 | 167 | it('parameterizes values within a where expression', async () => { 168 | interface Params { 169 | targetNickname: string; 170 | targetBirthYear1: number; 171 | targetBirthYear2: number; 172 | } 173 | await db.insertInto('users').values([user1, user2, user3]).execute(); 174 | 175 | const parameterization = parameterizeQuery( 176 | db.selectFrom('users').selectAll() 177 | ).asFollows(({ qb, param }) => 178 | qb.where(({ and, cmpr }) => 179 | and([ 180 | cmpr('nickname', '=', param('targetNickname')), 181 | cmpr('birthYear', 'in', [ 182 | param('targetBirthYear1'), 183 | param('targetBirthYear2'), 184 | ]), 185 | ]) 186 | ) 187 | ); 188 | const results = await parameterization.execute(db, { 189 | targetNickname: user2.nickname, 190 | targetBirthYear1: 1980, 191 | targetBirthYear2: 1990, 192 | }); 193 | expect(results.rows).toEqual([ 194 | { ...user1, id: 1 }, 195 | { ...user2, id: 2 }, 196 | ]); 197 | }); 198 | 199 | it('parameterizes values within a SQL expression', async () => { 200 | interface Params { 201 | targetName: string; 202 | } 203 | await db.insertInto('users').values([user1, user2, user3]).execute(); 204 | 205 | const parameterization = parameterizeQuery( 206 | db.selectFrom('users').selectAll() 207 | ).asFollows(({ qb, param }) => 208 | qb.where(sql`name = ${param('targetName')}`) 209 | ); 210 | 211 | // First execution 212 | 213 | const results1 = await parameterization.execute(db, { 214 | targetName: user1.name, 215 | }); 216 | expect(results1.rows).toEqual([{ ...user1, id: 1 }]); 217 | 218 | // Second execution 219 | 220 | const results2 = await parameterization.execute(db, { 221 | targetName: user2.name, 222 | }); 223 | expect(results2.rows).toEqual([{ ...user2, id: 2 }]); 224 | }); 225 | 226 | it('parameterizes without defined parameters', async () => { 227 | await db.insertInto('users').values([user1, user2, user3]).execute(); 228 | 229 | const parameterization = parameterizeQuery( 230 | db.selectFrom('users').selectAll() 231 | ).asFollows(({ qb }) => 232 | qb 233 | .where('nickname', '=', user2.nickname) 234 | .where('birthYear', '=', user1.birthYear) 235 | ); 236 | const result2 = await parameterization.executeTakeFirst(db, {}); 237 | expect(result2).toEqual({ ...user1, id: 1 }); 238 | }); 239 | 240 | ignore('array parameters are not allowed', () => { 241 | interface InvalidParams { 242 | targetBirthYears: number[]; 243 | } 244 | parameterizeQuery( 245 | db.selectFrom('users').selectAll() 246 | // @ts-expect-error - invalid parameter type 247 | ).asFollows(({ qb, param }) => 248 | qb.where('birthYear', 'in', param('targetBirthYears')) 249 | ); 250 | }); 251 | 252 | ignore('disallows incompatible parameter types', () => { 253 | interface InvalidParams { 254 | targetHandle: number; 255 | } 256 | parameterizeQuery(db.selectFrom('users')).asFollows( 257 | ({ qb, param }) => 258 | //@ts-expect-error - invalid parameter type 259 | qb.where('handle', '=', param('targetHandle')) 260 | ); 261 | parameterizeQuery(db.selectFrom('users')).asFollows( 262 | ({ qb, param }) => 263 | qb.where(({ or, cmpr }) => 264 | //@ts-expect-error - invalid parameter type 265 | or([cmpr('handle', '=', param('targetHandle'))]) 266 | ) 267 | ); 268 | }); 269 | 270 | ignore('disallows parameters in column positions', () => { 271 | interface ValidParams { 272 | targetHandle: string; 273 | } 274 | 275 | parameterizeQuery(db.selectFrom('users')).asFollows( 276 | ({ qb, param }) => 277 | // @ts-expect-error - invalid parameter position 278 | qb.where(param('targetHandle'), '=', 'jsmith') 279 | ); 280 | 281 | parameterizeQuery(db.selectFrom('users')).asFollows( 282 | ({ qb, param }) => 283 | qb.where(({ or, cmpr }) => 284 | or([ 285 | // @ts-expect-error - invalid parameter position 286 | cmpr(param('targetHandle'), '=', 'jsmith'), 287 | // @ts-expect-error - invalid parameter position 288 | cmpr('birthYear', param('targetHandle'), 1980), 289 | ]) 290 | ) 291 | ); 292 | }); 293 | 294 | ignore('restricts provided parameters', async () => { 295 | interface ValidParams { 296 | targetHandle: string; 297 | targetBirthYear: number; 298 | } 299 | 300 | const parameterization = parameterizeQuery( 301 | db.selectFrom('users') 302 | ).asFollows(({ qb, param }) => 303 | qb 304 | .where('handle', '=', param('targetHandle')) 305 | .where('name', '=', 'John Smith') 306 | .where('birthYear', '=', param('targetBirthYear')) 307 | ); 308 | 309 | await parameterization.execute(db, { 310 | //@ts-expect-error - invalid parameter name 311 | invalidParam: 'invalid', 312 | }); 313 | await parameterization.executeTakeFirst(db, { 314 | //@ts-expect-error - invalid parameter name 315 | invalidParam: 'invalid', 316 | }); 317 | 318 | await parameterization.execute(db, { 319 | //@ts-expect-error - invalid parameter type 320 | targetBirthYear: '2020', 321 | targetHandle: 'jsmith', 322 | }); 323 | await parameterization.executeTakeFirst(db, { 324 | //@ts-expect-error - invalid parameter type 325 | targetBirthYear: '2020', 326 | targetHandle: 'jsmith', 327 | }); 328 | 329 | await parameterization.execute(db, { 330 | //@ts-expect-error - invalid parameter type 331 | targetHandle: null, 332 | }); 333 | await parameterization.executeTakeFirst(db, { 334 | //@ts-expect-error - invalid parameter type 335 | targetHandle: null, 336 | }); 337 | 338 | //@ts-expect-error - missing parameter name 339 | await parameterization.execute(db, { 340 | targetBirthYear: 2020, 341 | }); 342 | //@ts-expect-error - missing parameter name 343 | await parameterization.executeTakeFirst(db, { 344 | targetBirthYear: 2020, 345 | }); 346 | //@ts-expect-error - missing parameter name 347 | await parameterization.execute(db, {}); 348 | //@ts-expect-error - missing parameter name 349 | await parameterization.executeTakeFirst(db, {}); 350 | }); 351 | 352 | ignore('restrict selected column names', async () => { 353 | interface ValidParams { 354 | targetHandle: string; 355 | } 356 | 357 | const parameterization = parameterizeQuery( 358 | db.selectFrom('users').selectAll() 359 | ).asFollows(({ qb, param }) => 360 | qb.where('handle', '=', param('targetHandle')) 361 | ); 362 | 363 | const result1 = await parameterization.executeTakeFirst(db, { 364 | targetHandle: 'jsmith', 365 | }); 366 | // @ts-expect-error - invalid returned column 367 | expect(result1?.notThere).toEqual('John Smith'); 368 | 369 | const result2 = await parameterization.execute(db, { 370 | targetHandle: 'jsmith', 371 | }); 372 | const firstRow = result2.rows[0]; 373 | // @ts-expect-error - invalid returned column 374 | expect(firstRow.notThere).toEqual('John Smith'); 375 | }); 376 | -------------------------------------------------------------------------------- /src/tests/update-params.test.ts: -------------------------------------------------------------------------------- 1 | import { Kysely } from 'kysely'; 2 | 3 | import { createDB, resetDB, destroyDB } from '../utils/test-setup'; 4 | import { Database } from '../utils/test-tables'; 5 | import { ignore } from '../utils/test-utils'; 6 | import { parameterizeQuery } from '../lib/parameterizer'; 7 | 8 | let db: Kysely; 9 | 10 | beforeAll(async () => { 11 | db = await createDB(); 12 | }); 13 | beforeEach(() => resetDB(db)); 14 | afterAll(() => destroyDB(db)); 15 | 16 | const user1 = { 17 | name: 'John Smith', 18 | nickname: 'Johnny', 19 | handle: 'jsmith', 20 | birthYear: 1980, 21 | }; 22 | const user2 = { 23 | name: 'John McSmith', 24 | nickname: 'Johnny', 25 | handle: 'jmsmith', 26 | birthYear: 1990, 27 | }; 28 | const user3 = { 29 | name: 'Jane Doe', 30 | nickname: 'Jane', 31 | handle: 'jdoe', 32 | birthYear: 1990, 33 | }; 34 | 35 | it("instantiates update values and 'where' selections, with multiple executions", async () => { 36 | interface Params { 37 | toBirthYear: number; 38 | whereNickname: string; 39 | } 40 | await db.insertInto('users').values([user1, user2, user3]).execute(); 41 | 42 | const parameterization = parameterizeQuery( 43 | db.updateTable('users') 44 | ).asFollows(({ qb, param }) => 45 | qb 46 | .set({ 47 | birthYear: param('toBirthYear'), 48 | handle: 'newHandle', 49 | }) 50 | .where('nickname', '=', param('whereNickname')) 51 | ); 52 | 53 | // First execution 54 | 55 | const compiledQuery1 = parameterization.instantiate({ 56 | toBirthYear: 2000, 57 | whereNickname: user2.nickname, 58 | }); 59 | const result1 = await db.executeQuery(compiledQuery1); 60 | expect(Number(result1?.numAffectedRows)).toEqual(2); 61 | 62 | // Second execution 63 | 64 | const compiledQuery2 = parameterization.instantiate({ 65 | toBirthYear: 2010, 66 | whereNickname: user3.nickname, 67 | }); 68 | const result2 = await db.executeQuery(compiledQuery2); 69 | expect(Number(result2?.numAffectedRows)).toEqual(1); 70 | 71 | const users = await db.selectFrom('users').selectAll().execute(); 72 | expect(users).toEqual([ 73 | { ...user1, id: 1, handle: 'newHandle', birthYear: 2000 }, 74 | { ...user2, id: 2, handle: 'newHandle', birthYear: 2000 }, 75 | { ...user3, id: 3, handle: 'newHandle', birthYear: 2010 }, 76 | ]); 77 | }); 78 | 79 | it("parameterizes update values and 'where' selections, with multiple executions", async () => { 80 | interface Params { 81 | toBirthYear: number; 82 | whereNickname: string; 83 | } 84 | await db.insertInto('users').values([user1, user2, user3]).execute(); 85 | 86 | // First execution 87 | 88 | const parameterization = parameterizeQuery( 89 | db.updateTable('users') 90 | ).asFollows(({ qb, param }) => 91 | qb 92 | .set({ 93 | birthYear: param('toBirthYear'), 94 | handle: 'newHandle', 95 | }) 96 | .where('nickname', '=', param('whereNickname')) 97 | ); 98 | 99 | const result1 = await parameterization.execute(db, { 100 | toBirthYear: 2000, 101 | whereNickname: user2.nickname, 102 | }); 103 | expect(Number(result1.numAffectedRows)).toEqual(2); 104 | 105 | // Second execution 106 | 107 | const result2 = await parameterization.executeTakeFirst(db, { 108 | toBirthYear: 2010, 109 | whereNickname: user3.nickname, 110 | }); 111 | expect(result2).toBeUndefined(); 112 | 113 | const users = await db.selectFrom('users').selectAll().execute(); 114 | expect(users).toEqual([ 115 | { ...user1, id: 1, handle: 'newHandle', birthYear: 2000 }, 116 | { ...user2, id: 2, handle: 'newHandle', birthYear: 2000 }, 117 | { ...user3, id: 3, handle: 'newHandle', birthYear: 2010 }, 118 | ]); 119 | }); 120 | 121 | it('parameterizes update values accepting nulls', async () => { 122 | interface Params { 123 | toBirthYear: number | null; 124 | whereNickname: string; 125 | } 126 | await db.insertInto('users').values([user1, user2, user3]).execute(); 127 | 128 | const parameterization = parameterizeQuery( 129 | db.updateTable('users') 130 | ).asFollows(({ qb, param }) => 131 | qb 132 | .set({ 133 | birthYear: param('toBirthYear'), 134 | }) 135 | .where('nickname', '=', param('whereNickname')) 136 | ); 137 | 138 | const result1 = await parameterization.execute(db, { 139 | toBirthYear: null, 140 | whereNickname: user2.nickname, 141 | }); 142 | expect(Number(result1.numAffectedRows)).toEqual(2); 143 | 144 | const result2 = await parameterization.executeTakeFirst(db, { 145 | toBirthYear: 2010, 146 | whereNickname: user3.nickname, 147 | }); 148 | expect(result2).toBeUndefined(); 149 | 150 | const users = await db.selectFrom('users').selectAll().execute(); 151 | expect(users).toEqual([ 152 | { ...user1, id: 1, birthYear: null }, 153 | { ...user2, id: 2, birthYear: null }, 154 | { ...user3, id: 3, birthYear: 2010 }, 155 | ]); 156 | }); 157 | 158 | it('parameterizes without defined parameters', async () => { 159 | await db.insertInto('users').values([user1, user2, user3]).execute(); 160 | 161 | const parameterization = parameterizeQuery(db.updateTable('users')).asFollows( 162 | ({ qb }) => 163 | qb 164 | .set({ 165 | birthYear: 2000, 166 | handle: 'newHandle', 167 | }) 168 | .where('nickname', '=', 'Johnny') 169 | ); 170 | 171 | const result1 = await parameterization.execute(db, {}); 172 | 173 | expect(Number(result1.numAffectedRows)).toEqual(2); 174 | 175 | const users = await db.selectFrom('users').selectAll().execute(); 176 | expect(users).toEqual([ 177 | { ...user1, id: 1, handle: 'newHandle', birthYear: 2000 }, 178 | { ...user2, id: 2, handle: 'newHandle', birthYear: 2000 }, 179 | { ...user3, id: 3, handle: 'jdoe', birthYear: 1990 }, 180 | ]); 181 | }); 182 | 183 | ignore('disallows incompatible set parameter types', () => { 184 | interface InvalidParams { 185 | sourceHandle: number; 186 | sourceName: string | null; 187 | } 188 | 189 | parameterizeQuery(db.updateTable('users')).asFollows( 190 | ({ qb, param }) => 191 | qb.set({ 192 | //@ts-expect-error - invalid parameter type 193 | handle: param('sourceHandle'), 194 | name: 'John Smith', 195 | }) 196 | ); 197 | 198 | parameterizeQuery(db.updateTable('users')).asFollows( 199 | ({ qb, param }) => 200 | qb.set({ 201 | handle: 'jsmith', 202 | //@ts-expect-error - invalid parameter type 203 | name: param('sourceName'), 204 | }) 205 | ); 206 | }); 207 | 208 | ignore('restricts a set generated column parameter', async () => { 209 | interface InvalidParams { 210 | sourceId?: string; 211 | } 212 | 213 | parameterizeQuery(db.insertInto('users')).asFollows( 214 | ({ qb, param }) => 215 | qb.values({ 216 | //@ts-expect-error - invalid parameter type 217 | id: param('sourceId'), 218 | name: 'John Smith', 219 | handle: 'jsmith', 220 | }) 221 | ); 222 | }); 223 | 224 | ignore('array parameters are not allowed', () => { 225 | interface InvalidParams { 226 | targetBirthYears: number[]; 227 | } 228 | parameterizeQuery(db.updateTable('users')) 229 | // @ts-expect-error - invalid parameter type 230 | .asFollows(({ qb, param }) => 231 | qb 232 | .set({ nickname: 'newNickname' }) 233 | .where('birthYear', 'in', param('targetBirthYears')) 234 | ); 235 | }); 236 | 237 | ignore('disallows incompatible parameter types', () => { 238 | interface InvalidParams { 239 | targetHandle: number; 240 | } 241 | parameterizeQuery(db.updateTable('users')).asFollows( 242 | ({ qb, param }) => 243 | qb 244 | .set({ nickname: 'newNickname' }) 245 | //@ts-expect-error - invalid parameter type 246 | .where('handle', '=', param('targetHandle')) 247 | ); 248 | }); 249 | 250 | ignore('restricts provided parameters', async () => { 251 | interface ValidParams { 252 | targetHandle: string; 253 | targetBirthYear: number; 254 | } 255 | 256 | const parameterization = parameterizeQuery( 257 | db.updateTable('users') 258 | ).asFollows(({ qb, param }) => 259 | qb 260 | .set({ nickname: 'newNickname' }) 261 | .where('handle', '=', param('targetHandle')) 262 | .where('name', '=', 'John Smith') 263 | .where('birthYear', '=', param('targetBirthYear')) 264 | ); 265 | 266 | await parameterization.execute(db, { 267 | //@ts-expect-error - invalid parameter name 268 | invalidParam: 'invalid', 269 | }); 270 | await parameterization.executeTakeFirst(db, { 271 | //@ts-expect-error - invalid parameter name 272 | invalidParam: 'invalid', 273 | }); 274 | 275 | await parameterization.execute(db, { 276 | //@ts-expect-error - invalid parameter type 277 | targetBirthYear: '2020', 278 | targetHandle: 'jsmith', 279 | }); 280 | await parameterization.executeTakeFirst(db, { 281 | //@ts-expect-error - invalid parameter type 282 | targetBirthYear: '2020', 283 | targetHandle: 'jsmith', 284 | }); 285 | 286 | await parameterization.execute(db, { 287 | //@ts-expect-error - invalid parameter type 288 | targetHandle: null, 289 | }); 290 | await parameterization.executeTakeFirst(db, { 291 | //@ts-expect-error - invalid parameter type 292 | targetHandle: null, 293 | }); 294 | 295 | //@ts-expect-error - missing parameter name 296 | await parameterization.execute(db, { 297 | targetBirthYear: 2020, 298 | }); 299 | //@ts-expect-error - missing parameter name 300 | await parameterization.executeTakeFirst(db, { 301 | targetBirthYear: 2020, 302 | }); 303 | //@ts-expect-error - missing parameter name 304 | await parameterization.execute(db, {}); 305 | //@ts-expect-error - missing parameter name 306 | await parameterization.executeTakeFirst(db, {}); 307 | }); 308 | -------------------------------------------------------------------------------- /src/utils/test-setup.ts: -------------------------------------------------------------------------------- 1 | import Sqlite3 from 'better-sqlite3'; 2 | import { Kysely, SqliteDialect } from 'kysely'; 3 | 4 | import { Database, createTables, dropTables } from './test-tables.js'; 5 | 6 | export async function createDB() { 7 | return new Kysely({ 8 | dialect: new SqliteDialect({ 9 | database: new Sqlite3(':memory:'), 10 | }), 11 | }); 12 | } 13 | 14 | export async function resetDB(db: Kysely) { 15 | await dropTables(db); 16 | await createTables(db); 17 | } 18 | 19 | export async function destroyDB(db: Kysely) { 20 | return db.destroy(); 21 | } 22 | -------------------------------------------------------------------------------- /src/utils/test-tables.ts: -------------------------------------------------------------------------------- 1 | import { Kysely, Generated } from 'kysely'; 2 | 3 | // list tables after those they depend on 4 | const TABLE_NAMES = ['users']; 5 | 6 | export interface Database { 7 | users: Users; 8 | } 9 | 10 | export interface Users { 11 | id: Generated; 12 | handle: string; 13 | name: string; 14 | nickname: string | null; 15 | birthYear: number | null; 16 | } 17 | 18 | export async function createTables(db: Kysely) { 19 | await db.schema 20 | .createTable('users') 21 | .addColumn('id', 'integer', (col) => col.autoIncrement().primaryKey()) 22 | .addColumn('handle', 'varchar(255)', (col) => col.notNull()) 23 | .addColumn('name', 'varchar(255)', (col) => col.notNull()) 24 | .addColumn('nickname', 'varchar(255)') 25 | .addColumn('birthYear', 'integer') 26 | .execute(); 27 | 28 | return db; 29 | } 30 | 31 | export async function dropTables(db: Kysely): Promise { 32 | for (const table of TABLE_NAMES) { 33 | await db.schema.dropTable(table).ifExists().execute(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/utils/test-utils.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Embeds code that will never run within a callback. Useful for 3 | * testing expected type errors. 4 | * @param description Description of the code that will never run 5 | * @param callback Callback that will never run 6 | */ 7 | export function ignore(_description: string, _: () => void) {} 8 | -------------------------------------------------------------------------------- /tsconfig.cjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "CommonJS", 5 | "outDir": "dist/cjs" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "compilerOptions": { 4 | "target": "ES6", 5 | "types": ["vitest/globals"], 6 | "sourceMap": true, 7 | "composite": false, 8 | "declaration": true, 9 | "declarationMap": true, 10 | "esModuleInterop": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "inlineSources": false, 13 | "moduleResolution": "node", 14 | "preserveWatchOutput": true, 15 | "skipLibCheck": true, 16 | "strict": true, 17 | "experimentalDecorators": true, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | "noImplicitReturns": true, 21 | "noFallthroughCasesInSwitch": true, 22 | "outDir": "./dist/esm", 23 | "rootDir": "./src" 24 | }, 25 | "include": ["*.d.ts", "**/*.ts", "**/*.tsx"], 26 | "exclude": ["dist", "build", "node_modules"] 27 | } 28 | -------------------------------------------------------------------------------- /vitest.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitest/config'; 2 | 3 | export default defineConfig({ 4 | plugins: [], 5 | test: { 6 | include: ['**/*.test.ts', '**/*.spec.ts'], 7 | globals: true, 8 | }, 9 | }); 10 | --------------------------------------------------------------------------------