From 6dff4a1f7610acf49d582f64fc3f2e98ec346dd6 Mon Sep 17 00:00:00 2001 From: "pragya.dave" Date: Mon, 1 Jun 2026 15:35:42 +0530 Subject: [PATCH] WIP: LWC engine POC --- package-lock.json | 1839 ++++++++++++++++- packages/code-analyzer-lwc-engine/README.md | 14 + .../eslint.config.mjs | 16 + .../code-analyzer-lwc-engine/package.json | 69 + .../code-analyzer-lwc-engine/src/bundle.ts | 35 + .../code-analyzer-lwc-engine/src/compile.ts | 190 ++ .../code-analyzer-lwc-engine/src/engine.ts | 85 + .../code-analyzer-lwc-engine/src/index.ts | 8 + .../code-analyzer-lwc-engine/src/messages.ts | 16 + .../code-analyzer-lwc-engine/src/plugin.ts | 20 + .../code-analyzer-lwc-engine/src/rules.ts | 113 + .../code-analyzer-lwc-engine/src/severity.ts | 20 + .../code-analyzer-lwc-engine/src/translate.ts | 18 + .../test/bundle.test.ts | 32 + .../test/engine.test.ts | 83 + .../test/severity.test.ts | 18 + .../test/test-data/lwc/bad/bad.js | 7 + .../test/test-data/lwc/good/good.js | 2 + .../test/translate.test.ts | 39 + .../tsconfig.build.json | 17 + .../code-analyzer-lwc-engine/tsconfig.json | 11 + 21 files changed, 2613 insertions(+), 39 deletions(-) create mode 100644 packages/code-analyzer-lwc-engine/README.md create mode 100644 packages/code-analyzer-lwc-engine/eslint.config.mjs create mode 100644 packages/code-analyzer-lwc-engine/package.json create mode 100644 packages/code-analyzer-lwc-engine/src/bundle.ts create mode 100644 packages/code-analyzer-lwc-engine/src/compile.ts create mode 100644 packages/code-analyzer-lwc-engine/src/engine.ts create mode 100644 packages/code-analyzer-lwc-engine/src/index.ts create mode 100644 packages/code-analyzer-lwc-engine/src/messages.ts create mode 100644 packages/code-analyzer-lwc-engine/src/plugin.ts create mode 100644 packages/code-analyzer-lwc-engine/src/rules.ts create mode 100644 packages/code-analyzer-lwc-engine/src/severity.ts create mode 100644 packages/code-analyzer-lwc-engine/src/translate.ts create mode 100644 packages/code-analyzer-lwc-engine/test/bundle.test.ts create mode 100644 packages/code-analyzer-lwc-engine/test/engine.test.ts create mode 100644 packages/code-analyzer-lwc-engine/test/severity.test.ts create mode 100644 packages/code-analyzer-lwc-engine/test/test-data/lwc/bad/bad.js create mode 100644 packages/code-analyzer-lwc-engine/test/test-data/lwc/good/good.js create mode 100644 packages/code-analyzer-lwc-engine/test/translate.test.ts create mode 100644 packages/code-analyzer-lwc-engine/tsconfig.build.json create mode 100644 packages/code-analyzer-lwc-engine/tsconfig.json diff --git a/package-lock.json b/package-lock.json index 97dc9106..90abd39b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -132,10 +132,12 @@ } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.27.3", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz", + "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==", "license": "MIT", "dependencies": { - "@babel/types": "^7.27.3" + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -201,29 +203,170 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-plugin-utils": { + "node_modules/@babel/helper-create-class-features-plugin/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/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz", + "integrity": "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "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.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-module-transforms/node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz", + "integrity": "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.29.7.tgz", + "integrity": "sha512-16AMiW26DbXWBbr3B8wNozKM0ydMLB892vaOaJW/fPJdnT8vJk5sdkQcU/isqUxyCE0cEoa8wZOcbgDuC4b6Og==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-wrap-function": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz", + "integrity": "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz", + "integrity": "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==", "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -304,6 +447,21 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-decorators": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.28.6.tgz", + "integrity": "sha512-71EYI0ONURHJBL4rSFXnITXqXrrY8q4P0q006DPfN+Rk+ASM+++IBXem/ruokgBZR8YNEWZ8R6B+rCb8VcUTqA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-import-attributes": { "version": "7.27.1", "devOptional": true, @@ -454,6 +612,69 @@ "devOptional": true, "license": "MIT", "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.0.tgz", + "integrity": "sha512-va0VdWro4zlBr2JsXC+ofCPB2iG12wPtVGTWFx2WLDOM3nYQZZIGP82qku2eW/JR83sD+k2k+CsNtyEbUqhU6w==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-remap-async-to-generator": "^7.27.1", + "@babel/traverse": "^7.29.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.28.6.tgz", + "integrity": "sha512-ilTRcmbuXjsMmcZ3HASTe4caH5Tpo93PkTxF9oG2VZsSWsahydmcEHhix9Ik122RcTnZnUzPbmux4wh1swfv7g==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-remap-async-to-generator": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator/node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.28.6.tgz", + "integrity": "sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { @@ -463,6 +684,72 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.29.7.tgz", + "integrity": "sha512-iPX8aD6H9zV5s7ZsqTdNocPN/MGQ5sSMnElKrktxjJRMnB2jN/1p2+R7GkfD6CAYoVFqy5A4XnSIUeGgJzIWpg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.29.7.tgz", + "integrity": "sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.6.tgz", + "integrity": "sha512-5rh+JR4JBC4pGkXLAcYdLHZjXudVxWMXbB6u6+E9lRL5TrGVbHt1TjxGbZ8CkmYw9zjkB7jutzOROArsqtncEA==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/plugin-transform-destructuring": "^7.28.5", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.29.7.tgz", + "integrity": "sha512-ZDOBqV/qLYJI0YElr8DcENEyARsFQeESqWXH6gZlghYXuPPjvweuDhP4VyEi4BlUBlLRFZVjxoZDMjxhLW766g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-transform-react-display-name": { "version": "7.28.0", "license": "MIT", @@ -520,6 +807,25 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.29.7.tgz", + "integrity": "sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/plugin-syntax-typescript": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/preset-react": { "version": "7.28.5", "license": "MIT", @@ -576,8 +882,8 @@ "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1486,6 +1792,16 @@ "node": ">=6.0.0" } }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", "license": "MIT" @@ -1688,37 +2004,822 @@ "eslint": "^6 || ^7 || ^8" } }, - "node_modules/@lwc/eslint-plugin-lwc-platform/node_modules/minimatch": { - "version": "5.1.6", + "node_modules/@lwc/eslint-plugin-lwc-platform/node_modules/minimatch": { + "version": "5.1.6", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lwc/eslint-plugin-lwc/node_modules/globals": { + "version": "13.24.0", + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@lwc/eslint-plugin-lwc/node_modules/type-fest": { + "version": "0.20.2", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@lwc/metadata": { + "version": "15.0.5", + "resolved": "https://registry.npmjs.org/@lwc/metadata/-/metadata-15.0.5.tgz", + "integrity": "sha512-HO8ymdwVbKh6xNXUUD0YLcc2gGysbOYqA/bc7pamD+lYKwe5KM7zO4zYiZzUd9QsnGd24wbkSmQoDqWsxUY2zw==", + "license": "SEE LICENSE IN LICENSE.txt", + "dependencies": { + "@babel/parser": "~7.29.0", + "@babel/traverse": "~7.29.0", + "@babel/types": "~7.29.0", + "@lwc/sfdc-compiler-utils": "15.0.5", + "postcss": "~8.5.6", + "postcss-selector-parser": "~7.1.1", + "postcss-value-parser": "~4.2.0" + }, + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "@lwc/errors": ">=9", + "@lwc/template-compiler": ">=9" + } + }, + "node_modules/@lwc/sfdc-compiler-utils": { + "version": "15.0.5", + "resolved": "https://registry.npmjs.org/@lwc/sfdc-compiler-utils/-/sfdc-compiler-utils-15.0.5.tgz", + "integrity": "sha512-uSShL3HF4fUi8NNj/1X2bOGHxuCGcNTx/j3yiPgpbm6j0S45YjN4HpaEp0C2zDzd7Tfv28Z4omGasGdKnEaW0w==", + "license": "SEE LICENSE IN LICENSE.txt", + "engines": { + "node": ">=20" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler": { + "version": "15.0.5", + "resolved": "https://registry.npmjs.org/@lwc/sfdc-lwc-compiler/-/sfdc-lwc-compiler-15.0.5.tgz", + "integrity": "sha512-gsFqgmsmjK5d0bWtl/wzXmEzayPQmqCkcgQmJZ8B8IT47GCrlJRPFLSR3XibBLM6tZLYxKrwYCXBxj/SVbH1lg==", + "license": "SEE LICENSE IN LICENSE.txt", + "dependencies": { + "@babel/core": "7.29.0", + "@babel/parser": "7.29.0", + "@babel/plugin-syntax-decorators": "7.28.6", + "@babel/preset-typescript": "7.28.5", + "@babel/traverse": "7.29.0", + "@babel/types": "7.29.0", + "@komaci/esm-generator": "264.5.0", + "@lwc/dev-server-plugin-lex": "15.0.5", + "@lwc/eslint-plugin-lwc": "3.5.0", + "@lwc/eslint-plugin-lwc-platform": "6.3.0", + "@lwc/metadata": "15.0.5", + "@lwc/sfdc-compiler-utils": "15.0.5", + "@rollup/plugin-babel": "^6.1.0", + "@rollup/plugin-replace": "^6.0.3", + "@rollup/wasm-node": "4.52.5", + "@salesforce/eslint-config-lwc": "4.1.2", + "@salesforce/eslint-plugin-lightning": "2.0.0", + "@swc/wasm": "1.15.21", + "astring": "~1.9.0", + "doctrine": "~3.0.0", + "eslint": "~9.39.3", + "eslint-plugin-import": "~2.32.0", + "gray-matter": "~4.0.3", + "line-column": "~1.0.2", + "magic-string": "~0.30.21", + "markdown-it": "~14.1.1", + "meriyah": "^7.1.0", + "parse5-sax-parser": "~8.0.0", + "postcss": "~8.5.6", + "postcss-selector-parser": "~7.1.1", + "terser": "~5.46.0", + "typescript": "5.9.3" + }, + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "@lwc/compiler": ">=9", + "@lwc/errors": ">=9", + "@lwc/shared": ">=9", + "@lwc/template-compiler": ">=9" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/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", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/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/@lwc/sfdc-lwc-compiler/node_modules/@babel/eslint-parser": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.25.9.tgz", + "integrity": "sha512-5UXfgpK0j0Xr/xIdgdLEhOFxaDZ0bRPWJJchRpqOSur/3rZoPbqqki5mm0p4NE2cs28krBEiSM2MB7//afRSQQ==", + "license": "MIT", + "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/@lwc/sfdc-lwc-compiler/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" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/node_modules/@babel/parser": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/node_modules/@eslint/eslintrc": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", + "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", + "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.1.1", + "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" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/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" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/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" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/node_modules/@eslint/js": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", + "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/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", + "globals": "~15.14.0", + "minimatch": "~9.0.4" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "@babel/eslint-parser": "^7", + "eslint": "^9" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/node_modules/@lwc/eslint-plugin-lwc-platform": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@lwc/eslint-plugin-lwc-platform/-/eslint-plugin-lwc-platform-6.3.0.tgz", + "integrity": "sha512-wlLiHeYureubt/JDhPllXbQcjJu58NMpiSkZMF6KRCBtZzHs4m6cxwpXJ1iy6d638/66O1B79FL3ZTC7v1hDxg==", + "license": "MIT", + "dependencies": { + "minimatch": "~5.1.1" + }, + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "@babel/eslint-parser": "^7", + "eslint": "^9" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/node_modules/@lwc/eslint-plugin-lwc-platform/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" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/node_modules/@salesforce/eslint-config-lwc": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@salesforce/eslint-config-lwc/-/eslint-config-lwc-4.1.2.tgz", + "integrity": "sha512-GMoXOiqdSLYYuup8i6HWJYIScTGyOdgJCXXNzWb76Xa0RehqViigVAroTYB5OKvp4F5T7OLnGq06dARduphauQ==", + "license": "MIT", + "dependencies": { + "@babel/core": "~7.26.0", + "@babel/eslint-parser": "~7.25.9", + "@eslint/js": "^9.17.0", + "eslint-restricted-globals": "~0.2.0", + "globals": "~15.14.0", + "semver": "^7.6.2" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "@lwc/eslint-plugin-lwc": "^3.0.0 || ^3.0.0-0", + "@salesforce/eslint-plugin-lightning": "^2.0.0 || ^2.0.0-0", + "eslint": "^9", + "eslint-plugin-import": "*", + "eslint-plugin-jest": "*" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/node_modules/@salesforce/eslint-config-lwc/node_modules/@babel/core": { + "version": "7.26.10", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.10.tgz", + "integrity": "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==", + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.10", + "@babel/helper-compilation-targets": "^7.26.5", + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helpers": "^7.26.10", + "@babel/parser": "^7.26.10", + "@babel/template": "^7.26.9", + "@babel/traverse": "^7.26.10", + "@babel/types": "^7.26.10", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/node_modules/@salesforce/eslint-config-lwc/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/@lwc/sfdc-lwc-compiler/node_modules/@salesforce/eslint-plugin-lightning": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@salesforce/eslint-plugin-lightning/-/eslint-plugin-lightning-2.0.0.tgz", + "integrity": "sha512-lC3GL2j6B2wAGeTFWT0h47BFg+0R7naqqlQW+ANvNSaIC/qEB+tNSRcdAZ8DRTojsI3GRdpgq3FTB1llbrFBng==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "eslint": "^9" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/node_modules/eslint": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", + "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", + "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.5", + "@eslint/js": "9.39.4", + "@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 + } + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/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", + "array-includes": "^3.1.9", + "array.prototype.findlastindex": "^1.2.6", + "array.prototype.flat": "^1.3.3", + "array.prototype.flatmap": "^1.3.3", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.1", + "hasown": "^2.0.2", + "is-core-module": "^2.16.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.1", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.9", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/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" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/node_modules/eslint-plugin-import/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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/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" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/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" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/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==", + "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" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/node_modules/eslint/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" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/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" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/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", + "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" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/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" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/node_modules/fast-xml-parser": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.8.0.tgz", + "integrity": "sha512-6bIM7fsJxeo3uXv7OncQYsBAMPJ7V16Slahl/6M98C/i2q+vB1+4a0MtrvYwDFEUrwDSbAmeLDRXsOBwrL7yAg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "@nodable/entities": "^2.1.0", + "fast-xml-builder": "^1.2.0", + "path-expression-matcher": "^1.5.0", + "strnum": "^2.3.0", + "xml-naming": "^0.1.0" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/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==", + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/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==", + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/node_modules/globals": { + "version": "15.14.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.14.0.tgz", + "integrity": "sha512-OkToC372DtlQeje9/zHIo5CT8lRP/FUgEOKBEhU4e0abL7J7CD24fD9ohiLN5hagG/kWCYj4K5oaxxtj2Z0Dig==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/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" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/node_modules/meriyah": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/meriyah/-/meriyah-7.1.0.tgz", + "integrity": "sha512-4K/lV+RFSrM8vy9H58FSd+wrxrXlPhYOK8AOaNQ7iFaHugYRx4tHIAaRYLMtXx/spMByZ4S080di6lXSTDI9eg==", + "license": "ISC", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@lwc/sfdc-lwc-compiler/node_modules/strnum": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.3.0.tgz", + "integrity": "sha512-ums3KNd42PGyx5xaoVTO1mjU1bH3NpY4vsrVlnv9PNGqQj8wd7rJ6nEypLrJ7z5vxK5RP0yMLo6J/Gsm62DI5Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, + "node_modules/@lwc/shared": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@lwc/shared/-/shared-9.2.1.tgz", + "integrity": "sha512-IdCbGTUo7SzehrR16RWsF4q2LbYjfSCuvjcejptoHWXsFDGxZbSG/Fh1oXC9D5xhszD2ToFXxlPy5EbyOr8vtQ==", + "license": "MIT", + "engines": { + "node": ">=16.6.0" + } + }, + "node_modules/@lwc/ssr-compiler": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@lwc/ssr-compiler/-/ssr-compiler-9.2.1.tgz", + "integrity": "sha512-0SwvmmUaV4Z5NqwOUQE0KlzhFtTbLKKEXN3UPZQECi7R8U06JSJBeFU2kT7rmBmfrdagu6cFkdDMFVgRiHjW2w==", + "license": "MIT", + "dependencies": { + "@babel/types": "7.29.0", + "@lwc/errors": "9.2.1", + "@lwc/shared": "9.2.1", + "@lwc/template-compiler": "9.2.1", + "acorn": "8.16.0", + "astring": "^1.9.0", + "estree-toolkit": "^1.7.13", + "immer": "^11.1.4", + "meriyah": "^7.1.0" + }, + "engines": { + "node": ">=16.6.0" + } + }, + "node_modules/@lwc/ssr-compiler/node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@lwc/ssr-compiler/node_modules/meriyah": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/meriyah/-/meriyah-7.1.0.tgz", + "integrity": "sha512-4K/lV+RFSrM8vy9H58FSd+wrxrXlPhYOK8AOaNQ7iFaHugYRx4tHIAaRYLMtXx/spMByZ4S080di6lXSTDI9eg==", "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, "engines": { - "node": ">=10" + "node": ">=20.0.0" } }, - "node_modules/@lwc/eslint-plugin-lwc/node_modules/globals": { - "version": "13.24.0", + "node_modules/@lwc/style-compiler": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@lwc/style-compiler/-/style-compiler-9.2.1.tgz", + "integrity": "sha512-IQz3tChWutIUKUo6VDO902L7S9VrnTIwHId1VrX5pND/KaB+LhkQi1oih0LGwYcczVZBTq/AX68XAQclv1Lulg==", "license": "MIT", "dependencies": { - "type-fest": "^0.20.2" + "@lwc/shared": "9.2.1", + "postcss": "~8.5.10", + "postcss-selector-parser": "~7.1.1", + "postcss-value-parser": "~4.2.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=16.6.0" } }, - "node_modules/@lwc/eslint-plugin-lwc/node_modules/type-fest": { - "version": "0.20.2", - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" + "node_modules/@lwc/template-compiler": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@lwc/template-compiler/-/template-compiler-9.2.1.tgz", + "integrity": "sha512-JeWT72QPkNRSeyfbHG8UiHOmtdrcJW6biBygTRlE1aMu+uESxP9F69nfpRlC1ZbD0mBWBOxxwDShINfVzJ4KFw==", + "license": "MIT", + "dependencies": { + "@lwc/errors": "9.2.1", + "@lwc/shared": "9.2.1", + "acorn": "~8.16.0", + "astring": "~1.9.0", + "he": "~1.2.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=16.6.0" } }, "node_modules/@napi-rs/wasm-runtime": { @@ -1746,6 +2847,18 @@ "eslint-scope": "5.1.1" } }, + "node_modules/@nodable/entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-nyT7T3nbMyBI/lvr6L5TyWbFJAI9FTgVRakNoBqCD+PmID8DzFrrNdLLtHMwMszOtqZa8PAOV24ZqDnQrhQINA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/nodable" + } + ], + "license": "MIT" + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "license": "MIT", @@ -1804,6 +2917,106 @@ "url": "https://opencollective.com/pkgr" } }, + "node_modules/@rollup/plugin-babel": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-6.1.0.tgz", + "integrity": "sha512-dFZNuFD2YRcoomP4oYf+DvQNSUA9ih+A3vUqopQx5EdtPGo3WBnQcI/S8pwpz91UsGfL0HsMSOlaMld8HrbubA==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@rollup/pluginutils": "^5.0.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "@types/babel__core": "^7.1.9", + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "@types/babel__core": { + "optional": true + }, + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-replace": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-6.0.3.tgz", + "integrity": "sha512-J4RZarRvQAm5IF0/LwUUg+obsm+xZhYnbMXmXROyoSE1ATJe3oXSb9L5MMppdxP2ylNSjv6zFBwKYjcKMucVfA==", + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "magic-string": "^0.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", + "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@rollup/wasm-node": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/wasm-node/-/wasm-node-4.52.5.tgz", + "integrity": "sha512-ldY4tEzSMBHNwB8TfRpi7RRRjjyfKlwjdebw5pS1lu0xaY3g4RDc6ople2wEYulVOKVeH7ZJwRx0iw4pGtjMHg==", + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, "node_modules/@rtsao/scc": { "version": "1.1.0", "license": "MIT" @@ -1864,6 +3077,10 @@ "resolved": "packages/code-analyzer-flow-engine", "link": true }, + "node_modules/@salesforce/code-analyzer-lwc-engine": { + "resolved": "packages/code-analyzer-lwc-engine", + "link": true + }, "node_modules/@salesforce/code-analyzer-pmd-engine": { "resolved": "packages/code-analyzer-pmd-engine", "link": true @@ -2018,6 +3235,12 @@ "@sinonjs/commons": "^3.0.1" } }, + "node_modules/@swc/wasm": { + "version": "1.15.21", + "resolved": "https://registry.npmjs.org/@swc/wasm/-/wasm-1.15.21.tgz", + "integrity": "sha512-AVomFdpE9LiB8Q0dNo1UqpqGut//Q7HJNyyCzyHsywHSUM/1pKfzywIjdha4WipgjyOPebYb93pTDBUn2iWvVA==", + "license": "Apache-2.0" + }, "node_modules/@tootallnate/quickjs-emscripten": { "version": "0.23.0", "license": "MIT" @@ -2090,6 +3313,15 @@ "version": "1.0.8", "license": "MIT" }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", "devOptional": true, @@ -2446,6 +3678,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2459,6 +3692,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2472,6 +3706,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2485,6 +3720,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2498,6 +3734,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2511,6 +3748,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2524,6 +3762,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2537,6 +3776,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2550,6 +3790,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2589,6 +3830,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2602,6 +3844,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2615,6 +3858,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2628,6 +3872,7 @@ "cpu": [ "s390x" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2641,6 +3886,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2654,6 +3900,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2680,6 +3927,7 @@ "cpu": [ "wasm32" ], + "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -2698,6 +3946,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2711,6 +3960,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2724,6 +3974,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2743,7 +3994,9 @@ } }, "node_modules/acorn": { - "version": "8.15.0", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -3004,6 +4257,15 @@ "version": "0.0.8", "license": "MIT" }, + "node_modules/astring": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz", + "integrity": "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==", + "license": "MIT", + "bin": { + "astring": "bin/astring" + } + }, "node_modules/astronomical": { "version": "3.0.0", "license": "Apache-2.0", @@ -4652,6 +5914,22 @@ "node": ">=4.0" } }, + "node_modules/estree-toolkit": { + "version": "1.7.14", + "resolved": "https://registry.npmjs.org/estree-toolkit/-/estree-toolkit-1.7.14.tgz", + "integrity": "sha512-UD46XPj9xCQ+5r+JRv1qdaJuWLbQaconfnFHWOc20ugbHzZSOO6/A+vye46arVxbOSr/KnzRzKfnp9SJ0IqaUw==", + "license": "MIT", + "dependencies": { + "@types/estree": ">=1.0.8", + "@types/estree-jsx": ">=1.0.5" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, "node_modules/esutils": { "version": "2.0.3", "license": "BSD-2-Clause", @@ -4805,9 +6083,9 @@ "license": "BSD-3-Clause" }, "node_modules/fast-xml-builder": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.4.tgz", - "integrity": "sha512-f2jhpN4Eccy0/Uz9csxh3Nu6q4ErKxf0XIsasomfOihuSUa3/xw6w8dnOtCDgEItQFJG8KyXPzQXzcODDrrbOg==", + "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", @@ -4816,7 +6094,8 @@ ], "license": "MIT", "dependencies": { - "path-expression-matcher": "^1.1.3" + "path-expression-matcher": "^1.5.0", + "xml-naming": "^0.1.0" } }, "node_modules/fast-xml-parser": { @@ -5292,6 +6571,43 @@ "version": "1.4.0", "license": "MIT" }, + "node_modules/gray-matter": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", + "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", + "license": "MIT", + "dependencies": { + "js-yaml": "^3.13.1", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/gray-matter/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/gray-matter/node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/handlebars": { "version": "4.7.9", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", @@ -5705,6 +7021,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "license": "MIT", @@ -5971,6 +7296,24 @@ "version": "2.0.0", "license": "ISC" }, + "node_modules/isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", + "license": "MIT", + "dependencies": { + "isarray": "1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isobject/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", "devOptional": true, @@ -6843,6 +8186,15 @@ "json-buffer": "3.0.1" } }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/language-subtag-registry": { "version": "0.3.23", "license": "CC0-1.0" @@ -6894,6 +8246,25 @@ "devOptional": true, "license": "MIT" }, + "node_modules/linkify-it": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.1.tgz", + "integrity": "sha512-wVoTjP4Q6R0NW5hiZkVJaFZPWgtXfoGF+6LucL3/FtiNjmcHhYjEr5f1Kqjirc1nBW07J/ZuRFumqr2oqccEWg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/markdown-it" + } + ], + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, "node_modules/locate-path": { "version": "6.0.0", "license": "MIT", @@ -6984,6 +8355,15 @@ "yallist": "^3.0.2" } }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, "node_modules/make-dir": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", @@ -7013,6 +8393,29 @@ "tmpl": "1.0.5" } }, + "node_modules/markdown-it": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.1.tgz", + "integrity": "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/match-json": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/match-json/-/match-json-1.3.7.tgz", + "integrity": "sha512-2/GIaio/oVWVHGdKOIbqfgqT5vH91K3c91l6EAsVydMAjB0iGy5PVABicKzNT1VAgHskZHbaZK9q96AmgTEqkw==", + "license": "MIT" + }, "node_modules/math-intrinsics": { "version": "1.1.0", "license": "MIT", @@ -7572,9 +8975,9 @@ } }, "node_modules/path-expression-matcher": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.2.0.tgz", - "integrity": "sha512-DwmPWeFn+tq7TiyJ2CxezCAirXjFxvaiD03npak3cRjlP9+OjTmSy1EpIrEbh+l6JgUundniloMLDQ/6VTdhLQ==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.5.0.tgz", + "integrity": "sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ==", "funding": [ { "type": "github", @@ -7897,6 +9300,53 @@ "node": ">= 0.4" } }, + "node_modules/postcss": { + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" + }, "node_modules/prelude-ls": { "version": "1.2.1", "license": "MIT", @@ -8035,6 +9485,15 @@ "node": ">=6" } }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/pure-rand": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", @@ -8700,7 +10159,6 @@ }, "node_modules/source-map": { "version": "0.6.1", - "devOptional": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -8735,7 +10193,6 @@ }, "node_modules/sprintf-js": { "version": "1.0.3", - "devOptional": true, "license": "BSD-3-Clause" }, "node_modules/stack-utils": { @@ -8985,7 +10442,16 @@ "devOptional": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=8" + } + }, + "node_modules/strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, "node_modules/strip-final-newline": { @@ -9054,6 +10520,40 @@ "url": "https://opencollective.com/synckit" } }, + "node_modules/terser": { + "version": "5.46.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.2.tgz", + "integrity": "sha512-uxfo9fPcSgLDYob/w1FuL0c99MWiJDnv+5qXSQc5+Ki5NjVNsYi66INnMFBjf6uFz6OnX12piJQPF4IpjJTNTw==", + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/terser/node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "node_modules/test-exclude": { "version": "6.0.0", "devOptional": true, @@ -9510,6 +11010,12 @@ "typescript": ">=4.8.4 <6.1.0" } }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "license": "MIT" + }, "node_modules/uglify-js": { "version": "3.19.3", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", @@ -12155,6 +13661,261 @@ "node": "*" } }, + "packages/code-analyzer-lwc-engine": { + "name": "@salesforce/code-analyzer-lwc-engine", + "version": "0.1.0-SNAPSHOT", + "license": "BSD-3-Clause", + "dependencies": { + "@lwc/compiler": "9.2.1", + "@lwc/errors": "9.2.1", + "@lwc/metadata": "15.0.5", + "@lwc/sfdc-lwc-compiler": "15.0.5", + "@salesforce/code-analyzer-engine-api": "0.36.0", + "@types/node": "^20.0.0" + }, + "devDependencies": { + "@eslint/js": "^9.39.2", + "@types/jest": "^30.0.0", + "eslint": "^9.39.2", + "jest": "^30.2.0", + "rimraf": "^6.1.2", + "ts-jest": "^29.4.6", + "typescript": "^5.9.3", + "typescript-eslint": "^8.50.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "packages/code-analyzer-lwc-engine/node_modules/@eslint/eslintrc": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", + "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", + "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.1.1", + "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-lwc-engine/node_modules/@eslint/js": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", + "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "packages/code-analyzer-lwc-engine/node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "packages/code-analyzer-lwc-engine/node_modules/eslint": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", + "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", + "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.5", + "@eslint/js": "9.39.4", + "@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-lwc-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-lwc-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-lwc-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-lwc-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-lwc-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-lwc-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-lwc-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": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/code-analyzer-lwc-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": { + "node": ">= 4" + } + }, + "packages/code-analyzer-lwc-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": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "packages/code-analyzer-pmd-engine": { "name": "@salesforce/code-analyzer-pmd-engine", "version": "0.41.0", diff --git a/packages/code-analyzer-lwc-engine/README.md b/packages/code-analyzer-lwc-engine/README.md new file mode 100644 index 00000000..5fbdd29d --- /dev/null +++ b/packages/code-analyzer-lwc-engine/README.md @@ -0,0 +1,14 @@ +# @salesforce/code-analyzer-lwc-engine + +POC implementation of the LWC compiler engine for Salesforce Code Analyzer. + +This engine runs the LWC compiler (`@lwc/compiler`) against `.js` / `.html` / `.css` +files inside LWC component bundles and translates each `CompilerDiagnostic` into +a Code Analyzer `Violation`. + +See [`handoff-notes/lwc-engine-spike-doc.md`](../../../handoff-notes/lwc-engine-spike-doc.md) +for the full design. + +## Status + +Draft / proof-of-concept. Not yet wired into `code-analyzer-core`'s plugin loader. diff --git a/packages/code-analyzer-lwc-engine/eslint.config.mjs b/packages/code-analyzer-lwc-engine/eslint.config.mjs new file mode 100644 index 00000000..44661709 --- /dev/null +++ b/packages/code-analyzer-lwc-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-lwc-engine/package.json b/packages/code-analyzer-lwc-engine/package.json new file mode 100644 index 00000000..141d116e --- /dev/null +++ b/packages/code-analyzer-lwc-engine/package.json @@ -0,0 +1,69 @@ +{ + "name": "@salesforce/code-analyzer-lwc-engine", + "description": "LWC compiler engine for Salesforce Code Analyzer (POC)", + "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-lwc-engine" + }, + "main": "dist/index.js", + "types": "dist/index.d.ts", + "dependencies": { + "@types/node": "^20.0.0", + "@salesforce/code-analyzer-engine-api": "0.36.0", + "@lwc/compiler": "9.2.1", + "@lwc/errors": "9.2.1", + "@lwc/sfdc-lwc-compiler": "15.0.5", + "@lwc/metadata": "15.0.5" + }, + "devDependencies": { + "@eslint/js": "^9.39.2", + "@types/jest": "^30.0.0", + "eslint": "^9.39.2", + "jest": "^30.2.0", + "rimraf": "^6.1.2", + "ts-jest": "^29.4.6", + "typescript": "^5.9.3", + "typescript-eslint": "^8.50.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "files": [ + "dist", + "LICENSE", + "package.json" + ], + "scripts": { + "build": "tsc --build tsconfig.build.json --verbose", + "test": "tsc --build tsconfig.json && cross-env NODE_OPTIONS=--experimental-vm-modules 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", + "scrub": "npm run clean && rimraf node_modules" + }, + "jest": { + "preset": "ts-jest", + "testEnvironment": "node", + "testMatch": [ + "**/*.test.ts" + ], + "testPathIgnorePatterns": [ + "/node_modules/", + "/dist/" + ], + "collectCoverageFrom": [ + "src/**/*.ts", + "!src/index.ts" + ], + "transformIgnorePatterns": [ + "node_modules/(?!(@lwc)/)" + ] + } +} diff --git a/packages/code-analyzer-lwc-engine/src/bundle.ts b/packages/code-analyzer-lwc-engine/src/bundle.ts new file mode 100644 index 00000000..d2629e05 --- /dev/null +++ b/packages/code-analyzer-lwc-engine/src/bundle.ts @@ -0,0 +1,35 @@ +import path from "node:path"; + +const BUNDLE_EXTENSIONS = new Set([".js", ".ts", ".mjs", ".html", ".css"]); +// TODO: Parse namespace from sfdx-project.json instead of hard-coding "c" +const DEFAULT_NAMESPACE = "c"; + +export interface BundleIdentity { + name: string; + namespace: string; +} + +// Spike doc §10.1. A file qualifies as an LWC bundle file when its extension +// is supported AND its parent directory's basename matches the file's stem +// AND the file is not under a __tests__/ directory. +export function isLwcBundleFile(absPath: string): boolean { + const ext = path.extname(absPath).toLowerCase(); + if (!BUNDLE_EXTENSIONS.has(ext)) return false; + + const stem = path.basename(absPath, ext); + const parentDir = path.basename(path.dirname(absPath)); + if (parentDir !== stem) return false; + + const segments = absPath.split(path.sep); + if (segments.includes("__tests__")) return false; + + return true; +} + +// Spike doc §10.2. v1: namespace is hard-coded to "c". sfdx-project.json +// parsing is a known limitation (§16). +export function bundleIdentity(absPath: string): BundleIdentity { + const ext = path.extname(absPath); + const stem = path.basename(absPath, ext); + return { name: stem, namespace: DEFAULT_NAMESPACE }; +} diff --git a/packages/code-analyzer-lwc-engine/src/compile.ts b/packages/code-analyzer-lwc-engine/src/compile.ts new file mode 100644 index 00000000..cf28f76e --- /dev/null +++ b/packages/code-analyzer-lwc-engine/src/compile.ts @@ -0,0 +1,190 @@ +import * as fsp from "node:fs/promises"; +import path from "node:path"; +import { BundleIdentity } from "./bundle"; + +export interface CollectedDiagnostic { + code: number; + message: string; + filename?: string; + location?: { line: number; column: number; start?: number; length?: number }; + level: number; + url?: string; +} + +// Compile a single LWC file using both open-source and platform compilers. +// Returns a merged, deduplicated list of diagnostics from both paths. +// +// Path 1: @lwc/compiler transformSync — throws CompilerError/CompilerAggregateError (codes 1001-1213) +// Path 2: @lwc/sfdc-lwc-compiler compile() — returns diagnostics on output (codes 1500-1538) +export async function compileAndCollect( + file: string, + bundle: BundleIdentity +): Promise { + const source = await fsp.readFile(file, "utf-8"); + const bundleFiles = await readBundleFiles(file, bundle.name); + + // Sequential — not parallel. Both paths import @lwc/compiler internally; + // concurrent dynamic import() of the same ESM module causes a Node race condition. + const openSourceDiags = await collectFromTransformSync(source, file, bundle); + const platformDiags = await collectFromPlatformCompile(bundleFiles, bundle); + + return deduplicateDiagnostics([...openSourceDiags, ...platformDiags]); +} + +// Read all sibling files in the bundle directory that belong to this component. +async function readBundleFiles(file: string, name: string): Promise> { + const dir = path.dirname(file); + const files: Record = {}; + try { + const entries = await fsp.readdir(dir); + for (const entry of entries) { + const stem = path.basename(entry, path.extname(entry)); + if (stem === name && !entry.includes("__tests__")) { + const content = await fsp.readFile(path.join(dir, entry), "utf-8"); + files[entry] = content; + } + } + } catch { + // If we can't read the directory, just use the single file + files[path.basename(file)] = await fsp.readFile(file, "utf-8"); + } + return files; +} + +// Path 1: open-source @lwc/compiler (throws on error) +async function collectFromTransformSync( + source: string, + file: string, + bundle: BundleIdentity +): Promise { + const lwcCompiler = await import("@lwc/compiler"); + const lwcErrors = await import("@lwc/errors"); + const { transformSync } = lwcCompiler as { transformSync: (src: string, filename: string, opts: { name: string; namespace: string }) => unknown }; + const { CompilerError, CompilerAggregateError } = lwcErrors as { + CompilerError: new (...args: unknown[]) => Error & CollectedDiagnostic; + CompilerAggregateError: new (...args: unknown[]) => Error & { errors: (Error & CollectedDiagnostic)[] }; + }; + + try { + transformSync(source, file, { name: bundle.name, namespace: bundle.namespace }); + return []; + } catch (e) { + if (e instanceof CompilerError) { + return [unwrap(e)]; + } + if (e instanceof CompilerAggregateError) { + return e.errors.map(unwrap); + } + const err = e as Error; + return [{ + code: 1001, + message: `Unexpected compilation error: ${err.message}`, + filename: file, + level: 1, + }]; + } +} + +// Path 2: @lwc/sfdc-lwc-compiler platform compile (returns diagnostics, doesn't throw) +async function collectFromPlatformCompile( + bundleFiles: Record, + bundle: BundleIdentity +): Promise { + try { + const sfdcCompiler = await import("@lwc/sfdc-lwc-compiler"); + const compile = (sfdcCompiler as { compile: (config: unknown) => Promise }).compile; + + const output = await compile({ + bundle: { + type: "platform" as const, + name: bundle.name, + namespace: bundle.namespace, + files: bundleFiles, + }, + }); + + const diagnostics: CollectedDiagnostic[] = []; + + // Top-level diagnostics + if (output.diagnostics) { + for (const d of output.diagnostics) { + if (isPlatformDiagnostic(d)) diagnostics.push(toDiag(d)); + } + } + + // Per-bundle result diagnostics + if (output.results) { + for (const result of output.results) { + if (result.diagnostics) { + for (const d of result.diagnostics) { + if (isPlatformDiagnostic(d)) diagnostics.push(toDiag(d)); + } + } + } + } + + return diagnostics; + } catch (_err) { + // If platform compile fails entirely (missing deps, version mismatch), fall back silently. + // Open-source path still provides coverage for codes 1001-1213. + // Platform compile unavailable — open-source path still covers codes 1001-1213. + return []; + } +} + +// Only keep diagnostics in the platform range (1500+) to avoid double-counting +// open-source errors that both compilers might emit. +function isPlatformDiagnostic(d: unknown): d is RawDiagnostic { + if (!d || typeof d !== "object") return false; + const obj = d as Record; + return typeof obj.code === "number" && obj.code >= 1500; +} + +function toDiag(d: RawDiagnostic): CollectedDiagnostic { + return { + code: d.code, + message: d.message ?? "", + filename: d.filename, + location: d.location, + level: d.level ?? 1, + url: d.url, + }; +} + +function unwrap(e: Error & CollectedDiagnostic): CollectedDiagnostic { + return { + code: e.code, + message: e.message, + filename: e.filename, + location: e.location, + level: e.level, + url: e.url, + }; +} + +function deduplicateDiagnostics(diags: CollectedDiagnostic[]): CollectedDiagnostic[] { + const seen = new Set(); + const result: CollectedDiagnostic[] = []; + for (const d of diags) { + const key = `${d.code}|${d.message}|${d.filename ?? ""}|${d.location?.line ?? ""}|${d.location?.column ?? ""}`; + if (!seen.has(key)) { + seen.add(key); + result.push(d); + } + } + return result; +} + +interface RawDiagnostic { + code: number; + message?: string; + filename?: string; + location?: { line: number; column: number; start?: number; length?: number }; + level?: number; + url?: string; +} + +interface PlatformOutput { + diagnostics?: unknown[]; + results?: Array<{ diagnostics?: unknown[] }>; +} diff --git a/packages/code-analyzer-lwc-engine/src/engine.ts b/packages/code-analyzer-lwc-engine/src/engine.ts new file mode 100644 index 00000000..041168d7 --- /dev/null +++ b/packages/code-analyzer-lwc-engine/src/engine.ts @@ -0,0 +1,85 @@ +import { + DescribeOptions, + Engine, + EngineRunResults, + LogLevel, + RuleDescription, + RunOptions, + Violation, +} from "@salesforce/code-analyzer-engine-api"; +import * as fsp from "node:fs/promises"; +import path from "node:path"; +import { buildRuleCatalog } from "./rules"; +import { isLwcBundleFile, bundleIdentity } from "./bundle"; +import { compileAndCollect } from "./compile"; +import { toViolation } from "./translate"; +import { getMessage } from "./messages"; + +export class LwcEngine extends Engine { + static readonly NAME = "lwc"; + + getName(): string { + return LwcEngine.NAME; + } + + async getEngineVersion(): Promise { + const pathToPackageJson = path.join(__dirname, "..", "package.json"); + const packageJson: { version: string } = JSON.parse(await fsp.readFile(pathToPackageJson, "utf-8")); + return packageJson.version; + } + + async describeRules(opts: DescribeOptions): Promise { + this.emitDescribeRulesProgressEvent(0); + + if (opts.workspace) { + const targetedFiles = await opts.workspace.getTargetedFiles(); + const hasLwcFiles = targetedFiles.some(isLwcBundleFile); + if (!hasLwcFiles) { + this.emitDescribeRulesProgressEvent(100); + return []; + } + } + + const rules = await buildRuleCatalog(); + this.emitDescribeRulesProgressEvent(100); + return rules; + } + + async runRules(ruleNames: string[], opts: RunOptions): Promise { + this.emitRunRulesProgressEvent(0); + + const selected = new Set(ruleNames); + const violations: Violation[] = []; + const targetedFiles = await opts.workspace.getTargetedFiles(); + const lwcFiles = targetedFiles.filter(isLwcBundleFile); + + if (lwcFiles.length === 0) { + this.emitRunRulesProgressEvent(100); + return { violations: [] }; + } + + const step = 100 / lwcFiles.length; + let progress = 0; + + for (const file of lwcFiles) { + try { + const diagnostics = await compileAndCollect(file, bundleIdentity(file)); + for (const d of diagnostics) { + const ruleName = `LWC${d.code}`; + if (selected.size > 0 && !selected.has(ruleName)) continue; + violations.push(toViolation(d, file)); + } + } catch (e) { + this.emitLogEvent( + LogLevel.Warn, + getMessage("UnexpectedThrowDuringCompile", file, (e as Error).message) + ); + } + progress += step; + this.emitRunRulesProgressEvent(progress); + } + + this.emitRunRulesProgressEvent(100); + return { violations }; + } +} diff --git a/packages/code-analyzer-lwc-engine/src/index.ts b/packages/code-analyzer-lwc-engine/src/index.ts new file mode 100644 index 00000000..6040d093 --- /dev/null +++ b/packages/code-analyzer-lwc-engine/src/index.ts @@ -0,0 +1,8 @@ +import { EnginePlugin } from "@salesforce/code-analyzer-engine-api"; +import { LwcEnginePlugin } from "./plugin"; + +function createEnginePlugin(): EnginePlugin { + return new LwcEnginePlugin(); +} + +export { createEnginePlugin, LwcEnginePlugin }; diff --git a/packages/code-analyzer-lwc-engine/src/messages.ts b/packages/code-analyzer-lwc-engine/src/messages.ts new file mode 100644 index 00000000..f3f08cdd --- /dev/null +++ b/packages/code-analyzer-lwc-engine/src/messages.ts @@ -0,0 +1,16 @@ +import { getMessageFromCatalog } from "@salesforce/code-analyzer-engine-api"; + +const MESSAGE_CATALOG: { [key: string]: string } = { + UnsupportedEngineName: + `The LwcEnginePlugin does not support an engine with name '%s'.`, + + CompileFailed: + `Failed to compile %s: %s`, + + UnexpectedThrowDuringCompile: + `Unexpected error while compiling %s: %s`, +}; + +export function getMessage(msgId: string, ...args: (string | number)[]): string { + return getMessageFromCatalog(MESSAGE_CATALOG, msgId, ...args); +} diff --git a/packages/code-analyzer-lwc-engine/src/plugin.ts b/packages/code-analyzer-lwc-engine/src/plugin.ts new file mode 100644 index 00000000..8fedddc6 --- /dev/null +++ b/packages/code-analyzer-lwc-engine/src/plugin.ts @@ -0,0 +1,20 @@ +import { + ConfigObject, + Engine, + EnginePluginV1, +} from "@salesforce/code-analyzer-engine-api"; +import { getMessage } from "./messages"; +import { LwcEngine } from "./engine"; + +export class LwcEnginePlugin extends EnginePluginV1 { + getAvailableEngineNames(): string[] { + return [LwcEngine.NAME]; + } + + async createEngine(engineName: string, _resolvedConfig: ConfigObject): Promise { + if (engineName !== LwcEngine.NAME) { + throw new Error(getMessage('UnsupportedEngineName', engineName)); + } + return new LwcEngine(); + } +} diff --git a/packages/code-analyzer-lwc-engine/src/rules.ts b/packages/code-analyzer-lwc-engine/src/rules.ts new file mode 100644 index 00000000..d2c922cf --- /dev/null +++ b/packages/code-analyzer-lwc-engine/src/rules.ts @@ -0,0 +1,113 @@ +import { RuleDescription } from "@salesforce/code-analyzer-engine-api"; +import { toSeverityLevel } from "./severity"; + +interface LWCErrorInfoLike { + code: number; + message: string; + level: number; + url?: string; +} + +// Lazy-load all error registries from three sources: +// 1. @lwc/errors (open-source compiler, codes 1001-1213) +// 2. @lwc/sfdc-lwc-compiler (platform compiler, codes 1500-1538) +// 3. @lwc/metadata (metadata extraction, codes 1700-1720) +// +// Platform packages (2 & 3) are CJS but require() @lwc/errors which is ESM-only. +// CJS cannot require ESM — this is a broken dependency in the published packages. +// Workaround: read the .js file from disk and execute it in a VM with a fake require() +// that supplies the only constants the file actually needs (DiagnosticLevel enum values). + +async function loadPlatformErrors(packageName: string): Promise> { + const resolvePath = require.resolve(`${packageName}/dist/errors/errors.js`); + const fs = await import("node:fs"); + const vm = await import("node:vm"); + const code = fs.readFileSync(resolvePath, "utf-8").replace(/\/\/# sourceMappingURL=.*$/m, ""); + const mod = { exports: {} as Record }; + const wrapped = `(function(exports, require, module) {\n${code}\n})`; + const fn = vm.runInThisContext(wrapped); + fn(mod.exports, () => ({ DiagnosticLevel: { Fatal: 0, Error: 1, Warning: 2, Log: 3 }, SITE_LOCAL_NAMESPACE: "Site" }), mod); + return mod.exports; +} + +async function loadRegistries(): Promise { + const lwcErrors = await import("@lwc/errors"); + const [sfdcErrors, metadataErrors] = await Promise.all([ + loadPlatformErrors("@lwc/sfdc-lwc-compiler"), + loadPlatformErrors("@lwc/metadata"), + ]); + + const collected: LWCErrorInfoLike[] = []; + + const pushFrom = (source: unknown) => { + if (!source || typeof source !== "object") return; + if (isLwcErrorInfo(source)) { + collected.push(source); + return; + } + for (const value of Object.values(source as Record)) { + if (isLwcErrorInfo(value)) { + collected.push(value); + } + } + }; + + // @lwc/errors registries + const e = lwcErrors as Record; + pushFrom(e.GENERIC_COMPILER_ERROR); + pushFrom(e.CompilerValidationErrors); + pushFrom(e.ModuleResolutionErrors); + pushFrom(e.TransformerErrors); + pushFrom(e.LWCClassErrors); + pushFrom(e.DecoratorErrors); + pushFrom(e.TemplateErrors); + pushFrom(e.ParserDiagnostics); + pushFrom(e.SsrCompilerErrors); + + // @lwc/sfdc-lwc-compiler platform errors (1500s) + const s = sfdcErrors as Record; + pushFrom(s.Errors); + pushFrom(s.JSDocErrors); + + // @lwc/metadata errors (1700s) + const m = metadataErrors as Record; + pushFrom(m.Errors); + + return collected; +} + +function isLwcErrorInfo(v: unknown): v is LWCErrorInfoLike { + if (!v || typeof v !== "object") return false; + const o = v as Record; + return typeof o.code === "number" + && typeof o.message === "string" + && typeof o.level === "number"; +} + +export function ruleNameForCode(code: number): string { + return `LWC${code}`; +} + +export async function buildRuleCatalog(): Promise { + const infos = await loadRegistries(); + + // Dedupe by code — registries can repeat entries for shared codes. + const byCode = new Map(); + for (const info of infos) { + if (!byCode.has(info.code)) byCode.set(info.code, info); + } + + const rules: RuleDescription[] = []; + for (const info of byCode.values()) { + rules.push({ + name: ruleNameForCode(info.code), + severityLevel: toSeverityLevel(info.level), + tags: ["Recommended", "LWC"], + description: info.message, + resourceUrls: info.url ? [info.url] : [] + }); + } + + rules.sort((a, b) => a.name.localeCompare(b.name)); + return rules; +} diff --git a/packages/code-analyzer-lwc-engine/src/severity.ts b/packages/code-analyzer-lwc-engine/src/severity.ts new file mode 100644 index 00000000..f61ca290 --- /dev/null +++ b/packages/code-analyzer-lwc-engine/src/severity.ts @@ -0,0 +1,20 @@ +import { SeverityLevel } from "@salesforce/code-analyzer-engine-api"; + +// DiagnosticLevel from @lwc/errors: +// Fatal=0, Error=1, Warning=2, Log=3 +// +// SeverityLevel from code-analyzer-engine-api: +// Critical=1, High=2, Moderate=3, Low=4, Info=5 +// +// TODO: Discuss this mapping further with the team +// Log collapses to Info; SARIF round-trip imperfection is accepted as +// a v1 known limitation (§16). +export function toSeverityLevel(level: number | undefined): SeverityLevel { + switch (level) { + case 0: return SeverityLevel.Critical; // Fatal + case 1: return SeverityLevel.Critical; // Error + case 2: return SeverityLevel.High; // Warning + case 3: return SeverityLevel.Info; // Log + default: return SeverityLevel.Moderate; // unknown — bias toward visibility + } +} diff --git a/packages/code-analyzer-lwc-engine/src/translate.ts b/packages/code-analyzer-lwc-engine/src/translate.ts new file mode 100644 index 00000000..3c33c0ba --- /dev/null +++ b/packages/code-analyzer-lwc-engine/src/translate.ts @@ -0,0 +1,18 @@ +import { Violation } from "@salesforce/code-analyzer-engine-api"; +import { CollectedDiagnostic } from "./compile"; +import { ruleNameForCode } from "./rules"; + +// Spike doc §11. Trust d.url only — no synthesis or fallback. +export function toViolation(d: CollectedDiagnostic, fallbackFile: string): Violation { + return { + ruleName: ruleNameForCode(d.code), + message: d.message, + codeLocations: [{ + file: d.filename ?? fallbackFile, + startLine: d.location?.line ?? 1, + startColumn: d.location?.column ?? 1, + }], + primaryLocationIndex: 0, + resourceUrls: d.url ? [d.url] : [], + }; +} diff --git a/packages/code-analyzer-lwc-engine/test/bundle.test.ts b/packages/code-analyzer-lwc-engine/test/bundle.test.ts new file mode 100644 index 00000000..910ac558 --- /dev/null +++ b/packages/code-analyzer-lwc-engine/test/bundle.test.ts @@ -0,0 +1,32 @@ +import path from "node:path"; +import { isLwcBundleFile, bundleIdentity } from "../src/bundle"; + +const j = (...p: string[]) => path.sep + path.join(...p); + +describe("isLwcBundleFile", () => { + it("accepts a JS file matching its parent directory name", () => { + expect(isLwcBundleFile(j("project", "force-app", "lwc", "foo", "foo.js"))).toBe(true); + }); + + it("accepts an HTML template", () => { + expect(isLwcBundleFile(j("project", "lwc", "foo", "foo.html"))).toBe(true); + }); + + it("rejects when stem doesn't match parent directory", () => { + expect(isLwcBundleFile(j("project", "lwc", "foo", "helper.js"))).toBe(false); + }); + + it("rejects unsupported extensions", () => { + expect(isLwcBundleFile(j("project", "lwc", "foo", "foo.json"))).toBe(false); + }); + + it("rejects files under __tests__", () => { + expect(isLwcBundleFile(j("project", "lwc", "foo", "__tests__", "foo.js"))).toBe(false); + }); +}); + +describe("bundleIdentity", () => { + it("derives name from file stem and namespace defaults to c", () => { + expect(bundleIdentity(j("project", "lwc", "foo", "foo.js"))).toEqual({ name: "foo", namespace: "c" }); + }); +}); diff --git a/packages/code-analyzer-lwc-engine/test/engine.test.ts b/packages/code-analyzer-lwc-engine/test/engine.test.ts new file mode 100644 index 00000000..57d71e24 --- /dev/null +++ b/packages/code-analyzer-lwc-engine/test/engine.test.ts @@ -0,0 +1,83 @@ +import { 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 { LwcEngine } from "../src/engine"; +import { LwcEnginePlugin } from "../src/plugin"; + +const TEST_DATA = path.join(__dirname, "test-data"); + +function mkRunOpts(workspace: Workspace) { + return { + logFolder: os.tmpdir(), + workspace, + workingFolder: fs.mkdtempSync(path.join(os.tmpdir(), "lwc-engine-test-")), + }; +} + +function mkDescribeOpts(workspace?: Workspace) { + return { + logFolder: os.tmpdir(), + workspace, + workingFolder: fs.mkdtempSync(path.join(os.tmpdir(), "lwc-engine-test-")), + }; +} + +describe("LwcEnginePlugin", () => { + it("advertises only the lwc engine name", () => { + expect(new LwcEnginePlugin().getAvailableEngineNames()).toEqual(["lwc"]); + }); + + it("creates an LwcEngine instance for the right name", async () => { + const engine = await new LwcEnginePlugin().createEngine("lwc", {}); + expect(engine).toBeInstanceOf(LwcEngine); + }); + + it("rejects unknown engine names", async () => { + await expect(new LwcEnginePlugin().createEngine("nope", {})).rejects.toThrow(); + }); +}); + +describe("LwcEngine", () => { + it("getName returns 'lwc'", () => { + expect(new LwcEngine().getName()).toBe("lwc"); + }); + + it("getEngineVersion returns a semver-shaped string", async () => { + const v = await new LwcEngine().getEngineVersion(); + expect(v).toMatch(/\d+\.\d+\.\d+/); + }); + + it("describeRules returns a non-empty rule catalog", async () => { + const engine = new LwcEngine(); + const rules = await engine.describeRules(mkDescribeOpts()); + expect(rules.length).toBeGreaterThan(0); + // Spike doc §7: every rule is named LWC + for (const r of rules) { + expect(r.name).toMatch(/^LWC\d+$/); + expect(r.tags).toContain("LWC"); + expect(r.tags).toContain("Recommended"); + } + }); + + it("runRules on a clean bundle produces zero violations", async () => { + const engine = new LwcEngine(); + const ws = new Workspace("test-good", [path.join(TEST_DATA, "lwc", "good")]); + const results = await engine.runRules([], mkRunOpts(ws)); + expect(results.violations).toEqual([]); + }); + + it("runRules on a bundle with bad decorators emits an LWC violation", async () => { + const engine = new LwcEngine(); + const ws = new Workspace("test-bad", [path.join(TEST_DATA, "lwc", "bad")]); + // Empty selector means "all rules" in this engine; if you want to scope, + // pass an explicit list. + const results = await engine.runRules([], mkRunOpts(ws)); + expect(results.violations.length).toBeGreaterThan(0); + for (const v of results.violations) { + expect(v.ruleName).toMatch(/^LWC\d+$/); + expect(v.message).toBeTruthy(); + expect(v.codeLocations.length).toBe(1); + } + }); +}); diff --git a/packages/code-analyzer-lwc-engine/test/severity.test.ts b/packages/code-analyzer-lwc-engine/test/severity.test.ts new file mode 100644 index 00000000..6c912c21 --- /dev/null +++ b/packages/code-analyzer-lwc-engine/test/severity.test.ts @@ -0,0 +1,18 @@ +import { SeverityLevel } from "@salesforce/code-analyzer-engine-api"; +import { toSeverityLevel } from "../src/severity"; + +describe("toSeverityLevel", () => { + it.each([ + [0, SeverityLevel.Critical], // Fatal + [1, SeverityLevel.High], // Error + [2, SeverityLevel.Moderate], // Warning + [3, SeverityLevel.Info], // Log + ])("DiagnosticLevel %i maps to SeverityLevel %i", (level, expected) => { + expect(toSeverityLevel(level)).toBe(expected); + }); + + it("unknown level falls back to Moderate", () => { + expect(toSeverityLevel(undefined)).toBe(SeverityLevel.Moderate); + expect(toSeverityLevel(99)).toBe(SeverityLevel.Moderate); + }); +}); diff --git a/packages/code-analyzer-lwc-engine/test/test-data/lwc/bad/bad.js b/packages/code-analyzer-lwc-engine/test/test-data/lwc/bad/bad.js new file mode 100644 index 00000000..b433d62e --- /dev/null +++ b/packages/code-analyzer-lwc-engine/test/test-data/lwc/bad/bad.js @@ -0,0 +1,7 @@ +// A LightningElement-class file with a decorator misuse that the +// LWC compiler rejects with an LWC1xxx diagnostic. +import { LightningElement, api } from 'lwc'; + +export default class Bad extends LightningElement { + @api @api duplicateApiOnSameField; +} diff --git a/packages/code-analyzer-lwc-engine/test/test-data/lwc/good/good.js b/packages/code-analyzer-lwc-engine/test/test-data/lwc/good/good.js new file mode 100644 index 00000000..71d8105f --- /dev/null +++ b/packages/code-analyzer-lwc-engine/test/test-data/lwc/good/good.js @@ -0,0 +1,2 @@ +import { LightningElement } from 'lwc'; +export default class Good extends LightningElement {} diff --git a/packages/code-analyzer-lwc-engine/test/translate.test.ts b/packages/code-analyzer-lwc-engine/test/translate.test.ts new file mode 100644 index 00000000..811f6789 --- /dev/null +++ b/packages/code-analyzer-lwc-engine/test/translate.test.ts @@ -0,0 +1,39 @@ +import { toViolation } from "../src/translate"; + +describe("toViolation", () => { + it("maps a basic diagnostic to a violation", () => { + const v = toViolation({ + code: 1121, + message: "Bad import", + level: 1, + filename: "/p/lwc/foo/foo.js", + location: { line: 3, column: 5, length: 4 }, + url: "https://lwc.dev/guide/error_codes#lwc1121", + }, "/p/lwc/foo/foo.js"); + + expect(v.ruleName).toBe("LWC1121"); + expect(v.message).toBe("Bad import"); + expect(v.codeLocations).toHaveLength(1); + expect(v.codeLocations[0]).toEqual({ + file: "/p/lwc/foo/foo.js", + startLine: 3, + startColumn: 5, + }); + expect(v.primaryLocationIndex).toBe(0); + expect(v.resourceUrls).toEqual(["https://lwc.dev/guide/error_codes#lwc1121"]); + }); + + it("returns empty resourceUrls when d.url is missing (spike doc §9: no synthesis)", () => { + const v = toViolation({ + code: 1099, message: "x", level: 2, filename: "/p/lwc/foo/foo.js", + }, "/p/lwc/foo/foo.js"); + expect(v.resourceUrls).toEqual([]); + }); + + it("falls back to provided file when d.filename is absent", () => { + const v = toViolation({ code: 1, message: "x", level: 1 }, "/fallback/path.js"); + expect(v.codeLocations[0].file).toBe("/fallback/path.js"); + expect(v.codeLocations[0].startLine).toBe(1); + expect(v.codeLocations[0].startColumn).toBe(1); + }); +}); diff --git a/packages/code-analyzer-lwc-engine/tsconfig.build.json b/packages/code-analyzer-lwc-engine/tsconfig.build.json new file mode 100644 index 00000000..91426db6 --- /dev/null +++ b/packages/code-analyzer-lwc-engine/tsconfig.build.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "composite": true, + "outDir": "./dist", + "rootDir": "./src", + "skipLibCheck": true + }, + "include": [ + "./src" + ], + "references": [ + { + "path": "../code-analyzer-engine-api/tsconfig.build.json" + } + ] +} diff --git a/packages/code-analyzer-lwc-engine/tsconfig.json b/packages/code-analyzer-lwc-engine/tsconfig.json new file mode 100644 index 00000000..8077e9a0 --- /dev/null +++ b/packages/code-analyzer-lwc-engine/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "./tsconfig.build.json", + "compilerOptions": { + "rootDir": ".", + "noEmit": true + }, + "include": [ + "./src", + "./test" + ] +}