From 02699e64ed8ca0e02184133cd232e4893f225da7 Mon Sep 17 00:00:00 2001 From: Zhiyuan Liang Date: Wed, 30 Oct 2024 15:59:15 +0800 Subject: [PATCH 01/14] add basic feature flag test --- libraryValidations/JavaScript/README.md | 0 .../JavaScript/out/validation.test.js | 57 + .../JavaScript/out/validation.test.js.map | 1 + .../JavaScript/package-lock.json | 2393 +++++++++++++++++ libraryValidations/JavaScript/package.json | 22 + libraryValidations/JavaScript/tsconfig.json | 22 + .../JavaScript/validation.test.ts | 86 + 7 files changed, 2581 insertions(+) create mode 100644 libraryValidations/JavaScript/README.md create mode 100644 libraryValidations/JavaScript/out/validation.test.js create mode 100644 libraryValidations/JavaScript/out/validation.test.js.map create mode 100644 libraryValidations/JavaScript/package-lock.json create mode 100644 libraryValidations/JavaScript/package.json create mode 100644 libraryValidations/JavaScript/tsconfig.json create mode 100644 libraryValidations/JavaScript/validation.test.ts diff --git a/libraryValidations/JavaScript/README.md b/libraryValidations/JavaScript/README.md new file mode 100644 index 0000000..e69de29 diff --git a/libraryValidations/JavaScript/out/validation.test.js b/libraryValidations/JavaScript/out/validation.test.js new file mode 100644 index 0000000..653170b --- /dev/null +++ b/libraryValidations/JavaScript/out/validation.test.js @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +import * as fs from "node:fs/promises"; +import * as chai from "chai"; +import chaiAsPromised from "chai-as-promised"; +chai.use(chaiAsPromised); +import { FeatureManager, ConfigurationObjectFeatureFlagProvider } from "@microsoft/feature-management"; +const expect = chai.expect; +const FILE_PATH = "../../Samples/"; +const SAMPLE_JSON_KEY = ".sample.json"; +const TESTS_JSON_KEY = ".tests.json"; +async function runTest(testName) { + const config = JSON.parse(await fs.readFile(FILE_PATH + testName + SAMPLE_JSON_KEY, "utf8")); + const testcases = JSON.parse(await fs.readFile(FILE_PATH + testName + TESTS_JSON_KEY, "utf8")); + const ffProvider = new ConfigurationObjectFeatureFlagProvider(config); + const fm = new FeatureManager(ffProvider); + for (const testcase of testcases) { + const featureFlagName = testcase.FeatureFlagName; + const context = { userId: testcase.Inputs?.user, groups: testcase.Inputs?.groups }; + if (testcase.IsEnabled) { + if (testcase.IsEnabled.Exception !== undefined) { + try { + await fm.isEnabled(featureFlagName, context); + expect.fail("It should throw exception."); + } + catch (error) { + // TODO: Verify the error message after we unify it across libraries + // expect(error.message).to.include(testcase.IsEnabled.Exception); + } + } + else { + expect(await fm.isEnabled(featureFlagName, context)).to.eq(testcase.IsEnabled.Result === "true"); + } + } + } +} +describe("feature manager", function () { + it("should pass NoFilters test", async () => { + await runTest("NoFilters"); + }); + it("should pass RequirementType test", async () => { + await runTest("RequirementType"); + }); + it("should pass RequirementType test", async () => { + await runTest("RequirementType"); + }); + it("should pass TimeWindowFilter test", async () => { + await runTest("TimeWindowFilter"); + }); + it("should pass TargetingFilter test", async () => { + await runTest("TargetingFilter"); + }); + it("should pass TargetingFilter.modified test", async () => { + await runTest("TargetingFilter.modified"); + }); +}); +//# sourceMappingURL=validation.test.js.map \ No newline at end of file diff --git a/libraryValidations/JavaScript/out/validation.test.js.map b/libraryValidations/JavaScript/out/validation.test.js.map new file mode 100644 index 0000000..96398f1 --- /dev/null +++ b/libraryValidations/JavaScript/out/validation.test.js.map @@ -0,0 +1 @@ +{"version":3,"file":"validation.test.js","sourceRoot":"","sources":["../validation.test.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,cAAc,MAAM,kBAAkB,CAAC;AAE9C,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;AACzB,OAAO,EAAE,cAAc,EAAE,sCAAsC,EAAE,MAAM,+BAA+B,CAAC;AACvG,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;AAE3B,MAAM,SAAS,GAAG,gBAAgB,CAAA;AAClC,MAAM,eAAe,GAAG,cAAc,CAAA;AACtC,MAAM,cAAc,GAAG,aAAa,CAAA;AAmBpC,KAAK,UAAU,OAAO,CAAC,QAAgB;IACnC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,GAAG,QAAQ,GAAG,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC;IAC7F,MAAM,SAAS,GAAsB,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,GAAG,QAAQ,GAAG,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC;IAClH,MAAM,UAAU,GAAG,IAAI,sCAAsC,CAAC,MAAM,CAAC,CAAC;IACtE,MAAM,EAAE,GAAG,IAAI,cAAc,CAAC,UAAU,CAAC,CAAC;IAE1C,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAC,CAAC;QAC9B,MAAM,eAAe,GAAG,QAAQ,CAAC,eAAe,CAAC;QACjD,MAAM,OAAO,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;QAEnF,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;YACrB,IAAI,QAAQ,CAAC,SAAS,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;gBAC7C,IAAI,CAAC;oBACD,MAAM,EAAE,CAAC,SAAS,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;oBAC7C,MAAM,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;gBAC9C,CAAC;gBACD,OAAO,KAAK,EAAE,CAAC;oBACX,oEAAoE;oBACpE,kEAAkE;gBACtE,CAAC;YACL,CAAC;iBACI,CAAC;gBACF,MAAM,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;YACrG,CAAC;QACL,CAAC;IACL,CAAC;AACL,CAAC;AAED,QAAQ,CAAC,iBAAiB,EAAE;IACxB,EAAE,CAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;QACxC,MAAM,OAAO,CAAC,WAAW,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;QAC9C,MAAM,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;QAC9C,MAAM,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;QAC/C,MAAM,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;QAC9C,MAAM,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;QACvD,MAAM,OAAO,CAAC,0BAA0B,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;AAEP,CAAC,CAAC,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\r\n// Licensed under the MIT license.\r\n\r\nimport * as fs from \"node:fs/promises\";\r\nimport * as chai from \"chai\";\r\nimport chaiAsPromised from \"chai-as-promised\";\r\n\r\nchai.use(chaiAsPromised);\r\nimport { FeatureManager, ConfigurationObjectFeatureFlagProvider } from \"@microsoft/feature-management\";\r\nconst expect = chai.expect;\r\n\r\nconst FILE_PATH = \"../../Samples/\"\r\nconst SAMPLE_JSON_KEY = \".sample.json\"\r\nconst TESTS_JSON_KEY = \".tests.json\"\r\n\r\ninterface IContext {\r\n user?: string;\r\n groups?: string[];\r\n}\r\n\r\ninterface IsEnabledResult {\r\n Result?: string;\r\n Exception?: string;\r\n}\r\n\r\ninterface FeatureFlagTest {\r\n FeatureFlagName: string;\r\n Inputs?: IContext;\r\n IsEnabled?: IsEnabledResult;\r\n Description?: string; \r\n}\r\n\r\nasync function runTest(testName: string) {\r\n const config = JSON.parse(await fs.readFile(FILE_PATH + testName + SAMPLE_JSON_KEY, \"utf8\"));\r\n const testcases: FeatureFlagTest[] = JSON.parse(await fs.readFile(FILE_PATH + testName + TESTS_JSON_KEY, \"utf8\"));\r\n const ffProvider = new ConfigurationObjectFeatureFlagProvider(config);\r\n const fm = new FeatureManager(ffProvider);\r\n\r\n for (const testcase of testcases){\r\n const featureFlagName = testcase.FeatureFlagName;\r\n const context = { userId: testcase.Inputs?.user, groups: testcase.Inputs?.groups };\r\n\r\n if (testcase.IsEnabled) {\r\n if (testcase.IsEnabled.Exception !== undefined) {\r\n try {\r\n await fm.isEnabled(featureFlagName, context);\r\n expect.fail(\"It should throw exception.\");\r\n } \r\n catch (error) {\r\n // TODO: Verify the error message after we unify it across libraries\r\n // expect(error.message).to.include(testcase.IsEnabled.Exception);\r\n }\r\n } \r\n else {\r\n expect(await fm.isEnabled(featureFlagName, context)).to.eq(testcase.IsEnabled.Result === \"true\");\r\n }\r\n }\r\n }\r\n} \r\n\r\ndescribe(\"feature manager\", function () {\r\n it(\"should pass NoFilters test\", async () => {\r\n await runTest(\"NoFilters\");\r\n });\r\n\r\n it(\"should pass RequirementType test\", async () => {\r\n await runTest(\"RequirementType\");\r\n });\r\n\r\n it(\"should pass RequirementType test\", async () => {\r\n await runTest(\"RequirementType\");\r\n });\r\n\r\n it(\"should pass TimeWindowFilter test\", async () => {\r\n await runTest(\"TimeWindowFilter\");\r\n });\r\n\r\n it(\"should pass TargetingFilter test\", async () => {\r\n await runTest(\"TargetingFilter\");\r\n });\r\n\r\n it(\"should pass TargetingFilter.modified test\", async () => {\r\n await runTest(\"TargetingFilter.modified\");\r\n });\r\n\r\n});"]} \ No newline at end of file diff --git a/libraryValidations/JavaScript/package-lock.json b/libraryValidations/JavaScript/package-lock.json new file mode 100644 index 0000000..c04be29 --- /dev/null +++ b/libraryValidations/JavaScript/package-lock.json @@ -0,0 +1,2393 @@ +{ + "name": "JavaScript", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "@microsoft/feature-management": "2.0.0-preview.2", + "@types/chai-as-promised": "^8.0.1", + "@types/mocha": "^10.0.6", + "@types/node": "^20.10.7", + "@typescript-eslint/eslint-plugin": "^6.18.1", + "@typescript-eslint/parser": "^6.18.1", + "chai": "^5.1.2", + "chai-as-promised": "^8.0.0", + "mocha": "^10.2.0", + "rimraf": "^5.0.5", + "tslib": "^2.6.2", + "typescript": "^5.3.3" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "peer": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "peer": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", + "peer": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "peer": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "peer": true + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@microsoft/feature-management": { + "version": "2.0.0-preview.2", + "resolved": "https://registry.npmjs.org/@microsoft/feature-management/-/feature-management-2.0.0-preview.2.tgz", + "integrity": "sha512-MK//1d20yz6ZvQO+2+y3ROGH6vFa/CgPQvYNQqwwJmOnATo86Cl1yYJ2TPlrM0g87EWXFyv7kzCDWiNM4sqTFQ==" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@types/chai": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.0.1.tgz", + "integrity": "sha512-5T8ajsg3M/FOncpLYW7sdOcD6yf4+722sze/tc4KQV0P8Z2rAr3SAuHCIkYmYpt8VbcQlnz8SxlOlPQYefe4cA==", + "dependencies": { + "@types/deep-eql": "*" + } + }, + "node_modules/@types/chai-as-promised": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-8.0.1.tgz", + "integrity": "sha512-dAlDhLjJlABwAVYObo9TPWYTRg9NaQM5CXeaeJYcYAkvzUf0JRLIiog88ao2Wqy/20WUnhbbUZcgvngEbJ3YXQ==", + "dependencies": { + "@types/chai": "*" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" + }, + "node_modules/@types/mocha": { + "version": "10.0.9", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.9.tgz", + "integrity": "sha512-sicdRoWtYevwxjOHNMPTl3vSfJM6oyW8o1wXeI7uww6b6xHg8eBznQDNSGBCDJmsE8UMxP05JgZRtsKbTqt//Q==" + }, + "node_modules/@types/node": { + "version": "20.17.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.3.tgz", + "integrity": "sha512-tSQrmKKatLDGnG92h40GD7FzUt0MjahaHwOME4VAFeeA/Xopayq5qLyQRy7Jg/pjgKIFBXuKcGhJo+UdYG55jQ==", + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", + "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/type-utils": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", + "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", + "dependencies": { + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", + "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", + "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", + "dependencies": { + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", + "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", + "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", + "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", + "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "peer": true + }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "peer": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==" + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chai": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.2.tgz", + "integrity": "sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/chai-as-promised": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-8.0.0.tgz", + "integrity": "sha512-sMsGXTrS3FunP/wbqh/KxM8Kj/aLPXQGkNtvE5wPfSToq8wkkvBpTZo1LIiEVmC4BwkKpag+l5h/20lBMk6nUg==", + "dependencies": { + "check-error": "^2.0.0" + }, + "peerDependencies": { + "chai": ">= 2.1.2 < 6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/check-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", + "engines": { + "node": ">= 16" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "peer": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "peer": true + }, + "node_modules/diff": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "peer": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "peer": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "peer": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "peer": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "peer": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "peer": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "peer": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "peer": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "peer": true + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "peer": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "peer": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flat-cache/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/flat-cache/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "peer": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/flat-cache/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/flat-cache/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "peer": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "peer": true + }, + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "peer": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "peer": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "bin": { + "he": "bin/he" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "peer": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "peer": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "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.", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "peer": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "peer": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "peer": true + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "peer": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "peer": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "peer": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/loupe": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.2.tgz", + "integrity": "sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==" + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mocha": { + "version": "10.8.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.1.tgz", + "integrity": "sha512-WxSpEWgF03HfgNKBuysfK40DUaOSVX5zxgLDoieMGO+zyE69iq2eQ1vBypvIJ5mOPKpuVAqWiTbt4Orj7L6wVw==", + "dependencies": { + "ansi-colors": "^4.1.3", + "browser-stdout": "^1.3.1", + "chokidar": "^3.5.3", + "debug": "^4.3.5", + "diff": "^5.2.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^8.1.0", + "he": "^1.2.0", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^5.1.6", + "ms": "^2.1.3", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^6.5.1", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9", + "yargs-unparser": "^2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "peer": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "peer": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/pathval": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", + "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", + "engines": { + "node": ">= 14.16" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "peer": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", + "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "peer": true + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/tslib": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz", + "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "peer": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "peer": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/workerpool": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", + "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/libraryValidations/JavaScript/package.json b/libraryValidations/JavaScript/package.json new file mode 100644 index 0000000..0b07a03 --- /dev/null +++ b/libraryValidations/JavaScript/package.json @@ -0,0 +1,22 @@ +{ + "type": "module", + "scripts": { + "build": "npm run clean && tsc -p ./tsconfig.json", + "clean": "rimraf out ", + "test": "mocha out/*.test.{js,cjs,mjs} --parallel" + }, + "dependencies": { + "@types/mocha": "^10.0.6", + "@types/node": "^20.10.7", + "@typescript-eslint/eslint-plugin": "^6.18.1", + "@typescript-eslint/parser": "^6.18.1", + "@types/chai-as-promised": "^8.0.1", + "chai": "^5.1.2", + "chai-as-promised": "^8.0.0", + "mocha": "^10.2.0", + "rimraf": "^5.0.5", + "tslib": "^2.6.2", + "typescript": "^5.3.3", + "@microsoft/feature-management": "2.0.0-preview.2" + } +} \ No newline at end of file diff --git a/libraryValidations/JavaScript/tsconfig.json b/libraryValidations/JavaScript/tsconfig.json new file mode 100644 index 0000000..7e7342d --- /dev/null +++ b/libraryValidations/JavaScript/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "lib": [ + "DOM", + "WebWorker", + "ESNext" + ], + "skipDefaultLibCheck": true, + "module": "ESNext", + "moduleResolution": "Node", + "target": "ES2022", + "strictNullChecks": true, + "strictFunctionTypes": true, + "sourceMap": true, + "inlineSources": true, + "outDir": "./out" + }, + "exclude": [ + "node_modules", + "**/node_modules/*" + ] +} \ No newline at end of file diff --git a/libraryValidations/JavaScript/validation.test.ts b/libraryValidations/JavaScript/validation.test.ts new file mode 100644 index 0000000..3774e55 --- /dev/null +++ b/libraryValidations/JavaScript/validation.test.ts @@ -0,0 +1,86 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import * as fs from "node:fs/promises"; +import * as chai from "chai"; +import chaiAsPromised from "chai-as-promised"; + +chai.use(chaiAsPromised); +import { FeatureManager, ConfigurationObjectFeatureFlagProvider } from "@microsoft/feature-management"; +const expect = chai.expect; + +const FILE_PATH = "../../Samples/" +const SAMPLE_JSON_KEY = ".sample.json" +const TESTS_JSON_KEY = ".tests.json" + +interface IContext { + user?: string; + groups?: string[]; +} + +interface IsEnabledResult { + Result?: string; + Exception?: string; +} + +interface FeatureFlagTest { + FeatureFlagName: string; + Inputs?: IContext; + IsEnabled?: IsEnabledResult; + Description?: string; +} + +async function runTest(testName: string) { + const config = JSON.parse(await fs.readFile(FILE_PATH + testName + SAMPLE_JSON_KEY, "utf8")); + const testcases: FeatureFlagTest[] = JSON.parse(await fs.readFile(FILE_PATH + testName + TESTS_JSON_KEY, "utf8")); + const ffProvider = new ConfigurationObjectFeatureFlagProvider(config); + const fm = new FeatureManager(ffProvider); + + for (const testcase of testcases){ + const featureFlagName = testcase.FeatureFlagName; + const context = { userId: testcase.Inputs?.user, groups: testcase.Inputs?.groups }; + + if (testcase.IsEnabled) { + if (testcase.IsEnabled.Exception !== undefined) { + try { + await fm.isEnabled(featureFlagName, context); + expect.fail("It should throw exception."); + } + catch (error) { + // TODO: Verify the error message after we unify it across libraries + // expect(error.message).to.include(testcase.IsEnabled.Exception); + } + } + else { + expect(await fm.isEnabled(featureFlagName, context)).to.eq(testcase.IsEnabled.Result === "true"); + } + } + } +} + +describe("feature manager", function () { + it("should pass NoFilters test", async () => { + await runTest("NoFilters"); + }); + + it("should pass RequirementType test", async () => { + await runTest("RequirementType"); + }); + + it("should pass RequirementType test", async () => { + await runTest("RequirementType"); + }); + + it("should pass TimeWindowFilter test", async () => { + await runTest("TimeWindowFilter"); + }); + + it("should pass TargetingFilter test", async () => { + await runTest("TargetingFilter"); + }); + + it("should pass TargetingFilter.modified test", async () => { + await runTest("TargetingFilter.modified"); + }); + +}); \ No newline at end of file From 789f6f40e5acd426aa05723226c753c88c43de0e Mon Sep 17 00:00:00 2001 From: Zhiyuan Liang Date: Wed, 30 Oct 2024 16:03:01 +0800 Subject: [PATCH 02/14] update readme --- libraryValidations/JavaScript/README.md | 13 + .../JavaScript/package-lock.json | 1145 +---------------- libraryValidations/JavaScript/package.json | 4 +- 3 files changed, 15 insertions(+), 1147 deletions(-) diff --git a/libraryValidations/JavaScript/README.md b/libraryValidations/JavaScript/README.md index e69de29..534bd62 100644 --- a/libraryValidations/JavaScript/README.md +++ b/libraryValidations/JavaScript/README.md @@ -0,0 +1,13 @@ +# JavaScript Feature Management Validation Tests + +This directory contains test cases to verify that the correctness of the latest JS Feature Management library against the files in the `Samples` directory. + +## Running the test + +To run the tests, execute the following command: + +```bash +npm install +npm run build +npm run test +``` diff --git a/libraryValidations/JavaScript/package-lock.json b/libraryValidations/JavaScript/package-lock.json index c04be29..d0f15e2 100644 --- a/libraryValidations/JavaScript/package-lock.json +++ b/libraryValidations/JavaScript/package-lock.json @@ -5,12 +5,10 @@ "packages": { "": { "dependencies": { - "@microsoft/feature-management": "2.0.0-preview.2", + "@microsoft/feature-management": "latest", "@types/chai-as-promised": "^8.0.1", "@types/mocha": "^10.0.6", "@types/node": "^20.10.7", - "@typescript-eslint/eslint-plugin": "^6.18.1", - "@typescript-eslint/parser": "^6.18.1", "chai": "^5.1.2", "chai-as-promised": "^8.0.0", "mocha": "^10.2.0", @@ -19,142 +17,6 @@ "typescript": "^5.3.3" } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", - "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "peer": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "peer": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/js": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", - "peer": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "deprecated": "Use @eslint/config-array instead", - "peer": true, - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "peer": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "peer": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "peer": true - }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -249,38 +111,6 @@ "resolved": "https://registry.npmjs.org/@microsoft/feature-management/-/feature-management-2.0.0-preview.2.tgz", "integrity": "sha512-MK//1d20yz6ZvQO+2+y3ROGH6vFa/CgPQvYNQqwwJmOnATo86Cl1yYJ2TPlrM0g87EWXFyv7kzCDWiNM4sqTFQ==" }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -311,11 +141,6 @@ "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==" }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" - }, "node_modules/@types/mocha": { "version": "10.0.9", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.9.tgz", @@ -329,236 +154,6 @@ "undici-types": "~6.19.2" } }, - "node_modules/@types/semver": { - "version": "7.5.8", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==" - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", - "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", - "dependencies": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/type-utils": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", - "graphemer": "^1.4.0", - "ignore": "^5.2.4", - "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", - "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", - "dependencies": { - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", - "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", - "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", - "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", - "dependencies": { - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", - "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", - "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", - "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", - "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "semver": "^7.5.4" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", - "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", - "dependencies": { - "@typescript-eslint/types": "6.21.0", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "peer": true - }, - "node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", - "peer": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "peer": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "peer": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", @@ -606,14 +201,6 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "engines": { - "node": ">=8" - } - }, "node_modules/assertion-error": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", @@ -662,15 +249,6 @@ "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==" }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "peer": true, - "engines": { - "node": ">=6" - } - }, "node_modules/camelcase": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", @@ -791,12 +369,6 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "peer": true - }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -845,12 +417,6 @@ "node": ">=6" } }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "peer": true - }, "node_modules/diff": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", @@ -859,29 +425,6 @@ "node": ">=0.3.1" } }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "peer": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -911,234 +454,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", - "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", - "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", - "peer": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.1", - "@humanwhocodes/config-array": "^0.13.0", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "peer": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "peer": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "peer": true, - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "peer": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "peer": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "peer": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "peer": true - }, - "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "peer": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "peer": true - }, - "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "peer": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -1173,85 +488,6 @@ "flat": "cli.js" } }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "peer": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flat-cache/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/flat-cache/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "peer": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/flat-cache/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "peer": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/flat-cache/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "peer": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "peer": true - }, "node_modules/foreground-child": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", @@ -1312,18 +548,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "peer": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, "node_modules/glob/node_modules/minimatch": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", @@ -1335,45 +559,6 @@ "node": ">=10" } }, - "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "peer": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" - }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -1390,39 +575,6 @@ "he": "bin/he" } }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "peer": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "peer": true, - "engines": { - "node": ">=0.8.19" - } - }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -1484,15 +636,6 @@ "node": ">=0.12.0" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "peer": true, - "engines": { - "node": ">=8" - } - }, "node_modules/is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", @@ -1542,46 +685,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "peer": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "peer": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "peer": true - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "peer": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "peer": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -1596,12 +699,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "peer": true - }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -1627,40 +724,6 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/minipass": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", @@ -1733,11 +796,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" - }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -1754,23 +812,6 @@ "wrappy": "1" } }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "peer": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -1804,18 +845,6 @@ "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==" }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "peer": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -1824,15 +853,6 @@ "node": ">=8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -1856,14 +876,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "engines": { - "node": ">=8" - } - }, "node_modules/pathval": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", @@ -1883,43 +895,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "peer": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -1947,24 +922,6 @@ "node": ">=0.10.0" } }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, "node_modules/rimraf": { "version": "5.0.10", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", @@ -2012,28 +969,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -2053,17 +988,6 @@ } ] }, - "node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/serialize-javascript": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", @@ -2102,14 +1026,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "engines": { - "node": ">=8" - } - }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -2182,12 +1098,6 @@ "node": ">=8" } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "peer": true - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -2199,46 +1109,11 @@ "node": ">=8.0" } }, - "node_modules/ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, "node_modules/tslib": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz", "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==" }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "peer": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/typescript": { "version": "5.6.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", @@ -2256,15 +1131,6 @@ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "peer": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -2279,15 +1145,6 @@ "node": ">= 8" } }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/workerpool": { "version": "6.5.1", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", diff --git a/libraryValidations/JavaScript/package.json b/libraryValidations/JavaScript/package.json index 0b07a03..817dcf9 100644 --- a/libraryValidations/JavaScript/package.json +++ b/libraryValidations/JavaScript/package.json @@ -8,8 +8,6 @@ "dependencies": { "@types/mocha": "^10.0.6", "@types/node": "^20.10.7", - "@typescript-eslint/eslint-plugin": "^6.18.1", - "@typescript-eslint/parser": "^6.18.1", "@types/chai-as-promised": "^8.0.1", "chai": "^5.1.2", "chai-as-promised": "^8.0.0", @@ -17,6 +15,6 @@ "rimraf": "^5.0.5", "tslib": "^2.6.2", "typescript": "^5.3.3", - "@microsoft/feature-management": "2.0.0-preview.2" + "@microsoft/feature-management": "latest" } } \ No newline at end of file From e1be2af6b8901afbba001bf44f1362297b4ef30f Mon Sep 17 00:00:00 2001 From: Zhiyuan Liang Date: Thu, 31 Oct 2024 18:24:09 +0800 Subject: [PATCH 03/14] remove out dir --- .../JavaScript/out/validation.test.js | 57 ------------------- .../JavaScript/out/validation.test.js.map | 1 - 2 files changed, 58 deletions(-) delete mode 100644 libraryValidations/JavaScript/out/validation.test.js delete mode 100644 libraryValidations/JavaScript/out/validation.test.js.map diff --git a/libraryValidations/JavaScript/out/validation.test.js b/libraryValidations/JavaScript/out/validation.test.js deleted file mode 100644 index 653170b..0000000 --- a/libraryValidations/JavaScript/out/validation.test.js +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. -import * as fs from "node:fs/promises"; -import * as chai from "chai"; -import chaiAsPromised from "chai-as-promised"; -chai.use(chaiAsPromised); -import { FeatureManager, ConfigurationObjectFeatureFlagProvider } from "@microsoft/feature-management"; -const expect = chai.expect; -const FILE_PATH = "../../Samples/"; -const SAMPLE_JSON_KEY = ".sample.json"; -const TESTS_JSON_KEY = ".tests.json"; -async function runTest(testName) { - const config = JSON.parse(await fs.readFile(FILE_PATH + testName + SAMPLE_JSON_KEY, "utf8")); - const testcases = JSON.parse(await fs.readFile(FILE_PATH + testName + TESTS_JSON_KEY, "utf8")); - const ffProvider = new ConfigurationObjectFeatureFlagProvider(config); - const fm = new FeatureManager(ffProvider); - for (const testcase of testcases) { - const featureFlagName = testcase.FeatureFlagName; - const context = { userId: testcase.Inputs?.user, groups: testcase.Inputs?.groups }; - if (testcase.IsEnabled) { - if (testcase.IsEnabled.Exception !== undefined) { - try { - await fm.isEnabled(featureFlagName, context); - expect.fail("It should throw exception."); - } - catch (error) { - // TODO: Verify the error message after we unify it across libraries - // expect(error.message).to.include(testcase.IsEnabled.Exception); - } - } - else { - expect(await fm.isEnabled(featureFlagName, context)).to.eq(testcase.IsEnabled.Result === "true"); - } - } - } -} -describe("feature manager", function () { - it("should pass NoFilters test", async () => { - await runTest("NoFilters"); - }); - it("should pass RequirementType test", async () => { - await runTest("RequirementType"); - }); - it("should pass RequirementType test", async () => { - await runTest("RequirementType"); - }); - it("should pass TimeWindowFilter test", async () => { - await runTest("TimeWindowFilter"); - }); - it("should pass TargetingFilter test", async () => { - await runTest("TargetingFilter"); - }); - it("should pass TargetingFilter.modified test", async () => { - await runTest("TargetingFilter.modified"); - }); -}); -//# sourceMappingURL=validation.test.js.map \ No newline at end of file diff --git a/libraryValidations/JavaScript/out/validation.test.js.map b/libraryValidations/JavaScript/out/validation.test.js.map deleted file mode 100644 index 96398f1..0000000 --- a/libraryValidations/JavaScript/out/validation.test.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"validation.test.js","sourceRoot":"","sources":["../validation.test.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,cAAc,MAAM,kBAAkB,CAAC;AAE9C,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;AACzB,OAAO,EAAE,cAAc,EAAE,sCAAsC,EAAE,MAAM,+BAA+B,CAAC;AACvG,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;AAE3B,MAAM,SAAS,GAAG,gBAAgB,CAAA;AAClC,MAAM,eAAe,GAAG,cAAc,CAAA;AACtC,MAAM,cAAc,GAAG,aAAa,CAAA;AAmBpC,KAAK,UAAU,OAAO,CAAC,QAAgB;IACnC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,GAAG,QAAQ,GAAG,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC;IAC7F,MAAM,SAAS,GAAsB,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,GAAG,QAAQ,GAAG,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC;IAClH,MAAM,UAAU,GAAG,IAAI,sCAAsC,CAAC,MAAM,CAAC,CAAC;IACtE,MAAM,EAAE,GAAG,IAAI,cAAc,CAAC,UAAU,CAAC,CAAC;IAE1C,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAC,CAAC;QAC9B,MAAM,eAAe,GAAG,QAAQ,CAAC,eAAe,CAAC;QACjD,MAAM,OAAO,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;QAEnF,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;YACrB,IAAI,QAAQ,CAAC,SAAS,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;gBAC7C,IAAI,CAAC;oBACD,MAAM,EAAE,CAAC,SAAS,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;oBAC7C,MAAM,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;gBAC9C,CAAC;gBACD,OAAO,KAAK,EAAE,CAAC;oBACX,oEAAoE;oBACpE,kEAAkE;gBACtE,CAAC;YACL,CAAC;iBACI,CAAC;gBACF,MAAM,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;YACrG,CAAC;QACL,CAAC;IACL,CAAC;AACL,CAAC;AAED,QAAQ,CAAC,iBAAiB,EAAE;IACxB,EAAE,CAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;QACxC,MAAM,OAAO,CAAC,WAAW,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;QAC9C,MAAM,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;QAC9C,MAAM,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;QAC/C,MAAM,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;QAC9C,MAAM,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;QACvD,MAAM,OAAO,CAAC,0BAA0B,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;AAEP,CAAC,CAAC,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\r\n// Licensed under the MIT license.\r\n\r\nimport * as fs from \"node:fs/promises\";\r\nimport * as chai from \"chai\";\r\nimport chaiAsPromised from \"chai-as-promised\";\r\n\r\nchai.use(chaiAsPromised);\r\nimport { FeatureManager, ConfigurationObjectFeatureFlagProvider } from \"@microsoft/feature-management\";\r\nconst expect = chai.expect;\r\n\r\nconst FILE_PATH = \"../../Samples/\"\r\nconst SAMPLE_JSON_KEY = \".sample.json\"\r\nconst TESTS_JSON_KEY = \".tests.json\"\r\n\r\ninterface IContext {\r\n user?: string;\r\n groups?: string[];\r\n}\r\n\r\ninterface IsEnabledResult {\r\n Result?: string;\r\n Exception?: string;\r\n}\r\n\r\ninterface FeatureFlagTest {\r\n FeatureFlagName: string;\r\n Inputs?: IContext;\r\n IsEnabled?: IsEnabledResult;\r\n Description?: string; \r\n}\r\n\r\nasync function runTest(testName: string) {\r\n const config = JSON.parse(await fs.readFile(FILE_PATH + testName + SAMPLE_JSON_KEY, \"utf8\"));\r\n const testcases: FeatureFlagTest[] = JSON.parse(await fs.readFile(FILE_PATH + testName + TESTS_JSON_KEY, \"utf8\"));\r\n const ffProvider = new ConfigurationObjectFeatureFlagProvider(config);\r\n const fm = new FeatureManager(ffProvider);\r\n\r\n for (const testcase of testcases){\r\n const featureFlagName = testcase.FeatureFlagName;\r\n const context = { userId: testcase.Inputs?.user, groups: testcase.Inputs?.groups };\r\n\r\n if (testcase.IsEnabled) {\r\n if (testcase.IsEnabled.Exception !== undefined) {\r\n try {\r\n await fm.isEnabled(featureFlagName, context);\r\n expect.fail(\"It should throw exception.\");\r\n } \r\n catch (error) {\r\n // TODO: Verify the error message after we unify it across libraries\r\n // expect(error.message).to.include(testcase.IsEnabled.Exception);\r\n }\r\n } \r\n else {\r\n expect(await fm.isEnabled(featureFlagName, context)).to.eq(testcase.IsEnabled.Result === \"true\");\r\n }\r\n }\r\n }\r\n} \r\n\r\ndescribe(\"feature manager\", function () {\r\n it(\"should pass NoFilters test\", async () => {\r\n await runTest(\"NoFilters\");\r\n });\r\n\r\n it(\"should pass RequirementType test\", async () => {\r\n await runTest(\"RequirementType\");\r\n });\r\n\r\n it(\"should pass RequirementType test\", async () => {\r\n await runTest(\"RequirementType\");\r\n });\r\n\r\n it(\"should pass TimeWindowFilter test\", async () => {\r\n await runTest(\"TimeWindowFilter\");\r\n });\r\n\r\n it(\"should pass TargetingFilter test\", async () => {\r\n await runTest(\"TargetingFilter\");\r\n });\r\n\r\n it(\"should pass TargetingFilter.modified test\", async () => {\r\n await runTest(\"TargetingFilter.modified\");\r\n });\r\n\r\n});"]} \ No newline at end of file From 44886871a8d446bc50c2c4f062a17ebacb3cfa51 Mon Sep 17 00:00:00 2001 From: Zhiyuan Liang Date: Thu, 31 Oct 2024 18:24:32 +0800 Subject: [PATCH 04/14] update gitignore --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index b1a5041..e0d1821 100644 --- a/.gitignore +++ b/.gitignore @@ -406,4 +406,7 @@ env/ .project .settings mvnw* -target/ \ No newline at end of file +target/ + +# JavaScript bundler folder +out/ \ No newline at end of file From 7682616ce94c8181fa92cc98650df52ae2f29aac Mon Sep 17 00:00:00 2001 From: Ross Grambo Date: Thu, 31 Oct 2024 13:51:53 -0700 Subject: [PATCH 05/14] Validation tests for dotnet (#16) * Python tests + Spring Start * debugging * fixed * requirementType * Python Readme & More Spring Tests * Spring Readme and Updates * Python variants + basic variants * Adds .net Validation Tests * Adjusts variant result to use dynamic configuration value * Uses Pascal Case in tests * Merge with main * Updates to pascal case * Resovles attribute Users instead of User * Adjusts tests to all work with new schema * Fixes test call in shared script * Update pom.xml * Fixes path after spring tests * Fixes schema typo * Adds name to variant result expectation * Misc. dotnet fixes * Adds more names --------- Co-authored-by: Matt Metcalf --- .gitignore | 1 + Samples/BasicVariant.tests.json | 24 +- Samples/NoFilters.tests.json | 2 +- Samples/ProviderTelemetry.tests.json | 57 ++-- Samples/ProviderTelemetryComplete.tests.json | 48 ++-- Samples/RequirementType.tests.json | 4 +- Samples/TargetingFilter.modified.tests.json | 16 +- Samples/TargetingFilter.tests.json | 38 +-- Samples/VariantAssignment.tests.json | 76 ++++-- libraryValidations/Dotnet/Dotnet.csproj | 23 ++ libraryValidations/Dotnet/Dotnet.sln | 25 ++ libraryValidations/Dotnet/MSTestSettings.cs | 1 + .../Dotnet/Properties/launchSettings.json | 10 + libraryValidations/Dotnet/README.md | 19 ++ libraryValidations/Dotnet/SharedTest.cs | 43 +++ libraryValidations/Dotnet/TestValidations.cs | 251 ++++++++++++++++++ .../Dotnet/UnknownJsonFieldConverter.cs | 42 +++ .../Python/test_json_validations.py | 22 +- .../test_json_validations_with_provider.py | 14 +- .../Spring/validation-tests/pom.xml | 2 +- .../ValidationTestsApplicationTests.java | 4 +- .../models/ValidationTestCase.java | 6 +- .../validation_tests/models/Variant.java | 28 +- .../models/VariantResult.java | 36 +++ libraryValidations/run_all_tests.ps1 | 17 ++ 25 files changed, 673 insertions(+), 136 deletions(-) create mode 100644 libraryValidations/Dotnet/Dotnet.csproj create mode 100644 libraryValidations/Dotnet/Dotnet.sln create mode 100644 libraryValidations/Dotnet/MSTestSettings.cs create mode 100644 libraryValidations/Dotnet/Properties/launchSettings.json create mode 100644 libraryValidations/Dotnet/README.md create mode 100644 libraryValidations/Dotnet/SharedTest.cs create mode 100644 libraryValidations/Dotnet/TestValidations.cs create mode 100644 libraryValidations/Dotnet/UnknownJsonFieldConverter.cs create mode 100644 libraryValidations/Spring/validation-tests/src/test/java/com/microsoft/validation_tests/models/VariantResult.java create mode 100644 libraryValidations/run_all_tests.ps1 diff --git a/.gitignore b/.gitignore index b1a5041..8e3678e 100644 --- a/.gitignore +++ b/.gitignore @@ -399,6 +399,7 @@ FodyWeavers.xsd # Python env env/ +venv/ .classpath diff --git a/Samples/BasicVariant.tests.json b/Samples/BasicVariant.tests.json index 5729d4e..514a578 100644 --- a/Samples/BasicVariant.tests.json +++ b/Samples/BasicVariant.tests.json @@ -6,7 +6,10 @@ "Result": "false" }, "Variant": { - "Result": "default" + "Result": { + "Name": "True_Override", + "ConfigurationValue": "default" + } }, "Description": "An Enabled Feature Flag with no Filters." }, @@ -17,33 +20,42 @@ "Result": "false" }, "Variant": { - "Result": "default" + "Result": { + "Name": "False_Override", + "ConfigurationValue": "default" + } }, "Description": "A Disabled Feature Flag with no Filters." }, { "FeatureFlagName": "TestVariants", "Inputs": { - "user": "Adam" + "User": "Adam" }, "IsEnabled": { "Result": "true" }, "Variant": { - "Result": "The Variant Alpha." + "Result": { + "Name": "Alpha", + "ConfigurationValue": "The Variant Alpha." + } }, "Description": "A Feature Flag with two Variants, one for Adam and one for Britney." }, { "FeatureFlagName": "TestVariants", "Inputs": { - "user": "Britney" + "User": "Britney" }, "IsEnabled": { "Result": "true" }, "Variant": { - "Result": "The Variant Beta." + "Result": { + "Name": "Beta", + "ConfigurationValue": "The Variant Beta." + } }, "Description": "A Feature Flag with two Variants, one for Adam and one for Britney." } diff --git a/Samples/NoFilters.tests.json b/Samples/NoFilters.tests.json index 01445d6..1b98c83 100644 --- a/Samples/NoFilters.tests.json +++ b/Samples/NoFilters.tests.json @@ -28,7 +28,7 @@ "Exception": "Invalid setting 'enabled' with value 'invalid' for feature 'InvalidEnabled'." }, "Variant": { - "Result": null + "Exception": "Invalid setting 'enabled' with value 'invalid' for feature 'InvalidEnabled'." }, "Description": "A Feature Flag with an invalid Enabled Value." }, diff --git a/Samples/ProviderTelemetry.tests.json b/Samples/ProviderTelemetry.tests.json index f54d31d..c6e1914 100644 --- a/Samples/ProviderTelemetry.tests.json +++ b/Samples/ProviderTelemetry.tests.json @@ -2,30 +2,33 @@ { "FeatureFlagName": "TelemetryVariantPercentile", "Inputs": { - "user": "Sami" + "User": "Sami" }, "IsEnabled": { "Result": "true" }, "Variant": { "Result": { - "someOtherKey": { - "someSubKey": "someSubValue" - }, - "someKey4": [ - 3, - 1, - 4, - true - ], - "someKey": "someValue", - "someKey3": 3.14, - "someKey2": 3 + "Name": "True_Override", + "ConfigurationValue": { + "someOtherKey": { + "someSubKey": "someSubValue" + }, + "someKey4": [ + 3, + 1, + 4, + true + ], + "someKey": "someValue", + "someKey3": 3.14, + "someKey2": 3 + } } }, "Telemetry": { - "event_name": "FeatureEvaluation", - "event_properties": { + "EventName": "FeatureEvaluation", + "EventProperties": { "FeatureName": "TelemetryVariantPercentile", "Enabled": "True", "Version": "1.0.0", @@ -44,17 +47,20 @@ { "FeatureFlagName": "Background.Colors", "Inputs": { - "user": "Aiden" + "User": "Aiden" }, "IsEnabled": { "Result": "true" }, "Variant": { - "Result": {"r": 75, "g": 0, "b": 130} + "Result": { + "Name": "Indigo", + "ConfigurationValue": { "r": 75, "g": 0, "b": 130 } + } }, "Telemetry": { - "event_name": "FeatureEvaluation", - "event_properties": { + "EventName": "FeatureEvaluation", + "EventProperties": { "FeatureName": "Background.Colors", "Enabled": "True", "Version": "1.0.0", @@ -73,17 +79,22 @@ { "FeatureFlagName": "Background.Colors", "Inputs": { - "user": "Brittney" + "User": "Brittney" }, "IsEnabled": { "Result": "true" }, "Variant": { - "Result": {"r": 255, "g": 162, "b": 0} + "Result": { + "Name": "Orange", + "ConfigurationValue": { + "r": 255, "g": 162, "b": 0 + } + } }, "Telemetry": { - "event_name": "FeatureEvaluation", - "event_properties": { + "EventName": "FeatureEvaluation", + "EventProperties": { "FeatureName": "Background.Colors", "Enabled": "True", "Version": "1.0.0", diff --git a/Samples/ProviderTelemetryComplete.tests.json b/Samples/ProviderTelemetryComplete.tests.json index c0a667e..b018b3b 100644 --- a/Samples/ProviderTelemetryComplete.tests.json +++ b/Samples/ProviderTelemetryComplete.tests.json @@ -2,17 +2,20 @@ { "FeatureFlagName": "Complete", "Inputs": { - "user": "Aiden" + "User": "Aiden" }, "IsEnabled": { "Result": "true" }, "Variant": { - "Result": 100 + "Result": { + "Name": "Large", + "ConfigurationValue": 100 + } }, "Telemetry": { - "event_name": "FeatureEvaluation", - "event_properties": { + "EventName": "FeatureEvaluation", + "EventProperties": { "FeatureName": "Complete", "Enabled": "True", "Version": "1.0.0", @@ -31,17 +34,20 @@ { "FeatureFlagName": "Complete", "Inputs": { - "user": "Rachel" + "User": "Rachel" }, "IsEnabled": { "Result": "true" }, "Variant": { - "Result": 10 + "Result": { + "Name": "Small", + "ConfigurationValue": 10 + } }, "Telemetry": { - "event_name": "FeatureEvaluation", - "event_properties": { + "EventName": "FeatureEvaluation", + "EventProperties": { "FeatureName": "Complete", "Enabled": "True", "Version": "1.0.0", @@ -59,18 +65,21 @@ { "FeatureFlagName": "Complete", "Inputs": { - "user": "Aiden", - "groups": ["beta"] + "User": "Aiden", + "Groups": ["beta"] }, "IsEnabled": { "Result": "true" }, "Variant": { - "Result": 100 + "Result": { + "Name": "Large", + "ConfigurationValue": 100 + } }, "Telemetry": { - "event_name": "FeatureEvaluation", - "event_properties": { + "EventName": "FeatureEvaluation", + "EventProperties": { "FeatureName": "Complete", "Enabled": "True", "Version": "1.0.0", @@ -88,18 +97,21 @@ { "FeatureFlagName": "Complete", "Inputs": { - "user": "Rachel", - "group": "beta" + "User": "Rachel", + "Groups": ["beta"] }, "IsEnabled": { "Result": "true" }, "Variant": { - "Result": 10 + "Result": { + "Name": "Small", + "ConfigurationValue": 10 + } }, "Telemetry": { - "event_name": "FeatureEvaluation", - "event_properties": { + "EventName": "FeatureEvaluation", + "EventProperties": { "FeatureName": "Complete", "Enabled": "True", "Version": "1.0.0", diff --git a/Samples/RequirementType.tests.json b/Samples/RequirementType.tests.json index 74df4d8..0524194 100644 --- a/Samples/RequirementType.tests.json +++ b/Samples/RequirementType.tests.json @@ -45,7 +45,7 @@ }, { "FeatureFlagName": "RequirementTypeAllPassed", - "Inputs": {"user":"Adam"}, + "Inputs": {"User":"Adam"}, "IsEnabled": { "Result": "true" }, @@ -56,7 +56,7 @@ }, { "FeatureFlagName": "RequirementTypeAllLastFilterFailed", - "Inputs": {"user":"Adam"}, + "Inputs": {"User":"Adam"}, "IsEnabled": { "Result": "false" }, diff --git a/Samples/TargetingFilter.modified.tests.json b/Samples/TargetingFilter.modified.tests.json index 1c1425b..8d32379 100644 --- a/Samples/TargetingFilter.modified.tests.json +++ b/Samples/TargetingFilter.modified.tests.json @@ -2,7 +2,7 @@ { "FriendlyName": "Aiden62", "FeatureFlagName": "RolloutPercentageUpdate", - "Inputs": {"user":"Aiden"}, + "Inputs": {"User":"Aiden"}, "IsEnabled": { "Result": "true" }, @@ -14,7 +14,7 @@ { "FriendlyName": "Aiden62 - Stage1", "FeatureFlagName": "RolloutPercentageUpdate", - "Inputs": {"user":"Aiden", "groups":["Stage1"]}, + "Inputs": {"User":"Aiden", "Groups":["Stage1"]}, "IsEnabled": { "Result": "true" }, @@ -26,7 +26,7 @@ { "FriendlyName": "Aiden62 - Stage2", "FeatureFlagName": "RolloutPercentageUpdate", - "Inputs": {"user":"Aiden", "groups":["Stage2"]}, + "Inputs": {"User":"Aiden", "Groups":["Stage2"]}, "IsEnabled": { "Result": "true" }, @@ -38,7 +38,7 @@ { "FriendlyName": "Aiden62 - Stage3", "FeatureFlagName": "RolloutPercentageUpdate", - "Inputs": {"user":"Aiden", "groups":["Stage3"]}, + "Inputs": {"User":"Aiden", "Groups":["Stage3"]}, "IsEnabled": { "Result": "true" }, @@ -50,7 +50,7 @@ { "FriendlyName": "Brittney62", "FeatureFlagName": "RolloutPercentageUpdate", - "Inputs": {"user":"Brittney"}, + "Inputs": {"User":"Brittney"}, "IsEnabled": { "Result": "true" }, @@ -62,7 +62,7 @@ { "FriendlyName": "Brittney62 - Stage1", "FeatureFlagName": "RolloutPercentageUpdate", - "Inputs": {"user":"Brittney", "groups":["Stage1"]}, + "Inputs": {"User":"Brittney", "Groups":["Stage1"]}, "IsEnabled": { "Result": "true" }, @@ -74,7 +74,7 @@ { "FriendlyName": "Brittney62 - Stage2", "FeatureFlagName": "RolloutPercentageUpdate", - "Inputs": {"user":"Brittney", "groups":["Stage2"]}, + "Inputs": {"User":"Brittney", "Groups":["Stage2"]}, "IsEnabled": { "Result": "true" }, @@ -86,7 +86,7 @@ { "FriendlyName": "Brittney62 - Stage3", "FeatureFlagName": "RolloutPercentageUpdate", - "Inputs": {"user":"Brittney", "groups":["Stage3"]}, + "Inputs": {"User":"Brittney", "Groups":["Stage3"]}, "IsEnabled": { "Result": "true" }, diff --git a/Samples/TargetingFilter.tests.json b/Samples/TargetingFilter.tests.json index 60e2f41..a3b88df 100644 --- a/Samples/TargetingFilter.tests.json +++ b/Samples/TargetingFilter.tests.json @@ -2,7 +2,7 @@ { "FriendlyName": "DisabledDefaultRollout", "FeatureFlagName": "ComplexTargeting", - "Inputs": {"user":"Aiden"}, + "Inputs": {"User":"Aiden"}, "IsEnabled": { "Result": "false" }, @@ -14,7 +14,7 @@ { "FriendlyName": "EnabledDefaultRollout", "FeatureFlagName": "ComplexTargeting", - "Inputs": {"user":"Blossom"}, + "Inputs": {"User":"Blossom"}, "IsEnabled": { "Result": "true" }, @@ -26,7 +26,7 @@ { "FriendlyName": "TargetedUser", "FeatureFlagName": "ComplexTargeting", - "Inputs": {"user":"Alice"}, + "Inputs": {"User":"Alice"}, "IsEnabled": { "Result": "true" }, @@ -38,7 +38,7 @@ { "FriendlyName": "TargetedGroup", "FeatureFlagName": "ComplexTargeting", - "Inputs": {"user":"Aiden", "groups":["Stage1"]}, + "Inputs": {"User":"Aiden", "Groups":["Stage1"]}, "IsEnabled": { "Result": "true" }, @@ -50,7 +50,7 @@ { "FriendlyName": "DisabledTargetedGroup", "FeatureFlagName": "ComplexTargeting", - "Inputs": {"groups":["Stage2"]}, + "Inputs": {"Groups":["Stage2"]}, "IsEnabled": { "Result": "false" }, @@ -62,7 +62,7 @@ { "FriendlyName": "EnabledTargetedGroup50", "FeatureFlagName": "ComplexTargeting", - "Inputs": {"user":"Aiden", "groups":["Stage2"]}, + "Inputs": {"User":"Aiden", "Groups":["Stage2"]}, "IsEnabled": { "Result": "true" }, @@ -74,7 +74,7 @@ { "FriendlyName": "DisabledTargetedGroup50", "FeatureFlagName": "ComplexTargeting", - "Inputs": {"user":"Chris", "groups":["Stage2"]}, + "Inputs": {"User":"Chris", "Groups":["Stage2"]}, "IsEnabled": { "Result": "false" }, @@ -86,7 +86,7 @@ { "FriendlyName": "ExcludedGroup", "FeatureFlagName": "ComplexTargeting", - "Inputs": {"groups":["Stage3"]}, + "Inputs": {"Groups":["Stage3"]}, "IsEnabled": { "Result": "false" }, @@ -98,7 +98,7 @@ { "FriendlyName": "ExcludedGroupTargetedUser", "FeatureFlagName": "ComplexTargeting", - "Inputs": {"user":"Alice", "groups":["Stage3"]}, + "Inputs": {"User":"Alice", "Groups":["Stage3"]}, "IsEnabled": { "Result": "false" }, @@ -110,7 +110,7 @@ { "FriendlyName": "ExcludedGroupDefaultRollout", "FeatureFlagName": "ComplexTargeting", - "Inputs": {"user":"Blossom", "groups":["Stage3"]}, + "Inputs": {"User":"Blossom", "Groups":["Stage3"]}, "IsEnabled": { "Result": "false" }, @@ -122,7 +122,7 @@ { "FriendlyName": "ExcludedUser", "FeatureFlagName": "ComplexTargeting", - "Inputs": {"user":"Dave", "groups":["Stage1"]}, + "Inputs": {"User":"Dave", "Groups":["Stage1"]}, "IsEnabled": { "Result": "false" }, @@ -134,7 +134,7 @@ { "FriendlyName": "Aiden61", "FeatureFlagName": "RolloutPercentageUpdate", - "Inputs": {"user":"Aiden"}, + "Inputs": {"User":"Aiden"}, "IsEnabled": { "Result": "true" }, @@ -146,7 +146,7 @@ { "FriendlyName": "Aiden61 - Stage1", "FeatureFlagName": "RolloutPercentageUpdate", - "Inputs": {"user":"Aiden", "groups":["Stage1"]}, + "Inputs": {"User":"Aiden", "Groups":["Stage1"]}, "IsEnabled": { "Result": "true" }, @@ -158,7 +158,7 @@ { "FriendlyName": "Aiden61 - Stage2", "FeatureFlagName": "RolloutPercentageUpdate", - "Inputs": {"user":"Aiden", "groups":["Stage2"]}, + "Inputs": {"User":"Aiden", "Groups":["Stage2"]}, "IsEnabled": { "Result": "true" }, @@ -170,7 +170,7 @@ { "FriendlyName": "Aiden61 - Stage3", "FeatureFlagName": "RolloutPercentageUpdate", - "Inputs": {"user":"Aiden", "groups":["Stage3"]}, + "Inputs": {"User":"Aiden", "Groups":["Stage3"]}, "IsEnabled": { "Result": "true" }, @@ -182,7 +182,7 @@ { "FriendlyName": "Brittney61", "FeatureFlagName": "RolloutPercentageUpdate", - "Inputs": {"user":"Brittney"}, + "Inputs": {"User":"Brittney"}, "IsEnabled": { "Result": "false" }, @@ -194,7 +194,7 @@ { "FriendlyName": "Brittney61 - Stage1", "FeatureFlagName": "RolloutPercentageUpdate", - "Inputs": {"user":"Brittney", "groups":["Stage1"]}, + "Inputs": {"User":"Brittney", "Groups":["Stage1"]}, "IsEnabled": { "Result": "false" }, @@ -206,7 +206,7 @@ { "FriendlyName": "Brittney61 - Stage2", "FeatureFlagName": "RolloutPercentageUpdate", - "Inputs": {"user":"Brittney", "groups":["Stage2"]}, + "Inputs": {"User":"Brittney", "Groups":["Stage2"]}, "IsEnabled": { "Result": "false" }, @@ -218,7 +218,7 @@ { "FriendlyName": "Brittney61 - Stage3", "FeatureFlagName": "RolloutPercentageUpdate", - "Inputs": {"user":"Brittney", "groups":["Stage3"]}, + "Inputs": {"User":"Brittney", "Groups":["Stage3"]}, "IsEnabled": { "Result": "false" }, diff --git a/Samples/VariantAssignment.tests.json b/Samples/VariantAssignment.tests.json index f91f1fa..6fa8323 100644 --- a/Samples/VariantAssignment.tests.json +++ b/Samples/VariantAssignment.tests.json @@ -2,148 +2,170 @@ { "FeatureFlagName": "UserAssignedVariant", "Inputs": { - "user": "Britney" + "User": "Britney" }, "IsEnabled": { "Result": "true" }, "Variant": { - "Result": "The Variant Beta." + "Result": { + "ConfigurationValue": "The Variant Beta." + } }, "Description": "A Feature Flag with two Variants, one for Adam and one for Britney." }, { "FeatureFlagName": "UserAssignedVariant", "Inputs": { - "user": "Adam" + "User": "Adam" }, "IsEnabled": { "Result": "true" }, "Variant": { - "Result": "The Variant Alpha." + "Result": { + "ConfigurationValue": "The Variant Alpha." + } }, "Description": "A Feature Flag with two Variants, one for Adam and one for Britney." }, { "FeatureFlagName": "GroupAssignedVariant", "Inputs": { - "user": "Britney", - "groups": ["Ring2"] + "User": "Britney", + "Groups": ["Ring2"] }, "IsEnabled": { "Result": "true" }, "Variant": { - "Result": "The Variant Beta." + "Result": { + "ConfigurationValue": "The Variant Beta." + } }, "Description": "A Feature Flag with two Variants, one for Ring1 and one for Ring2." }, { "FeatureFlagName": "GroupAssignedVariant", "Inputs": { - "user": "Britney", - "groups": ["Ring1"] + "User": "Britney", + "Groups": ["Ring1"] }, "IsEnabled": { "Result": "true" }, "Variant": { - "Result": "The Variant Alpha." + "Result": { + "ConfigurationValue": "The Variant Alpha." + } }, "Description": "A Feature Flag with two Variants, one for Ring1 and one for Ring2." }, { "FeatureFlagName": "AllocationAssignedVariant", "Inputs": { - "user": "Britney" + "User": "Britney" }, "IsEnabled": { "Result": "true" }, "Variant": { - "Result": "The Variant Beta." + "Result": { + "ConfigurationValue": "The Variant Beta." + } }, "Description": "A Feature Flag with two Variants, each with 50%." }, { "FeatureFlagName": "AllocationAssignedVariant", "Inputs": { - "user": "Adam" + "User": "Adam" }, "IsEnabled": { "Result": "true" }, "Variant": { - "Result": "The Variant Alpha." + "Result": { + "ConfigurationValue": "The Variant Alpha." + } }, "Description": "A Feature Flag with two Variants, each with 50%." }, { "FeatureFlagName": "ComplexAssignment", "Inputs": { - "user": "Adam" + "User": "Adam" }, "IsEnabled": { "Result": "true" }, "Variant": { - "Result": "The Variant Alpha." + "Result": { + "ConfigurationValue": "The Variant Alpha." + } }, "Description": "A Feature Flag with two Variants, with user, group, and percientile assignment." }, { "FeatureFlagName": "ComplexAssignment", "Inputs": { - "user": "Britney" + "User": "Britney" }, "IsEnabled": { "Result": "true" }, "Variant": { - "Result": "The Variant Beta." + "Result": { + "ConfigurationValue": "The Variant Beta." + } }, "Description": "A Feature Flag with two Variants, with user, group, and percientile assignment." }, { "FeatureFlagName": "ComplexAssignment", "Inputs": { - "user": "John", - "groups": ["Ring1"] + "User": "John", + "Groups": ["Ring1"] }, "IsEnabled": { "Result": "true" }, "Variant": { - "Result": "The Variant Alpha." + "Result": { + "ConfigurationValue": "The Variant Alpha." + } }, "Description": "A Feature Flag with two Variants, with user, group, and percientile assignment." }, { "FeatureFlagName": "ComplexAssignment", "Inputs": { - "user": "Jane", - "groups": ["Ring3"] + "User": "Jane", + "Groups": ["Ring3"] }, "IsEnabled": { "Result": "true" }, "Variant": { - "Result": "The Variant Alpha." + "Result": { + "ConfigurationValue": "The Variant Alpha." + } }, "Description": "A Feature Flag with two Variants, with user, group, and percientile assignment." }, { "FeatureFlagName": "ComplexAssignment", "Inputs": { - "user": "Selena", - "groups": ["Ring4"] + "User": "Selena", + "Groups": ["Ring4"] }, "IsEnabled": { "Result": "true" }, "Variant": { - "Result": "The Variant Beta." + "Result": { + "ConfigurationValue": "The Variant Beta." + } }, "Description": "A Feature Flag with two Variants, with user, group, and percientile assignment." } diff --git a/libraryValidations/Dotnet/Dotnet.csproj b/libraryValidations/Dotnet/Dotnet.csproj new file mode 100644 index 0000000..402face --- /dev/null +++ b/libraryValidations/Dotnet/Dotnet.csproj @@ -0,0 +1,23 @@ + + + + net9.0 + latest + enable + enable + + true + + + + + + + + + + + diff --git a/libraryValidations/Dotnet/Dotnet.sln b/libraryValidations/Dotnet/Dotnet.sln new file mode 100644 index 0000000..61f7364 --- /dev/null +++ b/libraryValidations/Dotnet/Dotnet.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.002.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dotnet", "Dotnet.csproj", "{F19DEACC-9B50-45D3-80F2-C619344722D9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F19DEACC-9B50-45D3-80F2-C619344722D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F19DEACC-9B50-45D3-80F2-C619344722D9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F19DEACC-9B50-45D3-80F2-C619344722D9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F19DEACC-9B50-45D3-80F2-C619344722D9}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {08D18984-BEEF-4BF5-94DC-DBD8096154DC} + EndGlobalSection +EndGlobal diff --git a/libraryValidations/Dotnet/MSTestSettings.cs b/libraryValidations/Dotnet/MSTestSettings.cs new file mode 100644 index 0000000..aaf278c --- /dev/null +++ b/libraryValidations/Dotnet/MSTestSettings.cs @@ -0,0 +1 @@ +[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)] diff --git a/libraryValidations/Dotnet/Properties/launchSettings.json b/libraryValidations/Dotnet/Properties/launchSettings.json new file mode 100644 index 0000000..0bed4f3 --- /dev/null +++ b/libraryValidations/Dotnet/Properties/launchSettings.json @@ -0,0 +1,10 @@ +{ + "profiles": { + "Dotnet": { + "commandName": "Project", + "environmentVariables": { + "APP_CONFIG_VALIDATION_CONNECTION_STRING": "Endpoint=https://appconfig4ndakx7twshlm.azconfig.io;Id=A3jj;Secret=1WWpbi6jB5Bw9sYAvrHfSteqInR0UCZhwA2ynipVN1LcutGRncMyJQQJ99AJACYeBjFAArohAAACAZACIycQ" + } + } + } +} \ No newline at end of file diff --git a/libraryValidations/Dotnet/README.md b/libraryValidations/Dotnet/README.md new file mode 100644 index 0000000..514e7bc --- /dev/null +++ b/libraryValidations/Dotnet/README.md @@ -0,0 +1,19 @@ +# .NET Validation Tests + +This directory contains a .NET script that can be used to validate the correctness of the library against the files in the `Samples` directory. + +## Prerequisites + +* .NET 9 or later + +## Running the tests + +To run the tests, execute the following command: + +```bash +dotnet test +``` + +## Update to run more tests + +To add more tests, after creating the required json files in the `Samples` directory, add a new test method in the `TestValidations.cs` file. diff --git a/libraryValidations/Dotnet/SharedTest.cs b/libraryValidations/Dotnet/SharedTest.cs new file mode 100644 index 0000000..69a6509 --- /dev/null +++ b/libraryValidations/Dotnet/SharedTest.cs @@ -0,0 +1,43 @@ +using System.Text.Json; + +namespace DotnetFeatureManagementTests; + +internal class SharedTest +{ + public required string FeatureFlagName { get; set; } + public InputsSection? Inputs { get; set; } + public IsEnabledSection? IsEnabled { get; set; } + public VariantSection? Variant { get; set; } + public TelemetrySection? Telemetry { get; set; } + public string? Description { get; set; } + + + internal class InputsSection + { + public string? User { get; set; } + public string[]? Groups { get; set; } + } + + internal class IsEnabledSection + { + public string? Result { get; set; } + public string? Exception { get; set; } + } + + internal class VariantSection + { + public VariantResultSection? Result { get; set; } + public string? Exception { get; set; } + } + + internal class VariantResultSection + { + public JsonElement? ConfigurationValue { get; set; } + } + + internal class TelemetrySection + { + public string? EventName { get; set; } + public Dictionary? EventProperties { get; set; } + } +} diff --git a/libraryValidations/Dotnet/TestValidations.cs b/libraryValidations/Dotnet/TestValidations.cs new file mode 100644 index 0000000..1b2629d --- /dev/null +++ b/libraryValidations/Dotnet/TestValidations.cs @@ -0,0 +1,251 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +// +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.FeatureManagement; +using Microsoft.FeatureManagement.FeatureFilters; +using System.Diagnostics; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace DotnetFeatureManagementTests; + +[TestClass] +public class Tests +{ + private const string FilePath = "../../../../../Samples/"; + private const string SampleJsonKey = ".sample.json"; + private const string TestsJsonKey = ".tests.json"; + + private ActivityListener? _activityListener; + + private readonly JsonSerializerOptions options = new() + { + Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) } + }; + + [TestMethod] + [DataRow("NoFilters")] + [DataRow("TimeWindowFilter")] + [DataRow("TargetingFilter")] + [DataRow("TargetingFilter.modified")] + [DataRow("RequirementType")] + [DataRow("BasicVariant")] + public async Task RunTestFile(string fileName) + { + // Use Sample JSON as Configuration + string file = Directory.GetFiles(FilePath, fileName + SampleJsonKey).First(); + + ConfigurationBuilder builder = new(); + + builder.AddJsonFile(Path.GetFullPath(file)); + + IConfiguration configuration = builder.Build(); + + // Setup FeatureManagement + IServiceCollection services = new ServiceCollection(); + + services.AddSingleton(configuration) + .AddFeatureManagement(); + + ServiceProvider serviceProvider = services.BuildServiceProvider(); + IVariantFeatureManager featureManager = serviceProvider.GetRequiredService(); + + await RunTests(featureManager, fileName); + } + + [TestMethod] + public async Task RunProviderTestFile() + { + // Use Provider for Configuration + IConfiguration configuration = new ConfigurationBuilder() + .AddAzureAppConfiguration(o => + { + o.Connect(Environment.GetEnvironmentVariable("APP_CONFIG_VALIDATION_CONNECTION_STRING")); + + o.UseFeatureFlags(); + }) + .Build(); + + // Setup FeatureManagement + IServiceCollection services = new ServiceCollection(); + + services.AddSingleton(configuration) + .AddFeatureManagement(); + + ServiceProvider serviceProvider = services.BuildServiceProvider(); + IVariantFeatureManager featureManager = serviceProvider.GetRequiredService(); + + // Can't use DataRow because ActivityListener requires these are run sequentially + await RunTests(featureManager, "ProviderTelemetry"); + await RunTests(featureManager, "ProviderTelemetryComplete"); + } + + private async Task RunTests(IVariantFeatureManager featureManager, string fileName) + { + // Get Test Suite JSON + var featureFlagTests = JsonSerializer.Deserialize(File.ReadAllText(FilePath + fileName + TestsJsonKey), options); + + if (featureFlagTests == null) { + throw new Exception("Test failed to parse JSON"); + } + + // Run each test + foreach (var featureFlagTest in featureFlagTests) + { + string featureFlagId = fileName + "." + featureFlagTest.FeatureFlagName; + string failedDescription = $"Test {featureFlagId} failed. Description: {featureFlagTest.Description}"; + + // Setup Activity Listener if we're validating Telemetry + if (featureFlagTest.Telemetry != null) + { + SetupActivityListener(featureFlagTest, failedDescription); + } + + // IsEnabledAsync + if (featureFlagTest.IsEnabled != null) + { + bool? expectedIsEnabledResult = featureFlagTest.IsEnabled.Result != null ? Convert.ToBoolean(featureFlagTest.IsEnabled.Result) : null; + + if (featureFlagTest.IsEnabled.Exception != null) + { + await Assert.ThrowsExceptionAsync(async () => await featureManager.IsEnabledAsync(featureFlagTest.FeatureFlagName), featureFlagTest.IsEnabled.Exception); + } + else + { + bool isEnabledResult = await featureManager.IsEnabledAsync(featureFlagTest.FeatureFlagName, new TargetingContext { UserId = featureFlagTest.Inputs?.User, Groups = featureFlagTest.Inputs?.Groups }); + Assert.AreEqual(expectedIsEnabledResult, isEnabledResult, failedDescription); + } + } + + // GetVariantAsync + if (featureFlagTest.Variant != null) + { + if (featureFlagTest.Variant.Exception != null) + { + await Assert.ThrowsExceptionAsync(async () => await featureManager.GetVariantAsync(featureFlagTest.FeatureFlagName), featureFlagTest.Variant.Exception); + } + else + { + Variant variantResult = await featureManager.GetVariantAsync(featureFlagTest.FeatureFlagName, new TargetingContext { UserId = featureFlagTest.Inputs?.User, Groups = featureFlagTest.Inputs?.Groups }); + + if (featureFlagTest.Variant.Result == null) + { + Assert.IsNull(variantResult); + } + else + { + ValidateJsonConfigurationValue(featureFlagTest.Variant.Result.ConfigurationValue, variantResult.Configuration); + } + } + } + + if (featureFlagTest.Telemetry != null) + { + _activityListener?.Dispose(); + } + } + } + + private void SetupActivityListener(SharedTest featureFlagTest, string failedDescription) + { + _activityListener = new ActivityListener + { + ShouldListenTo = (activitySource) => activitySource.Name == "Microsoft.FeatureManagement", + Sample = (ref ActivityCreationOptions options) => ActivitySamplingResult.AllData, + ActivityStopped = (activity) => + { + ActivityEvent? evaluationEvent = activity.Events.FirstOrDefault((activityEvent) => activityEvent.Name == "FeatureFlag"); + + if (evaluationEvent.HasValue && evaluationEvent.Value.Tags.Any()) + { + Dictionary evaluationEventProperties = evaluationEvent.Value.Tags.ToDictionary((tag) => tag.Key, (tag) => tag.Value); + + if (featureFlagTest.Telemetry != null && featureFlagTest.Telemetry.EventProperties != null) + { + foreach (var property in featureFlagTest.Telemetry.EventProperties) + { + Assert.IsTrue(evaluationEventProperties.ContainsKey(property.Key), failedDescription); + + if (property.Key == "FeatureFlagReference") + { + Assert.IsTrue(evaluationEventProperties[property.Key]?.ToString()?.EndsWith(property.Value)); + } + else + { + Assert.AreEqual(property.Value, evaluationEventProperties[property.Key]?.ToString(), failedDescription); + } + } + } + } + } + }; + + ActivitySource.AddActivityListener(_activityListener); + } + + private void ValidateJsonConfigurationValue(JsonElement? ele, IConfigurationSection configuration) + { + if (ele == null) + { + Assert.IsNull(configuration.Get()); + } + else + { + if (ele.Value.ValueKind == JsonValueKind.Object) + { + foreach (var property in ele.Value.EnumerateObject()) + { + ValidateProperty(property.Value, configuration.GetSection(property.Name)); + } + } + else if (ele.Value.ValueKind == JsonValueKind.Array) + { + for (int i = 0; i < ele.Value.GetArrayLength(); i++) + { + ValidateProperty(ele.Value[i], configuration.GetSection(i.ToString())); + } + } + else + { + ValidateProperty(ele.Value, configuration); + } + } + } + + private void ValidateProperty(JsonElement value, IConfigurationSection configuration) + { + if (value.ValueKind == JsonValueKind.String) + { + Assert.AreEqual(value.GetString(), configuration?.Get()); + } + else if (value.ValueKind == JsonValueKind.Number) + { + Assert.AreEqual(value.GetDouble(), configuration?.Get()); + } + else if (value.ValueKind == JsonValueKind.Null) + { + Assert.IsNull(configuration?.Get()); + } + else if (value.ValueKind == JsonValueKind.False) + { + Assert.IsFalse(configuration?.Get()); + } + else if (value.ValueKind == JsonValueKind.True) + { + Assert.IsTrue(configuration?.Get()); + } + else if (value.ValueKind == JsonValueKind.Object) + { + ValidateJsonConfigurationValue(value, configuration); + } + else if (value.ValueKind == JsonValueKind.Array) + { + ValidateJsonConfigurationValue(value, configuration); + } else + { + Assert.Fail(); + } + } +} \ No newline at end of file diff --git a/libraryValidations/Dotnet/UnknownJsonFieldConverter.cs b/libraryValidations/Dotnet/UnknownJsonFieldConverter.cs new file mode 100644 index 0000000..c9cbcd8 --- /dev/null +++ b/libraryValidations/Dotnet/UnknownJsonFieldConverter.cs @@ -0,0 +1,42 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace DotnetFeatureManagementTests; + +internal class UnknownJsonFieldConverter : JsonConverter +{ + public override object? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + switch (reader.TokenType) + { + case JsonTokenType.String: + return reader.GetString(); + case JsonTokenType.Number: + if (reader.TryGetInt32(out int intValue)) + return intValue; + if (reader.TryGetDouble(out double doubleValue)) + return doubleValue; + break; + case JsonTokenType.True: + return reader.GetBoolean(); + case JsonTokenType.False: + return reader.GetBoolean(); + case JsonTokenType.StartObject: + using (JsonDocument doc = JsonDocument.ParseValue(ref reader)) + { + return doc.RootElement.Clone(); + } + case JsonTokenType.StartArray: + using (JsonDocument doc = JsonDocument.ParseValue(ref reader)) + { + return doc.RootElement.Clone(); + } + } + throw new JsonException("Unknown JSON token type."); + } + + public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) + { + JsonSerializer.Serialize(writer, value, value.GetType(), options); + } +} diff --git a/libraryValidations/Python/test_json_validations.py b/libraryValidations/Python/test_json_validations.py index b6ab5db..16911d7 100644 --- a/libraryValidations/Python/test_json_validations.py +++ b/libraryValidations/Python/test_json_validations.py @@ -3,6 +3,7 @@ # Licensed under the MIT License. See License.txt in the project root for # license information. # -------------------------------------------------------------------------- + import logging import json import unittest @@ -16,10 +17,12 @@ IS_ENABLED_KEY = "IsEnabled" GET_VARIANT_KEY = "Variant" RESULT_KEY = "Result" +VARIANT_NAME_KEY = "Name" +CONFIGURATION_VALUE_KEY = "ConfigurationValue" FEATURE_FLAG_NAME_KEY = "FeatureFlagName" INPUTS_KEY = "Inputs" -USER_KEY = "user" -GROUPS_KEY = "groups" +USER_KEY = "User" +GROUPS_KEY = "Groups" EXCEPTION_KEY = "Exception" DESCRIPTION_KEY = "Description" @@ -70,6 +73,7 @@ def test_basic_variant(self): test_key = "BasicVariant" self.run_tests(test_key) + # method: is_enabled def test_variant_assignment(self): test_key = "VariantAssignment" @@ -115,11 +119,15 @@ def run_tests(self, test_key): expected_message = is_enabled.get(EXCEPTION_KEY) assert str(ex_info.value) == expected_message, failed_description - if get_variant is not None and get_variant[RESULT_KEY]: + if get_variant is not None and RESULT_KEY in get_variant: user = feature_flag_test[INPUTS_KEY].get(USER_KEY, None) groups = feature_flag_test[INPUTS_KEY].get(GROUPS_KEY, []) variant = feature_manager.get_variant(feature_flag_test[FEATURE_FLAG_NAME_KEY], TargetingContext(user_id=user, groups=groups)) - if not variant: - logger.error(f"Variant is None for {feature_flag_id}") - assert False, failed_description - assert variant.configuration == get_variant[RESULT_KEY], failed_description + + if get_variant[RESULT_KEY] == None: + assert variant == None + else: + if VARIANT_NAME_KEY in get_variant[RESULT_KEY]: + assert variant.name == get_variant[RESULT_KEY][VARIANT_NAME_KEY], failed_description + + assert variant.configuration == get_variant[RESULT_KEY][CONFIGURATION_VALUE_KEY], failed_description diff --git a/libraryValidations/Python/test_json_validations_with_provider.py b/libraryValidations/Python/test_json_validations_with_provider.py index 7464d49..835db5d 100644 --- a/libraryValidations/Python/test_json_validations_with_provider.py +++ b/libraryValidations/Python/test_json_validations_with_provider.py @@ -19,10 +19,12 @@ IS_ENABLED_KEY = "IsEnabled" GET_VARIANT_KEY = "Variant" RESULT_KEY = "Result" +VARIANT_NAME_KEY = "Name" +CONFIGURATION_VALUE_KEY = "ConfigurationValue" FEATURE_FLAG_NAME_KEY = "FeatureFlagName" INPUTS_KEY = "Inputs" -USER_KEY = "user" -GROUPS_KEY = "groups" +USER_KEY = "User" +GROUPS_KEY = "Groups" EXCEPTION_KEY = "Exception" DESCRIPTION_KEY = "Description" @@ -97,15 +99,17 @@ def run_tests(self, test_key, track_event_mock): groups = feature_flag_test[INPUTS_KEY].get(GROUPS_KEY, []) variant = feature_manager.get_variant(feature_flag_test[FEATURE_FLAG_NAME_KEY], TargetingContext(user_id=user, groups=groups)) assert variant, failed_description - assert variant.configuration == get_variant[RESULT_KEY], failed_description + if VARIANT_NAME_KEY in get_variant[RESULT_KEY]: + assert variant.name == get_variant[RESULT_KEY][VARIANT_NAME_KEY], failed_description + assert variant.configuration == get_variant[RESULT_KEY][CONFIGURATION_VALUE_KEY], failed_description if telemetry: assert track_event_mock.called assert track_event_mock.call_count == 2 - assert track_event_mock.call_args[0][0] == telemetry["event_name"] + assert track_event_mock.call_args[0][0] == telemetry["EventName"] event = track_event_mock.call_args[0][1] - event_properties = telemetry["event_properties"] + event_properties = telemetry["EventProperties"] connection_string = os.getenv("APP_CONFIG_VALIDATION_CONNECTION_STRING") endpoint = endpoint_from_connection_string(connection_string) diff --git a/libraryValidations/Spring/validation-tests/pom.xml b/libraryValidations/Spring/validation-tests/pom.xml index a2b4d19..b13988a 100644 --- a/libraryValidations/Spring/validation-tests/pom.xml +++ b/libraryValidations/Spring/validation-tests/pom.xml @@ -37,7 +37,7 @@ com.azure.spring spring-cloud-azure-feature-management - 5.15.0 + 5.17.0 diff --git a/libraryValidations/Spring/validation-tests/src/test/java/com/microsoft/validation_tests/ValidationTestsApplicationTests.java b/libraryValidations/Spring/validation-tests/src/test/java/com/microsoft/validation_tests/ValidationTestsApplicationTests.java index cb0ad24..c266cdd 100644 --- a/libraryValidations/Spring/validation-tests/src/test/java/com/microsoft/validation_tests/ValidationTestsApplicationTests.java +++ b/libraryValidations/Spring/validation-tests/src/test/java/com/microsoft/validation_tests/ValidationTestsApplicationTests.java @@ -31,9 +31,9 @@ class ValidationTestsApplicationTests { static final String TEST_FILE_POSTFIX = ".tests.json"; - private final String inputsUser = "user"; + private final String inputsUser = "User"; - private final String inputsGroups = "groups"; + private final String inputsGroups = "Groups"; @Autowired private FeatureManager featureManager; diff --git a/libraryValidations/Spring/validation-tests/src/test/java/com/microsoft/validation_tests/models/ValidationTestCase.java b/libraryValidations/Spring/validation-tests/src/test/java/com/microsoft/validation_tests/models/ValidationTestCase.java index bc0c243..218d1c5 100644 --- a/libraryValidations/Spring/validation-tests/src/test/java/com/microsoft/validation_tests/models/ValidationTestCase.java +++ b/libraryValidations/Spring/validation-tests/src/test/java/com/microsoft/validation_tests/models/ValidationTestCase.java @@ -9,7 +9,7 @@ public class ValidationTestCase { private String featureFlagName; private LinkedHashMap inputs; private IsEnabled isEnabled; - private Variant variant; + private VariantResult variant; private String description; /** @@ -71,14 +71,14 @@ public void setIsEnabled(IsEnabled isEnabled) { /** * @return variant * */ - public Variant getVariant() { + public VariantResult getVariant() { return variant; } /** * @param variant the variant of test case * */ - public void setVariant(Variant variant) { + public void setVariant(VariantResult variant) { this.variant = variant; } diff --git a/libraryValidations/Spring/validation-tests/src/test/java/com/microsoft/validation_tests/models/Variant.java b/libraryValidations/Spring/validation-tests/src/test/java/com/microsoft/validation_tests/models/Variant.java index 2bcb4b9..16c8981 100644 --- a/libraryValidations/Spring/validation-tests/src/test/java/com/microsoft/validation_tests/models/Variant.java +++ b/libraryValidations/Spring/validation-tests/src/test/java/com/microsoft/validation_tests/models/Variant.java @@ -3,34 +3,34 @@ package com.microsoft.validation_tests.models; public class Variant { - private String result; - private String exception; + private String name; + private Object configurationValue; /** - * @return result + * @return name * */ - public String getResult() { - return result; + public String getName() { + return name; } /** - * @param result the result of variant feature flag + * @param name the name of variant feature flag * */ - public void setResult(String result) { - this.result = result; + public void setName(String name) { + this.name = name; } /** - * @return exception + * @return configurationValue * */ - public String getException() { - return exception; + public Object getConfigurationValue() { + return configurationValue; } /** - * @param exception the exception message throws when run variant test case + * @param configurationValue the configurationValue of the variant * */ - public void setException(String exception) { - this.exception = exception; + public void setConfigurationValue(Object exception) { + this.configurationValue = exception; } } diff --git a/libraryValidations/Spring/validation-tests/src/test/java/com/microsoft/validation_tests/models/VariantResult.java b/libraryValidations/Spring/validation-tests/src/test/java/com/microsoft/validation_tests/models/VariantResult.java new file mode 100644 index 0000000..e45590c --- /dev/null +++ b/libraryValidations/Spring/validation-tests/src/test/java/com/microsoft/validation_tests/models/VariantResult.java @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.microsoft.validation_tests.models; + +public class VariantResult { + private Variant result; + private String exception; + + /** + * @return result + * */ + public Variant getResult() { + return result; + } + + /** + * @param result the variant result of variant feature flag + * */ + public void setResult(Variant result) { + this.result = result; + } + + /** + * @return exception + * */ + public String getException() { + return exception; + } + + /** + * @param exception the exception message throws when run variant test case + * */ + public void setException(String exception) { + this.exception = exception; + } +} diff --git a/libraryValidations/run_all_tests.ps1 b/libraryValidations/run_all_tests.ps1 new file mode 100644 index 0000000..c2961ff --- /dev/null +++ b/libraryValidations/run_all_tests.ps1 @@ -0,0 +1,17 @@ +# Navigate to the Dotnet directory and run dotnet test +Set-Location -Path "./Dotnet" +dotnet test + +# Navigate to the Python directory and run pytest +Set-Location -Path "../Python" +python -m venv venv +.\venv\Scripts\activate.ps1 +pip install -r requirements.txt +pytest +deactivate + +# Navigate to the Spring directory and run mvn test +Set-Location -Path "../Spring/validation-tests" +mvn test + +Set-Location -Path "../.." \ No newline at end of file From 5050dacffd248b27173e1242967b1c218fc57612 Mon Sep 17 00:00:00 2001 From: zhiyuanliang Date: Fri, 1 Nov 2024 12:19:01 +0800 Subject: [PATCH 06/14] remove package-lock.json --- .../JavaScript/package-lock.json | 1250 ----------------- libraryValidations/run_all_tests.ps1 | 6 + 2 files changed, 6 insertions(+), 1250 deletions(-) delete mode 100644 libraryValidations/JavaScript/package-lock.json diff --git a/libraryValidations/JavaScript/package-lock.json b/libraryValidations/JavaScript/package-lock.json deleted file mode 100644 index d0f15e2..0000000 --- a/libraryValidations/JavaScript/package-lock.json +++ /dev/null @@ -1,1250 +0,0 @@ -{ - "name": "JavaScript", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "dependencies": { - "@microsoft/feature-management": "latest", - "@types/chai-as-promised": "^8.0.1", - "@types/mocha": "^10.0.6", - "@types/node": "^20.10.7", - "chai": "^5.1.2", - "chai-as-promised": "^8.0.0", - "mocha": "^10.2.0", - "rimraf": "^5.0.5", - "tslib": "^2.6.2", - "typescript": "^5.3.3" - } - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/@microsoft/feature-management": { - "version": "2.0.0-preview.2", - "resolved": "https://registry.npmjs.org/@microsoft/feature-management/-/feature-management-2.0.0-preview.2.tgz", - "integrity": "sha512-MK//1d20yz6ZvQO+2+y3ROGH6vFa/CgPQvYNQqwwJmOnATo86Cl1yYJ2TPlrM0g87EWXFyv7kzCDWiNM4sqTFQ==" - }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@types/chai": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.0.1.tgz", - "integrity": "sha512-5T8ajsg3M/FOncpLYW7sdOcD6yf4+722sze/tc4KQV0P8Z2rAr3SAuHCIkYmYpt8VbcQlnz8SxlOlPQYefe4cA==", - "dependencies": { - "@types/deep-eql": "*" - } - }, - "node_modules/@types/chai-as-promised": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-8.0.1.tgz", - "integrity": "sha512-dAlDhLjJlABwAVYObo9TPWYTRg9NaQM5CXeaeJYcYAkvzUf0JRLIiog88ao2Wqy/20WUnhbbUZcgvngEbJ3YXQ==", - "dependencies": { - "@types/chai": "*" - } - }, - "node_modules/@types/deep-eql": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", - "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==" - }, - "node_modules/@types/mocha": { - "version": "10.0.9", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.9.tgz", - "integrity": "sha512-sicdRoWtYevwxjOHNMPTl3vSfJM6oyW8o1wXeI7uww6b6xHg8eBznQDNSGBCDJmsE8UMxP05JgZRtsKbTqt//Q==" - }, - "node_modules/@types/node": { - "version": "20.17.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.3.tgz", - "integrity": "sha512-tSQrmKKatLDGnG92h40GD7FzUt0MjahaHwOME4VAFeeA/Xopayq5qLyQRy7Jg/pjgKIFBXuKcGhJo+UdYG55jQ==", - "dependencies": { - "undici-types": "~6.19.2" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "node_modules/assertion-error": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", - "engines": { - "node": ">=12" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==" - }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/chai": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.2.tgz", - "integrity": "sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==", - "dependencies": { - "assertion-error": "^2.0.1", - "check-error": "^2.1.1", - "deep-eql": "^5.0.1", - "loupe": "^3.1.0", - "pathval": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/chai-as-promised": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-8.0.0.tgz", - "integrity": "sha512-sMsGXTrS3FunP/wbqh/KxM8Kj/aLPXQGkNtvE5wPfSToq8wkkvBpTZo1LIiEVmC4BwkKpag+l5h/20lBMk6nUg==", - "dependencies": { - "check-error": "^2.0.0" - }, - "peerDependencies": { - "chai": ">= 2.1.2 < 6" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/check-error": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", - "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", - "engines": { - "node": ">= 16" - } - }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/deep-eql": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", - "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", - "engines": { - "node": ">=6" - } - }, - "node_modules/diff": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", - "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "bin": { - "flat": "cli.js" - } - }, - "node_modules/foreground-child": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "bin": { - "he": "bin/he" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "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.", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" - }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/loupe": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.2.tgz", - "integrity": "sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==" - }, - "node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" - }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/mocha": { - "version": "10.8.1", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.1.tgz", - "integrity": "sha512-WxSpEWgF03HfgNKBuysfK40DUaOSVX5zxgLDoieMGO+zyE69iq2eQ1vBypvIJ5mOPKpuVAqWiTbt4Orj7L6wVw==", - "dependencies": { - "ansi-colors": "^4.1.3", - "browser-stdout": "^1.3.1", - "chokidar": "^3.5.3", - "debug": "^4.3.5", - "diff": "^5.2.0", - "escape-string-regexp": "^4.0.0", - "find-up": "^5.0.0", - "glob": "^8.1.0", - "he": "^1.2.0", - "js-yaml": "^4.1.0", - "log-symbols": "^4.1.0", - "minimatch": "^5.1.6", - "ms": "^2.1.3", - "serialize-javascript": "^6.0.2", - "strip-json-comments": "^3.1.1", - "supports-color": "^8.1.1", - "workerpool": "^6.5.1", - "yargs": "^16.2.0", - "yargs-parser": "^20.2.9", - "yargs-unparser": "^2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha.js" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/mocha/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==" - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/pathval": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", - "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", - "engines": { - "node": ">= 14.16" - } - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "5.0.10", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", - "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", - "dependencies": { - "glob": "^10.3.7" - }, - "bin": { - "rimraf": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "engines": { - "node": ">=8" - } - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tslib": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz", - "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==" - }, - "node_modules/typescript": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", - "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/workerpool": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", - "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==" - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/libraryValidations/run_all_tests.ps1 b/libraryValidations/run_all_tests.ps1 index c2961ff..e2b96eb 100644 --- a/libraryValidations/run_all_tests.ps1 +++ b/libraryValidations/run_all_tests.ps1 @@ -14,4 +14,10 @@ deactivate Set-Location -Path "../Spring/validation-tests" mvn test +# Navigate to the JavaScript directory and run test +Set-Location -Path "../JavaScript" +npm install +npm run build +npm run test + Set-Location -Path "../.." \ No newline at end of file From fa14233fd2ad34907d044fdeeac83a92ddf2f17b Mon Sep 17 00:00:00 2001 From: zhiyuanliang Date: Fri, 1 Nov 2024 12:19:35 +0800 Subject: [PATCH 07/14] update gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 4cc1121..264319f 100644 --- a/.gitignore +++ b/.gitignore @@ -409,5 +409,7 @@ venv/ mvnw* target/ +package-lock.json + # JavaScript bundler folder out/ \ No newline at end of file From c2ea91f194c6fa664014e5fbbdba767224973337 Mon Sep 17 00:00:00 2001 From: zhiyuanliang Date: Fri, 1 Nov 2024 12:44:29 +0800 Subject: [PATCH 08/14] add variant feature flag test --- .../JavaScript/validation.test.ts | 51 +++++++++++++++++-- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/libraryValidations/JavaScript/validation.test.ts b/libraryValidations/JavaScript/validation.test.ts index 3774e55..a07fcb0 100644 --- a/libraryValidations/JavaScript/validation.test.ts +++ b/libraryValidations/JavaScript/validation.test.ts @@ -14,8 +14,8 @@ const SAMPLE_JSON_KEY = ".sample.json" const TESTS_JSON_KEY = ".tests.json" interface IContext { - user?: string; - groups?: string[]; + User?: string; + Groups?: string[]; } interface IsEnabledResult { @@ -23,10 +23,21 @@ interface IsEnabledResult { Exception?: string; } +interface Variant { + Name?: string; + ConfigurationValue?: any; +} + +interface GetVariantResult { + Result?: null | Variant; + Exception?: string; +} + interface FeatureFlagTest { FeatureFlagName: string; Inputs?: IContext; IsEnabled?: IsEnabledResult; + Variant?: GetVariantResult; Description?: string; } @@ -38,7 +49,7 @@ async function runTest(testName: string) { for (const testcase of testcases){ const featureFlagName = testcase.FeatureFlagName; - const context = { userId: testcase.Inputs?.user, groups: testcase.Inputs?.groups }; + const context = { userId: testcase.Inputs?.User, groups: testcase.Inputs?.Groups }; if (testcase.IsEnabled) { if (testcase.IsEnabled.Exception !== undefined) { @@ -55,6 +66,33 @@ async function runTest(testName: string) { expect(await fm.isEnabled(featureFlagName, context)).to.eq(testcase.IsEnabled.Result === "true"); } } + + if (testcase.Variant){ + if (testcase.Variant.Exception !== undefined) { + try { + await fm.getVariant(featureFlagName, context); + expect.fail("It should throw exception."); + } + catch (error) { + // TODO: Verify the error message after we unify it across libraries + // expect(error.message).to.include(testcase.IsEnabled.Exception); + } + } + else { + const variant = await fm.getVariant(featureFlagName, context); + if (testcase.Variant.Result === null) { + expect(variant).to.be.undefined; + } + else { + if (testcase.Variant.Result?.Name) { + expect(variant?.name).to.eq(testcase.Variant.Result.Name); + } + if (testcase.Variant.Result?.ConfigurationValue) { + expect(variant?.configuration).to.deep.eq(testcase.Variant.Result.ConfigurationValue); + } + } + } + } } } @@ -83,4 +121,11 @@ describe("feature manager", function () { await runTest("TargetingFilter.modified"); }); + it("should pass BasicVariant test", async () => { + await runTest("BasicVariant"); + }); + + it("should pass VariantAssignment test", async () => { + await runTest("VariantAssignment"); + }); }); \ No newline at end of file From 5d5f061a5cb72b65aaff523b3b046b6ddb79b57d Mon Sep 17 00:00:00 2001 From: zhiyuanliang Date: Fri, 1 Nov 2024 12:44:50 +0800 Subject: [PATCH 09/14] update string to boolean --- Samples/BasicVariant.sample.json | 6 +++--- Samples/VariantAssignment.sample.json | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Samples/BasicVariant.sample.json b/Samples/BasicVariant.sample.json index 8f67188..b787443 100644 --- a/Samples/BasicVariant.sample.json +++ b/Samples/BasicVariant.sample.json @@ -4,7 +4,7 @@ { "id": "Variant_Override_True", "description": "", - "enabled": "true", + "enabled": true, "conditions": { "client_filters": [] }, @@ -23,7 +23,7 @@ { "id": "Variant_Override_False", "description": "", - "enabled": "false", + "enabled": false, "conditions": { "client_filters": [] }, @@ -42,7 +42,7 @@ { "id": "TestVariants", "description": "", - "enabled": "true", + "enabled": true, "allocation": { "user": [ { diff --git a/Samples/VariantAssignment.sample.json b/Samples/VariantAssignment.sample.json index fc9d10b..cadd89c 100644 --- a/Samples/VariantAssignment.sample.json +++ b/Samples/VariantAssignment.sample.json @@ -4,7 +4,7 @@ { "id": "UserAssignedVariant", "description": "", - "enabled": "true", + "enabled": true, "allocation": { "user": [ { @@ -36,7 +36,7 @@ { "id": "GroupAssignedVariant", "description": "", - "enabled": "true", + "enabled": true, "allocation": { "group": [ { @@ -67,7 +67,7 @@ { "id": "AllocationAssignedVariant", "description": "", - "enabled": "true", + "enabled": true, "allocation": { "percentile": [ { @@ -96,7 +96,7 @@ { "id": "ComplexAssignment", "description": "", - "enabled": "true", + "enabled": true, "allocation": { "user": [ { From 372a08b45dce7e845804f1bf0ca69eacec516581 Mon Sep 17 00:00:00 2001 From: zhiyuanliang Date: Wed, 6 Nov 2024 17:55:52 +0800 Subject: [PATCH 10/14] update code ql & gitignore --- .github/workflows/codeql.yml | 2 ++ .gitignore | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index a01b1ba..126b07c 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -49,6 +49,8 @@ jobs: build-mode: none # This mode only analyzes Java. Set this to 'autobuild' or 'manual' to analyze Kotlin too. - language: python build-mode: none + - language: javascript-typescript + build-mode: none # CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' # Use `c-cpp` to analyze code written in C, C++ or both # Use 'java-kotlin' to analyze code written in Java, Kotlin or both diff --git a/.gitignore b/.gitignore index 264319f..633122a 100644 --- a/.gitignore +++ b/.gitignore @@ -412,4 +412,5 @@ target/ package-lock.json # JavaScript bundler folder -out/ \ No newline at end of file +out/ +*.tgz \ No newline at end of file From 6a6ccb1c4d0d6339ea7d4037bb8f4dfe004ea8e6 Mon Sep 17 00:00:00 2001 From: zhiyuanliang Date: Fri, 8 Nov 2024 01:18:03 +0800 Subject: [PATCH 11/14] add telemetry test with provider --- .../Dotnet/Properties/launchSettings.json | 10 -- libraryValidations/JavaScript/package.json | 9 +- .../JavaScript/validation.test.ts | 165 +++++++++++++++++- 3 files changed, 169 insertions(+), 15 deletions(-) delete mode 100644 libraryValidations/Dotnet/Properties/launchSettings.json diff --git a/libraryValidations/Dotnet/Properties/launchSettings.json b/libraryValidations/Dotnet/Properties/launchSettings.json deleted file mode 100644 index 0bed4f3..0000000 --- a/libraryValidations/Dotnet/Properties/launchSettings.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "profiles": { - "Dotnet": { - "commandName": "Project", - "environmentVariables": { - "APP_CONFIG_VALIDATION_CONNECTION_STRING": "Endpoint=https://appconfig4ndakx7twshlm.azconfig.io;Id=A3jj;Secret=1WWpbi6jB5Bw9sYAvrHfSteqInR0UCZhwA2ynipVN1LcutGRncMyJQQJ99AJACYeBjFAArohAAACAZACIycQ" - } - } - } -} \ No newline at end of file diff --git a/libraryValidations/JavaScript/package.json b/libraryValidations/JavaScript/package.json index 817dcf9..1c04180 100644 --- a/libraryValidations/JavaScript/package.json +++ b/libraryValidations/JavaScript/package.json @@ -6,15 +6,20 @@ "test": "mocha out/*.test.{js,cjs,mjs} --parallel" }, "dependencies": { + "@types/chai-as-promised": "^8.0.1", "@types/mocha": "^10.0.6", "@types/node": "^20.10.7", - "@types/chai-as-promised": "^8.0.1", + "@types/sinon": "^17.0.1", "chai": "^5.1.2", "chai-as-promised": "^8.0.0", "mocha": "^10.2.0", "rimraf": "^5.0.5", + "sinon": "^15.2.0", "tslib": "^2.6.2", "typescript": "^5.3.3", - "@microsoft/feature-management": "latest" + "@microsoft/feature-management": "latest", + "@microsoft/feature-management-applicationinsights-browser": "latest", + "@azure/app-configuration-provider": "latest", + "@microsoft/applicationinsights-web": "^3.3.4" } } \ No newline at end of file diff --git a/libraryValidations/JavaScript/validation.test.ts b/libraryValidations/JavaScript/validation.test.ts index a07fcb0..b1014c6 100644 --- a/libraryValidations/JavaScript/validation.test.ts +++ b/libraryValidations/JavaScript/validation.test.ts @@ -3,12 +3,26 @@ import * as fs from "node:fs/promises"; import * as chai from "chai"; +import * as sinon from "sinon"; import chaiAsPromised from "chai-as-promised"; - chai.use(chaiAsPromised); -import { FeatureManager, ConfigurationObjectFeatureFlagProvider } from "@microsoft/feature-management"; const expect = chai.expect; +import { load } from "@azure/app-configuration-provider"; +import { FeatureManager, ConfigurationObjectFeatureFlagProvider, ConfigurationMapFeatureFlagProvider } from "@microsoft/feature-management"; +import { createTelemetryPublisher } from "@microsoft/feature-management-applicationinsights-browser" ; + +import { ApplicationInsights } from "@microsoft/applicationinsights-web"; +const appInsights = new ApplicationInsights({ config: { connectionString: "DUMMY-CONNECTION-STRING" }}); +// For telemetry validation +let eventToValidate; +let eventPropertiesToValidate; +sinon.stub(appInsights, "trackEvent").callsFake((event, customProperties) => { + eventToValidate = event; + eventPropertiesToValidate = customProperties; +}); + + const FILE_PATH = "../../Samples/" const SAMPLE_JSON_KEY = ".sample.json" const TESTS_JSON_KEY = ".tests.json" @@ -33,11 +47,31 @@ interface GetVariantResult { Exception?: string; } +interface FeatureEvaluationEventProperties { + FeatureName?: string; + Enabled?: string; + Version?: string; + Variant?: string; + VariantAssignmentReason?: string; + VariantAssignmentPercentage?: string; + DefaultWhenEnabled?: string; + AllocationId?: string; + FeatureFlagId?: string; + FeatureFlagReference?: string; + TargetingId?: string; +} + +interface TelemetryResult { + EventName?: string; + EventProperties?: FeatureEvaluationEventProperties; +} + interface FeatureFlagTest { FeatureFlagName: string; Inputs?: IContext; IsEnabled?: IsEnabledResult; Variant?: GetVariantResult; + Telemetry?: TelemetryResult; Description?: string; } @@ -94,7 +128,124 @@ async function runTest(testName: string) { } } } -} +} + +async function runTestWithProvider(testName: string) { + const connectionString = process.env["APP_CONFIG_VALIDATION_CONNECTION_STRING"]; + if (connectionString !== undefined) { + const config = await load( + connectionString, + { + featureFlagOptions: { + enabled: true, + selectors: [ + { + keyFilter: "*" + } + ] + } + }); + const testcases: FeatureFlagTest[] = JSON.parse(await fs.readFile(FILE_PATH + testName + TESTS_JSON_KEY, "utf8")); + const ffProvider = new ConfigurationMapFeatureFlagProvider(config); + + const fm = new FeatureManager(ffProvider, { onFeatureEvaluated: createTelemetryPublisher(appInsights) }); + for (const testcase of testcases){ + const featureFlagName = testcase.FeatureFlagName; + const context = { userId: testcase.Inputs?.User, groups: testcase.Inputs?.Groups }; + + if (testcase.IsEnabled) { + if (testcase.IsEnabled.Exception !== undefined) { + try { + await fm.isEnabled(featureFlagName, context); + expect.fail("It should throw exception."); + } + catch (error) { + // TODO: Verify the error message after we unify it across libraries + // expect(error.message).to.include(testcase.IsEnabled.Exception); + } + } + else { + expect(await fm.isEnabled(featureFlagName, context)).to.eq(testcase.IsEnabled.Result === "true"); + } + } + + if (testcase.Variant){ + if (testcase.Variant.Exception !== undefined) { + try { + await fm.getVariant(featureFlagName, context); + expect.fail("It should throw exception."); + } + catch (error) { + // TODO: Verify the error message after we unify it across libraries + // expect(error.message).to.include(testcase.IsEnabled.Exception); + } + } + else { + const variant = await fm.getVariant(featureFlagName, context); + if (testcase.Variant.Result === null) { + expect(variant).to.be.undefined; + } + else { + if (testcase.Variant.Result?.Name) { + expect(variant?.name).to.eq(testcase.Variant.Result.Name); + } + if (testcase.Variant.Result?.ConfigurationValue) { + expect(variant?.configuration).to.deep.eq(testcase.Variant.Result.ConfigurationValue); + } + } + } + } + + if (testcase.Telemetry?.EventName) { + expect(eventToValidate.name).to.eq(testcase.Telemetry.EventName); + } + + const eventProperties = testcase.Telemetry?.EventProperties; + if (eventProperties) { + if (eventProperties.FeatureName) { + expect(eventPropertiesToValidate["FeatureName"]).to.eq(eventProperties.FeatureName); + } + if (eventProperties.Enabled) { + expect(eventPropertiesToValidate["Enabled"]).to.eq(eventProperties.Enabled); + } + if (eventProperties.Version) { + expect(eventPropertiesToValidate["Version"]).to.eq(eventProperties.Version); + } + if (eventProperties.Variant) { + expect(eventPropertiesToValidate["Variant"]).to.eq(eventProperties.Variant); + } + if (eventProperties.VariantAssignmentReason) { + expect(eventPropertiesToValidate["VariantAssignmentReason"]).to.eq(eventProperties.VariantAssignmentReason); + } + if (eventProperties.VariantAssignmentPercentage) { + expect(eventPropertiesToValidate["VariantAssignmentPercentage"]).to.eq(eventProperties.VariantAssignmentPercentage); + } + if (eventProperties.DefaultWhenEnabled) { + expect(eventPropertiesToValidate["DefaultWhenEnabled"]).to.eq(eventProperties.DefaultWhenEnabled); + } + if (eventProperties.AllocationId) { + expect(eventPropertiesToValidate["AllocationId"]).to.eq(eventProperties.AllocationId); + } + if (eventProperties.FeatureFlagId) { + expect(eventPropertiesToValidate["FeatureFlagId"]).to.eq(eventProperties.FeatureFlagId); + } + if (eventProperties.FeatureFlagReference) { + const endpointMatch = connectionString.match(/Endpoint=([^;]+)/); + if (endpointMatch) { + expect(eventPropertiesToValidate["FeatureFlagReference"]).to.eq(endpointMatch[1] + eventProperties.FeatureFlagReference); + } + else { + expect.fail("Connection string does not contain endpoint."); + } + } + if (eventProperties.TargetingId) { + expect(eventPropertiesToValidate["TargetingId"]).to.eq(eventProperties.TargetingId); + } + } + + } + } +} describe("feature manager", function () { it("should pass NoFilters test", async () => { @@ -128,4 +279,12 @@ describe("feature manager", function () { it("should pass VariantAssignment test", async () => { await runTest("VariantAssignment"); }); + + it("should pass ProviderTelemetry test", async () => { + await runTestWithProvider("ProviderTelemetry"); + }); + + it("should pass ProviderTelemetryComplete test", async () => { + await runTestWithProvider("ProviderTelemetryComplete"); + }); }); \ No newline at end of file From 376e6bbc16981a4117ede5811200490910de179a Mon Sep 17 00:00:00 2001 From: zhiyuanliang Date: Fri, 8 Nov 2024 01:36:13 +0800 Subject: [PATCH 12/14] update --- .../JavaScript/validation.test.ts | 195 +++++++++--------- 1 file changed, 98 insertions(+), 97 deletions(-) diff --git a/libraryValidations/JavaScript/validation.test.ts b/libraryValidations/JavaScript/validation.test.ts index b1014c6..6cb27bc 100644 --- a/libraryValidations/JavaScript/validation.test.ts +++ b/libraryValidations/JavaScript/validation.test.ts @@ -132,117 +132,118 @@ async function runTest(testName: string) { async function runTestWithProvider(testName: string) { const connectionString = process.env["APP_CONFIG_VALIDATION_CONNECTION_STRING"]; - if (connectionString !== undefined) { - const config = await load( - connectionString, - { - featureFlagOptions: { - enabled: true, - selectors: [ - { - keyFilter: "*" - } - ] - } - }); - const testcases: FeatureFlagTest[] = JSON.parse(await fs.readFile(FILE_PATH + testName + TESTS_JSON_KEY, "utf8")); - const ffProvider = new ConfigurationMapFeatureFlagProvider(config); - - const fm = new FeatureManager(ffProvider, { onFeatureEvaluated: createTelemetryPublisher(appInsights) }); - for (const testcase of testcases){ - const featureFlagName = testcase.FeatureFlagName; - const context = { userId: testcase.Inputs?.User, groups: testcase.Inputs?.Groups }; - - if (testcase.IsEnabled) { - if (testcase.IsEnabled.Exception !== undefined) { - try { - await fm.isEnabled(featureFlagName, context); - expect.fail("It should throw exception."); - } - catch (error) { - // TODO: Verify the error message after we unify it across libraries - // expect(error.message).to.include(testcase.IsEnabled.Exception); + if (connectionString === undefined) { + console.log("Skipping test as environment variable APP_CONFIG_VALIDATION_CONNECTION_STRING is not set."); + return; + } + const config = await load( + connectionString, + { + featureFlagOptions: { + enabled: true, + selectors: [ + { + keyFilter: "*" } + ] + } + }); + const testcases: FeatureFlagTest[] = JSON.parse(await fs.readFile(FILE_PATH + testName + TESTS_JSON_KEY, "utf8")); + const ffProvider = new ConfigurationMapFeatureFlagProvider(config); + + const fm = new FeatureManager(ffProvider, { onFeatureEvaluated: createTelemetryPublisher(appInsights) }); + for (const testcase of testcases){ + const featureFlagName = testcase.FeatureFlagName; + const context = { userId: testcase.Inputs?.User, groups: testcase.Inputs?.Groups }; + + if (testcase.IsEnabled) { + if (testcase.IsEnabled.Exception !== undefined) { + try { + await fm.isEnabled(featureFlagName, context); + expect.fail("It should throw exception."); } - else { - expect(await fm.isEnabled(featureFlagName, context)).to.eq(testcase.IsEnabled.Result === "true"); + catch (error) { + // TODO: Verify the error message after we unify it across libraries + // expect(error.message).to.include(testcase.IsEnabled.Exception); } + } + else { + expect(await fm.isEnabled(featureFlagName, context)).to.eq(testcase.IsEnabled.Result === "true"); } - - if (testcase.Variant){ - if (testcase.Variant.Exception !== undefined) { - try { - await fm.getVariant(featureFlagName, context); - expect.fail("It should throw exception."); - } - catch (error) { - // TODO: Verify the error message after we unify it across libraries - // expect(error.message).to.include(testcase.IsEnabled.Exception); - } + } + + if (testcase.Variant){ + if (testcase.Variant.Exception !== undefined) { + try { + await fm.getVariant(featureFlagName, context); + expect.fail("It should throw exception."); + } + catch (error) { + // TODO: Verify the error message after we unify it across libraries + // expect(error.message).to.include(testcase.IsEnabled.Exception); + } + } + else { + const variant = await fm.getVariant(featureFlagName, context); + if (testcase.Variant.Result === null) { + expect(variant).to.be.undefined; } else { - const variant = await fm.getVariant(featureFlagName, context); - if (testcase.Variant.Result === null) { - expect(variant).to.be.undefined; - } - else { - if (testcase.Variant.Result?.Name) { - expect(variant?.name).to.eq(testcase.Variant.Result.Name); - } - if (testcase.Variant.Result?.ConfigurationValue) { - expect(variant?.configuration).to.deep.eq(testcase.Variant.Result.ConfigurationValue); - } + if (testcase.Variant.Result?.Name) { + expect(variant?.name).to.eq(testcase.Variant.Result.Name); + } + if (testcase.Variant.Result?.ConfigurationValue) { + expect(variant?.configuration).to.deep.eq(testcase.Variant.Result.ConfigurationValue); } } } + } - if (testcase.Telemetry?.EventName) { - expect(eventToValidate.name).to.eq(testcase.Telemetry.EventName); - } + if (testcase.Telemetry?.EventName) { + expect(eventToValidate.name).to.eq(testcase.Telemetry.EventName); + } - const eventProperties = testcase.Telemetry?.EventProperties; - if (eventProperties) { - if (eventProperties.FeatureName) { - expect(eventPropertiesToValidate["FeatureName"]).to.eq(eventProperties.FeatureName); - } - if (eventProperties.Enabled) { - expect(eventPropertiesToValidate["Enabled"]).to.eq(eventProperties.Enabled); - } - if (eventProperties.Version) { - expect(eventPropertiesToValidate["Version"]).to.eq(eventProperties.Version); - } - if (eventProperties.Variant) { - expect(eventPropertiesToValidate["Variant"]).to.eq(eventProperties.Variant); - } - if (eventProperties.VariantAssignmentReason) { - expect(eventPropertiesToValidate["VariantAssignmentReason"]).to.eq(eventProperties.VariantAssignmentReason); - } - if (eventProperties.VariantAssignmentPercentage) { - expect(eventPropertiesToValidate["VariantAssignmentPercentage"]).to.eq(eventProperties.VariantAssignmentPercentage); - } - if (eventProperties.DefaultWhenEnabled) { - expect(eventPropertiesToValidate["DefaultWhenEnabled"]).to.eq(eventProperties.DefaultWhenEnabled); - } - if (eventProperties.AllocationId) { - expect(eventPropertiesToValidate["AllocationId"]).to.eq(eventProperties.AllocationId); - } - if (eventProperties.FeatureFlagId) { - expect(eventPropertiesToValidate["FeatureFlagId"]).to.eq(eventProperties.FeatureFlagId); - } - if (eventProperties.FeatureFlagReference) { - const endpointMatch = connectionString.match(/Endpoint=([^;]+)/); - if (endpointMatch) { - expect(eventPropertiesToValidate["FeatureFlagReference"]).to.eq(endpointMatch[1] + eventProperties.FeatureFlagReference); - } - else { - expect.fail("Connection string does not contain endpoint."); - } + const eventProperties = testcase.Telemetry?.EventProperties; + if (eventProperties) { + if (eventProperties.FeatureName) { + expect(eventPropertiesToValidate["FeatureName"]).to.eq(eventProperties.FeatureName); + } + if (eventProperties.Enabled) { + expect(eventPropertiesToValidate["Enabled"]).to.eq(eventProperties.Enabled); + } + if (eventProperties.Version) { + expect(eventPropertiesToValidate["Version"]).to.eq(eventProperties.Version); + } + if (eventProperties.Variant) { + expect(eventPropertiesToValidate["Variant"]).to.eq(eventProperties.Variant); + } + if (eventProperties.VariantAssignmentReason) { + expect(eventPropertiesToValidate["VariantAssignmentReason"]).to.eq(eventProperties.VariantAssignmentReason); + } + if (eventProperties.VariantAssignmentPercentage) { + expect(eventPropertiesToValidate["VariantAssignmentPercentage"]).to.eq(eventProperties.VariantAssignmentPercentage); + } + if (eventProperties.DefaultWhenEnabled) { + expect(eventPropertiesToValidate["DefaultWhenEnabled"]).to.eq(eventProperties.DefaultWhenEnabled); + } + if (eventProperties.AllocationId) { + expect(eventPropertiesToValidate["AllocationId"]).to.eq(eventProperties.AllocationId); + } + if (eventProperties.FeatureFlagId) { + expect(eventPropertiesToValidate["FeatureFlagId"]).to.eq(eventProperties.FeatureFlagId); + } + if (eventProperties.FeatureFlagReference) { + const endpointMatch = connectionString.match(/Endpoint=([^;]+)/); + if (endpointMatch) { + expect(eventPropertiesToValidate["FeatureFlagReference"]).to.eq(endpointMatch[1] + eventProperties.FeatureFlagReference); } - if (eventProperties.TargetingId) { - expect(eventPropertiesToValidate["TargetingId"]).to.eq(eventProperties.TargetingId); + else { + expect.fail("Connection string does not contain endpoint."); } } - + if (eventProperties.TargetingId) { + expect(eventPropertiesToValidate["TargetingId"]).to.eq(eventProperties.TargetingId); + } } } } From fa3b7bb5cf8fff7aa594123d13095f405289020f Mon Sep 17 00:00:00 2001 From: Zhiyuan Liang Date: Fri, 8 Nov 2024 14:56:42 +0800 Subject: [PATCH 13/14] validate latest packages --- .../featureEvaluationValidation.test.ts | 51 +++ libraryValidations/JavaScript/package.json | 10 +- .../telemetryWithProviderValidation.test.ts | 106 +++++++ libraryValidations/JavaScript/tsconfig.json | 1 + libraryValidations/JavaScript/utils.ts | 158 ++++++++++ .../JavaScript/validation.test.ts | 291 ------------------ 6 files changed, 322 insertions(+), 295 deletions(-) create mode 100644 libraryValidations/JavaScript/featureEvaluationValidation.test.ts create mode 100644 libraryValidations/JavaScript/telemetryWithProviderValidation.test.ts create mode 100644 libraryValidations/JavaScript/utils.ts delete mode 100644 libraryValidations/JavaScript/validation.test.ts diff --git a/libraryValidations/JavaScript/featureEvaluationValidation.test.ts b/libraryValidations/JavaScript/featureEvaluationValidation.test.ts new file mode 100644 index 0000000..f9ac7b5 --- /dev/null +++ b/libraryValidations/JavaScript/featureEvaluationValidation.test.ts @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import * as fs from "node:fs/promises"; +import { FeatureManager, ConfigurationObjectFeatureFlagProvider } from "@microsoft/feature-management"; +import {FILE_PATH, SAMPLE_JSON_KEY, TESTS_JSON_KEY, validateFeatureEvaluation, FeatureFlagTest } from "./utils.js"; + +async function runTest(testName: string) { + const config = JSON.parse(await fs.readFile(FILE_PATH + testName + SAMPLE_JSON_KEY, "utf8")); + const testcases: FeatureFlagTest[] = JSON.parse(await fs.readFile(FILE_PATH + testName + TESTS_JSON_KEY, "utf8")); + const ffProvider = new ConfigurationObjectFeatureFlagProvider(config); + const fm = new FeatureManager(ffProvider); + + for (const testcase of testcases){ + validateFeatureEvaluation(testcase, fm); + } +} + +describe("feature evaluation validation", function () { + it("should pass NoFilters test", async () => { + await runTest("NoFilters"); + }); + + it("should pass RequirementType test", async () => { + await runTest("RequirementType"); + }); + + it("should pass RequirementType test", async () => { + await runTest("RequirementType"); + }); + + it("should pass TimeWindowFilter test", async () => { + await runTest("TimeWindowFilter"); + }); + + it("should pass TargetingFilter test", async () => { + await runTest("TargetingFilter"); + }); + + it("should pass TargetingFilter.modified test", async () => { + await runTest("TargetingFilter.modified"); + }); + + it("should pass BasicVariant test", async () => { + await runTest("BasicVariant"); + }); + + it("should pass VariantAssignment test", async () => { + await runTest("VariantAssignment"); + }); +}); diff --git a/libraryValidations/JavaScript/package.json b/libraryValidations/JavaScript/package.json index 1c04180..850e257 100644 --- a/libraryValidations/JavaScript/package.json +++ b/libraryValidations/JavaScript/package.json @@ -17,9 +17,11 @@ "sinon": "^15.2.0", "tslib": "^2.6.2", "typescript": "^5.3.3", - "@microsoft/feature-management": "latest", - "@microsoft/feature-management-applicationinsights-browser": "latest", - "@azure/app-configuration-provider": "latest", - "@microsoft/applicationinsights-web": "^3.3.4" + "@microsoft/feature-management": "file:./microsoft-feature-management-2.0.0-preview.3.tgz", + "@microsoft/feature-management-applicationinsights-browser": "file:./microsoft-feature-management-applicationinsights-browser-2.0.0-preview.3.tgz", + "@microsoft/feature-management-applicationinsights-node": "file:./microsoft-feature-management-applicationinsights-node-2.0.0-preview.3.tgz", + "@azure/app-configuration-provider": "file:./azure-app-configuration-provider-2.0.0-preview.1.tgz", + "@microsoft/applicationinsights-web": "^3.3.4", + "applicationinsights": "^2.9.6" } } \ No newline at end of file diff --git a/libraryValidations/JavaScript/telemetryWithProviderValidation.test.ts b/libraryValidations/JavaScript/telemetryWithProviderValidation.test.ts new file mode 100644 index 0000000..edd37af --- /dev/null +++ b/libraryValidations/JavaScript/telemetryWithProviderValidation.test.ts @@ -0,0 +1,106 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import * as sinon from "sinon"; +import * as fs from "node:fs/promises"; +import { load } from "@azure/app-configuration-provider"; +import { FeatureManager, ConfigurationMapFeatureFlagProvider } from "@microsoft/feature-management"; +import { createTelemetryPublisher as createNodeTelemetryPublisher } from "@microsoft/feature-management-applicationinsights-node"; +import { createTelemetryPublisher as createBrowserTelemetryPublisher } from "@microsoft/feature-management-applicationinsights-browser"; +import {FILE_PATH, TESTS_JSON_KEY, FeatureFlagTest, validateFeatureEvaluation, validateTelemetryWithProvider } from "./utils.js"; +import { ApplicationInsights } from "@microsoft/applicationinsights-web"; +import applicationInsights from "applicationinsights"; + +// For telemetry validation +let eventNameToValidate; +let eventPropertiesToValidate; + +applicationInsights.setup("DUMMY-CONNECTION-STRING").start(); +sinon.stub(applicationInsights.defaultClient, "trackEvent").callsFake((event) => { + eventNameToValidate = event.name; + eventPropertiesToValidate = event.properties; +}); + +const appInsights = new ApplicationInsights({ config: { connectionString: "DUMMY-CONNECTION-STRING" }}); +sinon.stub(appInsights, "trackEvent").callsFake((event, customProperties) => { + eventNameToValidate = event.name; + eventPropertiesToValidate = customProperties; +}); + +async function runTestWithProviderAndNodePackage(testName: string) { + const connectionString = process.env["APP_CONFIG_VALIDATION_CONNECTION_STRING"]; + if (connectionString === undefined) { + console.log("Skipping test as environment variable APP_CONFIG_VALIDATION_CONNECTION_STRING is not set."); + return; + } + const config = await load( + connectionString, + { + featureFlagOptions: { + enabled: true, + selectors: [ + { + keyFilter: "*" + } + ] + } + }); + const testcases: FeatureFlagTest[] = JSON.parse(await fs.readFile(FILE_PATH + testName + TESTS_JSON_KEY, "utf8")); + const ffProvider = new ConfigurationMapFeatureFlagProvider(config); + const fm = new FeatureManager(ffProvider, { onFeatureEvaluated: createNodeTelemetryPublisher(applicationInsights.defaultClient) }); + for (const testcase of testcases){ + const featureFlagName = testcase.FeatureFlagName; + const context = { userId: testcase.Inputs?.User, groups: testcase.Inputs?.Groups }; + await fm.getVariant(featureFlagName, context); + validateTelemetryWithProvider(testcase, connectionString, eventNameToValidate, eventPropertiesToValidate); + } +} + +async function runTestWithProviderAndBrowserPackage(testName: string) { + const connectionString = process.env["APP_CONFIG_VALIDATION_CONNECTION_STRING"]; + if (connectionString === undefined) { + console.log("Skipping test as environment variable APP_CONFIG_VALIDATION_CONNECTION_STRING is not set."); + return; + } + const config = await load( + connectionString, + { + featureFlagOptions: { + enabled: true, + selectors: [ + { + keyFilter: "*" + } + ] + } + }); + const testcases: FeatureFlagTest[] = JSON.parse(await fs.readFile(FILE_PATH + testName + TESTS_JSON_KEY, "utf8")); + const ffProvider = new ConfigurationMapFeatureFlagProvider(config); + const fm = new FeatureManager(ffProvider, { onFeatureEvaluated: createBrowserTelemetryPublisher(appInsights) }); + for (const testcase of testcases){ + const featureFlagName = testcase.FeatureFlagName; + const context = { userId: testcase.Inputs?.User, groups: testcase.Inputs?.Groups }; + await fm.getVariant(featureFlagName, context); + validateTelemetryWithProvider(testcase, connectionString, eventNameToValidate, eventPropertiesToValidate); + } +} + +describe("telemetry with provider and node package", function () { + it("should pass ProviderTelemetry test", async () => { + await runTestWithProviderAndNodePackage("ProviderTelemetry"); + }); + + it("should pass ProviderTelemetryComplete test", async () => { + await runTestWithProviderAndNodePackage("ProviderTelemetryComplete"); + }); +}); + +describe("telemetry with provider and browser package", function () { + it("should pass ProviderTelemetry test", async () => { + await runTestWithProviderAndBrowserPackage("ProviderTelemetry"); + }); + + it("should pass ProviderTelemetryComplete test", async () => { + await runTestWithProviderAndBrowserPackage("ProviderTelemetryComplete"); + }); +}); \ No newline at end of file diff --git a/libraryValidations/JavaScript/tsconfig.json b/libraryValidations/JavaScript/tsconfig.json index 7e7342d..33c7907 100644 --- a/libraryValidations/JavaScript/tsconfig.json +++ b/libraryValidations/JavaScript/tsconfig.json @@ -13,6 +13,7 @@ "strictFunctionTypes": true, "sourceMap": true, "inlineSources": true, + "esModuleInterop": true, "outDir": "./out" }, "exclude": [ diff --git a/libraryValidations/JavaScript/utils.ts b/libraryValidations/JavaScript/utils.ts new file mode 100644 index 0000000..05633c8 --- /dev/null +++ b/libraryValidations/JavaScript/utils.ts @@ -0,0 +1,158 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import * as chai from "chai"; +import chaiAsPromised from "chai-as-promised"; +chai.use(chaiAsPromised); +const expect = chai.expect; + +import { FeatureManager } from "@microsoft/feature-management"; + +export const FILE_PATH = "../../Samples/" +export const SAMPLE_JSON_KEY = ".sample.json" +export const TESTS_JSON_KEY = ".tests.json" + +interface IContext { + User?: string; + Groups?: string[]; +} + +interface IsEnabledResult { + Result?: string; + Exception?: string; +} + +interface Variant { + Name?: string; + ConfigurationValue?: any; +} + +interface GetVariantResult { + Result?: null | Variant; + Exception?: string; +} + +interface FeatureEvaluationEventProperties { + FeatureName?: string; + Enabled?: string; + Version?: string; + Variant?: string; + VariantAssignmentReason?: string; + VariantAssignmentPercentage?: string; + DefaultWhenEnabled?: string; + AllocationId?: string; + FeatureFlagId?: string; + FeatureFlagReference?: string; + TargetingId?: string; +} + +interface TelemetryResult { + EventName?: string; + EventProperties?: FeatureEvaluationEventProperties; +} + +export interface FeatureFlagTest { + FeatureFlagName: string; + Inputs?: IContext; + IsEnabled?: IsEnabledResult; + Variant?: GetVariantResult; + Telemetry?: TelemetryResult; + Description?: string; +} + +export async function validateFeatureEvaluation(testcase: FeatureFlagTest, featureManager: FeatureManager) { + const featureFlagName = testcase.FeatureFlagName; + const context = { userId: testcase.Inputs?.User, groups: testcase.Inputs?.Groups }; + + if (testcase.IsEnabled) { + if (testcase.IsEnabled.Exception !== undefined) { + try { + await featureManager.isEnabled(featureFlagName, context); + expect.fail("It should throw exception."); + } + catch (error) { + // TODO: Verify the error message after we unify it across libraries + // expect(error.message).to.include(testcase.IsEnabled.Exception); + } + } + else { + expect(await featureManager.isEnabled(featureFlagName, context)).to.eq(testcase.IsEnabled.Result === "true"); + } + } + + if (testcase.Variant){ + if (testcase.Variant.Exception !== undefined) { + try { + await featureManager.getVariant(featureFlagName, context); + expect.fail("It should throw exception."); + } + catch (error) { + // TODO: Verify the error message after we unify it across libraries + // expect(error.message).to.include(testcase.IsEnabled.Exception); + } + } + else { + const variant = await featureManager.getVariant(featureFlagName, context); + if (testcase.Variant.Result === null) { + expect(variant).to.be.undefined; + } + else { + if (testcase.Variant.Result?.Name) { + expect(variant?.name).to.eq(testcase.Variant.Result.Name); + } + if (testcase.Variant.Result?.ConfigurationValue) { + expect(variant?.configuration).to.deep.eq(testcase.Variant.Result.ConfigurationValue); + } + } + } + } +} + +export function validateTelemetryWithProvider(testcase: FeatureFlagTest, connectionString: string, eventNameToValidate: string, eventPropertiesToValidate: any) { + // if (testcase.Telemetry?.EventName) { + // expect(eventNameToValidate).to.eq(testcase.Telemetry.EventName); + // } + + const eventProperties = testcase.Telemetry?.EventProperties; + if (eventProperties) { + if (eventProperties.FeatureName) { + expect(eventPropertiesToValidate["FeatureName"]).to.eq(eventProperties.FeatureName); + } + if (eventProperties.Enabled) { + expect(eventPropertiesToValidate["Enabled"]).to.eq(eventProperties.Enabled); + } + if (eventProperties.Version) { + expect(eventPropertiesToValidate["Version"]).to.eq(eventProperties.Version); + } + if (eventProperties.Variant) { + expect(eventPropertiesToValidate["Variant"]).to.eq(eventProperties.Variant); + } + if (eventProperties.VariantAssignmentReason) { + expect(eventPropertiesToValidate["VariantAssignmentReason"]).to.eq(eventProperties.VariantAssignmentReason); + } + if (eventProperties.VariantAssignmentPercentage) { + expect(eventPropertiesToValidate["VariantAssignmentPercentage"]).to.eq(eventProperties.VariantAssignmentPercentage); + } + if (eventProperties.DefaultWhenEnabled) { + expect(eventPropertiesToValidate["DefaultWhenEnabled"]).to.eq(eventProperties.DefaultWhenEnabled); + } + if (eventProperties.AllocationId) { + expect(eventPropertiesToValidate["AllocationId"]).to.eq(eventProperties.AllocationId); + } + if (eventProperties.FeatureFlagId) { + expect(eventPropertiesToValidate["FeatureFlagId"]).to.eq(eventProperties.FeatureFlagId); + } + if (eventProperties.FeatureFlagReference) { + const endpointMatch = connectionString.match(/Endpoint=([^;]+)/); + if (endpointMatch) { + expect(eventPropertiesToValidate["FeatureFlagReference"]).to.eq(endpointMatch[1] + eventProperties.FeatureFlagReference); + } + else { + expect.fail("Connection string does not contain endpoint."); + } + } + if (eventProperties.TargetingId) { + expect(eventPropertiesToValidate["TargetingId"]).to.eq(eventProperties.TargetingId); + } + } +} \ No newline at end of file diff --git a/libraryValidations/JavaScript/validation.test.ts b/libraryValidations/JavaScript/validation.test.ts deleted file mode 100644 index 6cb27bc..0000000 --- a/libraryValidations/JavaScript/validation.test.ts +++ /dev/null @@ -1,291 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import * as fs from "node:fs/promises"; -import * as chai from "chai"; -import * as sinon from "sinon"; -import chaiAsPromised from "chai-as-promised"; -chai.use(chaiAsPromised); -const expect = chai.expect; - -import { load } from "@azure/app-configuration-provider"; -import { FeatureManager, ConfigurationObjectFeatureFlagProvider, ConfigurationMapFeatureFlagProvider } from "@microsoft/feature-management"; -import { createTelemetryPublisher } from "@microsoft/feature-management-applicationinsights-browser" ; - -import { ApplicationInsights } from "@microsoft/applicationinsights-web"; -const appInsights = new ApplicationInsights({ config: { connectionString: "DUMMY-CONNECTION-STRING" }}); -// For telemetry validation -let eventToValidate; -let eventPropertiesToValidate; -sinon.stub(appInsights, "trackEvent").callsFake((event, customProperties) => { - eventToValidate = event; - eventPropertiesToValidate = customProperties; -}); - - -const FILE_PATH = "../../Samples/" -const SAMPLE_JSON_KEY = ".sample.json" -const TESTS_JSON_KEY = ".tests.json" - -interface IContext { - User?: string; - Groups?: string[]; -} - -interface IsEnabledResult { - Result?: string; - Exception?: string; -} - -interface Variant { - Name?: string; - ConfigurationValue?: any; -} - -interface GetVariantResult { - Result?: null | Variant; - Exception?: string; -} - -interface FeatureEvaluationEventProperties { - FeatureName?: string; - Enabled?: string; - Version?: string; - Variant?: string; - VariantAssignmentReason?: string; - VariantAssignmentPercentage?: string; - DefaultWhenEnabled?: string; - AllocationId?: string; - FeatureFlagId?: string; - FeatureFlagReference?: string; - TargetingId?: string; -} - -interface TelemetryResult { - EventName?: string; - EventProperties?: FeatureEvaluationEventProperties; -} - -interface FeatureFlagTest { - FeatureFlagName: string; - Inputs?: IContext; - IsEnabled?: IsEnabledResult; - Variant?: GetVariantResult; - Telemetry?: TelemetryResult; - Description?: string; -} - -async function runTest(testName: string) { - const config = JSON.parse(await fs.readFile(FILE_PATH + testName + SAMPLE_JSON_KEY, "utf8")); - const testcases: FeatureFlagTest[] = JSON.parse(await fs.readFile(FILE_PATH + testName + TESTS_JSON_KEY, "utf8")); - const ffProvider = new ConfigurationObjectFeatureFlagProvider(config); - const fm = new FeatureManager(ffProvider); - - for (const testcase of testcases){ - const featureFlagName = testcase.FeatureFlagName; - const context = { userId: testcase.Inputs?.User, groups: testcase.Inputs?.Groups }; - - if (testcase.IsEnabled) { - if (testcase.IsEnabled.Exception !== undefined) { - try { - await fm.isEnabled(featureFlagName, context); - expect.fail("It should throw exception."); - } - catch (error) { - // TODO: Verify the error message after we unify it across libraries - // expect(error.message).to.include(testcase.IsEnabled.Exception); - } - } - else { - expect(await fm.isEnabled(featureFlagName, context)).to.eq(testcase.IsEnabled.Result === "true"); - } - } - - if (testcase.Variant){ - if (testcase.Variant.Exception !== undefined) { - try { - await fm.getVariant(featureFlagName, context); - expect.fail("It should throw exception."); - } - catch (error) { - // TODO: Verify the error message after we unify it across libraries - // expect(error.message).to.include(testcase.IsEnabled.Exception); - } - } - else { - const variant = await fm.getVariant(featureFlagName, context); - if (testcase.Variant.Result === null) { - expect(variant).to.be.undefined; - } - else { - if (testcase.Variant.Result?.Name) { - expect(variant?.name).to.eq(testcase.Variant.Result.Name); - } - if (testcase.Variant.Result?.ConfigurationValue) { - expect(variant?.configuration).to.deep.eq(testcase.Variant.Result.ConfigurationValue); - } - } - } - } - } -} - -async function runTestWithProvider(testName: string) { - const connectionString = process.env["APP_CONFIG_VALIDATION_CONNECTION_STRING"]; - if (connectionString === undefined) { - console.log("Skipping test as environment variable APP_CONFIG_VALIDATION_CONNECTION_STRING is not set."); - return; - } - const config = await load( - connectionString, - { - featureFlagOptions: { - enabled: true, - selectors: [ - { - keyFilter: "*" - } - ] - } - }); - const testcases: FeatureFlagTest[] = JSON.parse(await fs.readFile(FILE_PATH + testName + TESTS_JSON_KEY, "utf8")); - const ffProvider = new ConfigurationMapFeatureFlagProvider(config); - - const fm = new FeatureManager(ffProvider, { onFeatureEvaluated: createTelemetryPublisher(appInsights) }); - for (const testcase of testcases){ - const featureFlagName = testcase.FeatureFlagName; - const context = { userId: testcase.Inputs?.User, groups: testcase.Inputs?.Groups }; - - if (testcase.IsEnabled) { - if (testcase.IsEnabled.Exception !== undefined) { - try { - await fm.isEnabled(featureFlagName, context); - expect.fail("It should throw exception."); - } - catch (error) { - // TODO: Verify the error message after we unify it across libraries - // expect(error.message).to.include(testcase.IsEnabled.Exception); - } - } - else { - expect(await fm.isEnabled(featureFlagName, context)).to.eq(testcase.IsEnabled.Result === "true"); - } - } - - if (testcase.Variant){ - if (testcase.Variant.Exception !== undefined) { - try { - await fm.getVariant(featureFlagName, context); - expect.fail("It should throw exception."); - } - catch (error) { - // TODO: Verify the error message after we unify it across libraries - // expect(error.message).to.include(testcase.IsEnabled.Exception); - } - } - else { - const variant = await fm.getVariant(featureFlagName, context); - if (testcase.Variant.Result === null) { - expect(variant).to.be.undefined; - } - else { - if (testcase.Variant.Result?.Name) { - expect(variant?.name).to.eq(testcase.Variant.Result.Name); - } - if (testcase.Variant.Result?.ConfigurationValue) { - expect(variant?.configuration).to.deep.eq(testcase.Variant.Result.ConfigurationValue); - } - } - } - } - - if (testcase.Telemetry?.EventName) { - expect(eventToValidate.name).to.eq(testcase.Telemetry.EventName); - } - - const eventProperties = testcase.Telemetry?.EventProperties; - if (eventProperties) { - if (eventProperties.FeatureName) { - expect(eventPropertiesToValidate["FeatureName"]).to.eq(eventProperties.FeatureName); - } - if (eventProperties.Enabled) { - expect(eventPropertiesToValidate["Enabled"]).to.eq(eventProperties.Enabled); - } - if (eventProperties.Version) { - expect(eventPropertiesToValidate["Version"]).to.eq(eventProperties.Version); - } - if (eventProperties.Variant) { - expect(eventPropertiesToValidate["Variant"]).to.eq(eventProperties.Variant); - } - if (eventProperties.VariantAssignmentReason) { - expect(eventPropertiesToValidate["VariantAssignmentReason"]).to.eq(eventProperties.VariantAssignmentReason); - } - if (eventProperties.VariantAssignmentPercentage) { - expect(eventPropertiesToValidate["VariantAssignmentPercentage"]).to.eq(eventProperties.VariantAssignmentPercentage); - } - if (eventProperties.DefaultWhenEnabled) { - expect(eventPropertiesToValidate["DefaultWhenEnabled"]).to.eq(eventProperties.DefaultWhenEnabled); - } - if (eventProperties.AllocationId) { - expect(eventPropertiesToValidate["AllocationId"]).to.eq(eventProperties.AllocationId); - } - if (eventProperties.FeatureFlagId) { - expect(eventPropertiesToValidate["FeatureFlagId"]).to.eq(eventProperties.FeatureFlagId); - } - if (eventProperties.FeatureFlagReference) { - const endpointMatch = connectionString.match(/Endpoint=([^;]+)/); - if (endpointMatch) { - expect(eventPropertiesToValidate["FeatureFlagReference"]).to.eq(endpointMatch[1] + eventProperties.FeatureFlagReference); - } - else { - expect.fail("Connection string does not contain endpoint."); - } - } - if (eventProperties.TargetingId) { - expect(eventPropertiesToValidate["TargetingId"]).to.eq(eventProperties.TargetingId); - } - } - } -} - -describe("feature manager", function () { - it("should pass NoFilters test", async () => { - await runTest("NoFilters"); - }); - - it("should pass RequirementType test", async () => { - await runTest("RequirementType"); - }); - - it("should pass RequirementType test", async () => { - await runTest("RequirementType"); - }); - - it("should pass TimeWindowFilter test", async () => { - await runTest("TimeWindowFilter"); - }); - - it("should pass TargetingFilter test", async () => { - await runTest("TargetingFilter"); - }); - - it("should pass TargetingFilter.modified test", async () => { - await runTest("TargetingFilter.modified"); - }); - - it("should pass BasicVariant test", async () => { - await runTest("BasicVariant"); - }); - - it("should pass VariantAssignment test", async () => { - await runTest("VariantAssignment"); - }); - - it("should pass ProviderTelemetry test", async () => { - await runTestWithProvider("ProviderTelemetry"); - }); - - it("should pass ProviderTelemetryComplete test", async () => { - await runTestWithProvider("ProviderTelemetryComplete"); - }); -}); \ No newline at end of file From 8c2a0e300a6f097b1da2494921ec427ab5aabf15 Mon Sep 17 00:00:00 2001 From: Zhiyuan Liang Date: Fri, 8 Nov 2024 15:52:04 +0800 Subject: [PATCH 14/14] update --- libraryValidations/JavaScript/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraryValidations/JavaScript/package.json b/libraryValidations/JavaScript/package.json index 850e257..8824aab 100644 --- a/libraryValidations/JavaScript/package.json +++ b/libraryValidations/JavaScript/package.json @@ -17,10 +17,10 @@ "sinon": "^15.2.0", "tslib": "^2.6.2", "typescript": "^5.3.3", - "@microsoft/feature-management": "file:./microsoft-feature-management-2.0.0-preview.3.tgz", - "@microsoft/feature-management-applicationinsights-browser": "file:./microsoft-feature-management-applicationinsights-browser-2.0.0-preview.3.tgz", - "@microsoft/feature-management-applicationinsights-node": "file:./microsoft-feature-management-applicationinsights-node-2.0.0-preview.3.tgz", - "@azure/app-configuration-provider": "file:./azure-app-configuration-provider-2.0.0-preview.1.tgz", + "@microsoft/feature-management": "2.0.0-preview.3", + "@microsoft/feature-management-applicationinsights-browser": "2.0.0-preview.3", + "@microsoft/feature-management-applicationinsights-node": "2.0.0-preview.3", + "@azure/app-configuration-provider": "2.0.0-preview.1", "@microsoft/applicationinsights-web": "^3.3.4", "applicationinsights": "^2.9.6" }