UNPKG

@rushstack/eslint-config

Version:

A TypeScript ESLint ruleset designed for large teams and projects

800 lines (669 loc) 37 kB
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. const macros = require('./_macros'); const namingConventionRuleOptions = [ { // We should be stricter about 'enumMember', but it often functions legitimately as an ad hoc namespace. selectors: ['variable', 'enumMember', 'function'], format: ['camelCase', 'UPPER_CASE', 'PascalCase'], leadingUnderscore: 'allow', filter: { regex: [ // This is a special exception for naming patterns that use an underscore to separate two camel-cased // parts. Example: "checkBox1_onChanged" or "_checkBox1_onChanged" '^_?[a-z][a-z0-9]*([A-Z][a-z]?[a-z0-9]*)*_[a-z][a-z0-9]*([A-Z][a-z]?[a-z0-9]*)*$' ] .map((x) => `(${x})`) .join('|'), match: false } }, { selectors: ['parameter'], format: ['camelCase'], filter: { regex: [ // Silently accept names with a double-underscore prefix; we would like to be more strict about this, // pending a fix for https://github.com/typescript-eslint/typescript-eslint/issues/2240 '^__' ] .map((x) => `(${x})`) .join('|'), match: false } }, // Genuine properties { selectors: ['parameterProperty', 'accessor'], enforceLeadingUnderscoreWhenPrivate: true, format: ['camelCase', 'UPPER_CASE'], filter: { regex: [ // Silently accept names with a double-underscore prefix; we would like to be more strict about this, // pending a fix for https://github.com/typescript-eslint/typescript-eslint/issues/2240 '^__', // Ignore quoted identifiers such as { "X+Y": 123 }. Currently @typescript-eslint/naming-convention // cannot detect whether an identifier is quoted or not, so we simply assume that it is quoted // if-and-only-if it contains characters that require quoting. '[^a-zA-Z0-9_]', // This is a special exception for naming patterns that use an underscore to separate two camel-cased // parts. Example: "checkBox1_onChanged" or "_checkBox1_onChanged" '^_?[a-z][a-z0-9]*([A-Z][a-z]?[a-z0-9]*)*_[a-z][a-z0-9]*([A-Z][a-z]?[a-z0-9]*)*$' ] .map((x) => `(${x})`) .join('|'), match: false } }, // Properties that incorrectly match other contexts // See issue https://github.com/typescript-eslint/typescript-eslint/issues/2244 { selectors: ['property'], enforceLeadingUnderscoreWhenPrivate: true, // The @typescript-eslint/naming-convention "property" selector matches cases like this: // // someLegacyApiWeCannotChange.invokeMethod({ SomeProperty: 123 }); // // and this: // // const { CONSTANT1, CONSTANT2 } = someNamespace.constants; // // Thus for now "property" is more like a variable than a class member. format: ['camelCase', 'UPPER_CASE', 'PascalCase'], leadingUnderscore: 'allow', filter: { regex: [ // Silently accept names with a double-underscore prefix; we would like to be more strict about this, // pending a fix for https://github.com/typescript-eslint/typescript-eslint/issues/2240 '^__', // Ignore quoted identifiers such as { "X+Y": 123 }. Currently @typescript-eslint/naming-convention // cannot detect whether an identifier is quoted or not, so we simply assume that it is quoted // if-and-only-if it contains characters that require quoting. '[^a-zA-Z0-9_]', // This is a special exception for naming patterns that use an underscore to separate two camel-cased // parts. Example: "checkBox1_onChanged" or "_checkBox1_onChanged" '^_?[a-z][a-z0-9]*([A-Z][a-z]?[a-z0-9]*)*_[a-z][a-z0-9]*([A-Z][a-z]?[a-z0-9]*)*$' ] .map((x) => `(${x})`) .join('|'), match: false } }, { selectors: ['method'], enforceLeadingUnderscoreWhenPrivate: true, // A PascalCase method can arise somewhat legitimately in this way: // // class MyClass { // public static MyReactButton(props: IButtonProps): JSX.Element { // . . . // } // } format: ['camelCase', 'PascalCase'], leadingUnderscore: 'allow', filter: { regex: [ // Silently accept names with a double-underscore prefix; we would like to be more strict about this, // pending a fix for https://github.com/typescript-eslint/typescript-eslint/issues/2240 '^__', // This is a special exception for naming patterns that use an underscore to separate two camel-cased // parts. Example: "checkBox1_onChanged" or "_checkBox1_onChanged" '^_?[a-z][a-z0-9]*([A-Z][a-z]?[a-z0-9]*)*_[a-z][a-z0-9]*([A-Z][a-z]?[a-z0-9]*)*$' ] .map((x) => `(${x})`) .join('|'), match: false } }, // Types should use PascalCase { // Group selector for: class, interface, typeAlias, enum, typeParameter selectors: ['class', 'typeAlias', 'enum', 'typeParameter'], format: ['PascalCase'], leadingUnderscore: 'allow' }, { selectors: ['interface'], // It is very common for a class to implement an interface of the same name. // For example, the Widget class may implement the IWidget interface. The "I" prefix // avoids the need to invent a separate name such as "AbstractWidget" or "WidgetInterface". // In TypeScript it is also common to declare interfaces that are implemented by primitive // objects, here the "I" prefix also helps by avoiding spurious conflicts with classes // by the same name. format: ['PascalCase'], custom: { regex: '^_?I[A-Z]', match: true } } ]; // Rule severity guidelines // ------------------------ // // Errors are generally printed in red, and may prevent other build tasks from running (e.g. unit tests). // Developers should never ignore errors. Warnings are generally printed in yellow, and do not block local // development, although they must be fixed/suppressed before merging. Developers will commonly ignore warnings // until their feature is working. // // Rules that should be a WARNING: // - An issue that is very common in partially implemented work (e.g. missing type declaration) // - An issue that "keeps things nice" but otherwise doesn't affect the meaning of the code (e.g. naming convention) // - Security rules -- developers may need to temporarily introduce "insecure" expressions while debugging; // if our policy forces them to suppress the lint rule, they may forget to reenable it later. // // Rules that should be an ERROR: // - An issue that is very likely to be a typo (e.g. "x = x;") // - An issue that catches code that is likely to malfunction (e.g. unterminated promise chain) // - An obsolete language feature that nobody should be using for any good reason function buildRules(profile) { return { // After an .eslintrc.js file is loaded, ESLint will normally continue visiting all parent folders // to look for other .eslintrc.js files, and also consult a personal file ~/.eslintrc.js. If any files // are found, their options will be merged. This is difficult for humans to understand, and it will cause // nondeterministic behavior if files are loaded from outside the Git working folder. // // Setting root=true causes ESLint to stop looking for other config files after the first .eslintrc.js // is loaded. root: true, // Disable the parser by default parser: '', plugins: [ // Plugin documentation: https://www.npmjs.com/package/@rushstack/eslint-plugin '@rushstack/eslint-plugin', // Plugin documentation: https://www.npmjs.com/package/@rushstack/eslint-plugin-security '@rushstack/eslint-plugin-security', // Plugin documentation: https://www.npmjs.com/package/@typescript-eslint/eslint-plugin '@typescript-eslint/eslint-plugin', // Plugin documentation: https://www.npmjs.com/package/eslint-plugin-promise 'eslint-plugin-promise' ], // Manually authored .d.ts files are generally used to describe external APIs that are not expected // to follow our coding conventions. Linting those files tends to produce a lot of spurious suppressions, // so we simply ignore them. ignorePatterns: ['*.d.ts'], overrides: [ { // Declare an override that applies to TypeScript files only files: ['*.ts', '*.tsx'], parser: '@typescript-eslint/parser', parserOptions: { // The "project" path is resolved relative to parserOptions.tsconfigRootDir. // Your local .eslintrc.js must specify that parserOptions.tsconfigRootDir=__dirname. project: './tsconfig.json', // Allow parsing of newer ECMAScript constructs used in TypeScript source code. Although tsconfig.json // may allow only a small subset of ES2018 features, this liberal setting ensures that ESLint will correctly // parse whatever is encountered. ecmaVersion: 2018, sourceType: 'module' }, rules: { // ==================================================================== // CUSTOM RULES // ==================================================================== // The @rushstack rules are documented in the package README: // https://www.npmjs.com/package/@rushstack/eslint-plugin // RATIONALE: See the @rushstack/eslint-plugin documentation '@rushstack/no-new-null': 'warn', // RATIONALE: See the @rushstack/eslint-plugin documentation '@rushstack/typedef-var': 'warn', // RATIONALE: See the @rushstack/eslint-plugin documentation // This is enabled and classified as an error because it is required when using Heft. // It's not required when using ts-jest, but still a good practice. '@rushstack/hoist-jest-mock': 'error', // ==================================================================== // SECURITY RULES // ==================================================================== // This is disabled for tools because, for example, it is a common and safe practice for a tool // to read a RegExp from a config file and use it to filter files paths. '@rushstack/security/no-unsafe-regexp': profile === 'node-trusted-tool' ? 'off' : 'warn', // ==================================================================== // GENERAL RULES // ==================================================================== // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json '@typescript-eslint/adjacent-overload-signatures': 'warn', // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json '@typescript-eslint/no-unsafe-function-type': 'warn', // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json '@typescript-eslint/no-wrapper-object-types': 'warn', // RATIONALE: We require "x as number" instead of "<number>x" to avoid conflicts with JSX. '@typescript-eslint/consistent-type-assertions': 'warn', // RATIONALE: We prefer "interface IBlah { x: number }" over "type Blah = { x: number }" // because code is more readable when it is built from stereotypical forms // (interfaces, enums, functions, etc.) instead of freeform type algebra. '@typescript-eslint/consistent-type-definitions': 'warn', // RATIONALE: Code is more readable when the type of every variable is immediately obvious. // Even if the compiler may be able to infer a type, this inference will be unavailable // to a person who is reviewing a GitHub diff. This rule makes writing code harder, // but writing code is a much less important activity than reading it. // // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json '@typescript-eslint/explicit-function-return-type': [ 'warn', { allowExpressions: true, allowTypedFunctionExpressions: true, allowHigherOrderFunctions: false } ], // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json '@typescript-eslint/explicit-member-accessibility': 'warn', // RATIONALE: Object-oriented programming organizes code into "classes" that associate // data structures (the class's fields) and the operations performed on those // data structures (the class's members). Studying the fields often reveals the "idea" // behind a class. The choice of which class a field belongs to may greatly impact // the code readability and complexity. Thus, we group the fields prominently at the top // of the class declaration. We do NOT enforce sorting based on public/protected/private // or static/instance, because these designations tend to change as code evolves, and // reordering methods produces spurious diffs that make PRs hard to read. For classes // with lots of methods, alphabetization is probably a more useful secondary ordering. '@typescript-eslint/member-ordering': [ 'warn', { default: 'never', classes: ['field', 'constructor', 'method'] } ], // NOTE: This new rule replaces several deprecated rules from @typescript-eslint/eslint-plugin@2.3.3: // // - @typescript-eslint/camelcase // - @typescript-eslint/class-name-casing // - @typescript-eslint/interface-name-prefix // - @typescript-eslint/member-naming // // Docs: https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/naming-convention.md '@typescript-eslint/naming-convention': [ 'warn', ...macros.expandNamingConventionSelectors(namingConventionRuleOptions) ], // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json '@typescript-eslint/no-array-constructor': 'warn', // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json // // RATIONALE: The "any" keyword disables static type checking, the main benefit of using TypeScript. // This rule should be suppressed only in very special cases such as JSON.stringify() // where the type really can be anything. Even if the type is flexible, another type // may be more appropriate such as "unknown", "{}", or "Record<k,V>". '@typescript-eslint/no-explicit-any': 'warn', // RATIONALE: The #1 rule of promises is that every promise chain must be terminated by a catch() // handler. Thus wherever a Promise arises, the code must either append a catch handler, // or else return the object to a caller (who assumes this responsibility). Unterminated // promise chains are a serious issue. Besides causing errors to be silently ignored, // they can also cause a NodeJS process to terminate unexpectedly. '@typescript-eslint/no-floating-promises': 'error', // RATIONALE: Catches a common coding mistake. '@typescript-eslint/no-for-in-array': 'error', // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json '@typescript-eslint/no-misused-new': 'error', // RATIONALE: The "namespace" keyword is not recommended for organizing code because JavaScript lacks // a "using" statement to traverse namespaces. Nested namespaces prevent certain bundler // optimizations. If you are declaring loose functions/variables, it's better to make them // static members of a class, since classes support property getters and their private // members are accessible by unit tests. Also, the exercise of choosing a meaningful // class name tends to produce more discoverable APIs: for example, search+replacing // the function "reverse()" is likely to return many false matches, whereas if we always // write "Text.reverse()" is more unique. For large scale organization, it's recommended // to decompose your code into separate NPM packages, which ensures that component // dependencies are tracked more conscientiously. // // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json '@typescript-eslint/no-namespace': [ 'warn', { // Discourage "namespace" in .ts and .tsx files allowDeclarations: false, // Allow it in .d.ts files that describe legacy libraries allowDefinitionFiles: false } ], // RATIONALE: Parameter properties provide a shorthand such as "constructor(public title: string)" // that avoids the effort of declaring "title" as a field. This TypeScript feature makes // code easier to write, but arguably sacrifices readability: In the notes for // "@typescript-eslint/member-ordering" we pointed out that fields are central to // a class's design, so we wouldn't want to bury them in a constructor signature // just to save some typing. // // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json '@typescript-eslint/parameter-properties': 'warn', // RATIONALE: When left in shipping code, unused variables often indicate a mistake. Dead code // may impact performance. // // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json '@typescript-eslint/no-unused-vars': [ 'warn', { vars: 'all', // Unused function arguments often indicate a mistake in JavaScript code. However in TypeScript code, // the compiler catches most of those mistakes, and unused arguments are fairly common for type signatures // that are overriding a base class method or implementing an interface. args: 'none', // Unused error arguments are common and useful for inspection when a debugger is attached. caughtErrors: 'none' } ], // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json '@typescript-eslint/no-use-before-define': [ 'error', { // Base ESLint options // We set functions=false so that functions can be ordered based on exported/local visibility // similar to class methods. Also the base lint rule incorrectly flags a legitimate case like: // // function a(n: number): void { // if (n > 0) { // b(n-1); // lint error // } // } // function b(n: number): void { // if (n > 0) { // a(n-1); // } // } functions: false, classes: true, variables: true, // TypeScript extensions enums: true, typedefs: true // ignoreTypeReferences: true } ], // TODO: This is a good rule for web browser apps, but it is commonly needed API for Node.js tools. // '@typescript-eslint/no-var-requires': 'error', // RATIONALE: The "module" keyword is deprecated except when describing legacy libraries. // // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json '@typescript-eslint/prefer-namespace-keyword': 'warn', // RATIONALE: We require explicit type annotations, even when the compiler could infer the type. // This can be a controversial policy because it makes code more verbose. There are // a couple downsides to type inference, however. First, it is not always available. // For example, when reviewing a pull request or examining a Git history, we may see // code like this: // // // What is the type of "y" here? The compiler knows, but the // // person reading the code may have no clue. // const x = f.(); // const y = x.z; // // Second, relying on implicit types also discourages design discussions and documentation. // Consider this example: // // // Where's the documentation for "correlation" and "inventory"? // // Where would you even write the TSDoc comments? // function g() { // return { correlation: 123, inventory: 'xyz' }; // } // // Implicit types make sense for small scale scenarios, where everyone is familiar with // the project, and code should be "easy to write". Explicit types are preferable // for large scale scenarios, where people regularly work with source files they've never // seen before, and code should be "easy to read." // // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json '@typescript-eslint/typedef': [ 'warn', { arrayDestructuring: false, arrowParameter: false, memberVariableDeclaration: true, objectDestructuring: false, parameter: true, propertyDeclaration: true, // This case is handled by our "@rushstack/typedef-var" rule variableDeclaration: false, // Normally we require type declarations for class members. However, that rule is relaxed // for situations where we need to bind the "this" pointer for a callback. For example, consider // this event handler for a React component: // // class MyComponent { // public render(): React.ReactNode { // return ( // <a href="#" onClick={this._onClick}> click me </a> // ); // } // // // The assignment here avoids the need for "this._onClick.bind(this)" // private _onClick = (event: React.MouseEvent<HTMLAnchorElement>): void => { // console.log("Clicked! " + this.props.title); // }; // } // // This coding style has limitations and should be used sparingly. For example, "_onClick" // will not participate correctly in "virtual"/"override" inheritance. // // NOTE: This option affects both "memberVariableDeclaration" and "variableDeclaration" options. variableDeclarationIgnoreFunction: true } ], // RATIONALE: This rule warns if setters are defined without getters, which is probably a mistake. 'accessor-pairs': 'error', // RATIONALE: In TypeScript, if you write x["y"] instead of x.y, it disables type checking. 'dot-notation': [ 'warn', { allowPattern: '^_' } ], // RATIONALE: Catches code that is likely to be incorrect eqeqeq: 'error', // STANDARDIZED BY: eslint\conf\eslint-recommended.js 'for-direction': 'warn', // RATIONALE: Catches a common coding mistake. 'guard-for-in': 'error', // RATIONALE: If you have more than 2,000 lines in a single source file, it's probably time // to split up your code. 'max-lines': ['warn', { max: 2000 }], // STANDARDIZED BY: eslint\conf\eslint-recommended.js 'no-async-promise-executor': 'error', // RATIONALE: "|" and "&" are relatively rare, and are more likely to appear as a mistake when // someone meant "||" or "&&". (But nobody types the other operators by mistake.) 'no-bitwise': [ 'warn', { allow: [ '^', // "|", // "&", '<<', '>>', '>>>', '^=', // "|=", //"&=", '<<=', '>>=', '>>>=', '~' ] } ], // RATIONALE: Deprecated language feature. 'no-caller': 'error', // STANDARDIZED BY: eslint\conf\eslint-recommended.js 'no-compare-neg-zero': 'error', // STANDARDIZED BY: eslint\conf\eslint-recommended.js 'no-cond-assign': 'error', // STANDARDIZED BY: eslint\conf\eslint-recommended.js 'no-constant-condition': 'warn', // STANDARDIZED BY: eslint\conf\eslint-recommended.js 'no-control-regex': 'error', // STANDARDIZED BY: eslint\conf\eslint-recommended.js 'no-debugger': 'warn', // STANDARDIZED BY: eslint\conf\eslint-recommended.js 'no-delete-var': 'error', // RATIONALE: Catches code that is likely to be incorrect // STANDARDIZED BY: eslint\conf\eslint-recommended.js 'no-duplicate-case': 'error', // STANDARDIZED BY: eslint\conf\eslint-recommended.js 'no-empty': 'warn', // STANDARDIZED BY: eslint\conf\eslint-recommended.js 'no-empty-character-class': 'error', // STANDARDIZED BY: eslint\conf\eslint-recommended.js 'no-empty-pattern': 'warn', // RATIONALE: Eval is a security concern and a performance concern. 'no-eval': 'warn', // RATIONALE: Catches code that is likely to be incorrect // STANDARDIZED BY: eslint\conf\eslint-recommended.js 'no-ex-assign': 'error', // RATIONALE: System types are global and should not be tampered with in a scalable code base. // If two different libraries (or two versions of the same library) both try to modify // a type, only one of them can win. Polyfills are acceptable because they implement // a standardized interoperable contract, but polyfills are generally coded in plain // JavaScript. 'no-extend-native': 'error', // STANDARDIZED BY: eslint\conf\eslint-recommended.js 'no-extra-boolean-cast': 'warn', 'no-extra-label': 'warn', // STANDARDIZED BY: eslint\conf\eslint-recommended.js 'no-fallthrough': 'error', // STANDARDIZED BY: eslint\conf\eslint-recommended.js 'no-func-assign': 'warn', // RATIONALE: Catches a common coding mistake. 'no-implied-eval': 'error', // STANDARDIZED BY: eslint\conf\eslint-recommended.js 'no-invalid-regexp': 'error', // RATIONALE: Catches a common coding mistake. 'no-label-var': 'error', // RATIONALE: Eliminates redundant code. 'no-lone-blocks': 'warn', // STANDARDIZED BY: eslint\conf\eslint-recommended.js 'no-misleading-character-class': 'error', // RATIONALE: Catches a common coding mistake. 'no-multi-str': 'error', // RATIONALE: It's generally a bad practice to call "new Thing()" without assigning the result to // a variable. Either it's part of an awkward expression like "(new Thing()).doSomething()", // or else implies that the constructor is doing nontrivial computations, which is often // a poor class design. 'no-new': 'warn', // RATIONALE: Obsolete language feature that is deprecated. 'no-new-func': 'error', // RATIONALE: Obsolete language feature that is deprecated. 'no-new-object': 'error', // RATIONALE: Obsolete notation. 'no-new-wrappers': 'warn', // RATIONALE: Catches code that is likely to be incorrect // STANDARDIZED BY: eslint\conf\eslint-recommended.js 'no-octal': 'error', // RATIONALE: Catches code that is likely to be incorrect 'no-octal-escape': 'error', // RATIONALE: Catches code that is likely to be incorrect // STANDARDIZED BY: eslint\conf\eslint-recommended.js 'no-regex-spaces': 'error', // RATIONALE: Catches a common coding mistake. 'no-return-assign': 'error', // RATIONALE: Security risk. 'no-script-url': 'warn', // STANDARDIZED BY: eslint\conf\eslint-recommended.js 'no-self-assign': 'error', // RATIONALE: Catches a common coding mistake. 'no-self-compare': 'error', // RATIONALE: This avoids statements such as "while (a = next(), a && a.length);" that use // commas to create compound expressions. In general code is more readable if each // step is split onto a separate line. This also makes it easier to set breakpoints // in the debugger. 'no-sequences': 'error', // RATIONALE: Catches code that is likely to be incorrect // STANDARDIZED BY: eslint\conf\eslint-recommended.js 'no-shadow-restricted-names': 'error', // RATIONALE: Obsolete language feature that is deprecated. // STANDARDIZED BY: eslint\conf\eslint-recommended.js 'no-sparse-arrays': 'error', // RATIONALE: Although in theory JavaScript allows any possible data type to be thrown as an exception, // such flexibility adds pointless complexity, by requiring every catch block to test // the type of the object that it receives. Whereas if catch blocks can always assume // that their object implements the "Error" contract, then the code is simpler, and // we generally get useful additional information like a call stack. 'no-throw-literal': 'error', // RATIONALE: Catches a common coding mistake. 'no-unmodified-loop-condition': 'warn', // STANDARDIZED BY: eslint\conf\eslint-recommended.js 'no-unsafe-finally': 'error', // RATIONALE: Catches a common coding mistake. 'no-unused-expressions': 'warn', // STANDARDIZED BY: eslint\conf\eslint-recommended.js 'no-unused-labels': 'warn', // STANDARDIZED BY: eslint\conf\eslint-recommended.js 'no-useless-catch': 'warn', // RATIONALE: Avoids a potential performance problem. 'no-useless-concat': 'warn', // RATIONALE: The "var" keyword is deprecated because of its confusing "hoisting" behavior. // Always use "let" or "const" instead. // // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json 'no-var': 'error', // RATIONALE: Generally not needed in modern code. 'no-void': 'error', // RATIONALE: Obsolete language feature that is deprecated. // STANDARDIZED BY: eslint\conf\eslint-recommended.js 'no-with': 'error', // RATIONALE: Makes logic easier to understand, since constants always have a known value // @typescript-eslint\eslint-plugin\dist\configs\eslint-recommended.js 'prefer-const': 'warn', // RATIONALE: Catches a common coding mistake where "resolve" and "reject" are confused. 'promise/param-names': 'error', // RATIONALE: Catches code that is likely to be incorrect // STANDARDIZED BY: eslint\conf\eslint-recommended.js 'require-atomic-updates': 'error', // STANDARDIZED BY: eslint\conf\eslint-recommended.js 'require-yield': 'warn', // "Use strict" is redundant when using the TypeScript compiler. strict: ['error', 'never'], // RATIONALE: Catches code that is likely to be incorrect // STANDARDIZED BY: eslint\conf\eslint-recommended.js 'use-isnan': 'error' // The "no-restricted-syntax" rule is a general purpose pattern matcher that we can use to experiment with // new rules. If a rule works well, we should convert it to a proper rule so it gets its own name // for suppressions and documentation. // How it works: https://eslint.org/docs/rules/no-restricted-syntax // AST visualizer: https://astexplorer.net/ // Debugger: http://estools.github.io/esquery/ // // "no-restricted-syntax": [ // ], } }, { // For unit tests, we can be a little bit less strict. The settings below revise the // defaults specified above. files: [ // Test files '*.test.ts', '*.test.tsx', '*.spec.ts', '*.spec.tsx', // Facebook convention '**/__mocks__/*.ts', '**/__mocks__/*.tsx', '**/__tests__/*.ts', '**/__tests__/*.tsx', // Microsoft convention '**/test/*.ts', '**/test/*.tsx' ], rules: { // Unit tests sometimes use a standalone statement like "new Thing(123);" to test a constructor. 'no-new': 'off', // Jest's mocking API is designed in a way that produces compositional data types that often have // no concise description. Since test code does not ship, and typically does not introduce new // concepts or algorithms, the usual arguments for prioritizing readability over writability can be // relaxed in this case. '@rushstack/typedef-var': 'off', '@typescript-eslint/typedef': [ 'warn', { arrayDestructuring: false, arrowParameter: false, memberVariableDeclaration: true, objectDestructuring: false, parameter: true, propertyDeclaration: true, variableDeclaration: false, // <--- special case for test files variableDeclarationIgnoreFunction: true } ] } } ] }; } exports.buildRules = buildRules; exports.namingConventionRuleOptions = namingConventionRuleOptions;