├── .gitattributes ├── .github ├── dependabot.yml └── workflows │ ├── main.yml │ ├── node.js.yml │ └── npm-publish.yml ├── .gitignore ├── ErrorProcessor.js ├── HandlerProcessor.js ├── LICENSE ├── MessageGenerator.js ├── README.md ├── ServiceParser.js ├── TraceGenerator.js ├── cds-plugin.js ├── index.js ├── package-lock.json ├── package.json └── tests ├── .cdsrc.json ├── .vscode ├── extensions.json ├── launch.json ├── settings.json └── tasks.json ├── _i18n └── i18n.properties ├── db ├── data-model.cds └── data │ └── my.bookshop-Books.csv ├── eslint.config.js ├── package-lock.json ├── package.json ├── srv ├── cat-fiori-service.cds ├── cat-service.cds └── handlers │ ├── ConditionalCheck.js │ └── DateChecks.js └── test ├── BatchProcessor.js ├── batchrequests ├── activate.txt ├── child_create.txt ├── child_patch.txt ├── create.txt ├── edit.txt └── edit_activate.txt └── test.js /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file 5 | 6 | version: 2 7 | updates: 8 | # Enable version updates for npm 9 | - package-ecosystem: "npm" 10 | # Look for `package.json` and `lock` files in the `root` directory 11 | directory: "/","tests/" 12 | # Check the npm registry for updates every day (weekdays) 13 | schedule: 14 | interval: "daily" 15 | - package-ecosystem: "npm" 16 | # Look for `package.json` and `lock` files in the `root` directory 17 | directory: "/tests" 18 | # Check the npm registry for updates every day (weekdays) 19 | schedule: 20 | interval: "daily" 21 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | # Manual test 2 | 3 | name: Test on push and PR 4 | 5 | on: 6 | workflow_dispatch: 7 | push: 8 | branches: main 9 | pull_request: 10 | branches: main 11 | jobs: 12 | build-linux: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | - uses: actions/setup-node@v4 17 | with: 18 | node-version: 22 19 | - run: npm ci 20 | - run: cd tests && npm ci 21 | - run: npm run test 22 | -------------------------------------------------------------------------------- /.github/workflows/node.js.yml: -------------------------------------------------------------------------------- 1 | # This workflow performs an install of the latest packages of all dependecies(feature/tests branch) and executes tests 2 | name: Nightly Test 3 | 4 | on: 5 | # This can be used to automatically publish nightlies at UTC nighttime 6 | schedule: 7 | - cron: '0 23 * * *' # run at 11 PM UTC 8 | # This can be used to allow manually triggering nightlies from the web interface 9 | workflow_dispatch: 10 | jobs: 11 | build-linux: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | with: 16 | ref: main 17 | - uses: actions/setup-node@v4 18 | with: 19 | node-version: 20 20 | - run: npm install && npm update 21 | - run: cd tests && npm install && npm update 22 | - run: npm list 23 | - run: cd tests && npm list 24 | - run: npm run test 25 | 26 | -------------------------------------------------------------------------------- /.github/workflows/npm-publish.yml: -------------------------------------------------------------------------------- 1 | # This workflow will run tests using node and then publish a package to NPM when a release is created 2 | 3 | name: NPM Publish on release 4 | 5 | on: 6 | release: 7 | types: [created] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v4 14 | - uses: actions/setup-node@v4 15 | with: 16 | node-version: 22 17 | - run: npm ci 18 | - run: cd tests && npm ci 19 | - run: npm run test 20 | 21 | publish-npm: 22 | needs: build 23 | runs-on: ubuntu-latest 24 | steps: 25 | - uses: actions/checkout@v4 26 | - uses: actions/setup-node@v4 27 | with: 28 | node-version: 20 29 | registry-url: https://registry.npmjs.org/ 30 | - run: npm ci 31 | - run: npm publish 32 | env: 33 | NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN1}} 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Snowpack dependency directory (https://snowpack.dev/) 46 | web_modules/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Optional stylelint cache 58 | .stylelintcache 59 | 60 | # Microbundle cache 61 | .rpt2_cache/ 62 | .rts2_cache_cjs/ 63 | .rts2_cache_es/ 64 | .rts2_cache_umd/ 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Output of 'npm pack' 70 | *.tgz 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # dotenv environment variable files 76 | .env 77 | .env.development.local 78 | .env.test.local 79 | .env.production.local 80 | .env.local 81 | 82 | # parcel-bundler cache (https://parceljs.org/) 83 | .cache 84 | .parcel-cache 85 | 86 | # Next.js build output 87 | .next 88 | out 89 | 90 | # Nuxt.js build / generate output 91 | .nuxt 92 | dist 93 | 94 | # Gatsby files 95 | .cache/ 96 | # Comment in the public line in if your project uses Gatsby and not Next.js 97 | # https://nextjs.org/blog/next-9-1#public-directory-support 98 | # public 99 | 100 | # vuepress build output 101 | .vuepress/dist 102 | 103 | # vuepress v2.x temp and cache directory 104 | .temp 105 | .cache 106 | 107 | # Serverless directories 108 | .serverless/ 109 | 110 | # FuseBox cache 111 | .fusebox/ 112 | 113 | # DynamoDB Local files 114 | .dynamodb/ 115 | 116 | # TernJS port file 117 | .tern-port 118 | 119 | # Stores VSCode versions used for testing VSCode extensions 120 | .vscode-test 121 | 122 | # yarn v2 123 | .yarn/cache 124 | .yarn/unplugged 125 | .yarn/build-state.yml 126 | .yarn/install-state.gz 127 | .pnp.* 128 | -------------------------------------------------------------------------------- /ErrorProcessor.js: -------------------------------------------------------------------------------- 1 | const MessageGenerator = require("./MessageGenerator.js"); 2 | const TraceGenerator = require("./TraceGenerator.js"); 3 | 4 | module.exports = class HandlerProcessor { 5 | constructor(entity, validationElements, entities, serviceName) { 6 | this.entity = entity; 7 | this.validationElements = validationElements; 8 | this.entities = entities; 9 | this.serviceName = serviceName; 10 | } 11 | 12 | getErrorDetails(root, target) { 13 | let result = { 14 | entityName: "", 15 | fieldName: "", 16 | }; 17 | if (target === undefined) return result; 18 | try { 19 | if (target.startsWith("in/")) { 20 | target = target.replace("in/", ""); 21 | } 22 | target = target.replace("(", "["); 23 | target = target.replace(")", "]"); 24 | let reg = /\[.+?]/; 25 | 26 | let targetPath = target.replace(reg, ""); 27 | 28 | if (targetPath === targetPath.replace("/", "")) { 29 | result.entityName = root.EntityName; 30 | result.fieldName = targetPath; 31 | return result; 32 | } 33 | let path = targetPath.split("/"); 34 | result.fieldName = path.pop(); 35 | 36 | let searchTarget = path.join("/") + "/"; 37 | let childEntity = this.entities.find( 38 | (item) => 39 | searchTarget === item.target && root.ServiceName === item.ServiceName 40 | ); 41 | 42 | result.entityName = childEntity.EntityName; 43 | } catch (e) { 44 | console.log(e); 45 | } 46 | 47 | return result; 48 | } 49 | async generateErrors(data, locale, err) { 50 | let errorPromises = []; 51 | let details = []; 52 | if (err.details !== undefined) { 53 | details = err.details; 54 | } else { 55 | details.push(err); 56 | } 57 | 58 | const messageGenerator = new MessageGenerator(locale); 59 | await messageGenerator.loadBundle(); 60 | 61 | for (const detail of details) { 62 | //status code of 444 came from the save handler and don't need more processing 63 | if (detail.statusCode === 444) { 64 | detail.statusCode = 400; 65 | continue; 66 | } else if (detail.code === 444) { 67 | detail.code = 400; 68 | continue; 69 | } 70 | let errorDetails = this.getErrorDetails(this.entity, detail.target); 71 | let validationRule = this.validationElements.find( 72 | (item) => 73 | this.entity.ServiceName === item.ServiceName && 74 | errorDetails.entityName === item.EntityName && 75 | (errorDetails.fieldName === item.FieldName || 76 | errorDetails.fieldName === "in/" + item.FieldName) 77 | ); 78 | 79 | if (validationRule !== undefined) { 80 | const dataTracer = new TraceGenerator( 81 | data, 82 | this.entities, 83 | this.serviceName 84 | ); 85 | try { 86 | var trace = dataTracer.performTrace( 87 | detail.target, 88 | this.entity.EntityName 89 | ); 90 | } catch (E) {} 91 | errorPromises.push( 92 | messageGenerator.getMessage(validationRule.Message, trace, detail) 93 | ); 94 | } 95 | } 96 | 97 | await Promise.all(errorPromises); 98 | } 99 | }; 100 | -------------------------------------------------------------------------------- /HandlerProcessor.js: -------------------------------------------------------------------------------- 1 | const TraceGenerator = require("./TraceGenerator.js"); 2 | const MessageGenerator = require("./MessageGenerator.js"); 3 | module.exports = class HandlerProcessor { 4 | constructor(data, validationElements, entities, serviceName, locale) { 5 | // this.data = []; 6 | this.data = data; 7 | this.validationElements = validationElements; 8 | this.errors = []; 9 | this.entities = entities; 10 | this.locale = locale; 11 | this.serviceName = serviceName; 12 | this.traceGenerator = new TraceGenerator(this.data, entities, serviceName); 13 | this.errorPromises = []; 14 | } 15 | 16 | async prepareMessageGenerator() { 17 | this.messageGenerator = new MessageGenerator(this.locale); 18 | await this.messageGenerator.loadBundle(); 19 | } 20 | 21 | async validateData(rootEntity) { 22 | await this.prepareMessageGenerator(); 23 | await this.traverseTree(this.data, rootEntity, "", [], {}); 24 | return this.getErrors(); 25 | } 26 | 27 | async traverseTree(CurrentEntity, CurrentEntityName, path, trace) { 28 | for (const item of CurrentEntity) { 29 | const keys = this.getKeys(CurrentEntityName); 30 | var newPath = this.getPath(path, item, keys); 31 | 32 | Object.entries(item).forEach(([key, value]) => { 33 | if (!Array.isArray(value)) { 34 | trace[CurrentEntityName + "-" + key] = value; 35 | } 36 | }); 37 | 38 | Object.entries(item).forEach(([key, value]) => { 39 | if (Array.isArray(value)) { 40 | const ChildEntityName = this.traceGenerator.findEntityFromAssociation( 41 | CurrentEntityName, 42 | key 43 | ); 44 | this.validateField( 45 | CurrentEntityName, 46 | key, 47 | value, 48 | newPath + key, 49 | CurrentEntity, 50 | trace 51 | ); 52 | this.traverseTree(value, ChildEntityName, newPath + key, trace); 53 | } else { 54 | this.validateField( 55 | CurrentEntityName, 56 | key, 57 | value, 58 | newPath + key, 59 | CurrentEntity, 60 | trace 61 | ); 62 | } 63 | }); 64 | } 65 | if (this.errorPromises.length > 0) { 66 | await Promise.all(this.errorPromises); 67 | } 68 | } 69 | 70 | getKeys(ParentEntityName) { 71 | const entity = this.entities.find((item) => { 72 | return item.EntityName === ParentEntityName; 73 | }); 74 | return entity.Keys; 75 | } 76 | 77 | getPath(CurrentPath, Node, keys) { 78 | if (CurrentPath === "") { 79 | return "in/"; 80 | } 81 | 82 | let keyString = ""; 83 | let separater = ""; 84 | for (const key of keys) { 85 | let value = `'${Node[key.key]}'`; 86 | if (key.key === "IsActiveEntity") { 87 | value = false; 88 | } 89 | keyString = keyString + separater + key.key + "=" + value; 90 | separater = ","; 91 | } 92 | const newPath = CurrentPath + "(" + keyString + ")/"; 93 | return newPath; 94 | } 95 | 96 | addCustomFieldsToTrace(data, trace) { 97 | Object.entries(data).forEach(([key, value]) => { 98 | if (!Array.isArray(value)) { 99 | trace["custom-" + key] = value; 100 | } 101 | }); 102 | return trace; 103 | } 104 | 105 | validateField(EntityName, Field, value, path, Node, trace) { 106 | const validationRule = this.validationElements.find((item) => { 107 | return ( 108 | item.FieldName === Field && 109 | (item.EntityName === EntityName) & (item.handler !== "") && 110 | item.ServiceName === this.serviceName 111 | ); 112 | }); 113 | 114 | if (validationRule === undefined) return; 115 | 116 | if (validationRule.handlerClass === undefined) return; 117 | 118 | const Validator = validationRule.handlerClass; 119 | const v = new Validator( 120 | Field, 121 | Node, 122 | trace, 123 | this.data, 124 | validationRule.Message, 125 | path 126 | ); 127 | if (!v.isValid(value)) { 128 | const error = v.generateError(); 129 | 130 | trace = this.addCustomFieldsToTrace(v.getCustomMessageVariables(), trace); 131 | /* this.messageGenerator 132 | .getMessage(error.message, trace, error) 133 | .then((message) => {}); 134 | */ 135 | 136 | this.errorPromises.push( 137 | this.messageGenerator 138 | .getMessage(error.message, trace, error) 139 | .then((message) => { 140 | // error.message = message; 141 | this.errors.push(error); 142 | }) 143 | ); 144 | } 145 | } 146 | 147 | getErrors() { 148 | return this.errors; 149 | } 150 | }; 151 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /MessageGenerator.js: -------------------------------------------------------------------------------- 1 | const Mustache = require("mustache"); 2 | const { TextBundle } = require("@sap/textbundle"); 3 | const path = require("path"); 4 | const fs = require("fs"); 5 | module.exports = class MessageGenerator { 6 | constructor(locale) { 7 | this.locale = locale; 8 | } 9 | 10 | loadBundle() { 11 | return new Promise((resolve) => { 12 | let i18nPath = path.join(path.resolve("./"), "i18n", "i18n"); 13 | if (!fs.existsSync(i18nPath)) { 14 | i18nPath = path.join(path.resolve("./"), "_i18n", "i18n"); 15 | } 16 | this.bundle = new TextBundle(i18nPath, this.locale); 17 | resolve(); 18 | }); 19 | } 20 | 21 | getMessage(message, data, detail) { 22 | return new Promise((resolve) => { 23 | this.fetchMessageTextFromi18n(message, this.locale).then((message) => { 24 | this.message = message; 25 | let result = this.message; 26 | if (data !== undefined) { 27 | result = Mustache.render(this.message, data); 28 | } 29 | 30 | detail.message = result; 31 | resolve(result); 32 | }); 33 | }); 34 | } 35 | 36 | fetchMessageTextFromi18n(message) { 37 | return this.getText(message, this.bundle); 38 | } 39 | 40 | async getText(message, bundle) { 41 | if (message.indexOf("i18n>") === 0) { 42 | message = message.replace("i18n>", ""); 43 | const text = await bundle.getText(message); 44 | return text; 45 | } 46 | return message; 47 | } 48 | }; 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Extend SAP Cloud Application Programming Model(CAP) Validations with the CAPVAL Plugin 2 | 3 | SAP CAPVAL is a SAP Cloud Application Programming Model(CAP) plugin that aims to improve and extend the standard validations provided. 4 | 5 | This plugin aims to address the following: 6 | 7 | - Poor User Experience with default messages such as 'Value is required'. With a multilevel application with many mandatory fields this can leave the user feeling lost 8 | - Large handlers for custom validations/messages to address the above 9 | - Repetitive development implementing custom validations such as generating targets 10 | 11 | ## Setup 12 | 13 | To use CAPVAL, simply add the dependency to your project 14 | 15 | For @sap/cds version less than 8.0.0 use CAPVAL version 1.1.0. Use CAPVAL version 1.2.0 and above for @sap/cds version 8.0.0 and above 16 | 17 | ```sh 18 | npm add capval 19 | ``` 20 | 21 | # Annotations 22 | 23 | ## Custom Messages with contextual information 24 | 25 | To override messages all we need to do is place the @validation.message annotation alongside existing input validation annotations(@mandatory,@assert.format,@assert.range...) 26 | 27 | ### Examples 28 | 29 | #### Custom Message 30 | 31 | ```cds 32 | db/validations.cds 33 | 34 | using { sap.fe.cap.travel as schema } from '../db/schema'; 35 | 36 | annotate schema.Travel { 37 | @validation.message: 'Enter a valid begin date' 38 | @mandatory 39 | BeginDate; 40 | } 41 | ``` 42 | 43 | ### Localisation 44 | 45 | Localisation is supported and dynamic contextual information can be provided. 46 | 47 | ```cds 48 | db/validations.cds 49 | 50 | using { sap.fe.cap.travel as schema } from '../db/schema'; 51 | 52 | annotate schema.Travel { 53 | @validation.message: 'i18n>begindate-error' 54 | @mandatory 55 | BeginDate; 56 | } 57 | 58 | _i18n/i18n.properties 59 | 60 | begindate-error = Enter a valid begin date 61 | 62 | ``` 63 | 64 | ### Localisation with contextual information 65 | 66 | ```cds 67 | db/validations.cds 68 | using { sap.fe.cap.travel as schema } from '../db/schema'; 69 | 70 | annotate schema.Travel { 71 | @validation.message: 'i18n>begindate-error' 72 | @mandatory 73 | BeginDate; 74 | } 75 | 76 | _i18n/i18n.properties 77 | begindate-error = Begin Date required and must be before End Date {{Travel-EndDate}} 78 | ``` 79 | 80 | ## Custom Validations 81 | 82 | The introduced annotation @validation.handler allows a class to be specified that implements a custom validation. This allows for modulisation and reuse of validations. Implementations must extend the BaseValidation class and implement the IsValid Method, returning true or false. CAPVAL will automatically determine the targets (in/to_Booking(BookingUUID etc etc), collate, and return the errors. 83 | 84 | ### Example 85 | 86 | #### Custom Validation 87 | 88 | This handler checks that the begin date is before the end date 89 | 90 | ```js 91 | srv / handlers / BeginDateChecks.js; 92 | 93 | const BaseValidation = require("capval"); 94 | module.exports = class BeginDateChecks extends BaseValidation { 95 | isValid(InputValue) { 96 | var travel = this.getNode(); 97 | 98 | if (travel.BeginDate > travel.EndDate) { 99 | return false; 100 | } 101 | 102 | return true; 103 | } 104 | }; 105 | ``` 106 | 107 | ```cds 108 | db/validations.cds 109 | using { sap.fe.cap.travel as schema } from '../db/schema'; 110 | 111 | annotate schema.Travel { 112 | @validation: { 113 | message: 'Please enter a begin date that is before the end date', 114 | handler: 'srv/handlers/BeginDateChecks.js' 115 | } 116 | BeginDate; 117 | } 118 | 119 | ``` 120 | 121 | #### Advanced Scenario 122 | 123 | A generic conditional validation with dynamic error messages 124 | 125 | ```js 126 | srv / handlers / ConditionalMandatoryCheck.js; 127 | 128 | const BaseValidation = require("capval"); 129 | module.exports = class ConditionalMandatoryCheck extends BaseValidation { 130 | isValid(InputValue) { 131 | var data = this.getDataToRoot(); 132 | if (data["Travel-TravelStatus_code"] === "X") return true; 133 | if (!InputValue) { 134 | this.seti18nMessage(this.getField() + "-errorMessage"); 135 | return false; 136 | } 137 | return true; 138 | } 139 | }; 140 | ``` 141 | 142 | ```cds 143 | db/validations.cds 144 | using { sap.fe.cap.travel as schema } from '../db/schema'; 145 | annotate schema.Travel { 146 | @validation: { 147 | message: 'Default message', 148 | handler: 'srv/handlers/ConditionalMandatoryCheck.js' 149 | } 150 | BeginDate; 151 | @validation: { 152 | message: 'Default message', 153 | handler: 'srv/handlers/ConditionalMandatoryCheck.js' 154 | } 155 | EndDate; 156 | } 157 | 158 | _i18n/i18n.properties 159 | BeginDate-errorMessage = Please enter a valid begin date 160 | EndDate-errorMessage = Please enter a valid end date 161 | ``` 162 | 163 | #### Custom Data Scenario 164 | 165 | Custom Variables, that are not part of the Business Object can be added to provide information in messages. 166 | 167 | ```js 168 | srv / handlers / BeginDateChecks.js; 169 | 170 | const BaseValidation = require("capval"); 171 | module.exports = class BeginDateChecks extends BaseValidation { 172 | isValid(InputValue) { 173 | var travel = this.getNode(); 174 | var today = new Date().toISOString().slice(0, 10); 175 | 176 | if (travel.BeginDate < today) { 177 | this.seti18nMessage("begindatetoday-errorMessage"); 178 | this.setCustomMessageVariables({ today: today }); 179 | return false; 180 | } 181 | 182 | return true; 183 | } 184 | }; 185 | ``` 186 | 187 | ```cds 188 | db/validations.cds 189 | using { sap.fe.cap.travel as schema } from '../db/schema'; 190 | annotate schema.Travel { 191 | @validation: { 192 | message: 'Please enter a begin date that is before the end date', 193 | handler: 'srv/handlers/BeginDateChecks.js' 194 | } 195 | BeginDate; 196 | } 197 | 198 | _i18n/i18n.properties 199 | begindatetoday-errorMessage = Travel Begin Date {{Travel-BeginDate}} can not be before today {{custom-today}} 200 | ``` 201 | 202 | ### Methods 203 | 204 | The following getter methods can be used to access information to assist with the validation: 205 | 206 | 1. getField() : Returns the technical name of the Field getting validated. For Example: BeginDate 207 | 2. getNode() : Returns the Entity Data for which the Field is member of. For example: The Travel Instance 208 | 3. getMessage() : Returns the annotated error message 209 | 4. getTarget() : Returns the calculated target 210 | 5. getDataToRoot(): Returns a flat JSON Object(keys prefixed with the Entity Name-) of the Node under validation as well as its parents to root 211 | 6. getData(): Returns the full data(root with all ancestors) of the instance 212 | 213 | The following setter methods are available: 214 | 215 | 1. setMessage(Message): Overwrites the Error Message. Variables in double curly brackets can be provided 216 | 2. seti18nMessage(Message): Overwrites the Error Message by providing a key for an entry in the i18n.properties file 217 | 3. setTarget(Target): Overwrites the generated field target 218 | 4. setCustomMessageVariables(data): Allows a JSON Object with custom key value pairs to be used in error messages 219 | 220 | ## Demo 221 | 222 | SFLIGHT Scenario with CAPVAL 223 | https://github.com/MertSAP/cap-sflight 224 | -------------------------------------------------------------------------------- /ServiceParser.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | module.exports = class ServiceParser { 4 | constructor(Services) { 5 | this.validationElements = []; 6 | this.entities = []; 7 | 8 | this.parseInput(Services); 9 | } 10 | 11 | getEntities() { 12 | return this.entities; 13 | } 14 | 15 | getvalidationElements() { 16 | return this.validationElements; 17 | } 18 | 19 | parseInput(Services) { 20 | let compositions = []; 21 | for (const srv of Services) { 22 | // go through all entities 23 | if (srv instanceof cds.ApplicationService) { 24 | for (const entityKey in srv.entities) { 25 | const entity = srv.entities[entityKey]; 26 | 27 | const entityRow = { 28 | EntityName: entityKey, 29 | isRoot: true, 30 | Children: [], 31 | Keys: [], 32 | ServiceName: srv.name, 33 | HasValidations: false, 34 | AncestorsHaveValidations: false, 35 | HasHandlers: false, 36 | AncestorsHaveHandlers: false, 37 | target: "", 38 | }; 39 | 40 | for (const key in entity.elements) { 41 | const element = entity.elements[key]; 42 | 43 | if (element.type === "cds.Composition") { 44 | if ( 45 | key.search("DraftAdministrativeData", 0) > 0 || 46 | key.search("SiblingEntity", 0) > 0 47 | ) { 48 | continue; 49 | } 50 | 51 | const compositionRow = { 52 | ChildEntityName: element.target.replace(srv.name + ".", ""), 53 | ParentEntityName: entityKey, 54 | AssociationName: key, 55 | ServiceName: srv.name, 56 | }; 57 | 58 | compositions.push(compositionRow); 59 | } 60 | 61 | if (element["@validation.message"]) { 62 | entityRow.HasValidations = true; 63 | let handler = ""; 64 | if (element["@validation.handler"] !== undefined) { 65 | handler = path.join( 66 | "file:", 67 | ".", 68 | path.resolve("./"), 69 | element["@validation.handler"] 70 | ); 71 | entityRow.HasHandlers = true; 72 | } 73 | this.addValidationElement( 74 | srv.name, 75 | entityKey, 76 | key, 77 | element["@validation.message"], 78 | "Field", 79 | handler 80 | ); 81 | } 82 | 83 | if (element.key) { 84 | entityRow.Keys.push({ key }); 85 | } 86 | } 87 | 88 | this.entities.push(entityRow); 89 | } 90 | } 91 | 92 | for (const entity of this.entities) { 93 | for (const composition of compositions) { 94 | if (composition.ParentEntityName === entity.EntityName) { 95 | if ( 96 | composition.ParentEntityName === entity.EntityName && 97 | composition.ServiceName === entity.ServiceName 98 | ) { 99 | delete composition.ParentEntity; 100 | entity.Children.push(composition); 101 | } 102 | } 103 | } 104 | } 105 | this.getRoots(compositions); 106 | this.checkAncestorsHaveValidations(); 107 | this.checkAncestorsHaveHandlers(); 108 | compositions = []; 109 | } 110 | this.tracePathtoRoot(); 111 | } 112 | 113 | checkAncestorsHaveValidations() { 114 | for (const entity of this.entities) { 115 | if (entity.isRoot) { 116 | entity.AncestorsHaveHandlers = this.traverseValidationTree(entity); 117 | } 118 | } 119 | } 120 | 121 | checkAncestorsHaveHandlers() { 122 | for (const entity of this.entities) { 123 | if (entity.isRoot) { 124 | entity.AncestorsHaveHandlers = this.traverseHandlerTree(entity); 125 | } 126 | } 127 | } 128 | 129 | traverseHandlerTree(entity) { 130 | if (entity.HasHandlers) { 131 | return true; 132 | } 133 | 134 | let childrenHasHandlers = false; 135 | for (const child of entity.Children) { 136 | const childEntity = this.entities.find((item) => { 137 | return item.EntityName === child.ChildEntityName; 138 | }); 139 | childrenHasHandlers = this.traverseHandlerTree(childEntity); 140 | if (childrenHasHandlers) return true; 141 | } 142 | 143 | return false; 144 | } 145 | 146 | tracePathtoRoot() { 147 | for (const entity of this.entities) { 148 | if (entity.isRoot) { 149 | this.traverseTree(entity, entity.ServiceName); 150 | } 151 | } 152 | } 153 | 154 | traverseTree(entity, ServiceName) { 155 | for (const child of entity.Children) { 156 | const childEntity = this.entities.find((item) => { 157 | return ( 158 | item.EntityName === child.ChildEntityName && 159 | item.ServiceName === ServiceName 160 | ); 161 | }); 162 | childEntity.target = childEntity.target + child.AssociationName + "/"; 163 | this.traverseTree(childEntity, ServiceName); 164 | } 165 | } 166 | 167 | traverseValidationTree(entity) { 168 | if (entity.HasValidations) { 169 | return true; 170 | } 171 | 172 | let childrenHasValidations = false; 173 | for (const child of entity.Children) { 174 | const childEntity = this.entities.find((item) => { 175 | return item.EntityName === child.ChildEntityName; 176 | }); 177 | childrenHasValidations = this.traverseValidationTree(childEntity); 178 | if (childrenHasValidations) return true; 179 | } 180 | 181 | return false; 182 | } 183 | 184 | getRoots(compositions) { 185 | for (const entity of this.entities) { 186 | for (const composition of compositions) { 187 | if (composition.ChildEntityName === entity.EntityName) { 188 | entity.isRoot = false; 189 | } 190 | } 191 | } 192 | } 193 | 194 | checkAnsest; 195 | 196 | addValidationElement( 197 | Service, 198 | Entity, 199 | Field, 200 | Message, 201 | Level, 202 | Handler, 203 | AssertUniqueRegex 204 | ) { 205 | const element = { 206 | ServiceName: Service, 207 | EntityName: Entity, 208 | FieldName: Field, 209 | Message, 210 | Level, 211 | Handler, 212 | AssertUniqueRegex, 213 | }; 214 | this.validationElements.push(element); 215 | } 216 | }; 217 | -------------------------------------------------------------------------------- /TraceGenerator.js: -------------------------------------------------------------------------------- 1 | module.exports = class TraceGenerator { 2 | constructor (data, entities, srvName) { 3 | this.data = data 4 | this.entities = entities 5 | this.srvName = srvName 6 | } 7 | 8 | getNameFromPathVal = function (pathVal) { 9 | return /^(.+?)\(/.exec(pathVal)?.[1] || '' 10 | } 11 | 12 | getKeysFrom = function (pathVal) { 13 | const regRes = /\((.+?)\)/.exec(pathVal) 14 | regRes ? regRes[1] : '' 15 | 16 | if (regRes === '' || regRes === null) return [] 17 | const keys = String(regRes).split(',') 18 | const keyItems = [] 19 | for (const key of keys) { 20 | const pair = key.split('=') 21 | keyItems.push(pair) 22 | } 23 | // somethjong dodfy 24 | return keyItems 25 | } 26 | 27 | findEntityFromAssociation (ParentEntityName, Association) { 28 | const entity = this.entities.find((item) => { 29 | return item.EntityName === ParentEntityName 30 | }) 31 | 32 | const child = entity.Children.find((item) => { 33 | return item.AssociationName === Association 34 | }) 35 | return child.ChildEntityName 36 | } 37 | 38 | addToTrace (currentNode, trace, EntityName) { 39 | const EntityNameNoSerice = EntityName.replace(this.srvName + '.', '') 40 | Object.entries(currentNode).forEach(([key, value]) => { 41 | if (!Array.isArray(value)) { 42 | trace[EntityNameNoSerice + '-' + key] = value 43 | } 44 | }) 45 | return trace 46 | } 47 | 48 | performTrace (targetPath, root) { 49 | return this.getTrace(targetPath, this.data, root) 50 | } 51 | 52 | getTrace (targetPath, currentNode, EntityName) { 53 | const targets = targetPath.split('/') 54 | let trace = {} 55 | for (const target of targets) { 56 | if (target === 'in') continue 57 | let targetName = this.getNameFromPathVal(target) 58 | const targetKeys = this.getKeysFrom(target) 59 | 60 | if (targetName === '') targetName = target 61 | Object.entries(currentNode).forEach(([key, value]) => { 62 | if (key === targetName) { 63 | trace = this.addToTrace(currentNode, trace, EntityName) 64 | if (!Array.isArray(value)) { 65 | return trace 66 | } else { 67 | EntityName = this.findEntityFromAssociation(EntityName, key) 68 | currentNode = currentNode[key].find((item) => { 69 | for (const targetKey in targetKeys) { 70 | if (item[targetKey[0]] !== targetKey[1]) { 71 | return false 72 | } 73 | } 74 | 75 | return true 76 | }) 77 | } 78 | } 79 | }) 80 | } 81 | return trace 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /cds-plugin.js: -------------------------------------------------------------------------------- 1 | const ServiceParser = require("./ServiceParser.js"); 2 | 3 | const HandlerProcessor = require("./HandlerProcessor.js"); 4 | const ErrorProcessor = require("./ErrorProcessor.js"); 5 | 6 | cds.once("served", async () => { 7 | const serviceParser = new ServiceParser(cds.services); 8 | const entities = serviceParser.getEntities(); 9 | const validationElements = serviceParser.getvalidationElements(); 10 | 11 | for (const validationElement of validationElements) { 12 | if (validationElement.Handler !== "") { 13 | const { default: Validater } = await await import( 14 | validationElement.Handler 15 | ); 16 | validationElement.handlerClass = Validater; 17 | } 18 | } 19 | 20 | for (const srv of cds.services) { 21 | // go through all entities 22 | if (srv instanceof cds.ApplicationService) { 23 | for (const entity of entities) { 24 | if (srv.name !== entity.ServiceName) { 25 | continue; 26 | } 27 | if ( 28 | entity.isRoot && 29 | (entity.HasValidations || entity.AncestorsHaveValidations) 30 | ) { 31 | let errorProcessor = new ErrorProcessor( 32 | entity, 33 | validationElements, 34 | entities, 35 | srv.name 36 | ); 37 | 38 | const errorHandler = async function (err, req, res, next) { 39 | try { 40 | let results = await req._query; 41 | await errorProcessor.generateErrors(results[0], req.locale, err); 42 | res.status(err.statusCode); 43 | res.json({ error: err }); 44 | } catch (exception) { 45 | next(exception); 46 | } 47 | }; 48 | cds.middlewares.after = [errorHandler]; 49 | 50 | srv.on("error", entity.EntityName, async (err, req) => { 51 | let data = {}; 52 | try { 53 | data = req.http.req.body; 54 | } catch (e) {} 55 | await errorProcessor.generateErrors(data, req.locale, err); 56 | }); 57 | 58 | if ( 59 | entity.isRoot && 60 | (entity.HasHandlers || entity.AncestorsHaveHandlers) 61 | ) { 62 | srv.before("SAVE", entity.EntityName, async (req) => { 63 | if (!req.data) return; 64 | 65 | const myData = Array.isArray(req.data) ? req.data : [req.data]; 66 | 67 | const handlerProcessor = new HandlerProcessor( 68 | myData, 69 | validationElements, 70 | entities, 71 | srv.name, 72 | req.locale 73 | ); 74 | 75 | const errors = await handlerProcessor.validateData( 76 | entity.EntityName 77 | ); 78 | 79 | for (const error of errors) { 80 | ///setting as 444 as the error hanlder is invoked after this and will change to 400 to prevent double handling 81 | req.error(444, error.message, error.target); 82 | } 83 | }); 84 | } 85 | } 86 | } 87 | } 88 | } 89 | }); 90 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = class ValidationBase { 2 | constructor (Field, Node, DataToRoot, Data, Message, Target) { 3 | this.Field = Field 4 | this.Node = Node 5 | this.DataToRoot = DataToRoot 6 | this.Data = Data 7 | this.setMessage(Message) 8 | this.setTarget(Target) 9 | this.customMessageVariables = {} 10 | } 11 | 12 | isValid (InputValue) { 13 | 14 | } 15 | 16 | setCustomMessageVariables (data) { 17 | this.customMessageVariables = data 18 | } 19 | 20 | getCustomMessageVariables () { 21 | return this.customMessageVariables 22 | } 23 | 24 | getNode () { 25 | return this.Node[0] 26 | } 27 | 28 | getField () { 29 | return this.Field 30 | } 31 | 32 | setMessage (Message) { 33 | this.Message = Message 34 | } 35 | 36 | seti18nMessage (Message) { 37 | this.Message = 'i18n>' + Message 38 | } 39 | 40 | getMessage () { 41 | return this.Message 42 | } 43 | 44 | setTarget (Target) { 45 | this.Target = Target 46 | } 47 | 48 | getTarget () { 49 | return this.Target 50 | } 51 | 52 | getDataToRoot () { 53 | return this.DataToRoot 54 | } 55 | 56 | getData () { 57 | return this.Data 58 | } 59 | 60 | generateError () { 61 | return { 62 | target: this.getTarget(), 63 | message: this.getMessage() 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "capval", 3 | "version": "2.0.5", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "capval", 9 | "version": "2.0.5", 10 | "license": "ISC", 11 | "dependencies": { 12 | "@sap/textbundle": "^5.2.0", 13 | "mustache": "^4.2.0" 14 | } 15 | }, 16 | "node_modules/@sap/textbundle": { 17 | "version": "5.4.0", 18 | "resolved": "https://registry.npmjs.org/@sap/textbundle/-/textbundle-5.4.0.tgz", 19 | "integrity": "sha512-JQmhrMrBiu641CKVvp8ywRPUmMDkjvxQVBoEwGutpuZSkNH0X8367hbSAVxNLy8bWGhBzC3R6dTVSs0Goku+sg==", 20 | "license": "SEE LICENSE IN LICENSE file", 21 | "engines": { 22 | "node": "^18.0.0 || ^20.0.0 || ^22.0.0" 23 | } 24 | }, 25 | "node_modules/mustache": { 26 | "version": "4.2.0", 27 | "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", 28 | "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", 29 | "bin": { 30 | "mustache": "bin/mustache" 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "capval", 3 | "version": "2.0.6", 4 | "description": "SAP CAP Validation Plugin", 5 | "repository": "https://github.com/MertSAP/CAPVAL", 6 | "main": "index.js", 7 | "scripts": { 8 | "test": "cd tests && npm run test" 9 | }, 10 | "author": "MertSAP", 11 | "license": "ISC", 12 | "dependencies": { 13 | "@sap/textbundle": "^5.2.0", 14 | "mustache": "^4.2.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/.cdsrc.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /tests/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. 3 | // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp 4 | 5 | // List of extensions which should be recommended for users of this workspace. 6 | "recommendations": [ 7 | "SAPSE.vscode-cds", 8 | "dbaeumer.vscode-eslint", 9 | "esbenp.prettier-vscode", 10 | "mechatroner.rainbow-csv", 11 | "qwtel.sqlite-viewer", 12 | "humao.rest-client" 13 | ], 14 | // List of extensions recommended by VS Code that should not be recommended for users of this workspace. 15 | "unwantedRecommendations": [ 16 | 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /tests/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "cds serve", 6 | "request": "launch", 7 | "type": "node", 8 | "cwd": "${workspaceFolder}", 9 | "runtimeExecutable": "cds", 10 | "args": [ 11 | "serve", 12 | "--with-mocks", 13 | "--in-memory?" 14 | ], 15 | 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /tests/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | // uncomment entries once all libraries have been installed via 'npm install' 3 | "eslint.validate": [ 4 | // "cds", 5 | // "csn", 6 | // "csv", 7 | // "csv (semicolon)", 8 | // "tab", 9 | // "tsv" 10 | ] 11 | } -------------------------------------------------------------------------------- /tests/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "shell", 8 | "label": "cds watch", 9 | "command": "cds", 10 | "args": ["watch"], 11 | "group": { 12 | "kind": "build", 13 | "isDefault": true 14 | }, 15 | "problemMatcher": [] 16 | }, 17 | { 18 | "type": "shell", 19 | "label": "cds serve", 20 | "command": "cds", 21 | "args": ["serve", "--with-mocks", "--in-memory?"], 22 | "problemMatcher": [] 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /tests/_i18n/i18n.properties: -------------------------------------------------------------------------------- 1 | previewDate=Preview Date has to after today 2 | dateToday-errorMessage= Date has to be greater than today 3 | price-error = Price must be set 4 | statusCheck-Cancelled = Please use remaining stock before cancelling 5 | statusCheck-Released = Release Date must be today: {{custom-today}} -------------------------------------------------------------------------------- /tests/db/data-model.cds: -------------------------------------------------------------------------------- 1 | namespace my.bookshop; 2 | 3 | entity Books { 4 | key ID : UUID; 5 | title : String; 6 | 7 | @validation.message: 'Enter a valid description' 8 | @assert.format : '[a-z]+ [0-9]+' 9 | description : String; 10 | 11 | @assert.range : [ 12 | 0, 13 | 10000 14 | ] 15 | @validation.message: 'Stock can not be more than 10,000' 16 | stock : Integer; 17 | 18 | @assert.range : [ 19 | 0, 20 | 20 21 | ] 22 | @validation.message: 'Reorder Point: {{Books-reorderPoint}} not between 0 and 20' 23 | reorderPoint : Integer; 24 | 25 | @mandatory 26 | @validation.message: 'Release Date has to be to be set' 27 | releaseDate : Date; 28 | 29 | @validation : { 30 | message: 'i18n>previewDate', 31 | handler: 'srv/handlers/DateChecks.js' 32 | } 33 | previewDate : Date; 34 | 35 | @validation : { 36 | message: 'Default message0', 37 | handler: 'srv/handlers/ConditionalCheck.js' 38 | } 39 | statusCode : String; 40 | 41 | @mandatory 42 | @validation.message: 'i18n>price-error' 43 | price : Integer; 44 | to_Chapters : Composition of many Chapters 45 | on to_Chapters.to_Books = $self 46 | } 47 | 48 | entity Chapters { 49 | key ID : UUID; 50 | 51 | @mandatory 52 | @validation.message: 'Enter a valid chapter title' 53 | title : String; 54 | to_Books : Association to Books 55 | } 56 | -------------------------------------------------------------------------------- /tests/db/data/my.bookshop-Books.csv: -------------------------------------------------------------------------------- 1 | ID;title;stock 2 | 1;Wuthering Heights;100 3 | 2;Jane Eyre;500 4 | -------------------------------------------------------------------------------- /tests/eslint.config.js: -------------------------------------------------------------------------------- 1 | const cds = require("@sap/eslint-plugin-cds"); 2 | 3 | module.exports = [ 4 | cds.configs.recommended, 5 | { 6 | plugins: { 7 | "@sap/cds": cds, 8 | }, 9 | rules: { 10 | ...cds.configs.recommended.rules, 11 | }, 12 | verbose: false, 13 | }, 14 | ]; 15 | -------------------------------------------------------------------------------- /tests/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "capval-showcase", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "capval-showcase", 9 | "version": "1.0.0", 10 | "license": "UNLICENSED", 11 | "dependencies": { 12 | "@sap/cds": "^8.0.3", 13 | "capval": "file:..", 14 | "express": "^4" 15 | }, 16 | "devDependencies": { 17 | "@cap-js/sqlite": "^1", 18 | "@sap/eslint-plugin-cds": "^3", 19 | "axios": "^1.8.2", 20 | "chai": "^4.4.1", 21 | "chai-as-promised": "^7.1.2", 22 | "chai-subset": "^1.6.0", 23 | "eslint": "^9", 24 | "mocha": "^10.8.2" 25 | } 26 | }, 27 | "..": { 28 | "name": "capval", 29 | "version": "2.0.5", 30 | "license": "ISC", 31 | "dependencies": { 32 | "@sap/textbundle": "^5.2.0", 33 | "mustache": "^4.2.0" 34 | } 35 | }, 36 | "node_modules/@cap-js/db-service": { 37 | "version": "1.15.0", 38 | "resolved": "https://registry.npmjs.org/@cap-js/db-service/-/db-service-1.15.0.tgz", 39 | "integrity": "sha512-9MCyfumDsPRA/axkQ0kePd8MqolbDTCGAaSN1jR07bMSNo/gFoRGfqcqvlP8+XdX5S1xBiMmP1gbw8VktZr0yg==", 40 | "dev": true, 41 | "dependencies": { 42 | "generic-pool": "^3.9.0" 43 | }, 44 | "peerDependencies": { 45 | "@sap/cds": ">=7.9" 46 | } 47 | }, 48 | "node_modules/@cap-js/sqlite": { 49 | "version": "1.7.7", 50 | "resolved": "https://registry.npmjs.org/@cap-js/sqlite/-/sqlite-1.7.7.tgz", 51 | "integrity": "sha512-SOmFJMr6pjWOniFRkJsrI0BpQEQT5Q8o+IVZ/LXFj6+bAe0NQQztzxhMQx62V/Px3u58JJM3xkPMU+QC5PcJHw==", 52 | "dev": true, 53 | "dependencies": { 54 | "@cap-js/db-service": "^1.14.1", 55 | "better-sqlite3": "^11.0.0" 56 | }, 57 | "peerDependencies": { 58 | "@sap/cds": ">=7.6" 59 | } 60 | }, 61 | "node_modules/@eslint-community/eslint-utils": { 62 | "version": "4.4.1", 63 | "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", 64 | "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", 65 | "dev": true, 66 | "dependencies": { 67 | "eslint-visitor-keys": "^3.4.3" 68 | }, 69 | "engines": { 70 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 71 | }, 72 | "funding": { 73 | "url": "https://opencollective.com/eslint" 74 | }, 75 | "peerDependencies": { 76 | "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" 77 | } 78 | }, 79 | "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { 80 | "version": "3.4.3", 81 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", 82 | "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", 83 | "dev": true, 84 | "engines": { 85 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 86 | }, 87 | "funding": { 88 | "url": "https://opencollective.com/eslint" 89 | } 90 | }, 91 | "node_modules/@eslint-community/regexpp": { 92 | "version": "4.12.1", 93 | "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", 94 | "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", 95 | "dev": true, 96 | "engines": { 97 | "node": "^12.0.0 || ^14.0.0 || >=16.0.0" 98 | } 99 | }, 100 | "node_modules/@eslint/config-array": { 101 | "version": "0.19.0", 102 | "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.0.tgz", 103 | "integrity": "sha512-zdHg2FPIFNKPdcHWtiNT+jEFCHYVplAXRDlQDyqy0zGx/q2parwh7brGJSiTxRk/TSMkbM//zt/f5CHgyTyaSQ==", 104 | "dev": true, 105 | "dependencies": { 106 | "@eslint/object-schema": "^2.1.4", 107 | "debug": "^4.3.1", 108 | "minimatch": "^3.1.2" 109 | }, 110 | "engines": { 111 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 112 | } 113 | }, 114 | "node_modules/@eslint/core": { 115 | "version": "0.9.0", 116 | "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.0.tgz", 117 | "integrity": "sha512-7ATR9F0e4W85D/0w7cU0SNj7qkAexMG+bAHEZOjo9akvGuhHE2m7umzWzfnpa0XAg5Kxc1BWmtPMV67jJ+9VUg==", 118 | "dev": true, 119 | "engines": { 120 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 121 | } 122 | }, 123 | "node_modules/@eslint/eslintrc": { 124 | "version": "3.2.0", 125 | "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", 126 | "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", 127 | "dev": true, 128 | "dependencies": { 129 | "ajv": "^6.12.4", 130 | "debug": "^4.3.2", 131 | "espree": "^10.0.1", 132 | "globals": "^14.0.0", 133 | "ignore": "^5.2.0", 134 | "import-fresh": "^3.2.1", 135 | "js-yaml": "^4.1.0", 136 | "minimatch": "^3.1.2", 137 | "strip-json-comments": "^3.1.1" 138 | }, 139 | "engines": { 140 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 141 | }, 142 | "funding": { 143 | "url": "https://opencollective.com/eslint" 144 | } 145 | }, 146 | "node_modules/@eslint/js": { 147 | "version": "9.15.0", 148 | "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.15.0.tgz", 149 | "integrity": "sha512-tMTqrY+EzbXmKJR5ToI8lxu7jaN5EdmrBFJpQk5JmSlyLsx6o4t27r883K5xsLuCYCpfKBCGswMSWXsM+jB7lg==", 150 | "dev": true, 151 | "engines": { 152 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 153 | } 154 | }, 155 | "node_modules/@eslint/object-schema": { 156 | "version": "2.1.4", 157 | "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", 158 | "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", 159 | "dev": true, 160 | "engines": { 161 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 162 | } 163 | }, 164 | "node_modules/@eslint/plugin-kit": { 165 | "version": "0.2.3", 166 | "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.3.tgz", 167 | "integrity": "sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==", 168 | "dev": true, 169 | "dependencies": { 170 | "levn": "^0.4.1" 171 | }, 172 | "engines": { 173 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 174 | } 175 | }, 176 | "node_modules/@humanfs/core": { 177 | "version": "0.19.1", 178 | "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", 179 | "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", 180 | "dev": true, 181 | "engines": { 182 | "node": ">=18.18.0" 183 | } 184 | }, 185 | "node_modules/@humanfs/node": { 186 | "version": "0.16.6", 187 | "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", 188 | "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", 189 | "dev": true, 190 | "dependencies": { 191 | "@humanfs/core": "^0.19.1", 192 | "@humanwhocodes/retry": "^0.3.0" 193 | }, 194 | "engines": { 195 | "node": ">=18.18.0" 196 | } 197 | }, 198 | "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { 199 | "version": "0.3.1", 200 | "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", 201 | "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", 202 | "dev": true, 203 | "engines": { 204 | "node": ">=18.18" 205 | }, 206 | "funding": { 207 | "type": "github", 208 | "url": "https://github.com/sponsors/nzakas" 209 | } 210 | }, 211 | "node_modules/@humanwhocodes/module-importer": { 212 | "version": "1.0.1", 213 | "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", 214 | "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", 215 | "dev": true, 216 | "engines": { 217 | "node": ">=12.22" 218 | }, 219 | "funding": { 220 | "type": "github", 221 | "url": "https://github.com/sponsors/nzakas" 222 | } 223 | }, 224 | "node_modules/@humanwhocodes/retry": { 225 | "version": "0.4.1", 226 | "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz", 227 | "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", 228 | "dev": true, 229 | "engines": { 230 | "node": ">=18.18" 231 | }, 232 | "funding": { 233 | "type": "github", 234 | "url": "https://github.com/sponsors/nzakas" 235 | } 236 | }, 237 | "node_modules/@sap/cds": { 238 | "version": "8.4.2", 239 | "resolved": "https://registry.npmjs.org/@sap/cds/-/cds-8.4.2.tgz", 240 | "integrity": "sha512-wHiPU+PciyG6L7oGglUq22ji+aV5SFwef/gF/rnIheMirzxpDlHq+K8GwqmcrrFu3GWRioQGRe3rr8KAalOQrg==", 241 | "dependencies": { 242 | "@sap/cds-compiler": ">=5.1", 243 | "@sap/cds-fiori": "^1", 244 | "@sap/cds-foss": "^5.0.0" 245 | }, 246 | "bin": { 247 | "cds-deploy": "lib/dbs/cds-deploy.js", 248 | "cds-serve": "bin/serve.js", 249 | "cds-test": "bin/test.js", 250 | "chest": "bin/test.js" 251 | }, 252 | "engines": { 253 | "node": ">=18" 254 | }, 255 | "peerDependencies": { 256 | "express": ">=4" 257 | }, 258 | "peerDependenciesMeta": { 259 | "express": { 260 | "optional": true 261 | } 262 | } 263 | }, 264 | "node_modules/@sap/cds-compiler": { 265 | "version": "5.4.4", 266 | "resolved": "https://registry.npmjs.org/@sap/cds-compiler/-/cds-compiler-5.4.4.tgz", 267 | "integrity": "sha512-ZxkVzJyQoTG4dkdUYYZVT+CSbUtlsQsNn7wnZ2rT/zT81bezeuBMnKHjJwvNeCiRoNvfAxm5K/zxBvmpCB5AFA==", 268 | "dependencies": { 269 | "antlr4": "4.9.3" 270 | }, 271 | "bin": { 272 | "cdsc": "bin/cdsc.js", 273 | "cdshi": "bin/cdshi.js", 274 | "cdsse": "bin/cdsse.js" 275 | }, 276 | "engines": { 277 | "node": ">=18" 278 | } 279 | }, 280 | "node_modules/@sap/cds-fiori": { 281 | "version": "1.2.7", 282 | "resolved": "https://registry.npmjs.org/@sap/cds-fiori/-/cds-fiori-1.2.7.tgz", 283 | "integrity": "sha512-F6Uf9wvkv0fXW+Fh7PiV2BbB/k+p1cFJLkQCCKDRJH8HvlxWEcXcn/YIvBrQGuX+GToi125MxB3wd712d8OLTA==", 284 | "peerDependencies": { 285 | "@sap/cds": ">=7.6", 286 | "express": ">=4" 287 | } 288 | }, 289 | "node_modules/@sap/cds-foss": { 290 | "version": "5.0.1", 291 | "resolved": "https://registry.npmjs.org/@sap/cds-foss/-/cds-foss-5.0.1.tgz", 292 | "integrity": "sha512-q6h7LkEx6w9LswCIQzJJ2mnoyeGS8jrmBXN4I4+aECRL60mkLskoqGetot+2tX2xXGxCYJuo5v1dtSafwBqTRQ==", 293 | "dependencies": { 294 | "big.js": "^6.1.1", 295 | "generic-pool": "^3.8.2", 296 | "xmlbuilder": "^15.1.1", 297 | "yaml": "^2.2.2" 298 | }, 299 | "engines": { 300 | "node": ">=14" 301 | } 302 | }, 303 | "node_modules/@sap/eslint-plugin-cds": { 304 | "version": "3.1.2", 305 | "resolved": "https://registry.npmjs.org/@sap/eslint-plugin-cds/-/eslint-plugin-cds-3.1.2.tgz", 306 | "integrity": "sha512-tstnON4GgR6/FLdbHT0zxkAYYYPqatPk3zP6xxo3RWsP0+UVJeM2kAfzseUoRUEKAilRrx8hduxFr3PzUPQCFQ==", 307 | "dev": true, 308 | "dependencies": { 309 | "@sap/cds": ">=7", 310 | "semver": "^7.3.4" 311 | }, 312 | "engines": { 313 | "node": ">=18" 314 | }, 315 | "peerDependencies": { 316 | "eslint": ">=8" 317 | } 318 | }, 319 | "node_modules/@types/estree": { 320 | "version": "1.0.6", 321 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", 322 | "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", 323 | "dev": true 324 | }, 325 | "node_modules/@types/json-schema": { 326 | "version": "7.0.15", 327 | "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", 328 | "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", 329 | "dev": true 330 | }, 331 | "node_modules/accepts": { 332 | "version": "1.3.8", 333 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", 334 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", 335 | "dependencies": { 336 | "mime-types": "~2.1.34", 337 | "negotiator": "0.6.3" 338 | }, 339 | "engines": { 340 | "node": ">= 0.6" 341 | } 342 | }, 343 | "node_modules/acorn": { 344 | "version": "8.14.0", 345 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", 346 | "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", 347 | "dev": true, 348 | "bin": { 349 | "acorn": "bin/acorn" 350 | }, 351 | "engines": { 352 | "node": ">=0.4.0" 353 | } 354 | }, 355 | "node_modules/acorn-jsx": { 356 | "version": "5.3.2", 357 | "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", 358 | "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", 359 | "dev": true, 360 | "peerDependencies": { 361 | "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" 362 | } 363 | }, 364 | "node_modules/ajv": { 365 | "version": "6.12.6", 366 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", 367 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", 368 | "dev": true, 369 | "dependencies": { 370 | "fast-deep-equal": "^3.1.1", 371 | "fast-json-stable-stringify": "^2.0.0", 372 | "json-schema-traverse": "^0.4.1", 373 | "uri-js": "^4.2.2" 374 | }, 375 | "funding": { 376 | "type": "github", 377 | "url": "https://github.com/sponsors/epoberezkin" 378 | } 379 | }, 380 | "node_modules/ansi-colors": { 381 | "version": "4.1.3", 382 | "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", 383 | "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", 384 | "dev": true, 385 | "engines": { 386 | "node": ">=6" 387 | } 388 | }, 389 | "node_modules/ansi-regex": { 390 | "version": "5.0.1", 391 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 392 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 393 | "dev": true, 394 | "engines": { 395 | "node": ">=8" 396 | } 397 | }, 398 | "node_modules/ansi-styles": { 399 | "version": "4.3.0", 400 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 401 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 402 | "dev": true, 403 | "dependencies": { 404 | "color-convert": "^2.0.1" 405 | }, 406 | "engines": { 407 | "node": ">=8" 408 | }, 409 | "funding": { 410 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 411 | } 412 | }, 413 | "node_modules/antlr4": { 414 | "version": "4.9.3", 415 | "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.9.3.tgz", 416 | "integrity": "sha512-qNy2odgsa0skmNMCuxzXhM4M8J1YDaPv3TI+vCdnOAanu0N982wBrSqziDKRDctEZLZy9VffqIZXc0UGjjSP/g==", 417 | "engines": { 418 | "node": ">=14" 419 | } 420 | }, 421 | "node_modules/anymatch": { 422 | "version": "3.1.3", 423 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", 424 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", 425 | "dev": true, 426 | "dependencies": { 427 | "normalize-path": "^3.0.0", 428 | "picomatch": "^2.0.4" 429 | }, 430 | "engines": { 431 | "node": ">= 8" 432 | } 433 | }, 434 | "node_modules/argparse": { 435 | "version": "2.0.1", 436 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", 437 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", 438 | "dev": true 439 | }, 440 | "node_modules/array-flatten": { 441 | "version": "1.1.1", 442 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 443 | "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" 444 | }, 445 | "node_modules/assertion-error": { 446 | "version": "1.1.0", 447 | "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", 448 | "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", 449 | "dev": true, 450 | "engines": { 451 | "node": "*" 452 | } 453 | }, 454 | "node_modules/asynckit": { 455 | "version": "0.4.0", 456 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 457 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", 458 | "dev": true 459 | }, 460 | "node_modules/axios": { 461 | "version": "1.8.2", 462 | "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.2.tgz", 463 | "integrity": "sha512-ls4GYBm5aig9vWx8AWDSGLpnpDQRtWAfrjU+EuytuODrFBkqesN2RkOQCBzrA1RQNHw1SmRMSDDDSwzNAYQ6Rg==", 464 | "dev": true, 465 | "license": "MIT", 466 | "dependencies": { 467 | "follow-redirects": "^1.15.6", 468 | "form-data": "^4.0.0", 469 | "proxy-from-env": "^1.1.0" 470 | } 471 | }, 472 | "node_modules/balanced-match": { 473 | "version": "1.0.2", 474 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 475 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 476 | "dev": true 477 | }, 478 | "node_modules/base64-js": { 479 | "version": "1.5.1", 480 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", 481 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", 482 | "dev": true, 483 | "funding": [ 484 | { 485 | "type": "github", 486 | "url": "https://github.com/sponsors/feross" 487 | }, 488 | { 489 | "type": "patreon", 490 | "url": "https://www.patreon.com/feross" 491 | }, 492 | { 493 | "type": "consulting", 494 | "url": "https://feross.org/support" 495 | } 496 | ] 497 | }, 498 | "node_modules/better-sqlite3": { 499 | "version": "11.5.0", 500 | "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-11.5.0.tgz", 501 | "integrity": "sha512-e/6eggfOutzoK0JWiU36jsisdWoHOfN9iWiW/SieKvb7SAa6aGNmBM/UKyp+/wWSXpLlWNN8tCPwoDNPhzUvuQ==", 502 | "dev": true, 503 | "hasInstallScript": true, 504 | "dependencies": { 505 | "bindings": "^1.5.0", 506 | "prebuild-install": "^7.1.1" 507 | } 508 | }, 509 | "node_modules/big.js": { 510 | "version": "6.2.2", 511 | "resolved": "https://registry.npmjs.org/big.js/-/big.js-6.2.2.tgz", 512 | "integrity": "sha512-y/ie+Faknx7sZA5MfGA2xKlu0GDv8RWrXGsmlteyJQ2lvoKv9GBK/fpRMc2qlSoBAgNxrixICFCBefIq8WCQpQ==", 513 | "engines": { 514 | "node": "*" 515 | }, 516 | "funding": { 517 | "type": "opencollective", 518 | "url": "https://opencollective.com/bigjs" 519 | } 520 | }, 521 | "node_modules/binary-extensions": { 522 | "version": "2.3.0", 523 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", 524 | "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", 525 | "dev": true, 526 | "engines": { 527 | "node": ">=8" 528 | }, 529 | "funding": { 530 | "url": "https://github.com/sponsors/sindresorhus" 531 | } 532 | }, 533 | "node_modules/bindings": { 534 | "version": "1.5.0", 535 | "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", 536 | "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", 537 | "dev": true, 538 | "dependencies": { 539 | "file-uri-to-path": "1.0.0" 540 | } 541 | }, 542 | "node_modules/bl": { 543 | "version": "4.1.0", 544 | "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", 545 | "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", 546 | "dev": true, 547 | "dependencies": { 548 | "buffer": "^5.5.0", 549 | "inherits": "^2.0.4", 550 | "readable-stream": "^3.4.0" 551 | } 552 | }, 553 | "node_modules/body-parser": { 554 | "version": "1.20.3", 555 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", 556 | "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", 557 | "dependencies": { 558 | "bytes": "3.1.2", 559 | "content-type": "~1.0.5", 560 | "debug": "2.6.9", 561 | "depd": "2.0.0", 562 | "destroy": "1.2.0", 563 | "http-errors": "2.0.0", 564 | "iconv-lite": "0.4.24", 565 | "on-finished": "2.4.1", 566 | "qs": "6.13.0", 567 | "raw-body": "2.5.2", 568 | "type-is": "~1.6.18", 569 | "unpipe": "1.0.0" 570 | }, 571 | "engines": { 572 | "node": ">= 0.8", 573 | "npm": "1.2.8000 || >= 1.4.16" 574 | } 575 | }, 576 | "node_modules/body-parser/node_modules/debug": { 577 | "version": "2.6.9", 578 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 579 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 580 | "dependencies": { 581 | "ms": "2.0.0" 582 | } 583 | }, 584 | "node_modules/body-parser/node_modules/ms": { 585 | "version": "2.0.0", 586 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 587 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" 588 | }, 589 | "node_modules/brace-expansion": { 590 | "version": "1.1.11", 591 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 592 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 593 | "dev": true, 594 | "dependencies": { 595 | "balanced-match": "^1.0.0", 596 | "concat-map": "0.0.1" 597 | } 598 | }, 599 | "node_modules/braces": { 600 | "version": "3.0.3", 601 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", 602 | "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", 603 | "dev": true, 604 | "dependencies": { 605 | "fill-range": "^7.1.1" 606 | }, 607 | "engines": { 608 | "node": ">=8" 609 | } 610 | }, 611 | "node_modules/browser-stdout": { 612 | "version": "1.3.1", 613 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", 614 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", 615 | "dev": true 616 | }, 617 | "node_modules/buffer": { 618 | "version": "5.7.1", 619 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", 620 | "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", 621 | "dev": true, 622 | "funding": [ 623 | { 624 | "type": "github", 625 | "url": "https://github.com/sponsors/feross" 626 | }, 627 | { 628 | "type": "patreon", 629 | "url": "https://www.patreon.com/feross" 630 | }, 631 | { 632 | "type": "consulting", 633 | "url": "https://feross.org/support" 634 | } 635 | ], 636 | "dependencies": { 637 | "base64-js": "^1.3.1", 638 | "ieee754": "^1.1.13" 639 | } 640 | }, 641 | "node_modules/bytes": { 642 | "version": "3.1.2", 643 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", 644 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", 645 | "engines": { 646 | "node": ">= 0.8" 647 | } 648 | }, 649 | "node_modules/call-bind": { 650 | "version": "1.0.7", 651 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", 652 | "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", 653 | "dependencies": { 654 | "es-define-property": "^1.0.0", 655 | "es-errors": "^1.3.0", 656 | "function-bind": "^1.1.2", 657 | "get-intrinsic": "^1.2.4", 658 | "set-function-length": "^1.2.1" 659 | }, 660 | "engines": { 661 | "node": ">= 0.4" 662 | }, 663 | "funding": { 664 | "url": "https://github.com/sponsors/ljharb" 665 | } 666 | }, 667 | "node_modules/callsites": { 668 | "version": "3.1.0", 669 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", 670 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", 671 | "dev": true, 672 | "engines": { 673 | "node": ">=6" 674 | } 675 | }, 676 | "node_modules/camelcase": { 677 | "version": "6.3.0", 678 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", 679 | "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", 680 | "dev": true, 681 | "engines": { 682 | "node": ">=10" 683 | }, 684 | "funding": { 685 | "url": "https://github.com/sponsors/sindresorhus" 686 | } 687 | }, 688 | "node_modules/capval": { 689 | "resolved": "..", 690 | "link": true 691 | }, 692 | "node_modules/chai": { 693 | "version": "4.5.0", 694 | "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", 695 | "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", 696 | "dev": true, 697 | "dependencies": { 698 | "assertion-error": "^1.1.0", 699 | "check-error": "^1.0.3", 700 | "deep-eql": "^4.1.3", 701 | "get-func-name": "^2.0.2", 702 | "loupe": "^2.3.6", 703 | "pathval": "^1.1.1", 704 | "type-detect": "^4.1.0" 705 | }, 706 | "engines": { 707 | "node": ">=4" 708 | } 709 | }, 710 | "node_modules/chai-as-promised": { 711 | "version": "7.1.2", 712 | "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.2.tgz", 713 | "integrity": "sha512-aBDHZxRzYnUYuIAIPBH2s511DjlKPzXNlXSGFC8CwmroWQLfrW0LtE1nK3MAwwNhJPa9raEjNCmRoFpG0Hurdw==", 714 | "dev": true, 715 | "dependencies": { 716 | "check-error": "^1.0.2" 717 | }, 718 | "peerDependencies": { 719 | "chai": ">= 2.1.2 < 6" 720 | } 721 | }, 722 | "node_modules/chai-subset": { 723 | "version": "1.6.0", 724 | "resolved": "https://registry.npmjs.org/chai-subset/-/chai-subset-1.6.0.tgz", 725 | "integrity": "sha512-K3d+KmqdS5XKW5DWPd5sgNffL3uxdDe+6GdnJh3AYPhwnBGRY5urfvfcbRtWIvvpz+KxkL9FeBB6MZewLUNwug==", 726 | "dev": true, 727 | "engines": { 728 | "node": ">=4" 729 | } 730 | }, 731 | "node_modules/chalk": { 732 | "version": "4.1.2", 733 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 734 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 735 | "dev": true, 736 | "dependencies": { 737 | "ansi-styles": "^4.1.0", 738 | "supports-color": "^7.1.0" 739 | }, 740 | "engines": { 741 | "node": ">=10" 742 | }, 743 | "funding": { 744 | "url": "https://github.com/chalk/chalk?sponsor=1" 745 | } 746 | }, 747 | "node_modules/check-error": { 748 | "version": "1.0.3", 749 | "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", 750 | "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", 751 | "dev": true, 752 | "dependencies": { 753 | "get-func-name": "^2.0.2" 754 | }, 755 | "engines": { 756 | "node": "*" 757 | } 758 | }, 759 | "node_modules/chokidar": { 760 | "version": "3.6.0", 761 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", 762 | "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", 763 | "dev": true, 764 | "dependencies": { 765 | "anymatch": "~3.1.2", 766 | "braces": "~3.0.2", 767 | "glob-parent": "~5.1.2", 768 | "is-binary-path": "~2.1.0", 769 | "is-glob": "~4.0.1", 770 | "normalize-path": "~3.0.0", 771 | "readdirp": "~3.6.0" 772 | }, 773 | "engines": { 774 | "node": ">= 8.10.0" 775 | }, 776 | "funding": { 777 | "url": "https://paulmillr.com/funding/" 778 | }, 779 | "optionalDependencies": { 780 | "fsevents": "~2.3.2" 781 | } 782 | }, 783 | "node_modules/chokidar/node_modules/glob-parent": { 784 | "version": "5.1.2", 785 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 786 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 787 | "dev": true, 788 | "dependencies": { 789 | "is-glob": "^4.0.1" 790 | }, 791 | "engines": { 792 | "node": ">= 6" 793 | } 794 | }, 795 | "node_modules/chownr": { 796 | "version": "1.1.4", 797 | "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", 798 | "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", 799 | "dev": true 800 | }, 801 | "node_modules/cliui": { 802 | "version": "7.0.4", 803 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", 804 | "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", 805 | "dev": true, 806 | "dependencies": { 807 | "string-width": "^4.2.0", 808 | "strip-ansi": "^6.0.0", 809 | "wrap-ansi": "^7.0.0" 810 | } 811 | }, 812 | "node_modules/color-convert": { 813 | "version": "2.0.1", 814 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 815 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 816 | "dev": true, 817 | "dependencies": { 818 | "color-name": "~1.1.4" 819 | }, 820 | "engines": { 821 | "node": ">=7.0.0" 822 | } 823 | }, 824 | "node_modules/color-name": { 825 | "version": "1.1.4", 826 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 827 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 828 | "dev": true 829 | }, 830 | "node_modules/combined-stream": { 831 | "version": "1.0.8", 832 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 833 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 834 | "dev": true, 835 | "dependencies": { 836 | "delayed-stream": "~1.0.0" 837 | }, 838 | "engines": { 839 | "node": ">= 0.8" 840 | } 841 | }, 842 | "node_modules/concat-map": { 843 | "version": "0.0.1", 844 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 845 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 846 | "dev": true 847 | }, 848 | "node_modules/content-disposition": { 849 | "version": "0.5.4", 850 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", 851 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", 852 | "dependencies": { 853 | "safe-buffer": "5.2.1" 854 | }, 855 | "engines": { 856 | "node": ">= 0.6" 857 | } 858 | }, 859 | "node_modules/content-type": { 860 | "version": "1.0.5", 861 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", 862 | "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", 863 | "engines": { 864 | "node": ">= 0.6" 865 | } 866 | }, 867 | "node_modules/cookie": { 868 | "version": "0.7.1", 869 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", 870 | "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", 871 | "engines": { 872 | "node": ">= 0.6" 873 | } 874 | }, 875 | "node_modules/cookie-signature": { 876 | "version": "1.0.6", 877 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 878 | "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" 879 | }, 880 | "node_modules/cross-spawn": { 881 | "version": "7.0.5", 882 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.5.tgz", 883 | "integrity": "sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==", 884 | "dev": true, 885 | "dependencies": { 886 | "path-key": "^3.1.0", 887 | "shebang-command": "^2.0.0", 888 | "which": "^2.0.1" 889 | }, 890 | "engines": { 891 | "node": ">= 8" 892 | } 893 | }, 894 | "node_modules/debug": { 895 | "version": "4.3.7", 896 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", 897 | "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", 898 | "dev": true, 899 | "dependencies": { 900 | "ms": "^2.1.3" 901 | }, 902 | "engines": { 903 | "node": ">=6.0" 904 | }, 905 | "peerDependenciesMeta": { 906 | "supports-color": { 907 | "optional": true 908 | } 909 | } 910 | }, 911 | "node_modules/decamelize": { 912 | "version": "4.0.0", 913 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", 914 | "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", 915 | "dev": true, 916 | "engines": { 917 | "node": ">=10" 918 | }, 919 | "funding": { 920 | "url": "https://github.com/sponsors/sindresorhus" 921 | } 922 | }, 923 | "node_modules/decompress-response": { 924 | "version": "6.0.0", 925 | "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", 926 | "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", 927 | "dev": true, 928 | "dependencies": { 929 | "mimic-response": "^3.1.0" 930 | }, 931 | "engines": { 932 | "node": ">=10" 933 | }, 934 | "funding": { 935 | "url": "https://github.com/sponsors/sindresorhus" 936 | } 937 | }, 938 | "node_modules/deep-eql": { 939 | "version": "4.1.4", 940 | "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", 941 | "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", 942 | "dev": true, 943 | "dependencies": { 944 | "type-detect": "^4.0.0" 945 | }, 946 | "engines": { 947 | "node": ">=6" 948 | } 949 | }, 950 | "node_modules/deep-extend": { 951 | "version": "0.6.0", 952 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", 953 | "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", 954 | "dev": true, 955 | "engines": { 956 | "node": ">=4.0.0" 957 | } 958 | }, 959 | "node_modules/deep-is": { 960 | "version": "0.1.4", 961 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", 962 | "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", 963 | "dev": true 964 | }, 965 | "node_modules/define-data-property": { 966 | "version": "1.1.4", 967 | "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", 968 | "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", 969 | "dependencies": { 970 | "es-define-property": "^1.0.0", 971 | "es-errors": "^1.3.0", 972 | "gopd": "^1.0.1" 973 | }, 974 | "engines": { 975 | "node": ">= 0.4" 976 | }, 977 | "funding": { 978 | "url": "https://github.com/sponsors/ljharb" 979 | } 980 | }, 981 | "node_modules/delayed-stream": { 982 | "version": "1.0.0", 983 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 984 | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", 985 | "dev": true, 986 | "engines": { 987 | "node": ">=0.4.0" 988 | } 989 | }, 990 | "node_modules/depd": { 991 | "version": "2.0.0", 992 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", 993 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", 994 | "engines": { 995 | "node": ">= 0.8" 996 | } 997 | }, 998 | "node_modules/destroy": { 999 | "version": "1.2.0", 1000 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", 1001 | "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", 1002 | "engines": { 1003 | "node": ">= 0.8", 1004 | "npm": "1.2.8000 || >= 1.4.16" 1005 | } 1006 | }, 1007 | "node_modules/detect-libc": { 1008 | "version": "2.0.3", 1009 | "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", 1010 | "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", 1011 | "dev": true, 1012 | "engines": { 1013 | "node": ">=8" 1014 | } 1015 | }, 1016 | "node_modules/diff": { 1017 | "version": "5.2.0", 1018 | "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", 1019 | "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", 1020 | "dev": true, 1021 | "engines": { 1022 | "node": ">=0.3.1" 1023 | } 1024 | }, 1025 | "node_modules/ee-first": { 1026 | "version": "1.1.1", 1027 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 1028 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" 1029 | }, 1030 | "node_modules/emoji-regex": { 1031 | "version": "8.0.0", 1032 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 1033 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 1034 | "dev": true 1035 | }, 1036 | "node_modules/encodeurl": { 1037 | "version": "2.0.0", 1038 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", 1039 | "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", 1040 | "engines": { 1041 | "node": ">= 0.8" 1042 | } 1043 | }, 1044 | "node_modules/end-of-stream": { 1045 | "version": "1.4.4", 1046 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", 1047 | "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", 1048 | "dev": true, 1049 | "dependencies": { 1050 | "once": "^1.4.0" 1051 | } 1052 | }, 1053 | "node_modules/es-define-property": { 1054 | "version": "1.0.0", 1055 | "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", 1056 | "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", 1057 | "dependencies": { 1058 | "get-intrinsic": "^1.2.4" 1059 | }, 1060 | "engines": { 1061 | "node": ">= 0.4" 1062 | } 1063 | }, 1064 | "node_modules/es-errors": { 1065 | "version": "1.3.0", 1066 | "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", 1067 | "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", 1068 | "engines": { 1069 | "node": ">= 0.4" 1070 | } 1071 | }, 1072 | "node_modules/escalade": { 1073 | "version": "3.2.0", 1074 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", 1075 | "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", 1076 | "dev": true, 1077 | "engines": { 1078 | "node": ">=6" 1079 | } 1080 | }, 1081 | "node_modules/escape-html": { 1082 | "version": "1.0.3", 1083 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 1084 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" 1085 | }, 1086 | "node_modules/escape-string-regexp": { 1087 | "version": "4.0.0", 1088 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", 1089 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", 1090 | "dev": true, 1091 | "engines": { 1092 | "node": ">=10" 1093 | }, 1094 | "funding": { 1095 | "url": "https://github.com/sponsors/sindresorhus" 1096 | } 1097 | }, 1098 | "node_modules/eslint": { 1099 | "version": "9.15.0", 1100 | "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.15.0.tgz", 1101 | "integrity": "sha512-7CrWySmIibCgT1Os28lUU6upBshZ+GxybLOrmRzi08kS8MBuO8QA7pXEgYgY5W8vK3e74xv0lpjo9DbaGU9Rkw==", 1102 | "dev": true, 1103 | "dependencies": { 1104 | "@eslint-community/eslint-utils": "^4.2.0", 1105 | "@eslint-community/regexpp": "^4.12.1", 1106 | "@eslint/config-array": "^0.19.0", 1107 | "@eslint/core": "^0.9.0", 1108 | "@eslint/eslintrc": "^3.2.0", 1109 | "@eslint/js": "9.15.0", 1110 | "@eslint/plugin-kit": "^0.2.3", 1111 | "@humanfs/node": "^0.16.6", 1112 | "@humanwhocodes/module-importer": "^1.0.1", 1113 | "@humanwhocodes/retry": "^0.4.1", 1114 | "@types/estree": "^1.0.6", 1115 | "@types/json-schema": "^7.0.15", 1116 | "ajv": "^6.12.4", 1117 | "chalk": "^4.0.0", 1118 | "cross-spawn": "^7.0.5", 1119 | "debug": "^4.3.2", 1120 | "escape-string-regexp": "^4.0.0", 1121 | "eslint-scope": "^8.2.0", 1122 | "eslint-visitor-keys": "^4.2.0", 1123 | "espree": "^10.3.0", 1124 | "esquery": "^1.5.0", 1125 | "esutils": "^2.0.2", 1126 | "fast-deep-equal": "^3.1.3", 1127 | "file-entry-cache": "^8.0.0", 1128 | "find-up": "^5.0.0", 1129 | "glob-parent": "^6.0.2", 1130 | "ignore": "^5.2.0", 1131 | "imurmurhash": "^0.1.4", 1132 | "is-glob": "^4.0.0", 1133 | "json-stable-stringify-without-jsonify": "^1.0.1", 1134 | "lodash.merge": "^4.6.2", 1135 | "minimatch": "^3.1.2", 1136 | "natural-compare": "^1.4.0", 1137 | "optionator": "^0.9.3" 1138 | }, 1139 | "bin": { 1140 | "eslint": "bin/eslint.js" 1141 | }, 1142 | "engines": { 1143 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1144 | }, 1145 | "funding": { 1146 | "url": "https://eslint.org/donate" 1147 | }, 1148 | "peerDependencies": { 1149 | "jiti": "*" 1150 | }, 1151 | "peerDependenciesMeta": { 1152 | "jiti": { 1153 | "optional": true 1154 | } 1155 | } 1156 | }, 1157 | "node_modules/eslint-scope": { 1158 | "version": "8.2.0", 1159 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", 1160 | "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", 1161 | "dev": true, 1162 | "dependencies": { 1163 | "esrecurse": "^4.3.0", 1164 | "estraverse": "^5.2.0" 1165 | }, 1166 | "engines": { 1167 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1168 | }, 1169 | "funding": { 1170 | "url": "https://opencollective.com/eslint" 1171 | } 1172 | }, 1173 | "node_modules/eslint-visitor-keys": { 1174 | "version": "4.2.0", 1175 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", 1176 | "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", 1177 | "dev": true, 1178 | "engines": { 1179 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1180 | }, 1181 | "funding": { 1182 | "url": "https://opencollective.com/eslint" 1183 | } 1184 | }, 1185 | "node_modules/espree": { 1186 | "version": "10.3.0", 1187 | "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", 1188 | "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", 1189 | "dev": true, 1190 | "dependencies": { 1191 | "acorn": "^8.14.0", 1192 | "acorn-jsx": "^5.3.2", 1193 | "eslint-visitor-keys": "^4.2.0" 1194 | }, 1195 | "engines": { 1196 | "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1197 | }, 1198 | "funding": { 1199 | "url": "https://opencollective.com/eslint" 1200 | } 1201 | }, 1202 | "node_modules/esquery": { 1203 | "version": "1.6.0", 1204 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", 1205 | "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", 1206 | "dev": true, 1207 | "dependencies": { 1208 | "estraverse": "^5.1.0" 1209 | }, 1210 | "engines": { 1211 | "node": ">=0.10" 1212 | } 1213 | }, 1214 | "node_modules/esrecurse": { 1215 | "version": "4.3.0", 1216 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", 1217 | "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", 1218 | "dev": true, 1219 | "dependencies": { 1220 | "estraverse": "^5.2.0" 1221 | }, 1222 | "engines": { 1223 | "node": ">=4.0" 1224 | } 1225 | }, 1226 | "node_modules/estraverse": { 1227 | "version": "5.3.0", 1228 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", 1229 | "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", 1230 | "dev": true, 1231 | "engines": { 1232 | "node": ">=4.0" 1233 | } 1234 | }, 1235 | "node_modules/esutils": { 1236 | "version": "2.0.3", 1237 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", 1238 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", 1239 | "dev": true, 1240 | "engines": { 1241 | "node": ">=0.10.0" 1242 | } 1243 | }, 1244 | "node_modules/etag": { 1245 | "version": "1.8.1", 1246 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 1247 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", 1248 | "engines": { 1249 | "node": ">= 0.6" 1250 | } 1251 | }, 1252 | "node_modules/expand-template": { 1253 | "version": "2.0.3", 1254 | "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", 1255 | "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", 1256 | "dev": true, 1257 | "engines": { 1258 | "node": ">=6" 1259 | } 1260 | }, 1261 | "node_modules/express": { 1262 | "version": "4.21.2", 1263 | "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", 1264 | "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", 1265 | "license": "MIT", 1266 | "dependencies": { 1267 | "accepts": "~1.3.8", 1268 | "array-flatten": "1.1.1", 1269 | "body-parser": "1.20.3", 1270 | "content-disposition": "0.5.4", 1271 | "content-type": "~1.0.4", 1272 | "cookie": "0.7.1", 1273 | "cookie-signature": "1.0.6", 1274 | "debug": "2.6.9", 1275 | "depd": "2.0.0", 1276 | "encodeurl": "~2.0.0", 1277 | "escape-html": "~1.0.3", 1278 | "etag": "~1.8.1", 1279 | "finalhandler": "1.3.1", 1280 | "fresh": "0.5.2", 1281 | "http-errors": "2.0.0", 1282 | "merge-descriptors": "1.0.3", 1283 | "methods": "~1.1.2", 1284 | "on-finished": "2.4.1", 1285 | "parseurl": "~1.3.3", 1286 | "path-to-regexp": "0.1.12", 1287 | "proxy-addr": "~2.0.7", 1288 | "qs": "6.13.0", 1289 | "range-parser": "~1.2.1", 1290 | "safe-buffer": "5.2.1", 1291 | "send": "0.19.0", 1292 | "serve-static": "1.16.2", 1293 | "setprototypeof": "1.2.0", 1294 | "statuses": "2.0.1", 1295 | "type-is": "~1.6.18", 1296 | "utils-merge": "1.0.1", 1297 | "vary": "~1.1.2" 1298 | }, 1299 | "engines": { 1300 | "node": ">= 0.10.0" 1301 | }, 1302 | "funding": { 1303 | "type": "opencollective", 1304 | "url": "https://opencollective.com/express" 1305 | } 1306 | }, 1307 | "node_modules/express/node_modules/debug": { 1308 | "version": "2.6.9", 1309 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 1310 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 1311 | "dependencies": { 1312 | "ms": "2.0.0" 1313 | } 1314 | }, 1315 | "node_modules/express/node_modules/ms": { 1316 | "version": "2.0.0", 1317 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 1318 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" 1319 | }, 1320 | "node_modules/fast-deep-equal": { 1321 | "version": "3.1.3", 1322 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 1323 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", 1324 | "dev": true 1325 | }, 1326 | "node_modules/fast-json-stable-stringify": { 1327 | "version": "2.1.0", 1328 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", 1329 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", 1330 | "dev": true 1331 | }, 1332 | "node_modules/fast-levenshtein": { 1333 | "version": "2.0.6", 1334 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 1335 | "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", 1336 | "dev": true 1337 | }, 1338 | "node_modules/file-entry-cache": { 1339 | "version": "8.0.0", 1340 | "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", 1341 | "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", 1342 | "dev": true, 1343 | "dependencies": { 1344 | "flat-cache": "^4.0.0" 1345 | }, 1346 | "engines": { 1347 | "node": ">=16.0.0" 1348 | } 1349 | }, 1350 | "node_modules/file-uri-to-path": { 1351 | "version": "1.0.0", 1352 | "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", 1353 | "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", 1354 | "dev": true 1355 | }, 1356 | "node_modules/fill-range": { 1357 | "version": "7.1.1", 1358 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", 1359 | "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", 1360 | "dev": true, 1361 | "dependencies": { 1362 | "to-regex-range": "^5.0.1" 1363 | }, 1364 | "engines": { 1365 | "node": ">=8" 1366 | } 1367 | }, 1368 | "node_modules/finalhandler": { 1369 | "version": "1.3.1", 1370 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", 1371 | "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", 1372 | "dependencies": { 1373 | "debug": "2.6.9", 1374 | "encodeurl": "~2.0.0", 1375 | "escape-html": "~1.0.3", 1376 | "on-finished": "2.4.1", 1377 | "parseurl": "~1.3.3", 1378 | "statuses": "2.0.1", 1379 | "unpipe": "~1.0.0" 1380 | }, 1381 | "engines": { 1382 | "node": ">= 0.8" 1383 | } 1384 | }, 1385 | "node_modules/finalhandler/node_modules/debug": { 1386 | "version": "2.6.9", 1387 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 1388 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 1389 | "dependencies": { 1390 | "ms": "2.0.0" 1391 | } 1392 | }, 1393 | "node_modules/finalhandler/node_modules/ms": { 1394 | "version": "2.0.0", 1395 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 1396 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" 1397 | }, 1398 | "node_modules/find-up": { 1399 | "version": "5.0.0", 1400 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", 1401 | "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", 1402 | "dev": true, 1403 | "dependencies": { 1404 | "locate-path": "^6.0.0", 1405 | "path-exists": "^4.0.0" 1406 | }, 1407 | "engines": { 1408 | "node": ">=10" 1409 | }, 1410 | "funding": { 1411 | "url": "https://github.com/sponsors/sindresorhus" 1412 | } 1413 | }, 1414 | "node_modules/flat": { 1415 | "version": "5.0.2", 1416 | "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", 1417 | "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", 1418 | "dev": true, 1419 | "bin": { 1420 | "flat": "cli.js" 1421 | } 1422 | }, 1423 | "node_modules/flat-cache": { 1424 | "version": "4.0.1", 1425 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", 1426 | "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", 1427 | "dev": true, 1428 | "dependencies": { 1429 | "flatted": "^3.2.9", 1430 | "keyv": "^4.5.4" 1431 | }, 1432 | "engines": { 1433 | "node": ">=16" 1434 | } 1435 | }, 1436 | "node_modules/flatted": { 1437 | "version": "3.3.1", 1438 | "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", 1439 | "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", 1440 | "dev": true 1441 | }, 1442 | "node_modules/follow-redirects": { 1443 | "version": "1.15.9", 1444 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", 1445 | "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", 1446 | "dev": true, 1447 | "funding": [ 1448 | { 1449 | "type": "individual", 1450 | "url": "https://github.com/sponsors/RubenVerborgh" 1451 | } 1452 | ], 1453 | "engines": { 1454 | "node": ">=4.0" 1455 | }, 1456 | "peerDependenciesMeta": { 1457 | "debug": { 1458 | "optional": true 1459 | } 1460 | } 1461 | }, 1462 | "node_modules/form-data": { 1463 | "version": "4.0.1", 1464 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", 1465 | "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", 1466 | "dev": true, 1467 | "dependencies": { 1468 | "asynckit": "^0.4.0", 1469 | "combined-stream": "^1.0.8", 1470 | "mime-types": "^2.1.12" 1471 | }, 1472 | "engines": { 1473 | "node": ">= 6" 1474 | } 1475 | }, 1476 | "node_modules/forwarded": { 1477 | "version": "0.2.0", 1478 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", 1479 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", 1480 | "engines": { 1481 | "node": ">= 0.6" 1482 | } 1483 | }, 1484 | "node_modules/fresh": { 1485 | "version": "0.5.2", 1486 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 1487 | "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", 1488 | "engines": { 1489 | "node": ">= 0.6" 1490 | } 1491 | }, 1492 | "node_modules/fs-constants": { 1493 | "version": "1.0.0", 1494 | "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", 1495 | "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", 1496 | "dev": true 1497 | }, 1498 | "node_modules/fs.realpath": { 1499 | "version": "1.0.0", 1500 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 1501 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", 1502 | "dev": true 1503 | }, 1504 | "node_modules/fsevents": { 1505 | "version": "2.3.3", 1506 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 1507 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 1508 | "dev": true, 1509 | "hasInstallScript": true, 1510 | "optional": true, 1511 | "os": [ 1512 | "darwin" 1513 | ], 1514 | "engines": { 1515 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 1516 | } 1517 | }, 1518 | "node_modules/function-bind": { 1519 | "version": "1.1.2", 1520 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", 1521 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", 1522 | "funding": { 1523 | "url": "https://github.com/sponsors/ljharb" 1524 | } 1525 | }, 1526 | "node_modules/generic-pool": { 1527 | "version": "3.9.0", 1528 | "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", 1529 | "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==", 1530 | "engines": { 1531 | "node": ">= 4" 1532 | } 1533 | }, 1534 | "node_modules/get-caller-file": { 1535 | "version": "2.0.5", 1536 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 1537 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 1538 | "dev": true, 1539 | "engines": { 1540 | "node": "6.* || 8.* || >= 10.*" 1541 | } 1542 | }, 1543 | "node_modules/get-func-name": { 1544 | "version": "2.0.2", 1545 | "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", 1546 | "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", 1547 | "dev": true, 1548 | "engines": { 1549 | "node": "*" 1550 | } 1551 | }, 1552 | "node_modules/get-intrinsic": { 1553 | "version": "1.2.4", 1554 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", 1555 | "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", 1556 | "dependencies": { 1557 | "es-errors": "^1.3.0", 1558 | "function-bind": "^1.1.2", 1559 | "has-proto": "^1.0.1", 1560 | "has-symbols": "^1.0.3", 1561 | "hasown": "^2.0.0" 1562 | }, 1563 | "engines": { 1564 | "node": ">= 0.4" 1565 | }, 1566 | "funding": { 1567 | "url": "https://github.com/sponsors/ljharb" 1568 | } 1569 | }, 1570 | "node_modules/github-from-package": { 1571 | "version": "0.0.0", 1572 | "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", 1573 | "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", 1574 | "dev": true 1575 | }, 1576 | "node_modules/glob": { 1577 | "version": "8.1.0", 1578 | "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", 1579 | "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", 1580 | "deprecated": "Glob versions prior to v9 are no longer supported", 1581 | "dev": true, 1582 | "dependencies": { 1583 | "fs.realpath": "^1.0.0", 1584 | "inflight": "^1.0.4", 1585 | "inherits": "2", 1586 | "minimatch": "^5.0.1", 1587 | "once": "^1.3.0" 1588 | }, 1589 | "engines": { 1590 | "node": ">=12" 1591 | }, 1592 | "funding": { 1593 | "url": "https://github.com/sponsors/isaacs" 1594 | } 1595 | }, 1596 | "node_modules/glob-parent": { 1597 | "version": "6.0.2", 1598 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", 1599 | "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", 1600 | "dev": true, 1601 | "dependencies": { 1602 | "is-glob": "^4.0.3" 1603 | }, 1604 | "engines": { 1605 | "node": ">=10.13.0" 1606 | } 1607 | }, 1608 | "node_modules/glob/node_modules/brace-expansion": { 1609 | "version": "2.0.1", 1610 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", 1611 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", 1612 | "dev": true, 1613 | "dependencies": { 1614 | "balanced-match": "^1.0.0" 1615 | } 1616 | }, 1617 | "node_modules/glob/node_modules/minimatch": { 1618 | "version": "5.1.6", 1619 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", 1620 | "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", 1621 | "dev": true, 1622 | "dependencies": { 1623 | "brace-expansion": "^2.0.1" 1624 | }, 1625 | "engines": { 1626 | "node": ">=10" 1627 | } 1628 | }, 1629 | "node_modules/globals": { 1630 | "version": "14.0.0", 1631 | "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", 1632 | "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", 1633 | "dev": true, 1634 | "engines": { 1635 | "node": ">=18" 1636 | }, 1637 | "funding": { 1638 | "url": "https://github.com/sponsors/sindresorhus" 1639 | } 1640 | }, 1641 | "node_modules/gopd": { 1642 | "version": "1.0.1", 1643 | "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", 1644 | "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", 1645 | "dependencies": { 1646 | "get-intrinsic": "^1.1.3" 1647 | }, 1648 | "funding": { 1649 | "url": "https://github.com/sponsors/ljharb" 1650 | } 1651 | }, 1652 | "node_modules/has-flag": { 1653 | "version": "4.0.0", 1654 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 1655 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 1656 | "dev": true, 1657 | "engines": { 1658 | "node": ">=8" 1659 | } 1660 | }, 1661 | "node_modules/has-property-descriptors": { 1662 | "version": "1.0.2", 1663 | "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", 1664 | "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", 1665 | "dependencies": { 1666 | "es-define-property": "^1.0.0" 1667 | }, 1668 | "funding": { 1669 | "url": "https://github.com/sponsors/ljharb" 1670 | } 1671 | }, 1672 | "node_modules/has-proto": { 1673 | "version": "1.0.3", 1674 | "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", 1675 | "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", 1676 | "engines": { 1677 | "node": ">= 0.4" 1678 | }, 1679 | "funding": { 1680 | "url": "https://github.com/sponsors/ljharb" 1681 | } 1682 | }, 1683 | "node_modules/has-symbols": { 1684 | "version": "1.0.3", 1685 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", 1686 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", 1687 | "engines": { 1688 | "node": ">= 0.4" 1689 | }, 1690 | "funding": { 1691 | "url": "https://github.com/sponsors/ljharb" 1692 | } 1693 | }, 1694 | "node_modules/hasown": { 1695 | "version": "2.0.2", 1696 | "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", 1697 | "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", 1698 | "dependencies": { 1699 | "function-bind": "^1.1.2" 1700 | }, 1701 | "engines": { 1702 | "node": ">= 0.4" 1703 | } 1704 | }, 1705 | "node_modules/he": { 1706 | "version": "1.2.0", 1707 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", 1708 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", 1709 | "dev": true, 1710 | "bin": { 1711 | "he": "bin/he" 1712 | } 1713 | }, 1714 | "node_modules/http-errors": { 1715 | "version": "2.0.0", 1716 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", 1717 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", 1718 | "dependencies": { 1719 | "depd": "2.0.0", 1720 | "inherits": "2.0.4", 1721 | "setprototypeof": "1.2.0", 1722 | "statuses": "2.0.1", 1723 | "toidentifier": "1.0.1" 1724 | }, 1725 | "engines": { 1726 | "node": ">= 0.8" 1727 | } 1728 | }, 1729 | "node_modules/iconv-lite": { 1730 | "version": "0.4.24", 1731 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 1732 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 1733 | "dependencies": { 1734 | "safer-buffer": ">= 2.1.2 < 3" 1735 | }, 1736 | "engines": { 1737 | "node": ">=0.10.0" 1738 | } 1739 | }, 1740 | "node_modules/ieee754": { 1741 | "version": "1.2.1", 1742 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", 1743 | "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", 1744 | "dev": true, 1745 | "funding": [ 1746 | { 1747 | "type": "github", 1748 | "url": "https://github.com/sponsors/feross" 1749 | }, 1750 | { 1751 | "type": "patreon", 1752 | "url": "https://www.patreon.com/feross" 1753 | }, 1754 | { 1755 | "type": "consulting", 1756 | "url": "https://feross.org/support" 1757 | } 1758 | ] 1759 | }, 1760 | "node_modules/ignore": { 1761 | "version": "5.3.2", 1762 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", 1763 | "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", 1764 | "dev": true, 1765 | "engines": { 1766 | "node": ">= 4" 1767 | } 1768 | }, 1769 | "node_modules/import-fresh": { 1770 | "version": "3.3.0", 1771 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", 1772 | "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", 1773 | "dev": true, 1774 | "dependencies": { 1775 | "parent-module": "^1.0.0", 1776 | "resolve-from": "^4.0.0" 1777 | }, 1778 | "engines": { 1779 | "node": ">=6" 1780 | }, 1781 | "funding": { 1782 | "url": "https://github.com/sponsors/sindresorhus" 1783 | } 1784 | }, 1785 | "node_modules/imurmurhash": { 1786 | "version": "0.1.4", 1787 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 1788 | "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", 1789 | "dev": true, 1790 | "engines": { 1791 | "node": ">=0.8.19" 1792 | } 1793 | }, 1794 | "node_modules/inflight": { 1795 | "version": "1.0.6", 1796 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 1797 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", 1798 | "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", 1799 | "dev": true, 1800 | "dependencies": { 1801 | "once": "^1.3.0", 1802 | "wrappy": "1" 1803 | } 1804 | }, 1805 | "node_modules/inherits": { 1806 | "version": "2.0.4", 1807 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 1808 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 1809 | }, 1810 | "node_modules/ini": { 1811 | "version": "1.3.8", 1812 | "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", 1813 | "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", 1814 | "dev": true 1815 | }, 1816 | "node_modules/ipaddr.js": { 1817 | "version": "1.9.1", 1818 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 1819 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", 1820 | "engines": { 1821 | "node": ">= 0.10" 1822 | } 1823 | }, 1824 | "node_modules/is-binary-path": { 1825 | "version": "2.1.0", 1826 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 1827 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 1828 | "dev": true, 1829 | "dependencies": { 1830 | "binary-extensions": "^2.0.0" 1831 | }, 1832 | "engines": { 1833 | "node": ">=8" 1834 | } 1835 | }, 1836 | "node_modules/is-extglob": { 1837 | "version": "2.1.1", 1838 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 1839 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 1840 | "dev": true, 1841 | "engines": { 1842 | "node": ">=0.10.0" 1843 | } 1844 | }, 1845 | "node_modules/is-fullwidth-code-point": { 1846 | "version": "3.0.0", 1847 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 1848 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 1849 | "dev": true, 1850 | "engines": { 1851 | "node": ">=8" 1852 | } 1853 | }, 1854 | "node_modules/is-glob": { 1855 | "version": "4.0.3", 1856 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 1857 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 1858 | "dev": true, 1859 | "dependencies": { 1860 | "is-extglob": "^2.1.1" 1861 | }, 1862 | "engines": { 1863 | "node": ">=0.10.0" 1864 | } 1865 | }, 1866 | "node_modules/is-number": { 1867 | "version": "7.0.0", 1868 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 1869 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 1870 | "dev": true, 1871 | "engines": { 1872 | "node": ">=0.12.0" 1873 | } 1874 | }, 1875 | "node_modules/is-plain-obj": { 1876 | "version": "2.1.0", 1877 | "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", 1878 | "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", 1879 | "dev": true, 1880 | "engines": { 1881 | "node": ">=8" 1882 | } 1883 | }, 1884 | "node_modules/is-unicode-supported": { 1885 | "version": "0.1.0", 1886 | "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", 1887 | "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", 1888 | "dev": true, 1889 | "engines": { 1890 | "node": ">=10" 1891 | }, 1892 | "funding": { 1893 | "url": "https://github.com/sponsors/sindresorhus" 1894 | } 1895 | }, 1896 | "node_modules/isexe": { 1897 | "version": "2.0.0", 1898 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 1899 | "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", 1900 | "dev": true 1901 | }, 1902 | "node_modules/js-yaml": { 1903 | "version": "4.1.0", 1904 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", 1905 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", 1906 | "dev": true, 1907 | "dependencies": { 1908 | "argparse": "^2.0.1" 1909 | }, 1910 | "bin": { 1911 | "js-yaml": "bin/js-yaml.js" 1912 | } 1913 | }, 1914 | "node_modules/json-buffer": { 1915 | "version": "3.0.1", 1916 | "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", 1917 | "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", 1918 | "dev": true 1919 | }, 1920 | "node_modules/json-schema-traverse": { 1921 | "version": "0.4.1", 1922 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 1923 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", 1924 | "dev": true 1925 | }, 1926 | "node_modules/json-stable-stringify-without-jsonify": { 1927 | "version": "1.0.1", 1928 | "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", 1929 | "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", 1930 | "dev": true 1931 | }, 1932 | "node_modules/keyv": { 1933 | "version": "4.5.4", 1934 | "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", 1935 | "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", 1936 | "dev": true, 1937 | "dependencies": { 1938 | "json-buffer": "3.0.1" 1939 | } 1940 | }, 1941 | "node_modules/levn": { 1942 | "version": "0.4.1", 1943 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", 1944 | "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", 1945 | "dev": true, 1946 | "dependencies": { 1947 | "prelude-ls": "^1.2.1", 1948 | "type-check": "~0.4.0" 1949 | }, 1950 | "engines": { 1951 | "node": ">= 0.8.0" 1952 | } 1953 | }, 1954 | "node_modules/locate-path": { 1955 | "version": "6.0.0", 1956 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", 1957 | "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", 1958 | "dev": true, 1959 | "dependencies": { 1960 | "p-locate": "^5.0.0" 1961 | }, 1962 | "engines": { 1963 | "node": ">=10" 1964 | }, 1965 | "funding": { 1966 | "url": "https://github.com/sponsors/sindresorhus" 1967 | } 1968 | }, 1969 | "node_modules/lodash.merge": { 1970 | "version": "4.6.2", 1971 | "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", 1972 | "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", 1973 | "dev": true 1974 | }, 1975 | "node_modules/log-symbols": { 1976 | "version": "4.1.0", 1977 | "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", 1978 | "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", 1979 | "dev": true, 1980 | "dependencies": { 1981 | "chalk": "^4.1.0", 1982 | "is-unicode-supported": "^0.1.0" 1983 | }, 1984 | "engines": { 1985 | "node": ">=10" 1986 | }, 1987 | "funding": { 1988 | "url": "https://github.com/sponsors/sindresorhus" 1989 | } 1990 | }, 1991 | "node_modules/loupe": { 1992 | "version": "2.3.7", 1993 | "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", 1994 | "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", 1995 | "dev": true, 1996 | "dependencies": { 1997 | "get-func-name": "^2.0.1" 1998 | } 1999 | }, 2000 | "node_modules/media-typer": { 2001 | "version": "0.3.0", 2002 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 2003 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", 2004 | "engines": { 2005 | "node": ">= 0.6" 2006 | } 2007 | }, 2008 | "node_modules/merge-descriptors": { 2009 | "version": "1.0.3", 2010 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", 2011 | "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", 2012 | "funding": { 2013 | "url": "https://github.com/sponsors/sindresorhus" 2014 | } 2015 | }, 2016 | "node_modules/methods": { 2017 | "version": "1.1.2", 2018 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 2019 | "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", 2020 | "engines": { 2021 | "node": ">= 0.6" 2022 | } 2023 | }, 2024 | "node_modules/mime": { 2025 | "version": "1.6.0", 2026 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 2027 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", 2028 | "bin": { 2029 | "mime": "cli.js" 2030 | }, 2031 | "engines": { 2032 | "node": ">=4" 2033 | } 2034 | }, 2035 | "node_modules/mime-db": { 2036 | "version": "1.52.0", 2037 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 2038 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 2039 | "engines": { 2040 | "node": ">= 0.6" 2041 | } 2042 | }, 2043 | "node_modules/mime-types": { 2044 | "version": "2.1.35", 2045 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 2046 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 2047 | "dependencies": { 2048 | "mime-db": "1.52.0" 2049 | }, 2050 | "engines": { 2051 | "node": ">= 0.6" 2052 | } 2053 | }, 2054 | "node_modules/mimic-response": { 2055 | "version": "3.1.0", 2056 | "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", 2057 | "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", 2058 | "dev": true, 2059 | "engines": { 2060 | "node": ">=10" 2061 | }, 2062 | "funding": { 2063 | "url": "https://github.com/sponsors/sindresorhus" 2064 | } 2065 | }, 2066 | "node_modules/minimatch": { 2067 | "version": "3.1.2", 2068 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 2069 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 2070 | "dev": true, 2071 | "dependencies": { 2072 | "brace-expansion": "^1.1.7" 2073 | }, 2074 | "engines": { 2075 | "node": "*" 2076 | } 2077 | }, 2078 | "node_modules/minimist": { 2079 | "version": "1.2.8", 2080 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", 2081 | "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", 2082 | "dev": true, 2083 | "funding": { 2084 | "url": "https://github.com/sponsors/ljharb" 2085 | } 2086 | }, 2087 | "node_modules/mkdirp-classic": { 2088 | "version": "0.5.3", 2089 | "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", 2090 | "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", 2091 | "dev": true 2092 | }, 2093 | "node_modules/mocha": { 2094 | "version": "10.8.2", 2095 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz", 2096 | "integrity": "sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==", 2097 | "dev": true, 2098 | "dependencies": { 2099 | "ansi-colors": "^4.1.3", 2100 | "browser-stdout": "^1.3.1", 2101 | "chokidar": "^3.5.3", 2102 | "debug": "^4.3.5", 2103 | "diff": "^5.2.0", 2104 | "escape-string-regexp": "^4.0.0", 2105 | "find-up": "^5.0.0", 2106 | "glob": "^8.1.0", 2107 | "he": "^1.2.0", 2108 | "js-yaml": "^4.1.0", 2109 | "log-symbols": "^4.1.0", 2110 | "minimatch": "^5.1.6", 2111 | "ms": "^2.1.3", 2112 | "serialize-javascript": "^6.0.2", 2113 | "strip-json-comments": "^3.1.1", 2114 | "supports-color": "^8.1.1", 2115 | "workerpool": "^6.5.1", 2116 | "yargs": "^16.2.0", 2117 | "yargs-parser": "^20.2.9", 2118 | "yargs-unparser": "^2.0.0" 2119 | }, 2120 | "bin": { 2121 | "_mocha": "bin/_mocha", 2122 | "mocha": "bin/mocha.js" 2123 | }, 2124 | "engines": { 2125 | "node": ">= 14.0.0" 2126 | } 2127 | }, 2128 | "node_modules/mocha/node_modules/brace-expansion": { 2129 | "version": "2.0.1", 2130 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", 2131 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", 2132 | "dev": true, 2133 | "dependencies": { 2134 | "balanced-match": "^1.0.0" 2135 | } 2136 | }, 2137 | "node_modules/mocha/node_modules/minimatch": { 2138 | "version": "5.1.6", 2139 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", 2140 | "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", 2141 | "dev": true, 2142 | "dependencies": { 2143 | "brace-expansion": "^2.0.1" 2144 | }, 2145 | "engines": { 2146 | "node": ">=10" 2147 | } 2148 | }, 2149 | "node_modules/mocha/node_modules/supports-color": { 2150 | "version": "8.1.1", 2151 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", 2152 | "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", 2153 | "dev": true, 2154 | "dependencies": { 2155 | "has-flag": "^4.0.0" 2156 | }, 2157 | "engines": { 2158 | "node": ">=10" 2159 | }, 2160 | "funding": { 2161 | "url": "https://github.com/chalk/supports-color?sponsor=1" 2162 | } 2163 | }, 2164 | "node_modules/ms": { 2165 | "version": "2.1.3", 2166 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 2167 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 2168 | }, 2169 | "node_modules/napi-build-utils": { 2170 | "version": "1.0.2", 2171 | "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", 2172 | "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", 2173 | "dev": true 2174 | }, 2175 | "node_modules/natural-compare": { 2176 | "version": "1.4.0", 2177 | "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", 2178 | "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", 2179 | "dev": true 2180 | }, 2181 | "node_modules/negotiator": { 2182 | "version": "0.6.3", 2183 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", 2184 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", 2185 | "engines": { 2186 | "node": ">= 0.6" 2187 | } 2188 | }, 2189 | "node_modules/node-abi": { 2190 | "version": "3.71.0", 2191 | "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.71.0.tgz", 2192 | "integrity": "sha512-SZ40vRiy/+wRTf21hxkkEjPJZpARzUMVcJoQse2EF8qkUWbbO2z7vd5oA/H6bVH6SZQ5STGcu0KRDS7biNRfxw==", 2193 | "dev": true, 2194 | "dependencies": { 2195 | "semver": "^7.3.5" 2196 | }, 2197 | "engines": { 2198 | "node": ">=10" 2199 | } 2200 | }, 2201 | "node_modules/normalize-path": { 2202 | "version": "3.0.0", 2203 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 2204 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 2205 | "dev": true, 2206 | "engines": { 2207 | "node": ">=0.10.0" 2208 | } 2209 | }, 2210 | "node_modules/object-inspect": { 2211 | "version": "1.13.3", 2212 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", 2213 | "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", 2214 | "engines": { 2215 | "node": ">= 0.4" 2216 | }, 2217 | "funding": { 2218 | "url": "https://github.com/sponsors/ljharb" 2219 | } 2220 | }, 2221 | "node_modules/on-finished": { 2222 | "version": "2.4.1", 2223 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", 2224 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", 2225 | "dependencies": { 2226 | "ee-first": "1.1.1" 2227 | }, 2228 | "engines": { 2229 | "node": ">= 0.8" 2230 | } 2231 | }, 2232 | "node_modules/once": { 2233 | "version": "1.4.0", 2234 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 2235 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 2236 | "dev": true, 2237 | "dependencies": { 2238 | "wrappy": "1" 2239 | } 2240 | }, 2241 | "node_modules/optionator": { 2242 | "version": "0.9.4", 2243 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", 2244 | "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", 2245 | "dev": true, 2246 | "dependencies": { 2247 | "deep-is": "^0.1.3", 2248 | "fast-levenshtein": "^2.0.6", 2249 | "levn": "^0.4.1", 2250 | "prelude-ls": "^1.2.1", 2251 | "type-check": "^0.4.0", 2252 | "word-wrap": "^1.2.5" 2253 | }, 2254 | "engines": { 2255 | "node": ">= 0.8.0" 2256 | } 2257 | }, 2258 | "node_modules/p-limit": { 2259 | "version": "3.1.0", 2260 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", 2261 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", 2262 | "dev": true, 2263 | "dependencies": { 2264 | "yocto-queue": "^0.1.0" 2265 | }, 2266 | "engines": { 2267 | "node": ">=10" 2268 | }, 2269 | "funding": { 2270 | "url": "https://github.com/sponsors/sindresorhus" 2271 | } 2272 | }, 2273 | "node_modules/p-locate": { 2274 | "version": "5.0.0", 2275 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", 2276 | "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", 2277 | "dev": true, 2278 | "dependencies": { 2279 | "p-limit": "^3.0.2" 2280 | }, 2281 | "engines": { 2282 | "node": ">=10" 2283 | }, 2284 | "funding": { 2285 | "url": "https://github.com/sponsors/sindresorhus" 2286 | } 2287 | }, 2288 | "node_modules/parent-module": { 2289 | "version": "1.0.1", 2290 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", 2291 | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", 2292 | "dev": true, 2293 | "dependencies": { 2294 | "callsites": "^3.0.0" 2295 | }, 2296 | "engines": { 2297 | "node": ">=6" 2298 | } 2299 | }, 2300 | "node_modules/parseurl": { 2301 | "version": "1.3.3", 2302 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 2303 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", 2304 | "engines": { 2305 | "node": ">= 0.8" 2306 | } 2307 | }, 2308 | "node_modules/path-exists": { 2309 | "version": "4.0.0", 2310 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 2311 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", 2312 | "dev": true, 2313 | "engines": { 2314 | "node": ">=8" 2315 | } 2316 | }, 2317 | "node_modules/path-key": { 2318 | "version": "3.1.1", 2319 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 2320 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", 2321 | "dev": true, 2322 | "engines": { 2323 | "node": ">=8" 2324 | } 2325 | }, 2326 | "node_modules/path-to-regexp": { 2327 | "version": "0.1.12", 2328 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", 2329 | "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", 2330 | "license": "MIT" 2331 | }, 2332 | "node_modules/pathval": { 2333 | "version": "1.1.1", 2334 | "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", 2335 | "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", 2336 | "dev": true, 2337 | "engines": { 2338 | "node": "*" 2339 | } 2340 | }, 2341 | "node_modules/picomatch": { 2342 | "version": "2.3.1", 2343 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 2344 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 2345 | "dev": true, 2346 | "engines": { 2347 | "node": ">=8.6" 2348 | }, 2349 | "funding": { 2350 | "url": "https://github.com/sponsors/jonschlinkert" 2351 | } 2352 | }, 2353 | "node_modules/prebuild-install": { 2354 | "version": "7.1.2", 2355 | "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.2.tgz", 2356 | "integrity": "sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==", 2357 | "dev": true, 2358 | "dependencies": { 2359 | "detect-libc": "^2.0.0", 2360 | "expand-template": "^2.0.3", 2361 | "github-from-package": "0.0.0", 2362 | "minimist": "^1.2.3", 2363 | "mkdirp-classic": "^0.5.3", 2364 | "napi-build-utils": "^1.0.1", 2365 | "node-abi": "^3.3.0", 2366 | "pump": "^3.0.0", 2367 | "rc": "^1.2.7", 2368 | "simple-get": "^4.0.0", 2369 | "tar-fs": "^2.0.0", 2370 | "tunnel-agent": "^0.6.0" 2371 | }, 2372 | "bin": { 2373 | "prebuild-install": "bin.js" 2374 | }, 2375 | "engines": { 2376 | "node": ">=10" 2377 | } 2378 | }, 2379 | "node_modules/prelude-ls": { 2380 | "version": "1.2.1", 2381 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", 2382 | "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", 2383 | "dev": true, 2384 | "engines": { 2385 | "node": ">= 0.8.0" 2386 | } 2387 | }, 2388 | "node_modules/proxy-addr": { 2389 | "version": "2.0.7", 2390 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", 2391 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", 2392 | "dependencies": { 2393 | "forwarded": "0.2.0", 2394 | "ipaddr.js": "1.9.1" 2395 | }, 2396 | "engines": { 2397 | "node": ">= 0.10" 2398 | } 2399 | }, 2400 | "node_modules/proxy-from-env": { 2401 | "version": "1.1.0", 2402 | "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", 2403 | "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", 2404 | "dev": true 2405 | }, 2406 | "node_modules/pump": { 2407 | "version": "3.0.2", 2408 | "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", 2409 | "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", 2410 | "dev": true, 2411 | "dependencies": { 2412 | "end-of-stream": "^1.1.0", 2413 | "once": "^1.3.1" 2414 | } 2415 | }, 2416 | "node_modules/punycode": { 2417 | "version": "2.3.1", 2418 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", 2419 | "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", 2420 | "dev": true, 2421 | "engines": { 2422 | "node": ">=6" 2423 | } 2424 | }, 2425 | "node_modules/qs": { 2426 | "version": "6.13.0", 2427 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", 2428 | "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", 2429 | "dependencies": { 2430 | "side-channel": "^1.0.6" 2431 | }, 2432 | "engines": { 2433 | "node": ">=0.6" 2434 | }, 2435 | "funding": { 2436 | "url": "https://github.com/sponsors/ljharb" 2437 | } 2438 | }, 2439 | "node_modules/randombytes": { 2440 | "version": "2.1.0", 2441 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", 2442 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", 2443 | "dev": true, 2444 | "dependencies": { 2445 | "safe-buffer": "^5.1.0" 2446 | } 2447 | }, 2448 | "node_modules/range-parser": { 2449 | "version": "1.2.1", 2450 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 2451 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", 2452 | "engines": { 2453 | "node": ">= 0.6" 2454 | } 2455 | }, 2456 | "node_modules/raw-body": { 2457 | "version": "2.5.2", 2458 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", 2459 | "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", 2460 | "dependencies": { 2461 | "bytes": "3.1.2", 2462 | "http-errors": "2.0.0", 2463 | "iconv-lite": "0.4.24", 2464 | "unpipe": "1.0.0" 2465 | }, 2466 | "engines": { 2467 | "node": ">= 0.8" 2468 | } 2469 | }, 2470 | "node_modules/rc": { 2471 | "version": "1.2.8", 2472 | "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", 2473 | "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", 2474 | "dev": true, 2475 | "dependencies": { 2476 | "deep-extend": "^0.6.0", 2477 | "ini": "~1.3.0", 2478 | "minimist": "^1.2.0", 2479 | "strip-json-comments": "~2.0.1" 2480 | }, 2481 | "bin": { 2482 | "rc": "cli.js" 2483 | } 2484 | }, 2485 | "node_modules/rc/node_modules/strip-json-comments": { 2486 | "version": "2.0.1", 2487 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 2488 | "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", 2489 | "dev": true, 2490 | "engines": { 2491 | "node": ">=0.10.0" 2492 | } 2493 | }, 2494 | "node_modules/readable-stream": { 2495 | "version": "3.6.2", 2496 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", 2497 | "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", 2498 | "dev": true, 2499 | "dependencies": { 2500 | "inherits": "^2.0.3", 2501 | "string_decoder": "^1.1.1", 2502 | "util-deprecate": "^1.0.1" 2503 | }, 2504 | "engines": { 2505 | "node": ">= 6" 2506 | } 2507 | }, 2508 | "node_modules/readdirp": { 2509 | "version": "3.6.0", 2510 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 2511 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 2512 | "dev": true, 2513 | "dependencies": { 2514 | "picomatch": "^2.2.1" 2515 | }, 2516 | "engines": { 2517 | "node": ">=8.10.0" 2518 | } 2519 | }, 2520 | "node_modules/require-directory": { 2521 | "version": "2.1.1", 2522 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 2523 | "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", 2524 | "dev": true, 2525 | "engines": { 2526 | "node": ">=0.10.0" 2527 | } 2528 | }, 2529 | "node_modules/resolve-from": { 2530 | "version": "4.0.0", 2531 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", 2532 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", 2533 | "dev": true, 2534 | "engines": { 2535 | "node": ">=4" 2536 | } 2537 | }, 2538 | "node_modules/safe-buffer": { 2539 | "version": "5.2.1", 2540 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 2541 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 2542 | "funding": [ 2543 | { 2544 | "type": "github", 2545 | "url": "https://github.com/sponsors/feross" 2546 | }, 2547 | { 2548 | "type": "patreon", 2549 | "url": "https://www.patreon.com/feross" 2550 | }, 2551 | { 2552 | "type": "consulting", 2553 | "url": "https://feross.org/support" 2554 | } 2555 | ] 2556 | }, 2557 | "node_modules/safer-buffer": { 2558 | "version": "2.1.2", 2559 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 2560 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 2561 | }, 2562 | "node_modules/semver": { 2563 | "version": "7.6.3", 2564 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", 2565 | "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", 2566 | "dev": true, 2567 | "bin": { 2568 | "semver": "bin/semver.js" 2569 | }, 2570 | "engines": { 2571 | "node": ">=10" 2572 | } 2573 | }, 2574 | "node_modules/send": { 2575 | "version": "0.19.0", 2576 | "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", 2577 | "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", 2578 | "dependencies": { 2579 | "debug": "2.6.9", 2580 | "depd": "2.0.0", 2581 | "destroy": "1.2.0", 2582 | "encodeurl": "~1.0.2", 2583 | "escape-html": "~1.0.3", 2584 | "etag": "~1.8.1", 2585 | "fresh": "0.5.2", 2586 | "http-errors": "2.0.0", 2587 | "mime": "1.6.0", 2588 | "ms": "2.1.3", 2589 | "on-finished": "2.4.1", 2590 | "range-parser": "~1.2.1", 2591 | "statuses": "2.0.1" 2592 | }, 2593 | "engines": { 2594 | "node": ">= 0.8.0" 2595 | } 2596 | }, 2597 | "node_modules/send/node_modules/debug": { 2598 | "version": "2.6.9", 2599 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 2600 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 2601 | "dependencies": { 2602 | "ms": "2.0.0" 2603 | } 2604 | }, 2605 | "node_modules/send/node_modules/debug/node_modules/ms": { 2606 | "version": "2.0.0", 2607 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 2608 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" 2609 | }, 2610 | "node_modules/send/node_modules/encodeurl": { 2611 | "version": "1.0.2", 2612 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 2613 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", 2614 | "engines": { 2615 | "node": ">= 0.8" 2616 | } 2617 | }, 2618 | "node_modules/serialize-javascript": { 2619 | "version": "6.0.2", 2620 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", 2621 | "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", 2622 | "dev": true, 2623 | "dependencies": { 2624 | "randombytes": "^2.1.0" 2625 | } 2626 | }, 2627 | "node_modules/serve-static": { 2628 | "version": "1.16.2", 2629 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", 2630 | "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", 2631 | "dependencies": { 2632 | "encodeurl": "~2.0.0", 2633 | "escape-html": "~1.0.3", 2634 | "parseurl": "~1.3.3", 2635 | "send": "0.19.0" 2636 | }, 2637 | "engines": { 2638 | "node": ">= 0.8.0" 2639 | } 2640 | }, 2641 | "node_modules/set-function-length": { 2642 | "version": "1.2.2", 2643 | "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", 2644 | "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", 2645 | "dependencies": { 2646 | "define-data-property": "^1.1.4", 2647 | "es-errors": "^1.3.0", 2648 | "function-bind": "^1.1.2", 2649 | "get-intrinsic": "^1.2.4", 2650 | "gopd": "^1.0.1", 2651 | "has-property-descriptors": "^1.0.2" 2652 | }, 2653 | "engines": { 2654 | "node": ">= 0.4" 2655 | } 2656 | }, 2657 | "node_modules/setprototypeof": { 2658 | "version": "1.2.0", 2659 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", 2660 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" 2661 | }, 2662 | "node_modules/shebang-command": { 2663 | "version": "2.0.0", 2664 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 2665 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 2666 | "dev": true, 2667 | "dependencies": { 2668 | "shebang-regex": "^3.0.0" 2669 | }, 2670 | "engines": { 2671 | "node": ">=8" 2672 | } 2673 | }, 2674 | "node_modules/shebang-regex": { 2675 | "version": "3.0.0", 2676 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", 2677 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", 2678 | "dev": true, 2679 | "engines": { 2680 | "node": ">=8" 2681 | } 2682 | }, 2683 | "node_modules/side-channel": { 2684 | "version": "1.0.6", 2685 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", 2686 | "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", 2687 | "dependencies": { 2688 | "call-bind": "^1.0.7", 2689 | "es-errors": "^1.3.0", 2690 | "get-intrinsic": "^1.2.4", 2691 | "object-inspect": "^1.13.1" 2692 | }, 2693 | "engines": { 2694 | "node": ">= 0.4" 2695 | }, 2696 | "funding": { 2697 | "url": "https://github.com/sponsors/ljharb" 2698 | } 2699 | }, 2700 | "node_modules/simple-concat": { 2701 | "version": "1.0.1", 2702 | "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", 2703 | "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", 2704 | "dev": true, 2705 | "funding": [ 2706 | { 2707 | "type": "github", 2708 | "url": "https://github.com/sponsors/feross" 2709 | }, 2710 | { 2711 | "type": "patreon", 2712 | "url": "https://www.patreon.com/feross" 2713 | }, 2714 | { 2715 | "type": "consulting", 2716 | "url": "https://feross.org/support" 2717 | } 2718 | ] 2719 | }, 2720 | "node_modules/simple-get": { 2721 | "version": "4.0.1", 2722 | "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", 2723 | "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", 2724 | "dev": true, 2725 | "funding": [ 2726 | { 2727 | "type": "github", 2728 | "url": "https://github.com/sponsors/feross" 2729 | }, 2730 | { 2731 | "type": "patreon", 2732 | "url": "https://www.patreon.com/feross" 2733 | }, 2734 | { 2735 | "type": "consulting", 2736 | "url": "https://feross.org/support" 2737 | } 2738 | ], 2739 | "dependencies": { 2740 | "decompress-response": "^6.0.0", 2741 | "once": "^1.3.1", 2742 | "simple-concat": "^1.0.0" 2743 | } 2744 | }, 2745 | "node_modules/statuses": { 2746 | "version": "2.0.1", 2747 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", 2748 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", 2749 | "engines": { 2750 | "node": ">= 0.8" 2751 | } 2752 | }, 2753 | "node_modules/string_decoder": { 2754 | "version": "1.3.0", 2755 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", 2756 | "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", 2757 | "dev": true, 2758 | "dependencies": { 2759 | "safe-buffer": "~5.2.0" 2760 | } 2761 | }, 2762 | "node_modules/string-width": { 2763 | "version": "4.2.3", 2764 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 2765 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 2766 | "dev": true, 2767 | "dependencies": { 2768 | "emoji-regex": "^8.0.0", 2769 | "is-fullwidth-code-point": "^3.0.0", 2770 | "strip-ansi": "^6.0.1" 2771 | }, 2772 | "engines": { 2773 | "node": ">=8" 2774 | } 2775 | }, 2776 | "node_modules/strip-ansi": { 2777 | "version": "6.0.1", 2778 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 2779 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 2780 | "dev": true, 2781 | "dependencies": { 2782 | "ansi-regex": "^5.0.1" 2783 | }, 2784 | "engines": { 2785 | "node": ">=8" 2786 | } 2787 | }, 2788 | "node_modules/strip-json-comments": { 2789 | "version": "3.1.1", 2790 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", 2791 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", 2792 | "dev": true, 2793 | "engines": { 2794 | "node": ">=8" 2795 | }, 2796 | "funding": { 2797 | "url": "https://github.com/sponsors/sindresorhus" 2798 | } 2799 | }, 2800 | "node_modules/supports-color": { 2801 | "version": "7.2.0", 2802 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 2803 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 2804 | "dev": true, 2805 | "dependencies": { 2806 | "has-flag": "^4.0.0" 2807 | }, 2808 | "engines": { 2809 | "node": ">=8" 2810 | } 2811 | }, 2812 | "node_modules/tar-fs": { 2813 | "version": "2.1.2", 2814 | "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.2.tgz", 2815 | "integrity": "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==", 2816 | "dev": true, 2817 | "license": "MIT", 2818 | "dependencies": { 2819 | "chownr": "^1.1.1", 2820 | "mkdirp-classic": "^0.5.2", 2821 | "pump": "^3.0.0", 2822 | "tar-stream": "^2.1.4" 2823 | } 2824 | }, 2825 | "node_modules/tar-stream": { 2826 | "version": "2.2.0", 2827 | "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", 2828 | "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", 2829 | "dev": true, 2830 | "dependencies": { 2831 | "bl": "^4.0.3", 2832 | "end-of-stream": "^1.4.1", 2833 | "fs-constants": "^1.0.0", 2834 | "inherits": "^2.0.3", 2835 | "readable-stream": "^3.1.1" 2836 | }, 2837 | "engines": { 2838 | "node": ">=6" 2839 | } 2840 | }, 2841 | "node_modules/to-regex-range": { 2842 | "version": "5.0.1", 2843 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 2844 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 2845 | "dev": true, 2846 | "dependencies": { 2847 | "is-number": "^7.0.0" 2848 | }, 2849 | "engines": { 2850 | "node": ">=8.0" 2851 | } 2852 | }, 2853 | "node_modules/toidentifier": { 2854 | "version": "1.0.1", 2855 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", 2856 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", 2857 | "engines": { 2858 | "node": ">=0.6" 2859 | } 2860 | }, 2861 | "node_modules/tunnel-agent": { 2862 | "version": "0.6.0", 2863 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", 2864 | "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", 2865 | "dev": true, 2866 | "dependencies": { 2867 | "safe-buffer": "^5.0.1" 2868 | }, 2869 | "engines": { 2870 | "node": "*" 2871 | } 2872 | }, 2873 | "node_modules/type-check": { 2874 | "version": "0.4.0", 2875 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", 2876 | "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", 2877 | "dev": true, 2878 | "dependencies": { 2879 | "prelude-ls": "^1.2.1" 2880 | }, 2881 | "engines": { 2882 | "node": ">= 0.8.0" 2883 | } 2884 | }, 2885 | "node_modules/type-detect": { 2886 | "version": "4.1.0", 2887 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", 2888 | "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", 2889 | "dev": true, 2890 | "engines": { 2891 | "node": ">=4" 2892 | } 2893 | }, 2894 | "node_modules/type-is": { 2895 | "version": "1.6.18", 2896 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 2897 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 2898 | "dependencies": { 2899 | "media-typer": "0.3.0", 2900 | "mime-types": "~2.1.24" 2901 | }, 2902 | "engines": { 2903 | "node": ">= 0.6" 2904 | } 2905 | }, 2906 | "node_modules/unpipe": { 2907 | "version": "1.0.0", 2908 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 2909 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", 2910 | "engines": { 2911 | "node": ">= 0.8" 2912 | } 2913 | }, 2914 | "node_modules/uri-js": { 2915 | "version": "4.4.1", 2916 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", 2917 | "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", 2918 | "dev": true, 2919 | "dependencies": { 2920 | "punycode": "^2.1.0" 2921 | } 2922 | }, 2923 | "node_modules/util-deprecate": { 2924 | "version": "1.0.2", 2925 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 2926 | "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", 2927 | "dev": true 2928 | }, 2929 | "node_modules/utils-merge": { 2930 | "version": "1.0.1", 2931 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 2932 | "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", 2933 | "engines": { 2934 | "node": ">= 0.4.0" 2935 | } 2936 | }, 2937 | "node_modules/vary": { 2938 | "version": "1.1.2", 2939 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 2940 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", 2941 | "engines": { 2942 | "node": ">= 0.8" 2943 | } 2944 | }, 2945 | "node_modules/which": { 2946 | "version": "2.0.2", 2947 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 2948 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 2949 | "dev": true, 2950 | "dependencies": { 2951 | "isexe": "^2.0.0" 2952 | }, 2953 | "bin": { 2954 | "node-which": "bin/node-which" 2955 | }, 2956 | "engines": { 2957 | "node": ">= 8" 2958 | } 2959 | }, 2960 | "node_modules/word-wrap": { 2961 | "version": "1.2.5", 2962 | "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", 2963 | "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", 2964 | "dev": true, 2965 | "engines": { 2966 | "node": ">=0.10.0" 2967 | } 2968 | }, 2969 | "node_modules/workerpool": { 2970 | "version": "6.5.1", 2971 | "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", 2972 | "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", 2973 | "dev": true 2974 | }, 2975 | "node_modules/wrap-ansi": { 2976 | "version": "7.0.0", 2977 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 2978 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 2979 | "dev": true, 2980 | "dependencies": { 2981 | "ansi-styles": "^4.0.0", 2982 | "string-width": "^4.1.0", 2983 | "strip-ansi": "^6.0.0" 2984 | }, 2985 | "engines": { 2986 | "node": ">=10" 2987 | }, 2988 | "funding": { 2989 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 2990 | } 2991 | }, 2992 | "node_modules/wrappy": { 2993 | "version": "1.0.2", 2994 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 2995 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", 2996 | "dev": true 2997 | }, 2998 | "node_modules/xmlbuilder": { 2999 | "version": "15.1.1", 3000 | "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", 3001 | "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", 3002 | "engines": { 3003 | "node": ">=8.0" 3004 | } 3005 | }, 3006 | "node_modules/y18n": { 3007 | "version": "5.0.8", 3008 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", 3009 | "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", 3010 | "dev": true, 3011 | "engines": { 3012 | "node": ">=10" 3013 | } 3014 | }, 3015 | "node_modules/yaml": { 3016 | "version": "2.6.0", 3017 | "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.0.tgz", 3018 | "integrity": "sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==", 3019 | "bin": { 3020 | "yaml": "bin.mjs" 3021 | }, 3022 | "engines": { 3023 | "node": ">= 14" 3024 | } 3025 | }, 3026 | "node_modules/yargs": { 3027 | "version": "16.2.0", 3028 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", 3029 | "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", 3030 | "dev": true, 3031 | "dependencies": { 3032 | "cliui": "^7.0.2", 3033 | "escalade": "^3.1.1", 3034 | "get-caller-file": "^2.0.5", 3035 | "require-directory": "^2.1.1", 3036 | "string-width": "^4.2.0", 3037 | "y18n": "^5.0.5", 3038 | "yargs-parser": "^20.2.2" 3039 | }, 3040 | "engines": { 3041 | "node": ">=10" 3042 | } 3043 | }, 3044 | "node_modules/yargs-parser": { 3045 | "version": "20.2.9", 3046 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", 3047 | "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", 3048 | "dev": true, 3049 | "engines": { 3050 | "node": ">=10" 3051 | } 3052 | }, 3053 | "node_modules/yargs-unparser": { 3054 | "version": "2.0.0", 3055 | "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", 3056 | "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", 3057 | "dev": true, 3058 | "dependencies": { 3059 | "camelcase": "^6.0.0", 3060 | "decamelize": "^4.0.0", 3061 | "flat": "^5.0.2", 3062 | "is-plain-obj": "^2.1.0" 3063 | }, 3064 | "engines": { 3065 | "node": ">=10" 3066 | } 3067 | }, 3068 | "node_modules/yocto-queue": { 3069 | "version": "0.1.0", 3070 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", 3071 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", 3072 | "dev": true, 3073 | "engines": { 3074 | "node": ">=10" 3075 | }, 3076 | "funding": { 3077 | "url": "https://github.com/sponsors/sindresorhus" 3078 | } 3079 | } 3080 | } 3081 | } 3082 | -------------------------------------------------------------------------------- /tests/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "capval-showcase", 3 | "version": "1.0.0", 4 | "description": "A simple CAP project.", 5 | "repository": "", 6 | "license": "UNLICENSED", 7 | "private": true, 8 | "dependencies": { 9 | "@sap/cds": "^8.0.3", 10 | "capval": "file:..", 11 | "express": "^4" 12 | }, 13 | "devDependencies": { 14 | "@cap-js/sqlite": "^1", 15 | "@sap/eslint-plugin-cds": "^3", 16 | "axios": "^1.8.2", 17 | "chai": "^4.4.1", 18 | "chai-as-promised": "^7.1.2", 19 | "chai-subset": "^1.6.0", 20 | "eslint": "^9", 21 | "mocha": "^10.8.2" 22 | }, 23 | "scripts": { 24 | "start": "cds-serve", 25 | "test": "mocha" 26 | }, 27 | "sapux": [ 28 | "app/project1" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /tests/srv/cat-fiori-service.cds: -------------------------------------------------------------------------------- 1 | using my.bookshop as my from '../db/data-model'; 2 | 3 | 4 | service CatalogFioriService { 5 | @odata.draft.enabled 6 | entity Books as projection on my.Books; 7 | } 8 | -------------------------------------------------------------------------------- /tests/srv/cat-service.cds: -------------------------------------------------------------------------------- 1 | using my.bookshop as my from '../db/data-model'; 2 | 3 | 4 | service CatalogService { 5 | entity Books as projection on my.Books; 6 | entity Chapters as projection on my.Chapters; 7 | } 8 | -------------------------------------------------------------------------------- /tests/srv/handlers/ConditionalCheck.js: -------------------------------------------------------------------------------- 1 | const BaseValidation = require("capval"); 2 | module.exports = class BeginDateChecks extends BaseValidation { 3 | isValid(InputValue) { 4 | let entity = this.getNode(); 5 | let stock = entity["stock"]; 6 | //Can't cancel a Book if it has stock 7 | if (InputValue === "C" && stock > 0) { 8 | this.seti18nMessage("statusCheck-Cancelled"); 9 | return false; 10 | } 11 | 12 | if (InputValue === "R" && entity["releaseDate"] !== today) { 13 | var today = new Date().toISOString().slice(0, 10); 14 | this.setCustomMessageVariables({ today: today }); 15 | this.seti18nMessage("statusCheck-Released"); 16 | return false; 17 | } 18 | 19 | return true; 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /tests/srv/handlers/DateChecks.js: -------------------------------------------------------------------------------- 1 | const BaseValidation = require("capval"); 2 | module.exports = class BeginDateChecks extends BaseValidation { 3 | isValid(InputValue) { 4 | let entity = this.getNode(); 5 | let today = new Date().toISOString().slice(0, 10); 6 | if (entity.previewDate < today) { 7 | //this.seti18nMessage("dateToday-errorMessage"); 8 | return false; 9 | } 10 | 11 | return true; 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /tests/test/BatchProcessor.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | var path = require("path"); 3 | 4 | //const { expect, GET, POST, PATCH, DELETE } = cds.test(__dirname + "/.."); 5 | const urlDraftBooks = "odata/v4/catalog-fiori/$batch"; 6 | 7 | module.exports = class BatchProcessor { 8 | constructor() {} 9 | 10 | async createBook(testPayload) { 11 | const payload = this.createBookPayload(); 12 | let draftResp = await this.postBookWithHeaders( 13 | payload.body, 14 | true, 15 | payload.header 16 | ); 17 | 18 | const book = this.createBookParseResponse(draftResp); 19 | 20 | const activatePayload = this.getActivatePayload(book.ID, testPayload); 21 | let activateResp = await this.postBookWithHeaders( 22 | activatePayload.body, 23 | true, 24 | activatePayload.header 25 | ); 26 | //console.log(activateResp.data); 27 | } 28 | getCreateBookPayload() { 29 | return this.getPayload("create"); 30 | } 31 | getEditBookPayload(bookUUID) { 32 | let payload = this.getPayload("edit"); 33 | payload.body = this.replaceAll(payload.body, "UUID_REPLACE", bookUUID); 34 | return payload; 35 | } 36 | getPatchChapterPayload(chapterUUID, data) { 37 | let payload = this.getPayload("child_patch"); 38 | payload.body = this.replaceAll( 39 | payload.body, 40 | "JSON_REPLACE", 41 | JSON.stringify(data) 42 | ); 43 | payload.body = this.replaceAll(payload.body, "UUID_REPLACE", chapterUUID); 44 | 45 | return payload; 46 | } 47 | getCreateChapterPayload(bookUUID) { 48 | let payload = this.getPayload("child_create"); 49 | payload.body = this.replaceAll(payload.body, "UUID_REPLACE", bookUUID); 50 | 51 | return payload; 52 | } 53 | 54 | createBookParseResponse(response) { 55 | return response.data.responses[0].body; 56 | } 57 | 58 | getActivatePayload(uuid, data) { 59 | let payload = this.getPayload("activate"); 60 | payload.body = this.replaceAll(payload.body, "UUID_REPLACE", uuid); 61 | payload.body = this.replaceAll( 62 | payload.body, 63 | "JSON_REPLACE", 64 | JSON.stringify(data) 65 | ); 66 | 67 | return payload; 68 | } 69 | 70 | getEditActivatePayload(uuid, data) { 71 | let payload = this.getPayload("edit_activate"); 72 | payload.body = this.replaceAll(payload.body, "UUID_REPLACE", uuid); 73 | payload.body = this.replaceAll( 74 | payload.body, 75 | "JSON_REPLACE", 76 | JSON.stringify(data) 77 | ); 78 | 79 | return payload; 80 | } 81 | 82 | getPayload(type) { 83 | let payload = { 84 | header: { 85 | headers: { 86 | "Content-Type": 87 | "multipart/mixed; boundary=batch_id-1723714275153-541", 88 | }, 89 | }, 90 | body: "", 91 | }; 92 | const file = path.join("test", "batchrequests", type + ".txt"); 93 | payload.body = fs.readFileSync(file, "utf-8"); 94 | let regex = /\r?\n/g; 95 | payload.body = payload.body.replace(regex, "\r\n"); 96 | return payload; 97 | } 98 | replaceAll(str, find, replace) { 99 | return str.replace(new RegExp(find, "g"), replace); 100 | } 101 | }; 102 | -------------------------------------------------------------------------------- /tests/test/batchrequests/activate.txt: -------------------------------------------------------------------------------- 1 | --batch_id-1723714641903-541 2 | Content-Type:application/http 3 | Content-Transfer-Encoding:binary 4 | 5 | PATCH Books(ID=UUID_REPLACE,IsActiveEntity=false) HTTP/1.1 6 | Accept:application/json;odata.metadata=minimal;IEEE754Compatible=true 7 | Accept-Language:en-US 8 | Prefer:return=minimal 9 | Content-Type:application/json;charset=UTF-8;IEEE754Compatible=true 10 | 11 | JSON_REPLACE 12 | --batch_id-1723714641903-541 13 | Content-Type:application/http 14 | Content-Transfer-Encoding:binary 15 | 16 | POST Books(ID=UUID_REPLACE,IsActiveEntity=false)/CatalogFioriService.draftPrepare HTTP/1.1 17 | Accept:application/json;odata.metadata=minimal;IEEE754Compatible=true 18 | Accept-Language:en-US 19 | Content-Type:application/json;charset=UTF-8;IEEE754Compatible=true 20 | 21 | {"SideEffectsQualifier":""} 22 | --batch_id-1723714275153-541 23 | Content-Type:application/http 24 | Content-Transfer-Encoding:binary 25 | 26 | POST Books(ID=UUID_REPLACE,IsActiveEntity=false)/CatalogFioriService.draftActivate?$select=HasActiveEntity,HasDraftEntity,ID,IsActiveEntity,description,previewDate,price,releaseDate,reorderPoint,statusCode,stock,title&$expand=DraftAdministrativeData($select=DraftIsCreatedByMe,DraftUUID,InProcessByUser) HTTP/1.1 27 | Accept:application/json;odata.metadata=minimal;IEEE754Compatible=true 28 | Accept-Language:en-US 29 | Prefer:handling=strict 30 | Content-Type:application/json;charset=UTF-8;IEEE754Compatible=true 31 | 32 | {} 33 | --batch_id-1723714275153-541-- 34 | Group ID: $auto -------------------------------------------------------------------------------- /tests/test/batchrequests/child_create.txt: -------------------------------------------------------------------------------- 1 | --batch_id-1723714275153-541 2 | Content-Type:application/http 3 | Content-Transfer-Encoding:binary 4 | 5 | POST Books(ID=UUID_REPLACE,IsActiveEntity=false)/to_Chapters HTTP/1.1 6 | Accept:application/json;odata.metadata=minimal;IEEE754Compatible=true 7 | Accept-Language:en-US 8 | Content-Type:application/json;charset=UTF-8;IEEE754Compatible=true 9 | 10 | {} 11 | --batch_id-1723714275153-541-- 12 | Group ID: $auto -------------------------------------------------------------------------------- /tests/test/batchrequests/child_patch.txt: -------------------------------------------------------------------------------- 1 | --batch_id-1723714275153-541 2 | Content-Type:application/http 3 | Content-Transfer-Encoding:binary 4 | 5 | PATCH Chapters(ID=UUID_REPLACE,IsActiveEntity=false) HTTP/1.1 6 | Accept:application/json;odata.metadata=minimal;IEEE754Compatible=true 7 | Accept-Language:en-US 8 | Prefer:return=minimal 9 | Content-Type:application/json;charset=UTF-8;IEEE754Compatible=true 10 | 11 | JSON_REPLACE 12 | --batch_id-1723714275153-541 13 | Group ID: $auto -------------------------------------------------------------------------------- /tests/test/batchrequests/create.txt: -------------------------------------------------------------------------------- 1 | --batch_id-1723714275153-541 2 | Content-Type:application/http 3 | Content-Transfer-Encoding:binary 4 | 5 | POST Books HTTP/1.1 6 | Accept:application/json;odata.metadata=minimal;IEEE754Compatible=true 7 | Accept-Language:en-US 8 | Content-Type:application/json;charset=UTF-8;IEEE754Compatible=true 9 | 10 | {} 11 | --batch_id-1723714275153-541-- 12 | Group ID: $auto -------------------------------------------------------------------------------- /tests/test/batchrequests/edit.txt: -------------------------------------------------------------------------------- 1 | --batch_id-1723724743814-316 2 | Content-Type:application/http 3 | Content-Transfer-Encoding:binary 4 | 5 | POST Books(ID=UUID_REPLACE,IsActiveEntity=true)/CatalogFioriService.draftEdit?$select=HasActiveEntity,HasDraftEntity,ID,IsActiveEntity,description,previewDate,price,releaseDate,reorderPoint,statusCode,stock,title&$expand=DraftAdministrativeData($select=DraftIsCreatedByMe,DraftUUID,InProcessByUser) HTTP/1.1 6 | Accept:application/json;odata.metadata=minimal;IEEE754Compatible=true 7 | Accept-Language:en-US 8 | Prefer:handling=strict 9 | Content-Type:application/json;charset=UTF-8;IEEE754Compatible=true 10 | 11 | {"PreserveChanges":true} 12 | --batch_id-1723724743814-316-- 13 | Group ID (API): editGroup -------------------------------------------------------------------------------- /tests/test/batchrequests/edit_activate.txt: -------------------------------------------------------------------------------- 1 | --batch_id-1723725231259-397 2 | Content-Type:application/http 3 | Content-Transfer-Encoding:binary 4 | 5 | PATCH Books(ID=UUID_REPLACE,IsActiveEntity=false) HTTP/1.1 6 | Accept:application/json;odata.metadata=minimal;IEEE754Compatible=true 7 | Accept-Language:en-US 8 | Prefer:return=minimal 9 | Content-Type:application/json;charset=UTF-8;IEEE754Compatible=true 10 | 11 | JSON_REPLACE 12 | --batch_id-1723725231259-397 13 | Content-Type:application/http 14 | Content-Transfer-Encoding:binary 15 | 16 | POST Books(ID=UUID_REPLACE,IsActiveEntity=false)/CatalogFioriService.draftPrepare HTTP/1.1 17 | Accept:application/json;odata.metadata=minimal;IEEE754Compatible=true 18 | Accept-Language:en-US 19 | Content-Type:application/json;charset=UTF-8;IEEE754Compatible=true 20 | 21 | {"SideEffectsQualifier":""} 22 | --batch_id-1723725231259-397 23 | Content-Type:application/http 24 | Content-Transfer-Encoding:binary 25 | 26 | POST Books(ID=UUID_REPLACE,IsActiveEntity=false)/CatalogFioriService.draftActivate?$select=HasActiveEntity,HasDraftEntity,ID,IsActiveEntity,description,previewDate,price,releaseDate,reorderPoint,statusCode,stock,title&$expand=DraftAdministrativeData($select=DraftIsCreatedByMe,DraftUUID,InProcessByUser) HTTP/1.1 27 | Accept:application/json;odata.metadata=minimal;IEEE754Compatible=true 28 | Accept-Language:en-US 29 | Prefer:handling=strict 30 | Content-Type:application/json;charset=UTF-8;IEEE754Compatible=true 31 | 32 | {} 33 | --batch_id-1723725231259-397-- 34 | Group ID: $auto -------------------------------------------------------------------------------- /tests/test/test.js: -------------------------------------------------------------------------------- 1 | const cds = require("@sap/cds"); 2 | const BatchProcessor = require("./BatchProcessor.js"); 3 | const { INSERT } = require("@sap/cds/lib/ql/cds-ql"); 4 | const { before } = require("@sap/cds/lib/srv/middlewares"); 5 | 6 | const urlBooks = "odata/v4/catalog/Books"; 7 | const urlDraftBooks = "odata/v4/catalog-fiori/$batch"; 8 | 9 | let yourDate = new Date(); 10 | 11 | const basePayload = { 12 | title: "201", 13 | stock: 1, 14 | releaseDate: yourDate.toISOString().split("T")[0], 15 | description: "capval 3", 16 | price: 3, 17 | statusCode: "A", 18 | reorderPoint: 6, 19 | to_Chapters: [ 20 | { 21 | title: "Introduction", 22 | }, 23 | ], 24 | }; 25 | 26 | describe("Happy Days", () => { 27 | let testPayload = {}; 28 | 29 | beforeEach(() => { 30 | testPayload = Object.assign({}, basePayload, {}); 31 | }); 32 | 33 | it("drafts", async () => { 34 | let response = await createBookBatch(testPayload); 35 | let title = response.finalPostResponses[1].body.title; 36 | expect(title).to.eql(testPayload.title); 37 | }); 38 | 39 | it("non drafts", async () => { 40 | let resp = await postBook(testPayload, false); 41 | let title = resp.data.title; 42 | expect(title).to.eql(testPayload.title); 43 | }); 44 | }); 45 | 46 | describe("Contextual Information", () => { 47 | let testPayload = {}; 48 | let errorMessage = "Reorder Point: 21 not between 0 and 20"; 49 | 50 | beforeEach(() => { 51 | testPayload = Object.assign({}, basePayload, {}); 52 | testPayload.reorderPoint = 21; 53 | }); 54 | 55 | it("drafts", async () => { 56 | let response = await createBookBatch(testPayload); 57 | 58 | expect(response.finalPostResponses[2].body.error.message).to.eql( 59 | errorMessage 60 | ); 61 | }); 62 | 63 | it("non drafts", async () => { 64 | let error = await postBook(testPayload, false); 65 | expect(error.response.data.error.message).to.eql(errorMessage); 66 | }); 67 | }); 68 | 69 | describe("Update", () => { 70 | let testPayload = {}; 71 | 72 | beforeEach(() => { 73 | testPayload = Object.assign({}, basePayload, {}); 74 | }); 75 | 76 | it("non drafts", async () => { 77 | let resp = await postBook(testPayload, false); 78 | let title = resp.data.title; 79 | expect(title).to.eql(testPayload.title); 80 | 81 | testPayload.releaseDate = null; 82 | let error = await patchBook(testPayload, resp.data.ID, false); 83 | 84 | expect(error.response.data.error.message).to.eql( 85 | "Release Date has to be to be set" 86 | ); 87 | }); 88 | 89 | it("drafts", async () => { 90 | let response = await createBookBatch(testPayload); 91 | let title = response.finalPostResponses[1].body.title; 92 | expect(title).to.eql(testPayload.title); 93 | testPayload.releaseDate = null; 94 | let editDraftResp = await editBookBatch( 95 | testPayload, 96 | response.finalPostResponses[1].body.ID 97 | ); 98 | 99 | expect(editDraftResp.finalPostResponses[2].body.error.message).to.eql( 100 | "Release Date has to be to be set" 101 | ); 102 | }); 103 | }); 104 | 105 | describe("Custom Handler", () => { 106 | let testPayload = {}; 107 | 108 | beforeEach(() => { 109 | testPayload = Object.assign({}, basePayload, {}); 110 | testPayload.previewDate = "2024-01-01"; 111 | }); 112 | 113 | it("drafts", async () => { 114 | let response = await createBookBatch(testPayload); 115 | 116 | expect(response.finalPostResponses[2].body.error.message).to.eql( 117 | "Preview Date has to after today" 118 | ); 119 | }); 120 | 121 | it("non drafts", async () => { 122 | let error = await postBook(testPayload, false); 123 | expect(error.response.data.error.message).to.eql( 124 | "Preview Date has to after today" 125 | ); 126 | }); 127 | }); 128 | 129 | describe("Mandatory Annotation", () => { 130 | let testPayload = {}; 131 | 132 | beforeEach(() => { 133 | testPayload = Object.assign({}, basePayload, {}); 134 | testPayload.releaseDate = null; 135 | }); 136 | 137 | it("drafts", async () => { 138 | let response = await createBookBatch(testPayload); 139 | expect(response.finalPostResponses[2].body.error.message).to.eql( 140 | "Release Date has to be to be set" 141 | ); 142 | }); 143 | 144 | it("non drafts", async () => { 145 | let error = await postBook(testPayload, false); 146 | expect(error.response.data.error.message).to.eql( 147 | "Release Date has to be to be set" 148 | ); 149 | }); 150 | }); 151 | 152 | describe("Assert Format Annotation", () => { 153 | let testPayload = {}; 154 | 155 | beforeEach(() => { 156 | testPayload = Object.assign({}, basePayload, {}); 157 | testPayload.description = "capval"; 158 | }); 159 | 160 | it("drafts", async () => { 161 | let response = await createBookBatch(testPayload); 162 | expect(response.finalPostResponses[2].body.error.message).to.eql( 163 | "Enter a valid description" 164 | ); 165 | }); 166 | 167 | it("non drafts", async () => { 168 | let error = await postBook(testPayload, false); 169 | expect(error.response.data.error.message).to.eql( 170 | "Enter a valid description" 171 | ); 172 | }); 173 | }); 174 | 175 | describe("Assert Range Annotation", () => { 176 | let testPayload = {}; 177 | 178 | beforeEach(() => { 179 | testPayload = Object.assign({}, basePayload, {}); 180 | testPayload.stock = 10001; 181 | }); 182 | 183 | it("drafts", async () => { 184 | let response = await createBookBatch(testPayload); 185 | expect(response.finalPostResponses[2].body.error.message).to.eql( 186 | "Stock can not be more than 10,000" 187 | ); 188 | }); 189 | 190 | it("non drafts", async () => { 191 | let error = await postBook(testPayload, false); 192 | expect(error.response.data.error.message).to.eql( 193 | "Stock can not be more than 10,000" 194 | ); 195 | }); 196 | }); 197 | 198 | describe("Localisation", () => { 199 | let testPayload = {}; 200 | 201 | beforeEach(() => { 202 | testPayload = Object.assign({}, basePayload, {}); 203 | testPayload.price = null; 204 | }); 205 | 206 | it("drafts", async () => { 207 | let response = await createBookBatch(testPayload); 208 | expect(response.finalPostResponses[2].body.error.message).to.eql( 209 | "Price must be set" 210 | ); 211 | }); 212 | 213 | it("non drafts", async () => { 214 | let error = await postBook(testPayload, false); 215 | expect(error.response.data.error.message).to.eql("Price must be set"); 216 | }); 217 | }); 218 | 219 | describe("Child Validations", () => { 220 | let testPayload = {}; 221 | 222 | beforeEach(() => { 223 | testPayload = Object.assign({}, basePayload, {}); 224 | testPayload.to_Chapters[0].title = ""; 225 | }); 226 | 227 | it("drafts", async () => { 228 | let response = await createBookBatch(testPayload); 229 | 230 | expect(response.finalPostResponses[2].body.error.message).to.eql( 231 | "Enter a valid chapter title" 232 | ); 233 | 234 | let target = `in/to_Chapters${getKey(response.chapters[0].ID)}/title`; 235 | expect(response.finalPostResponses[2].body.error.target).to.eql(target); 236 | }); 237 | 238 | it("non drafts", async () => { 239 | let error = await postBook(testPayload, false); 240 | expect(error.response.data.error.message).to.eql( 241 | "Enter a valid chapter title" 242 | ); 243 | expect(error.response.data.error.target).to.eql("to_Chapters[0]/title"); 244 | }); 245 | }); 246 | 247 | describe("Multiple Errors", () => { 248 | let testPayload = {}; 249 | 250 | beforeEach(() => { 251 | testPayload = Object.assign({}, basePayload, {}); 252 | testPayload.to_Chapters[0].title = ""; 253 | testPayload.description = "capval"; 254 | testPayload.price = null; 255 | }); 256 | 257 | it("drafts", async () => { 258 | let response = await createBookBatch(testPayload); 259 | expect(response.finalPostResponses[2].body.error.details[1].message).to.eql( 260 | "Price must be set" 261 | ); 262 | 263 | expect(response.finalPostResponses[2].body.error.details[1].target).to.eql( 264 | "in/price" 265 | ); 266 | 267 | expect(response.finalPostResponses[2].body.error.details[0].message).to.eql( 268 | "Enter a valid description" 269 | ); 270 | expect(response.finalPostResponses[2].body.error.details[0].target).to.eql( 271 | "in/description" 272 | ); 273 | expect(response.finalPostResponses[2].body.error.details[2].message).to.eql( 274 | "Enter a valid chapter title" 275 | ); 276 | 277 | let target = `in/to_Chapters${getKey(response.chapters[0].ID)}/title`; 278 | 279 | expect(response.finalPostResponses[2].body.error.details[2].target).to.eql( 280 | target 281 | ); 282 | }); 283 | 284 | it("non drafts", async () => { 285 | let error = await postBook(testPayload, false); 286 | 287 | expect(error.response.data.error.details[1].message).to.eql( 288 | "Price must be set" 289 | ); 290 | expect(error.response.data.error.details[1].target).to.eql("price"); 291 | expect(error.response.data.error.details[0].message).to.eql( 292 | "Enter a valid description" 293 | ); 294 | expect(error.response.data.error.details[0].target).to.eql("description"); 295 | expect(error.response.data.error.details[2].message).to.eql( 296 | "Enter a valid chapter title" 297 | ); 298 | expect(error.response.data.error.details[2].target).to.eql( 299 | "to_Chapters[0]/title" 300 | ); 301 | }); 302 | }); 303 | 304 | describe("Conditional", () => { 305 | let testPayload = {}; 306 | 307 | beforeEach(() => { 308 | testPayload = Object.assign({}, basePayload, {}); 309 | testPayload.price = 23; 310 | testPayload.statusCode = "C"; 311 | testPayload.to_Chapters[0].title = "DEs"; 312 | }); 313 | 314 | it("drafts", async () => { 315 | let response = await createBookBatch(testPayload); 316 | 317 | expect(response.finalPostResponses[2].body.error.message).to.eql( 318 | "Please use remaining stock before cancelling" 319 | ); 320 | }); 321 | 322 | it("non drafts", async () => { 323 | let error = await postBook(testPayload, false); 324 | expect(error.response.data.error.message).to.eql( 325 | "Please use remaining stock before cancelling" 326 | ); 327 | }); 328 | }); 329 | 330 | describe("Custom Data", () => { 331 | let testPayload = {}; 332 | let message = ""; 333 | beforeEach(() => { 334 | testPayload = Object.assign({}, basePayload, {}); 335 | testPayload.releaseDate = "2024-01-01"; 336 | testPayload.statusCode = "R"; 337 | 338 | message = `Release Date must be today: ${ 339 | yourDate.toISOString().split("T")[0] 340 | }`; 341 | }); 342 | 343 | it("drafts", async () => { 344 | let response = await createBookBatch(testPayload); 345 | 346 | expect(response.finalPostResponses[2].body.error.message).to.eql(message); 347 | }); 348 | 349 | it("non drafts", async () => { 350 | let error = await postBook(testPayload, false); 351 | expect(error.response.data.error.message).to.eql(message); 352 | }); 353 | }); 354 | 355 | function getKey(id, active = false) { 356 | return `(ID=${id},IsActiveEntity=${active})`; 357 | } 358 | function getKeyNonDraft(id) { 359 | return `(ID=${id})`; 360 | } 361 | 362 | const { expect, GET, POST, PATCH, DELETE } = cds.test(__dirname + "/.."); 363 | 364 | async function postBook(payload, draft) { 365 | let url = draft ? urlDraftBooks : urlBooks; 366 | let data; 367 | try { 368 | data = await POST(url, payload); 369 | } catch (e) { 370 | return e; 371 | } 372 | 373 | return data; 374 | } 375 | 376 | async function postWithHeaders(payload, draft, header) { 377 | let url = draft ? urlDraftBooks : urlBooks; 378 | let data; 379 | try { 380 | data = await POST(url, payload, header); 381 | } catch (e) { 382 | return e; 383 | } 384 | 385 | return data; 386 | } 387 | 388 | async function patchBook(payload, id, draft) { 389 | let url = draft ? urlDraftBooks : urlBooks; 390 | let key = draft ? getKey(id, false) : getKeyNonDraft(id); 391 | url = url + key; 392 | 393 | let data; 394 | try { 395 | data = await PATCH(url, payload); 396 | } catch (e) { 397 | return e; 398 | } 399 | 400 | return data; 401 | } 402 | 403 | async function editBookBatch(testPayload, bookUUID) { 404 | let responseStack = { 405 | final: {}, 406 | chapters: [], 407 | }; 408 | 409 | delete testPayload["to_Chapters"]; 410 | 411 | const batchProcessor = new BatchProcessor(); 412 | let payload = batchProcessor.getEditBookPayload(bookUUID); 413 | let draftResp = await postWithHeaders(payload.body, true, payload.header); 414 | 415 | const respEdit = batchProcessor.createBookParseResponse(draftResp); 416 | 417 | const activatePayload = batchProcessor.getEditActivatePayload( 418 | respEdit.ID, 419 | testPayload 420 | ); 421 | let activateResp = await postWithHeaders( 422 | activatePayload.body, 423 | true, 424 | activatePayload.header 425 | ); 426 | responseStack.finalPostResponses = activateResp.data.responses; 427 | return responseStack; 428 | } 429 | async function createBookBatch(testPayload) { 430 | let responseStack = { 431 | final: {}, 432 | chapters: [], 433 | }; 434 | let chapters = testPayload["to_Chapters"]; 435 | delete testPayload["to_Chapters"]; 436 | 437 | const batchProcessor = new BatchProcessor(); 438 | let payload = batchProcessor.getCreateBookPayload(testPayload); 439 | let draftResp = await postWithHeaders(payload.body, true, payload.header); 440 | const respCreate = batchProcessor.createBookParseResponse(draftResp); 441 | 442 | for (let chapter of chapters) { 443 | let childPayload = batchProcessor.getCreateChapterPayload(respCreate.ID); 444 | let draftChildResp = await postWithHeaders( 445 | childPayload.body, 446 | true, 447 | childPayload.header 448 | ); 449 | const respChildCreate = 450 | batchProcessor.createBookParseResponse(draftChildResp); 451 | 452 | responseStack.chapters.push(respChildCreate); 453 | 454 | const childPatchPayload = batchProcessor.getPatchChapterPayload( 455 | respChildCreate.ID, 456 | chapter 457 | ); 458 | const respChild = await postWithHeaders( 459 | childPatchPayload.body, 460 | true, 461 | childPatchPayload.header 462 | ); 463 | } 464 | const activatePayload = batchProcessor.getActivatePayload( 465 | respCreate.ID, 466 | testPayload 467 | ); 468 | let activateResp = await postWithHeaders( 469 | activatePayload.body, 470 | true, 471 | activatePayload.header 472 | ); 473 | responseStack.finalPostResponses = activateResp.data.responses; 474 | return responseStack; 475 | } 476 | --------------------------------------------------------------------------------