UNPKG

@fluidframework/eslint-config-fluid

Version:

Shareable ESLint config for the Fluid Framework

557 lines (493 loc) 16.9 kB
/*! * Copyright (c) Microsoft Corporation and contributors. All rights reserved. * Licensed under the MIT License. */ /** * Base ESLint rules. * * This module contains the foundational rules applied by the base configuration. * These rules are inherited by all higher-level configs (recommended, strict). * Rules are organized by plugin/source and include custom Fluid rules, TypeScript rules, * import-x rules, unicorn rules, and core ESLint rules. */ import type { Linter } from "eslint"; import { restrictedImportPaths, restrictedImportPatternsForProductionCode, permittedImports, } from "../constants.mjs"; /** * Base rules. * * Includes rules from eslint:recommended, @typescript-eslint/recommended-type-checked, * @typescript-eslint/stylistic-type-checked, import-x/recommended, import-x/typescript, * and the former minimal-deprecated rules (TypeScript, JSDoc/TSDoc, import restrictions, * Fluid-specific custom rules). */ export const baseRules = { // Please keep entries alphabetized within a group // #region Fluid Custom Rules /** * Disallow `-` immediately following a JSDoc/TSDoc tag (e.g. `@deprecated - foo`). */ "@fluid-internal/fluid/no-hyphen-after-jsdoc-tag": "error", /** * Disallow file path based links in JSDoc/TSDoc comments. */ "@fluid-internal/fluid/no-file-path-links-in-jsdoc": "error", /** * Disallow the use of Markdown-syntax links in JSDoc/TSDoc comments. */ "@fluid-internal/fluid/no-markdown-links-in-jsdoc": "error", /** * Restricts including release tags inside the member class / interface. * * Refer to the rule by the unprefixed plugin name in the consumed package. * {@link https://eslint.org/docs/latest/extend/plugins#rules-in-plugins} */ "@fluid-internal/fluid/no-member-release-tags": "error", /** * Rule to enforce safe property access on index signature types. * * Reports issues when non-array index properties are accessed without handling * the possibility that they are absent. * Enabling `noUncheckedIndexedAccess` will disable these checks. */ "@fluid-internal/fluid/no-unchecked-record-access": "error", // #endregion // #region @typescript-eslint "@typescript-eslint/adjacent-overload-signatures": "error", "@typescript-eslint/array-type": "error", "@typescript-eslint/await-thenable": "error", "@typescript-eslint/consistent-type-assertions": [ "error", { assertionStyle: "as", objectLiteralTypeAssertions: "never", }, ], "@typescript-eslint/consistent-type-definitions": "error", "@typescript-eslint/dot-notation": "error", // In some cases, type inference can be wrong, and this can cause a "flip-flop" of type changes in our // API documentation. For example, type inference might decide a function returns a concrete type // instead of an interface. This has no runtime impact, but would cause compilation problems. "@typescript-eslint/explicit-function-return-type": [ "error", { allowExpressions: true, allowTypedFunctionExpressions: true, allowHigherOrderFunctions: true, allowDirectConstAssertionInArrowFunctions: true, allowConciseArrowFunctionExpressionsStartingWithVoid: false, }, ], "@typescript-eslint/no-dynamic-delete": "error", "@typescript-eslint/no-empty-function": "off", "@typescript-eslint/no-empty-object-type": [ "error", { allowInterfaces: "with-single-extends" }, ], "@typescript-eslint/no-explicit-any": [ "warn", { ignoreRestArgs: true, }, ], "@typescript-eslint/no-extraneous-class": "error", "@typescript-eslint/no-floating-promises": "error", "@typescript-eslint/no-for-in-array": "error", "@typescript-eslint/no-inferrable-types": "off", "@typescript-eslint/no-invalid-this": "off", "@typescript-eslint/no-magic-numbers": "off", "@typescript-eslint/no-misused-new": "error", "@typescript-eslint/no-non-null-assertion": "error", "@typescript-eslint/no-require-imports": "error", "@typescript-eslint/no-shadow": [ "error", { hoist: "all", ignoreTypeValueShadow: true, }, ], "@typescript-eslint/no-this-alias": "error", "@typescript-eslint/no-unused-expressions": "error", "@typescript-eslint/no-unsafe-argument": "warn", "@typescript-eslint/no-unsafe-assignment": "warn", "@typescript-eslint/no-unsafe-call": "warn", "@typescript-eslint/no-unsafe-member-access": "warn", "@typescript-eslint/no-unsafe-return": "warn", "@typescript-eslint/no-unused-vars": "off", "@typescript-eslint/no-unnecessary-qualifier": "error", "@typescript-eslint/no-unnecessary-type-arguments": "error", "@typescript-eslint/no-unnecessary-type-assertion": "error", "@typescript-eslint/no-unsafe-function-type": "error", "@typescript-eslint/only-throw-error": "error", "@typescript-eslint/prefer-for-of": "error", "@typescript-eslint/prefer-function-type": "error", "@typescript-eslint/prefer-namespace-keyword": "error", "@typescript-eslint/prefer-readonly": "error", "@typescript-eslint/promise-function-async": "error", "@typescript-eslint/require-await": "off", "@typescript-eslint/restrict-plus-operands": "error", "@typescript-eslint/restrict-template-expressions": "off", "@typescript-eslint/return-await": "error", "@typescript-eslint/strict-boolean-expressions": "error", "@typescript-eslint/triple-slash-reference": "error", "@typescript-eslint/unbound-method": [ "error", { ignoreStatic: true, }, ], "@typescript-eslint/no-wrapper-object-types": "error", /** * Requires explicit typing for anything exported from a module. * @remarks Note: this will be promoted to "error" in a future release. */ "@typescript-eslint/explicit-module-boundary-types": "warn", /** * Note: will be promoted to an error in the future. */ "@typescript-eslint/consistent-type-exports": [ "warn", { fixMixedExportsWithInlineTypeSpecifier: true, }, ], /** * Enforces consistent usage of `import type` for type-only imports. * @remarks Note: this will be promoted to "error" in a future release. */ "@typescript-eslint/consistent-type-imports": ["warn", { fixStyle: "inline-type-imports" }], /** * Ensures that type-only import statements do not result in runtime side-effects. */ "@typescript-eslint/no-import-type-side-effects": "error", "@typescript-eslint/no-restricted-imports": [ "error", { paths: restrictedImportPaths, patterns: restrictedImportPatternsForProductionCode, }, ], /** * RATIONALE: Harmless. * * Our guideline is to only use leading underscores on private members when required to avoid a conflict * between private fields and a public property. */ "@typescript-eslint/naming-convention": [ "error", { selector: "accessor", modifiers: ["private"], format: ["camelCase"], leadingUnderscore: "allow", }, ], "@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. */ "@typescript-eslint/unified-signatures": "off", // Requires a lot of changes "@typescript-eslint/no-duplicate-type-constituents": "off", // Lots of false positives "@typescript-eslint/non-nullable-type-assertion-style": "off", // Requires breaking changes; enabled in the strict config "@typescript-eslint/consistent-indexed-object-style": "off", // Requires a lot of changes; enabled in the strict config "@typescript-eslint/no-unsafe-enum-comparison": "off", // Requires a lot of changes; enabled in the strict config "@typescript-eslint/no-redundant-type-constituents": "off", // Requires a lot of changes; enabled in the strict config "@typescript-eslint/consistent-generic-constructors": "off", /** * Disabled because we don't require that all variable declarations be explicitly typed. */ "@rushstack/typedef-var": "off", /** * The @rushstack rules are documented in the package README: * {@link https://www.npmjs.com/package/@rushstack/eslint-plugin} */ "@rushstack/no-new-null": "warn", // #endregion // #region @eslint-community/eslint-plugin-eslint-comments "@eslint-community/eslint-comments/disable-enable-pair": [ "error", { allowWholeFile: true, }, ], // #endregion // #region eslint-plugin-import-x // Note: Additional import-x settings are in the settings.mts module "import-x/no-default-export": "error", "import-x/no-deprecated": "error", "import-x/no-extraneous-dependencies": "error", /** * Allow Fluid Framework to import from its own internal packages. * https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-internal-modules.md */ "import-x/no-internal-modules": [ "error", { allow: permittedImports, }, ], /** * By default, libraries should not take dependencies on node libraries. * This rule can be disabled at the project level for libraries that are intended to be used only in node. */ "import-x/no-nodejs-modules": ["error"], "import-x/no-unassigned-import": "error", "import-x/no-unresolved": [ "error", { caseSensitive: true, }, ], "import-x/no-unused-modules": "error", // #endregion // #region eslint-plugin-unicorn "unicorn/better-regex": "error", "unicorn/filename-case": [ "error", { cases: { camelCase: true, pascalCase: true, }, }, ], // Rationale: Destructuring of `Array.entries()` in order to get the index variable results in a // significant performance regression [node 14 x64]. "unicorn/no-for-loop": "off", "unicorn/no-new-buffer": "error", /** * Warns if separators are inconsistent in number literals that contain separators. */ "unicorn/numeric-separators-style": ["warn", { onlyIfContainsSeparator: true }], "unicorn/prefer-switch": "error", "unicorn/prefer-ternary": "error", "unicorn/prefer-type-error": "error", // The rule seems to crash on some of our code "unicorn/expiring-todo-comments": "off", // #endregion // #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", "no-constant-condition": "error", "no-control-regex": "error", "no-debugger": "off", "no-duplicate-case": "error", "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", "no-octal": "error", "no-octal-escape": "error", "no-param-reassign": "error", "no-redeclare": "off", // Superseded by @typescript-eslint/no-redeclare "no-regex-spaces": "error", "no-restricted-syntax": [ "error", { selector: "ExportAllDeclaration", message: "Exporting * is not permitted. You should export only named items you intend to export.", }, "ForInStatement", ], "no-sequences": "error", "no-shadow": "off", // Superseded by @typescript-eslint/no-shadow "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", "no-unused-expressions": "off", // Superseded by @typescript-eslint/no-unused-expressions "no-unused-labels": "error", "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", "yoda": "off", // #endregion // #region unused-imports /** * Note: this can be replaced altogether by `@typescript-eslint/no-unused-vars`, * but that rule covers many more scenarios than this one does, and there are many violations * currently in the repository, so it has not been enabled yet. */ "unused-imports/no-unused-imports": "error", // #endregion // #region promise /** * Catches a common coding mistake where "resolve" and "reject" are confused. */ "promise/param-names": "warn", // #endregion // #region tsdoc/jsdoc /** * This rule ensures that our Intellisense looks good by verifying the TSDoc syntax. */ "tsdoc/syntax": "error", /** * Ensures that conflicting access tags don't exist in the same comment. */ "jsdoc/check-access": "error", /** * Ensures consistent line formatting in JSDoc/TSDoc comments. * TODO: This is temporarily set to "warn" because there are a lot of false positives with code blocks. */ "jsdoc/check-line-alignment": "warn", /** * The syntax this validates does not accommodate the syntax used by API-Extractor. */ "jsdoc/check-examples": "off", /** * Ensures correct indentation within JSDoc/TSDoc comment body. */ "jsdoc/check-indentation": "error", /** * Covered by `tsdoc/syntax`. */ "jsdoc/check-tag-names": "off", /** * Ensures that JSDoc/TSDoc "modifier" tags are empty. */ "jsdoc/empty-tags": "error", /** * Ensures JSDoc/TSDoc comments use consistent formatting. */ "jsdoc/multiline-blocks": ["error"], /** * Ensures multi-line formatting meets JSDoc/TSDoc requirements. */ "jsdoc/no-bad-blocks": "error", /** * Requires that each line in a JSDoc/TSDoc comment starts with a `*`. */ "jsdoc/require-asterisk-prefix": "error", /** * Ensure function/method parameter comments include a `-` between name and description. */ "jsdoc/require-hyphen-before-param-description": "error", /** * Require `@param` tags be non-empty. */ "jsdoc/require-param-description": "error", /** * Requires `@returns` tags to be non-empty. */ "jsdoc/require-returns-description": "error", // #endregion } as const satisfies Linter.RulesRecord; /** * eslint-comments/recommended rules. */ export const eslintCommentsRecommendedRules = { "@eslint-community/eslint-comments/disable-enable-pair": "error", "@eslint-community/eslint-comments/no-aggregating-enable": "error", "@eslint-community/eslint-comments/no-duplicate-disable": "error", "@eslint-community/eslint-comments/no-unlimited-disable": "error", "@eslint-community/eslint-comments/no-unused-enable": "error", } as const satisfies Linter.RulesRecord;