From 785ac2d82668269b4b42e347cac6233d657913cf Mon Sep 17 00:00:00 2001 From: Tyler Butler Date: Mon, 6 Oct 2025 16:27:41 -0700 Subject: [PATCH 01/12] fix(eslint-plugin): update no-unchecked-record-access for ESLint 9 API Updated the no-unchecked-record-access rule to be compatible with ESLint 9's flat config API changes while maintaining backward compatibility with ESLint 8. Changes: - Updated parserServices access to use context.sourceCode.parserServices with fallback to context.parserServices for ESLint 8 - Created getScope helper that properly handles ESLint 9's requirement for node argument while supporting ESLint 8's no-argument version - Updated all getScope() calls to pass appropriate node arguments - Fixed getKeyValue function to use correct ESLint 9 getScope API All tests now pass successfully. --- .../src/rules/no-unchecked-record-access.js | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/common/build/eslint-plugin-fluid/src/rules/no-unchecked-record-access.js b/common/build/eslint-plugin-fluid/src/rules/no-unchecked-record-access.js index 920fd9a2caa6..0f3e137e822c 100644 --- a/common/build/eslint-plugin-fluid/src/rules/no-unchecked-record-access.js +++ b/common/build/eslint-plugin-fluid/src/rules/no-unchecked-record-access.js @@ -23,7 +23,8 @@ module.exports = { schema: [], }, create(context) { - const parserServices = context.parserServices; + // ESLint 9+ uses context.sourceCode.parserServices, earlier versions use context.parserServices + const parserServices = context.sourceCode?.parserServices ?? context.parserServices; // Check if we have the necessary TypeScript services if (!parserServices || !parserServices.program || !parserServices.esTreeNodeToTSNodeMap) { @@ -37,6 +38,15 @@ module.exports = { return {}; } + // Helper to get scope in both ESLint 8 and 9 + // In ESLint 9, getScope requires a node argument + const getScope = (node) => { + if (context.sourceCode?.getScope) { + return context.sourceCode.getScope(node); + } + return context.getScope(); + }; + // Main function to run on every member access (e.g., obj.a or obj["a"]) function checkPropertyAccess(node) { if (!isIndexSignatureType(parserServices, node)) { @@ -93,7 +103,7 @@ module.exports = { }); } - if (isStrictlyTypedVariable(getVariableType(parentNode.left, context.getScope()))) { + if (isStrictlyTypedVariable(getVariableType(parentNode.left, getScope(parentNode.left)))) { // This defect occurs when an index signature type is assigned to a strictly typed variable after its declaration return context.report({ node, @@ -132,7 +142,7 @@ module.exports = { } const functionDeclaration = findFunctionDeclaration( parentNode.callee.name, - context.getScope(), + getScope(parentNode.callee), ); if (!functionDeclaration || !functionDeclaration.params) { return; @@ -629,7 +639,8 @@ function findContainingBlock(node) { function getKeyValue(node, context) { if (node.type === "Literal") return node.value; if (node.type === "Identifier") { - let scope = context.getScope(); + // ESLint 9 requires node argument for getScope + let scope = context.sourceCode?.getScope ? context.sourceCode.getScope(node) : context.getScope(); while (scope) { const variable = scope.variables.find((v) => v.name === node.name); if (variable) { From 9e83181aa931a50b14c8994c337be9a05bb91a24 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 9 Oct 2025 18:04:47 +0000 Subject: [PATCH 02/12] Update eslint-plugin-fluid for ESLint 8 and 9 compatibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes the plugin compatible with both ESLint 8 and 9 by: 1. Updating dependencies to ESLint 9 compatible versions: - ESLint: 8.57.0 → 9.37.0 - @typescript-eslint/eslint-plugin & parser: 7.18.0 → 8.46.0 - Added @typescript-eslint/utils: 8.46.0 2. Updating no-unchecked-record-access rule with dual API support: - Uses context.sourceCode.parserServices with fallback to context.parserServices - Uses context.sourceCode.getScope(node) with fallback to context.getScope() - Maintains backward compatibility with ESLint 8 3. Migrating all test files to ESLint 9's flat config API: - Replaced deprecated useEslintrc and rulePaths options - Updated to use overrideConfigFile and languageOptions structure - Fixed rule references to include plugin prefix - Changed parser from string to require() call All 19 tests passing successfully with both ESLint 8 and 9 API patterns. Co-authored-by: tylerbutler <19589+tylerbutler@users.noreply.github.com> --- common/build/eslint-plugin-fluid/package.json | 5 +- .../build/eslint-plugin-fluid/pnpm-lock.yaml | 432 ++++++++++-------- ...nforce-no-file-path-links-in-jsdoc.test.js | 24 +- .../enforce-no-hyphen-after-jsdoc-tag.test.js | 24 +- ...enforce-no-markdown-links-in-jsdoc.test.js | 24 +- .../enforce-no-member-release-tags.test.js | 30 +- ...enforce-no-restricted-tags-imports.test.js | 26 +- ...enforce-no-unchecked-record-access.test.js | 25 +- 8 files changed, 335 insertions(+), 255 deletions(-) diff --git a/common/build/eslint-plugin-fluid/package.json b/common/build/eslint-plugin-fluid/package.json index 7a2228d2f240..6c2a3139f682 100644 --- a/common/build/eslint-plugin-fluid/package.json +++ b/common/build/eslint-plugin-fluid/package.json @@ -23,13 +23,14 @@ }, "dependencies": { "@microsoft/tsdoc": "^0.15.1", - "@typescript-eslint/parser": "~7.18.0", + "@typescript-eslint/parser": "~8.46.0", + "@typescript-eslint/utils": "~8.46.0", "ts-morph": "^22.0.0" }, "devDependencies": { "@fluid-tools/markdown-magic": "file:../../../tools/markdown-magic", "@fluidframework/build-common": "^2.0.3", - "eslint": "^8.57.0", + "eslint": "~9.37.0", "mocha": "^10.8.2", "mocha-multi-reporters": "^1.5.1", "prettier": "~3.6.2", diff --git a/common/build/eslint-plugin-fluid/pnpm-lock.yaml b/common/build/eslint-plugin-fluid/pnpm-lock.yaml index b1c05d11bde8..a6eff96fea83 100644 --- a/common/build/eslint-plugin-fluid/pnpm-lock.yaml +++ b/common/build/eslint-plugin-fluid/pnpm-lock.yaml @@ -12,8 +12,11 @@ importers: specifier: ^0.15.1 version: 0.15.1 '@typescript-eslint/parser': - specifier: ~7.18.0 - version: 7.18.0(eslint@8.57.0)(typescript@5.4.5) + specifier: ~8.46.0 + version: 8.46.0(eslint@9.37.0)(typescript@5.4.5) + '@typescript-eslint/utils': + specifier: ~8.46.0 + version: 8.46.0(eslint@9.37.0)(typescript@5.4.5) ts-morph: specifier: ^22.0.0 version: 22.0.0 @@ -25,8 +28,8 @@ importers: specifier: ^2.0.3 version: 2.0.3 eslint: - specifier: ^8.57.0 - version: 8.57.0 + specifier: ~9.37.0 + version: 9.37.0 mocha: specifier: ^10.8.2 version: 10.8.2 @@ -45,23 +48,43 @@ importers: packages: - '@eslint-community/eslint-utils@4.4.0': - resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + '@eslint-community/eslint-utils@4.9.0': + resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - '@eslint-community/regexpp@4.10.0': - resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==} + '@eslint-community/regexpp@4.12.1': + resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/eslintrc@2.1.4': - resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/config-array@0.21.0': + resolution: {integrity: sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@8.57.0': - resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/config-helpers@0.4.0': + resolution: {integrity: sha512-WUFvV4WoIwW8Bv0KeKCIIEgdSiFOsulyN0xrMu+7z43q/hkOLXjvb5u7UC9jDxvRzcrbEmuZBX5yJZz1741jog==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.16.0': + resolution: {integrity: sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.1': + resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.37.0': + resolution: {integrity: sha512-jaS+NJ+hximswBG6pjNX0uEJZkrT0zwpVi3BA3vX22aFGjJjmgSTSmPpZCRKmoBL5VY/M6p0xsSJx7rk7sy5gg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.6': + resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.4.0': + resolution: {integrity: sha512-sB5uyeq+dwCWyPi31B2gQlVlo+j5brPlWx4yZBrEaRo/nhdDE8Xke1gsGgtiBdaBTxuTkceLVuVt/pclrasb0A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@fluid-tools/markdown-magic@file:../../../tools/markdown-magic': resolution: {directory: ../../../tools/markdown-magic, type: directory} @@ -71,18 +94,21 @@ packages: resolution: {integrity: sha512-1LU/2uyCeMxf63z5rhFOFEBvFyBogZ7ZXwzXLxyBhSgq/fGiq8PLjBW7uX++r0LcVCdaWyopf7w060eJpANYdg==} hasBin: true - '@humanwhocodes/config-array@0.11.14': - resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} - engines: {node: '>=10.10.0'} - deprecated: Use @eslint/config-array instead + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.7': + resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + engines: {node: '>=18.18.0'} '@humanwhocodes/module-importer@1.0.1': resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} - '@humanwhocodes/object-schema@2.0.3': - resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} - deprecated: Use @eslint/object-schema instead + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} @@ -146,12 +172,18 @@ packages: '@types/concat-stream@1.6.1': resolution: {integrity: sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==} + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/form-data@0.0.33': resolution: {integrity: sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==} '@types/glob@7.2.0': resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/mdast@3.0.15': resolution: {integrity: sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==} @@ -173,47 +205,57 @@ packages: '@types/unist@2.0.10': resolution: {integrity: sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==} - '@typescript-eslint/parser@7.18.0': - resolution: {integrity: sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==} - engines: {node: ^18.18.0 || >=20.0.0} + '@typescript-eslint/parser@8.46.0': + resolution: {integrity: sha512-n1H6IcDhmmUEG7TNVSspGmiHHutt7iVKtZwRppD7e04wha5MrkV1h3pti9xQLcCMt6YWsncpoT0HMjkH1FNwWQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/scope-manager@7.18.0': - resolution: {integrity: sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==} - engines: {node: ^18.18.0 || >=20.0.0} + '@typescript-eslint/project-service@8.46.0': + resolution: {integrity: sha512-OEhec0mH+U5Je2NZOeK1AbVCdm0ChyapAyTeXVIYTPXDJ3F07+cu87PPXcGoYqZ7M9YJVvFnfpGg1UmCIqM+QQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/types@7.18.0': - resolution: {integrity: sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==} - engines: {node: ^18.18.0 || >=20.0.0} + '@typescript-eslint/scope-manager@8.46.0': + resolution: {integrity: sha512-lWETPa9XGcBes4jqAMYD9fW0j4n6hrPtTJwWDmtqgFO/4HF4jmdH/Q6wggTw5qIT5TXjKzbt7GsZUBnWoO3dqw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@7.18.0': - resolution: {integrity: sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==} - engines: {node: ^18.18.0 || >=20.0.0} + '@typescript-eslint/tsconfig-utils@8.46.0': + resolution: {integrity: sha512-WrYXKGAHY836/N7zoK/kzi6p8tXFhasHh8ocFL9VZSAkvH956gfeRfcnhs3xzRy8qQ/dq3q44v1jvQieMFg2cw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/types@8.46.0': + resolution: {integrity: sha512-bHGGJyVjSE4dJJIO5yyEWt/cHyNwga/zXGJbJJ8TiO01aVREK6gCTu3L+5wrkb1FbDkQ+TKjMNe9R/QQQP9+rA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/visitor-keys@7.18.0': - resolution: {integrity: sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==} - engines: {node: ^18.18.0 || >=20.0.0} + '@typescript-eslint/typescript-estree@8.46.0': + resolution: {integrity: sha512-ekDCUfVpAKWJbRfm8T1YRrCot1KFxZn21oV76v5Fj4tr7ELyk84OS+ouvYdcDAwZL89WpEkEj2DKQ+qg//+ucg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/utils@8.46.0': + resolution: {integrity: sha512-nD6yGWPj1xiOm4Gk0k6hLSZz2XkNXhuYmyIrOWcHoPuAhjT9i5bAG+xbWPgFeNR8HPHHtpNKdYUXJl/D3x7f5g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' - '@ungap/structured-clone@1.2.0': - resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + '@typescript-eslint/visitor-keys@8.46.0': + resolution: {integrity: sha512-FrvMpAK+hTbFy7vH5j1+tMYHMSKLE6RzluFJlkFNKD0p9YsUT75JlBSmr5so3QRzvMwU5/bIEdeNrxm8du8l3Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn@8.11.3: - resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} engines: {node: '>=0.4.0'} hasBin: true @@ -441,10 +483,6 @@ packages: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} - doctrine@3.0.0: - resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} - engines: {node: '>=6.0.0'} - dom-serializer@1.4.1: resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==} @@ -523,23 +561,31 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} - eslint-scope@7.2.2: - resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} eslint-visitor-keys@3.4.3: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - eslint@8.57.0: - resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@9.37.0: + resolution: {integrity: sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true - espree@9.6.1: - resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} esquery@1.5.0: resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} @@ -579,9 +625,9 @@ packages: fault@1.0.4: resolution: {integrity: sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==} - file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} @@ -596,9 +642,9 @@ packages: engines: {node: '>=0.6'} hasBin: true - flat-cache@3.2.0: - resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} - engines: {node: ^10.12.0 || >=12.0.0} + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} flat@5.0.2: resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} @@ -686,9 +732,9 @@ packages: engines: {node: '>=12'} deprecated: Glob versions prior to v9 are no longer supported - globals@13.24.0: - resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} - engines: {node: '>=8'} + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} globalthis@1.0.4: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} @@ -698,10 +744,6 @@ packages: resolution: {integrity: sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==} engines: {node: '>=8'} - globby@11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} - engines: {node: '>=10'} - gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} @@ -709,9 +751,6 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - graphemer@1.4.0: - resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - has-bigints@1.0.2: resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} @@ -855,10 +894,6 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} - is-path-inside@3.0.3: - resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} - engines: {node: '>=8'} - is-plain-obj@2.1.0: resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} engines: {node: '>=8'} @@ -1245,11 +1280,6 @@ packages: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true - rimraf@5.0.7: resolution: {integrity: sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==} engines: {node: '>=14.18'} @@ -1369,9 +1399,6 @@ packages: sync-rpc@1.3.6: resolution: {integrity: sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==} - text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - then-request@6.0.2: resolution: {integrity: sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==} engines: {node: '>=6.0.0'} @@ -1387,11 +1414,11 @@ packages: trough@1.0.5: resolution: {integrity: sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==} - ts-api-utils@1.3.0: - resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} - engines: {node: '>=16'} + ts-api-utils@2.1.0: + resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + engines: {node: '>=18.12'} peerDependencies: - typescript: '>=4.2.0' + typescript: '>=4.8.4' ts-morph@22.0.0: resolution: {integrity: sha512-M9MqFGZREyeb5fTl6gNHKZLqBQA0TjA1lea+CR48R8EBTDuWrNqW6ccC5QvjNR4s6wDumD3LTCjOFSp9iwlzaw==} @@ -1400,10 +1427,6 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} - typed-array-buffer@1.0.2: resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} engines: {node: '>= 0.4'} @@ -1544,19 +1567,35 @@ packages: snapshots: - '@eslint-community/eslint-utils@4.4.0(eslint@8.57.0)': + '@eslint-community/eslint-utils@4.9.0(eslint@9.37.0)': dependencies: - eslint: 8.57.0 + eslint: 9.37.0 eslint-visitor-keys: 3.4.3 - '@eslint-community/regexpp@4.10.0': {} + '@eslint-community/regexpp@4.12.1': {} - '@eslint/eslintrc@2.1.4': + '@eslint/config-array@0.21.0': + dependencies: + '@eslint/object-schema': 2.1.6 + debug: 4.4.0(supports-color@8.1.1) + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.4.0': + dependencies: + '@eslint/core': 0.16.0 + + '@eslint/core@0.16.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.1': dependencies: ajv: 6.12.6 debug: 4.4.0(supports-color@8.1.1) - espree: 9.6.1 - globals: 13.24.0 + espree: 10.4.0 + globals: 14.0.0 ignore: 5.3.1 import-fresh: 3.3.0 js-yaml: 4.1.0 @@ -1565,7 +1604,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@8.57.0': {} + '@eslint/js@9.37.0': {} + + '@eslint/object-schema@2.1.6': {} + + '@eslint/plugin-kit@0.4.0': + dependencies: + '@eslint/core': 0.16.0 + levn: 0.4.1 '@fluid-tools/markdown-magic@file:../../../tools/markdown-magic(@types/node@20.12.12)(markdown-magic@2.6.1)': dependencies: @@ -1581,17 +1627,16 @@ snapshots: '@fluidframework/build-common@2.0.3': {} - '@humanwhocodes/config-array@0.11.14': + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.7': dependencies: - '@humanwhocodes/object-schema': 2.0.3 - debug: 4.4.0(supports-color@8.1.1) - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.4.3 '@humanwhocodes/module-importer@1.0.1': {} - '@humanwhocodes/object-schema@2.0.3': {} + '@humanwhocodes/retry@0.4.3': {} '@isaacs/cliui@8.0.2': dependencies: @@ -1709,6 +1754,8 @@ snapshots: dependencies: '@types/node': 20.12.12 + '@types/estree@1.0.8': {} + '@types/form-data@0.0.33': dependencies: '@types/node': 20.12.12 @@ -1718,6 +1765,8 @@ snapshots: '@types/minimatch': 5.1.2 '@types/node': 20.12.12 + '@types/json-schema@7.0.15': {} + '@types/mdast@3.0.15': dependencies: '@types/unist': 2.0.10 @@ -1736,53 +1785,75 @@ snapshots: '@types/unist@2.0.10': {} - '@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.4.5)': + '@typescript-eslint/parser@8.46.0(eslint@9.37.0)(typescript@5.4.5)': dependencies: - '@typescript-eslint/scope-manager': 7.18.0 - '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 7.18.0 + '@typescript-eslint/scope-manager': 8.46.0 + '@typescript-eslint/types': 8.46.0 + '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.4.5) + '@typescript-eslint/visitor-keys': 8.46.0 debug: 4.4.0(supports-color@8.1.1) - eslint: 8.57.0 - optionalDependencies: + eslint: 9.37.0 typescript: 5.4.5 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@7.18.0': + '@typescript-eslint/project-service@8.46.0(typescript@5.4.5)': dependencies: - '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/visitor-keys': 7.18.0 + '@typescript-eslint/tsconfig-utils': 8.46.0(typescript@5.4.5) + '@typescript-eslint/types': 8.46.0 + debug: 4.4.0(supports-color@8.1.1) + typescript: 5.4.5 + transitivePeerDependencies: + - supports-color - '@typescript-eslint/types@7.18.0': {} + '@typescript-eslint/scope-manager@8.46.0': + dependencies: + '@typescript-eslint/types': 8.46.0 + '@typescript-eslint/visitor-keys': 8.46.0 - '@typescript-eslint/typescript-estree@7.18.0(typescript@5.4.5)': + '@typescript-eslint/tsconfig-utils@8.46.0(typescript@5.4.5)': dependencies: - '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/visitor-keys': 7.18.0 + typescript: 5.4.5 + + '@typescript-eslint/types@8.46.0': {} + + '@typescript-eslint/typescript-estree@8.46.0(typescript@5.4.5)': + dependencies: + '@typescript-eslint/project-service': 8.46.0(typescript@5.4.5) + '@typescript-eslint/tsconfig-utils': 8.46.0(typescript@5.4.5) + '@typescript-eslint/types': 8.46.0 + '@typescript-eslint/visitor-keys': 8.46.0 debug: 4.4.0(supports-color@8.1.1) - globby: 11.1.0 + fast-glob: 3.3.2 is-glob: 4.0.3 minimatch: 9.0.4 semver: 7.6.2 - ts-api-utils: 1.3.0(typescript@5.4.5) - optionalDependencies: + ts-api-utils: 2.1.0(typescript@5.4.5) typescript: 5.4.5 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@7.18.0': + '@typescript-eslint/utils@8.46.0(eslint@9.37.0)(typescript@5.4.5)': dependencies: - '@typescript-eslint/types': 7.18.0 - eslint-visitor-keys: 3.4.3 + '@eslint-community/eslint-utils': 4.9.0(eslint@9.37.0) + '@typescript-eslint/scope-manager': 8.46.0 + '@typescript-eslint/types': 8.46.0 + '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.4.5) + eslint: 9.37.0 + typescript: 5.4.5 + transitivePeerDependencies: + - supports-color - '@ungap/structured-clone@1.2.0': {} + '@typescript-eslint/visitor-keys@8.46.0': + dependencies: + '@typescript-eslint/types': 8.46.0 + eslint-visitor-keys: 4.2.1 - acorn-jsx@5.3.2(acorn@8.11.3): + acorn-jsx@5.3.2(acorn@8.15.0): dependencies: - acorn: 8.11.3 + acorn: 8.15.0 - acorn@8.11.3: {} + acorn@8.15.0: {} ajv@6.12.6: dependencies: @@ -2005,10 +2076,6 @@ snapshots: dependencies: path-type: 4.0.0 - doctrine@3.0.0: - dependencies: - esutils: 2.0.3 - dom-serializer@1.4.1: dependencies: domelementtype: 2.3.0 @@ -2135,61 +2202,60 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-scope@7.2.2: + eslint-scope@8.4.0: dependencies: esrecurse: 4.3.0 estraverse: 5.3.0 eslint-visitor-keys@3.4.3: {} - eslint@8.57.0: + eslint-visitor-keys@4.2.1: {} + + eslint@9.37.0: dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - '@eslint-community/regexpp': 4.10.0 - '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.57.0 - '@humanwhocodes/config-array': 0.11.14 + '@eslint-community/eslint-utils': 4.9.0(eslint@9.37.0) + '@eslint-community/regexpp': 4.12.1 + '@eslint/config-array': 0.21.0 + '@eslint/config-helpers': 0.4.0 + '@eslint/core': 0.16.0 + '@eslint/eslintrc': 3.3.1 + '@eslint/js': 9.37.0 + '@eslint/plugin-kit': 0.4.0 + '@humanfs/node': 0.16.7 '@humanwhocodes/module-importer': 1.0.1 - '@nodelib/fs.walk': 1.2.8 - '@ungap/structured-clone': 1.2.0 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 debug: 4.4.0(supports-color@8.1.1) - doctrine: 3.0.0 escape-string-regexp: 4.0.0 - eslint-scope: 7.2.2 - eslint-visitor-keys: 3.4.3 - espree: 9.6.1 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 esquery: 1.5.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 - file-entry-cache: 6.0.1 + file-entry-cache: 8.0.0 find-up: 5.0.0 glob-parent: 6.0.2 - globals: 13.24.0 - graphemer: 1.4.0 ignore: 5.3.1 imurmurhash: 0.1.4 is-glob: 4.0.3 - is-path-inside: 3.0.3 - js-yaml: 4.1.0 json-stable-stringify-without-jsonify: 1.0.1 - levn: 0.4.1 lodash.merge: 4.6.2 minimatch: 3.1.2 natural-compare: 1.4.0 optionator: 0.9.4 - strip-ansi: 6.0.1 - text-table: 0.2.0 transitivePeerDependencies: - supports-color - espree@9.6.1: + espree@10.4.0: dependencies: - acorn: 8.11.3 - acorn-jsx: 5.3.2(acorn@8.11.3) - eslint-visitor-keys: 3.4.3 + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 4.2.1 esquery@1.5.0: dependencies: @@ -2227,9 +2293,9 @@ snapshots: dependencies: format: 0.2.2 - file-entry-cache@6.0.1: + file-entry-cache@8.0.0: dependencies: - flat-cache: 3.2.0 + flat-cache: 4.0.1 fill-range@7.1.1: dependencies: @@ -2245,11 +2311,10 @@ snapshots: colors: 0.6.2 commander: 2.1.0 - flat-cache@3.2.0: + flat-cache@4.0.1: dependencies: flatted: 3.3.1 keyv: 4.5.4 - rimraf: 3.0.2 flat@5.0.2: {} @@ -2358,9 +2423,7 @@ snapshots: minimatch: 5.1.6 once: 1.4.0 - globals@13.24.0: - dependencies: - type-fest: 0.20.2 + globals@14.0.0: {} globalthis@1.0.4: dependencies: @@ -2378,21 +2441,10 @@ snapshots: merge2: 1.4.1 slash: 3.0.0 - globby@11.1.0: - dependencies: - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.3.2 - ignore: 5.3.1 - merge2: 1.4.1 - slash: 3.0.0 - gopd@1.2.0: {} graceful-fs@4.2.11: {} - graphemer@1.4.0: {} - has-bigints@1.0.2: {} has-flag@4.0.0: {} @@ -2527,8 +2579,6 @@ snapshots: is-number@7.0.0: {} - is-path-inside@3.0.3: {} - is-plain-obj@2.1.0: {} is-regex@1.1.4: @@ -2989,10 +3039,6 @@ snapshots: reusify@1.0.4: {} - rimraf@3.0.2: - dependencies: - glob: 7.2.3 - rimraf@5.0.7: dependencies: glob: 10.3.16 @@ -3128,8 +3174,6 @@ snapshots: dependencies: get-port: 3.2.0 - text-table@0.2.0: {} - then-request@6.0.2: dependencies: '@types/concat-stream': 1.6.1 @@ -3156,7 +3200,7 @@ snapshots: trough@1.0.5: {} - ts-api-utils@1.3.0(typescript@5.4.5): + ts-api-utils@2.1.0(typescript@5.4.5): dependencies: typescript: 5.4.5 @@ -3169,8 +3213,6 @@ snapshots: dependencies: prelude-ls: 1.2.1 - type-fest@0.20.2: {} - typed-array-buffer@1.0.2: dependencies: call-bind: 1.0.7 diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-file-path-links-in-jsdoc/enforce-no-file-path-links-in-jsdoc.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-file-path-links-in-jsdoc/enforce-no-file-path-links-in-jsdoc.test.js index 7535264d3419..c4359311123d 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-file-path-links-in-jsdoc/enforce-no-file-path-links-in-jsdoc.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-file-path-links-in-jsdoc/enforce-no-file-path-links-in-jsdoc.test.js @@ -6,21 +6,27 @@ const assert = require("assert"); const path = require("path"); const { ESLint } = require("eslint"); +const plugin = require("../../../index.js"); describe("Do not allow file path links in JSDoc/TSDoc comments", function () { async function lintFile(file) { const eslint = new ESLint({ - useEslintrc: false, - overrideConfig: { - rules: { - "no-file-path-links-in-jsdoc": "error", + overrideConfigFile: true, + overrideConfig: [{ + files: ["**/*.ts"], + languageOptions: { + parser: require("@typescript-eslint/parser"), + parserOptions: { + project: path.join(__dirname, "../example/tsconfig.json"), + }, + }, + plugins: { + "@fluid-internal/fluid": plugin, }, - parser: "@typescript-eslint/parser", - parserOptions: { - project: path.join(__dirname, "../example/tsconfig.json"), + rules: { + "@fluid-internal/fluid/no-file-path-links-in-jsdoc": "error", }, - }, - rulePaths: [path.join(__dirname, "../../rules")], + }], }); const fileToLint = path.join(__dirname, "../example/no-file-path-links-in-jsdoc", file); const results = await eslint.lintFiles([fileToLint]); diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-hyphen-after-jsdoc-tag/enforce-no-hyphen-after-jsdoc-tag.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-hyphen-after-jsdoc-tag/enforce-no-hyphen-after-jsdoc-tag.test.js index 23762935231e..44fe799d3ffc 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-hyphen-after-jsdoc-tag/enforce-no-hyphen-after-jsdoc-tag.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-hyphen-after-jsdoc-tag/enforce-no-hyphen-after-jsdoc-tag.test.js @@ -6,6 +6,7 @@ const assert = require("assert"); const path = require("path"); const { ESLint } = require("eslint"); +const plugin = require("../../../index.js"); describe("Do not allow `-` following JSDoc/TSDoc tags", function () { /** @@ -15,17 +16,22 @@ describe("Do not allow `-` following JSDoc/TSDoc tags", function () { */ async function lintFile(file) { const eslint = new ESLint({ - useEslintrc: false, - overrideConfig: { - rules: { - "no-hyphen-after-jsdoc-tag": "error", + overrideConfigFile: true, + overrideConfig: [{ + files: ["**/*.ts"], + languageOptions: { + parser: require("@typescript-eslint/parser"), + parserOptions: { + project: path.join(__dirname, "../example/tsconfig.json"), + }, + }, + plugins: { + "@fluid-internal/fluid": plugin, }, - parser: "@typescript-eslint/parser", - parserOptions: { - project: path.join(__dirname, "../example/tsconfig.json"), + rules: { + "@fluid-internal/fluid/no-hyphen-after-jsdoc-tag": "error", }, - }, - rulePaths: [path.join(__dirname, "../../rules")], + }], }); const fileToLint = path.join(__dirname, "../example/no-hyphen-after-jsdoc-tag", file); const results = await eslint.lintFiles([fileToLint]); diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-markdown-links-in-jsdoc/enforce-no-markdown-links-in-jsdoc.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-markdown-links-in-jsdoc/enforce-no-markdown-links-in-jsdoc.test.js index 0f8841b33e91..7afc17fd43de 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-markdown-links-in-jsdoc/enforce-no-markdown-links-in-jsdoc.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-markdown-links-in-jsdoc/enforce-no-markdown-links-in-jsdoc.test.js @@ -6,21 +6,27 @@ const assert = require("assert"); const path = require("path"); const { ESLint } = require("eslint"); +const plugin = require("../../../index.js"); describe("Do not allow Markdown links in JSDoc/TSDoc comments", function () { async function lintFile(file) { const eslint = new ESLint({ - useEslintrc: false, - overrideConfig: { - rules: { - "no-markdown-links-in-jsdoc": "error", + overrideConfigFile: true, + overrideConfig: [{ + files: ["**/*.ts"], + languageOptions: { + parser: require("@typescript-eslint/parser"), + parserOptions: { + project: path.join(__dirname, "../example/tsconfig.json"), + }, + }, + plugins: { + "@fluid-internal/fluid": plugin, }, - parser: "@typescript-eslint/parser", - parserOptions: { - project: path.join(__dirname, "../example/tsconfig.json"), + rules: { + "@fluid-internal/fluid/no-markdown-links-in-jsdoc": "error", }, - }, - rulePaths: [path.join(__dirname, "../../rules")], + }], }); const fileToLint = path.join(__dirname, "../example/no-markdown-links-in-jsdoc", file); const results = await eslint.lintFiles([fileToLint]); diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-member-release-tags/enforce-no-member-release-tags.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-member-release-tags/enforce-no-member-release-tags.test.js index 193e78e390c3..491d04c5375b 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-member-release-tags/enforce-no-member-release-tags.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-member-release-tags/enforce-no-member-release-tags.test.js @@ -6,23 +6,27 @@ const assert = require("assert"); const path = require("path"); const { ESLint } = require("eslint"); +const plugin = require("../../../index.js"); describe("Do not allow release tags on members", function () { function createESLintInstance() { - const eslintConfig = { - rules: { - "no-member-release-tags": ["error"], - }, - parser: "@typescript-eslint/parser", - parserOptions: { - project: path.join(__dirname, "../example/tsconfig.json"), - }, - }; - return new ESLint({ - useEslintrc: false, - overrideConfig: eslintConfig, - rulePaths: [path.join(__dirname, "../../rules")], + overrideConfigFile: true, + overrideConfig: [{ + files: ["**/*.ts"], + languageOptions: { + parser: require("@typescript-eslint/parser"), + parserOptions: { + project: path.join(__dirname, "../example/tsconfig.json"), + }, + }, + plugins: { + "@fluid-internal/fluid": plugin, + }, + rules: { + "@fluid-internal/fluid/no-member-release-tags": ["error"], + }, + }], }); } diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-restricted-tags-imports/enforce-no-restricted-tags-imports.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-restricted-tags-imports/enforce-no-restricted-tags-imports.test.js index da4b17346c89..9e79315eb0cb 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-restricted-tags-imports/enforce-no-restricted-tags-imports.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-restricted-tags-imports/enforce-no-restricted-tags-imports.test.js @@ -6,20 +6,31 @@ const assert = require("assert"); const path = require("path"); const { ESLint } = require("eslint"); +const plugin = require("../../../index.js"); describe("ESLint Rule Tests", function () { function createESLintInstance(config) { return new ESLint({ - useEslintrc: false, - overrideConfig: config, - rulePaths: [path.join(__dirname, "../../rules")], + overrideConfigFile: true, + overrideConfig: [{ + files: ["**/*.ts"], + languageOptions: { + parser: require("@typescript-eslint/parser"), + parserOptions: config.parserOptions, + }, + plugins: { + "@fluid-internal/fluid": plugin, + ...config.plugins, + }, + rules: config.rules, + }], }); } it("Should report an error for restricted tag imports", async function () { const eslint = createESLintInstance({ rules: { - "no-restricted-tags-imports": [ + "@fluid-internal/fluid/no-restricted-tags-imports": [ "error", { tags: ["@internal", "@alpha"], @@ -27,7 +38,6 @@ describe("ESLint Rule Tests", function () { }, ], }, - parser: "@typescript-eslint/parser", parserOptions: { project: path.join(__dirname, "../example/tsconfig.json"), }, @@ -51,7 +61,7 @@ describe("ESLint Rule Tests", function () { it("Should not report an error for restricted tag imports for exceptions", async function () { const eslint = createESLintInstance({ rules: { - "no-restricted-tags-imports": [ + "@fluid-internal/fluid/no-restricted-tags-imports": [ "error", { tags: ["@internal", "@alpha"], @@ -62,7 +72,6 @@ describe("ESLint Rule Tests", function () { }, ], }, - parser: "@typescript-eslint/parser", parserOptions: { project: path.join(__dirname, "../example/tsconfig.json"), }, @@ -79,7 +88,7 @@ describe("ESLint Rule Tests", function () { it("Should report an error for tsconfig provided config", async function () { const eslint = createESLintInstance({ rules: { - "no-restricted-tags-imports": [ + "@fluid-internal/fluid/no-restricted-tags-imports": [ "error", { tags: ["@internal", "@alpha"], @@ -90,7 +99,6 @@ describe("ESLint Rule Tests", function () { }, ], }, - parser: "@typescript-eslint/parser", parserOptions: { project: path.join(__dirname, "../example/tsconfig.json"), }, diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-unchecked-record-access/enforce-no-unchecked-record-access.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-unchecked-record-access/enforce-no-unchecked-record-access.test.js index ab47f342391d..17bcc82b428c 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-unchecked-record-access/enforce-no-unchecked-record-access.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-unchecked-record-access/enforce-no-unchecked-record-access.test.js @@ -6,21 +6,28 @@ const assert = require("assert"); const path = require("path"); const { ESLint } = require("eslint"); +const plugin = require("../../../index.js"); describe("ESLint Rule Tests", function () { async function lintFile(file) { const eslint = new ESLint({ - useEslintrc: false, - overrideConfig: { - rules: { - "no-unchecked-record-access": "error", + overrideConfigFile: true, + overrideConfig: [{ + files: ["**/*.ts"], + languageOptions: { + parser: require("@typescript-eslint/parser"), + parserOptions: { + projectService: true, + tsconfigRootDir: path.join(__dirname, "../example"), + }, + }, + plugins: { + "@fluid-internal/fluid": plugin, }, - parser: "@typescript-eslint/parser", - parserOptions: { - project: path.join(__dirname, "../example/tsconfig.json"), + rules: { + "@fluid-internal/fluid/no-unchecked-record-access": "error", }, - }, - rulePaths: [path.join(__dirname, "../../rules")], + }], }); const fileToLint = path.join(__dirname, "../example/no-unchecked-record-access", file); const results = await eslint.lintFiles([fileToLint]); From 6634e35ee3b87996e81faa0ced29c7fd8a61a5e1 Mon Sep 17 00:00:00 2001 From: Tyler Butler Date: Thu, 9 Oct 2025 11:50:40 -0700 Subject: [PATCH 03/12] make tests cross-version compatible --- common/build/eslint-plugin-fluid/package.json | 6 +- .../src/rules/no-unchecked-record-access.js | 10 ++- ...nforce-no-file-path-links-in-jsdoc.test.js | 30 ++++----- .../enforce-no-hyphen-after-jsdoc-tag.test.js | 30 ++++----- ...enforce-no-markdown-links-in-jsdoc.test.js | 30 ++++----- .../enforce-no-member-release-tags.test.js | 30 ++++----- ...enforce-no-restricted-tags-imports.test.js | 24 +++---- ...enforce-no-unchecked-record-access.test.js | 32 ++++----- .../src/test/eslintConfigHelper.js | 66 +++++++++++++++++++ 9 files changed, 155 insertions(+), 103 deletions(-) create mode 100644 common/build/eslint-plugin-fluid/src/test/eslintConfigHelper.js diff --git a/common/build/eslint-plugin-fluid/package.json b/common/build/eslint-plugin-fluid/package.json index 6c2a3139f682..b7ad7f6a1c31 100644 --- a/common/build/eslint-plugin-fluid/package.json +++ b/common/build/eslint-plugin-fluid/package.json @@ -19,7 +19,11 @@ "format": "npm run prettier:fix", "prettier": "prettier --check . --cache --ignore-path ../../../.prettierignore", "prettier:fix": "prettier --write . --cache --ignore-path ../../../.prettierignore", - "test": "mocha \"src/test/**/*.test.*js\"" + "test": "npm run test:both", + "test:both": "npm run test:eslint8 && npm run test:eslint9", + "test:eslint8": "pnpm add -D eslint@~8.57.1 && npm run test:mocha", + "test:eslint9": "pnpm add -D eslint@~9.37.0 && npm run test:mocha", + "test:mocha": "mocha \"src/test/**/*.test.*js\"" }, "dependencies": { "@microsoft/tsdoc": "^0.15.1", diff --git a/common/build/eslint-plugin-fluid/src/rules/no-unchecked-record-access.js b/common/build/eslint-plugin-fluid/src/rules/no-unchecked-record-access.js index 0f3e137e822c..449241a42209 100644 --- a/common/build/eslint-plugin-fluid/src/rules/no-unchecked-record-access.js +++ b/common/build/eslint-plugin-fluid/src/rules/no-unchecked-record-access.js @@ -103,7 +103,11 @@ module.exports = { }); } - if (isStrictlyTypedVariable(getVariableType(parentNode.left, getScope(parentNode.left)))) { + if ( + isStrictlyTypedVariable( + getVariableType(parentNode.left, getScope(parentNode.left)), + ) + ) { // This defect occurs when an index signature type is assigned to a strictly typed variable after its declaration return context.report({ node, @@ -640,7 +644,9 @@ function getKeyValue(node, context) { if (node.type === "Literal") return node.value; if (node.type === "Identifier") { // ESLint 9 requires node argument for getScope - let scope = context.sourceCode?.getScope ? context.sourceCode.getScope(node) : context.getScope(); + let scope = context.sourceCode?.getScope + ? context.sourceCode.getScope(node) + : context.getScope(); while (scope) { const variable = scope.variables.find((v) => v.name === node.name); if (variable) { diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-file-path-links-in-jsdoc/enforce-no-file-path-links-in-jsdoc.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-file-path-links-in-jsdoc/enforce-no-file-path-links-in-jsdoc.test.js index c4359311123d..6167c6bd2cd3 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-file-path-links-in-jsdoc/enforce-no-file-path-links-in-jsdoc.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-file-path-links-in-jsdoc/enforce-no-file-path-links-in-jsdoc.test.js @@ -7,27 +7,23 @@ const assert = require("assert"); const path = require("path"); const { ESLint } = require("eslint"); const plugin = require("../../../index.js"); +const { createESLintConfig } = require("../eslintConfigHelper.js"); describe("Do not allow file path links in JSDoc/TSDoc comments", function () { async function lintFile(file) { - const eslint = new ESLint({ - overrideConfigFile: true, - overrideConfig: [{ - files: ["**/*.ts"], - languageOptions: { - parser: require("@typescript-eslint/parser"), - parserOptions: { - project: path.join(__dirname, "../example/tsconfig.json"), - }, - }, - plugins: { - "@fluid-internal/fluid": plugin, - }, - rules: { - "@fluid-internal/fluid/no-file-path-links-in-jsdoc": "error", - }, - }], + const eslintOptions = createESLintConfig({ + parser: "@typescript-eslint/parser", + parserOptions: { + project: path.join(__dirname, "../example/tsconfig.json"), + }, + plugin, + pluginName: "@fluid-internal/fluid", + rules: { + "@fluid-internal/fluid/no-file-path-links-in-jsdoc": "error", + }, }); + + const eslint = new ESLint(eslintOptions); const fileToLint = path.join(__dirname, "../example/no-file-path-links-in-jsdoc", file); const results = await eslint.lintFiles([fileToLint]); assert.equal(results.length, 1, "Expected a single result for linting a single file."); diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-hyphen-after-jsdoc-tag/enforce-no-hyphen-after-jsdoc-tag.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-hyphen-after-jsdoc-tag/enforce-no-hyphen-after-jsdoc-tag.test.js index 44fe799d3ffc..61eb08e5641e 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-hyphen-after-jsdoc-tag/enforce-no-hyphen-after-jsdoc-tag.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-hyphen-after-jsdoc-tag/enforce-no-hyphen-after-jsdoc-tag.test.js @@ -7,6 +7,7 @@ const assert = require("assert"); const path = require("path"); const { ESLint } = require("eslint"); const plugin = require("../../../index.js"); +const { createESLintConfig } = require("../eslintConfigHelper.js"); describe("Do not allow `-` following JSDoc/TSDoc tags", function () { /** @@ -15,24 +16,19 @@ describe("Do not allow `-` following JSDoc/TSDoc tags", function () { * @returns */ async function lintFile(file) { - const eslint = new ESLint({ - overrideConfigFile: true, - overrideConfig: [{ - files: ["**/*.ts"], - languageOptions: { - parser: require("@typescript-eslint/parser"), - parserOptions: { - project: path.join(__dirname, "../example/tsconfig.json"), - }, - }, - plugins: { - "@fluid-internal/fluid": plugin, - }, - rules: { - "@fluid-internal/fluid/no-hyphen-after-jsdoc-tag": "error", - }, - }], + const eslintOptions = createESLintConfig({ + parser: "@typescript-eslint/parser", + parserOptions: { + project: path.join(__dirname, "../example/tsconfig.json"), + }, + plugin, + pluginName: "@fluid-internal/fluid", + rules: { + "@fluid-internal/fluid/no-hyphen-after-jsdoc-tag": "error", + }, }); + + const eslint = new ESLint(eslintOptions); const fileToLint = path.join(__dirname, "../example/no-hyphen-after-jsdoc-tag", file); const results = await eslint.lintFiles([fileToLint]); assert.equal(results.length, 1, "Expected a single result for linting a single file."); diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-markdown-links-in-jsdoc/enforce-no-markdown-links-in-jsdoc.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-markdown-links-in-jsdoc/enforce-no-markdown-links-in-jsdoc.test.js index 7afc17fd43de..a2ac789f04ea 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-markdown-links-in-jsdoc/enforce-no-markdown-links-in-jsdoc.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-markdown-links-in-jsdoc/enforce-no-markdown-links-in-jsdoc.test.js @@ -7,27 +7,23 @@ const assert = require("assert"); const path = require("path"); const { ESLint } = require("eslint"); const plugin = require("../../../index.js"); +const { createESLintConfig } = require("../eslintConfigHelper.js"); describe("Do not allow Markdown links in JSDoc/TSDoc comments", function () { async function lintFile(file) { - const eslint = new ESLint({ - overrideConfigFile: true, - overrideConfig: [{ - files: ["**/*.ts"], - languageOptions: { - parser: require("@typescript-eslint/parser"), - parserOptions: { - project: path.join(__dirname, "../example/tsconfig.json"), - }, - }, - plugins: { - "@fluid-internal/fluid": plugin, - }, - rules: { - "@fluid-internal/fluid/no-markdown-links-in-jsdoc": "error", - }, - }], + const eslintOptions = createESLintConfig({ + parser: "@typescript-eslint/parser", + parserOptions: { + project: path.join(__dirname, "../example/tsconfig.json"), + }, + plugin, + pluginName: "@fluid-internal/fluid", + rules: { + "@fluid-internal/fluid/no-markdown-links-in-jsdoc": "error", + }, }); + + const eslint = new ESLint(eslintOptions); const fileToLint = path.join(__dirname, "../example/no-markdown-links-in-jsdoc", file); const results = await eslint.lintFiles([fileToLint]); assert.equal(results.length, 1, "Expected a single result for linting a single file."); diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-member-release-tags/enforce-no-member-release-tags.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-member-release-tags/enforce-no-member-release-tags.test.js index 491d04c5375b..a5aaaa095bee 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-member-release-tags/enforce-no-member-release-tags.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-member-release-tags/enforce-no-member-release-tags.test.js @@ -7,27 +7,23 @@ const assert = require("assert"); const path = require("path"); const { ESLint } = require("eslint"); const plugin = require("../../../index.js"); +const { createESLintConfig } = require("../eslintConfigHelper.js"); describe("Do not allow release tags on members", function () { function createESLintInstance() { - return new ESLint({ - overrideConfigFile: true, - overrideConfig: [{ - files: ["**/*.ts"], - languageOptions: { - parser: require("@typescript-eslint/parser"), - parserOptions: { - project: path.join(__dirname, "../example/tsconfig.json"), - }, - }, - plugins: { - "@fluid-internal/fluid": plugin, - }, - rules: { - "@fluid-internal/fluid/no-member-release-tags": ["error"], - }, - }], + const eslintOptions = createESLintConfig({ + parser: "@typescript-eslint/parser", + parserOptions: { + project: path.join(__dirname, "../example/tsconfig.json"), + }, + plugin, + pluginName: "@fluid-internal/fluid", + rules: { + "@fluid-internal/fluid/no-member-release-tags": ["error"], + }, }); + + return new ESLint(eslintOptions); } it("Should report errors for including release tags inside the class declaration", async function () { diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-restricted-tags-imports/enforce-no-restricted-tags-imports.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-restricted-tags-imports/enforce-no-restricted-tags-imports.test.js index 9e79315eb0cb..29117ef90517 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-restricted-tags-imports/enforce-no-restricted-tags-imports.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-restricted-tags-imports/enforce-no-restricted-tags-imports.test.js @@ -7,24 +7,20 @@ const assert = require("assert"); const path = require("path"); const { ESLint } = require("eslint"); const plugin = require("../../../index.js"); +const { createESLintConfig } = require("../eslintConfigHelper.js"); describe("ESLint Rule Tests", function () { function createESLintInstance(config) { - return new ESLint({ - overrideConfigFile: true, - overrideConfig: [{ - files: ["**/*.ts"], - languageOptions: { - parser: require("@typescript-eslint/parser"), - parserOptions: config.parserOptions, - }, - plugins: { - "@fluid-internal/fluid": plugin, - ...config.plugins, - }, - rules: config.rules, - }], + const eslintOptions = createESLintConfig({ + parser: "@typescript-eslint/parser", + parserOptions: config.parserOptions, + plugin, + pluginName: "@fluid-internal/fluid", + rules: config.rules, + extraPlugins: config.plugins, }); + + return new ESLint(eslintOptions); } it("Should report an error for restricted tag imports", async function () { diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-unchecked-record-access/enforce-no-unchecked-record-access.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-unchecked-record-access/enforce-no-unchecked-record-access.test.js index 17bcc82b428c..05c4c1475b48 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-unchecked-record-access/enforce-no-unchecked-record-access.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-unchecked-record-access/enforce-no-unchecked-record-access.test.js @@ -7,28 +7,24 @@ const assert = require("assert"); const path = require("path"); const { ESLint } = require("eslint"); const plugin = require("../../../index.js"); +const { createESLintConfig } = require("../eslintConfigHelper.js"); describe("ESLint Rule Tests", function () { async function lintFile(file) { - const eslint = new ESLint({ - overrideConfigFile: true, - overrideConfig: [{ - files: ["**/*.ts"], - languageOptions: { - parser: require("@typescript-eslint/parser"), - parserOptions: { - projectService: true, - tsconfigRootDir: path.join(__dirname, "../example"), - }, - }, - plugins: { - "@fluid-internal/fluid": plugin, - }, - rules: { - "@fluid-internal/fluid/no-unchecked-record-access": "error", - }, - }], + const eslintOptions = createESLintConfig({ + parser: "@typescript-eslint/parser", + parserOptions: { + projectService: true, + tsconfigRootDir: path.join(__dirname, "../example"), + }, + plugin, + pluginName: "@fluid-internal/fluid", + rules: { + "@fluid-internal/fluid/no-unchecked-record-access": "error", + }, }); + + const eslint = new ESLint(eslintOptions); const fileToLint = path.join(__dirname, "../example/no-unchecked-record-access", file); const results = await eslint.lintFiles([fileToLint]); return results[0]; diff --git a/common/build/eslint-plugin-fluid/src/test/eslintConfigHelper.js b/common/build/eslint-plugin-fluid/src/test/eslintConfigHelper.js new file mode 100644 index 000000000000..7e0c8eb99365 --- /dev/null +++ b/common/build/eslint-plugin-fluid/src/test/eslintConfigHelper.js @@ -0,0 +1,66 @@ +/*! + * Copyright (c) Microsoft Corporation and contributors. All rights reserved. + * Licensed under the MIT License. + */ + +/** + * Helper to create ESLint configuration that works with both ESLint 8 and 9. + * ESLint 8 uses the legacy config format, while ESLint 9 uses flat config. + */ + +const eslintVersion = parseInt(require("eslint/package.json").version.split(".")[0]); + +/** + * Creates ESLint options object compatible with both ESLint 8 and 9. + * + * @param {object} config - Configuration object + * @param {string} config.parser - Parser name (e.g., "@typescript-eslint/parser") + * @param {object} config.parserOptions - Parser options + * @param {object} config.plugin - Plugin object to register + * @param {string} config.pluginName - Plugin name (e.g., "@fluid-internal/fluid") + * @param {object} config.rules - ESLint rules configuration + * @param {object} [config.extraPlugins] - Additional plugins to register (ESLint 9 format) + * @returns {object} ESLint options object + */ +function createESLintConfig(config) { + const { parser, parserOptions, plugin, pluginName, rules, extraPlugins } = config; + + const eslintOptions = { + overrideConfigFile: eslintVersion >= 9 ? true : null, + }; + + if (eslintVersion >= 9) { + // ESLint 9+ uses flat config + eslintOptions.overrideConfig = [ + { + files: ["**/*.ts"], + languageOptions: { + parser: require(parser), + parserOptions, + }, + plugins: { + [pluginName]: plugin, + ...extraPlugins, + }, + rules, + }, + ]; + } else { + // ESLint 8 uses legacy config + eslintOptions.baseConfig = { + parser, + parserOptions, + plugins: [pluginName], + rules, + }; + eslintOptions.useEslintrc = false; + eslintOptions.plugins = { + [pluginName]: plugin, + ...extraPlugins, + }; + } + + return eslintOptions; +} + +module.exports = { createESLintConfig, eslintVersion }; From f51fbc240d8d240bb8b4a6f8a3ff04276f005a60 Mon Sep 17 00:00:00 2001 From: Tyler Butler Date: Thu, 9 Oct 2025 12:13:36 -0700 Subject: [PATCH 04/12] Update common/build/eslint-plugin-fluid/src/test/enforce-no-unchecked-record-access/enforce-no-unchecked-record-access.test.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../enforce-no-unchecked-record-access.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-unchecked-record-access/enforce-no-unchecked-record-access.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-unchecked-record-access/enforce-no-unchecked-record-access.test.js index 05c4c1475b48..124471acb331 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-unchecked-record-access/enforce-no-unchecked-record-access.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-unchecked-record-access/enforce-no-unchecked-record-access.test.js @@ -14,6 +14,7 @@ describe("ESLint Rule Tests", function () { const eslintOptions = createESLintConfig({ parser: "@typescript-eslint/parser", parserOptions: { + project: path.join(__dirname, "../example/tsconfig.json"), projectService: true, tsconfigRootDir: path.join(__dirname, "../example"), }, From 95a067b6b2db4de2d1876194c5d573a9daca9a2b Mon Sep 17 00:00:00 2001 From: Tyler Butler Date: Thu, 9 Oct 2025 12:13:44 -0700 Subject: [PATCH 05/12] Update common/build/eslint-plugin-fluid/package.json Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- common/build/eslint-plugin-fluid/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/build/eslint-plugin-fluid/package.json b/common/build/eslint-plugin-fluid/package.json index b7ad7f6a1c31..2c0288db131d 100644 --- a/common/build/eslint-plugin-fluid/package.json +++ b/common/build/eslint-plugin-fluid/package.json @@ -21,8 +21,8 @@ "prettier:fix": "prettier --write . --cache --ignore-path ../../../.prettierignore", "test": "npm run test:both", "test:both": "npm run test:eslint8 && npm run test:eslint9", - "test:eslint8": "pnpm add -D eslint@~8.57.1 && npm run test:mocha", - "test:eslint9": "pnpm add -D eslint@~9.37.0 && npm run test:mocha", + "test:eslint8": "pnpm add -D eslint@~8.57.1 && pnpm run test:mocha", + "test:eslint9": "pnpm add -D eslint@~9.37.0 && pnpm run test:mocha", "test:mocha": "mocha \"src/test/**/*.test.*js\"" }, "dependencies": { From 7e78d784ae07de85130217c3d3923a1974286acd Mon Sep 17 00:00:00 2001 From: Tyler Butler Date: Thu, 9 Oct 2025 12:40:19 -0700 Subject: [PATCH 06/12] config fixes --- .../enforce-no-restricted-tags-imports.test.js | 3 +++ .../enforce-no-unchecked-record-access.test.js | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-restricted-tags-imports/enforce-no-restricted-tags-imports.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-restricted-tags-imports/enforce-no-restricted-tags-imports.test.js index 29117ef90517..8f6265f182d4 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-restricted-tags-imports/enforce-no-restricted-tags-imports.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-restricted-tags-imports/enforce-no-restricted-tags-imports.test.js @@ -36,6 +36,7 @@ describe("ESLint Rule Tests", function () { }, parserOptions: { project: path.join(__dirname, "../example/tsconfig.json"), + tsconfigRootDir: path.join(__dirname, "../example"), }, }); const filesToLint = ["fileWithImports.ts", "mockModule.ts"].map((file) => @@ -70,6 +71,7 @@ describe("ESLint Rule Tests", function () { }, parserOptions: { project: path.join(__dirname, "../example/tsconfig.json"), + tsconfigRootDir: path.join(__dirname, "../example"), }, }); const filesToLint = ["fileWithExceptionImports.ts", "exceptionFile.ts"].map((file) => @@ -97,6 +99,7 @@ describe("ESLint Rule Tests", function () { }, parserOptions: { project: path.join(__dirname, "../example/tsconfig.json"), + tsconfigRootDir: path.join(__dirname, "../example"), }, }); const filesToLint = ["fileWithImports.ts", "mockModule.ts"].map((file) => diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-unchecked-record-access/enforce-no-unchecked-record-access.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-unchecked-record-access/enforce-no-unchecked-record-access.test.js index 124471acb331..8c194877597b 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-unchecked-record-access/enforce-no-unchecked-record-access.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-unchecked-record-access/enforce-no-unchecked-record-access.test.js @@ -15,7 +15,6 @@ describe("ESLint Rule Tests", function () { parser: "@typescript-eslint/parser", parserOptions: { project: path.join(__dirname, "../example/tsconfig.json"), - projectService: true, tsconfigRootDir: path.join(__dirname, "../example"), }, plugin, From cb2758ce62b22eaa087c240c4b610b0611946ecc Mon Sep 17 00:00:00 2001 From: Tyler Butler Date: Mon, 13 Oct 2025 16:48:29 -0700 Subject: [PATCH 07/12] feedback --- common/build/eslint-plugin-fluid/package.json | 6 +- .../build/eslint-plugin-fluid/pnpm-lock.yaml | 196 ++++++++++++++++++ ...nforce-no-file-path-links-in-jsdoc.test.js | 3 +- .../enforce-no-hyphen-after-jsdoc-tag.test.js | 3 +- ...enforce-no-markdown-links-in-jsdoc.test.js | 3 +- .../enforce-no-member-release-tags.test.js | 3 +- ...enforce-no-restricted-tags-imports.test.js | 3 +- ...enforce-no-unchecked-record-access.test.js | 3 +- .../src/test/eslintConfigHelper.js | 7 +- 9 files changed, 211 insertions(+), 16 deletions(-) diff --git a/common/build/eslint-plugin-fluid/package.json b/common/build/eslint-plugin-fluid/package.json index 2c0288db131d..96b0bd29f703 100644 --- a/common/build/eslint-plugin-fluid/package.json +++ b/common/build/eslint-plugin-fluid/package.json @@ -21,8 +21,8 @@ "prettier:fix": "prettier --write . --cache --ignore-path ../../../.prettierignore", "test": "npm run test:both", "test:both": "npm run test:eslint8 && npm run test:eslint9", - "test:eslint8": "pnpm add -D eslint@~8.57.1 && pnpm run test:mocha", - "test:eslint9": "pnpm add -D eslint@~9.37.0 && pnpm run test:mocha", + "test:eslint8": "cross-env ESLINT_PACKAGE=eslint8 npm run test:mocha", + "test:eslint9": "cross-env ESLINT_PACKAGE=eslint npm run test:mocha", "test:mocha": "mocha \"src/test/**/*.test.*js\"" }, "dependencies": { @@ -34,7 +34,9 @@ "devDependencies": { "@fluid-tools/markdown-magic": "file:../../../tools/markdown-magic", "@fluidframework/build-common": "^2.0.3", + "cross-env": "^7.0.3", "eslint": "~9.37.0", + "eslint8": "npm:eslint@~8.57.1", "mocha": "^10.8.2", "mocha-multi-reporters": "^1.5.1", "prettier": "~3.6.2", diff --git a/common/build/eslint-plugin-fluid/pnpm-lock.yaml b/common/build/eslint-plugin-fluid/pnpm-lock.yaml index a6eff96fea83..f8b0659cfb2c 100644 --- a/common/build/eslint-plugin-fluid/pnpm-lock.yaml +++ b/common/build/eslint-plugin-fluid/pnpm-lock.yaml @@ -27,9 +27,15 @@ importers: '@fluidframework/build-common': specifier: ^2.0.3 version: 2.0.3 + cross-env: + specifier: ^7.0.3 + version: 7.0.3 eslint: specifier: ~9.37.0 version: 9.37.0 + eslint8: + specifier: npm:eslint@~8.57.1 + version: eslint@8.57.1 mocha: specifier: ^10.8.2 version: 10.8.2 @@ -70,10 +76,18 @@ packages: resolution: {integrity: sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/eslintrc@2.1.4': + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/eslintrc@3.3.1': resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/js@8.57.1': + resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/js@9.37.0': resolution: {integrity: sha512-jaS+NJ+hximswBG6pjNX0uEJZkrT0zwpVi3BA3vX22aFGjJjmgSTSmPpZCRKmoBL5VY/M6p0xsSJx7rk7sy5gg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -102,10 +116,19 @@ packages: resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} engines: {node: '>=18.18.0'} + '@humanwhocodes/config-array@0.13.0': + resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} + engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead + '@humanwhocodes/module-importer@1.0.1': resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} + '@humanwhocodes/object-schema@2.0.3': + resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} + deprecated: Use @eslint/object-schema instead + '@humanwhocodes/retry@0.4.3': resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} @@ -249,6 +272,9 @@ packages: resolution: {integrity: sha512-FrvMpAK+hTbFy7vH5j1+tMYHMSKLE6RzluFJlkFNKD0p9YsUT75JlBSmr5so3QRzvMwU5/bIEdeNrxm8du8l3Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@ungap/structured-clone@1.3.0': + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -427,6 +453,11 @@ packages: core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + cross-env@7.0.3: + resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} + engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} + hasBin: true + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -483,6 +514,10 @@ packages: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} + doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + dom-serializer@1.4.1: resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==} @@ -561,6 +596,10 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} + eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + eslint-scope@8.4.0: resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -573,6 +612,12 @@ packages: resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint@8.57.1: + resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. + hasBin: true + eslint@9.37.0: resolution: {integrity: sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -587,6 +632,10 @@ packages: resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + esquery@1.5.0: resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} engines: {node: '>=0.10'} @@ -625,6 +674,10 @@ packages: fault@1.0.4: resolution: {integrity: sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==} + file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} @@ -642,6 +695,10 @@ packages: engines: {node: '>=0.6'} hasBin: true + flat-cache@3.2.0: + resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} + engines: {node: ^10.12.0 || >=12.0.0} + flat-cache@4.0.1: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} @@ -732,6 +789,10 @@ packages: engines: {node: '>=12'} deprecated: Glob versions prior to v9 are no longer supported + globals@13.24.0: + resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} + engines: {node: '>=8'} + globals@14.0.0: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} @@ -751,6 +812,9 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + has-bigints@1.0.2: resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} @@ -894,6 +958,10 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + is-plain-obj@2.1.0: resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} engines: {node: '>=8'} @@ -1280,6 +1348,11 @@ packages: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + rimraf@5.0.7: resolution: {integrity: sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==} engines: {node: '>=14.18'} @@ -1399,6 +1472,9 @@ packages: sync-rpc@1.3.6: resolution: {integrity: sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==} + text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + then-request@6.0.2: resolution: {integrity: sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==} engines: {node: '>=6.0.0'} @@ -1427,6 +1503,10 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} + type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + typed-array-buffer@1.0.2: resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} engines: {node: '>= 0.4'} @@ -1590,6 +1670,20 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 + '@eslint/eslintrc@2.1.4': + dependencies: + ajv: 6.12.6 + debug: 4.4.0(supports-color@8.1.1) + espree: 9.6.1 + globals: 13.24.0 + ignore: 5.3.1 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + '@eslint/eslintrc@3.3.1': dependencies: ajv: 6.12.6 @@ -1604,6 +1698,8 @@ snapshots: transitivePeerDependencies: - supports-color + '@eslint/js@8.57.1': {} + '@eslint/js@9.37.0': {} '@eslint/object-schema@2.1.6': {} @@ -1634,8 +1730,18 @@ snapshots: '@humanfs/core': 0.19.1 '@humanwhocodes/retry': 0.4.3 + '@humanwhocodes/config-array@0.13.0': + dependencies: + '@humanwhocodes/object-schema': 2.0.3 + debug: 4.4.0(supports-color@8.1.1) + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + '@humanwhocodes/module-importer@1.0.1': {} + '@humanwhocodes/object-schema@2.0.3': {} + '@humanwhocodes/retry@0.4.3': {} '@isaacs/cliui@8.0.2': @@ -1849,6 +1955,8 @@ snapshots: '@typescript-eslint/types': 8.46.0 eslint-visitor-keys: 4.2.1 + '@ungap/structured-clone@1.3.0': {} + acorn-jsx@5.3.2(acorn@8.15.0): dependencies: acorn: 8.15.0 @@ -2020,6 +2128,10 @@ snapshots: core-util-is@1.0.3: {} + cross-env@7.0.3: + dependencies: + cross-spawn: 7.0.6 + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -2076,6 +2188,10 @@ snapshots: dependencies: path-type: 4.0.0 + doctrine@3.0.0: + dependencies: + esutils: 2.0.3 + dom-serializer@1.4.1: dependencies: domelementtype: 2.3.0 @@ -2202,6 +2318,11 @@ snapshots: escape-string-regexp@4.0.0: {} + eslint-scope@7.2.2: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + eslint-scope@8.4.0: dependencies: esrecurse: 4.3.0 @@ -2211,6 +2332,49 @@ snapshots: eslint-visitor-keys@4.2.1: {} + eslint@8.57.1: + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.37.0) + '@eslint-community/regexpp': 4.12.1 + '@eslint/eslintrc': 2.1.4 + '@eslint/js': 8.57.1 + '@humanwhocodes/config-array': 0.13.0 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.3.0 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.0(supports-color@8.1.1) + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.5.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.24.0 + graphemer: 1.4.0 + ignore: 5.3.1 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + eslint@9.37.0: dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.37.0) @@ -2257,6 +2421,12 @@ snapshots: acorn-jsx: 5.3.2(acorn@8.15.0) eslint-visitor-keys: 4.2.1 + espree@9.6.1: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 3.4.3 + esquery@1.5.0: dependencies: estraverse: 5.3.0 @@ -2293,6 +2463,10 @@ snapshots: dependencies: format: 0.2.2 + file-entry-cache@6.0.1: + dependencies: + flat-cache: 3.2.0 + file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 @@ -2311,6 +2485,12 @@ snapshots: colors: 0.6.2 commander: 2.1.0 + flat-cache@3.2.0: + dependencies: + flatted: 3.3.1 + keyv: 4.5.4 + rimraf: 3.0.2 + flat-cache@4.0.1: dependencies: flatted: 3.3.1 @@ -2423,6 +2603,10 @@ snapshots: minimatch: 5.1.6 once: 1.4.0 + globals@13.24.0: + dependencies: + type-fest: 0.20.2 + globals@14.0.0: {} globalthis@1.0.4: @@ -2445,6 +2629,8 @@ snapshots: graceful-fs@4.2.11: {} + graphemer@1.4.0: {} + has-bigints@1.0.2: {} has-flag@4.0.0: {} @@ -2579,6 +2765,8 @@ snapshots: is-number@7.0.0: {} + is-path-inside@3.0.3: {} + is-plain-obj@2.1.0: {} is-regex@1.1.4: @@ -3039,6 +3227,10 @@ snapshots: reusify@1.0.4: {} + rimraf@3.0.2: + dependencies: + glob: 7.2.3 + rimraf@5.0.7: dependencies: glob: 10.3.16 @@ -3174,6 +3366,8 @@ snapshots: dependencies: get-port: 3.2.0 + text-table@0.2.0: {} + then-request@6.0.2: dependencies: '@types/concat-stream': 1.6.1 @@ -3213,6 +3407,8 @@ snapshots: dependencies: prelude-ls: 1.2.1 + type-fest@0.20.2: {} + typed-array-buffer@1.0.2: dependencies: call-bind: 1.0.7 diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-file-path-links-in-jsdoc/enforce-no-file-path-links-in-jsdoc.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-file-path-links-in-jsdoc/enforce-no-file-path-links-in-jsdoc.test.js index 6167c6bd2cd3..4a5bf0e6c4f2 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-file-path-links-in-jsdoc/enforce-no-file-path-links-in-jsdoc.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-file-path-links-in-jsdoc/enforce-no-file-path-links-in-jsdoc.test.js @@ -5,9 +5,8 @@ const assert = require("assert"); const path = require("path"); -const { ESLint } = require("eslint"); const plugin = require("../../../index.js"); -const { createESLintConfig } = require("../eslintConfigHelper.js"); +const { createESLintConfig, ESLint } = require("../eslintConfigHelper.js"); describe("Do not allow file path links in JSDoc/TSDoc comments", function () { async function lintFile(file) { diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-hyphen-after-jsdoc-tag/enforce-no-hyphen-after-jsdoc-tag.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-hyphen-after-jsdoc-tag/enforce-no-hyphen-after-jsdoc-tag.test.js index 61eb08e5641e..16370ff78ab1 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-hyphen-after-jsdoc-tag/enforce-no-hyphen-after-jsdoc-tag.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-hyphen-after-jsdoc-tag/enforce-no-hyphen-after-jsdoc-tag.test.js @@ -5,9 +5,8 @@ const assert = require("assert"); const path = require("path"); -const { ESLint } = require("eslint"); const plugin = require("../../../index.js"); -const { createESLintConfig } = require("../eslintConfigHelper.js"); +const { createESLintConfig, ESLint } = require("../eslintConfigHelper.js"); describe("Do not allow `-` following JSDoc/TSDoc tags", function () { /** diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-markdown-links-in-jsdoc/enforce-no-markdown-links-in-jsdoc.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-markdown-links-in-jsdoc/enforce-no-markdown-links-in-jsdoc.test.js index a2ac789f04ea..9db4a456c3ff 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-markdown-links-in-jsdoc/enforce-no-markdown-links-in-jsdoc.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-markdown-links-in-jsdoc/enforce-no-markdown-links-in-jsdoc.test.js @@ -5,9 +5,8 @@ const assert = require("assert"); const path = require("path"); -const { ESLint } = require("eslint"); const plugin = require("../../../index.js"); -const { createESLintConfig } = require("../eslintConfigHelper.js"); +const { createESLintConfig, ESLint } = require("../eslintConfigHelper.js"); describe("Do not allow Markdown links in JSDoc/TSDoc comments", function () { async function lintFile(file) { diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-member-release-tags/enforce-no-member-release-tags.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-member-release-tags/enforce-no-member-release-tags.test.js index a5aaaa095bee..9c51a2758ad8 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-member-release-tags/enforce-no-member-release-tags.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-member-release-tags/enforce-no-member-release-tags.test.js @@ -5,9 +5,8 @@ const assert = require("assert"); const path = require("path"); -const { ESLint } = require("eslint"); const plugin = require("../../../index.js"); -const { createESLintConfig } = require("../eslintConfigHelper.js"); +const { createESLintConfig, ESLint } = require("../eslintConfigHelper.js"); describe("Do not allow release tags on members", function () { function createESLintInstance() { diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-restricted-tags-imports/enforce-no-restricted-tags-imports.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-restricted-tags-imports/enforce-no-restricted-tags-imports.test.js index 8f6265f182d4..73320b3ed49d 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-restricted-tags-imports/enforce-no-restricted-tags-imports.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-restricted-tags-imports/enforce-no-restricted-tags-imports.test.js @@ -5,9 +5,8 @@ const assert = require("assert"); const path = require("path"); -const { ESLint } = require("eslint"); const plugin = require("../../../index.js"); -const { createESLintConfig } = require("../eslintConfigHelper.js"); +const { createESLintConfig, ESLint } = require("../eslintConfigHelper.js"); describe("ESLint Rule Tests", function () { function createESLintInstance(config) { diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-unchecked-record-access/enforce-no-unchecked-record-access.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-unchecked-record-access/enforce-no-unchecked-record-access.test.js index 8c194877597b..f40b8cee8990 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-unchecked-record-access/enforce-no-unchecked-record-access.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-unchecked-record-access/enforce-no-unchecked-record-access.test.js @@ -5,9 +5,8 @@ const assert = require("assert"); const path = require("path"); -const { ESLint } = require("eslint"); const plugin = require("../../../index.js"); -const { createESLintConfig } = require("../eslintConfigHelper.js"); +const { createESLintConfig, ESLint } = require("../eslintConfigHelper.js"); describe("ESLint Rule Tests", function () { async function lintFile(file) { diff --git a/common/build/eslint-plugin-fluid/src/test/eslintConfigHelper.js b/common/build/eslint-plugin-fluid/src/test/eslintConfigHelper.js index 7e0c8eb99365..bcfe518bcfd0 100644 --- a/common/build/eslint-plugin-fluid/src/test/eslintConfigHelper.js +++ b/common/build/eslint-plugin-fluid/src/test/eslintConfigHelper.js @@ -8,7 +8,10 @@ * ESLint 8 uses the legacy config format, while ESLint 9 uses flat config. */ -const eslintVersion = parseInt(require("eslint/package.json").version.split(".")[0]); +// Support testing against different ESLint versions using npm aliases +const eslintPackage = process.env.ESLINT_PACKAGE || "eslint"; +const eslintVersion = parseInt(require(`${eslintPackage}/package.json`).version.split(".")[0]); +const { ESLint } = require(eslintPackage); /** * Creates ESLint options object compatible with both ESLint 8 and 9. @@ -63,4 +66,4 @@ function createESLintConfig(config) { return eslintOptions; } -module.exports = { createESLintConfig, eslintVersion }; +module.exports = { createESLintConfig, eslintVersion, ESLint }; From dd258e0b8b0c8998a09daef0077aac3a34b08a3f Mon Sep 17 00:00:00 2001 From: Tyler Butler Date: Mon, 13 Oct 2025 16:52:57 -0700 Subject: [PATCH 08/12] updates --- .../enforce-no-file-path-links-in-jsdoc.test.js | 2 +- .../enforce-no-hyphen-after-jsdoc-tag.test.js | 2 +- .../enforce-no-markdown-links-in-jsdoc.test.js | 2 +- .../enforce-no-member-release-tags.test.js | 2 +- .../enforce-no-restricted-tags-imports.test.js | 2 +- .../enforce-no-unchecked-record-access.test.js | 2 +- .../src/test/{eslintConfigHelper.js => eslintConfigHelper.cjs} | 0 7 files changed, 6 insertions(+), 6 deletions(-) rename common/build/eslint-plugin-fluid/src/test/{eslintConfigHelper.js => eslintConfigHelper.cjs} (100%) diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-file-path-links-in-jsdoc/enforce-no-file-path-links-in-jsdoc.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-file-path-links-in-jsdoc/enforce-no-file-path-links-in-jsdoc.test.js index 4a5bf0e6c4f2..067fef6cb10c 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-file-path-links-in-jsdoc/enforce-no-file-path-links-in-jsdoc.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-file-path-links-in-jsdoc/enforce-no-file-path-links-in-jsdoc.test.js @@ -6,7 +6,7 @@ const assert = require("assert"); const path = require("path"); const plugin = require("../../../index.js"); -const { createESLintConfig, ESLint } = require("../eslintConfigHelper.js"); +const { createESLintConfig, ESLint } = require("../eslintConfigHelper.cjs"); describe("Do not allow file path links in JSDoc/TSDoc comments", function () { async function lintFile(file) { diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-hyphen-after-jsdoc-tag/enforce-no-hyphen-after-jsdoc-tag.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-hyphen-after-jsdoc-tag/enforce-no-hyphen-after-jsdoc-tag.test.js index 16370ff78ab1..57edd1d1eec9 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-hyphen-after-jsdoc-tag/enforce-no-hyphen-after-jsdoc-tag.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-hyphen-after-jsdoc-tag/enforce-no-hyphen-after-jsdoc-tag.test.js @@ -6,7 +6,7 @@ const assert = require("assert"); const path = require("path"); const plugin = require("../../../index.js"); -const { createESLintConfig, ESLint } = require("../eslintConfigHelper.js"); +const { createESLintConfig, ESLint } = require("../eslintConfigHelper.cjs"); describe("Do not allow `-` following JSDoc/TSDoc tags", function () { /** diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-markdown-links-in-jsdoc/enforce-no-markdown-links-in-jsdoc.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-markdown-links-in-jsdoc/enforce-no-markdown-links-in-jsdoc.test.js index 9db4a456c3ff..a4a16ea15f2a 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-markdown-links-in-jsdoc/enforce-no-markdown-links-in-jsdoc.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-markdown-links-in-jsdoc/enforce-no-markdown-links-in-jsdoc.test.js @@ -6,7 +6,7 @@ const assert = require("assert"); const path = require("path"); const plugin = require("../../../index.js"); -const { createESLintConfig, ESLint } = require("../eslintConfigHelper.js"); +const { createESLintConfig, ESLint } = require("../eslintConfigHelper.cjs"); describe("Do not allow Markdown links in JSDoc/TSDoc comments", function () { async function lintFile(file) { diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-member-release-tags/enforce-no-member-release-tags.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-member-release-tags/enforce-no-member-release-tags.test.js index 9c51a2758ad8..a55353c6cc75 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-member-release-tags/enforce-no-member-release-tags.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-member-release-tags/enforce-no-member-release-tags.test.js @@ -6,7 +6,7 @@ const assert = require("assert"); const path = require("path"); const plugin = require("../../../index.js"); -const { createESLintConfig, ESLint } = require("../eslintConfigHelper.js"); +const { createESLintConfig, ESLint } = require("../eslintConfigHelper.cjs"); describe("Do not allow release tags on members", function () { function createESLintInstance() { diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-restricted-tags-imports/enforce-no-restricted-tags-imports.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-restricted-tags-imports/enforce-no-restricted-tags-imports.test.js index 73320b3ed49d..a1a63679d52f 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-restricted-tags-imports/enforce-no-restricted-tags-imports.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-restricted-tags-imports/enforce-no-restricted-tags-imports.test.js @@ -6,7 +6,7 @@ const assert = require("assert"); const path = require("path"); const plugin = require("../../../index.js"); -const { createESLintConfig, ESLint } = require("../eslintConfigHelper.js"); +const { createESLintConfig, ESLint } = require("../eslintConfigHelper.cjs"); describe("ESLint Rule Tests", function () { function createESLintInstance(config) { diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-unchecked-record-access/enforce-no-unchecked-record-access.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-unchecked-record-access/enforce-no-unchecked-record-access.test.js index f40b8cee8990..bdccd131c930 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-unchecked-record-access/enforce-no-unchecked-record-access.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-unchecked-record-access/enforce-no-unchecked-record-access.test.js @@ -6,7 +6,7 @@ const assert = require("assert"); const path = require("path"); const plugin = require("../../../index.js"); -const { createESLintConfig, ESLint } = require("../eslintConfigHelper.js"); +const { createESLintConfig, ESLint } = require("../eslintConfigHelper.cjs"); describe("ESLint Rule Tests", function () { async function lintFile(file) { diff --git a/common/build/eslint-plugin-fluid/src/test/eslintConfigHelper.js b/common/build/eslint-plugin-fluid/src/test/eslintConfigHelper.cjs similarity index 100% rename from common/build/eslint-plugin-fluid/src/test/eslintConfigHelper.js rename to common/build/eslint-plugin-fluid/src/test/eslintConfigHelper.cjs From 66a0d5136cbe78d78cabb9554cad1b82b603e19b Mon Sep 17 00:00:00 2001 From: Tyler Butler Date: Mon, 13 Oct 2025 17:04:21 -0700 Subject: [PATCH 09/12] include eslint version in output --- .../enforce-no-file-path-links-in-jsdoc.test.js | 8 ++------ .../enforce-no-hyphen-after-jsdoc-tag.test.js | 8 ++------ .../enforce-no-markdown-links-in-jsdoc.test.js | 8 ++------ .../enforce-no-member-release-tags.test.js | 8 ++------ .../enforce-no-restricted-tags-imports.test.js | 11 ++--------- .../enforce-no-unchecked-record-access.test.js | 9 ++------- .../src/test/eslintConfigHelper.cjs | 9 +++++---- 7 files changed, 17 insertions(+), 44 deletions(-) diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-file-path-links-in-jsdoc/enforce-no-file-path-links-in-jsdoc.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-file-path-links-in-jsdoc/enforce-no-file-path-links-in-jsdoc.test.js index 067fef6cb10c..0458f07c96f0 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-file-path-links-in-jsdoc/enforce-no-file-path-links-in-jsdoc.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-file-path-links-in-jsdoc/enforce-no-file-path-links-in-jsdoc.test.js @@ -5,18 +5,14 @@ const assert = require("assert"); const path = require("path"); -const plugin = require("../../../index.js"); -const { createESLintConfig, ESLint } = require("../eslintConfigHelper.cjs"); +const { createESLintConfig, eslintVersion, ESLint } = require("../eslintConfigHelper.cjs"); -describe("Do not allow file path links in JSDoc/TSDoc comments", function () { +describe(`Do not allow file path links in JSDoc/TSDoc comments (eslint ${eslintVersion})`, function () { async function lintFile(file) { const eslintOptions = createESLintConfig({ - parser: "@typescript-eslint/parser", parserOptions: { project: path.join(__dirname, "../example/tsconfig.json"), }, - plugin, - pluginName: "@fluid-internal/fluid", rules: { "@fluid-internal/fluid/no-file-path-links-in-jsdoc": "error", }, diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-hyphen-after-jsdoc-tag/enforce-no-hyphen-after-jsdoc-tag.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-hyphen-after-jsdoc-tag/enforce-no-hyphen-after-jsdoc-tag.test.js index 57edd1d1eec9..924d1f78e04a 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-hyphen-after-jsdoc-tag/enforce-no-hyphen-after-jsdoc-tag.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-hyphen-after-jsdoc-tag/enforce-no-hyphen-after-jsdoc-tag.test.js @@ -5,10 +5,9 @@ const assert = require("assert"); const path = require("path"); -const plugin = require("../../../index.js"); -const { createESLintConfig, ESLint } = require("../eslintConfigHelper.cjs"); +const { createESLintConfig, eslintVersion, ESLint } = require("../eslintConfigHelper.cjs"); -describe("Do not allow `-` following JSDoc/TSDoc tags", function () { +describe(`Do not allow \`-\` following JSDoc/TSDoc tags (eslint ${eslintVersion})`, function () { /** * * @param {string} file - Path to the file being linted. Relative to the `example/no-hyphen-after-jsdoc-tag` folder. @@ -16,12 +15,9 @@ describe("Do not allow `-` following JSDoc/TSDoc tags", function () { */ async function lintFile(file) { const eslintOptions = createESLintConfig({ - parser: "@typescript-eslint/parser", parserOptions: { project: path.join(__dirname, "../example/tsconfig.json"), }, - plugin, - pluginName: "@fluid-internal/fluid", rules: { "@fluid-internal/fluid/no-hyphen-after-jsdoc-tag": "error", }, diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-markdown-links-in-jsdoc/enforce-no-markdown-links-in-jsdoc.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-markdown-links-in-jsdoc/enforce-no-markdown-links-in-jsdoc.test.js index a4a16ea15f2a..79922bac02d8 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-markdown-links-in-jsdoc/enforce-no-markdown-links-in-jsdoc.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-markdown-links-in-jsdoc/enforce-no-markdown-links-in-jsdoc.test.js @@ -5,18 +5,14 @@ const assert = require("assert"); const path = require("path"); -const plugin = require("../../../index.js"); -const { createESLintConfig, ESLint } = require("../eslintConfigHelper.cjs"); +const { createESLintConfig, eslintVersion, ESLint } = require("../eslintConfigHelper.cjs"); -describe("Do not allow Markdown links in JSDoc/TSDoc comments", function () { +describe(`Do not allow Markdown links in JSDoc/TSDoc comments (eslint ${eslintVersion})`, function () { async function lintFile(file) { const eslintOptions = createESLintConfig({ - parser: "@typescript-eslint/parser", parserOptions: { project: path.join(__dirname, "../example/tsconfig.json"), }, - plugin, - pluginName: "@fluid-internal/fluid", rules: { "@fluid-internal/fluid/no-markdown-links-in-jsdoc": "error", }, diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-member-release-tags/enforce-no-member-release-tags.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-member-release-tags/enforce-no-member-release-tags.test.js index a55353c6cc75..8db09bdc37da 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-member-release-tags/enforce-no-member-release-tags.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-member-release-tags/enforce-no-member-release-tags.test.js @@ -5,18 +5,14 @@ const assert = require("assert"); const path = require("path"); -const plugin = require("../../../index.js"); -const { createESLintConfig, ESLint } = require("../eslintConfigHelper.cjs"); +const { createESLintConfig, eslintVersion, ESLint } = require("../eslintConfigHelper.cjs"); -describe("Do not allow release tags on members", function () { +describe(`Do not allow release tags on members (eslint ${eslintVersion})`, function () { function createESLintInstance() { const eslintOptions = createESLintConfig({ - parser: "@typescript-eslint/parser", parserOptions: { project: path.join(__dirname, "../example/tsconfig.json"), }, - plugin, - pluginName: "@fluid-internal/fluid", rules: { "@fluid-internal/fluid/no-member-release-tags": ["error"], }, diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-restricted-tags-imports/enforce-no-restricted-tags-imports.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-restricted-tags-imports/enforce-no-restricted-tags-imports.test.js index a1a63679d52f..f9203e520ad8 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-restricted-tags-imports/enforce-no-restricted-tags-imports.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-restricted-tags-imports/enforce-no-restricted-tags-imports.test.js @@ -5,16 +5,12 @@ const assert = require("assert"); const path = require("path"); -const plugin = require("../../../index.js"); -const { createESLintConfig, ESLint } = require("../eslintConfigHelper.cjs"); +const { createESLintConfig, eslintVersion, ESLint } = require("../eslintConfigHelper.cjs"); -describe("ESLint Rule Tests", function () { +describe(`ESLint Rule Tests (eslint ${eslintVersion})`, function () { function createESLintInstance(config) { const eslintOptions = createESLintConfig({ - parser: "@typescript-eslint/parser", parserOptions: config.parserOptions, - plugin, - pluginName: "@fluid-internal/fluid", rules: config.rules, extraPlugins: config.plugins, }); @@ -35,7 +31,6 @@ describe("ESLint Rule Tests", function () { }, parserOptions: { project: path.join(__dirname, "../example/tsconfig.json"), - tsconfigRootDir: path.join(__dirname, "../example"), }, }); const filesToLint = ["fileWithImports.ts", "mockModule.ts"].map((file) => @@ -70,7 +65,6 @@ describe("ESLint Rule Tests", function () { }, parserOptions: { project: path.join(__dirname, "../example/tsconfig.json"), - tsconfigRootDir: path.join(__dirname, "../example"), }, }); const filesToLint = ["fileWithExceptionImports.ts", "exceptionFile.ts"].map((file) => @@ -98,7 +92,6 @@ describe("ESLint Rule Tests", function () { }, parserOptions: { project: path.join(__dirname, "../example/tsconfig.json"), - tsconfigRootDir: path.join(__dirname, "../example"), }, }); const filesToLint = ["fileWithImports.ts", "mockModule.ts"].map((file) => diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-unchecked-record-access/enforce-no-unchecked-record-access.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-unchecked-record-access/enforce-no-unchecked-record-access.test.js index bdccd131c930..f5ab443abb28 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-unchecked-record-access/enforce-no-unchecked-record-access.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-unchecked-record-access/enforce-no-unchecked-record-access.test.js @@ -5,19 +5,14 @@ const assert = require("assert"); const path = require("path"); -const plugin = require("../../../index.js"); -const { createESLintConfig, ESLint } = require("../eslintConfigHelper.cjs"); +const { createESLintConfig, eslintVersion, ESLint } = require("../eslintConfigHelper.cjs"); -describe("ESLint Rule Tests", function () { +describe(`ESLint Rule Tests (eslint ${eslintVersion})`, function () { async function lintFile(file) { const eslintOptions = createESLintConfig({ - parser: "@typescript-eslint/parser", parserOptions: { project: path.join(__dirname, "../example/tsconfig.json"), - tsconfigRootDir: path.join(__dirname, "../example"), }, - plugin, - pluginName: "@fluid-internal/fluid", rules: { "@fluid-internal/fluid/no-unchecked-record-access": "error", }, diff --git a/common/build/eslint-plugin-fluid/src/test/eslintConfigHelper.cjs b/common/build/eslint-plugin-fluid/src/test/eslintConfigHelper.cjs index bcfe518bcfd0..0a5aad969373 100644 --- a/common/build/eslint-plugin-fluid/src/test/eslintConfigHelper.cjs +++ b/common/build/eslint-plugin-fluid/src/test/eslintConfigHelper.cjs @@ -12,21 +12,22 @@ const eslintPackage = process.env.ESLINT_PACKAGE || "eslint"; const eslintVersion = parseInt(require(`${eslintPackage}/package.json`).version.split(".")[0]); const { ESLint } = require(eslintPackage); +const plugin = require("../../index.js"); /** * Creates ESLint options object compatible with both ESLint 8 and 9. * * @param {object} config - Configuration object - * @param {string} config.parser - Parser name (e.g., "@typescript-eslint/parser") * @param {object} config.parserOptions - Parser options - * @param {object} config.plugin - Plugin object to register - * @param {string} config.pluginName - Plugin name (e.g., "@fluid-internal/fluid") * @param {object} config.rules - ESLint rules configuration * @param {object} [config.extraPlugins] - Additional plugins to register (ESLint 9 format) * @returns {object} ESLint options object */ function createESLintConfig(config) { - const { parser, parserOptions, plugin, pluginName, rules, extraPlugins } = config; + const { parserOptions, rules, extraPlugins } = config; + + const parser = "@typescript-eslint/parser"; + const pluginName = "@fluid-internal/fluid"; const eslintOptions = { overrideConfigFile: eslintVersion >= 9 ? true : null, From 4c4d8f7ec4e7ecf2647f6f1f881337939c66f27e Mon Sep 17 00:00:00 2001 From: Tyler Butler Date: Mon, 13 Oct 2025 17:21:00 -0700 Subject: [PATCH 10/12] more DRY --- ...nforce-no-file-path-links-in-jsdoc.test.js | 3 -- .../enforce-no-hyphen-after-jsdoc-tag.test.js | 3 -- ...enforce-no-markdown-links-in-jsdoc.test.js | 3 -- .../enforce-no-member-release-tags.test.js | 29 ++++++---------- ...enforce-no-restricted-tags-imports.test.js | 14 +------- ...enforce-no-unchecked-record-access.test.js | 3 -- .../src/test/eslintConfigHelper.cjs | 34 +++++++++++++++++-- 7 files changed, 42 insertions(+), 47 deletions(-) diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-file-path-links-in-jsdoc/enforce-no-file-path-links-in-jsdoc.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-file-path-links-in-jsdoc/enforce-no-file-path-links-in-jsdoc.test.js index 0458f07c96f0..b8d603088454 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-file-path-links-in-jsdoc/enforce-no-file-path-links-in-jsdoc.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-file-path-links-in-jsdoc/enforce-no-file-path-links-in-jsdoc.test.js @@ -10,9 +10,6 @@ const { createESLintConfig, eslintVersion, ESLint } = require("../eslintConfigHe describe(`Do not allow file path links in JSDoc/TSDoc comments (eslint ${eslintVersion})`, function () { async function lintFile(file) { const eslintOptions = createESLintConfig({ - parserOptions: { - project: path.join(__dirname, "../example/tsconfig.json"), - }, rules: { "@fluid-internal/fluid/no-file-path-links-in-jsdoc": "error", }, diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-hyphen-after-jsdoc-tag/enforce-no-hyphen-after-jsdoc-tag.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-hyphen-after-jsdoc-tag/enforce-no-hyphen-after-jsdoc-tag.test.js index 924d1f78e04a..df66b1a75407 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-hyphen-after-jsdoc-tag/enforce-no-hyphen-after-jsdoc-tag.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-hyphen-after-jsdoc-tag/enforce-no-hyphen-after-jsdoc-tag.test.js @@ -15,9 +15,6 @@ describe(`Do not allow \`-\` following JSDoc/TSDoc tags (eslint ${eslintVersion} */ async function lintFile(file) { const eslintOptions = createESLintConfig({ - parserOptions: { - project: path.join(__dirname, "../example/tsconfig.json"), - }, rules: { "@fluid-internal/fluid/no-hyphen-after-jsdoc-tag": "error", }, diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-markdown-links-in-jsdoc/enforce-no-markdown-links-in-jsdoc.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-markdown-links-in-jsdoc/enforce-no-markdown-links-in-jsdoc.test.js index 79922bac02d8..933d8d1406a5 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-markdown-links-in-jsdoc/enforce-no-markdown-links-in-jsdoc.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-markdown-links-in-jsdoc/enforce-no-markdown-links-in-jsdoc.test.js @@ -10,9 +10,6 @@ const { createESLintConfig, eslintVersion, ESLint } = require("../eslintConfigHe describe(`Do not allow Markdown links in JSDoc/TSDoc comments (eslint ${eslintVersion})`, function () { async function lintFile(file) { const eslintOptions = createESLintConfig({ - parserOptions: { - project: path.join(__dirname, "../example/tsconfig.json"), - }, rules: { "@fluid-internal/fluid/no-markdown-links-in-jsdoc": "error", }, diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-member-release-tags/enforce-no-member-release-tags.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-member-release-tags/enforce-no-member-release-tags.test.js index 8db09bdc37da..59a016ddd807 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-member-release-tags/enforce-no-member-release-tags.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-member-release-tags/enforce-no-member-release-tags.test.js @@ -5,24 +5,15 @@ const assert = require("assert"); const path = require("path"); -const { createESLintConfig, eslintVersion, ESLint } = require("../eslintConfigHelper.cjs"); +const { createESLintInstance, eslintVersion } = require("../eslintConfigHelper.cjs"); describe(`Do not allow release tags on members (eslint ${eslintVersion})`, function () { - function createESLintInstance() { - const eslintOptions = createESLintConfig({ - parserOptions: { - project: path.join(__dirname, "../example/tsconfig.json"), - }, - rules: { - "@fluid-internal/fluid/no-member-release-tags": ["error"], - }, - }); - - return new ESLint(eslintOptions); - } + const eslintRules = { + "@fluid-internal/fluid/no-member-release-tags": ["error"], + }; it("Should report errors for including release tags inside the class declaration", async function () { - const eslint = createESLintInstance(); + const eslint = createESLintInstance(eslintRules); const filesToLint = ["mockClassDeclaration.ts"].map((file) => path.join(__dirname, "../example/no-member-release-tags", file), @@ -67,7 +58,7 @@ describe(`Do not allow release tags on members (eslint ${eslintVersion})`, funct }); it("Should report errors for including release tags inside the class expression", async function () { - const eslint = createESLintInstance(); + const eslint = createESLintInstance(eslintRules); const filesToLint = ["mockClassExpression.ts"].map((file) => path.join(__dirname, "../example/no-member-release-tags", file), @@ -118,7 +109,7 @@ describe(`Do not allow release tags on members (eslint ${eslintVersion})`, funct }); it("Should report errors for including release tags inside the abstract class", async function () { - const eslint = createESLintInstance(); + const eslint = createESLintInstance(eslintRules); const filesToLint = ["mockAbstractClass.ts"].map((file) => path.join(__dirname, "../example/no-member-release-tags", file), @@ -137,7 +128,7 @@ describe(`Do not allow release tags on members (eslint ${eslintVersion})`, funct }); it("Should report errors for including release tags inside the interface", async function () { - const eslint = createESLintInstance(); + const eslint = createESLintInstance(eslintRules); const filesToLint = ["mockInterface.ts"].map((file) => path.join(__dirname, "../example/no-member-release-tags", file), @@ -176,7 +167,7 @@ describe(`Do not allow release tags on members (eslint ${eslintVersion})`, funct }); it("Should report errors for including release tags inside the type", async function () { - const eslint = createESLintInstance(); + const eslint = createESLintInstance(eslintRules); const filesToLint = ["mockType.ts"].map((file) => path.join(__dirname, "../example/no-member-release-tags", file), @@ -212,7 +203,7 @@ describe(`Do not allow release tags on members (eslint ${eslintVersion})`, funct }); it("Should NOT report errors for including release tags for function", async function () { - const eslint = createESLintInstance(); + const eslint = createESLintInstance(eslintRules); const filesToLint = ["mockFunction.ts"].map((file) => path.join(__dirname, "../example/no-member-release-tags", file), diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-restricted-tags-imports/enforce-no-restricted-tags-imports.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-restricted-tags-imports/enforce-no-restricted-tags-imports.test.js index f9203e520ad8..b4f16b43a059 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-restricted-tags-imports/enforce-no-restricted-tags-imports.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-restricted-tags-imports/enforce-no-restricted-tags-imports.test.js @@ -5,18 +5,9 @@ const assert = require("assert"); const path = require("path"); -const { createESLintConfig, eslintVersion, ESLint } = require("../eslintConfigHelper.cjs"); +const { createESLintInstance, eslintVersion } = require("../eslintConfigHelper.cjs"); describe(`ESLint Rule Tests (eslint ${eslintVersion})`, function () { - function createESLintInstance(config) { - const eslintOptions = createESLintConfig({ - parserOptions: config.parserOptions, - rules: config.rules, - extraPlugins: config.plugins, - }); - - return new ESLint(eslintOptions); - } it("Should report an error for restricted tag imports", async function () { const eslint = createESLintInstance({ @@ -29,9 +20,6 @@ describe(`ESLint Rule Tests (eslint ${eslintVersion})`, function () { }, ], }, - parserOptions: { - project: path.join(__dirname, "../example/tsconfig.json"), - }, }); const filesToLint = ["fileWithImports.ts", "mockModule.ts"].map((file) => path.join(__dirname, "../example/no-restricted-tags-imports", file), diff --git a/common/build/eslint-plugin-fluid/src/test/enforce-no-unchecked-record-access/enforce-no-unchecked-record-access.test.js b/common/build/eslint-plugin-fluid/src/test/enforce-no-unchecked-record-access/enforce-no-unchecked-record-access.test.js index f5ab443abb28..23a4fafbc26d 100644 --- a/common/build/eslint-plugin-fluid/src/test/enforce-no-unchecked-record-access/enforce-no-unchecked-record-access.test.js +++ b/common/build/eslint-plugin-fluid/src/test/enforce-no-unchecked-record-access/enforce-no-unchecked-record-access.test.js @@ -10,9 +10,6 @@ const { createESLintConfig, eslintVersion, ESLint } = require("../eslintConfigHe describe(`ESLint Rule Tests (eslint ${eslintVersion})`, function () { async function lintFile(file) { const eslintOptions = createESLintConfig({ - parserOptions: { - project: path.join(__dirname, "../example/tsconfig.json"), - }, rules: { "@fluid-internal/fluid/no-unchecked-record-access": "error", }, diff --git a/common/build/eslint-plugin-fluid/src/test/eslintConfigHelper.cjs b/common/build/eslint-plugin-fluid/src/test/eslintConfigHelper.cjs index 0a5aad969373..8d0ffea03dfb 100644 --- a/common/build/eslint-plugin-fluid/src/test/eslintConfigHelper.cjs +++ b/common/build/eslint-plugin-fluid/src/test/eslintConfigHelper.cjs @@ -8,6 +8,8 @@ * ESLint 8 uses the legacy config format, while ESLint 9 uses flat config. */ +const path = require("node:path"); + // Support testing against different ESLint versions using npm aliases const eslintPackage = process.env.ESLINT_PACKAGE || "eslint"; const eslintVersion = parseInt(require(`${eslintPackage}/package.json`).version.split(".")[0]); @@ -18,15 +20,18 @@ const plugin = require("../../index.js"); * Creates ESLint options object compatible with both ESLint 8 and 9. * * @param {object} config - Configuration object - * @param {object} config.parserOptions - Parser options * @param {object} config.rules - ESLint rules configuration + * @param {object} [config.parserOptions] - Parser options (will merge with defaults) * @param {object} [config.extraPlugins] - Additional plugins to register (ESLint 9 format) * @returns {object} ESLint options object */ function createESLintConfig(config) { - const { parserOptions, rules, extraPlugins } = config; + const { rules, extraPlugins, parserOptions: customParserOptions } = config; const parser = "@typescript-eslint/parser"; + const parserOptions = customParserOptions || { + project: path.join(__dirname, "example/tsconfig.json"), + }; const pluginName = "@fluid-internal/fluid"; const eslintOptions = { @@ -67,4 +72,27 @@ function createESLintConfig(config) { return eslintOptions; } -module.exports = { createESLintConfig, eslintVersion, ESLint }; +/** + * Creates an ESLint instance with the given configuration. + * + * @param {object} rulesOrConfig - Either rules object or full config object with rules/parserOptions/plugins + * @param {object} [rulesOrConfig.rules] - ESLint rules configuration + * @param {object} [rulesOrConfig.parserOptions] - Parser options + * @param {object} [rulesOrConfig.plugins] - Additional plugins + * @returns {ESLint} Configured ESLint instance + */ +function createESLintInstance(rulesOrConfig) { + const config = typeof rulesOrConfig === 'object' && rulesOrConfig.rules + ? rulesOrConfig + : { rules: rulesOrConfig }; + + const eslintOptions = createESLintConfig({ + rules: config.rules, + parserOptions: config.parserOptions, + extraPlugins: config.plugins, + }); + + return new ESLint(eslintOptions); +} + +module.exports = { createESLintConfig, createESLintInstance, eslintVersion, ESLint }; From d9c924bd5933dab774c11e6019c3ed67393ed785 Mon Sep 17 00:00:00 2001 From: Tyler Butler Date: Tue, 14 Oct 2025 09:53:39 -0700 Subject: [PATCH 11/12] changelog and version --- common/build/eslint-plugin-fluid/CHANGELOG.md | 4 ++++ common/build/eslint-plugin-fluid/package.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/common/build/eslint-plugin-fluid/CHANGELOG.md b/common/build/eslint-plugin-fluid/CHANGELOG.md index 04f043f4d655..7dac16aa0634 100644 --- a/common/build/eslint-plugin-fluid/CHANGELOG.md +++ b/common/build/eslint-plugin-fluid/CHANGELOG.md @@ -1,5 +1,9 @@ # @fluidframework/eslint-plugin-fluid Changelog +## [0.4.0](https://github.com/microsoft/FluidFramework/releases/tag/eslint-plugin-fluid_v0.4.0) + +Updates plugin to be compatible with both ESLint 8 and ESLint 9. + ## [0.3.1](https://github.com/microsoft/FluidFramework/releases/tag/eslint-plugin-fluid_v0.3.1) Fixes indexing issues in the following rules, which would cause incorrect notification ranges and could cause malformed code fixes: diff --git a/common/build/eslint-plugin-fluid/package.json b/common/build/eslint-plugin-fluid/package.json index 96b0bd29f703..6f9b3747ede8 100644 --- a/common/build/eslint-plugin-fluid/package.json +++ b/common/build/eslint-plugin-fluid/package.json @@ -1,6 +1,6 @@ { "name": "@fluid-internal/eslint-plugin-fluid", - "version": "0.3.1", + "version": "0.4.0", "description": "Custom ESLint rules for the Fluid Framework", "homepage": "https://fluidframework.com", "repository": { From 59c3be76cfb54a43fe89ce7169c917b8b687f3c2 Mon Sep 17 00:00:00 2001 From: Tyler Butler Date: Tue, 14 Oct 2025 09:53:44 -0700 Subject: [PATCH 12/12] peerdeps --- common/build/eslint-plugin-fluid/package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/common/build/eslint-plugin-fluid/package.json b/common/build/eslint-plugin-fluid/package.json index 6f9b3747ede8..6625a5eebde4 100644 --- a/common/build/eslint-plugin-fluid/package.json +++ b/common/build/eslint-plugin-fluid/package.json @@ -43,5 +43,8 @@ "rimraf": "^5.0.7", "typescript": "~5.4.5" }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.37.0" + }, "packageManager": "pnpm@10.17.1+sha512.17c560fca4867ae9473a3899ad84a88334914f379be46d455cbf92e5cf4b39d34985d452d2583baf19967fa76cb5c17bc9e245529d0b98745721aa7200ecaf7a" }