diff --git a/.prettierignore b/.prettierignore index 8edf4678fad4..001c801b75fa 100644 --- a/.prettierignore +++ b/.prettierignore @@ -19,6 +19,7 @@ SECURITY.md !**/test/lib/** common/lib/**/lib common/build/eslint-config-fluid/printed-configs/ +common/build/eslint-config-fluid/data/ build-tools/packages/*/docs/*.md build-tools/packages/build-cli/README.md build-tools/packages/version-tools/README.md diff --git a/common/build/eslint-config-fluid/README.md b/common/build/eslint-config-fluid/README.md index cd3696e69d62..7169fb2d100e 100644 --- a/common/build/eslint-config-fluid/README.md +++ b/common/build/eslint-config-fluid/README.md @@ -134,9 +134,10 @@ a diff to review as part of a PR -- just like we do with API reports for code ch | `build:readme:disabled` | `markdown-magic --files "**/*.md"` | | `clean` | `rimraf --glob dist "**/*.build.log"` | | `format` | `npm run prettier:fix` | +| `generate-deprecated-rules` | `jiti scripts/generate-deprecated-rules.ts` | | `prettier` | `prettier --check .` | | `prettier:fix` | `prettier --write .` | -| `print-configs` | `tsx scripts/print-configs.ts printed-configs` | +| `print-configs` | `jiti scripts/print-configs.ts printed-configs` | | `test` | `echo TODO: add tests in @fluidframework/eslint-config-fluid` | | `test:mocha` | `mocha "src/test/**/*.test.mts"` | diff --git a/common/build/eslint-config-fluid/data/deprecated-rules.json b/common/build/eslint-config-fluid/data/deprecated-rules.json new file mode 100644 index 000000000000..382a41313dad --- /dev/null +++ b/common/build/eslint-config-fluid/data/deprecated-rules.json @@ -0,0 +1,659 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Auto-generated list of deprecated ESLint rules. Do not edit manually. Run: tsx scripts/generate-deprecated-rules.ts", + "deprecatedRules": [ + { + "rule": "@eslint-react/no-forbidden-props", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "@typescript-eslint/no-empty-interface", + "isConfigured": false, + "isConfiguredInSource": false, + "replacedBy": [ + "@typescript-eslint/no-empty-object-type" + ] + }, + { + "rule": "@typescript-eslint/no-loss-of-precision", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "@typescript-eslint/no-type-alias", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "@typescript-eslint/no-var-requires", + "isConfigured": false, + "isConfiguredInSource": false, + "replacedBy": [ + "@typescript-eslint/no-require-imports" + ] + }, + { + "rule": "@typescript-eslint/prefer-ts-expect-error", + "isConfigured": false, + "isConfiguredInSource": false, + "replacedBy": [ + "@typescript-eslint/ban-ts-comment" + ] + }, + { + "rule": "@typescript-eslint/sort-type-constituents", + "isConfigured": false, + "isConfiguredInSource": false, + "replacedBy": [ + "perfectionist/sort-intersection-types", + "perfectionist/sort-union-types" + ] + }, + { + "rule": "@typescript-eslint/typedef", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "array-bracket-newline", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "array-bracket-spacing", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "array-element-newline", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "arrow-parens", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "arrow-spacing", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "block-spacing", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "brace-style", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "callback-return", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "comma-dangle", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "comma-spacing", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "comma-style", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "computed-property-spacing", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "dot-location", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "eol-last", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "func-call-spacing", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "function-call-argument-newline", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "function-paren-newline", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "generator-star-spacing", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "global-require", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "handle-callback-err", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "id-blacklist", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "implicit-arrow-linebreak", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "import-x/imports-first", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "indent", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "indent-legacy", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "jsx-quotes", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "key-spacing", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "keyword-spacing", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "line-comment-position", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "linebreak-style", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "lines-around-comment", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "lines-around-directive", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "lines-between-class-members", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "max-len", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "max-statements-per-line", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "multiline-comment-style", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "multiline-ternary", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "new-parens", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "newline-after-var", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "newline-before-return", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "newline-per-chained-call", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "no-buffer-constructor", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "no-catch-shadow", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "no-confusing-arrow", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "no-extra-parens", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "no-extra-semi", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "no-floating-decimal", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "no-mixed-operators", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "no-mixed-requires", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "no-mixed-spaces-and-tabs", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "no-multi-spaces", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "no-multiple-empty-lines", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "no-native-reassign", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "no-negated-in-lhs", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "no-new-object", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "no-new-require", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "no-new-symbol", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "no-path-concat", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "no-process-env", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "no-process-exit", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "no-restricted-modules", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "no-return-await", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "no-spaced-func", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "no-sync", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "no-tabs", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "no-trailing-spaces", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "no-whitespace-before-property", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "nonblock-statement-body-position", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "object-curly-newline", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "object-curly-spacing", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "object-property-newline", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "one-var-declaration-per-line", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "operator-linebreak", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "padded-blocks", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "padding-line-between-statements", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "prefer-reflect", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "quote-props", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "quotes", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "rest-spread-spacing", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "semi", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "semi-spacing", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "semi-style", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "space-before-blocks", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "space-before-function-paren", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "space-in-parens", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "space-infix-ops", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "space-unary-ops", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "spaced-comment", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "switch-colon-spacing", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "template-curly-spacing", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "template-tag-spacing", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "unicorn/import-index", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "unicorn/no-array-instanceof", + "isConfigured": false, + "isConfiguredInSource": false, + "replacedBy": [ + "unicorn/no-instanceof-array" + ] + }, + { + "rule": "unicorn/no-fn-reference-in-iterator", + "isConfigured": false, + "isConfiguredInSource": false, + "replacedBy": [ + "unicorn/no-array-callback-reference" + ] + }, + { + "rule": "unicorn/no-reduce", + "isConfigured": false, + "isConfiguredInSource": false, + "replacedBy": [ + "unicorn/no-array-reduce" + ] + }, + { + "rule": "unicorn/no-unsafe-regex", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "unicorn/prefer-dataset", + "isConfigured": false, + "isConfiguredInSource": false, + "replacedBy": [ + "unicorn/prefer-dom-node-dataset" + ] + }, + { + "rule": "unicorn/prefer-event-key", + "isConfigured": false, + "isConfiguredInSource": false, + "replacedBy": [ + "unicorn/prefer-keyboard-event-key" + ] + }, + { + "rule": "unicorn/prefer-exponentiation-operator", + "isConfigured": false, + "isConfiguredInSource": false, + "replacedBy": [ + "prefer-exponentiation-operator" + ] + }, + { + "rule": "unicorn/prefer-flat-map", + "isConfigured": false, + "isConfiguredInSource": false, + "replacedBy": [ + "unicorn/prefer-array-flat-map" + ] + }, + { + "rule": "unicorn/prefer-node-append", + "isConfigured": false, + "isConfiguredInSource": false, + "replacedBy": [ + "unicorn/prefer-dom-node-append" + ] + }, + { + "rule": "unicorn/prefer-node-remove", + "isConfigured": false, + "isConfiguredInSource": false, + "replacedBy": [ + "unicorn/prefer-dom-node-remove" + ] + }, + { + "rule": "unicorn/prefer-object-has-own", + "isConfigured": false, + "isConfiguredInSource": false, + "replacedBy": [ + "prefer-object-has-own" + ] + }, + { + "rule": "unicorn/prefer-replace-all", + "isConfigured": false, + "isConfiguredInSource": false, + "replacedBy": [ + "unicorn/prefer-string-replace-all" + ] + }, + { + "rule": "unicorn/prefer-starts-ends-with", + "isConfigured": false, + "isConfiguredInSource": false, + "replacedBy": [ + "unicorn/prefer-string-starts-ends-with" + ] + }, + { + "rule": "unicorn/prefer-text-content", + "isConfigured": false, + "isConfiguredInSource": false, + "replacedBy": [ + "unicorn/prefer-dom-node-text-content" + ] + }, + { + "rule": "unicorn/prefer-trim-start-end", + "isConfigured": false, + "isConfiguredInSource": false, + "replacedBy": [ + "unicorn/prefer-string-trim-start-end" + ] + }, + { + "rule": "unicorn/regex-shorthand", + "isConfigured": false, + "isConfiguredInSource": false, + "replacedBy": [ + "unicorn/better-regex" + ] + }, + { + "rule": "wrap-iife", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "wrap-regex", + "isConfigured": false, + "isConfiguredInSource": false + }, + { + "rule": "yield-star-spacing", + "isConfigured": false, + "isConfiguredInSource": false + } + ] +} diff --git a/common/build/eslint-config-fluid/library/configs/base.mts b/common/build/eslint-config-fluid/library/configs/base.mts index d1e2f6432797..f363ec583198 100644 --- a/common/build/eslint-config-fluid/library/configs/base.mts +++ b/common/build/eslint-config-fluid/library/configs/base.mts @@ -116,15 +116,10 @@ export const baseConfig: FlatConfigArray = [ }, // Prettier disables conflicting rules - must come after custom rules prettierConfig satisfies Linter.Config, - // Re-enable no-multi-spaces after prettier (which disables it) + // Keep deprecated core stylistic rules disabled after prettier. { rules: { - "no-multi-spaces": [ - "error", - { - ignoreEOLComments: true, - }, - ], + "no-multi-spaces": "off", }, }, ]; diff --git a/common/build/eslint-config-fluid/library/rules/base.mts b/common/build/eslint-config-fluid/library/rules/base.mts index f0538087c716..13e04e21f5a8 100644 --- a/common/build/eslint-config-fluid/library/rules/base.mts +++ b/common/build/eslint-config-fluid/library/rules/base.mts @@ -208,7 +208,6 @@ export const baseRules = { "@typescript-eslint/explicit-member-accessibility": "off", "@typescript-eslint/member-ordering": "off", "@typescript-eslint/no-use-before-define": "off", - "@typescript-eslint/typedef": "off", /** * Disabled because we want to encourage documenting different events separately. @@ -319,39 +318,18 @@ export const baseRules = { // #region eslint core rules "arrow-body-style": "off", - "arrow-parens": ["error", "always"], "camelcase": "off", // Superseded by @typescript-eslint/naming-convention - "brace-style": "off", // Superseded by @typescript-eslint/brace-style "capitalized-comments": "off", - "comma-dangle": "off", // Superseded by @typescript-eslint/comma-dangle - "comma-spacing": "off", // Superseded by @typescript-eslint/comma-spacing "complexity": "off", "constructor-super": "error", "curly": "error", "default-case": "error", "dot-notation": "off", // Superseded by @typescript-eslint/dot-notation - "eol-last": "error", "eqeqeq": ["error", "smart"], - "func-call-spacing": "off", // Superseded by @typescript-eslint/func-call-spacing "guard-for-in": "error", "id-match": "error", - "linebreak-style": "off", - "keyword-spacing": "off", // Superseded by @typescript-eslint/keyword-spacing "max-classes-per-file": "off", - /** - * Disabled as it conflicts with biome formatting. - */ - "max-len": [ - "off", - { - ignoreRegExpLiterals: false, - ignoreStrings: false, - code: 120, - }, - ], "max-lines": "off", - "new-parens": "error", - "newline-per-chained-call": "off", "no-bitwise": "error", "no-caller": "error", "no-cond-assign": "error", @@ -362,21 +340,12 @@ export const baseRules = { "no-duplicate-imports": "off", // Doesn't work with TypeScript "no-empty": "error", "no-eval": "error", - "no-extra-semi": "off", // Superseded by @typescript-eslint/no-extra-semi "no-fallthrough": "off", "no-invalid-regexp": "error", "no-invalid-this": "off", // Superseded by @typescript-eslint/no-invalid-this "no-irregular-whitespace": "error", "no-magic-numbers": "off", // Superseded by @typescript-eslint/no-magic-numbers "no-multi-str": "off", - "no-multiple-empty-lines": [ - "error", - { - max: 1, - maxBOF: 0, - maxEOF: 0, - }, - ], "no-nested-ternary": "off", // Superseded by unicorn/no-nested-ternary "no-new-func": "error", "no-new-wrappers": "error", @@ -399,7 +368,6 @@ export const baseRules = { "no-sparse-arrays": "error", "no-template-curly-in-string": "error", "no-throw-literal": "off", // Superseded by @typescript-eslint/only-throw-error - "no-trailing-spaces": "error", "no-undef-init": "error", "no-underscore-dangle": "off", "no-unsafe-finally": "error", @@ -408,44 +376,15 @@ export const baseRules = { "no-unused-vars": "off", // Superseded by @typescript-eslint/no-unused-vars "no-var": "error", "no-void": "warn", - "no-whitespace-before-property": "error", - "object-curly-spacing": "off", // Superseded by @typescript-eslint/object-curly-spacing "object-shorthand": "error", "one-var": ["error", "never"], - "padded-blocks": ["error", "never"], - "padding-line-between-statements": [ - "off", - { - blankLine: "always", - prev: "*", - next: "return", - }, - ], "prefer-arrow-callback": "error", "prefer-const": "error", "prefer-object-spread": "error", "prefer-promise-reject-errors": "error", "prefer-template": "error", - "quote-props": ["error", "consistent-as-needed"], - "quotes": "off", // Superseded by @typescript-eslint/quotes "radix": "error", "require-await": "off", // Superseded by @typescript-eslint/require-await - "semi": "off", // Superseded by @typescript-eslint/semi - "semi-spacing": "error", - "space-before-blocks": "error", - "space-before-function-paren": "off", // Superseded by @typescript-eslint/space-before-function-paren - "space-infix-ops": "off", // Superseded by @typescript-eslint/space-infix-ops - "space-in-parens": ["error", "never"], - "spaced-comment": [ - "error", - "always", - { - block: { - markers: ["!"], - balanced: true, - }, - }, - ], "require-atomic-updates": "warn", "use-isnan": "error", "valid-typeof": "error", diff --git a/common/build/eslint-config-fluid/package.json b/common/build/eslint-config-fluid/package.json index 22efef305aee..8ec6ee615ae1 100644 --- a/common/build/eslint-config-fluid/package.json +++ b/common/build/eslint-config-fluid/package.json @@ -17,10 +17,11 @@ }, "main": "./index.mts", "scripts": { - "build": "npm run print-configs && npm run prettier", + "build": "npm run print-configs && npm run generate-deprecated-rules && npm run prettier", "build:readme:disabled": "markdown-magic --files \"**/*.md\"", "clean": "rimraf --glob dist \"**/*.build.log\" nyc", "format": "npm run prettier:fix", + "generate-deprecated-rules": "jiti scripts/generate-deprecated-rules.ts", "prettier": "prettier --check . --cache --ignore-path ../../../.prettierignore", "prettier:fix": "prettier --write . --cache --ignore-path ../../../.prettierignore", "print-configs": "jiti scripts/print-configs.ts printed-configs", diff --git a/common/build/eslint-config-fluid/printed-configs/default.json b/common/build/eslint-config-fluid/printed-configs/default.json index a4bb869dbd34..640ef402dc28 100644 --- a/common/build/eslint-config-fluid/printed-configs/default.json +++ b/common/build/eslint-config-fluid/printed-configs/default.json @@ -1009,9 +1009,6 @@ "@typescript-eslint/type-annotation-spacing": [ "off" ], - "@typescript-eslint/typedef": [ - "off" - ], "@typescript-eslint/unbound-method": [ "error", { @@ -1035,8 +1032,7 @@ "as-needed" ], "arrow-parens": [ - "off", - "always" + "off" ], "arrow-spacing": [ "off" @@ -1320,12 +1316,7 @@ "off" ], "max-len": [ - "off", - { - "ignoreRegExpLiterals": false, - "ignoreStrings": false, - "code": 120 - } + "off" ], "max-lines": [ "off" @@ -1530,21 +1521,13 @@ "off" ], "no-multi-spaces": [ - "error", - { - "ignoreEOLComments": true - } + "off" ], "no-multi-str": [ "off" ], "no-multiple-empty-lines": [ - "off", - { - "max": 1, - "maxBOF": 0, - "maxEOF": 0 - } + "off" ], "no-negated-condition": [ "off" @@ -1777,16 +1760,7 @@ "off" ], "padded-blocks": [ - "off", - "never" - ], - "padding-line-between-statements": [ - "off", - { - "blankLine": "always", - "prev": "*", - "next": "return" - } + "off" ], "prefer-arrow-callback": [ "error", @@ -1824,8 +1798,7 @@ "warn" ], "quote-props": [ - "off", - "consistent-as-needed" + "off" ], "quotes": [ "off" @@ -1928,8 +1901,7 @@ "off" ], "space-in-parens": [ - "off", - "never" + "off" ], "space-infix-ops": [ "off" @@ -1943,18 +1915,6 @@ "space-unary-word-ops": [ "off" ], - "spaced-comment": [ - "error", - "always", - { - "block": { - "markers": [ - "!" - ], - "balanced": true - } - } - ], "standard/array-bracket-even-spacing": [ "off" ], diff --git a/common/build/eslint-config-fluid/printed-configs/react.json b/common/build/eslint-config-fluid/printed-configs/react.json index 211dd2604681..7fa3cb129da8 100644 --- a/common/build/eslint-config-fluid/printed-configs/react.json +++ b/common/build/eslint-config-fluid/printed-configs/react.json @@ -1218,9 +1218,6 @@ "@typescript-eslint/type-annotation-spacing": [ "off" ], - "@typescript-eslint/typedef": [ - "off" - ], "@typescript-eslint/unbound-method": [ "error", { @@ -1244,8 +1241,7 @@ "as-needed" ], "arrow-parens": [ - "off", - "always" + "off" ], "arrow-spacing": [ "off" @@ -1529,12 +1525,7 @@ "off" ], "max-len": [ - "off", - { - "ignoreRegExpLiterals": false, - "ignoreStrings": false, - "code": 120 - } + "off" ], "max-lines": [ "off" @@ -1739,21 +1730,13 @@ "off" ], "no-multi-spaces": [ - "error", - { - "ignoreEOLComments": true - } + "off" ], "no-multi-str": [ "off" ], "no-multiple-empty-lines": [ - "off", - { - "max": 1, - "maxBOF": 0, - "maxEOF": 0 - } + "off" ], "no-negated-condition": [ "off" @@ -1986,16 +1969,7 @@ "off" ], "padded-blocks": [ - "off", - "never" - ], - "padding-line-between-statements": [ - "off", - { - "blankLine": "always", - "prev": "*", - "next": "return" - } + "off" ], "prefer-arrow-callback": [ "error", @@ -2033,8 +2007,7 @@ "warn" ], "quote-props": [ - "off", - "consistent-as-needed" + "off" ], "quotes": [ "off" @@ -2188,8 +2161,7 @@ "off" ], "space-in-parens": [ - "off", - "never" + "off" ], "space-infix-ops": [ "off" @@ -2203,18 +2175,6 @@ "space-unary-word-ops": [ "off" ], - "spaced-comment": [ - "error", - "always", - { - "block": { - "markers": [ - "!" - ], - "balanced": true - } - } - ], "standard/array-bracket-even-spacing": [ "off" ], diff --git a/common/build/eslint-config-fluid/printed-configs/recommended.json b/common/build/eslint-config-fluid/printed-configs/recommended.json index a4bb869dbd34..640ef402dc28 100644 --- a/common/build/eslint-config-fluid/printed-configs/recommended.json +++ b/common/build/eslint-config-fluid/printed-configs/recommended.json @@ -1009,9 +1009,6 @@ "@typescript-eslint/type-annotation-spacing": [ "off" ], - "@typescript-eslint/typedef": [ - "off" - ], "@typescript-eslint/unbound-method": [ "error", { @@ -1035,8 +1032,7 @@ "as-needed" ], "arrow-parens": [ - "off", - "always" + "off" ], "arrow-spacing": [ "off" @@ -1320,12 +1316,7 @@ "off" ], "max-len": [ - "off", - { - "ignoreRegExpLiterals": false, - "ignoreStrings": false, - "code": 120 - } + "off" ], "max-lines": [ "off" @@ -1530,21 +1521,13 @@ "off" ], "no-multi-spaces": [ - "error", - { - "ignoreEOLComments": true - } + "off" ], "no-multi-str": [ "off" ], "no-multiple-empty-lines": [ - "off", - { - "max": 1, - "maxBOF": 0, - "maxEOF": 0 - } + "off" ], "no-negated-condition": [ "off" @@ -1777,16 +1760,7 @@ "off" ], "padded-blocks": [ - "off", - "never" - ], - "padding-line-between-statements": [ - "off", - { - "blankLine": "always", - "prev": "*", - "next": "return" - } + "off" ], "prefer-arrow-callback": [ "error", @@ -1824,8 +1798,7 @@ "warn" ], "quote-props": [ - "off", - "consistent-as-needed" + "off" ], "quotes": [ "off" @@ -1928,8 +1901,7 @@ "off" ], "space-in-parens": [ - "off", - "never" + "off" ], "space-infix-ops": [ "off" @@ -1943,18 +1915,6 @@ "space-unary-word-ops": [ "off" ], - "spaced-comment": [ - "error", - "always", - { - "block": { - "markers": [ - "!" - ], - "balanced": true - } - } - ], "standard/array-bracket-even-spacing": [ "off" ], diff --git a/common/build/eslint-config-fluid/printed-configs/strict-biome.json b/common/build/eslint-config-fluid/printed-configs/strict-biome.json index ccf71fdf08d9..3c35104fee6d 100644 --- a/common/build/eslint-config-fluid/printed-configs/strict-biome.json +++ b/common/build/eslint-config-fluid/printed-configs/strict-biome.json @@ -1019,9 +1019,6 @@ "@typescript-eslint/type-annotation-spacing": [ "off" ], - "@typescript-eslint/typedef": [ - "off" - ], "@typescript-eslint/unbound-method": [ "error", { @@ -1045,8 +1042,7 @@ "as-needed" ], "arrow-parens": [ - "off", - "always" + "off" ], "arrow-spacing": [ "off" @@ -1359,12 +1355,7 @@ "off" ], "max-len": [ - "off", - { - "ignoreRegExpLiterals": false, - "ignoreStrings": false, - "code": 120 - } + "off" ], "max-lines": [ "off" @@ -1569,21 +1560,13 @@ "off" ], "no-multi-spaces": [ - "error", - { - "ignoreEOLComments": true - } + "off" ], "no-multi-str": [ "off" ], "no-multiple-empty-lines": [ - "off", - { - "max": 1, - "maxBOF": 0, - "maxEOF": 0 - } + "off" ], "no-negated-condition": [ "off" @@ -1816,16 +1799,7 @@ "off" ], "padded-blocks": [ - "off", - "never" - ], - "padding-line-between-statements": [ - "off", - { - "blankLine": "always", - "prev": "*", - "next": "return" - } + "off" ], "prefer-arrow-callback": [ "error", @@ -1863,8 +1837,7 @@ "warn" ], "quote-props": [ - "off", - "consistent-as-needed" + "off" ], "quotes": [ "off" @@ -1967,8 +1940,7 @@ "off" ], "space-in-parens": [ - "off", - "never" + "off" ], "space-infix-ops": [ "off" @@ -1982,18 +1954,6 @@ "space-unary-word-ops": [ "off" ], - "spaced-comment": [ - "error", - "always", - { - "block": { - "markers": [ - "!" - ], - "balanced": true - } - } - ], "standard/array-bracket-even-spacing": [ "off" ], diff --git a/common/build/eslint-config-fluid/printed-configs/strict.json b/common/build/eslint-config-fluid/printed-configs/strict.json index ccf71fdf08d9..3c35104fee6d 100644 --- a/common/build/eslint-config-fluid/printed-configs/strict.json +++ b/common/build/eslint-config-fluid/printed-configs/strict.json @@ -1019,9 +1019,6 @@ "@typescript-eslint/type-annotation-spacing": [ "off" ], - "@typescript-eslint/typedef": [ - "off" - ], "@typescript-eslint/unbound-method": [ "error", { @@ -1045,8 +1042,7 @@ "as-needed" ], "arrow-parens": [ - "off", - "always" + "off" ], "arrow-spacing": [ "off" @@ -1359,12 +1355,7 @@ "off" ], "max-len": [ - "off", - { - "ignoreRegExpLiterals": false, - "ignoreStrings": false, - "code": 120 - } + "off" ], "max-lines": [ "off" @@ -1569,21 +1560,13 @@ "off" ], "no-multi-spaces": [ - "error", - { - "ignoreEOLComments": true - } + "off" ], "no-multi-str": [ "off" ], "no-multiple-empty-lines": [ - "off", - { - "max": 1, - "maxBOF": 0, - "maxEOF": 0 - } + "off" ], "no-negated-condition": [ "off" @@ -1816,16 +1799,7 @@ "off" ], "padded-blocks": [ - "off", - "never" - ], - "padding-line-between-statements": [ - "off", - { - "blankLine": "always", - "prev": "*", - "next": "return" - } + "off" ], "prefer-arrow-callback": [ "error", @@ -1863,8 +1837,7 @@ "warn" ], "quote-props": [ - "off", - "consistent-as-needed" + "off" ], "quotes": [ "off" @@ -1967,8 +1940,7 @@ "off" ], "space-in-parens": [ - "off", - "never" + "off" ], "space-infix-ops": [ "off" @@ -1982,18 +1954,6 @@ "space-unary-word-ops": [ "off" ], - "spaced-comment": [ - "error", - "always", - { - "block": { - "markers": [ - "!" - ], - "balanced": true - } - } - ], "standard/array-bracket-even-spacing": [ "off" ], diff --git a/common/build/eslint-config-fluid/printed-configs/test.json b/common/build/eslint-config-fluid/printed-configs/test.json index 3f51e4c1accd..83653abce57a 100644 --- a/common/build/eslint-config-fluid/printed-configs/test.json +++ b/common/build/eslint-config-fluid/printed-configs/test.json @@ -1001,9 +1001,6 @@ "@typescript-eslint/type-annotation-spacing": [ "off" ], - "@typescript-eslint/typedef": [ - "off" - ], "@typescript-eslint/unbound-method": [ "off", { @@ -1027,8 +1024,7 @@ "as-needed" ], "arrow-parens": [ - "off", - "always" + "off" ], "arrow-spacing": [ "off" @@ -1316,12 +1312,7 @@ "off" ], "max-len": [ - "off", - { - "ignoreRegExpLiterals": false, - "ignoreStrings": false, - "code": 120 - } + "off" ], "max-lines": [ "off" @@ -1526,21 +1517,13 @@ "off" ], "no-multi-spaces": [ - "error", - { - "ignoreEOLComments": true - } + "off" ], "no-multi-str": [ "off" ], "no-multiple-empty-lines": [ - "off", - { - "max": 1, - "maxBOF": 0, - "maxEOF": 0 - } + "off" ], "no-negated-condition": [ "off" @@ -1776,16 +1759,7 @@ "off" ], "padded-blocks": [ - "off", - "never" - ], - "padding-line-between-statements": [ - "off", - { - "blankLine": "always", - "prev": "*", - "next": "return" - } + "off" ], "prefer-arrow-callback": [ "error", @@ -1823,8 +1797,7 @@ "warn" ], "quote-props": [ - "off", - "consistent-as-needed" + "off" ], "quotes": [ "off" @@ -1927,8 +1900,7 @@ "off" ], "space-in-parens": [ - "off", - "never" + "off" ], "space-infix-ops": [ "off" @@ -1942,18 +1914,6 @@ "space-unary-word-ops": [ "off" ], - "spaced-comment": [ - "error", - "always", - { - "block": { - "markers": [ - "!" - ], - "balanced": true - } - } - ], "standard/array-bracket-even-spacing": [ "off" ], diff --git a/common/build/eslint-config-fluid/scripts/generate-deprecated-rules.ts b/common/build/eslint-config-fluid/scripts/generate-deprecated-rules.ts new file mode 100644 index 000000000000..9b2bdb3655ae --- /dev/null +++ b/common/build/eslint-config-fluid/scripts/generate-deprecated-rules.ts @@ -0,0 +1,274 @@ +/*! + * Copyright (c) Microsoft Corporation and contributors. All rights reserved. + * Licensed under the MIT License. + */ + +/** + * Script to generate a list of deprecated ESLint rules from all plugins used in the flat configs. + * + * Loads the flat configs (recommended, strict, strictBiome), inspects each plugin's rule + * metadata for `meta.deprecated === true`, cross-references with the configured rules, and + * writes the results to `data/deprecated-rules.json`. + * + * Usage: tsx scripts/generate-deprecated-rules.ts + */ + +import fs from "node:fs/promises"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +import { ESLint } from "eslint"; +import { builtinRules } from "eslint/use-at-your-own-risk"; +import type { Linter, Rule } from "eslint"; + +// Import flat configs directly from flat.mjs (same pattern as print-configs.ts) +import { recommended, strict, strictBiome } from "../flat.mjs"; +import type { FlatConfigArray } from "../library/configs/base.mjs"; +import { baseRules, eslintCommentsRecommendedRules } from "../library/rules/base.mjs"; +import { recommendedRules } from "../library/rules/recommended.mjs"; +import { strictRules, strictTsRules } from "../library/rules/strict.mjs"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +interface DeprecatedRuleInfo { + rule: string; + replacedBy?: string[]; +} + +interface DeprecatedRuleOutput { + rule: string; + replacedBy?: string[]; + isConfigured: boolean; + isConfiguredInSource: boolean; +} + +export const flatConfigsToInspect: readonly { name: string; config: FlatConfigArray }[] = [ + { name: "recommended", config: recommended }, + { name: "strict", config: strict }, + { name: "strictBiome", config: strictBiome }, +] as const; + +const localRuleSources = [ + baseRules, + eslintCommentsRecommendedRules, + recommendedRules, + strictRules, + strictTsRules, +] as const; + +/** + * Extracts deprecated rules from a rules collection. + * @param prefix - Plugin prefix (empty string for core ESLint rules) + * @param rules - Map or Record of rule definitions + * @returns Array of deprecated rule information + */ +function findDeprecatedRules( + prefix: string, + rules: Map | Record | undefined, +): DeprecatedRuleInfo[] { + const deprecated: DeprecatedRuleInfo[] = []; + if (!rules) { + return deprecated; + } + + const entries: [string, Rule.RuleModule][] = + rules instanceof Map ? [...rules.entries()] : Object.entries(rules); + + for (const [name, rule] of entries) { + const meta = rule.meta; + if (meta?.deprecated) { + const fullName = prefix ? `${prefix}/${name}` : name; + const info: DeprecatedRuleInfo = { rule: fullName }; + if (meta.replacedBy && meta.replacedBy.length > 0) { + info.replacedBy = meta.replacedBy as string[]; + } + deprecated.push(info); + } + } + return deprecated; +} + +/** + * Collects all plugins from an array of flat config objects. + * Returns a map of plugin prefix to plugin object. + */ +function collectPlugins( + configs: readonly Readonly[], +): Map }> { + const plugins = new Map }>(); + + for (const config of configs) { + if (config.plugins) { + for (const [prefix, plugin] of Object.entries(config.plugins)) { + if (!plugins.has(prefix)) { + plugins.set(prefix, plugin as { rules?: Record }); + } + } + } + } + + return plugins; +} + +/** + * Finds rules explicitly configured by the local rule definition modules. + */ +function getSourceConfiguredRules(): Set { + const sourceConfiguredRules = new Set(); + + for (const rules of localRuleSources) { + for (const ruleName of Object.keys(rules)) { + sourceConfiguredRules.add(ruleName); + } + } + + return sourceConfiguredRules; +} + +/** + * Resolves the effective rules for a given config by using ESLint's calculateConfigForFile. + * This gives us the fully-resolved rule configuration including all overrides. + */ +async function getResolvedRules( + config: readonly Readonly[], + filePath: string, +): Promise> { + const eslint = new ESLint({ + overrideConfigFile: true, + overrideConfig: config as Linter.Config[], + }); + + const resolvedConfig = (await eslint.calculateConfigForFile(filePath)) as { + rules?: Record; + }; + + return resolvedConfig?.rules ?? {}; +} + +/** + * Checks whether a rule severity means the rule is enabled (not "off"). + */ +function isRuleEnabled(ruleConfig: Linter.RuleSeverityAndOptions | undefined): boolean { + if (ruleConfig === undefined) { + return false; + } + + const severity = Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig; + + return severity !== "off" && severity !== 0; +} + +async function main(): Promise { + // Combine all configs to discover all registered plugins + const allConfigs = flatConfigsToInspect.flatMap(({ config }) => config); + + // Collect all deprecated rules from core ESLint and all plugins + const allDeprecated: DeprecatedRuleInfo[] = []; + + // ESLint core built-in rules + allDeprecated.push(...findDeprecatedRules("", builtinRules as Map)); + + // Plugin rules - extract plugins from the flat config objects + const plugins = collectPlugins(allConfigs); + for (const [prefix, plugin] of plugins) { + if (plugin.rules) { + allDeprecated.push(...findDeprecatedRules(prefix, plugin.rules)); + } + } + + // Sort for consistent output + allDeprecated.sort((a, b) => a.rule.localeCompare(b.rule)); + + // Resolve configured rules from each config for a .ts file + const sampleTsFile = path.join(__dirname, "..", "src", "file.ts"); + const resolvedRulesByConfig = await Promise.all( + flatConfigsToInspect.map(async ({ config }) => getResolvedRules(config, sampleTsFile)), + ); + + // Merge all configured rule names + const configuredRules = new Set( + resolvedRulesByConfig.flatMap((rules) => Object.keys(rules)), + ); + + // Determine which deprecated rules are enabled (not just configured, but not "off") + const enabledRules = new Set(); + for (const ruleName of configuredRules) { + if (resolvedRulesByConfig.some((rules) => isRuleEnabled(rules[ruleName]))) { + enabledRules.add(ruleName); + } + } + + const sourceConfiguredRules = getSourceConfiguredRules(); + + // Build the output + const deprecatedRulesOutput: DeprecatedRuleOutput[] = allDeprecated.map((d) => { + const output: DeprecatedRuleOutput = { + rule: d.rule, + isConfigured: enabledRules.has(d.rule), + isConfiguredInSource: sourceConfiguredRules.has(d.rule), + }; + if (d.replacedBy && d.replacedBy.length > 0) { + output.replacedBy = d.replacedBy; + } + return output; + }); + + // Write to data/deprecated-rules.json (NOT printed-configs/ which is cleaned by print-configs.ts) + const outputDir = path.join(__dirname, "..", "data"); + await fs.mkdir(outputDir, { recursive: true }); + const outputPath = path.join(outputDir, "deprecated-rules.json"); + + const output = { + $schema: "http://json-schema.org/draft-07/schema#", + description: + "Auto-generated list of deprecated ESLint rules. Do not edit manually. Run: tsx scripts/generate-deprecated-rules.ts", + deprecatedRules: deprecatedRulesOutput, + }; + + await fs.writeFile(outputPath, JSON.stringify(output, null, "\t") + "\n"); + + // Print summary + const configured = deprecatedRulesOutput.filter((r) => r.isConfigured); + const withReplacements = deprecatedRulesOutput.filter((r) => r.replacedBy); + + console.log(`Generated ${deprecatedRulesOutput.length} deprecated rules to ${outputPath}`); + console.log(` - ${configured.length} deprecated rules are enabled in our ESLint configs`); + console.log(` - ${withReplacements.length} deprecated rules have replacements`); + + // Summary by plugin + const byPlugin: Record = {}; + for (const d of allDeprecated) { + const slashIndex = d.rule.indexOf("/"); + const plugin = slashIndex > 0 ? d.rule.slice(0, slashIndex) : "eslint"; + byPlugin[plugin] = (byPlugin[plugin] ?? 0) + 1; + } + + console.log("\nBy plugin:"); + for (const [plugin, count] of Object.entries(byPlugin).sort((a, b) => + a[0].localeCompare(b[0]), + )) { + console.log(` ${plugin}: ${count}`); + } + + // Highlight deprecated rules that are still enabled + if (configured.length > 0) { + console.log(`\n${"=".repeat(60)}`); + console.log(`DEPRECATED RULES STILL ENABLED (${configured.length}):`); + console.log("=".repeat(60)); + for (const info of configured) { + const replacement = info.replacedBy?.length + ? `-> ${info.replacedBy.join(", ")}` + : "(no replacement)"; + console.log(` ${info.rule} ${replacement}`); + } + } +} + +const isInvokedScript = process.argv.slice(1).some((arg) => path.resolve(arg) === __filename); +if (isInvokedScript) { + main().catch((error) => { + console.error("Error generating deprecated rules:", error); + process.exit(1); + }); +}