diff --git a/.cspell.json b/.cspell.json index 7ee50214e7fd..9df7d65a1b56 100644 --- a/.cspell.json +++ b/.cspell.json @@ -35,45 +35,47 @@ "\\(#.+?\\)" ], "words": [ - "ASTs", "Airbnb", "Airbnb's", - "Codecov", - "Crockford", - "errored", - "IDE's", - "IIFE", - "IIFEs", - "OOM", - "OOMs", - "Premade", - "ROADMAP", + "ASTs", "autofix", "autofixers", "backticks", "bigint", + "bivariant", "blockless", "codebases", + "Codecov", + "contravariant", + "Crockford", "declarators", "destructure", "destructured", + "errored", "erroring", "ESLint", "ESLint's", "espree", "estree", + "IDE's", + "IIFE", + "IIFEs", "linebreaks", "necroing", "nocheck", "nullish", + "OOM", + "OOMs", "parameterised", "performant", "pluggable", "postprocess", + "Premade", "prettier's", "recurse", "reimplement", "resync", + "ROADMAP", "ruleset", "rulesets", "superset", diff --git a/.eslintrc.js b/.eslintrc.js index 39ca61de5168..cee2ec901cca 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -174,7 +174,7 @@ module.exports = { '@typescript-eslint/internal/no-typescript-estree-import': 'error', }, }, - // rule source files + // plugin rule source files { files: [ 'packages/eslint-plugin-internal/src/rules/**/*.ts', @@ -187,6 +187,17 @@ module.exports = { 'import/no-default-export': 'off', }, }, + // plugin rule tests + { + files: [ + 'packages/eslint-plugin-internal/tests/rules/**/*.test.ts', + 'packages/eslint-plugin-tslint/tests/rules/**/*.test.ts', + 'packages/eslint-plugin/tests/rules/**/*.test.ts', + ], + rules: { + '@typescript-eslint/internal/plugin-test-formatting': 'error', + }, + }, // tools and tests { files: ['**/tools/**/*.ts', '**/tests/**/*.ts'], diff --git a/.github/ISSUE_TEMPLATE/eslint-plugin-tslint.md b/.github/ISSUE_TEMPLATE/eslint-plugin-tslint.md index b94f19fb5b82..e999830e4f18 100644 --- a/.github/ISSUE_TEMPLATE/eslint-plugin-tslint.md +++ b/.github/ISSUE_TEMPLATE/eslint-plugin-tslint.md @@ -15,7 +15,7 @@ The more relevant information you can include, the faster we can find the issue **Repro** diff --git a/.github/ISSUE_TEMPLATE/eslint-plugin-typescript.md b/.github/ISSUE_TEMPLATE/eslint-plugin-typescript.md index 3c0fb548f139..b9ab13f92496 100644 --- a/.github/ISSUE_TEMPLATE/eslint-plugin-typescript.md +++ b/.github/ISSUE_TEMPLATE/eslint-plugin-typescript.md @@ -28,7 +28,7 @@ Are you opening an issue because the rule you're trying to use is not found? **Repro** diff --git a/.github/ISSUE_TEMPLATE/typescript-eslint-parser.md b/.github/ISSUE_TEMPLATE/typescript-eslint-parser.md index aaa4bfd356c0..ca8d245b263f 100644 --- a/.github/ISSUE_TEMPLATE/typescript-eslint-parser.md +++ b/.github/ISSUE_TEMPLATE/typescript-eslint-parser.md @@ -15,7 +15,7 @@ The more relevant information you can include, the faster we can find the issue **Repro** diff --git a/.github/ISSUE_TEMPLATE/typescript-eslint-utils.md b/.github/ISSUE_TEMPLATE/typescript-eslint-utils.md index 5b365a85ea85..48bb39e6fe0e 100644 --- a/.github/ISSUE_TEMPLATE/typescript-eslint-utils.md +++ b/.github/ISSUE_TEMPLATE/typescript-eslint-utils.md @@ -15,7 +15,7 @@ The more relevant information you can include, the faster we can find the issue **Repro** diff --git a/.github/ISSUE_TEMPLATE/typescript-estree.md b/.github/ISSUE_TEMPLATE/typescript-estree.md index 21f4c800d548..f4a72b75b0ea 100644 --- a/.github/ISSUE_TEMPLATE/typescript-estree.md +++ b/.github/ISSUE_TEMPLATE/typescript-estree.md @@ -15,7 +15,7 @@ The more relevant information you can include, the faster we can find the issue **Repro** diff --git a/.prettierrc.json b/.prettierrc.json index bf357fbbc081..a20502b7f06d 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -1,3 +1,4 @@ { + "singleQuote": true, "trailingComma": "all" } diff --git a/CHANGELOG.md b/CHANGELOG.md index c4f8ac29ce3d..17a398ca454a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,30 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.27.0](https://github.com/typescript-eslint/typescript-eslint/compare/v2.26.0...v2.27.0) (2020-04-06) + + +### Bug Fixes + +* **eslint-plugin:** [no-throw-literal] fix crash caused by getBaseTypes ([#1830](https://github.com/typescript-eslint/typescript-eslint/issues/1830)) ([9d53c76](https://github.com/typescript-eslint/typescript-eslint/commit/9d53c761983dd964109b9f13eb9bfe20caf9defb)) +* **eslint-plugin:** [no-unsafe-call] fix incorrect selector ([#1826](https://github.com/typescript-eslint/typescript-eslint/issues/1826)) ([8ec53a3](https://github.com/typescript-eslint/typescript-eslint/commit/8ec53a3579fcb59cdffea0c60fbb755d056f4c8a)) +* **eslint-plugin:** [require-await] handle async generators ([#1782](https://github.com/typescript-eslint/typescript-eslint/issues/1782)) ([9642d9d](https://github.com/typescript-eslint/typescript-eslint/commit/9642d9dce693befac89a4e9d8bf8dd18f4361e2a)) +* **eslint-plugin:** no-explicit-any constructor functions (& mo… ([#1711](https://github.com/typescript-eslint/typescript-eslint/issues/1711)) ([ab8572e](https://github.com/typescript-eslint/typescript-eslint/commit/ab8572e30e14ebda91c8437be5ee35e7dc9add2e)) +* **typescript-estree:** add support for TS3.9 extra file extensions ([#1833](https://github.com/typescript-eslint/typescript-eslint/issues/1833)) ([1f0ff41](https://github.com/typescript-eslint/typescript-eslint/commit/1f0ff41aa1bc3b7c5330b2f5fe22e24bf578a6b2)) + + +### Features + +* **eslint-plugin:** new rule method-signature-style ([#1685](https://github.com/typescript-eslint/typescript-eslint/issues/1685)) ([c49d771](https://github.com/typescript-eslint/typescript-eslint/commit/c49d771ba62f1a21d3c1aec106341daddfcd3c9a)) +* **eslint-plugin:** sort members alphabetically ([#263](https://github.com/typescript-eslint/typescript-eslint/issues/263)) ([485e902](https://github.com/typescript-eslint/typescript-eslint/commit/485e90213a0f8baac0587f7d56925448883fc5bd)) +* **eslint-plugin-internal:** add plugin-test-formatting rule ([#1821](https://github.com/typescript-eslint/typescript-eslint/issues/1821)) ([9b0023a](https://github.com/typescript-eslint/typescript-eslint/commit/9b0023a4996ecdd7dfcb30abd1678091a78f3064)) +* **experimental-utils:** add types for suggestions from CLIEngine ([#1844](https://github.com/typescript-eslint/typescript-eslint/issues/1844)) ([7c11bd6](https://github.com/typescript-eslint/typescript-eslint/commit/7c11bd66f2d0e5ea9d3943e6b8c66e6ddff50862)) +* **experimental-utils:** update eslint types to match v6.8 ([#1846](https://github.com/typescript-eslint/typescript-eslint/issues/1846)) ([16ce74d](https://github.com/typescript-eslint/typescript-eslint/commit/16ce74d247781ac890dc0baa30c384f97e581b6b)) + + + + + # [2.26.0](https://github.com/typescript-eslint/typescript-eslint/compare/v2.25.0...v2.26.0) (2020-03-30) diff --git a/lerna.json b/lerna.json index c6d458fa9fa0..ecad9d3e932c 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.26.0", + "version": "2.27.0", "npmClient": "yarn", "useWorkspaces": true, "stream": true diff --git a/packages/eslint-plugin-internal/CHANGELOG.md b/packages/eslint-plugin-internal/CHANGELOG.md index 54cacab88898..00db774efbae 100644 --- a/packages/eslint-plugin-internal/CHANGELOG.md +++ b/packages/eslint-plugin-internal/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.27.0](https://github.com/typescript-eslint/typescript-eslint/compare/v2.26.0...v2.27.0) (2020-04-06) + + +### Features + +* **eslint-plugin-internal:** add plugin-test-formatting rule ([#1821](https://github.com/typescript-eslint/typescript-eslint/issues/1821)) ([9b0023a](https://github.com/typescript-eslint/typescript-eslint/commit/9b0023a4996ecdd7dfcb30abd1678091a78f3064)) + + + + + # [2.26.0](https://github.com/typescript-eslint/typescript-eslint/compare/v2.25.0...v2.26.0) (2020-03-30) **Note:** Version bump only for package @typescript-eslint/eslint-plugin-internal diff --git a/packages/eslint-plugin-internal/package.json b/packages/eslint-plugin-internal/package.json index 2a66b0484926..c70d071c3955 100644 --- a/packages/eslint-plugin-internal/package.json +++ b/packages/eslint-plugin-internal/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/eslint-plugin-internal", - "version": "2.26.0", + "version": "2.27.0", "private": true, "main": "dist/index.js", "scripts": { @@ -12,6 +12,7 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/experimental-utils": "2.26.0" + "@typescript-eslint/experimental-utils": "2.27.0", + "prettier": "*" } } diff --git a/packages/eslint-plugin-internal/src/rules/index.ts b/packages/eslint-plugin-internal/src/rules/index.ts index f781e01e6df1..eb8d8efe8520 100644 --- a/packages/eslint-plugin-internal/src/rules/index.ts +++ b/packages/eslint-plugin-internal/src/rules/index.ts @@ -1,9 +1,11 @@ import noTypescriptDefaultImport from './no-typescript-default-import'; import noTypescriptEstreeImport from './no-typescript-estree-import'; +import pluginTestFormatting from './plugin-test-formatting'; import preferASTTypesEnum from './prefer-ast-types-enum'; export default { 'no-typescript-default-import': noTypescriptDefaultImport, 'no-typescript-estree-import': noTypescriptEstreeImport, + 'plugin-test-formatting': pluginTestFormatting, 'prefer-ast-types-enum': preferASTTypesEnum, }; diff --git a/packages/eslint-plugin-internal/src/rules/plugin-test-formatting.ts b/packages/eslint-plugin-internal/src/rules/plugin-test-formatting.ts new file mode 100644 index 000000000000..bc26d9d9d9a1 --- /dev/null +++ b/packages/eslint-plugin-internal/src/rules/plugin-test-formatting.ts @@ -0,0 +1,508 @@ +import { + AST_NODE_TYPES, + TSESTree, +} from '@typescript-eslint/experimental-utils'; +import { format, resolveConfig } from 'prettier'; +import { createRule } from '../util'; + +/* +The strings that are used for eslint plugins will not be checked for formatting. +This can lead to diff noise as one contributor adjusts formatting, uses different quotes, etc. + +This rule just enforces the following: +- all code samples are formatted with prettier +- all single line tests do not use backticks +- all multiline tests have: + - no code on the first line + - no code on the last line + - the closing backtick indentation === property indentation + - one of the following indentations: + - no indentation at all + - indentation of 1 + object indent + +eg: +[ + 'const a = 1;', + ` +const a = 1; + `, + ` + const a = 1; + `, + { + code: 'const a = 1', + } + { + code: ` +const a = 1; + `, + } + { + code: ` + const a = 1; + `, + } +] +*/ + +const prettierConfig = resolveConfig.sync(__dirname) ?? {}; +const START_OF_LINE_WHITESPACE_MATCHER = /^([ ]*)/; +const BACKTICK_REGEX = /`/g; +const TEMPLATE_EXPR_OPENER = /\$\{/g; + +function getExpectedIndentForNode( + node: TSESTree.Node, + sourceCodeLines: string[], +): number { + const lineIdx = node.loc.start.line - 1; + const indent = START_OF_LINE_WHITESPACE_MATCHER.exec( + sourceCodeLines[lineIdx], + )![1]; + return indent.length; +} +function doIndent(line: string, indent: number): string { + for (let i = 0; i < indent; i += 1) { + line = ' ' + line; + } + return line; +} + +function getQuote(code: string): "'" | '"' | null { + const hasSingleQuote = code.includes("'"); + const hasDoubleQuote = code.includes('"'); + if (hasSingleQuote && hasDoubleQuote) { + // be lazy and make them fix and escape the quotes manually + return null; + } + + return hasSingleQuote ? '"' : "'"; +} + +function escapeTemplateString(code: string): string { + let fixed = code; + fixed = fixed.replace(BACKTICK_REGEX, '\\`'); + fixed = fixed.replace(TEMPLATE_EXPR_OPENER, '\\${'); + return fixed; +} + +type Options = [ + { + // This option exists so that rules like type-annotation-spacing can exist without every test needing a prettier-ignore + formatWithPrettier?: boolean; + }, +]; + +type MessageIds = + | 'invalidFormatting' + | 'invalidFormattingErrorTest' + | 'singleLineQuotes' + | 'templateLiteralEmptyEnds' + | 'templateLiteralLastLineIndent' + | 'templateStringRequiresIndent' + | 'templateStringMinimumIndent' + | 'prettierException'; + +export default createRule({ + name: 'plugin-test-formatting', + meta: { + type: 'problem', + docs: { + description: `Enforces that eslint-plugin test snippets are correctly formatted`, + category: 'Stylistic Issues', + recommended: 'error', + }, + fixable: 'code', + schema: [ + { + type: 'object', + additionalProperties: false, + properties: { + formatWithPrettier: { + type: 'boolean', + }, + }, + }, + ], + messages: { + invalidFormatting: + 'This snippet should be formatted correctly. Use the fixer to format the code.', + invalidFormattingErrorTest: + 'This snippet should be formatted correctly. Use the fixer to format the code. Note that the automated fixer may break your test locations.', + singleLineQuotes: 'Use quotes (\' or ") for single line tests.', + templateLiteralEmptyEnds: + 'Template literals must start and end with an empty line.', + templateLiteralLastLineIndent: + 'The closing line of the template literal must be indented to align with its parent.', + templateStringRequiresIndent: + 'Test code should either have no indent, or be indented {{indent}} spaces.', + templateStringMinimumIndent: + 'Test code should be indented at least {{indent}} spaces.', + prettierException: + 'Prettier was unable to format this snippet: {{message}}', + }, + }, + defaultOptions: [ + { + formatWithPrettier: true, + }, + ], + create(context, [{ formatWithPrettier }]) { + const sourceCode = context.getSourceCode(); + + function prettierFormat( + code: string, + location: TSESTree.Node, + ): string | null { + if (formatWithPrettier === false) { + return null; + } + + try { + return format(code, { + ...prettierConfig, + parser: 'typescript', + }).trimRight(); // prettier will insert a new line at the end of the code + } catch (ex) { + // adapted from https://github.com/prettier/eslint-plugin-prettier/blob/185b1064d3dd674538456fb2fad97fbfcde49e0d/eslint-plugin-prettier.js#L242-L257 + if (!(ex instanceof SyntaxError)) { + throw ex; + } + const err = ex as Error & { + codeFrame: string; + loc?: unknown; + }; + + let message = err.message; + + if (err.codeFrame) { + message = message.replace(`\n${err.codeFrame}`, ''); + } + if (err.loc) { + message = message.replace(/ \(\d+:\d+\)$/, ''); + } + + context.report({ + node: location, + messageId: 'prettierException', + data: { + message, + }, + }); + return null; + } + } + + function checkExpression(node: TSESTree.Node, isErrorTest: boolean): void { + switch (node.type) { + case AST_NODE_TYPES.Literal: + checkLiteral(node, isErrorTest); + break; + + case AST_NODE_TYPES.TemplateLiteral: + checkTemplateLiteral(node, isErrorTest); + break; + + case AST_NODE_TYPES.TaggedTemplateExpression: + checkTaggedTemplateExpression(node, isErrorTest); + break; + + case AST_NODE_TYPES.CallExpression: + checkCallExpression(node, isErrorTest); + break; + } + } + + function checkLiteral( + literal: TSESTree.Literal, + isErrorTest: boolean, + quoteIn?: string, + ): void { + if (typeof literal.value === 'string') { + const output = prettierFormat(literal.value, literal); + if (output && output !== literal.value) { + context.report({ + node: literal, + messageId: isErrorTest + ? 'invalidFormattingErrorTest' + : 'invalidFormatting', + fix(fixer) { + if (output.includes('\n')) { + // formatted string is multiline, then have to use backticks + return fixer.replaceText( + literal, + `\`${escapeTemplateString(output)}\``, + ); + } + + const quote = quoteIn ?? getQuote(output); + if (quote == null) { + return null; + } + + return fixer.replaceText(literal, `${quote}${output}${quote}`); + }, + }); + } + } + } + + function checkTemplateLiteral( + literal: TSESTree.TemplateLiteral, + isErrorTest: boolean, + isNoFormatTagged = false, + ): void { + if (literal.quasis.length > 1) { + // ignore template literals with ${expressions} for simplicity + return; + } + + const text = literal.quasis[0].value.cooked; + + if (literal.loc.end.line === literal.loc.start.line) { + // don't use template strings for single line tests + return context.report({ + node: literal, + messageId: 'singleLineQuotes', + fix(fixer) { + const quote = getQuote(text); + if (quote == null) { + return null; + } + + return [ + fixer.replaceTextRange( + [literal.range[0], literal.range[0] + 1], + quote, + ), + fixer.replaceTextRange( + [literal.range[1] - 1, literal.range[1]], + quote, + ), + ]; + }, + }); + } + + const lines = text.split('\n'); + const lastLine = lines[lines.length - 1]; + // prettier will trim out the end of line on save, but eslint will check before then + const isStartEmpty = lines[0].trimRight() === ''; + // last line can be indented + const isEndEmpty = lastLine.trimLeft() === ''; + if (!isStartEmpty || !isEndEmpty) { + // multiline template strings must have an empty first/last line + return context.report({ + node: literal, + messageId: 'templateLiteralEmptyEnds', + *fix(fixer) { + if (!isStartEmpty) { + yield fixer.replaceTextRange( + [literal.range[0], literal.range[0] + 1], + '`\n', + ); + } + + if (!isEndEmpty) { + yield fixer.replaceTextRange( + [literal.range[1] - 1, literal.range[1]], + '\n`', + ); + } + }, + }); + } + + const parentIndent = getExpectedIndentForNode(literal, sourceCode.lines); + if (lastLine.length !== parentIndent) { + return context.report({ + node: literal, + messageId: 'templateLiteralLastLineIndent', + fix(fixer) { + return fixer.replaceTextRange( + [literal.range[1] - lastLine.length - 1, literal.range[1]], + doIndent('`', parentIndent), + ); + }, + }); + } + + // remove the empty lines + lines.pop(); + lines.shift(); + + // +2 because we expect the string contents are indented one level + const expectedIndent = parentIndent + 2; + + const firstLineIndent = START_OF_LINE_WHITESPACE_MATCHER.exec( + lines[0], + )![1]; + const requiresIndent = firstLineIndent.length > 0; + if (requiresIndent) { + if (firstLineIndent.length !== expectedIndent) { + return context.report({ + node: literal, + messageId: 'templateStringRequiresIndent', + data: { + indent: expectedIndent, + }, + }); + } + + // quick-and-dirty validation that lines are roughly indented correctly + for (const line of lines) { + if (line.length === 0) { + // empty lines are valid + continue; + } + + const matches = START_OF_LINE_WHITESPACE_MATCHER.exec(line)!; + + const indent = matches[1]; + if (indent.length < expectedIndent) { + return context.report({ + node: literal, + messageId: 'templateStringMinimumIndent', + data: { + indent: expectedIndent, + }, + }); + } + } + + // trim the lines to remove expectedIndent characters from the start + // this makes it easier to check formatting + for (let i = 0; i < lines.length; i += 1) { + lines[i] = lines[i].substring(expectedIndent); + } + } + + if (isNoFormatTagged) { + return; + } + + const code = lines.join('\n'); + const formatted = prettierFormat(code, literal); + if (formatted && formatted !== code) { + const formattedIndented = requiresIndent + ? formatted + .split('\n') + .map(l => doIndent(l, expectedIndent)) + .join('\n') + : formatted; + + return context.report({ + node: literal, + messageId: isErrorTest + ? 'invalidFormattingErrorTest' + : 'invalidFormatting', + fix(fixer) { + return fixer.replaceText( + literal, + `\`\n${escapeTemplateString(formattedIndented)}\n${doIndent( + '', + parentIndent, + )}\``, + ); + }, + }); + } + } + + function isNoFormatTemplateTag(tag: TSESTree.Expression): boolean { + return tag.type === AST_NODE_TYPES.Identifier && tag.name === 'noFormat'; + } + + function checkTaggedTemplateExpression( + expr: TSESTree.TaggedTemplateExpression, + isErrorTest: boolean, + ): void { + if (!isNoFormatTemplateTag(expr.tag)) { + return; + } + + if (expr.loc.start.line === expr.loc.end.line) { + // all we do on single line test cases is check format, but there's no formatting to do + return; + } + + checkTemplateLiteral( + expr.quasi, + isErrorTest, + isNoFormatTemplateTag(expr.tag), + ); + } + + function checkCallExpression( + callExpr: TSESTree.CallExpression, + isErrorTest: boolean, + ): void { + if (callExpr.callee.type !== AST_NODE_TYPES.MemberExpression) { + return; + } + const memberExpr = callExpr.callee; + // handle cases like 'aa'.trimRight and `aa`.trimRight() + checkExpression(memberExpr.object, isErrorTest); + } + + function checkInvalidTest( + test: TSESTree.ObjectExpression, + isErrorTest = true, + ): void { + for (const prop of test.properties) { + if ( + prop.type !== AST_NODE_TYPES.Property || + prop.computed || + prop.key.type !== AST_NODE_TYPES.Identifier + ) { + continue; + } + + if (prop.key.name === 'code' || prop.key.name === 'output') { + checkExpression(prop.value, isErrorTest); + } + } + } + + function checkValidTest(tests: TSESTree.ArrayExpression): void { + for (const test of tests.elements) { + switch (test.type) { + case AST_NODE_TYPES.ObjectExpression: + // delegate object-style tests to the invalid checker + checkInvalidTest(test, false); + break; + + default: + checkExpression(test, false); + break; + } + } + } + + const invalidTestsSelectorPath = [ + AST_NODE_TYPES.CallExpression, + AST_NODE_TYPES.ObjectExpression, + 'Property[key.name = "invalid"]', + AST_NODE_TYPES.ArrayExpression, + AST_NODE_TYPES.ObjectExpression, + ]; + + return { + // valid + 'CallExpression > ObjectExpression > Property[key.name = "valid"] > ArrayExpression': checkValidTest, + // invalid - errors + [invalidTestsSelectorPath.join(' > ')]: checkInvalidTest, + // invalid - suggestions + [[ + ...invalidTestsSelectorPath, + 'Property[key.name = "errors"]', + AST_NODE_TYPES.ArrayExpression, + AST_NODE_TYPES.ObjectExpression, + 'Property[key.name = "suggestions"]', + AST_NODE_TYPES.ArrayExpression, + AST_NODE_TYPES.ObjectExpression, + ].join(' > ')]: checkInvalidTest, + // special case for our batchedSingleLineTests utility + 'CallExpression[callee.name = "batchedSingleLineTests"] > ObjectExpression': checkInvalidTest, + }; + }, +}); diff --git a/packages/eslint-plugin-internal/tests/rules/no-typescript-estree.test.ts b/packages/eslint-plugin-internal/tests/rules/no-typescript-estree.test.ts index a76e03b7c1d5..74b9478b58a1 100644 --- a/packages/eslint-plugin-internal/tests/rules/no-typescript-estree.test.ts +++ b/packages/eslint-plugin-internal/tests/rules/no-typescript-estree.test.ts @@ -10,20 +10,20 @@ const ruleTester = new RuleTester({ ruleTester.run('no-typescript-estree-import', rule, { valid: [ - 'import { foo } from "@typescript-eslint/experimental-utils";', - 'import foo from "@typescript-eslint/experimental-utils";', - 'import * as foo from "@typescript-eslint/experimental-utils";', + "import { foo } from '@typescript-eslint/experimental-utils';", + "import foo from '@typescript-eslint/experimental-utils';", + "import * as foo from '@typescript-eslint/experimental-utils';", ], invalid: batchedSingleLineTests({ code: ` -import { foo } from "@typescript-eslint/typescript-estree"; -import foo from "@typescript-eslint/typescript-estree"; -import * as foo from "@typescript-eslint/typescript-estree"; +import { foo } from '@typescript-eslint/typescript-estree'; +import foo from '@typescript-eslint/typescript-estree'; +import * as foo from '@typescript-eslint/typescript-estree'; `, output: ` -import { foo } from "@typescript-eslint/experimental-utils"; -import foo from "@typescript-eslint/experimental-utils"; -import * as foo from "@typescript-eslint/experimental-utils"; +import { foo } from '@typescript-eslint/experimental-utils'; +import foo from '@typescript-eslint/experimental-utils'; +import * as foo from '@typescript-eslint/experimental-utils'; `, errors: [ { diff --git a/packages/eslint-plugin-internal/tests/rules/plugin-test-formatting.test.ts b/packages/eslint-plugin-internal/tests/rules/plugin-test-formatting.test.ts new file mode 100644 index 000000000000..c2af09bec90a --- /dev/null +++ b/packages/eslint-plugin-internal/tests/rules/plugin-test-formatting.test.ts @@ -0,0 +1,519 @@ +import rule from '../../src/rules/plugin-test-formatting'; +import { RuleTester } from '../RuleTester'; + +const ruleTester = new RuleTester({ + parser: '@typescript-eslint/parser', + parserOptions: { + sourceType: 'module', + }, +}); + +const CODE_INDENT = ' '; +const PARENT_INDENT = ' '; +function wrap(strings: TemplateStringsArray, ...keys: string[]): string { + const lastIndex = strings.length - 1; + const code = + strings.slice(0, lastIndex).reduce((p, s, i) => p + s + keys[i], '') + + strings[lastIndex]; + return ` +ruleTester.run({ + valid: [ + { + code: ${code}, + }, + ], +}); + `; +} +function wrapWithOutput( + strings: TemplateStringsArray, + ...keys: string[] +): string { + const lastIndex = strings.length - 1; + const code = + strings.slice(0, lastIndex).reduce((p, s, i) => p + s + keys[i], '') + + strings[lastIndex]; + return ` +ruleTester.run({ + invalid: [ + { + code: ${code}, + output: ${code}, + }, + ], +}); + `; +} + +ruleTester.run('plugin-test-formatting', rule, { + valid: [ + // sanity check for valid tests non-object style + ` +ruleTester.run({ + valid: [ + 'const a = 1;', + \` + const a = 1; + \`, + \` +const a = 1; + \`, + noFormat\`const x=1;\`, + ], +}); + `, + wrap`'const a = 1;'`, + wrap`\` +${CODE_INDENT}const a = 1; +${PARENT_INDENT}\``, + wrap`\` +const a = 1; +${PARENT_INDENT}\``, + wrap`noFormat\`const a = 1;\``, + // sanity check suggestion validation + // eslint-disable-next-line @typescript-eslint/internal/plugin-test-formatting + ` + ruleTester.run({ + invalid: [ + { + code: 'const a = 1;', + output: 'const a = 1;', + errors: [ + { + messageId: 'foo', + suggestions: [ + { + messageId: 'bar', + output: 'const a = 1;', + }, + ], + } + ] + }, + { + code: \` + const a = 1; + \`, + output: \` + const a = 1; + \`, + errors: [ + { + messageId: 'foo', + suggestions: [ + { + messageId: 'bar', + output: \` + const a = 1; + \`, + }, + ], + } + ] + }, + { + code: \` +const a = 1; + \`, + output: \` +const a = 1; + \`, + errors: [ + { + messageId: 'foo', + suggestions: [ + { + messageId: 'bar', + output: \` +const a = 1; + \`, + }, + ], + } + ] + }, + ], + }); + `, + + // test the only option + { + code: wrap`'const x=1;'`, + options: [ + { + formatWithPrettier: false, + }, + ], + }, + + // empty linems are valid when everything else is indented + wrap`\` +${CODE_INDENT}const a = 1; + +${CODE_INDENT}const b = 1; +${PARENT_INDENT}\``, + ], + invalid: [ + // Literal + { + code: wrap`'const a=1;'`, + output: wrap`'const a = 1;'`, + errors: [ + { + messageId: 'invalidFormatting', + }, + ], + }, + { + code: wrap`'const a="1";'`, + output: wrap`"const a = '1';"`, + errors: [ + { + messageId: 'invalidFormatting', + }, + ], + }, + { + code: wrap`"const a='1';"`, + output: wrap`"const a = '1';"`, + errors: [ + { + messageId: 'invalidFormatting', + }, + ], + }, + { + code: wrap`'for (const x of y) {}'`, + output: wrap`\`for (const x of y) { +}\``, + errors: [ + { + messageId: 'invalidFormatting', + }, + ], + }, + { + code: wrap`'for (const x of \`asdf\`) {}'`, + // make sure it escapes the backticks + output: wrap`\`for (const x of \\\`asdf\\\`) { +}\``, + errors: [ + { + messageId: 'invalidFormatting', + }, + ], + }, + // TemplateLiteral + // singleLineQuotes + { + code: wrap`\`const a = 1;\``, + output: wrap`'const a = 1;'`, + errors: [ + { + messageId: 'singleLineQuotes', + }, + ], + }, + { + code: wrap`\`const a = '1'\``, + output: wrap`"const a = '1'"`, + errors: [ + { + messageId: 'singleLineQuotes', + }, + ], + }, + { + code: wrap`\`const a = "1";\``, + output: wrap`'const a = "1";'`, + errors: [ + { + messageId: 'singleLineQuotes', + }, + ], + }, + // templateLiteralEmptyEnds + { + code: wrap`\`const a = "1"; +${PARENT_INDENT}\``, + output: wrap`\` +const a = "1"; +${PARENT_INDENT}\``, + errors: [ + { + messageId: 'templateLiteralEmptyEnds', + }, + ], + }, + { + code: wrap`\` +${CODE_INDENT}const a = "1";\``, + output: wrap`\` +${CODE_INDENT}const a = "1"; +\``, + errors: [ + { + messageId: 'templateLiteralEmptyEnds', + }, + ], + }, + { + code: wrap`\`const a = "1"; +${CODE_INDENT}const b = "2";\``, + output: wrap`\` +const a = "1"; +${CODE_INDENT}const b = "2"; +\``, + errors: [ + { + messageId: 'templateLiteralEmptyEnds', + }, + ], + }, + // templateLiteralLastLineIndent + { + code: wrap`\` +${CODE_INDENT}const a = "1"; +\``, + output: wrap`\` +${CODE_INDENT}const a = "1"; +${PARENT_INDENT}\``, + errors: [ + { + messageId: 'templateLiteralLastLineIndent', + }, + ], + }, + { + code: wrap`\` +${CODE_INDENT}const a = "1"; + \``, + output: wrap`\` +${CODE_INDENT}const a = "1"; +${PARENT_INDENT}\``, + errors: [ + { + messageId: 'templateLiteralLastLineIndent', + }, + ], + }, + // templateStringRequiresIndent + { + code: wrap`\` + const a = "1"; +${PARENT_INDENT}\``, + errors: [ + { + messageId: 'templateStringRequiresIndent', + data: { + indent: CODE_INDENT.length, + }, + }, + ], + }, + { + code: ` +ruleTester.run({ + valid: [ + \` + const a = "1"; + \`, + ], +}); + `, + errors: [ + { + messageId: 'templateStringRequiresIndent', + data: { + indent: 6, + }, + }, + ], + }, + // templateStringMinimumIndent + { + code: wrap`\` +${CODE_INDENT}const a = "1"; + const b = "2"; +${PARENT_INDENT}\``, + errors: [ + { + messageId: 'templateStringMinimumIndent', + data: { + indent: CODE_INDENT.length, + }, + }, + ], + }, + // invalidFormatting + { + code: wrap`\` +${CODE_INDENT}const a="1"; +${CODE_INDENT} const b = "2"; +${PARENT_INDENT}\``, + output: wrap`\` +${CODE_INDENT}const a = '1'; +${CODE_INDENT}const b = '2'; +${PARENT_INDENT}\``, + errors: [ + { + messageId: 'invalidFormatting', + }, + ], + }, + { + code: wrap`\` +${CODE_INDENT}const a=\\\`\\\${a}\\\`; +${PARENT_INDENT}\``, + // make sure it escapes backticks + output: wrap`\` +${CODE_INDENT}const a = \\\`\\\${a}\\\`; +${PARENT_INDENT}\``, + errors: [ + { + messageId: 'invalidFormatting', + }, + ], + }, + + // sanity check that it runs on both output and code properties + { + code: wrapWithOutput`\` +${CODE_INDENT}const a="1"; +${CODE_INDENT} const b = "2"; +${PARENT_INDENT}\``, + output: wrapWithOutput`\` +${CODE_INDENT}const a = '1'; +${CODE_INDENT}const b = '2'; +${PARENT_INDENT}\``, + errors: [ + { + messageId: 'invalidFormattingErrorTest', + }, + { + messageId: 'invalidFormattingErrorTest', + }, + ], + }, + + // sanity check that it handles suggestion output + { + code: ` +ruleTester.run({ + valid: [], + invalid: [ + { + code: 'const x=1;', + errors: [ + { + messageId: 'foo', + suggestions: [ + { + messageId: 'bar', + output: 'const x=1;', + }, + ], + }, + ], + }, + ], +}); + `, + errors: [ + { + messageId: 'invalidFormattingErrorTest', + }, + { + messageId: 'invalidFormattingErrorTest', + }, + ], + }, + + // sanity check that it runs on all tests + { + code: ` +ruleTester.run({ + valid: [ + { + code: \`foo\`, + }, + { + code: \`foo +\`, + }, + { + code: \` + foo\`, + }, + ], + invalid: [ + { + code: \`foo\`, + }, + { + code: \`foo +\`, + }, + { + code: \` + foo\`, + }, + ], +}); + `, + errors: [ + { + messageId: 'singleLineQuotes', + }, + { + messageId: 'templateLiteralEmptyEnds', + }, + { + messageId: 'templateLiteralEmptyEnds', + }, + { + messageId: 'singleLineQuotes', + }, + { + messageId: 'templateLiteralEmptyEnds', + }, + { + messageId: 'templateLiteralEmptyEnds', + }, + ], + }, + + // handles prettier errors + { + code: wrap`'const x = ";'`, + errors: [ + { + messageId: 'prettierException', + data: { + message: 'Unterminated string literal.', + }, + }, + ], + }, + + // checks tests with .trimRight calls + { + code: wrap`'const a=1;'.trimRight()`, + output: wrap`'const a = 1;'.trimRight()`, + errors: [ + { + messageId: 'invalidFormatting', + }, + ], + }, + { + code: wrap`\`const a = "1"; +${CODE_INDENT}\`.trimRight()`, + errors: [ + { + messageId: 'templateLiteralEmptyEnds', + }, + ], + }, + ], +}); diff --git a/packages/eslint-plugin-internal/tests/rules/prefer-ast-types-enum.test.ts b/packages/eslint-plugin-internal/tests/rules/prefer-ast-types-enum.test.ts index 2688e035b59c..c2ffd8e489e0 100644 --- a/packages/eslint-plugin-internal/tests/rules/prefer-ast-types-enum.test.ts +++ b/packages/eslint-plugin-internal/tests/rules/prefer-ast-types-enum.test.ts @@ -14,29 +14,29 @@ const ruleTester = new RuleTester({ ruleTester.run('prefer-ast-types-enum', rule, { valid: [ - 'node.type === "constructor"', - 'node.type === AST_NODE_TYPES.Literal', - 'node.type === AST_TOKEN_TYPES.Keyword', - 'node.type === 1', + "node.type === 'constructor';", + 'node.type === AST_NODE_TYPES.Literal;', + 'node.type === AST_TOKEN_TYPES.Keyword;', + 'node.type === 1;', ` - enum MY_ENUM { - Literal = 1 - } + enum MY_ENUM { + Literal = 1, + } `, ` - enum AST_NODE_TYPES { - Literal = 'Literal' - } + enum AST_NODE_TYPES { + Literal = 'Literal', + } `, ], invalid: batchedSingleLineTests({ code: ` -node.type === 'Literal' -node.type === 'Keyword' +node.type === 'Literal'; +node.type === 'Keyword'; `, output: ` -node.type === AST_NODE_TYPES.Literal -node.type === AST_TOKEN_TYPES.Keyword +node.type === AST_NODE_TYPES.Literal; +node.type === AST_TOKEN_TYPES.Keyword; `, errors: [ { diff --git a/packages/eslint-plugin-tslint/CHANGELOG.md b/packages/eslint-plugin-tslint/CHANGELOG.md index efd31d32624e..feca294a7d3f 100644 --- a/packages/eslint-plugin-tslint/CHANGELOG.md +++ b/packages/eslint-plugin-tslint/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.27.0](https://github.com/typescript-eslint/typescript-eslint/compare/v2.26.0...v2.27.0) (2020-04-06) + +**Note:** Version bump only for package @typescript-eslint/eslint-plugin-tslint + + + + + # [2.26.0](https://github.com/typescript-eslint/typescript-eslint/compare/v2.25.0...v2.26.0) (2020-03-30) diff --git a/packages/eslint-plugin-tslint/package.json b/packages/eslint-plugin-tslint/package.json index 9a75ee89cd64..5a3c9134f85c 100644 --- a/packages/eslint-plugin-tslint/package.json +++ b/packages/eslint-plugin-tslint/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/eslint-plugin-tslint", - "version": "2.26.0", + "version": "2.27.0", "main": "dist/index.js", "typings": "src/index.ts", "description": "TSLint wrapper plugin for ESLint", @@ -31,7 +31,7 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/experimental-utils": "2.26.0", + "@typescript-eslint/experimental-utils": "2.27.0", "lodash": "^4.17.15" }, "peerDependencies": { @@ -41,6 +41,6 @@ }, "devDependencies": { "@types/lodash": "^4.14.149", - "@typescript-eslint/parser": "2.26.0" + "@typescript-eslint/parser": "2.27.0" } } diff --git a/packages/eslint-plugin/CHANGELOG.md b/packages/eslint-plugin/CHANGELOG.md index 057df3312e59..965a0e893bea 100644 --- a/packages/eslint-plugin/CHANGELOG.md +++ b/packages/eslint-plugin/CHANGELOG.md @@ -3,6 +3,27 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.27.0](https://github.com/typescript-eslint/typescript-eslint/compare/v2.26.0...v2.27.0) (2020-04-06) + + +### Bug Fixes + +* **eslint-plugin:** [no-throw-literal] fix crash caused by getBaseTypes ([#1830](https://github.com/typescript-eslint/typescript-eslint/issues/1830)) ([9d53c76](https://github.com/typescript-eslint/typescript-eslint/commit/9d53c761983dd964109b9f13eb9bfe20caf9defb)) +* **eslint-plugin:** [no-unsafe-call] fix incorrect selector ([#1826](https://github.com/typescript-eslint/typescript-eslint/issues/1826)) ([8ec53a3](https://github.com/typescript-eslint/typescript-eslint/commit/8ec53a3579fcb59cdffea0c60fbb755d056f4c8a)) +* **eslint-plugin:** [require-await] handle async generators ([#1782](https://github.com/typescript-eslint/typescript-eslint/issues/1782)) ([9642d9d](https://github.com/typescript-eslint/typescript-eslint/commit/9642d9dce693befac89a4e9d8bf8dd18f4361e2a)) +* **eslint-plugin:** no-explicit-any constructor functions (& mo… ([#1711](https://github.com/typescript-eslint/typescript-eslint/issues/1711)) ([ab8572e](https://github.com/typescript-eslint/typescript-eslint/commit/ab8572e30e14ebda91c8437be5ee35e7dc9add2e)) + + +### Features + +* **eslint-plugin:** new rule method-signature-style ([#1685](https://github.com/typescript-eslint/typescript-eslint/issues/1685)) ([c49d771](https://github.com/typescript-eslint/typescript-eslint/commit/c49d771ba62f1a21d3c1aec106341daddfcd3c9a)) +* **eslint-plugin:** sort members alphabetically ([#263](https://github.com/typescript-eslint/typescript-eslint/issues/263)) ([485e902](https://github.com/typescript-eslint/typescript-eslint/commit/485e90213a0f8baac0587f7d56925448883fc5bd)) +* **eslint-plugin-internal:** add plugin-test-formatting rule ([#1821](https://github.com/typescript-eslint/typescript-eslint/issues/1821)) ([9b0023a](https://github.com/typescript-eslint/typescript-eslint/commit/9b0023a4996ecdd7dfcb30abd1678091a78f3064)) + + + + + # [2.26.0](https://github.com/typescript-eslint/typescript-eslint/compare/v2.25.0...v2.26.0) (2020-03-30) diff --git a/packages/eslint-plugin/README.md b/packages/eslint-plugin/README.md index fa049b2cfb27..92131acf458e 100644 --- a/packages/eslint-plugin/README.md +++ b/packages/eslint-plugin/README.md @@ -107,6 +107,7 @@ Pro Tip: For larger codebases you may want to consider splitting our linting int | [`@typescript-eslint/explicit-module-boundary-types`](./docs/rules/explicit-module-boundary-types.md) | Require explicit return and argument types on exported functions' and classes' public class methods | | | | | [`@typescript-eslint/member-delimiter-style`](./docs/rules/member-delimiter-style.md) | Require a specific member delimiter style for interfaces and type literals | :heavy_check_mark: | :wrench: | | | [`@typescript-eslint/member-ordering`](./docs/rules/member-ordering.md) | Require a consistent member declaration order | | | | +| [`@typescript-eslint/method-signature-style`](./docs/rules/method-signature-style.md) | Enforces using a particular method signature syntax. | | :wrench: | | | [`@typescript-eslint/naming-convention`](./docs/rules/naming-convention.md) | Enforces naming conventions for everything across a codebase | | | :thought_balloon: | | [`@typescript-eslint/no-base-to-string`](./docs/rules/no-base-to-string.md) | Requires that `.toString()` is only called on objects which provide useful information when stringified | | | :thought_balloon: | | [`@typescript-eslint/no-dynamic-delete`](./docs/rules/no-dynamic-delete.md) | Disallow the delete operator with computed key expressions | | :wrench: | | diff --git a/packages/eslint-plugin/docs/rules/member-ordering.md b/packages/eslint-plugin/docs/rules/member-ordering.md index d028d844368a..cccf2bbbe0ab 100644 --- a/packages/eslint-plugin/docs/rules/member-ordering.md +++ b/packages/eslint-plugin/docs/rules/member-ordering.md @@ -1,29 +1,54 @@ # Require a consistent member declaration order (`member-ordering`) -A consistent ordering of fields, methods and constructors can make interfaces, type literals, classes and class -expressions easier to read, navigate and edit. +A consistent ordering of fields, methods and constructors can make interfaces, type literals, classes and class expressions easier to read, navigate and edit. ## Rule Details -This rule aims to standardize the way class declarations, class expressions, interfaces and type literals are structured. +This rule aims to standardize the way class declarations, class expressions, interfaces and type literals are structured and ordered. -It allows to group members by their type (e.g. `public-static-field`, `protected-static-field`, `private-static-field`, `public-instance-field`, ...). By default, their order is the same inside `classes`, `classExpressions`, `interfaces` and `typeLiterals` (note: not all member types apply to `interfaces` and `typeLiterals`). It is possible to define the order for any of those individually or to change the default order for all of them by setting the `default` option. +### Grouping and sorting member groups + +It allows to group members by their type (e.g. `public-static-field`, `protected-static-field`, `private-static-field`, `public-instance-field`, ...) and enforce a certain order for these groups. By default, their order is the same inside `classes`, `classExpressions`, `interfaces` and `typeLiterals` (note: not all member types apply to `interfaces` and `typeLiterals`). It is possible to define the order for any of those individually or to change the default order for all of them by setting the `default` option. + +### Sorting members + +Besides grouping the members and sorting their groups, this rule also allows to sort the members themselves (e.g. `a`, `b`, `c`, ...). You have 2 options: Sort all of them while ignoring their type or sort them while respecting their types (e.g. sort all fields in an interface alphabetically). ## Options +These options allow to specify how to group the members and sort their groups. + +- Sort groups, don't enforce member order: Use `memberTypes` +- Sort members, don't enforce group order: Use `order` +- Sort members within groups: Use `memberTypes` and `order` + ```ts +type TypeOptions = + | { + memberTypes: Array | 'never', + order?: 'alphabetically' | 'as-written', + } + | { + order: 'alphabetically', + }; + { - default?: Array | never - classes?: Array | never - classExpressions?: Array | never + default?: TypeOptions, + + classes?: TypeOptions, + classExpressions?: TypeOptions, - interfaces?: ['signature' | 'field' | 'method' | 'constructor'] | never - typeLiterals?: ['signature' | 'field' | 'method' | 'constructor'] | never + interfaces?: TypeOptions<'signature' | 'field' | 'method' | 'constructor'>, + typeLiterals?: TypeOptions<'signature' | 'field' | 'method' | 'constructor'>, } ``` See below for the possible definitions of `MemberType`. +### Deprecated syntax + +Note: There is a deprecated syntax to specify the member types as an array. + ### Member types (granular form) There are multiple ways to specify the member types. The most explicit and granular form is the following: @@ -138,62 +163,72 @@ The third grouping option is to ignore both scope and accessibility. The default configuration looks as follows: -```json +```json5 { - "default": [ - "signature", + default: [ + // Index signature + 'signature', - "public-static-field", - "protected-static-field", - "private-static-field", + // Fields + 'public-static-field', + 'protected-static-field', + 'private-static-field', - "public-instance-field", - "protected-instance-field", - "private-instance-field", + 'public-instance-field', + 'protected-instance-field', + 'private-instance-field', - "public-abstract-field", - "protected-abstract-field", - "private-abstract-field", + 'public-abstract-field', + 'protected-abstract-field', + 'private-abstract-field', - "public-field", - "protected-field", - "private-field", + 'public-field', + 'protected-field', + 'private-field', - "static-field", - "instance-field", - "abstract-field", + 'static-field', + 'instance-field', + 'abstract-field', - "field", + 'field', - "constructor", + // Constructors + 'public-constructor', + 'protected-constructor', + 'private-constructor', - "public-static-method", - "protected-static-method", - "private-static-method", + 'constructor', - "public-instance-method", - "protected-instance-method", - "private-instance-method", + // Methods + 'public-static-method', + 'protected-static-method', + 'private-static-method', - "public-abstract-method", - "protected-abstract-method", - "private-abstract-method", + 'public-instance-method', + 'protected-instance-method', + 'private-instance-method', - "public-method", - "protected-method", - "private-method", + 'public-abstract-method', + 'protected-abstract-method', + 'private-abstract-method', - "static-method", - "instance-method", - "abstract-method", + 'public-method', + 'protected-method', + 'private-method', - "method" - ] + 'static-method', + 'instance-method', + 'abstract-method', + + 'method', + ], } ``` Note: The default configuration contains member group types which contain other member types (see above). This is intentional to provide better error messages. +Note: By default, the members are not sorted. If you want to sort them alphabetically, you have to provide a custom configuration. + ## Examples ### Custom `default` configuration @@ -448,7 +483,7 @@ const foo = class { }; ``` -Issue: Public static fields should come first, followed by static fields and instance fields. +Note: Public static fields should come first, followed by static fields and instance fields. ##### Correct examples @@ -542,21 +577,19 @@ class Foo { ##### Correct example -Examples of **correct** code for `{ "classes": [...] }` option: - ```ts class Foo { private C: string; // (irrelevant) public D: string; // (irrelevant) - public static E: string; // -> public static field + public B(): void {} // -> public instance method constructor() {} // (irrelevant) public static A(): void {} // (irrelevant) - public B(): void {} // -> public instance method + public static E: string; // -> public static field } ``` @@ -712,6 +745,73 @@ type Foo = { }; ``` +### Sorting alphabetically within member groups + +It is possible to sort all members within a group alphabetically. + +#### Configuration: `{ default: { memberTypes: , order: 'alphabetically' } }` + +This will apply the default order (see above) and enforce an alphabetic order within each group. + +##### Incorrect examples + +```ts +interface Foo { + a: x; + b: x; + c: x; + + new (): Bar; + (): Baz; + + a(): void; + b(): void; + c(): void; + + // Wrong group order, should be placed before all field definitions + [a: string]: number; +} +``` + +```ts +interface Foo { + [a: string]: number; + + a: x; + b: x; + c: x; + + new (): Bar; + (): Baz; + + // Wrong alphabetic order within group + c(): void; + b(): void; + a(): void; +} +``` + +### Sorting alphabetically while ignoring member groups + +It is also possible to sort all members and ignore the member groups completely. + +#### Configuration: `{ default: { memberTypes: 'never', order: 'alphabetically' } }` + +##### Incorrect example + +```ts +interface Foo { + b(): void; + a: b; + + [a: string]: number; // Order doesn't matter (no sortable identifier) + new (): Bar; // Order doesn't matter (no sortable identifier) + (): Baz; // Order doesn't matter (no sortable identifier) +} +``` + +Note: Wrong alphabetic order `b(): void` should come after `a: b`. + ## When Not To Use It If you don't care about the general structure of your classes and interfaces, then you will not need this rule. diff --git a/packages/eslint-plugin/docs/rules/method-signature-style.md b/packages/eslint-plugin/docs/rules/method-signature-style.md new file mode 100644 index 000000000000..d760c8d01932 --- /dev/null +++ b/packages/eslint-plugin/docs/rules/method-signature-style.md @@ -0,0 +1,83 @@ +# Enforces using a particular method signature syntax. (`method-signature-style`) + +There are two ways to define an object/interface function property. + +```ts +// method shorthand syntax +interface T1 { + func(arg: string): number; +} + +// regular property with function type +interface T2 { + func: (arg: string) => number; +} +``` + +A good practice is to use the TypeScript's `strict` option (which implies `strictFunctionTypes`) which enables correct typechecking for function properties only (method signatures get old behavior). + +TypeScript FAQ: + +> A method and a function property of the same type behave differently. +> Methods are always bivariant in their argument, while function properties are contravariant in their argument under `strictFunctionTypes`. + +See the reasoning behind that in the [TypeScript PR for the compiler option](https://github.com/microsoft/TypeScript/pull/18654). + +## Options + +This rule accepts one string option: + +- `"property"`: Enforce using property signature for functions. Use this to enforce maximum correctness together with TypeScript's strict mode. +- `"method"`: Enforce using method signature for functions. Use this if you aren't using TypeScript's strict mode and prefer this style. + +The default is `"property"`. + +## Rule Details + +Examples of **incorrect** code with `property` option. + +```ts +interface T1 { + func(arg: string): number; +} +type T2 = { + func(arg: boolean): void; +}; +``` + +Examples of **correct** code with `property` option. + +```ts +interface T1 { + func: (arg: string) => number; +} +type T2 = { + func: (arg: boolean) => void; +}; +``` + +Examples of **incorrect** code with `method` option. + +```ts +interface T1 { + func: (arg: string) => number; +} +type T2 = { + func: (arg: boolean) => void; +}; +``` + +Examples of **correct** code with `method` option. + +```ts +interface T1 { + func(arg: string): number; +} +type T2 = { + func(arg: boolean): void; +}; +``` + +## When Not To Use It + +If you don't want to enforce a particular style for object/interface function types, and/or if you don't use `strictFunctionTypes`, then you don't need this rule. diff --git a/packages/eslint-plugin/docs/rules/no-explicit-any.md b/packages/eslint-plugin/docs/rules/no-explicit-any.md index 0c2713923492..c440d3bdc602 100644 --- a/packages/eslint-plugin/docs/rules/no-explicit-any.md +++ b/packages/eslint-plugin/docs/rules/no-explicit-any.md @@ -119,30 +119,23 @@ function foo2(...args: readonly any[]): void {} function foo3(...args: Array): void {} function foo4(...args: ReadonlyArray): void {} -const bar1 = (...args: any[]): void {} -const bar2 = (...args: readonly any[]): void {} -const bar3 = (...args: Array): void {} -const bar4 = (...args: ReadonlyArray): void {} +declare function bar(...args: any[]): void; -const baz1 = function (...args: any[]) {} -const baz2 = function (...args: readonly any[]) {} -const baz3 = function (...args: Array) {} -const baz4 = function (...args: ReadonlyArray) {} +const baz = (...args: any[]) => {}; +const qux = function(...args: any[]) {}; -interface Qux1 { (...args: any[]): void; } -interface Qux2 { (...args: readonly any[]): void; } -interface Qux3 { (...args: Array): void; } -interface Qux4 { (...args: ReadonlyArray): void; } +type Quux = (...args: any[]) => void; +type Quuz = new (...args: any[]) => void; -function quux1(fn: (...args: any[]) => void): void {} -function quux2(fn: (...args: readonly any[]) => void): void {} -function quux3(fn: (...args: Array) => void): void {} -function quux4(fn: (...args: ReadonlyArray) => void): void {} - -function quuz1(): ((...args: any[]) => void) {} -function quuz2(): ((...args: readonly any[]) => void) {} -function quuz3(): ((...args: Array) => void) {} -function quuz4(): ((...args: ReadonlyArray) => void) {} +interface Grault { + (...args: any[]): void; +} +interface Corge { + new (...args: any[]): void; +} +interface Garply { + f(...args: any[]): void; +} ``` Examples of **correct** code for the `{ "ignoreRestArgs": true }` option: @@ -155,30 +148,23 @@ function foo2(...args: readonly any[]): void {} function foo3(...args: Array): void {} function foo4(...args: ReadonlyArray): void {} -const bar1 = (...args: any[]): void {} -const bar2 = (...args: readonly any[]): void {} -const bar3 = (...args: Array): void {} -const bar4 = (...args: ReadonlyArray): void {} - -const baz1 = function (...args: any[]) {} -const baz2 = function (...args: readonly any[]) {} -const baz3 = function (...args: Array) {} -const baz4 = function (...args: ReadonlyArray) {} - -interface Qux1 { (...args: any[]): void; } -interface Qux2 { (...args: readonly any[]): void; } -interface Qux3 { (...args: Array): void; } -interface Qux4 { (...args: ReadonlyArray): void; } - -function quux1(fn: (...args: any[]) => void): void {} -function quux2(fn: (...args: readonly any[]) => void): void {} -function quux3(fn: (...args: Array) => void): void {} -function quux4(fn: (...args: ReadonlyArray) => void): void {} - -function quuz1(): ((...args: any[]) => void) {} -function quuz2(): ((...args: readonly any[]) => void) {} -function quuz3(): ((...args: Array) => void) {} -function quuz4(): ((...args: ReadonlyArray) => void) {} +declare function bar(...args: any[]): void; + +const baz = (...args: any[]) => {}; +const qux = function(...args: any[]) {}; + +type Quux = (...args: any[]) => void; +type Quuz = new (...args: any[]) => void; + +interface Grault { + (...args: any[]): void; +} +interface Corge { + new (...args: any[]): void; +} +interface Garply { + f(...args: any[]): void; +} ``` ## When Not To Use It diff --git a/packages/eslint-plugin/docs/rules/no-type-alias.md b/packages/eslint-plugin/docs/rules/no-type-alias.md index 9d7f1d47744a..5b720b2f331d 100644 --- a/packages/eslint-plugin/docs/rules/no-type-alias.md +++ b/packages/eslint-plugin/docs/rules/no-type-alias.md @@ -69,7 +69,7 @@ On the other hand, using a type alias as an interface can limit your ability to: - Debug your code: interfaces create a new name, so is easy to identify the base type of an object while debugging the application. -Finally, mapping types is an advance technique, leaving it open can quickly become a pain point +Finally, mapping types is an advanced technique and leaving it open can quickly become a pain point in your application. ## Rule Details diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index 7689d700f4a2..290f200a0d3e 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/eslint-plugin", - "version": "2.26.0", + "version": "2.27.0", "description": "TypeScript plugin for ESLint", "keywords": [ "eslint", @@ -41,7 +41,7 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/experimental-utils": "2.26.0", + "@typescript-eslint/experimental-utils": "2.27.0", "functional-red-black-tree": "^1.0.1", "regexpp": "^3.0.0", "tsutils": "^3.17.1" diff --git a/packages/eslint-plugin/src/configs/all.json b/packages/eslint-plugin/src/configs/all.json index c5575d4970d6..cfcb38ced24f 100644 --- a/packages/eslint-plugin/src/configs/all.json +++ b/packages/eslint-plugin/src/configs/all.json @@ -24,6 +24,7 @@ "@typescript-eslint/indent": "error", "@typescript-eslint/member-delimiter-style": "error", "@typescript-eslint/member-ordering": "error", + "@typescript-eslint/method-signature-style": "error", "@typescript-eslint/naming-convention": "error", "no-array-constructor": "off", "@typescript-eslint/no-array-constructor": "error", diff --git a/packages/eslint-plugin/src/rules/index.ts b/packages/eslint-plugin/src/rules/index.ts index 29db58b681ab..332c706c832c 100644 --- a/packages/eslint-plugin/src/rules/index.ts +++ b/packages/eslint-plugin/src/rules/index.ts @@ -22,6 +22,7 @@ import interfaceNamePrefix from './interface-name-prefix'; import memberDelimiterStyle from './member-delimiter-style'; import memberNaming from './member-naming'; import memberOrdering from './member-ordering'; +import methodSignatureStyle from './method-signature-style'; import namingConvention from './naming-convention'; import noArrayConstructor from './no-array-constructor'; import noBaseToString from './no-base-to-string'; @@ -30,10 +31,10 @@ import noDynamicDelete from './no-dynamic-delete'; import noEmptyFunction from './no-empty-function'; import noEmptyInterface from './no-empty-interface'; import noExplicitAny from './no-explicit-any'; -import noExtraneousClass from './no-extraneous-class'; import noExtraNonNullAssertion from './no-extra-non-null-assertion'; import noExtraParens from './no-extra-parens'; import noExtraSemi from './no-extra-semi'; +import noExtraneousClass from './no-extraneous-class'; import noFloatingPromises from './no-floating-promises'; import noForInArray from './no-for-in-array'; import noImpliedEval from './no-implied-eval'; @@ -99,7 +100,6 @@ export default { 'ban-ts-comment': banTsComment, 'ban-ts-ignore': banTsIgnore, 'ban-types': banTypes, - 'no-base-to-string': noBaseToString, 'brace-style': braceStyle, camelcase: camelcase, 'class-name-casing': classNameCasing, @@ -118,8 +118,10 @@ export default { 'member-delimiter-style': memberDelimiterStyle, 'member-naming': memberNaming, 'member-ordering': memberOrdering, + 'method-signature-style': methodSignatureStyle, 'naming-convention': namingConvention, 'no-array-constructor': noArrayConstructor, + 'no-base-to-string': noBaseToString, 'no-dupe-class-members': noDupeClassMembers, 'no-dynamic-delete': noDynamicDelete, 'no-empty-function': noEmptyFunction, diff --git a/packages/eslint-plugin/src/rules/member-ordering.ts b/packages/eslint-plugin/src/rules/member-ordering.ts index b9fb0ee8ef0d..14ddcc236a90 100644 --- a/packages/eslint-plugin/src/rules/member-ordering.ts +++ b/packages/eslint-plugin/src/rules/member-ordering.ts @@ -1,12 +1,21 @@ import { - TSESTree, AST_NODE_TYPES, + TSESLint, + TSESTree, } from '@typescript-eslint/experimental-utils'; import * as util from '../util'; -type MessageIds = 'incorrectOrder'; -type OrderConfig = string[] | 'never'; -type Options = [ +export type MessageIds = 'incorrectGroupOrder' | 'incorrectOrder'; + +interface SortedOrderConfig { + memberTypes?: string[] | 'never'; + order: 'alphabetically' | 'as-written'; +} + +type OrderConfig = string[] | SortedOrderConfig | 'never'; +type Member = TSESTree.ClassElement | TSESTree.TypeElement; + +export type Options = [ { default?: OrderConfig; classes?: OrderConfig; @@ -16,30 +25,287 @@ type Options = [ }, ]; -const allMemberTypes = ['field', 'method', 'constructor'].reduce( - (all, type) => { - all.push(type); +const neverConfig = { + type: 'string', + enum: ['never'], +}; + +const arrayConfig = (memberTypes: string[]): object => ({ + type: 'array', + items: { + enum: memberTypes, + }, +}); + +const objectConfig = (memberTypes: string[]): object => ({ + type: 'object', + properties: { + memberTypes: { + oneOf: [arrayConfig(memberTypes), neverConfig], + }, + order: { + type: 'string', + enum: ['alphabetically', 'as-written'], + }, + }, + additionalProperties: false, +}); + +export const defaultOrder = [ + // Index signature + 'signature', - ['public', 'protected', 'private'].forEach(accessibility => { + // Fields + 'public-static-field', + 'protected-static-field', + 'private-static-field', + + 'public-instance-field', + 'protected-instance-field', + 'private-instance-field', + + 'public-abstract-field', + 'protected-abstract-field', + 'private-abstract-field', + + 'public-field', + 'protected-field', + 'private-field', + + 'static-field', + 'instance-field', + 'abstract-field', + + 'field', + + // Constructors + 'public-constructor', + 'protected-constructor', + 'private-constructor', + + 'constructor', + + // Methods + 'public-static-method', + 'protected-static-method', + 'private-static-method', + + 'public-instance-method', + 'protected-instance-method', + 'private-instance-method', + + 'public-abstract-method', + 'protected-abstract-method', + 'private-abstract-method', + + 'public-method', + 'protected-method', + 'private-method', + + 'static-method', + 'instance-method', + 'abstract-method', + + 'method', +]; + +const allMemberTypes = ['signature', 'field', 'method', 'constructor'].reduce< + string[] +>((all, type) => { + all.push(type); + + ['public', 'protected', 'private'].forEach(accessibility => { + if (type !== 'signature') { all.push(`${accessibility}-${type}`); // e.g. `public-field` + } - if (type !== 'constructor') { - // There is no `static-constructor` or `instance-constructor or `abstract-constructor` - ['static', 'instance', 'abstract'].forEach(scope => { - if (!all.includes(`${scope}-${type}`)) { - all.push(`${scope}-${type}`); - } + if (type !== 'constructor' && type !== 'signature') { + // There is no `static-constructor` or `instance-constructor` or `abstract-constructor` + ['static', 'instance', 'abstract'].forEach(scope => { + if (!all.includes(`${scope}-${type}`)) { + all.push(`${scope}-${type}`); + } - all.push(`${accessibility}-${scope}-${type}`); - }); - } - }); + all.push(`${accessibility}-${scope}-${type}`); + }); + } + }); - return all; - }, - [], -); -allMemberTypes.unshift('signature'); + return all; +}, []); + +const functionExpressions = [ + AST_NODE_TYPES.FunctionExpression, + AST_NODE_TYPES.ArrowFunctionExpression, +]; + +/** + * Gets the node type. + * + * @param node the node to be evaluated. + */ +function getNodeType(node: Member): string | null { + // TODO: add missing TSCallSignatureDeclaration + switch (node.type) { + case AST_NODE_TYPES.TSAbstractMethodDefinition: + case AST_NODE_TYPES.MethodDefinition: + return node.kind; + case AST_NODE_TYPES.TSMethodSignature: + return 'method'; + case AST_NODE_TYPES.TSConstructSignatureDeclaration: + return 'constructor'; + case AST_NODE_TYPES.TSAbstractClassProperty: + case AST_NODE_TYPES.ClassProperty: + return node.value && functionExpressions.includes(node.value.type) + ? 'method' + : 'field'; + case AST_NODE_TYPES.TSPropertySignature: + return 'field'; + case AST_NODE_TYPES.TSIndexSignature: + return 'signature'; + default: + return null; + } +} + +/** + * Gets the member name based on the member type. + * + * @param node the node to be evaluated. + * @param sourceCode + */ +function getMemberName( + node: Member, + sourceCode: TSESLint.SourceCode, +): string | null { + switch (node.type) { + case AST_NODE_TYPES.TSPropertySignature: + case AST_NODE_TYPES.TSMethodSignature: + case AST_NODE_TYPES.TSAbstractClassProperty: + case AST_NODE_TYPES.ClassProperty: + return util.getNameFromMember(node, sourceCode); + case AST_NODE_TYPES.TSAbstractMethodDefinition: + case AST_NODE_TYPES.MethodDefinition: + return node.kind === 'constructor' + ? 'constructor' + : util.getNameFromMember(node, sourceCode); + case AST_NODE_TYPES.TSConstructSignatureDeclaration: + return 'new'; + case AST_NODE_TYPES.TSIndexSignature: + return util.getNameFromIndexSignature(node); + default: + return null; + } +} + +/** + * Gets the calculated rank using the provided method definition. + * The algorithm is as follows: + * - Get the rank based on the accessibility-scope-type name, e.g. public-instance-field + * - If there is no order for accessibility-scope-type, then strip out the accessibility. + * - If there is no order for scope-type, then strip out the scope. + * - If there is no order for type, then return -1 + * @param memberGroups the valid names to be validated. + * @param orderConfig the current order to be validated. + * + * @return Index of the matching member type in the order configuration. + */ +function getRankOrder(memberGroups: string[], orderConfig: string[]): number { + let rank = -1; + const stack = memberGroups.slice(); // Get a copy of the member groups + + while (stack.length > 0 && rank === -1) { + rank = orderConfig.indexOf(stack.shift()!); + } + + return rank; +} + +/** + * Gets the rank of the node given the order. + * @param node the node to be evaluated. + * @param orderConfig the current order to be validated. + * @param supportsModifiers a flag indicating whether the type supports modifiers (scope or accessibility) or not. + */ +function getRank( + node: Member, + orderConfig: string[], + supportsModifiers: boolean, +): number { + const type = getNodeType(node); + + if (type === null) { + // shouldn't happen but just in case, put it on the end + return orderConfig.length - 1; + } + + const abstract = + node.type === AST_NODE_TYPES.TSAbstractClassProperty || + node.type === AST_NODE_TYPES.TSAbstractMethodDefinition; + + const scope = + 'static' in node && node.static + ? 'static' + : abstract + ? 'abstract' + : 'instance'; + const accessibility = + 'accessibility' in node && node.accessibility + ? node.accessibility + : 'public'; + + // Collect all existing member groups (e.g. 'public-instance-field', 'instance-field', 'public-field', 'constructor' etc.) + const memberGroups = []; + + if (supportsModifiers) { + if (type !== 'constructor') { + // Constructors have no scope + memberGroups.push(`${accessibility}-${scope}-${type}`); + memberGroups.push(`${scope}-${type}`); + } + + memberGroups.push(`${accessibility}-${type}`); + } + + memberGroups.push(type); + + return getRankOrder(memberGroups, orderConfig); +} + +/** + * Gets the lowest possible rank higher than target. + * e.g. given the following order: + * ... + * public-static-method + * protected-static-method + * private-static-method + * public-instance-method + * protected-instance-method + * private-instance-method + * ... + * and considering that a public-instance-method has already been declared, so ranks contains + * public-instance-method, then the lowest possible rank for public-static-method is + * public-instance-method. + * @param ranks the existing ranks in the object. + * @param target the target rank. + * @param order the current order to be validated. + * @returns the name of the lowest possible rank without dashes (-). + */ +function getLowestRank( + ranks: number[], + target: number, + order: string[], +): string { + let lowest = ranks[ranks.length - 1]; + + ranks.forEach(rank => { + if (rank > target) { + lowest = Math.min(lowest, rank); + } + }); + + return order[lowest].replace(/-/g, ' '); +} export default util.createRule({ name: 'member-ordering', @@ -52,6 +318,8 @@ export default util.createRule({ }, messages: { incorrectOrder: + 'Member "{{member}}" should be declared before member "{{beforeMember}}".', + incorrectGroupOrder: 'Member {{name}} should be declared before all {{rank}} definitions.', }, schema: [ @@ -60,67 +328,37 @@ export default util.createRule({ properties: { default: { oneOf: [ - { - enum: ['never'], - }, - { - type: 'array', - items: { - enum: allMemberTypes, - }, - }, + neverConfig, + arrayConfig(allMemberTypes), + objectConfig(allMemberTypes), ], }, classes: { oneOf: [ - { - enum: ['never'], - }, - { - type: 'array', - items: { - enum: allMemberTypes, - }, - }, + neverConfig, + arrayConfig(allMemberTypes), + objectConfig(allMemberTypes), ], }, classExpressions: { oneOf: [ - { - enum: ['never'], - }, - { - type: 'array', - items: { - enum: allMemberTypes, - }, - }, + neverConfig, + arrayConfig(allMemberTypes), + objectConfig(allMemberTypes), ], }, interfaces: { oneOf: [ - { - enum: ['never'], - }, - { - type: 'array', - items: { - enum: ['signature', 'field', 'method', 'constructor'], - }, - }, + neverConfig, + arrayConfig(['signature', 'field', 'method', 'constructor']), + objectConfig(['signature', 'field', 'method', 'constructor']), ], }, typeLiterals: { oneOf: [ - { - enum: ['never'], - }, - { - type: 'array', - items: { - enum: ['signature', 'field', 'method', 'constructor'], - }, - }, + neverConfig, + arrayConfig(['signature', 'field', 'method', 'constructor']), + objectConfig(['signature', 'field', 'method', 'constructor']), ], }, }, @@ -130,263 +368,140 @@ export default util.createRule({ }, defaultOptions: [ { - default: [ - 'signature', - - 'public-static-field', - 'protected-static-field', - 'private-static-field', - - 'public-instance-field', - 'protected-instance-field', - 'private-instance-field', - - 'public-abstract-field', - 'protected-abstract-field', - 'private-abstract-field', - - 'public-field', - 'protected-field', - 'private-field', - - 'static-field', - 'instance-field', - 'abstract-field', - - 'field', - - 'constructor', - - 'public-static-method', - 'protected-static-method', - 'private-static-method', - - 'public-instance-method', - 'protected-instance-method', - 'private-instance-method', - - 'public-abstract-method', - 'protected-abstract-method', - 'private-abstract-method', - - 'public-method', - 'protected-method', - 'private-method', - - 'static-method', - 'instance-method', - 'abstract-method', - - 'method', - ], + default: defaultOrder, }, ], create(context, [options]) { - const sourceCode = context.getSourceCode(); - - const functionExpressions = [ - AST_NODE_TYPES.FunctionExpression, - AST_NODE_TYPES.ArrowFunctionExpression, - ]; - /** - * Gets the node type. - * @param node the node to be evaluated. - */ - function getNodeType( - node: TSESTree.ClassElement | TSESTree.TypeElement, - ): string | null { - // TODO: add missing TSCallSignatureDeclaration - switch (node.type) { - case AST_NODE_TYPES.TSAbstractMethodDefinition: - case AST_NODE_TYPES.MethodDefinition: - return node.kind; - case AST_NODE_TYPES.TSMethodSignature: - return 'method'; - case AST_NODE_TYPES.TSConstructSignatureDeclaration: - return 'constructor'; - case AST_NODE_TYPES.TSAbstractClassProperty: - case AST_NODE_TYPES.ClassProperty: - return node.value && functionExpressions.includes(node.value.type) - ? 'method' - : 'field'; - case AST_NODE_TYPES.TSPropertySignature: - return 'field'; - case AST_NODE_TYPES.TSIndexSignature: - return 'signature'; - default: - return null; - } - } - - /** - * Gets the member name based on the member type. - * @param node the node to be evaluated. - */ - function getMemberName( - node: TSESTree.ClassElement | TSESTree.TypeElement, - ): string | null { - switch (node.type) { - case AST_NODE_TYPES.TSPropertySignature: - case AST_NODE_TYPES.TSMethodSignature: - case AST_NODE_TYPES.TSAbstractClassProperty: - case AST_NODE_TYPES.ClassProperty: - return util.getNameFromMember(node, sourceCode); - case AST_NODE_TYPES.TSAbstractMethodDefinition: - case AST_NODE_TYPES.MethodDefinition: - return node.kind === 'constructor' - ? 'constructor' - : util.getNameFromMember(node, sourceCode); - case AST_NODE_TYPES.TSConstructSignatureDeclaration: - return 'new'; - case AST_NODE_TYPES.TSIndexSignature: - return util.getNameFromIndexSignature(node); - default: - return null; - } - } - - /** - * Gets the calculated rank using the provided method definition. - * The algorithm is as follows: - * - Get the rank based on the accessibility-scope-type name, e.g. public-instance-field - * - If there is no order for accessibility-scope-type, then strip out the accessibility. - * - If there is no order for scope-type, then strip out the scope. - * - If there is no order for type, then return -1 - * @param memberTypes the valid names to be validated. - * @param order the current order to be validated. + * Checks if the member groups are correctly sorted. * - * @return Index of the matching member type in the order configuration. - */ - function getRankOrder(memberTypes: string[], order: string[]): number { - let rank = -1; - const stack = memberTypes.slice(); // Get a copy of the member types - - while (stack.length > 0 && rank === -1) { - rank = order.indexOf(stack.shift()!); - } - - return rank; - } - - /** - * Gets the rank of the node given the order. - * @param node the node to be evaluated. - * @param order the current order to be validated. - * @param supportsModifiers a flag indicating whether the type supports modifiers (scope or accessibility) or not. + * @param members Members to be validated. + * @param groupOrder Group order to be validated. + * @param supportsModifiers A flag indicating whether the type supports modifiers (scope or accessibility) or not. + * + * @return Array of member groups or null if one of the groups is not correctly sorted. */ - function getRank( - node: TSESTree.ClassElement | TSESTree.TypeElement, - order: string[], + function checkGroupSort( + members: Member[], + groupOrder: string[], supportsModifiers: boolean, - ): number { - const type = getNodeType(node); - if (type === null) { - // shouldn't happen but just in case, put it on the end - return order.length - 1; - } - - const abstract = - node.type === AST_NODE_TYPES.TSAbstractClassProperty || - node.type === AST_NODE_TYPES.TSAbstractMethodDefinition; - - const scope = - 'static' in node && node.static - ? 'static' - : abstract - ? 'abstract' - : 'instance'; - const accessibility = - 'accessibility' in node && node.accessibility - ? node.accessibility - : 'public'; - - const memberTypes = []; - - if (supportsModifiers) { - if (type !== 'constructor') { - // Constructors have no scope - memberTypes.push(`${accessibility}-${scope}-${type}`); - memberTypes.push(`${scope}-${type}`); + ): Array | null { + const previousRanks: number[] = []; + const memberGroups: Array = []; + let isCorrectlySorted = true; + + // Find first member which isn't correctly sorted + members.forEach(member => { + const rank = getRank(member, groupOrder, supportsModifiers); + const name = getMemberName(member, context.getSourceCode()); + const rankLastMember = previousRanks[previousRanks.length - 1]; + + if (rank !== -1) { + // Works for 1st item because x < undefined === false for any x (typeof string) + if (rank < rankLastMember) { + context.report({ + node: member, + messageId: 'incorrectGroupOrder', + data: { + name, + rank: getLowestRank(previousRanks, rank, groupOrder), + }, + }); + + isCorrectlySorted = false; + } else if (rank === rankLastMember) { + // Same member group --> Push to existing member group array + memberGroups[memberGroups.length - 1].push(member); + } else { + // New member group --> Create new member group array + previousRanks.push(rank); + memberGroups.push([member]); + } } + }); - memberTypes.push(`${accessibility}-${type}`); - } - - memberTypes.push(type); - - return getRankOrder(memberTypes, order); + return isCorrectlySorted ? memberGroups : null; } /** - * Gets the lowest possible rank higher than target. - * e.g. given the following order: - * ... - * public-static-method - * protected-static-method - * private-static-method - * public-instance-method - * protected-instance-method - * private-instance-method - * ... - * and considering that a public-instance-method has already been declared, so ranks contains - * public-instance-method, then the lowest possible rank for public-static-method is - * public-instance-method. - * @param ranks the existing ranks in the object. - * @param target the target rank. - * @param order the current order to be validated. - * @returns the name of the lowest possible rank without dashes (-). + * Checks if the members are alphabetically sorted. + * + * @param members Members to be validated. + * + * @return True if all members are correctly sorted. */ - function getLowestRank( - ranks: number[], - target: number, - order: string[], - ): string { - let lowest = ranks[ranks.length - 1]; - - ranks.forEach(rank => { - if (rank > target) { - lowest = Math.min(lowest, rank); + function checkAlphaSort(members: Member[]): boolean { + let previousName = ''; + let isCorrectlySorted = true; + + // Find first member which isn't correctly sorted + members.forEach(member => { + const name = getMemberName(member, context.getSourceCode()); + + // Note: Not all members have names + if (name) { + if (name < previousName) { + context.report({ + node: member, + messageId: 'incorrectOrder', + data: { + member: name, + beforeMember: previousName, + }, + }); + + isCorrectlySorted = false; + } + + previousName = name; } }); - return order[lowest].replace(/-/g, ' '); + return isCorrectlySorted; } /** * Validates if all members are correctly sorted. * * @param members Members to be validated. - * @param order Current order to be validated. + * @param orderConfig Order config to be validated. * @param supportsModifiers A flag indicating whether the type supports modifiers (scope or accessibility) or not. */ function validateMembersOrder( - members: (TSESTree.ClassElement | TSESTree.TypeElement)[], - order: OrderConfig, + members: Member[], + orderConfig: OrderConfig, supportsModifiers: boolean, ): void { - if (members && order !== 'never') { - const previousRanks: number[] = []; - - // Find first member which isn't correctly sorted - members.forEach(member => { - const rank = getRank(member, order, supportsModifiers); - - if (rank !== -1) { - if (rank < previousRanks[previousRanks.length - 1]) { - context.report({ - node: member, - messageId: 'incorrectOrder', - data: { - name: getMemberName(member), - rank: getLowestRank(previousRanks, rank, order), - }, - }); - } else { - previousRanks.push(rank); - } + if (orderConfig !== 'never') { + // Standardize config + let order = null; + let memberTypes; + + if (Array.isArray(orderConfig)) { + memberTypes = orderConfig; + } else { + order = orderConfig.order; + memberTypes = orderConfig.memberTypes; + } + + // Check order + if (Array.isArray(memberTypes)) { + const grouped = checkGroupSort( + members, + memberTypes, + supportsModifiers, + ); + + if (grouped === null) { + return; } - }); + + if (order === 'alphabetically') { + grouped.some(groupMember => !checkAlphaSort(groupMember)); + } + } else if (order === 'alphabetically') { + checkAlphaSort(members); + } } } diff --git a/packages/eslint-plugin/src/rules/method-signature-style.ts b/packages/eslint-plugin/src/rules/method-signature-style.ts new file mode 100644 index 000000000000..6ef8db5a0c9b --- /dev/null +++ b/packages/eslint-plugin/src/rules/method-signature-style.ts @@ -0,0 +1,124 @@ +import { + AST_NODE_TYPES, + TSESTree, +} from '@typescript-eslint/experimental-utils'; +import * as util from '../util'; + +export type Options = ['property' | 'method']; + +export type MessageId = 'errorMethod' | 'errorProperty'; + +export default util.createRule({ + name: 'method-signature-style', + meta: { + type: 'suggestion', + docs: { + description: 'Enforces using a particular method signature syntax.', + category: 'Best Practices', + recommended: false, + }, + fixable: 'code', + messages: { + errorMethod: + 'Shorthand method signature is forbidden. Use a function property instead.', + errorProperty: + 'Function property signature is forbidden. Use a method shorthand instead.', + }, + schema: [ + { + enum: ['property', 'method'], + }, + ], + }, + defaultOptions: ['property'], + + create(context, [mode]) { + const sourceCode = context.getSourceCode(); + + function getMethodKey( + node: TSESTree.TSMethodSignature | TSESTree.TSPropertySignature, + ): string { + let key = sourceCode.getText(node.key); + if (node.computed) { + key = `[${key}]`; + } + if (node.optional) { + key = `${key}?`; + } + if (node.readonly) { + key = `readonly ${key}`; + } + return key; + } + + function getMethodParams( + node: TSESTree.TSMethodSignature | TSESTree.TSFunctionType, + ): string { + let params = '()'; + if (node.params.length > 0) { + params = sourceCode.text.substring( + sourceCode.getTokenBefore(node.params[0])!.range[0], + sourceCode.getTokenAfter(node.params[node.params.length - 1])! + .range[1], + ); + } + if (node.typeParameters != null) { + const typeParams = sourceCode.getText(node.typeParameters); + params = `${typeParams}${params}`; + } + return params; + } + + function getMethodReturnType( + node: TSESTree.TSMethodSignature | TSESTree.TSFunctionType, + ): string { + return sourceCode.getText(node.returnType!.typeAnnotation); + } + + return { + TSMethodSignature(methodNode): void { + if (mode === 'method') { + return; + } + + context.report({ + node: methodNode, + messageId: 'errorMethod', + fix: fixer => { + const key = getMethodKey(methodNode); + const params = getMethodParams(methodNode); + const returnType = getMethodReturnType(methodNode); + return fixer.replaceText( + methodNode, + `${key}: ${params} => ${returnType}`, + ); + }, + }); + }, + TSPropertySignature(propertyNode): void { + const typeNode = propertyNode.typeAnnotation?.typeAnnotation; + if (typeNode?.type !== AST_NODE_TYPES.TSFunctionType) { + return; + } + + if (mode === 'property') { + return; + } + + context.report({ + node: propertyNode, + messageId: 'errorProperty', + fix: fixer => { + const key = getMethodKey(propertyNode); + const params = getMethodParams(typeNode); + const returnType = getMethodReturnType(typeNode); + return fixer.replaceText( + propertyNode, + `${key}${params}: ${returnType}`, + ); + }, + }); + }, + }; + }, +}); diff --git a/packages/eslint-plugin/src/rules/no-explicit-any.ts b/packages/eslint-plugin/src/rules/no-explicit-any.ts index 91765c40e262..795dae017253 100644 --- a/packages/eslint-plugin/src/rules/no-explicit-any.ts +++ b/packages/eslint-plugin/src/rules/no-explicit-any.ts @@ -53,18 +53,23 @@ export default util.createRule({ ], create(context, [{ ignoreRestArgs, fixToUnknown }]) { /** - * Checks if the node is an arrow function, function declaration or function expression + * Checks if the node is an arrow function, function/constructor declaration or function expression * @param node the node to be validated. - * @returns true if the node is an arrow function, function declaration, function expression, function type, or call signature + * @returns true if the node is any kind of function declaration or expression * @private */ function isNodeValidFunction(node: TSESTree.Node): boolean { return [ - AST_NODE_TYPES.ArrowFunctionExpression, - AST_NODE_TYPES.FunctionDeclaration, - AST_NODE_TYPES.FunctionExpression, - AST_NODE_TYPES.TSFunctionType, - AST_NODE_TYPES.TSCallSignatureDeclaration, + AST_NODE_TYPES.ArrowFunctionExpression, // const x = (...args: any[]) => {}; + AST_NODE_TYPES.FunctionDeclaration, // function f(...args: any[]) {} + AST_NODE_TYPES.FunctionExpression, // const x = function(...args: any[]) {}; + AST_NODE_TYPES.TSEmptyBodyFunctionExpression, // declare class A { f(...args: any[]): unknown; } + AST_NODE_TYPES.TSFunctionType, // type T = (...args: any[]) => unknown; + AST_NODE_TYPES.TSConstructorType, // type T = new (...args: any[]) => unknown + AST_NODE_TYPES.TSCallSignatureDeclaration, // type T = {(...args: any[]): unknown}; + AST_NODE_TYPES.TSConstructSignatureDeclaration, // type T = {new (...args: any[]): unknown}; + AST_NODE_TYPES.TSMethodSignature, // type T = {f(...args: any[]): unknown}; + AST_NODE_TYPES.TSDeclareFunction, // declare function _8(...args: any[]): unknown; ].includes(node.type); } diff --git a/packages/eslint-plugin/src/rules/no-throw-literal.ts b/packages/eslint-plugin/src/rules/no-throw-literal.ts index c8c5bcc1837f..ffa8a614e6b6 100644 --- a/packages/eslint-plugin/src/rules/no-throw-literal.ts +++ b/packages/eslint-plugin/src/rules/no-throw-literal.ts @@ -43,10 +43,11 @@ export default util.createRule({ } } - const baseTypes = checker.getBaseTypes(type as ts.InterfaceType); - for (const baseType of baseTypes) { - if (isErrorLike(baseType)) { - return true; + if (symbol.flags & (ts.SymbolFlags.Class | ts.SymbolFlags.Interface)) { + for (const baseType of checker.getBaseTypes(type as ts.InterfaceType)) { + if (isErrorLike(baseType)) { + return true; + } } } diff --git a/packages/eslint-plugin/src/rules/no-unsafe-call.ts b/packages/eslint-plugin/src/rules/no-unsafe-call.ts index 13cabc87d924..66f66448c28b 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-call.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-call.ts @@ -41,7 +41,7 @@ export default util.createRule<[], MessageIds>({ } return { - ':matches(CallExpression, OptionalCallExpression) > :not(Import)'( + ':matches(CallExpression, OptionalCallExpression) > :not(Import).callee'( node: Exclude, ): void { checkCall(node, node, 'unsafeCall'); diff --git a/packages/eslint-plugin/src/rules/require-await.ts b/packages/eslint-plugin/src/rules/require-await.ts index e7b6a5f5959a..99c455cd0f6a 100644 --- a/packages/eslint-plugin/src/rules/require-await.ts +++ b/packages/eslint-plugin/src/rules/require-await.ts @@ -11,6 +11,8 @@ interface ScopeInfo { upper: ScopeInfo | null; hasAwait: boolean; hasAsync: boolean; + isGen: boolean; + isAsyncYield: boolean; } type FunctionNode = | TSESTree.FunctionDeclaration @@ -49,6 +51,8 @@ export default util.createRule({ upper: scopeInfo, hasAwait: false, hasAsync: node.async, + isGen: node.generator || false, + isAsyncYield: false, }; } @@ -62,7 +66,12 @@ export default util.createRule({ return; } - if (node.async && !scopeInfo.hasAwait && !isEmptyFunction(node)) { + if ( + node.async && + !scopeInfo.hasAwait && + !isEmptyFunction(node) && + !(scopeInfo.isGen && scopeInfo.isAsyncYield) + ) { context.report({ node, loc: getFunctionHeadLoc(node, sourceCode), @@ -92,10 +101,34 @@ export default util.createRule({ if (!scopeInfo) { return; } - scopeInfo.hasAwait = true; } + /** + * mark `scopeInfo.isAsyncYield` to `true` if its a generator + * function and the delegate is `true` + */ + function markAsHasDelegateGen(node: TSESTree.YieldExpression): void { + if (!scopeInfo || !scopeInfo.isGen || !node.argument) { + return; + } + + if (node?.argument?.type === AST_NODE_TYPES.Literal) { + // making this `false` as for literals we don't need to check the definition + // eg : async function* run() { yield* 1 } + scopeInfo.isAsyncYield = false; + } + + const tsNode = parserServices.esTreeNodeToTSNodeMap.get(node?.argument); + const type = checker.getTypeAtLocation(tsNode); + const symbol = type.getSymbol(); + + // async function* test1() {yield* asyncGenerator() } + if (symbol?.getName() === 'AsyncGenerator') { + scopeInfo.isAsyncYield = true; + } + } + return { FunctionDeclaration: enterFunction, FunctionExpression: enterFunction, @@ -106,6 +139,7 @@ export default util.createRule({ AwaitExpression: markAsHasAwait, 'ForOfStatement[await = true]': markAsHasAwait, + 'YieldExpression[delegate = true]': markAsHasDelegateGen, // check body-less async arrow function. // ignore `async () => await foo` because it's obviously correct diff --git a/packages/eslint-plugin/tests/RuleTester.ts b/packages/eslint-plugin/tests/RuleTester.ts index c650c83449c4..1774200db322 100644 --- a/packages/eslint-plugin/tests/RuleTester.ts +++ b/packages/eslint-plugin/tests/RuleTester.ts @@ -89,4 +89,16 @@ afterAll(() => { clearCaches(); }); -export { RuleTester, getFixturesRootDir, batchedSingleLineTests }; +/** + * Simple no-op tag to mark code samples as "should not format with prettier" + * for the internal/plugin-test-formatting lint rule + */ +function noFormat(strings: TemplateStringsArray, ...keys: string[]): string { + const lastIndex = strings.length - 1; + return ( + strings.slice(0, lastIndex).reduce((p, s, i) => p + s + keys[i], '') + + strings[lastIndex] + ); +} + +export { batchedSingleLineTests, getFixturesRootDir, noFormat, RuleTester }; diff --git a/packages/eslint-plugin/tests/rules/adjacent-overload-signatures.test.ts b/packages/eslint-plugin/tests/rules/adjacent-overload-signatures.test.ts index c040362a1286..8e844bb96bef 100644 --- a/packages/eslint-plugin/tests/rules/adjacent-overload-signatures.test.ts +++ b/packages/eslint-plugin/tests/rules/adjacent-overload-signatures.test.ts @@ -11,217 +11,224 @@ ruleTester.run('adjacent-overload-signatures', rule, { code: ` function error(a: string); function error(b: number); -function error(ab: string|number){ } +function error(ab: string | number) {} export { error }; - `, + `, parserOptions: { sourceType: 'module' }, }, { code: ` import { connect } from 'react-redux'; -export interface ErrorMessageModel { message: string; } -function mapStateToProps() { } -function mapDispatchToProps() { } +export interface ErrorMessageModel { + message: string; +} +function mapStateToProps() {} +function mapDispatchToProps() {} export default connect(mapStateToProps, mapDispatchToProps)(ErrorMessage); - `, + `, parserOptions: { sourceType: 'module' }, }, ` -export const foo = "a", bar = "b"; +export const foo = 'a', + bar = 'b'; export interface Foo {} export class Foo {} - `, + `, ` export interface Foo {} -export const foo = "a", bar = "b"; +export const foo = 'a', + bar = 'b'; export class Foo {} - `, + `, ` -const foo = "a", bar = "b"; +const foo = 'a', + bar = 'b'; interface Foo {} class Foo {} - `, + `, ` interface Foo {} -const foo = "a", bar = "b"; +const foo = 'a', + bar = 'b'; class Foo {} - `, + `, ` export class Foo {} export class Bar {} export type FooBar = Foo | Bar; - `, + `, ` export interface Foo {} export class Foo {} export class Bar {} export type FooBar = Foo | Bar; - `, + `, ` export function foo(s: string); export function foo(n: number); export function foo(sn: string | number) {} export function bar(): void {} export function baz(): void {} - `, + `, ` function foo(s: string); function foo(n: number); function foo(sn: string | number) {} function bar(): void {} function baz(): void {} - `, + `, ` declare function foo(s: string); declare function foo(n: number); declare function foo(sn: string | number); declare function bar(): void; declare function baz(): void; - `, + `, ` -declare module "Foo" { - export function foo(s: string): void; - export function foo(n: number): void; - export function foo(sn: string | number): void; - export function bar(): void; - export function baz(): void; -} - `, +declare module 'Foo' { + export function foo(s: string): void; + export function foo(n: number): void; + export function foo(sn: string | number): void; + export function bar(): void; + export function baz(): void; +} + `, ` declare namespace Foo { - export function foo(s: string): void; - export function foo(n: number): void; - export function foo(sn: string | number): void; - export function bar(): void; - export function baz(): void; + export function foo(s: string): void; + export function foo(n: number): void; + export function foo(sn: string | number): void; + export function bar(): void; + export function baz(): void; } - `, + `, ` type Foo = { - foo(s: string): void; - foo(n: number): void; - foo(sn: string | number): void; - bar(): void; - baz(): void; -} - `, + foo(s: string): void; + foo(n: number): void; + foo(sn: string | number): void; + bar(): void; + baz(): void; +}; + `, ` type Foo = { - foo(s: string): void; - ["foo"](n: number): void; - foo(sn: string | number): void; - bar(): void; - baz(): void; -} - `, + foo(s: string): void; + ['foo'](n: number): void; + foo(sn: string | number): void; + bar(): void; + baz(): void; +}; + `, ` interface Foo { - (s: string): void; - (n: number): void; - (sn: string | number): void; - foo(n: number): void; - bar(): void; - baz(): void; -} - `, + (s: string): void; + (n: number): void; + (sn: string | number): void; + foo(n: number): void; + bar(): void; + baz(): void; +} + `, ` interface Foo { - foo(s: string): void; - foo(n: number): void; - foo(sn: string | number): void; - bar(): void; - baz(): void; + foo(s: string): void; + foo(n: number): void; + foo(sn: string | number): void; + bar(): void; + baz(): void; } - `, + `, ` interface Foo { - foo(s: string): void; - ["foo"](n: number): void; - foo(sn: string | number): void; - bar(): void; - baz(): void; + foo(s: string): void; + ['foo'](n: number): void; + foo(sn: string | number): void; + bar(): void; + baz(): void; } - `, + `, ` interface Foo { - foo(): void; - bar: { - baz(s: string): void; - baz(n: number): void; - baz(sn: string | number): void; - } -} - `, + foo(): void; + bar: { + baz(s: string): void; + baz(n: number): void; + baz(sn: string | number): void; + }; +} + `, ` interface Foo { - new(s: string); - new(n: number); - new(sn: string | number); - foo(): void; + new (s: string); + new (n: number); + new (sn: string | number); + foo(): void; } - `, + `, ` class Foo { - constructor(s: string); - constructor(n: number); - constructor(sn: string | number) {} - bar(): void {} - baz(): void {} + constructor(s: string); + constructor(n: number); + constructor(sn: string | number) {} + bar(): void {} + baz(): void {} } - `, + `, ` class Foo { - foo(s: string): void; - foo(n: number): void; - foo(sn: string | number): void {} - bar(): void {} - baz(): void {} + foo(s: string): void; + foo(n: number): void; + foo(sn: string | number): void {} + bar(): void {} + baz(): void {} } - `, + `, ` class Foo { - foo(s: string): void; - ["foo"](n: number): void; - foo(sn: string | number): void {} - bar(): void {} - baz(): void {} + foo(s: string): void; + ['foo'](n: number): void; + foo(sn: string | number): void {} + bar(): void {} + baz(): void {} } - `, + `, ` class Foo { - name: string; - foo(s: string): void; - foo(n: number): void; - foo(sn: string | number): void {} - bar(): void {} - baz(): void {} -} - `, + name: string; + foo(s: string): void; + foo(n: number): void; + foo(sn: string | number): void {} + bar(): void {} + baz(): void {} +} + `, ` class Foo { - name: string; - static foo(s: string): void; - static foo(n: number): void; - static foo(sn: string | number): void {} - bar(): void {} - baz(): void {} -} - `, + name: string; + static foo(s: string): void; + static foo(n: number): void; + static foo(sn: string | number): void {} + bar(): void {} + baz(): void {} +} + `, ` class Test { static test() {} untest() {} test() {} } - `, + `, // examples from https://github.com/nzakas/eslint-plugin-typescript/issues/138 - 'export default function(foo : T) {}', - 'export default function named(foo : T) {}', + 'export default function(foo: T) {}', + 'export default function named(foo: T) {}', ` interface Foo { [Symbol.toStringTag](): void; [Symbol.iterator](): void; -}`, +} + `, ], invalid: [ { @@ -231,7 +238,7 @@ export function foo(n: number); export function bar(): void {} export function baz(): void {} export function foo(sn: string | number) {} - `, + `, errors: [ { messageId: 'adjacentSignature', @@ -248,7 +255,7 @@ export function foo(n: number); export type bar = number; export type baz = number | string; export function foo(sn: string | number) {} - `, + `, errors: [ { messageId: 'adjacentSignature', @@ -265,7 +272,7 @@ function foo(n: number); function bar(): void {} function baz(): void {} function foo(sn: string | number) {} - `, + `, errors: [ { messageId: 'adjacentSignature', @@ -282,7 +289,7 @@ function foo(n: number); type bar = number; type baz = number | string; function foo(sn: string | number) {} - `, + `, errors: [ { messageId: 'adjacentSignature', @@ -296,10 +303,10 @@ function foo(sn: string | number) {} code: ` function foo(s: string) {} function foo(n: number) {} -const a = ""; -const b = ""; +const a = ''; +const b = ''; function foo(sn: string | number) {} - `, + `, errors: [ { messageId: 'adjacentSignature', @@ -315,7 +322,7 @@ function foo(s: string) {} function foo(n: number) {} class Bar {} function foo(sn: string | number) {} - `, + `, errors: [ { messageId: 'adjacentSignature', @@ -331,18 +338,18 @@ function foo(s: string) {} function foo(n: number) {} function foo(sn: string | number) {} class Bar { - foo(s: string); - foo(n: number); - name: string; - foo(sn: string | number) { } + foo(s: string); + foo(n: number); + name: string; + foo(sn: string | number) {} } - `, + `, errors: [ { messageId: 'adjacentSignature', data: { name: 'foo' }, line: 9, - column: 5, + column: 3, }, ], }, @@ -353,7 +360,7 @@ declare function foo(n: number); declare function bar(): void; declare function baz(): void; declare function foo(sn: string | number); - `, + `, errors: [ { messageId: 'adjacentSignature', @@ -367,10 +374,10 @@ declare function foo(sn: string | number); code: ` declare function foo(s: string); declare function foo(n: number); -const a = ""; -const b = ""; +const a = ''; +const b = ''; declare function foo(sn: string | number); - `, + `, errors: [ { messageId: 'adjacentSignature', @@ -382,437 +389,438 @@ declare function foo(sn: string | number); }, { code: ` -declare module "Foo" { - export function foo(s: string): void; - export function foo(n: number): void; - export function bar(): void; - export function baz(): void; - export function foo(sn: string | number): void; +declare module 'Foo' { + export function foo(s: string): void; + export function foo(n: number): void; + export function bar(): void; + export function baz(): void; + export function foo(sn: string | number): void; } - `, + `, errors: [ { messageId: 'adjacentSignature', data: { name: 'foo' }, line: 7, - column: 5, + column: 3, }, ], }, { code: ` -declare module "Foo" { - export function foo(s: string): void; - export function foo(n: number): void; - export function foo(sn: string | number): void; - function baz(s: string): void; - export function bar(): void; - function baz(n: number): void; - function baz(sn: string | number): void; +declare module 'Foo' { + export function foo(s: string): void; + export function foo(n: number): void; + export function foo(sn: string | number): void; + function baz(s: string): void; + export function bar(): void; + function baz(n: number): void; + function baz(sn: string | number): void; } - `, + `, errors: [ { messageId: 'adjacentSignature', data: { name: 'baz' }, line: 8, - column: 5, + column: 3, }, ], }, { code: ` declare namespace Foo { - export function foo(s: string): void; - export function foo(n: number): void; - export function bar(): void; - export function baz(): void; - export function foo(sn: string | number): void; + export function foo(s: string): void; + export function foo(n: number): void; + export function bar(): void; + export function baz(): void; + export function foo(sn: string | number): void; } - `, + `, errors: [ { messageId: 'adjacentSignature', data: { name: 'foo' }, line: 7, - column: 5, + column: 3, }, ], }, { code: ` declare namespace Foo { - export function foo(s: string): void; - export function foo(n: number): void; - export function foo(sn: string | number): void; - function baz(s: string): void; - export function bar(): void; - function baz(n: number): void; - function baz(sn: string | number): void; -} - `, + export function foo(s: string): void; + export function foo(n: number): void; + export function foo(sn: string | number): void; + function baz(s: string): void; + export function bar(): void; + function baz(n: number): void; + function baz(sn: string | number): void; +} + `, errors: [ { messageId: 'adjacentSignature', data: { name: 'baz' }, line: 8, - column: 5, + column: 3, }, ], }, { code: ` type Foo = { - foo(s: string): void; - foo(n: number): void; - bar(): void; - baz(): void; - foo(sn: string | number): void; -} - `, + foo(s: string): void; + foo(n: number): void; + bar(): void; + baz(): void; + foo(sn: string | number): void; +}; + `, errors: [ { messageId: 'adjacentSignature', data: { name: 'foo' }, line: 7, - column: 5, + column: 3, }, ], }, { code: ` type Foo = { - foo(s: string): void; - ["foo"](n: number): void; - bar(): void; - baz(): void; - foo(sn: string | number): void; -} - `, + foo(s: string): void; + ['foo'](n: number): void; + bar(): void; + baz(): void; + foo(sn: string | number): void; +}; + `, errors: [ { messageId: 'adjacentSignature', data: { name: 'foo' }, line: 7, - column: 5, + column: 3, }, ], }, { code: ` type Foo = { - foo(s: string): void; - name: string; - foo(n: number): void; - foo(sn: string | number): void; - bar(): void; - baz(): void; -} - `, + foo(s: string): void; + name: string; + foo(n: number): void; + foo(sn: string | number): void; + bar(): void; + baz(): void; +}; + `, errors: [ { messageId: 'adjacentSignature', data: { name: 'foo' }, line: 5, - column: 5, + column: 3, }, ], }, { code: ` interface Foo { - (s: string): void; - foo(n: number): void; - (n: number): void; - (sn: string | number): void; - bar(): void; - baz(): void; -} - `, + (s: string): void; + foo(n: number): void; + (n: number): void; + (sn: string | number): void; + bar(): void; + baz(): void; +} + `, errors: [ { messageId: 'adjacentSignature', data: { name: 'call' }, line: 5, - column: 5, + column: 3, }, ], }, { code: ` interface Foo { - foo(s: string): void; - foo(n: number): void; - bar(): void; - baz(): void; - foo(sn: string | number): void; + foo(s: string): void; + foo(n: number): void; + bar(): void; + baz(): void; + foo(sn: string | number): void; } - `, + `, errors: [ { messageId: 'adjacentSignature', data: { name: 'foo' }, line: 7, - column: 5, + column: 3, }, ], }, { code: ` interface Foo { - foo(s: string): void; - ["foo"](n: number): void; - bar(): void; - baz(): void; - foo(sn: string | number): void; + foo(s: string): void; + ['foo'](n: number): void; + bar(): void; + baz(): void; + foo(sn: string | number): void; } - `, + `, errors: [ { messageId: 'adjacentSignature', data: { name: 'foo' }, line: 7, - column: 5, + column: 3, }, ], }, { code: ` interface Foo { - foo(s: string): void; - "foo"(n: number): void; - bar(): void; - baz(): void; - foo(sn: string | number): void; + foo(s: string): void; + 'foo'(n: number): void; + bar(): void; + baz(): void; + foo(sn: string | number): void; } - `, + `, errors: [ { messageId: 'adjacentSignature', data: { name: 'foo' }, line: 7, - column: 5, + column: 3, }, ], }, { code: ` interface Foo { - foo(s: string): void; - name: string; - foo(n: number): void; - foo(sn: string | number): void; - bar(): void; - baz(): void; -} - `, + foo(s: string): void; + name: string; + foo(n: number): void; + foo(sn: string | number): void; + bar(): void; + baz(): void; +} + `, errors: [ { messageId: 'adjacentSignature', data: { name: 'foo' }, line: 5, - column: 5, + column: 3, }, ], }, { code: ` interface Foo { + foo(): void; + bar: { + baz(s: string): void; + baz(n: number): void; foo(): void; - bar: { - baz(s: string): void; - baz(n: number): void; - foo(): void; - baz(sn: string | number): void; - } -} - `, + baz(sn: string | number): void; + }; +} + `, errors: [ { messageId: 'adjacentSignature', data: { name: 'baz' }, line: 8, - column: 9, + column: 5, }, ], }, { code: ` interface Foo { - new(s: string); - new(n: number); - foo(): void; - bar(): void; - new(sn: string | number); + new (s: string); + new (n: number); + foo(): void; + bar(): void; + new (sn: string | number); } - `, + `, errors: [ { messageId: 'adjacentSignature', data: { name: 'new' }, line: 7, - column: 5, + column: 3, }, ], }, { code: ` interface Foo { - new(s: string); - foo(): void; - new(n: number); - bar(): void; - new(sn: string | number); + new (s: string); + foo(): void; + new (n: number); + bar(): void; + new (sn: string | number); } - `, + `, errors: [ { messageId: 'adjacentSignature', data: { name: 'new' }, line: 5, - column: 5, + column: 3, }, { messageId: 'adjacentSignature', data: { name: 'new' }, line: 7, - column: 5, + column: 3, }, ], }, { code: ` class Foo { - constructor(s: string); - constructor(n: number); - bar(): void {} - baz(): void {} - constructor(sn: string | number) {} + constructor(s: string); + constructor(n: number); + bar(): void {} + baz(): void {} + constructor(sn: string | number) {} } - `, + `, errors: [ { messageId: 'adjacentSignature', data: { name: 'constructor' }, line: 7, - column: 5, + column: 3, }, ], }, { code: ` class Foo { - foo(s: string): void; - foo(n: number): void; - bar(): void {} - baz(): void {} - foo(sn: string | number): void {} + foo(s: string): void; + foo(n: number): void; + bar(): void {} + baz(): void {} + foo(sn: string | number): void {} } - `, + `, errors: [ { messageId: 'adjacentSignature', data: { name: 'foo' }, line: 7, - column: 5, + column: 3, }, ], }, { code: ` class Foo { - foo(s: string): void; - ["foo"](n: number): void; - bar(): void {} - baz(): void {} - foo(sn: string | number): void {} + foo(s: string): void; + ['foo'](n: number): void; + bar(): void {} + baz(): void {} + foo(sn: string | number): void {} } - `, + `, errors: [ { messageId: 'adjacentSignature', data: { name: 'foo' }, line: 7, - column: 5, + column: 3, }, ], }, { code: ` class Foo { - foo(s: string): void; - "foo"(n: number): void; - bar(): void {} - baz(): void {} - foo(sn: string | number): void {} -} - `, + // prettier-ignore + "foo"(s: string): void; + foo(n: number): void; + bar(): void {} + baz(): void {} + foo(sn: string | number): void {} +} + `, errors: [ { messageId: 'adjacentSignature', data: { name: 'foo' }, - line: 7, - column: 5, + line: 8, + column: 3, }, ], }, { code: ` class Foo { - constructor(s: string); - name: string; - constructor(n: number); - constructor(sn: string | number) {} - bar(): void {} - baz(): void {} -} - `, + constructor(s: string); + name: string; + constructor(n: number); + constructor(sn: string | number) {} + bar(): void {} + baz(): void {} +} + `, errors: [ { messageId: 'adjacentSignature', data: { name: 'constructor' }, line: 5, - column: 5, + column: 3, }, ], }, { code: ` class Foo { - foo(s: string): void; - name: string; - foo(n: number): void; - foo(sn: string | number): void {} - bar(): void {} - baz(): void {} -} - `, + foo(s: string): void; + name: string; + foo(n: number): void; + foo(sn: string | number): void {} + bar(): void {} + baz(): void {} +} + `, errors: [ { messageId: 'adjacentSignature', data: { name: 'foo' }, line: 5, - column: 5, + column: 3, }, ], }, { code: ` class Foo { - static foo(s: string): void; - name: string; - static foo(n: number): void; - static foo(sn: string | number): void {} - bar(): void {} - baz(): void {} -} - `, + static foo(s: string): void; + name: string; + static foo(n: number): void; + static foo(sn: string | number): void {} + bar(): void {} + baz(): void {} +} + `, errors: [ { messageId: 'adjacentSignature', data: { name: 'static foo' }, line: 5, - column: 5, + column: 3, }, ], }, diff --git a/packages/eslint-plugin/tests/rules/array-type.test.ts b/packages/eslint-plugin/tests/rules/array-type.test.ts index b74c06c09fd1..5f15ba5e8220 100644 --- a/packages/eslint-plugin/tests/rules/array-type.test.ts +++ b/packages/eslint-plugin/tests/rules/array-type.test.ts @@ -10,35 +10,35 @@ const ruleTester = new RuleTester({ ruleTester.run('array-type', rule, { valid: [ { - code: 'let a: readonly any[] = []', + code: 'let a: readonly any[] = [];', options: [{ default: 'array' }], }, { - code: 'let a = new Array()', + code: 'let a = new Array();', options: [{ default: 'array' }], }, { - code: 'let a: string[] = []', + code: 'let a: string[] = [];', options: [{ default: 'array' }], }, { - code: 'let a: (string | number)[] = []', + code: 'let a: (string | number)[] = [];', options: [{ default: 'array' }], }, { - code: 'let a: ({ foo: Bar[] })[] = []', + code: 'let a: { foo: Bar[] }[] = [];', options: [{ default: 'array' }], }, { - code: 'let a: Array = []', + code: 'let a: Array = [];', options: [{ default: 'generic' }], }, { - code: 'let a: Array = []', + code: 'let a: Array = [];', options: [{ default: 'generic' }], }, { - code: 'let a: Array<{ foo: Array }> = []', + code: 'let a: Array<{ foo: Array }> = [];', options: [{ default: 'generic' }], }, { @@ -46,7 +46,7 @@ ruleTester.run('array-type', rule, { options: [{ default: 'generic' }], }, { - code: 'function foo (a: Array): Array {}', + code: 'function foo(a: Array): Array {}', options: [{ default: 'generic' }], }, { @@ -54,15 +54,19 @@ ruleTester.run('array-type', rule, { options: [{ default: 'array-simple' }], }, { - code: `function fooFunction(foo: Array>) { - return foo.map(e => e.foo); -}`, + code: ` +function fooFunction(foo: Array>) { + return foo.map(e => e.foo); +} + `, options: [{ default: 'array-simple' }], }, { - code: `function bazFunction(baz: Arr>) { - return baz.map(e => e.baz); -}`, + code: ` +function bazFunction(baz: Arr>) { + return baz.map(e => e.baz); +} + `, options: [{ default: 'array-simple' }], }, { @@ -78,16 +82,20 @@ ruleTester.run('array-type', rule, { options: [{ default: 'array-simple' }], }, { - code: `namespace fooName { - type BarType = { bar: string }; - type BazType = Arr; -}`, + code: ` +namespace fooName { + type BarType = { bar: string }; + type BazType = Arr; +} + `, options: [{ default: 'array-simple' }], }, { - code: `interface FooInterface { - '.bar': {baz: string[];}; -}`, + code: ` +interface FooInterface { + '.bar': { baz: string[] }; +} + `, options: [{ default: 'array-simple' }], }, { @@ -95,19 +103,23 @@ ruleTester.run('array-type', rule, { options: [{ default: 'array' }], }, { - code: 'let ya = [[1, "2"]] as[number, string][];', + code: "let ya = [[1, '2']] as [number, string][];", options: [{ default: 'array' }], }, { - code: `function barFunction(bar: ArrayClass[]) { - return bar.map(e => e.bar); -}`, + code: ` +function barFunction(bar: ArrayClass[]) { + return bar.map(e => e.bar); +} + `, options: [{ default: 'array' }], }, { - code: `function bazFunction(baz: Arr>) { - return baz.map(e => e.baz); -}`, + code: ` +function bazFunction(baz: Arr>) { + return baz.map(e => e.baz); +} + `, options: [{ default: 'array' }], }, { @@ -115,7 +127,7 @@ ruleTester.run('array-type', rule, { options: [{ default: 'array' }], }, { - code: 'type barUnion = (string|number|boolean)[];', + code: 'type barUnion = (string | number | boolean)[];', options: [{ default: 'array' }], }, { @@ -123,18 +135,20 @@ ruleTester.run('array-type', rule, { options: [{ default: 'array' }], }, { - code: `interface FooInterface { - '.bar': {baz: string[];}; -}`, + code: ` +interface FooInterface { + '.bar': { baz: string[] }; +} + `, options: [{ default: 'array' }], }, { // https://github.com/typescript-eslint/typescript-eslint/issues/172 - code: 'type Unwrap = T extends (infer E)[] ? E : T', + code: 'type Unwrap = T extends (infer E)[] ? E : T;', options: [{ default: 'array' }], }, { - code: 'let z: Array = [3, "4"];', + code: "let z: Array = [3, '4'];", options: [{ default: 'generic' }], }, { @@ -146,15 +160,19 @@ ruleTester.run('array-type', rule, { options: [{ default: 'generic' }], }, { - code: `function fooFunction(foo: Array>) { - return foo.map(e => e.foo); -}`, + code: ` +function fooFunction(foo: Array>) { + return foo.map(e => e.foo); +} + `, options: [{ default: 'generic' }], }, { - code: `function bazFunction(baz: Arr>) { - return baz.map(e => e.baz); -}`, + code: ` +function bazFunction(baz: Arr>) { + return baz.map(e => e.baz); +} + `, options: [{ default: 'generic' }], }, { @@ -162,7 +180,7 @@ ruleTester.run('array-type', rule, { options: [{ default: 'generic' }], }, { - code: 'type fooUnion = Array;', + code: 'type fooUnion = Array;', options: [{ default: 'generic' }], }, { @@ -171,40 +189,40 @@ ruleTester.run('array-type', rule, { }, { // https://github.com/typescript-eslint/typescript-eslint/issues/172 - code: 'type Unwrap = T extends Array ? E : T', + code: 'type Unwrap = T extends Array ? E : T;', options: [{ default: 'generic' }], }, // readonly { - code: 'let a: string[] = []', + code: 'let a: string[] = [];', options: [{ default: 'array', readonly: 'generic' }], }, { - code: 'let a: ReadonlyArray = []', + code: 'let a: ReadonlyArray = [];', options: [{ default: 'array', readonly: 'generic' }], }, { - code: 'let a: ReadonlyArray = [[]]', + code: 'let a: ReadonlyArray = [[]];', options: [{ default: 'array', readonly: 'generic' }], }, { - code: 'let a: Array = []', + code: 'let a: Array = [];', options: [{ default: 'generic', readonly: 'array' }], }, { - code: 'let a: readonly number[] = []', + code: 'let a: readonly number[] = [];', options: [{ default: 'generic', readonly: 'array' }], }, { - code: 'let a: readonly Array[] = [[]]', + code: 'let a: readonly Array[] = [[]];', options: [{ default: 'generic', readonly: 'array' }], }, ], invalid: [ { - code: 'let a: Array = []', - output: 'let a: string[] = []', + code: 'let a: Array = [];', + output: 'let a: string[] = [];', options: [{ default: 'array' }], errors: [ { @@ -216,8 +234,8 @@ ruleTester.run('array-type', rule, { ], }, { - code: 'let a: Array = []', - output: 'let a: (string | number)[] = []', + code: 'let a: Array = [];', + output: 'let a: (string | number)[] = [];', options: [{ default: 'array' }], errors: [ { @@ -229,21 +247,21 @@ ruleTester.run('array-type', rule, { ], }, { - code: 'let a: ({ foo: Array })[] = []', - output: 'let a: ({ foo: Bar[] })[] = []', + code: 'let a: { foo: Array }[] = [];', + output: 'let a: { foo: Bar[] }[] = [];', options: [{ default: 'array' }], errors: [ { messageId: 'errorStringArray', data: { type: 'Bar' }, line: 1, - column: 16, + column: 15, }, ], }, { - code: 'let a: string[] = []', - output: 'let a: Array = []', + code: 'let a: string[] = [];', + output: 'let a: Array = [];', options: [{ default: 'generic' }], errors: [ { @@ -255,8 +273,8 @@ ruleTester.run('array-type', rule, { ], }, { - code: 'let a: (string | number)[] = []', - output: 'let a: Array = []', + code: 'let a: (string | number)[] = [];', + output: 'let a: Array = [];', options: [{ default: 'generic' }], errors: [ { @@ -268,8 +286,8 @@ ruleTester.run('array-type', rule, { ], }, { - code: 'let a: Array<{ foo: Bar[] }> = []', - output: 'let a: Array<{ foo: Array }> = []', + code: 'let a: Array<{ foo: Bar[] }> = [];', + output: 'let a: Array<{ foo: Array }> = [];', options: [{ default: 'generic' }], errors: [ { @@ -281,8 +299,8 @@ ruleTester.run('array-type', rule, { ], }, { - code: 'let a: Array<{ foo: Foo | Bar[] }> = []', - output: 'let a: Array<{ foo: Foo | Array }> = []', + code: 'let a: Array<{ foo: Foo | Bar[] }> = [];', + output: 'let a: Array<{ foo: Foo | Array }> = [];', options: [{ default: 'generic' }], errors: [ { @@ -294,27 +312,27 @@ ruleTester.run('array-type', rule, { ], }, { - code: 'function foo (a: Array): Array {}', - output: 'function foo (a: Bar[]): Bar[] {}', + code: 'function foo(a: Array): Array {}', + output: 'function foo(a: Bar[]): Bar[] {}', options: [{ default: 'array' }], errors: [ { messageId: 'errorStringArray', data: { type: 'Bar' }, line: 1, - column: 18, + column: 17, }, { messageId: 'errorStringArray', data: { type: 'Bar' }, line: 1, - column: 31, + column: 30, }, ], }, { - code: 'let a: Array<>[] = []', - output: 'let a: any[][] = []', + code: 'let a: Array<>[] = [];', + output: 'let a: any[][] = [];', options: [{ default: 'array-simple' }], errors: [ { @@ -358,8 +376,8 @@ ruleTester.run('array-type', rule, { ], }, { - code: 'let y: string[] = >["2"];', - output: 'let y: string[] = ["2"];', + code: "let y: string[] = >['2'];", + output: "let y: string[] = ['2'];", options: [{ default: 'array-simple' }], errors: [ { @@ -371,8 +389,8 @@ ruleTester.run('array-type', rule, { ], }, { - code: 'let z: Array = [3, "4"];', - output: 'let z: any[] = [3, "4"];', + code: "let z: Array = [3, '4'];", + output: "let z: any[] = [3, '4'];", options: [{ default: 'array-simple' }], errors: [ { @@ -384,15 +402,15 @@ ruleTester.run('array-type', rule, { ], }, { - code: 'let ya = [[1, "2"]] as[number, string][];', - output: 'let ya = [[1, "2"]] as Array<[number, string]>;', + code: "let ya = [[1, '2']] as [number, string][];", + output: "let ya = [[1, '2']] as Array<[number, string]>;", options: [{ default: 'array-simple' }], errors: [ { messageId: 'errorStringGenericSimple', data: { type: 'T' }, line: 1, - column: 23, + column: 24, }, ], }, @@ -410,56 +428,68 @@ ruleTester.run('array-type', rule, { ], }, { - code: `// Ignore user defined aliases -let yyyy: Arr>[]> = [[[["2"]]]];`, - output: `// Ignore user defined aliases -let yyyy: Arr>>> = [[[["2"]]]];`, + code: ` +// Ignore user defined aliases +let yyyy: Arr>[]> = [[[['2']]]]; + `, + output: ` +// Ignore user defined aliases +let yyyy: Arr>>> = [[[['2']]]]; + `, options: [{ default: 'array-simple' }], errors: [ { messageId: 'errorStringGenericSimple', data: { type: 'T' }, - line: 2, + line: 3, column: 15, }, ], }, { - code: `interface ArrayClass { - foo: Array; - bar: T[]; - baz: Arr; - xyz: this[]; -}`, - output: `interface ArrayClass { - foo: T[]; - bar: T[]; - baz: Arr; - xyz: this[]; -}`, + code: ` +interface ArrayClass { + foo: Array; + bar: T[]; + baz: Arr; + xyz: this[]; +} + `, + output: ` +interface ArrayClass { + foo: T[]; + bar: T[]; + baz: Arr; + xyz: this[]; +} + `, options: [{ default: 'array-simple' }], errors: [ { messageId: 'errorStringArraySimple', data: { type: 'T' }, - line: 2, - column: 10, + line: 3, + column: 8, }, ], }, { - code: `function barFunction(bar: ArrayClass[]) { - return bar.map(e => e.bar); -}`, - output: `function barFunction(bar: Array>) { - return bar.map(e => e.bar); -}`, + code: ` +function barFunction(bar: ArrayClass[]) { + return bar.map(e => e.bar); +} + `, + output: ` +function barFunction(bar: Array>) { + return bar.map(e => e.bar); +} + `, options: [{ default: 'array-simple' }], errors: [ { messageId: 'errorStringGenericSimple', data: { type: 'T' }, - line: 1, + line: 2, column: 27, }, ], @@ -478,8 +508,8 @@ let yyyy: Arr>>> = [[[["2"]]]];`, ], }, { - code: 'type barUnion = (string|number|boolean)[];', - output: 'type barUnion = Array;', + code: 'type barUnion = (string | number | boolean)[];', + output: 'type barUnion = Array;', options: [{ default: 'array-simple' }], errors: [ { @@ -504,8 +534,8 @@ let yyyy: Arr>>> = [[[["2"]]]];`, ], }, { - code: 'let v: Array = [{ bar: "bar" }];', - output: 'let v: fooName.BarType[] = [{ bar: "bar" }];', + code: "let v: Array = [{ bar: 'bar' }];", + output: "let v: fooName.BarType[] = [{ bar: 'bar' }];", options: [{ default: 'array-simple' }], errors: [ { @@ -517,8 +547,8 @@ let yyyy: Arr>>> = [[[["2"]]]];`, ], }, { - code: 'let w: fooName.BazType[] = [["baz"]];', - output: 'let w: Array> = [["baz"]];', + code: "let w: fooName.BazType[] = [['baz']];", + output: "let w: Array> = [['baz']];", options: [{ default: 'array-simple' }], errors: [ { @@ -543,8 +573,8 @@ let yyyy: Arr>>> = [[[["2"]]]];`, ], }, { - code: 'let y: string[] = >["2"];', - output: 'let y: string[] = ["2"];', + code: "let y: string[] = >['2'];", + output: "let y: string[] = ['2'];", options: [{ default: 'array' }], errors: [ { @@ -556,8 +586,8 @@ let yyyy: Arr>>> = [[[["2"]]]];`, ], }, { - code: 'let z: Array = [3, "4"];', - output: 'let z: any[] = [3, "4"];', + code: "let z: Array = [3, '4'];", + output: "let z: any[] = [3, '4'];", options: [{ default: 'array' }], errors: [ { @@ -582,54 +612,66 @@ let yyyy: Arr>>> = [[[["2"]]]];`, ], }, { - code: `// Ignore user defined aliases -let yyyy: Arr>[]> = [[[["2"]]]];`, - output: `// Ignore user defined aliases -let yyyy: Arr[][]> = [[[["2"]]]];`, + code: ` +// Ignore user defined aliases +let yyyy: Arr>[]> = [[[['2']]]]; + `, + output: ` +// Ignore user defined aliases +let yyyy: Arr[][]> = [[[['2']]]]; + `, options: [{ default: 'array' }], errors: [ { messageId: 'errorStringArray', data: { type: 'T' }, - line: 2, + line: 3, column: 15, }, ], }, { - code: `interface ArrayClass { - foo: Array; - bar: T[]; - baz: Arr; -}`, - output: `interface ArrayClass { - foo: T[]; - bar: T[]; - baz: Arr; -}`, + code: ` +interface ArrayClass { + foo: Array; + bar: T[]; + baz: Arr; +} + `, + output: ` +interface ArrayClass { + foo: T[]; + bar: T[]; + baz: Arr; +} + `, options: [{ default: 'array' }], errors: [ { messageId: 'errorStringArray', data: { type: 'T' }, - line: 2, - column: 10, + line: 3, + column: 8, }, ], }, { - code: `function fooFunction(foo: Array>) { - return foo.map(e => e.foo); -}`, - output: `function fooFunction(foo: ArrayClass[]) { - return foo.map(e => e.foo); -}`, + code: ` +function fooFunction(foo: Array>) { + return foo.map(e => e.foo); +} + `, + output: ` +function fooFunction(foo: ArrayClass[]) { + return foo.map(e => e.foo); +} + `, options: [{ default: 'array' }], errors: [ { messageId: 'errorStringArray', data: { type: 'T' }, - line: 1, + line: 2, column: 27, }, ], @@ -648,8 +690,8 @@ let yyyy: Arr[][]> = [[[["2"]]]];`, ], }, { - code: 'type fooUnion = Array;', - output: 'type fooUnion = (string|number|boolean)[];', + code: 'type fooUnion = Array;', + output: 'type fooUnion = (string | number | boolean)[];', options: [{ default: 'array' }], errors: [ { @@ -711,8 +753,8 @@ let yyyy: Arr[][]> = [[[["2"]]]];`, ], }, { - code: 'let y: string[] = >["2"];', - output: 'let y: Array = >["2"];', + code: "let y: string[] = >['2'];", + output: "let y: Array = >['2'];", options: [{ default: 'generic' }], errors: [ { @@ -724,67 +766,79 @@ let yyyy: Arr[][]> = [[[["2"]]]];`, ], }, { - code: 'let ya = [[1, "2"]] as[number, string][];', - output: 'let ya = [[1, "2"]] as Array<[number, string]>;', + code: "let ya = [[1, '2']] as [number, string][];", + output: "let ya = [[1, '2']] as Array<[number, string]>;", options: [{ default: 'generic' }], errors: [ { messageId: 'errorStringGeneric', data: { type: 'T' }, line: 1, - column: 23, + column: 24, }, ], }, { - code: `// Ignore user defined aliases -let yyyy: Arr>[]> = [[[["2"]]]];`, - output: `// Ignore user defined aliases -let yyyy: Arr>>> = [[[["2"]]]];`, + code: ` +// Ignore user defined aliases +let yyyy: Arr>[]> = [[[['2']]]]; + `, + output: ` +// Ignore user defined aliases +let yyyy: Arr>>> = [[[['2']]]]; + `, options: [{ default: 'generic' }], errors: [ { messageId: 'errorStringGeneric', data: { type: 'T' }, - line: 2, + line: 3, column: 15, }, ], }, { - code: `interface ArrayClass { - foo: Array; - bar: T[]; - baz: Arr; -}`, - output: `interface ArrayClass { - foo: Array; - bar: Array; - baz: Arr; -}`, + code: ` +interface ArrayClass { + foo: Array; + bar: T[]; + baz: Arr; +} + `, + output: ` +interface ArrayClass { + foo: Array; + bar: Array; + baz: Arr; +} + `, options: [{ default: 'generic' }], errors: [ { messageId: 'errorStringGeneric', data: { type: 'T' }, - line: 3, - column: 10, + line: 4, + column: 8, }, ], }, { - code: `function barFunction(bar: ArrayClass[]) { - return bar.map(e => e.bar); -}`, - output: `function barFunction(bar: Array>) { - return bar.map(e => e.bar); -}`, + code: ` +function barFunction(bar: ArrayClass[]) { + return bar.map(e => e.bar); +} + `, + output: ` +function barFunction(bar: Array>) { + return bar.map(e => e.bar); +} + `, options: [{ default: 'generic' }], errors: [ { messageId: 'errorStringGeneric', data: { type: 'T' }, - line: 1, + line: 2, column: 27, }, ], @@ -803,8 +857,8 @@ let yyyy: Arr>>> = [[[["2"]]]];`, ], }, { - code: 'type barUnion = (string|number|boolean)[];', - output: 'type barUnion = Array;', + code: 'type barUnion = (string | number | boolean)[];', + output: 'type barUnion = Array;', options: [{ default: 'generic' }], errors: [ { @@ -829,26 +883,30 @@ let yyyy: Arr>>> = [[[["2"]]]];`, ], }, { - code: `interface FooInterface { - '.bar': {baz: string[];}; -}`, - output: `interface FooInterface { - '.bar': {baz: Array;}; -}`, + code: ` +interface FooInterface { + '.bar': { baz: string[] }; +} + `, + output: ` +interface FooInterface { + '.bar': { baz: Array }; +} + `, options: [{ default: 'generic' }], errors: [ { messageId: 'errorStringGeneric', data: { type: 'string' }, - line: 2, - column: 19, + line: 3, + column: 18, }, ], }, { // https://github.com/typescript-eslint/typescript-eslint/issues/172 - code: 'type Unwrap = T extends Array ? E : T', - output: 'type Unwrap = T extends (infer E)[] ? E : T', + code: 'type Unwrap = T extends Array ? E : T;', + output: 'type Unwrap = T extends (infer E)[] ? E : T;', options: [{ default: 'array' }], errors: [ { @@ -861,8 +919,8 @@ let yyyy: Arr>>> = [[[["2"]]]];`, }, { // https://github.com/typescript-eslint/typescript-eslint/issues/172 - code: 'type Unwrap = T extends (infer E)[] ? E : T', - output: 'type Unwrap = T extends Array ? E : T', + code: 'type Unwrap = T extends (infer E)[] ? E : T;', + output: 'type Unwrap = T extends Array ? E : T;', options: [{ default: 'generic' }], errors: [ { @@ -928,8 +986,8 @@ let yyyy: Arr>>> = [[[["2"]]]];`, ], }, { - code: 'const x: readonly number[] = []', - output: 'const x: ReadonlyArray = []', + code: 'const x: readonly number[] = [];', + output: 'const x: ReadonlyArray = [];', options: [{ default: 'array', readonly: 'generic' }], errors: [ { @@ -941,8 +999,8 @@ let yyyy: Arr>>> = [[[["2"]]]];`, ], }, { - code: 'const x: readonly number[][] = []', - output: 'const x: readonly Array[] = []', + code: 'const x: readonly number[][] = [];', + output: 'const x: readonly Array[] = [];', options: [{ default: 'generic', readonly: 'array' }], errors: [ { diff --git a/packages/eslint-plugin/tests/rules/await-thenable.test.ts b/packages/eslint-plugin/tests/rules/await-thenable.test.ts index 5ee0f7d03410..52fc1ca23061 100644 --- a/packages/eslint-plugin/tests/rules/await-thenable.test.ts +++ b/packages/eslint-plugin/tests/rules/await-thenable.test.ts @@ -13,51 +13,51 @@ const ruleTester = new RuleTester({ parser: '@typescript-eslint/parser', }); -ruleTester.run('await-promise', rule, { +ruleTester.run('await-thenable', rule, { valid: [ ` async function test() { - await Promise.resolve("value"); - await Promise.reject(new Error("message")); + await Promise.resolve('value'); + await Promise.reject(new Error('message')); } -`, + `, ` async function test() { await (async () => true)(); } -`, + `, ` async function test() { function returnsPromise() { - return Promise.resolve("value"); + return Promise.resolve('value'); } await returnsPromise(); } -`, + `, ` async function test() { async function returnsPromiseAsync() {} await returnsPromiseAsync(); } -`, + `, ` async function test() { let anyValue: any; await anyValue; } -`, + `, ` async function test() { let unknownValue: unknown; await unknownValue; } -`, + `, ` async function test() { const numberPromise: Promise; await numberPromise; } -`, + `, ` async function test() { class Foo extends Promise {} @@ -68,7 +68,7 @@ async function test() { const bar: Bar = Bar.resolve(2); await bar; } -`, + `, ` async function test() { await (Math.random() > 0.5 ? numberPromise : 0); @@ -78,15 +78,17 @@ async function test() { const intersectionPromise: Promise & number; await intersectionPromise; } -`, + `, ` async function test() { - class Thenable { then(callback: () => {}) { } }; + class Thenable { + then(callback: () => {}) {} + } const thenable = new Thenable(); await thenable; } -`, + `, ` // https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/promise-polyfill/index.d.ts // Type definitions for promise-polyfill 6.0 @@ -96,7 +98,7 @@ async function test() { // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped interface PromisePolyfillConstructor extends PromiseConstructor { - _immediateFn?: (handler: (() => void) | string) => void; + _immediateFn?: (handler: (() => void) | string) => void; } declare const PromisePolyfill: PromisePolyfillConstructor; @@ -106,7 +108,7 @@ async function test() { await promise; } -`, + `, ` // https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/bluebird/index.d.ts // Type definitions for bluebird 3.5 @@ -151,14 +153,21 @@ type CatchFilter = ((error: E) => boolean) | (object & E); type IterableItem = R extends Iterable ? U : never; type IterableOrNever = Extract>; type Resolvable = R | PromiseLike; -type IterateFunction = (item: T, index: number, arrayLength: number) => Resolvable; +type IterateFunction = ( + item: T, + index: number, + arrayLength: number, +) => Resolvable; declare class Bluebird implements PromiseLike { - then(onFulfill?: (value: R) => Resolvable, onReject?: (error: any) => Resolvable): Bluebird; // For simpler signature help. + then( + onFulfill?: (value: R) => Resolvable, + onReject?: (error: any) => Resolvable, + ): Bluebird; // For simpler signature help. then( - onfulfilled?: ((value: R) => Resolvable) | null, - onrejected?: ((reason: any) => Resolvable) | null - ): Bluebird; + onfulfilled?: ((value: R) => Resolvable) | null, + onrejected?: ((reason: any) => Resolvable) | null, + ): Bluebird; } declare const bluebird: Bluebird; @@ -166,7 +175,7 @@ declare const bluebird: Bluebird; async function test() { await bluebird; } -`, + `, ], invalid: [ @@ -174,14 +183,14 @@ async function test() { code: ` async function test() { await 0; - await "value"; + await 'value'; - await (Math.random() > 0.5 ? "" : 0); + await (Math.random() > 0.5 ? '' : 0); class NonPromise extends Array {} await new NonPromise(); } -`, + `, errors: [ { line: 3, @@ -204,7 +213,9 @@ async function test() { { code: ` async function test() { - class IncorrectThenable { then() { } }; + class IncorrectThenable { + then() {} + } const thenable = new IncorrectThenable(); await thenable; @@ -212,7 +223,7 @@ async function test() { `, errors: [ { - line: 6, + line: 8, messageId, }, ], diff --git a/packages/eslint-plugin/tests/rules/ban-ts-comment.test.ts b/packages/eslint-plugin/tests/rules/ban-ts-comment.test.ts index c2226f7041a7..fcbb788a3082 100644 --- a/packages/eslint-plugin/tests/rules/ban-ts-comment.test.ts +++ b/packages/eslint-plugin/tests/rules/ban-ts-comment.test.ts @@ -5,14 +5,16 @@ const ruleTester = new RuleTester({ parser: '@typescript-eslint/parser', }); -ruleTester.run('ts-ignore', rule, { +ruleTester.run('ban-ts-comment', rule, { valid: [ - `// just a comment containing @ts-ignore somewhere`, - `/* @ts-ignore */`, - `/** @ts-ignore */`, - `/* + '// just a comment containing @ts-ignore somewhere', + '/* @ts-ignore */', + '/** @ts-ignore */', + ` +/* // @ts-ignore in a block -*/`, +*/ + `, { code: '// @ts-ignore', options: [{ 'ts-ignore': false }], @@ -68,9 +70,9 @@ ruleTester.run('ts-ignore', rule, { code: ` if (false) { // @ts-ignore: Unreachable code error - console.log("hello"); + console.log('hello'); } - `, + `, errors: [ { data: { directive: 'ignore' }, @@ -85,12 +87,14 @@ if (false) { ruleTester.run('ts-nocheck', rule, { valid: [ - `// just a comment containing @ts-nocheck somewhere`, - `/* @ts-nocheck */`, - `/** @ts-nocheck */`, - `/* + '// just a comment containing @ts-nocheck somewhere', + '/* @ts-nocheck */', + '/** @ts-nocheck */', + ` +/* // @ts-nocheck in a block -*/`, +*/ + `, { code: '// @ts-nocheck', options: [{ 'ts-nocheck': false }], @@ -146,9 +150,9 @@ ruleTester.run('ts-nocheck', rule, { code: ` if (false) { // @ts-nocheck: Unreachable code error - console.log("hello"); + console.log('hello'); } - `, + `, errors: [ { data: { directive: 'nocheck' }, @@ -163,12 +167,14 @@ if (false) { ruleTester.run('ts-check', rule, { valid: [ - `// just a comment containing @ts-check somewhere`, - `/* @ts-check */`, - `/** @ts-check */`, - `/* + '// just a comment containing @ts-check somewhere', + '/* @ts-check */', + '/** @ts-check */', + ` +/* // @ts-check in a block -*/`, +*/ + `, { code: '// @ts-check', options: [{ 'ts-check': false }], @@ -216,9 +222,9 @@ ruleTester.run('ts-check', rule, { code: ` if (false) { // @ts-check: Unreachable code error - console.log("hello"); + console.log('hello'); } - `, + `, options: [{ 'ts-check': true }], errors: [ { diff --git a/packages/eslint-plugin/tests/rules/ban-ts-ignore.test.ts b/packages/eslint-plugin/tests/rules/ban-ts-ignore.test.ts index d9132df2b0d4..e1471950f464 100644 --- a/packages/eslint-plugin/tests/rules/ban-ts-ignore.test.ts +++ b/packages/eslint-plugin/tests/rules/ban-ts-ignore.test.ts @@ -7,12 +7,14 @@ const ruleTester = new RuleTester({ ruleTester.run('ban-ts-ignore', rule, { valid: [ - `// just a comment containing @ts-ignore somewhere`, - `/* @ts-ignore */`, - `/** @ts-ignore */`, - `/* + '// just a comment containing @ts-ignore somewhere', + '/* @ts-ignore */', + '/** @ts-ignore */', + ` +/* // @ts-ignore in a block -*/`, +*/ + `, ], invalid: [ { @@ -49,9 +51,9 @@ ruleTester.run('ban-ts-ignore', rule, { code: ` if (false) { // @ts-ignore: Unreachable code error - console.log("hello"); + console.log('hello'); } - `, + `, errors: [ { messageId: 'tsIgnoreComment', diff --git a/packages/eslint-plugin/tests/rules/ban-types.test.ts b/packages/eslint-plugin/tests/rules/ban-types.test.ts index 0edeb74f8d1c..772fa7716f8f 100644 --- a/packages/eslint-plugin/tests/rules/ban-types.test.ts +++ b/packages/eslint-plugin/tests/rules/ban-types.test.ts @@ -1,5 +1,5 @@ import rule from '../../src/rules/ban-types'; -import { RuleTester } from '../RuleTester'; +import { RuleTester, noFormat } from '../RuleTester'; import { InferOptionsTypeFromRule } from '../../src/util'; const ruleTester = new RuleTester({ @@ -47,7 +47,7 @@ ruleTester.run('ban-types', rule, { valid: [ 'let f = Object();', // Should not fail if there is no options set 'let f: {} = {};', - 'let f: { x: number, y: number } = { x: 1, y: 1 };', + 'let f: { x: number; y: number } = { x: 1, y: 1 };', { code: 'let f = Object();', options, @@ -65,11 +65,11 @@ ruleTester.run('ban-types', rule, { options, }, { - code: 'let a: _.NS.Bad', + code: 'let a: _.NS.Bad;', options, }, { - code: 'let a: NS.Bad._', + code: 'let a: NS.Bad._;', options, }, // Replace default options instead of merging with extendDefaults: false @@ -88,11 +88,11 @@ ruleTester.run('ban-types', rule, { ], }, { - code: 'let a: undefined', + code: 'let a: undefined;', options: options2, }, { - code: 'let a: null', + code: 'let a: null;', options: options3, }, ], @@ -166,8 +166,8 @@ ruleTester.run('ban-types', rule, { ], }, { - code: 'let b: {c: String};', - output: 'let b: {c: string};', + code: 'let b: { c: String };', + output: 'let b: { c: string };', errors: [ { messageId: 'bannedTypeMessage', @@ -177,7 +177,7 @@ ruleTester.run('ban-types', rule, { customMessage: ' Use string instead.', }, line: 1, - column: 12, + column: 13, }, ], options, @@ -231,22 +231,22 @@ ruleTester.run('ban-types', rule, { { code: ` class Foo extends Bar implements Baz { - constructor (foo: String | Object) {} + constructor(foo: String | Object) {} - exit() : Array { - const foo: String = 1 as String + exit(): Array { + const foo: String = 1 as String; } } - `, + `, output: ` class Foo extends Bar implements Baz { - constructor (foo: string | Object) {} + constructor(foo: string | Object) {} - exit() : Array { - const foo: string = 1 as string + exit(): Array { + const foo: string = 1 as string; } } - `, + `, errors: [ { messageId: 'bannedTypeMessage', @@ -285,7 +285,7 @@ class Foo extends Bar implements Baz { customMessage: ' Use string instead.', }, line: 3, - column: 21, + column: 20, }, { messageId: 'bannedTypeMessage', @@ -294,13 +294,13 @@ class Foo extends Bar implements Baz { customMessage: " Use '{}' instead.", }, line: 3, - column: 30, + column: 29, }, { messageId: 'bannedTypeMessage', data: { name: 'Array', customMessage: '' }, line: 5, - column: 12, + column: 11, }, { messageId: 'bannedTypeMessage', @@ -310,7 +310,7 @@ class Foo extends Bar implements Baz { customMessage: ' Use string instead.', }, line: 5, - column: 18, + column: 17, }, { messageId: 'bannedTypeMessage', @@ -383,8 +383,8 @@ let b: Foo; options, }, { - code: `let foo: {} = {};`, - output: `let foo: object = {};`, + code: 'let foo: {} = {};', + output: 'let foo: object = {};', options: [ { types: { @@ -408,7 +408,7 @@ let b: Foo; ], }, { - code: ` + code: noFormat` let foo: {} = {}; let bar: { } = {}; `, @@ -473,8 +473,8 @@ let bar: object = {}; ], }, { - code: 'let a: Foo< F >;', - output: 'let a: Foo< T >;', + code: noFormat`let a: Foo< F >;`, + output: noFormat`let a: Foo< T >;`, errors: [ { messageId: 'bannedTypeMessage', diff --git a/packages/eslint-plugin/tests/rules/brace-style.test.ts b/packages/eslint-plugin/tests/rules/brace-style.test.ts index 21d10998eac1..28b9413795db 100644 --- a/packages/eslint-plugin/tests/rules/brace-style.test.ts +++ b/packages/eslint-plugin/tests/rules/brace-style.test.ts @@ -1,3 +1,8 @@ +/* eslint-disable eslint-comments/no-use */ +// this rule tests the position of braces, which prettier will want to fix and break the tests +/* eslint "@typescript-eslint/internal/plugin-test-formatting": ["error", { formatWithPrettier: false }] */ +/* eslint-enable eslint-comments/no-use */ + import rule from '../../src/rules/brace-style'; import { RuleTester } from '../RuleTester'; @@ -211,67 +216,67 @@ catch (e) options: ['allman'], }, { - code: `function foo () { return; }`, + code: 'function foo () { return; }', options: ['1tbs', { allowSingleLine: true }], }, { - code: `function foo () { a(); b(); return; }`, + code: 'function foo () { a(); b(); return; }', options: ['1tbs', { allowSingleLine: true }], }, { - code: `function a(b,c,d) { }`, + code: 'function a(b,c,d) { }', options: ['1tbs', { allowSingleLine: true }], }, { - code: `!function foo () { return; }`, + code: '!function foo () { return; }', options: ['1tbs', { allowSingleLine: true }], }, { - code: `!function a(b,c,d) { }`, + code: '!function a(b,c,d) { }', options: ['1tbs', { allowSingleLine: true }], }, { - code: `if (foo) { bar(); }`, + code: 'if (foo) { bar(); }', options: ['1tbs', { allowSingleLine: true }], }, { - code: `if (a) { b(); } else { c(); }`, + code: 'if (a) { b(); } else { c(); }', options: ['1tbs', { allowSingleLine: true }], }, { - code: `while (foo) { bar(); }`, + code: 'while (foo) { bar(); }', options: ['1tbs', { allowSingleLine: true }], }, { - code: `for (;;) { bar(); }`, + code: 'for (;;) { bar(); }', options: ['1tbs', { allowSingleLine: true }], }, { - code: `with (foo) { bar(); }`, + code: 'with (foo) { bar(); }', options: ['1tbs', { allowSingleLine: true }], }, { - code: `switch (foo) { case 'bar': break; }`, + code: "switch (foo) { case 'bar': break; }", options: ['1tbs', { allowSingleLine: true }], }, { - code: `try { bar(); } catch (e) { baz(); }`, + code: 'try { bar(); } catch (e) { baz(); }', options: ['1tbs', { allowSingleLine: true }], }, { - code: `do { bar(); } while (true)`, + code: 'do { bar(); } while (true)', options: ['1tbs', { allowSingleLine: true }], }, { - code: `for (foo in bar) { baz(); }`, + code: 'for (foo in bar) { baz(); }', options: ['1tbs', { allowSingleLine: true }], }, { - code: `if (a && b && c) { }`, + code: 'if (a && b && c) { }', options: ['1tbs', { allowSingleLine: true }], }, { - code: `switch(0) {}`, + code: 'switch(0) {}', options: ['1tbs', { allowSingleLine: true }], }, { @@ -289,7 +294,7 @@ catch (e) { baz(); } options: ['stroustrup', { allowSingleLine: true }], }, { - code: `var foo = () => { return; }`, + code: 'var foo = () => { return; }', options: ['stroustrup', { allowSingleLine: true }], parserOptions: { ecmaVersion: 6 }, }, @@ -308,7 +313,7 @@ catch (e) { baz(); } options: ['allman', { allowSingleLine: true }], }, { - code: `var foo = () => { return; }`, + code: 'var foo = () => { return; }', options: ['allman', { allowSingleLine: true }], parserOptions: { ecmaVersion: 6 }, }, @@ -345,7 +350,7 @@ switch(x) options: ['allman'], }, { - code: `switch(x) {}`, + code: 'switch(x) {}', options: ['allman', { allowSingleLine: true }], }, { @@ -388,25 +393,25 @@ Foo options: ['allman'], }, { - code: `class Foo {}`, + code: 'class Foo {}', options: ['1tbs', { allowSingleLine: true }], }, { - code: `class Foo {}`, + code: 'class Foo {}', options: ['allman', { allowSingleLine: true }], }, { - code: `(class {})`, + code: '(class {})', options: ['1tbs', { allowSingleLine: true }], }, { - code: `(class {})`, + code: '(class {})', options: ['allman', { allowSingleLine: true }], }, // https://github.com/eslint/eslint/issues/7908 { - code: `{}`, + code: '{}', }, { code: ` @@ -568,7 +573,7 @@ enum Foo { options: ['stroustrup'], }, { - code: `enum Foo { A, B }`, + code: 'enum Foo { A, B }', options: ['1tbs', { allowSingleLine: true }], }, ], @@ -591,8 +596,8 @@ if (f) { errors: [{ messageId: 'nextLineClose' }], }, { - code: `var foo = () => { return; }`, - output: `var foo = () => {\n return; \n}`, + code: 'var foo = () => { return; }', + output: 'var foo = () => {\n return; \n}', parserOptions: { ecmaVersion: 6 }, errors: [ { messageId: 'blockSameLine' }, @@ -600,31 +605,31 @@ if (f) { ], }, { - code: `function foo() { return; }`, - output: `function foo() {\n return; \n}`, + code: 'function foo() { return; }', + output: 'function foo() {\n return; \n}', errors: [ { messageId: 'blockSameLine' }, { messageId: 'singleLineClose' }, ], }, { - code: `function foo() \n { \n return; }`, - output: `function foo() { \n return; \n}`, + code: 'function foo() \n { \n return; }', + output: 'function foo() { \n return; \n}', errors: [{ messageId: 'nextLineOpen' }, { messageId: 'singleLineClose' }], }, { - code: `!function foo() \n { \n return; }`, - output: `!function foo() { \n return; \n}`, + code: '!function foo() \n { \n return; }', + output: '!function foo() { \n return; \n}', errors: [{ messageId: 'nextLineOpen' }, { messageId: 'singleLineClose' }], }, { - code: `if (foo) \n { \n bar(); }`, - output: `if (foo) { \n bar(); \n}`, + code: 'if (foo) \n { \n bar(); }', + output: 'if (foo) { \n bar(); \n}', errors: [{ messageId: 'nextLineOpen' }, { messageId: 'singleLineClose' }], }, { - code: `if (a) { \nb();\n } else \n { c(); }`, - output: `if (a) { \nb();\n } else {\n c(); \n}`, + code: 'if (a) { \nb();\n } else \n { c(); }', + output: 'if (a) { \nb();\n } else {\n c(); \n}', errors: [ { messageId: 'nextLineOpen' }, { messageId: 'blockSameLine' }, @@ -632,104 +637,108 @@ if (f) { ], }, { - code: `while (foo) \n { \n bar(); }`, - output: `while (foo) { \n bar(); \n}`, + code: 'while (foo) \n { \n bar(); }', + output: 'while (foo) { \n bar(); \n}', errors: [{ messageId: 'nextLineOpen' }, { messageId: 'singleLineClose' }], }, { - code: `for (;;) \n { \n bar(); }`, - output: `for (;;) { \n bar(); \n}`, + code: 'for (;;) \n { \n bar(); }', + output: 'for (;;) { \n bar(); \n}', errors: [{ messageId: 'nextLineOpen' }, { messageId: 'singleLineClose' }], }, { - code: `with (foo) \n { \n bar(); }`, - output: `with (foo) { \n bar(); \n}`, + code: 'with (foo) \n { \n bar(); }', + output: 'with (foo) { \n bar(); \n}', errors: [{ messageId: 'nextLineOpen' }, { messageId: 'singleLineClose' }], }, { - code: `switch (foo) \n { \n case 'bar': break; }`, - output: `switch (foo) { \n case 'bar': break; \n}`, + code: "switch (foo) \n { \n case 'bar': break; }", + output: "switch (foo) { \n case 'bar': break; \n}", errors: [{ messageId: 'nextLineOpen' }, { messageId: 'singleLineClose' }], }, { - code: `switch (foo) \n { }`, - output: `switch (foo) { }`, + code: 'switch (foo) \n { }', + output: 'switch (foo) { }', errors: [{ messageId: 'nextLineOpen' }], }, { - code: `try \n { \n bar(); \n } catch (e) {}`, - output: `try { \n bar(); \n } catch (e) {}`, + code: 'try \n { \n bar(); \n } catch (e) {}', + output: 'try { \n bar(); \n } catch (e) {}', errors: [{ messageId: 'nextLineOpen' }], }, { - code: `try { \n bar(); \n } catch (e) \n {}`, - output: `try { \n bar(); \n } catch (e) {}`, + code: 'try { \n bar(); \n } catch (e) \n {}', + output: 'try { \n bar(); \n } catch (e) {}', errors: [{ messageId: 'nextLineOpen' }], }, { - code: `do \n { \n bar(); \n} while (true)`, - output: `do { \n bar(); \n} while (true)`, + code: 'do \n { \n bar(); \n} while (true)', + output: 'do { \n bar(); \n} while (true)', errors: [{ messageId: 'nextLineOpen' }], }, { - code: `for (foo in bar) \n { \n baz(); \n }`, - output: `for (foo in bar) { \n baz(); \n }`, + code: 'for (foo in bar) \n { \n baz(); \n }', + output: 'for (foo in bar) { \n baz(); \n }', errors: [{ messageId: 'nextLineOpen' }], }, { - code: `for (foo of bar) \n { \n baz(); \n }`, - output: `for (foo of bar) { \n baz(); \n }`, + code: 'for (foo of bar) \n { \n baz(); \n }', + output: 'for (foo of bar) { \n baz(); \n }', parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: 'nextLineOpen' }], }, { - code: `try { \n bar(); \n }\ncatch (e) {\n}`, - output: `try { \n bar(); \n } catch (e) {\n}`, + code: 'try { \n bar(); \n }\ncatch (e) {\n}', + output: 'try { \n bar(); \n } catch (e) {\n}', errors: [{ messageId: 'nextLineClose' }], }, { - code: `try { \n bar(); \n } catch (e) {\n}\n finally {\n}`, - output: `try { \n bar(); \n } catch (e) {\n} finally {\n}`, + code: 'try { \n bar(); \n } catch (e) {\n}\n finally {\n}', + output: 'try { \n bar(); \n } catch (e) {\n} finally {\n}', errors: [{ messageId: 'nextLineClose' }], }, { - code: `if (a) { \nb();\n } \n else { \nc();\n }`, - output: `if (a) { \nb();\n } else { \nc();\n }`, + code: 'if (a) { \nb();\n } \n else { \nc();\n }', + output: 'if (a) { \nb();\n } else { \nc();\n }', errors: [{ messageId: 'nextLineClose' }], }, { - code: `try { \n bar(); \n }\ncatch (e) {\n} finally {\n}`, - output: `try { \n bar(); \n }\ncatch (e) {\n}\n finally {\n}`, + code: 'try { \n bar(); \n }\ncatch (e) {\n} finally {\n}', + output: 'try { \n bar(); \n }\ncatch (e) {\n}\n finally {\n}', options: ['stroustrup'], errors: [{ messageId: 'sameLineClose' }], }, { - code: `try { \n bar(); \n } catch (e) {\n}\n finally {\n}`, - output: `try { \n bar(); \n }\n catch (e) {\n}\n finally {\n}`, + code: 'try { \n bar(); \n } catch (e) {\n}\n finally {\n}', + output: 'try { \n bar(); \n }\n catch (e) {\n}\n finally {\n}', options: ['stroustrup'], errors: [{ messageId: 'sameLineClose' }], }, { - code: `if (a) { \nb();\n } else { \nc();\n }`, - output: `if (a) { \nb();\n }\n else { \nc();\n }`, + code: 'if (a) { \nb();\n } else { \nc();\n }', + output: 'if (a) { \nb();\n }\n else { \nc();\n }', options: ['stroustrup'], errors: [{ messageId: 'sameLineClose' }], }, { - code: `if (foo) {\nbaz();\n} else if (bar) {\nbaz();\n}\nelse {\nqux();\n}`, - output: `if (foo) {\nbaz();\n}\n else if (bar) {\nbaz();\n}\nelse {\nqux();\n}`, + code: + 'if (foo) {\nbaz();\n} else if (bar) {\nbaz();\n}\nelse {\nqux();\n}', + output: + 'if (foo) {\nbaz();\n}\n else if (bar) {\nbaz();\n}\nelse {\nqux();\n}', options: ['stroustrup'], errors: [{ messageId: 'sameLineClose' }], }, { - code: `if (foo) {\npoop();\n} \nelse if (bar) {\nbaz();\n} else if (thing) {\nboom();\n}\nelse {\nqux();\n}`, - output: `if (foo) {\npoop();\n} \nelse if (bar) {\nbaz();\n}\n else if (thing) {\nboom();\n}\nelse {\nqux();\n}`, + code: + 'if (foo) {\npoop();\n} \nelse if (bar) {\nbaz();\n} else if (thing) {\nboom();\n}\nelse {\nqux();\n}', + output: + 'if (foo) {\npoop();\n} \nelse if (bar) {\nbaz();\n}\n else if (thing) {\nboom();\n}\nelse {\nqux();\n}', options: ['stroustrup'], errors: [{ messageId: 'sameLineClose' }], }, { - code: `try { \n bar(); \n }\n catch (e) {\n}\n finally {\n}`, - output: `try \n{ \n bar(); \n }\n catch (e) \n{\n}\n finally \n{\n}`, + code: 'try { \n bar(); \n }\n catch (e) {\n}\n finally {\n}', + output: 'try \n{ \n bar(); \n }\n catch (e) \n{\n}\n finally \n{\n}', options: ['allman'], errors: [ { messageId: 'sameLineOpen', line: 1 }, @@ -738,8 +747,8 @@ if (f) { ], }, { - code: `switch(x) { case 1: \nbar(); }\n `, - output: `switch(x) \n{\n case 1: \nbar(); \n}\n `, + code: 'switch(x) { case 1: \nbar(); }\n ', + output: 'switch(x) \n{\n case 1: \nbar(); \n}\n ', options: ['allman'], errors: [ { messageId: 'sameLineOpen', line: 1 }, @@ -748,8 +757,8 @@ if (f) { ], }, { - code: `if (a) { \nb();\n } else { \nc();\n }`, - output: `if (a) \n{ \nb();\n }\n else \n{ \nc();\n }`, + code: 'if (a) { \nb();\n } else { \nc();\n }', + output: 'if (a) \n{ \nb();\n }\n else \n{ \nc();\n }', options: ['allman'], errors: [ { messageId: 'sameLineOpen' }, @@ -758,8 +767,10 @@ if (f) { ], }, { - code: `if (foo) {\nbaz();\n} else if (bar) {\nbaz();\n}\nelse {\nqux();\n}`, - output: `if (foo) \n{\nbaz();\n}\n else if (bar) \n{\nbaz();\n}\nelse \n{\nqux();\n}`, + code: + 'if (foo) {\nbaz();\n} else if (bar) {\nbaz();\n}\nelse {\nqux();\n}', + output: + 'if (foo) \n{\nbaz();\n}\n else if (bar) \n{\nbaz();\n}\nelse \n{\nqux();\n}', options: ['allman'], errors: [ { messageId: 'sameLineOpen' }, @@ -769,8 +780,10 @@ if (f) { ], }, { - code: `if (foo)\n{ poop();\n} \nelse if (bar) {\nbaz();\n} else if (thing) {\nboom();\n}\nelse {\nqux();\n}`, - output: `if (foo)\n{\n poop();\n} \nelse if (bar) \n{\nbaz();\n}\n else if (thing) \n{\nboom();\n}\nelse \n{\nqux();\n}`, + code: + 'if (foo)\n{ poop();\n} \nelse if (bar) {\nbaz();\n} else if (thing) {\nboom();\n}\nelse {\nqux();\n}', + output: + 'if (foo)\n{\n poop();\n} \nelse if (bar) \n{\nbaz();\n}\n else if (thing) \n{\nboom();\n}\nelse \n{\nqux();\n}', options: ['allman'], errors: [ { messageId: 'blockSameLine' }, @@ -781,159 +794,162 @@ if (f) { ], }, { - code: `if (foo)\n{\n bar(); }`, - output: `if (foo)\n{\n bar(); \n}`, + code: 'if (foo)\n{\n bar(); }', + output: 'if (foo)\n{\n bar(); \n}', options: ['allman'], errors: [{ messageId: 'singleLineClose' }], }, { - code: `try\n{\n somethingRisky();\n} catch (e)\n{\n handleError()\n}`, - output: `try\n{\n somethingRisky();\n}\n catch (e)\n{\n handleError()\n}`, + code: 'try\n{\n somethingRisky();\n} catch (e)\n{\n handleError()\n}', + output: + 'try\n{\n somethingRisky();\n}\n catch (e)\n{\n handleError()\n}', options: ['allman'], errors: [{ messageId: 'sameLineClose' }], }, // allowSingleLine: true { - code: `function foo() { return; \n}`, - output: `function foo() {\n return; \n}`, + code: 'function foo() { return; \n}', + output: 'function foo() {\n return; \n}', options: ['1tbs', { allowSingleLine: true }], errors: [{ messageId: 'blockSameLine' }], }, { - code: `function foo() { a(); b(); return; \n}`, - output: `function foo() {\n a(); b(); return; \n}`, + code: 'function foo() { a(); b(); return; \n}', + output: 'function foo() {\n a(); b(); return; \n}', options: ['1tbs', { allowSingleLine: true }], errors: [{ messageId: 'blockSameLine' }], }, { - code: `function foo() { \n return; }`, - output: `function foo() { \n return; \n}`, + code: 'function foo() { \n return; }', + output: 'function foo() { \n return; \n}', options: ['1tbs', { allowSingleLine: true }], errors: [{ messageId: 'singleLineClose' }], }, { - code: `function foo() {\na();\nb();\nreturn; }`, - output: `function foo() {\na();\nb();\nreturn; \n}`, + code: 'function foo() {\na();\nb();\nreturn; }', + output: 'function foo() {\na();\nb();\nreturn; \n}', options: ['1tbs', { allowSingleLine: true }], errors: [{ messageId: 'singleLineClose' }], }, { - code: `!function foo() { \n return; }`, - output: `!function foo() { \n return; \n}`, + code: '!function foo() { \n return; }', + output: '!function foo() { \n return; \n}', options: ['1tbs', { allowSingleLine: true }], errors: [{ messageId: 'singleLineClose' }], }, { - code: `if (a) { b();\n } else { c(); }`, - output: `if (a) {\n b();\n } else { c(); }`, + code: 'if (a) { b();\n } else { c(); }', + output: 'if (a) {\n b();\n } else { c(); }', options: ['1tbs', { allowSingleLine: true }], errors: [{ messageId: 'blockSameLine' }], }, { - code: `if (a) { b(); }\nelse { c(); }`, - output: `if (a) { b(); } else { c(); }`, + code: 'if (a) { b(); }\nelse { c(); }', + output: 'if (a) { b(); } else { c(); }', options: ['1tbs', { allowSingleLine: true }], errors: [{ messageId: 'nextLineClose' }], }, { - code: `while (foo) { \n bar(); }`, - output: `while (foo) { \n bar(); \n}`, + code: 'while (foo) { \n bar(); }', + output: 'while (foo) { \n bar(); \n}', options: ['1tbs', { allowSingleLine: true }], errors: [{ messageId: 'singleLineClose' }], }, { - code: `for (;;) { bar(); \n }`, - output: `for (;;) {\n bar(); \n }`, + code: 'for (;;) { bar(); \n }', + output: 'for (;;) {\n bar(); \n }', options: ['1tbs', { allowSingleLine: true }], errors: [{ messageId: 'blockSameLine' }], }, { - code: `with (foo) { bar(); \n }`, - output: `with (foo) {\n bar(); \n }`, + code: 'with (foo) { bar(); \n }', + output: 'with (foo) {\n bar(); \n }', options: ['1tbs', { allowSingleLine: true }], errors: [{ messageId: 'blockSameLine' }], }, { - code: `switch (foo) \n { \n case \`bar\`: break; }`, - output: `switch (foo) { \n case \`bar\`: break; \n}`, + code: 'switch (foo) \n { \n case `bar`: break; }', + output: 'switch (foo) { \n case `bar`: break; \n}', options: ['1tbs', { allowSingleLine: true }], errors: [{ messageId: 'nextLineOpen' }, { messageId: 'singleLineClose' }], }, { - code: `switch (foo) \n { }`, - output: `switch (foo) { }`, + code: 'switch (foo) \n { }', + output: 'switch (foo) { }', options: ['1tbs', { allowSingleLine: true }], errors: [{ messageId: 'nextLineOpen' }], }, { - code: `try { bar(); }\ncatch (e) { baz(); }`, - output: `try { bar(); } catch (e) { baz(); }`, + code: 'try { bar(); }\ncatch (e) { baz(); }', + output: 'try { bar(); } catch (e) { baz(); }', options: ['1tbs', { allowSingleLine: true }], errors: [{ messageId: 'nextLineClose' }], }, { - code: `try \n { \n bar(); \n } catch (e) {}`, - output: `try { \n bar(); \n } catch (e) {}`, + code: 'try \n { \n bar(); \n } catch (e) {}', + output: 'try { \n bar(); \n } catch (e) {}', options: ['1tbs', { allowSingleLine: true }], errors: [{ messageId: 'nextLineOpen' }], }, { - code: `try { \n bar(); \n } catch (e) \n {}`, - output: `try { \n bar(); \n } catch (e) {}`, + code: 'try { \n bar(); \n } catch (e) \n {}', + output: 'try { \n bar(); \n } catch (e) {}', options: ['1tbs', { allowSingleLine: true }], errors: [{ messageId: 'nextLineOpen' }], }, { - code: `do \n { \n bar(); \n} while (true)`, - output: `do { \n bar(); \n} while (true)`, + code: 'do \n { \n bar(); \n} while (true)', + output: 'do { \n bar(); \n} while (true)', options: ['1tbs', { allowSingleLine: true }], errors: [{ messageId: 'nextLineOpen' }], }, { - code: `for (foo in bar) \n { \n baz(); \n }`, - output: `for (foo in bar) { \n baz(); \n }`, + code: 'for (foo in bar) \n { \n baz(); \n }', + output: 'for (foo in bar) { \n baz(); \n }', options: ['1tbs', { allowSingleLine: true }], errors: [{ messageId: 'nextLineOpen' }], }, { - code: `try { \n bar(); \n }\ncatch (e) {\n}`, - output: `try { \n bar(); \n } catch (e) {\n}`, + code: 'try { \n bar(); \n }\ncatch (e) {\n}', + output: 'try { \n bar(); \n } catch (e) {\n}', options: ['1tbs', { allowSingleLine: true }], errors: [{ messageId: 'nextLineClose' }], }, { - code: `try { \n bar(); \n } catch (e) {\n}\n finally {\n}`, - output: `try { \n bar(); \n } catch (e) {\n} finally {\n}`, + code: 'try { \n bar(); \n } catch (e) {\n}\n finally {\n}', + output: 'try { \n bar(); \n } catch (e) {\n} finally {\n}', options: ['1tbs', { allowSingleLine: true }], errors: [{ messageId: 'nextLineClose' }], }, { - code: `if (a) { \nb();\n } \n else { \nc();\n }`, - output: `if (a) { \nb();\n } else { \nc();\n }`, + code: 'if (a) { \nb();\n } \n else { \nc();\n }', + output: 'if (a) { \nb();\n } else { \nc();\n }', options: ['1tbs', { allowSingleLine: true }], errors: [{ messageId: 'nextLineClose' }], }, { - code: `try { \n bar(); \n }\ncatch (e) {\n} finally {\n}`, - output: `try { \n bar(); \n }\ncatch (e) {\n}\n finally {\n}`, + code: 'try { \n bar(); \n }\ncatch (e) {\n} finally {\n}', + output: 'try { \n bar(); \n }\ncatch (e) {\n}\n finally {\n}', options: ['stroustrup', { allowSingleLine: true }], errors: [{ messageId: 'sameLineClose' }], }, { - code: `try { \n bar(); \n } catch (e) {\n}\n finally {\n}`, - output: `try { \n bar(); \n }\n catch (e) {\n}\n finally {\n}`, + code: 'try { \n bar(); \n } catch (e) {\n}\n finally {\n}', + output: 'try { \n bar(); \n }\n catch (e) {\n}\n finally {\n}', options: ['stroustrup', { allowSingleLine: true }], errors: [{ messageId: 'sameLineClose' }], }, { - code: `if (a) { \nb();\n } else { \nc();\n }`, - output: `if (a) { \nb();\n }\n else { \nc();\n }`, + code: 'if (a) { \nb();\n } else { \nc();\n }', + output: 'if (a) { \nb();\n }\n else { \nc();\n }', options: ['stroustrup', { allowSingleLine: true }], errors: [{ messageId: 'sameLineClose' }], }, { - code: `if (foo)\n{ poop();\n} \nelse if (bar) {\nbaz();\n} else if (thing) {\nboom();\n}\nelse {\nqux();\n}`, - output: `if (foo)\n{\n poop();\n} \nelse if (bar) \n{\nbaz();\n}\n else if (thing) \n{\nboom();\n}\nelse \n{\nqux();\n}`, + code: + 'if (foo)\n{ poop();\n} \nelse if (bar) {\nbaz();\n} else if (thing) {\nboom();\n}\nelse {\nqux();\n}', + output: + 'if (foo)\n{\n poop();\n} \nelse if (bar) \n{\nbaz();\n}\n else if (thing) \n{\nboom();\n}\nelse \n{\nqux();\n}', options: ['allman', { allowSingleLine: true }], errors: [ { messageId: 'blockSameLine' }, @@ -945,25 +961,25 @@ if (f) { }, // Comment interferes with fix { - code: `if (foo) // comment \n{\nbar();\n}`, + code: 'if (foo) // comment \n{\nbar();\n}', output: null, errors: [{ messageId: 'nextLineOpen' }], }, // https://github.com/eslint/eslint/issues/7493 { - code: `if (foo) {\n bar\n.baz }`, - output: `if (foo) {\n bar\n.baz \n}`, + code: 'if (foo) {\n bar\n.baz }', + output: 'if (foo) {\n bar\n.baz \n}', errors: [{ messageId: 'singleLineClose' }], }, { - code: `if (foo)\n{\n bar\n.baz }`, - output: `if (foo)\n{\n bar\n.baz \n}`, + code: 'if (foo)\n{\n bar\n.baz }', + output: 'if (foo)\n{\n bar\n.baz \n}', options: ['allman'], errors: [{ messageId: 'singleLineClose' }], }, { - code: `if (foo) { bar\n.baz }`, - output: `if (foo) {\n bar\n.baz \n}`, + code: 'if (foo) { bar\n.baz }', + output: 'if (foo) {\n bar\n.baz \n}', options: ['1tbs', { allowSingleLine: true }], errors: [ { messageId: 'blockSameLine' }, @@ -971,8 +987,8 @@ if (f) { ], }, { - code: `if (foo) { bar\n.baz }`, - output: `if (foo) \n{\n bar\n.baz \n}`, + code: 'if (foo) { bar\n.baz }', + output: 'if (foo) \n{\n bar\n.baz \n}', options: ['allman', { allowSingleLine: true }], errors: [ { messageId: 'sameLineOpen' }, @@ -981,46 +997,46 @@ if (f) { ], }, { - code: `switch (x) {\n case 1: foo() }`, - output: `switch (x) {\n case 1: foo() \n}`, + code: 'switch (x) {\n case 1: foo() }', + output: 'switch (x) {\n case 1: foo() \n}', options: ['1tbs', { allowSingleLine: true }], errors: [{ messageId: 'singleLineClose' }], }, { - code: `class Foo\n{\n}`, - output: `class Foo {\n}`, + code: 'class Foo\n{\n}', + output: 'class Foo {\n}', errors: [{ messageId: 'nextLineOpen' }], }, { - code: `(class\n{\n})`, - output: `(class {\n})`, + code: '(class\n{\n})', + output: '(class {\n})', errors: [{ messageId: 'nextLineOpen' }], }, { - code: `class Foo{\n}`, - output: `class Foo\n{\n}`, + code: 'class Foo{\n}', + output: 'class Foo\n{\n}', options: ['allman'], errors: [{ messageId: 'sameLineOpen' }], }, { - code: `(class {\n})`, - output: `(class \n{\n})`, + code: '(class {\n})', + output: '(class \n{\n})', options: ['allman'], errors: [{ messageId: 'sameLineOpen' }], }, { - code: `class Foo {\nbar() {\n}}`, - output: `class Foo {\nbar() {\n}\n}`, + code: 'class Foo {\nbar() {\n}}', + output: 'class Foo {\nbar() {\n}\n}', errors: [{ messageId: 'singleLineClose' }], }, { - code: `(class Foo {\nbar() {\n}})`, - output: `(class Foo {\nbar() {\n}\n})`, + code: '(class Foo {\nbar() {\n}})', + output: '(class Foo {\nbar() {\n}\n})', errors: [{ messageId: 'singleLineClose' }], }, { - code: `class\nFoo{}`, - output: `class\nFoo\n{}`, + code: 'class\nFoo{}', + output: 'class\nFoo\n{}', options: ['allman'], errors: [{ messageId: 'sameLineOpen' }], }, @@ -1070,8 +1086,8 @@ interface Foo { errors: [{ messageId: 'nextLineOpen' }], }, { - code: `interface Foo { \n }`, - output: `interface Foo \n{ \n }`, + code: 'interface Foo { \n }', + output: 'interface Foo \n{ \n }', options: ['allman'], errors: [{ messageId: 'sameLineOpen' }], }, @@ -1101,8 +1117,8 @@ module "Foo" { errors: [{ messageId: 'nextLineOpen' }], }, { - code: `module "Foo" { \n }`, - output: `module "Foo" \n{ \n }`, + code: 'module "Foo" { \n }', + output: 'module "Foo" \n{ \n }', options: ['allman'], errors: [{ messageId: 'sameLineOpen' }], }, @@ -1132,8 +1148,8 @@ namespace Foo { errors: [{ messageId: 'nextLineOpen' }], }, { - code: `namespace Foo { \n }`, - output: `namespace Foo \n{ \n }`, + code: 'namespace Foo { \n }', + output: 'namespace Foo \n{ \n }', options: ['allman'], errors: [{ messageId: 'sameLineOpen' }], }, @@ -1163,8 +1179,8 @@ enum Foo { errors: [{ messageId: 'nextLineOpen' }], }, { - code: `enum Foo { A }`, - output: `enum Foo \n{\n A \n}`, + code: 'enum Foo { A }', + output: 'enum Foo \n{\n A \n}', options: ['allman'], errors: [ { messageId: 'sameLineOpen' }, diff --git a/packages/eslint-plugin/tests/rules/camelcase.test.ts b/packages/eslint-plugin/tests/rules/camelcase.test.ts index 617cdf3e40f7..1a35ee87cc82 100644 --- a/packages/eslint-plugin/tests/rules/camelcase.test.ts +++ b/packages/eslint-plugin/tests/rules/camelcase.test.ts @@ -1,5 +1,5 @@ import rule from '../../src/rules/camelcase'; -import { RuleTester } from '../RuleTester'; +import { RuleTester, noFormat } from '../RuleTester'; const ruleTester = new RuleTester({ parser: '@typescript-eslint/parser', @@ -8,75 +8,147 @@ const ruleTester = new RuleTester({ ruleTester.run('camelcase', rule, { valid: [ { - code: 'interface Foo { b_ar: number }', + code: ` +interface Foo { + b_ar: number; +} + `, options: [{ properties: 'never' }], }, { - code: 'interface Foo { bar: number }', + code: ` +interface Foo { + bar: number; +} + `, options: [{ properties: 'always' }], }, { - code: 'class Foo { b_ar: number; }', + code: ` +class Foo { + b_ar: number; +} + `, options: [{ properties: 'never' }], }, { - code: 'class Foo { bar: number; }', + code: ` +class Foo { + bar: number; +} + `, options: [{ properties: 'always' }], }, { - code: 'class Foo { b_ar: number = 0; }', + code: ` +class Foo { + b_ar: number = 0; +} + `, options: [{ properties: 'never' }], }, { - code: 'class Foo { bar: number = 0; }', + code: ` +class Foo { + bar: number = 0; +} + `, options: [{ properties: 'always' }], }, { - code: 'class Foo { constructor(private b_ar: number) {} }', + code: ` +class Foo { + constructor(private b_ar: number) {} +} + `, options: [{ properties: 'never' }], }, { - code: 'class Foo { constructor(private bar: number) {} }', + code: ` +class Foo { + constructor(private bar: number) {} +} + `, options: [{ properties: 'always' }], }, { - code: 'class Foo { constructor(private b_ar: number = 0) {} }', + code: ` +class Foo { + constructor(private b_ar: number = 0) {} +} + `, options: [{ properties: 'never' }], }, { - code: 'class Foo { constructor(private bar: number = 0) {} }', + code: ` +class Foo { + constructor(private bar: number = 0) {} +} + `, options: [{ properties: 'always' }], }, { - code: 'abstract class Foo { b_ar: number; }', + code: ` +abstract class Foo { + b_ar: number; +} + `, options: [{ properties: 'never' }], }, { - code: 'abstract class Foo { bar: number; }', + code: ` +abstract class Foo { + bar: number; +} + `, options: [{ properties: 'always' }], }, { - code: 'abstract class Foo { b_ar: number = 0; }', + code: ` +abstract class Foo { + b_ar: number = 0; +} + `, options: [{ properties: 'never' }], }, { - code: 'abstract class Foo { bar: number = 0; }', + code: ` +abstract class Foo { + bar: number = 0; +} + `, options: [{ properties: 'always' }], }, { - code: 'abstract class Foo { abstract b_ar: number; }', + code: ` +abstract class Foo { + abstract b_ar: number; +} + `, options: [{ properties: 'never' }], }, { - code: 'abstract class Foo { abstract bar: number; }', + code: ` +abstract class Foo { + abstract bar: number; +} + `, options: [{ properties: 'always' }], }, { - code: 'abstract class Foo { abstract b_ar: number = 0; }', + code: ` +abstract class Foo { + abstract b_ar: number = 0; +} + `, options: [{ properties: 'never' }], }, { - code: 'abstract class Foo { abstract bar: number = 0; }', + code: ` +abstract class Foo { + abstract bar: number = 0; +} + `, options: [{ properties: 'always' }], }, { @@ -141,19 +213,19 @@ class Foo { }, { code: ` -type Foo = {} +type Foo = {}; `, options: [{ genericType: 'always' }], }, { code: ` -type Foo = {} +type Foo = {}; `, options: [{ genericType: 'always' }], }, { code: ` -type Foo = {} +type Foo = {}; `, options: [{ genericType: 'never' }], }, @@ -183,7 +255,7 @@ class Foo { code: 'const foo = foo.bar?.foo_bar_baz;', }, { - code: 'const foo = (foo?.bar?.baz)?.foo_bar_baz;', + code: noFormat`const foo = (foo?.bar?.baz)?.foo_bar_baz;`, }, { code: 'const foo = foo_bar?.foo;', @@ -193,7 +265,11 @@ class Foo { invalid: [ { - code: 'interface Foo { b_ar: number }', + code: ` +interface Foo { + b_ar: number; +} + `, options: [{ properties: 'always' }], errors: [ { @@ -201,13 +277,17 @@ class Foo { data: { name: 'b_ar', }, - line: 1, - column: 17, + line: 3, + column: 3, }, ], }, { - code: 'class Foo { b_ar: number; }', + code: ` +class Foo { + b_ar: number; +} + `, options: [{ properties: 'always' }], errors: [ { @@ -215,13 +295,17 @@ class Foo { data: { name: 'b_ar', }, - line: 1, - column: 13, + line: 3, + column: 3, }, ], }, { - code: 'class Foo { constructor(private b_ar: number) {} }', + code: ` +class Foo { + constructor(private b_ar: number) {} +} + `, options: [{ properties: 'always' }], errors: [ { @@ -229,13 +313,17 @@ class Foo { data: { name: 'b_ar', }, - line: 1, - column: 33, + line: 3, + column: 23, }, ], }, { - code: 'class Foo { constructor(private b_ar: number = 0) {} }', + code: ` +class Foo { + constructor(private b_ar: number = 0) {} +} + `, options: [{ properties: 'always' }], errors: [ { @@ -243,13 +331,17 @@ class Foo { data: { name: 'b_ar', }, - line: 1, - column: 33, + line: 3, + column: 23, }, ], }, { - code: 'abstract class Foo { b_ar: number; }', + code: ` +abstract class Foo { + b_ar: number; +} + `, options: [{ properties: 'always' }], errors: [ { @@ -257,13 +349,17 @@ class Foo { data: { name: 'b_ar', }, - line: 1, - column: 22, + line: 3, + column: 3, }, ], }, { - code: 'abstract class Foo { b_ar: number = 0; }', + code: ` +abstract class Foo { + b_ar: number = 0; +} + `, options: [{ properties: 'always' }], errors: [ { @@ -271,13 +367,17 @@ class Foo { data: { name: 'b_ar', }, - line: 1, - column: 22, + line: 3, + column: 3, }, ], }, { - code: 'abstract class Foo { abstract b_ar: number; }', + code: ` +abstract class Foo { + abstract b_ar: number; +} + `, options: [{ properties: 'always' }], errors: [ { @@ -285,13 +385,17 @@ class Foo { data: { name: 'b_ar', }, - line: 1, - column: 31, + line: 3, + column: 12, }, ], }, { - code: 'abstract class Foo { abstract b_ar: number = 0; }', + code: ` +abstract class Foo { + abstract b_ar: number = 0; +} + `, options: [{ properties: 'always' }], errors: [ { @@ -299,8 +403,8 @@ class Foo { data: { name: 'b_ar', }, - line: 1, - column: 31, + line: 3, + column: 12, }, ], }, @@ -319,7 +423,7 @@ class Foo { ], }, { - code: 'const foo = (foo_test?.bar)?.baz;', + code: noFormat`const foo = (foo_test?.bar)?.baz;`, options: [{ properties: 'always' }], errors: [ { diff --git a/packages/eslint-plugin/tests/rules/class-literal-property-style.test.ts b/packages/eslint-plugin/tests/rules/class-literal-property-style.test.ts index f0c5f2afc055..19d5fb183b54 100644 --- a/packages/eslint-plugin/tests/rules/class-literal-property-style.test.ts +++ b/packages/eslint-plugin/tests/rules/class-literal-property-style.test.ts @@ -1,5 +1,5 @@ import rule from '../../src/rules/class-literal-property-style'; -import { RuleTester } from '../RuleTester'; +import { RuleTester, noFormat } from '../RuleTester'; const ruleTester = new RuleTester({ parser: '@typescript-eslint/parser', @@ -7,18 +7,50 @@ const ruleTester = new RuleTester({ ruleTester.run('class-literal-property-style', rule, { valid: [ - 'class Mx { declare readonly p1 = 1; }', - 'class Mx { readonly p1 = "hello world"; }', - 'class Mx { p1 = "hello world"; }', - 'class Mx { static p1 = "hello world"; }', - 'class Mx { p1: string; }', - 'class Mx { get p1(); }', - 'class Mx { get p1() {} }', - 'abstract class Mx { abstract get p1(): string }', + ` +class Mx { + declare readonly p1 = 1; +} + `, + ` +class Mx { + readonly p1 = 'hello world'; +} + `, + ` +class Mx { + p1 = 'hello world'; +} + `, + ` +class Mx { + static p1 = 'hello world'; +} + `, + ` +class Mx { + p1: string; +} + `, + ` +class Mx { + get p1(); +} + `, + ` +class Mx { + get p1() {} +} + `, + ` +abstract class Mx { + abstract get p1(): string; +} + `, ` class Mx { get mySetting() { - if(this._aValue) { + if (this._aValue) { return 'on'; } @@ -29,14 +61,14 @@ ruleTester.run('class-literal-property-style', rule, { ` class Mx { get mySetting() { - return \`build-\${process.env.build}\` + return \`build-\${process.env.build}\`; } } `, ` class Mx { getMySetting() { - if(this._aValue) { + if (this._aValue) { return 'on'; } @@ -64,31 +96,63 @@ ruleTester.run('class-literal-property-style', rule, { options: ['fields'], }, { - code: 'class Mx { declare public readonly foo = 1; }', + code: ` +class Mx { + public declare readonly foo = 1; +} + `, options: ['getters'], }, { - code: 'class Mx { get p1() { return "hello world"; } }', + code: ` +class Mx { + get p1() { + return 'hello world'; + } +} + `, options: ['getters'], }, { - code: 'class Mx { p1 = "hello world"; }', + code: ` +class Mx { + p1 = 'hello world'; +} + `, options: ['getters'], }, { - code: 'class Mx { p1: string; }', + code: ` +class Mx { + p1: string; +} + `, options: ['getters'], }, { - code: 'class Mx { readonly p1 = [1, 2, 3]; }', + code: ` +class Mx { + readonly p1 = [1, 2, 3]; +} + `, options: ['getters'], }, { - code: 'class Mx { static p1: string; }', + code: ` +class Mx { + static p1: string; +} + `, options: ['getters'], }, { - code: 'class Mx { static get p1() { return "hello world"; } }', + code: ` +class Mx { + static get p1() { + return 'hello world'; + } +} + `, options: ['getters'], }, { @@ -116,259 +180,358 @@ ruleTester.run('class-literal-property-style', rule, { ], invalid: [ { - code: 'class Mx { get p1() { return "hello world"; } }', - output: 'class Mx { readonly p1 = "hello world"; }', + code: ` +class Mx { + get p1() { + return 'hello world'; + } +} + `, + output: ` +class Mx { + readonly p1 = 'hello world'; +} + `, errors: [ { messageId: 'preferFieldStyle', - column: 16, - line: 1, + column: 7, + line: 3, }, ], }, { - code: 'class Mx { get p1() { return `hello world`; } }', - output: 'class Mx { readonly p1 = `hello world`; }', + code: ` +class Mx { + get p1() { + return \`hello world\`; + } +} + `, + output: ` +class Mx { + readonly p1 = \`hello world\`; +} + `, errors: [ { messageId: 'preferFieldStyle', - column: 16, - line: 1, + column: 7, + line: 3, }, ], }, { - code: 'class Mx { static get p1() { return "hello world"; } }', - output: 'class Mx { static readonly p1 = "hello world"; }', + code: ` +class Mx { + static get p1() { + return 'hello world'; + } +} + `, + output: ` +class Mx { + static readonly p1 = 'hello world'; +} + `, errors: [ { messageId: 'preferFieldStyle', - column: 23, - line: 1, + column: 14, + line: 3, }, ], }, { - code: - 'class Mx { public static readonly static private public protected get foo() { return 1; } }', - output: 'class Mx { public static readonly foo = 1; }', + code: ` +class Mx { + public static get foo() { + return 1; + } +} + `, + output: ` +class Mx { + public static readonly foo = 1; +} + `, errors: [ { messageId: 'preferFieldStyle', - column: 71, - line: 1, + column: 21, + line: 3, }, ], }, { code: ` - class Mx { - public get [myValue]() { - return 'a literal value'; - } - } +class Mx { + public get [myValue]() { + return 'a literal value'; + } +} `, output: ` - class Mx { - public readonly [myValue] = 'a literal value'; - } +class Mx { + public readonly [myValue] = 'a literal value'; +} `, errors: [ { messageId: 'preferFieldStyle', - column: 23, + column: 15, line: 3, }, ], }, { code: ` - class Mx { - public get [myValue]() { - return 12345n; - } - } +class Mx { + public get [myValue]() { + return 12345n; + } +} `, output: ` - class Mx { - public readonly [myValue] = 12345n; - } +class Mx { + public readonly [myValue] = 12345n; +} `, errors: [ { messageId: 'preferFieldStyle', - column: 23, + column: 15, line: 3, }, ], }, { code: ` - class Mx { - public readonly [myValue] = 'a literal value'; - } +class Mx { + public readonly [myValue] = 'a literal value'; +} `, - output: ` - class Mx { - public get [myValue]() { return 'a literal value'; } - } + output: noFormat` +class Mx { + public get [myValue]() { return 'a literal value'; } +} `, errors: [ { messageId: 'preferGetterStyle', - column: 28, + column: 20, line: 3, }, ], options: ['getters'], }, { - code: 'class Mx { readonly p1 = "hello world"; }', - output: 'class Mx { get p1() { return "hello world"; } }', + code: ` +class Mx { + readonly p1 = 'hello world'; +} + `, + output: noFormat` +class Mx { + get p1() { return 'hello world'; } +} + `, errors: [ { messageId: 'preferGetterStyle', - column: 21, - line: 1, + column: 12, + line: 3, }, ], options: ['getters'], }, { - code: 'class Mx { readonly p1 = `hello world`; }', - output: 'class Mx { get p1() { return `hello world`; } }', + code: ` +class Mx { + readonly p1 = \`hello world\`; +} + `, + output: noFormat` +class Mx { + get p1() { return \`hello world\`; } +} + `, errors: [ { messageId: 'preferGetterStyle', - column: 21, - line: 1, + column: 12, + line: 3, }, ], options: ['getters'], }, { - code: 'class Mx { static readonly p1 = "hello world"; }', - output: 'class Mx { static get p1() { return "hello world"; } }', + code: ` +class Mx { + static readonly p1 = 'hello world'; +} + `, + output: noFormat` +class Mx { + static get p1() { return 'hello world'; } +} + `, errors: [ { messageId: 'preferGetterStyle', - column: 28, - line: 1, + column: 19, + line: 3, }, ], options: ['getters'], }, { - code: 'class Mx { protected get p1() { return "hello world"; } }', - output: 'class Mx { protected readonly p1 = "hello world"; }', + code: ` +class Mx { + protected get p1() { + return 'hello world'; + } +} + `, + output: ` +class Mx { + protected readonly p1 = 'hello world'; +} + `, errors: [ { messageId: 'preferFieldStyle', - column: 26, - line: 1, + column: 17, + line: 3, }, ], options: ['fields'], }, { - code: 'class Mx { protected readonly p1 = "hello world"; }', - output: 'class Mx { protected get p1() { return "hello world"; } }', + code: ` +class Mx { + protected readonly p1 = 'hello world'; +} + `, + output: noFormat` +class Mx { + protected get p1() { return 'hello world'; } +} + `, errors: [ { messageId: 'preferGetterStyle', - column: 31, - line: 1, + column: 22, + line: 3, }, ], options: ['getters'], }, { - code: 'class Mx { public static get p1() { return "hello world"; } }', - output: 'class Mx { public static readonly p1 = "hello world"; }', + code: ` +class Mx { + public static get p1() { + return 'hello world'; + } +} + `, + output: ` +class Mx { + public static readonly p1 = 'hello world'; +} + `, errors: [ { messageId: 'preferFieldStyle', - column: 30, - line: 1, + column: 21, + line: 3, }, ], }, { - code: 'class Mx { public static readonly p1 = "hello world"; }', - output: 'class Mx { public static get p1() { return "hello world"; } }', + code: ` +class Mx { + public static readonly p1 = 'hello world'; +} + `, + output: noFormat` +class Mx { + public static get p1() { return 'hello world'; } +} + `, errors: [ { messageId: 'preferGetterStyle', - column: 35, - line: 1, + column: 26, + line: 3, }, ], options: ['getters'], }, { code: ` - class Mx { - public get myValue() { - return gql\` - { - user(id: 5) { - firstName - lastName - } - } - \`; - } +class Mx { + public get myValue() { + return gql\` + { + user(id: 5) { + firstName + lastName } + } + \`; + } +} `, - output: ` - class Mx { - public readonly myValue = gql\` - { - user(id: 5) { - firstName - lastName - } - } - \`; + output: noFormat` +class Mx { + public readonly myValue = gql\` + { + user(id: 5) { + firstName + lastName } + } + \`; +} `, errors: [ { messageId: 'preferFieldStyle', - column: 22, + column: 14, line: 3, }, ], }, { code: ` - class Mx { - public readonly myValue = gql\` - { - user(id: 5) { - firstName - lastName - } - } - \`; - } +class Mx { + public readonly myValue = gql\` + { + user(id: 5) { + firstName + lastName + } + } + \`; +} `, - output: ` - class Mx { - public get myValue() { return gql\` - { - user(id: 5) { - firstName - lastName - } - } - \`; } - } + output: noFormat` +class Mx { + public get myValue() { return gql\` + { + user(id: 5) { + firstName + lastName + } + } + \`; } +} `, errors: [ { messageId: 'preferGetterStyle', - column: 27, + column: 19, line: 3, }, ], diff --git a/packages/eslint-plugin/tests/rules/class-name-casing.test.ts b/packages/eslint-plugin/tests/rules/class-name-casing.test.ts index 11f6dc8b8889..1977a36415da 100644 --- a/packages/eslint-plugin/tests/rules/class-name-casing.test.ts +++ b/packages/eslint-plugin/tests/rules/class-name-casing.test.ts @@ -35,12 +35,19 @@ ruleTester.run('class-name-casing', rule, { 'class ÈClassNameWithUnicode {}', 'class ClassNameWithæUnicode {}', // Following test cases are valid, but no one is going to write code like this - 'var { bar } = class { static bar() { return 2 } }', - `var [ bar ] = class { - static [Symbol.iterator]() { - return { next: () => ({ value: 1, done: false}) } - } - } + ` +var { bar } = class { + static bar() { + return 2; + } +}; + `, + ` +var [bar] = class { + static [Symbol.iterator]() { + return { next: () => ({ value: 1, done: false }) }; + } +}; `, ], @@ -116,7 +123,7 @@ ruleTester.run('class-name-casing', rule, { ], }, { - code: 'var bar = class invalidName {}', + code: 'var bar = class invalidName {};', errors: [ { messageId: 'notPascalCased', diff --git a/packages/eslint-plugin/tests/rules/comma-spacing.test.ts b/packages/eslint-plugin/tests/rules/comma-spacing.test.ts index 12a6e0219f8c..7147815b7595 100644 --- a/packages/eslint-plugin/tests/rules/comma-spacing.test.ts +++ b/packages/eslint-plugin/tests/rules/comma-spacing.test.ts @@ -1,3 +1,8 @@ +/* eslint-disable eslint-comments/no-use */ +// this rule tests the spacing, which prettier will want to fix and break the tests +/* eslint "@typescript-eslint/internal/plugin-test-formatting": ["error", { formatWithPrettier: false }] */ +/* eslint-enable eslint-comments/no-use */ + import rule from '../../src/rules/comma-spacing'; import { RuleTester } from '../RuleTester'; @@ -7,280 +12,280 @@ const ruleTester = new RuleTester({ ruleTester.run('comma-spacing', rule, { valid: [ - `foo(1, true/* comment */, 'text');`, - `foo(1, true /* comment */, 'text');`, - `foo(1, true/* comment *//* comment */, 'text');`, - `foo(1, true/* comment */ /* comment */, 'text');`, - `foo(1, true, /* comment */ 'text');`, - `foo(1, // comment\n true, /* comment */ 'text');`, - { - code: `foo(1, // comment\n true,/* comment */ 'text');`, + "foo(1, true/* comment */, 'text');", + "foo(1, true /* comment */, 'text');", + "foo(1, true/* comment *//* comment */, 'text');", + "foo(1, true/* comment */ /* comment */, 'text');", + "foo(1, true, /* comment */ 'text');", + "foo(1, // comment\n true, /* comment */ 'text');", + { + code: "foo(1, // comment\n true,/* comment */ 'text');", options: [{ before: false, after: false }], }, - `const a = 1, b = 2;`, - `const foo = [, ];`, - `const foo = [1, ];`, - `const foo = [, 2];`, - `const foo = [1, 2];`, - `const foo = [, , ];`, - `const foo = [1, , ];`, - `const foo = [, 2, ];`, - `const foo = [, , 3];`, - `const foo = [1, 2, ];`, - `const foo = [, 2, 3];`, - `const foo = [1, , 3];`, - `const foo = [1, 2, 3];`, - `const foo = {'foo':'foo', 'baz':'baz'};`, - `const foo = {'foo':'foo', 'baz':\n'baz'};`, - `const foo = {'foo':\n'foo', 'baz':\n'baz'};`, - `function foo(a, b){}`, - `function foo(a, b = 1){}`, - `function foo(a = 1, b, c){}`, - `const foo = (a, b) => {}`, - `const foo = (a=1, b) => {}`, - `const foo = a => a + 2`, - `a, b`, - `const a = (1 + 2, 2)`, - `a(b, c)`, - `new A(b, c)`, - `foo((a), b)`, - `const b = ((1 + 2), 2)`, - `parseInt((a + b), 10)`, - `go.boom((a + b), 10)`, - `go.boom((a + b), 10, (4))`, - `const x = [ (a + c), (b + b) ]`, - `[' , ']`, + 'const a = 1, b = 2;', + 'const foo = [, ];', + 'const foo = [1, ];', + 'const foo = [, 2];', + 'const foo = [1, 2];', + 'const foo = [, , ];', + 'const foo = [1, , ];', + 'const foo = [, 2, ];', + 'const foo = [, , 3];', + 'const foo = [1, 2, ];', + 'const foo = [, 2, 3];', + 'const foo = [1, , 3];', + 'const foo = [1, 2, 3];', + "const foo = {'foo':'foo', 'baz':'baz'};", + "const foo = {'foo':'foo', 'baz':\n'baz'};", + "const foo = {'foo':\n'foo', 'baz':\n'baz'};", + 'function foo(a, b){}', + 'function foo(a, b = 1){}', + 'function foo(a = 1, b, c){}', + 'const foo = (a, b) => {}', + 'const foo = (a=1, b) => {}', + 'const foo = a => a + 2', + 'a, b', + 'const a = (1 + 2, 2)', + 'a(b, c)', + 'new A(b, c)', + 'foo((a), b)', + 'const b = ((1 + 2), 2)', + 'parseInt((a + b), 10)', + 'go.boom((a + b), 10)', + 'go.boom((a + b), 10, (4))', + 'const x = [ (a + c), (b + b) ]', + "[' , ']", '[` , `]', '`${[1, 2]}`', - `fn(a, b,)`, - `const fn = (a, b,) => {}`, - `const fn = function (a, b,) {}`, - `foo(/,/, 'a')`, - `const x = ',,,,,';`, - `const code = 'var foo = 1, bar = 3;'`, - `['apples', \n 'oranges'];`, - `{x: 'var x,y,z'}`, - { - code: `const foo = {'foo':\n'bar' ,'baz':\n'qur'};`, + 'fn(a, b,)', + 'const fn = (a, b,) => {}', + 'const fn = function (a, b,) {}', + "foo(/,/, 'a')", + "const x = ',,,,,';", + "const code = 'var foo = 1, bar = 3;'", + "['apples', \n 'oranges'];", + "{x: 'var x,y,z'}", + { + code: "const foo = {'foo':\n'bar' ,'baz':\n'qur'};", options: [{ before: true, after: false }], }, { - code: `const a = 1 ,b = 2;`, + code: 'const a = 1 ,b = 2;', options: [{ before: true, after: false }], }, { - code: `function foo(a ,b){}`, + code: 'function foo(a ,b){}', options: [{ before: true, after: false }], }, { - code: `const arr = [,];`, + code: 'const arr = [,];', options: [{ before: true, after: false }], }, { - code: `const arr = [1 ,];`, + code: 'const arr = [1 ,];', options: [{ before: true, after: false }], }, { - code: `const arr = [ ,2];`, + code: 'const arr = [ ,2];', options: [{ before: true, after: false }], }, { - code: `const arr = [1 ,2];`, + code: 'const arr = [1 ,2];', options: [{ before: true, after: false }], }, { - code: `const arr = [,,];`, + code: 'const arr = [,,];', options: [{ before: true, after: false }], }, { - code: `const arr = [1 , ,];`, + code: 'const arr = [1 , ,];', options: [{ before: true, after: false }], }, { - code: `const arr = [ ,2 ,];`, + code: 'const arr = [ ,2 ,];', options: [{ before: true, after: false }], }, { - code: `const arr = [ , ,3];`, + code: 'const arr = [ , ,3];', options: [{ before: true, after: false }], }, { - code: `const arr = [1 ,2 ,];`, + code: 'const arr = [1 ,2 ,];', options: [{ before: true, after: false }], }, { - code: `const arr = [ ,2 ,3];`, + code: 'const arr = [ ,2 ,3];', options: [{ before: true, after: false }], }, { - code: `const arr = [1 , ,3];`, + code: 'const arr = [1 , ,3];', options: [{ before: true, after: false }], }, { - code: `const arr = [1 ,2 ,3];`, + code: 'const arr = [1 ,2 ,3];', options: [{ before: true, after: false }], }, { - code: `const obj = {'foo':'bar' , 'baz':'qur'};`, + code: "const obj = {'foo':'bar' , 'baz':'qur'};", options: [{ before: true, after: true }], }, { - code: `const a = 1 , b = 2;`, + code: 'const a = 1 , b = 2;', options: [{ before: true, after: true }], }, { - code: `const arr = [, ];`, + code: 'const arr = [, ];', options: [{ before: true, after: true }], }, { - code: `const arr = [1 , ];`, + code: 'const arr = [1 , ];', options: [{ before: true, after: true }], }, { - code: `const arr = [ , 2];`, + code: 'const arr = [ , 2];', options: [{ before: true, after: true }], }, { - code: `const arr = [1 , 2];`, + code: 'const arr = [1 , 2];', options: [{ before: true, after: true }], }, { - code: `const arr = [, , ];`, + code: 'const arr = [, , ];', options: [{ before: true, after: true }], }, { - code: `const arr = [1 , , ];`, + code: 'const arr = [1 , , ];', options: [{ before: true, after: true }], }, { - code: `const arr = [ , 2 , ];`, + code: 'const arr = [ , 2 , ];', options: [{ before: true, after: true }], }, { - code: `const arr = [ , , 3];`, + code: 'const arr = [ , , 3];', options: [{ before: true, after: true }], }, { - code: `const arr = [1 , 2 , ];`, + code: 'const arr = [1 , 2 , ];', options: [{ before: true, after: true }], }, { - code: `const arr = [, 2 , 3];`, + code: 'const arr = [, 2 , 3];', options: [{ before: true, after: true }], }, { - code: `const arr = [1 , , 3];`, + code: 'const arr = [1 , , 3];', options: [{ before: true, after: true }], }, { - code: `const arr = [1 , 2 , 3];`, + code: 'const arr = [1 , 2 , 3];', options: [{ before: true, after: true }], }, { - code: `a , b`, + code: 'a , b', options: [{ before: true, after: true }], }, { - code: `const arr = [,];`, + code: 'const arr = [,];', options: [{ before: false, after: false }], }, { - code: `const arr = [ ,];`, + code: 'const arr = [ ,];', options: [{ before: false, after: false }], }, { - code: `const arr = [1,];`, + code: 'const arr = [1,];', options: [{ before: false, after: false }], }, { - code: `const arr = [,2];`, + code: 'const arr = [,2];', options: [{ before: false, after: false }], }, { - code: `const arr = [ ,2];`, + code: 'const arr = [ ,2];', options: [{ before: false, after: false }], }, { - code: `const arr = [1,2];`, + code: 'const arr = [1,2];', options: [{ before: false, after: false }], }, { - code: `const arr = [,,];`, + code: 'const arr = [,,];', options: [{ before: false, after: false }], }, { - code: `const arr = [ ,,];`, + code: 'const arr = [ ,,];', options: [{ before: false, after: false }], }, { - code: `const arr = [1,,];`, + code: 'const arr = [1,,];', options: [{ before: false, after: false }], }, { - code: `const arr = [,2,];`, + code: 'const arr = [,2,];', options: [{ before: false, after: false }], }, { - code: `const arr = [ ,2,];`, + code: 'const arr = [ ,2,];', options: [{ before: false, after: false }], }, { - code: `const arr = [,,3];`, + code: 'const arr = [,,3];', options: [{ before: false, after: false }], }, { - code: `const arr = [1,2,];`, + code: 'const arr = [1,2,];', options: [{ before: false, after: false }], }, { - code: `const arr = [,2,3];`, + code: 'const arr = [,2,3];', options: [{ before: false, after: false }], }, { - code: `const arr = [1,,3];`, + code: 'const arr = [1,,3];', options: [{ before: false, after: false }], }, { - code: `const arr = [1,2,3];`, + code: 'const arr = [1,2,3];', options: [{ before: false, after: false }], }, { - code: `const a = (1 + 2,2)`, + code: 'const a = (1 + 2,2)', options: [{ before: false, after: false }], }, 'const a; console.log(`${a}`, "a");', - `const [a, b] = [1, 2];`, - `const [a, b, ] = [1, 2];`, - `const [a, , b] = [1, 2, 3];`, - `const [ , b] = a;`, - `const [, b] = a;`, + 'const [a, b] = [1, 2];', + 'const [a, b, ] = [1, 2];', + 'const [a, , b] = [1, 2, 3];', + 'const [ , b] = a;', + 'const [, b] = a;', { - code: `,`, + code: ',', parserOptions: { ecmaFeatures: { jsx: true }, }, }, { - code: ` , `, + code: ' , ', parserOptions: { ecmaFeatures: { jsx: true }, }, }, { - code: `Hello, world`, + code: 'Hello, world', options: [{ before: true, after: false }], parserOptions: { ecmaFeatures: { jsx: true } }, }, - `const Foo = (foo: T) => {}`, - `function foo() {}`, - `class Foo {}`, - `interface Foo{}`, + 'const Foo = (foo: T) => {}', + 'function foo() {}', + 'class Foo {}', + 'interface Foo{}', ], invalid: [ { - code: `a(b,c)`, - output: `a(b , c)`, + code: 'a(b,c)', + output: 'a(b , c)', options: [{ before: true, after: true }], errors: [ { @@ -298,8 +303,8 @@ ruleTester.run('comma-spacing', rule, { ], }, { - code: `new A(b,c)`, - output: `new A(b , c)`, + code: 'new A(b,c)', + output: 'new A(b , c)', options: [{ before: true, after: true }], errors: [ { @@ -317,8 +322,8 @@ ruleTester.run('comma-spacing', rule, { ], }, { - code: `const a = 1 ,b = 2;`, - output: `const a = 1, b = 2;`, + code: 'const a = 1 ,b = 2;', + output: 'const a = 1, b = 2;', errors: [ { messageId: 'unexpected', @@ -335,8 +340,8 @@ ruleTester.run('comma-spacing', rule, { ], }, { - code: `const arr = [1 , 2];`, - output: `const arr = [1, 2];`, + code: 'const arr = [1 , 2];', + output: 'const arr = [1, 2];', errors: [ { messageId: 'unexpected', @@ -359,8 +364,8 @@ ruleTester.run('comma-spacing', rule, { ], }, { - code: `const arr = [1 , ];`, - output: `const arr = [1 ,];`, + code: 'const arr = [1 , ];', + output: 'const arr = [1 ,];', options: [{ before: true, after: false }], errors: [ { @@ -372,8 +377,8 @@ ruleTester.run('comma-spacing', rule, { ], }, { - code: `const arr = [1 ,2];`, - output: `const arr = [1, 2];`, + code: 'const arr = [1 ,2];', + output: 'const arr = [1, 2];', errors: [ { messageId: 'unexpected', @@ -390,8 +395,8 @@ ruleTester.run('comma-spacing', rule, { ], }, { - code: `const arr = [(1) , 2];`, - output: `const arr = [(1), 2];`, + code: 'const arr = [(1) , 2];', + output: 'const arr = [(1), 2];', errors: [ { messageId: 'unexpected', @@ -402,8 +407,8 @@ ruleTester.run('comma-spacing', rule, { ], }, { - code: `const arr = [1, 2];`, - output: `const arr = [1 ,2];`, + code: 'const arr = [1, 2];', + output: 'const arr = [1 ,2];', options: [{ before: true, after: false }], errors: [ { @@ -421,8 +426,8 @@ ruleTester.run('comma-spacing', rule, { ], }, { - code: `const arr = [1\n , 2];`, - output: `const arr = [1\n ,2];`, + code: 'const arr = [1\n , 2];', + output: 'const arr = [1\n ,2];', options: [{ before: false, after: false }], errors: [ { @@ -434,8 +439,8 @@ ruleTester.run('comma-spacing', rule, { ], }, { - code: `const arr = [1,\n 2];`, - output: `const arr = [1 ,\n 2];`, + code: 'const arr = [1,\n 2];', + output: 'const arr = [1 ,\n 2];', options: [{ before: true, after: false }], errors: [ { @@ -447,8 +452,8 @@ ruleTester.run('comma-spacing', rule, { ], }, { - code: `const obj = {'foo':\n'bar', 'baz':\n'qur'};`, - output: `const obj = {'foo':\n'bar' ,'baz':\n'qur'};`, + code: "const obj = {'foo':\n'bar', 'baz':\n'qur'};", + output: "const obj = {'foo':\n'bar' ,'baz':\n'qur'};", options: [{ before: true, after: false }], errors: [ { @@ -466,8 +471,8 @@ ruleTester.run('comma-spacing', rule, { ], }, { - code: `const obj = {a: 1\n ,b: 2};`, - output: `const obj = {a: 1\n , b: 2};`, + code: 'const obj = {a: 1\n ,b: 2};', + output: 'const obj = {a: 1\n , b: 2};', options: [{ before: false, after: true }], errors: [ { @@ -479,8 +484,8 @@ ruleTester.run('comma-spacing', rule, { ], }, { - code: `const obj = {a: 1 ,\n b: 2};`, - output: `const obj = {a: 1,\n b: 2};`, + code: 'const obj = {a: 1 ,\n b: 2};', + output: 'const obj = {a: 1,\n b: 2};', options: [{ before: false, after: false }], errors: [ { @@ -492,8 +497,8 @@ ruleTester.run('comma-spacing', rule, { ], }, { - code: `const arr = [1 ,2];`, - output: `const arr = [1 , 2];`, + code: 'const arr = [1 ,2];', + output: 'const arr = [1 , 2];', options: [{ before: true, after: true }], errors: [ { @@ -505,8 +510,8 @@ ruleTester.run('comma-spacing', rule, { ], }, { - code: `const arr = [1,2];`, - output: `const arr = [1 , 2];`, + code: 'const arr = [1,2];', + output: 'const arr = [1 , 2];', options: [{ before: true, after: true }], errors: [ { @@ -524,8 +529,8 @@ ruleTester.run('comma-spacing', rule, { ], }, { - code: `const obj = {'foo':\n'bar','baz':\n'qur'};`, - output: `const obj = {'foo':\n'bar' , 'baz':\n'qur'};`, + code: "const obj = {'foo':\n'bar','baz':\n'qur'};", + output: "const obj = {'foo':\n'bar' , 'baz':\n'qur'};", options: [{ before: true, after: true }], errors: [ { @@ -543,8 +548,8 @@ ruleTester.run('comma-spacing', rule, { ], }, { - code: `const arr = [1 , 2];`, - output: `const arr = [1,2];`, + code: 'const arr = [1 , 2];', + output: 'const arr = [1,2];', options: [{ before: false, after: false }], errors: [ { @@ -562,8 +567,8 @@ ruleTester.run('comma-spacing', rule, { ], }, { - code: `a ,b`, - output: `a, b`, + code: 'a ,b', + output: 'a, b', options: [{ before: false, after: true }], errors: [ { @@ -581,8 +586,8 @@ ruleTester.run('comma-spacing', rule, { ], }, { - code: `function foo(a,b){}`, - output: `function foo(a , b){}`, + code: 'function foo(a,b){}', + output: 'function foo(a , b){}', options: [{ before: true, after: true }], errors: [ { @@ -600,8 +605,8 @@ ruleTester.run('comma-spacing', rule, { ], }, { - code: `const foo = (a,b) => {}`, - output: `const foo = (a , b) => {}`, + code: 'const foo = (a,b) => {}', + output: 'const foo = (a , b) => {}', options: [{ before: true, after: true }], errors: [ { @@ -619,8 +624,8 @@ ruleTester.run('comma-spacing', rule, { ], }, { - code: `const foo = (a = 1,b) => {}`, - output: `const foo = (a = 1 , b) => {}`, + code: 'const foo = (a = 1,b) => {}', + output: 'const foo = (a = 1 , b) => {}', options: [{ before: true, after: true }], errors: [ { @@ -638,8 +643,8 @@ ruleTester.run('comma-spacing', rule, { ], }, { - code: `function foo(a = 1 ,b = 2) {}`, - output: `function foo(a = 1, b = 2) {}`, + code: 'function foo(a = 1 ,b = 2) {}', + output: 'function foo(a = 1, b = 2) {}', options: [{ before: false, after: true }], errors: [ { @@ -657,8 +662,8 @@ ruleTester.run('comma-spacing', rule, { ], }, { - code: `{foo(1 ,2)}`, - output: `{foo(1, 2)}`, + code: '{foo(1 ,2)}', + output: '{foo(1, 2)}', parserOptions: { ecmaFeatures: { jsx: true }, }, @@ -678,8 +683,8 @@ ruleTester.run('comma-spacing', rule, { ], }, { - code: `foo(1, true/* comment */ , 'foo');`, - output: `foo(1, true/* comment */, 'foo');`, + code: "foo(1, true/* comment */ , 'foo');", + output: "foo(1, true/* comment */, 'foo');", errors: [ { messageId: 'unexpected', @@ -690,8 +695,8 @@ ruleTester.run('comma-spacing', rule, { ], }, { - code: `foo(1, true,/* comment */ 'foo');`, - output: `foo(1, true, /* comment */ 'foo');`, + code: "foo(1, true,/* comment */ 'foo');", + output: "foo(1, true, /* comment */ 'foo');", errors: [ { messageId: 'missing', @@ -702,8 +707,8 @@ ruleTester.run('comma-spacing', rule, { ], }, { - code: `foo(404,// comment\n true, 'hello');`, - output: `foo(404, // comment\n true, 'hello');`, + code: "foo(404,// comment\n true, 'hello');", + output: "foo(404, // comment\n true, 'hello');", errors: [ { messageId: 'missing', @@ -714,8 +719,8 @@ ruleTester.run('comma-spacing', rule, { ], }, { - code: `function Foo() {}`, - output: `function Foo() {}`, + code: 'function Foo() {}', + output: 'function Foo() {}', errors: [ { messageId: 'missing', @@ -726,8 +731,8 @@ ruleTester.run('comma-spacing', rule, { ], }, { - code: `function Foo() {}`, - output: `function Foo() {}`, + code: 'function Foo() {}', + output: 'function Foo() {}', errors: [ { messageId: 'unexpected', @@ -738,8 +743,8 @@ ruleTester.run('comma-spacing', rule, { ], }, { - code: `function Foo() {}`, - output: `function Foo() {}`, + code: 'function Foo() {}', + output: 'function Foo() {}', errors: [ { messageId: 'unexpected', @@ -756,8 +761,8 @@ ruleTester.run('comma-spacing', rule, { ], }, { - code: `function Foo() {}`, - output: `function Foo() {}`, + code: 'function Foo() {}', + output: 'function Foo() {}', options: [{ before: false, after: false }], errors: [ { @@ -769,8 +774,8 @@ ruleTester.run('comma-spacing', rule, { ], }, { - code: `function Foo() {}`, - output: `function Foo() {}`, + code: 'function Foo() {}', + output: 'function Foo() {}', options: [{ before: true, after: false }], errors: [ { diff --git a/packages/eslint-plugin/tests/rules/consistent-type-definitions.test.ts b/packages/eslint-plugin/tests/rules/consistent-type-definitions.test.ts index b777a1fc68f7..78e5d3ceb018 100644 --- a/packages/eslint-plugin/tests/rules/consistent-type-definitions.test.ts +++ b/packages/eslint-plugin/tests/rules/consistent-type-definitions.test.ts @@ -1,5 +1,5 @@ import rule from '../../src/rules/consistent-type-definitions'; -import { RuleTester } from '../RuleTester'; +import { RuleTester, noFormat } from '../RuleTester'; const ruleTester = new RuleTester({ parser: '@typescript-eslint/parser', @@ -8,58 +8,62 @@ const ruleTester = new RuleTester({ ruleTester.run('consistent-type-definitions', rule, { valid: [ { - code: `var foo = { };`, + code: 'var foo = {};', options: ['interface'], }, { - code: `interface A {}`, + code: 'interface A {}', options: ['interface'], }, { - code: `interface A extends B { x: number; }`, + code: ` +interface A extends B { + x: number; +} + `, options: ['interface'], }, { - code: `type U = string;`, + code: 'type U = string;', options: ['interface'], }, { - code: `type V = { x: number; } | { y: string; };`, + code: 'type V = { x: number } | { y: string };', options: ['interface'], }, { code: ` type Record = { - [K in T]: U; -} -`, + [K in T]: U; +}; + `, options: ['interface'], }, { - code: `type T = { x: number; }`, + code: 'type T = { x: number };', options: ['type'], }, { - code: `type A = { x: number; } & B & C;`, + code: 'type A = { x: number } & B & C;', options: ['type'], }, { - code: `type A = { x: number; } & B & C;`, + code: 'type A = { x: number } & B & C;', options: ['type'], }, { code: ` export type W = { - x: T, + x: T; }; -`, + `, options: ['type'], }, ], invalid: [ { - code: `type T = { x: number; };`, - output: `interface T { x: number; }`, + code: noFormat`type T = { x: number; };`, + output: noFormat`interface T { x: number; }`, options: ['interface'], errors: [ { @@ -70,8 +74,8 @@ export type W = { ], }, { - code: `type T={ x: number; };`, - output: `interface T { x: number; }`, + code: noFormat`type T={ x: number; };`, + output: noFormat`interface T { x: number; }`, options: ['interface'], errors: [ { @@ -82,8 +86,8 @@ export type W = { ], }, { - code: `type T= { x: number; };`, - output: `interface T { x: number; }`, + code: noFormat`type T= { x: number; };`, + output: noFormat`interface T { x: number; }`, options: ['interface'], errors: [ { @@ -96,14 +100,14 @@ export type W = { { code: ` export type W = { - x: T, + x: T; }; -`, + `, output: ` export interface W { - x: T, + x: T; } -`, + `, options: ['interface'], errors: [ { @@ -114,8 +118,8 @@ export interface W { ], }, { - code: `interface T { x: number; }`, - output: `type T = { x: number; }`, + code: noFormat`interface T { x: number; }`, + output: noFormat`type T = { x: number; }`, options: ['type'], errors: [ { @@ -126,8 +130,8 @@ export interface W { ], }, { - code: `interface T{ x: number; }`, - output: `type T = { x: number; }`, + code: noFormat`interface T{ x: number; }`, + output: noFormat`type T = { x: number; }`, options: ['type'], errors: [ { @@ -138,8 +142,8 @@ export interface W { ], }, { - code: `interface T { x: number; }`, - output: `type T = { x: number; }`, + code: noFormat`interface T { x: number; }`, + output: noFormat`type T = { x: number; }`, options: ['type'], errors: [ { @@ -150,8 +154,8 @@ export interface W { ], }, { - code: `interface A extends B, C { x: number; };`, - output: `type A = { x: number; } & B & C;`, + code: noFormat`interface A extends B, C { x: number; };`, + output: noFormat`type A = { x: number; } & B & C;`, options: ['type'], errors: [ { @@ -162,8 +166,8 @@ export interface W { ], }, { - code: `interface A extends B, C { x: number; };`, - output: `type A = { x: number; } & B & C;`, + code: noFormat`interface A extends B, C { x: number; };`, + output: noFormat`type A = { x: number; } & B & C;`, options: ['type'], errors: [ { @@ -176,14 +180,14 @@ export interface W { { code: ` export interface W { - x: T, -}; -`, - output: ` + x: T; +} + `, + output: noFormat` export type W = { - x: T, -}; -`, + x: T; +} + `, options: ['type'], errors: [ { diff --git a/packages/eslint-plugin/tests/rules/default-param-last.test.ts b/packages/eslint-plugin/tests/rules/default-param-last.test.ts index d965df3c77fa..76e23bbe8a78 100644 --- a/packages/eslint-plugin/tests/rules/default-param-last.test.ts +++ b/packages/eslint-plugin/tests/rules/default-param-last.test.ts @@ -19,29 +19,29 @@ ruleTester.run('default-param-last', rule, { 'function foo(a: number, b?: number, c = 1) {}', 'function foo(a: number, b = 1, ...c) {}', - 'const foo = function () {}', - 'const foo = function (a: number) {}', - 'const foo = function (a = 1) {}', - 'const foo = function (a?: number) {}', - 'const foo = function (a: number, b: number) {}', - 'const foo = function (a: number, b: number, c?: number) {}', - 'const foo = function (a: number, b = 1) {}', - 'const foo = function (a: number, b = 1, c = 1) {}', - 'const foo = function (a: number, b = 1, c?: number) {}', - 'const foo = function (a: number, b?: number, c = 1) {}', - 'const foo = function (a: number, b = 1, ...c) {}', + 'const foo = function() {};', + 'const foo = function(a: number) {};', + 'const foo = function(a = 1) {};', + 'const foo = function(a?: number) {};', + 'const foo = function(a: number, b: number) {};', + 'const foo = function(a: number, b: number, c?: number) {};', + 'const foo = function(a: number, b = 1) {};', + 'const foo = function(a: number, b = 1, c = 1) {};', + 'const foo = function(a: number, b = 1, c?: number) {};', + 'const foo = function(a: number, b?: number, c = 1) {};', + 'const foo = function(a: number, b = 1, ...c) {};', - 'const foo = () => {}', - 'const foo = (a: number) => {}', - 'const foo = (a = 1) => {}', - 'const foo = (a?: number) => {}', - 'const foo = (a: number, b: number) => {}', - 'const foo = (a: number, b: number, c?: number) => {}', - 'const foo = (a: number, b = 1) => {}', - 'const foo = (a: number, b = 1, c = 1) => {}', - 'const foo = (a: number, b = 1, c?: number) => {}', - 'const foo = (a: number, b?: number, c = 1) => {}', - 'const foo = (a: number, b = 1, ...c) => {}', + 'const foo = () => {};', + 'const foo = (a: number) => {};', + 'const foo = (a = 1) => {};', + 'const foo = (a?: number) => {};', + 'const foo = (a: number, b: number) => {};', + 'const foo = (a: number, b: number, c?: number) => {};', + 'const foo = (a: number, b = 1) => {};', + 'const foo = (a: number, b = 1, c = 1) => {};', + 'const foo = (a: number, b = 1, c?: number) => {};', + 'const foo = (a: number, b?: number, c = 1) => {};', + 'const foo = (a: number, b = 1, ...c) => {};', ` class Foo { constructor(a: number, b: number, c: number) {} @@ -251,7 +251,7 @@ class Foo { ], }, { - code: 'const foo = function(a = 1, b: number) {}', + code: 'const foo = function(a = 1, b: number) {};', errors: [ { messageId: 'shouldBeLast', @@ -262,7 +262,7 @@ class Foo { ], }, { - code: 'const foo = function(a = 1, b = 2, c: number) {}', + code: 'const foo = function(a = 1, b = 2, c: number) {};', errors: [ { messageId: 'shouldBeLast', @@ -279,7 +279,7 @@ class Foo { ], }, { - code: 'const foo = function(a = 1, b: number, c = 2, d: number) {}', + code: 'const foo = function(a = 1, b: number, c = 2, d: number) {};', errors: [ { messageId: 'shouldBeLast', @@ -296,7 +296,7 @@ class Foo { ], }, { - code: 'const foo = function(a = 1, b: number, c = 2) {}', + code: 'const foo = function(a = 1, b: number, c = 2) {};', errors: [ { messageId: 'shouldBeLast', @@ -307,7 +307,7 @@ class Foo { ], }, { - code: 'const foo = function(a = 1, b: number, ...c) {}', + code: 'const foo = function(a = 1, b: number, ...c) {};', errors: [ { messageId: 'shouldBeLast', @@ -318,7 +318,7 @@ class Foo { ], }, { - code: 'const foo = function(a?: number, b: number) {}', + code: 'const foo = function(a?: number, b: number) {};', errors: [ { messageId: 'shouldBeLast', @@ -329,7 +329,7 @@ class Foo { ], }, { - code: 'const foo = function(a: number, b?: number, c: number) {}', + code: 'const foo = function(a: number, b?: number, c: number) {};', errors: [ { messageId: 'shouldBeLast', @@ -340,7 +340,7 @@ class Foo { ], }, { - code: 'const foo = function(a = 1, b?: number, c: number) {}', + code: 'const foo = function(a = 1, b?: number, c: number) {};', errors: [ { messageId: 'shouldBeLast', @@ -357,7 +357,7 @@ class Foo { ], }, { - code: 'const foo = function(a = 1, { b }) {}', + code: 'const foo = function(a = 1, { b }) {};', errors: [ { messageId: 'shouldBeLast', @@ -368,7 +368,7 @@ class Foo { ], }, { - code: 'const foo = function({ a } = {}, b) {}', + code: 'const foo = function({ a } = {}, b) {};', errors: [ { messageId: 'shouldBeLast', @@ -379,7 +379,7 @@ class Foo { ], }, { - code: 'const foo = function({ a, b } = { a: 1, b: 2 }, c) {}', + code: 'const foo = function({ a, b } = { a: 1, b: 2 }, c) {};', errors: [ { messageId: 'shouldBeLast', @@ -390,7 +390,7 @@ class Foo { ], }, { - code: 'const foo = function([a] = [], b) {}', + code: 'const foo = function([a] = [], b) {};', errors: [ { messageId: 'shouldBeLast', @@ -401,7 +401,7 @@ class Foo { ], }, { - code: 'const foo = function([a, b] = [1, 2], c) {}', + code: 'const foo = function([a, b] = [1, 2], c) {};', errors: [ { messageId: 'shouldBeLast', @@ -412,7 +412,7 @@ class Foo { ], }, { - code: 'const foo = (a = 1, b: number) => {}', + code: 'const foo = (a = 1, b: number) => {};', errors: [ { messageId: 'shouldBeLast', @@ -423,7 +423,7 @@ class Foo { ], }, { - code: 'const foo = (a = 1, b = 2, c: number) => {}', + code: 'const foo = (a = 1, b = 2, c: number) => {};', errors: [ { messageId: 'shouldBeLast', @@ -440,7 +440,7 @@ class Foo { ], }, { - code: 'const foo = (a = 1, b: number, c = 2, d: number) => {}', + code: 'const foo = (a = 1, b: number, c = 2, d: number) => {};', errors: [ { messageId: 'shouldBeLast', @@ -457,7 +457,7 @@ class Foo { ], }, { - code: 'const foo = (a = 1, b: number, c = 2) => {}', + code: 'const foo = (a = 1, b: number, c = 2) => {};', errors: [ { messageId: 'shouldBeLast', @@ -468,7 +468,7 @@ class Foo { ], }, { - code: 'const foo = (a = 1, b: number, ...c) => {}', + code: 'const foo = (a = 1, b: number, ...c) => {};', errors: [ { messageId: 'shouldBeLast', @@ -479,7 +479,7 @@ class Foo { ], }, { - code: 'const foo = (a?: number, b: number) => {}', + code: 'const foo = (a?: number, b: number) => {};', errors: [ { messageId: 'shouldBeLast', @@ -490,7 +490,7 @@ class Foo { ], }, { - code: 'const foo = (a: number, b?: number, c: number) => {}', + code: 'const foo = (a: number, b?: number, c: number) => {};', errors: [ { messageId: 'shouldBeLast', @@ -501,7 +501,7 @@ class Foo { ], }, { - code: 'const foo = (a = 1, b?: number, c: number) => {}', + code: 'const foo = (a = 1, b?: number, c: number) => {};', errors: [ { messageId: 'shouldBeLast', @@ -518,7 +518,7 @@ class Foo { ], }, { - code: 'const foo = (a = 1, { b }) => {}', + code: 'const foo = (a = 1, { b }) => {};', errors: [ { messageId: 'shouldBeLast', @@ -529,7 +529,7 @@ class Foo { ], }, { - code: 'const foo = ({ a } = {}, b) => {}', + code: 'const foo = ({ a } = {}, b) => {};', errors: [ { messageId: 'shouldBeLast', @@ -540,7 +540,7 @@ class Foo { ], }, { - code: 'const foo = ({ a, b } = { a: 1, b: 2 }, c) => {}', + code: 'const foo = ({ a, b } = { a: 1, b: 2 }, c) => {};', errors: [ { messageId: 'shouldBeLast', @@ -551,7 +551,7 @@ class Foo { ], }, { - code: 'const foo = ([a] = [], b) => {}', + code: 'const foo = ([a] = [], b) => {};', errors: [ { messageId: 'shouldBeLast', @@ -562,7 +562,7 @@ class Foo { ], }, { - code: 'const foo = ([a, b] = [1, 2], c) => {}', + code: 'const foo = ([a, b] = [1, 2], c) => {};', errors: [ { messageId: 'shouldBeLast', diff --git a/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts b/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts index fb353eec1a37..46ab49441858 100644 --- a/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts +++ b/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts @@ -11,23 +11,23 @@ ruleTester.run('explicit-function-return-type', rule, { filename: 'test.ts', code: ` function test(): void { - return; + return; } - `, + `, }, { filename: 'test.ts', code: ` var fn = function(): number { - return 1; + return 1; }; - `, + `, }, { filename: 'test.ts', code: ` var arrowFn = (): string => 'test'; - `, + `, }, { filename: 'test.ts', @@ -43,11 +43,11 @@ class Test { } arrow = (): string => 'arrow'; } - `, + `, }, { filename: 'test.ts', - code: `fn(() => {});`, + code: 'fn(() => {});', options: [ { allowExpressions: true, @@ -56,7 +56,7 @@ class Test { }, { filename: 'test.ts', - code: `fn(function() {});`, + code: 'fn(function() {});', options: [ { allowExpressions: true, @@ -65,7 +65,7 @@ class Test { }, { filename: 'test.ts', - code: `[function() {}, () => {}]`, + code: '[function() {}, () => {}];', options: [ { allowExpressions: true, @@ -74,7 +74,7 @@ class Test { }, { filename: 'test.ts', - code: `(function() {});`, + code: '(function() {});', options: [ { allowExpressions: true, @@ -83,7 +83,7 @@ class Test { }, { filename: 'test.ts', - code: `(() => {})();`, + code: '(() => {})();', options: [ { allowExpressions: true, @@ -92,7 +92,7 @@ class Test { }, { filename: 'test.ts', - code: `export default (): void => {}`, + code: 'export default (): void => {};', options: [ { allowExpressions: true, @@ -103,7 +103,7 @@ class Test { filename: 'test.ts', code: ` var arrowFn: Foo = () => 'test'; - `, + `, options: [ { allowTypedFunctionExpressions: true, @@ -113,8 +113,10 @@ var arrowFn: Foo = () => 'test'; { filename: 'test.ts', code: ` -var funcExpr: Foo = function() { return 'test'; }; - `, +var funcExpr: Foo = function() { + return 'test'; +}; + `, options: [ { allowTypedFunctionExpressions: true, @@ -123,12 +125,12 @@ var funcExpr: Foo = function() { return 'test'; }; }, { filename: 'test.ts', - code: `const x = (() => {}) as Foo`, + code: 'const x = (() => {}) as Foo;', options: [{ allowTypedFunctionExpressions: true }], }, { filename: 'test.ts', - code: `const x = (() => {})`, + code: 'const x = (() => {});', options: [{ allowTypedFunctionExpressions: true }], }, { @@ -136,7 +138,7 @@ var funcExpr: Foo = function() { return 'test'; }; code: ` const x = { foo: () => {}, -} as Foo +} as Foo; `, options: [{ allowTypedFunctionExpressions: true }], }, @@ -145,7 +147,7 @@ const x = { code: ` const x = { foo: () => {}, -} +}; `, options: [{ allowTypedFunctionExpressions: true }], }, @@ -154,7 +156,7 @@ const x = { code: ` const x: Foo = { foo: () => {}, -} +}; `, options: [{ allowTypedFunctionExpressions: true }], }, @@ -165,7 +167,7 @@ const x: Foo = { type MethodType = () => void; class App { - private method: MethodType = () => {} + private method: MethodType = () => {}; } `, options: [{ allowTypedFunctionExpressions: true }], @@ -185,42 +187,50 @@ const myObj = { filename: 'test.ts', code: ` () => (): void => {}; - `, + `, options: [{ allowHigherOrderFunctions: true }], }, { filename: 'test.ts', code: ` -() => function (): void {}; - `, +() => function(): void {}; + `, options: [{ allowHigherOrderFunctions: true }], }, { filename: 'test.ts', code: ` -() => { return (): void => {} }; - `, +() => { + return (): void => {}; +}; + `, options: [{ allowHigherOrderFunctions: true }], }, { filename: 'test.ts', code: ` -() => { return function (): void {} }; - `, +() => { + return function(): void {}; +}; + `, options: [{ allowHigherOrderFunctions: true }], }, { filename: 'test.ts', code: ` -function fn() { return (): void => {} }; - `, +function fn() { + return (): void => {}; +} + `, options: [{ allowHigherOrderFunctions: true }], }, { filename: 'test.ts', code: ` -function fn() { return function (): void {} }; - `, +function fn() { + return function(): void {}; +} + `, options: [{ allowHigherOrderFunctions: true }], }, { @@ -229,33 +239,39 @@ function fn() { return function (): void {} }; function FunctionDeclaration() { return function FunctionExpression_Within_FunctionDeclaration() { return function FunctionExpression_Within_FunctionExpression() { - return () => { // ArrowFunctionExpression_Within_FunctionExpression - return () => // ArrowFunctionExpression_Within_ArrowFunctionExpression - (): number => 1 // ArrowFunctionExpression_Within_ArrowFunctionExpression_WithNoBody - } - } - } + return () => { + // ArrowFunctionExpression_Within_FunctionExpression + return () => + // ArrowFunctionExpression_Within_ArrowFunctionExpression + (): number => 1; // ArrowFunctionExpression_Within_ArrowFunctionExpression_WithNoBody + }; + }; + }; } - `, + `, options: [{ allowHigherOrderFunctions: true }], }, { filename: 'test.ts', code: ` -() => () => { return (): void => { return; } }; - `, +() => () => { + return (): void => { + return; + }; +}; + `, options: [{ allowHigherOrderFunctions: true }], }, // https://github.com/typescript-eslint/typescript-eslint/issues/679 { filename: 'test.ts', code: ` -declare function foo(arg: () => void): void -foo(() => 1) -foo(() => {}) -foo(() => null) -foo(() => true) -foo(() => '') +declare function foo(arg: () => void): void; +foo(() => 1); +foo(() => {}); +foo(() => null); +foo(() => true); +foo(() => ''); `, options: [ { @@ -266,12 +282,12 @@ foo(() => '') { filename: 'test.ts', code: ` -declare function foo(arg: () => void): void -foo?.(() => 1) -foo?.bar(() => {}) -foo?.bar?.(() => null) -foo.bar?.(() => true) -foo?.(() => '') +declare function foo(arg: () => void): void; +foo?.(() => 1); +foo?.bar(() => {}); +foo?.bar?.(() => null); +foo.bar?.(() => true); +foo?.(() => ''); `, options: [ { @@ -301,22 +317,22 @@ new Accumulator().accumulate(() => 1); { filename: 'test.ts', code: ` -declare function foo(arg: { meth: () => number }): void +declare function foo(arg: { meth: () => number }): void; foo({ meth() { return 1; }, -}) +}); foo({ - meth: function () { + meth: function() { return 1; }, -}) +}); foo({ meth: () => { return 1; }, -}) +}); `, options: [ { @@ -327,9 +343,9 @@ foo({ { filename: 'test.ts', code: ` -const func = (value: number) => (({ type: "X", value }) as const); -const func = (value: number) => ({ type: "X", value } as const); -const func = (value: number) => (x as const); +const func = (value: number) => ({ type: 'X', value } as const); +const func = (value: number) => ({ type: 'X', value } as const); +const func = (value: number) => x as const; const func = (value: number) => x as const; `, options: [ @@ -355,10 +371,7 @@ new Foo(1, () => {}); { filename: 'test.ts', code: ` -function test( - a: number, - b: number, -) { +function test(a: number, b: number) { return; } `, @@ -366,9 +379,9 @@ function test( { messageId: 'missingReturnType', line: 2, - endLine: 5, + endLine: 2, column: 1, - endColumn: 2, + endColumn: 36, }, ], }, @@ -427,7 +440,7 @@ var arrowFn = () => 'test'; class Test { constructor() {} get prop() { - return 1; + return 1; } set prop() {} method() { @@ -532,7 +545,7 @@ function test() { }, { filename: 'test.ts', - code: 'export default function() {};', + code: 'export default function() {}', options: [{ allowExpressions: true }], errors: [ { @@ -549,11 +562,11 @@ function test() { code: ` class Foo { public a = () => {}; - public b = function () {}; + public b = function() {}; public c = function test() {}; static d = () => {}; - static e = function () {}; + static e = function() {}; } `, options: [{ allowExpressions: true }], @@ -570,7 +583,7 @@ class Foo { line: 4, endLine: 4, column: 14, - endColumn: 25, + endColumn: 24, }, { messageId: 'missingReturnType', @@ -591,7 +604,7 @@ class Foo { line: 8, endLine: 8, column: 14, - endColumn: 25, + endColumn: 24, }, ], }, @@ -611,13 +624,17 @@ class Foo { }, { filename: 'test.ts', - code: "var funcExpr = function() { return 'test'; };", + code: ` +var funcExpr = function() { + return 'test'; +}; + `, options: [{ allowTypedFunctionExpressions: true }], errors: [ { messageId: 'missingReturnType', - line: 1, - endLine: 1, + line: 2, + endLine: 2, column: 16, endColumn: 26, }, @@ -626,7 +643,7 @@ class Foo { { filename: 'test.ts', - code: 'const x = (() => {}) as Foo', + code: 'const x = (() => {}) as Foo;', options: [{ allowTypedFunctionExpressions: false }], errors: [ { @@ -644,7 +661,7 @@ class Foo { interface Foo {} const x = { foo: () => {}, -} as Foo +} as Foo; `, options: [{ allowTypedFunctionExpressions: false }], errors: [ @@ -663,7 +680,7 @@ const x = { interface Foo {} const x: Foo = { foo: () => {}, -} +}; `, options: [{ allowTypedFunctionExpressions: false }], errors: [ @@ -692,7 +709,7 @@ const x: Foo = { }, { filename: 'test.ts', - code: '() => function () {};', + code: '() => function() {};', options: [{ allowHigherOrderFunctions: true }], errors: [ { @@ -700,63 +717,79 @@ const x: Foo = { line: 1, endLine: 1, column: 7, - endColumn: 18, + endColumn: 17, }, ], }, { filename: 'test.ts', - code: '() => { return () => {} };', + code: ` +() => { + return () => {}; +}; + `, options: [{ allowHigherOrderFunctions: true }], errors: [ { messageId: 'missingReturnType', - line: 1, - endLine: 1, - column: 16, - endColumn: 21, + line: 3, + endLine: 3, + column: 10, + endColumn: 15, }, ], }, { filename: 'test.ts', - code: '() => { return function () {} };', + code: ` +() => { + return function() {}; +}; + `, options: [{ allowHigherOrderFunctions: true }], errors: [ { messageId: 'missingReturnType', - line: 1, - endLine: 1, - column: 16, - endColumn: 27, + line: 3, + endLine: 3, + column: 10, + endColumn: 20, }, ], }, { filename: 'test.ts', - code: 'function fn() { return () => {} };', + code: ` +function fn() { + return () => {}; +} + `, options: [{ allowHigherOrderFunctions: true }], errors: [ { messageId: 'missingReturnType', - line: 1, - endLine: 1, - column: 24, - endColumn: 29, + line: 3, + endLine: 3, + column: 10, + endColumn: 15, }, ], }, { filename: 'test.ts', - code: 'function fn() { return function () {} };', + code: ` +function fn() { + return function() {}; +} + `, options: [{ allowHigherOrderFunctions: true }], errors: [ { messageId: 'missingReturnType', - line: 1, - endLine: 1, - column: 24, - endColumn: 35, + line: 3, + endLine: 3, + column: 10, + endColumn: 20, }, ], }, @@ -766,20 +799,22 @@ const x: Foo = { function FunctionDeclaration() { return function FunctionExpression_Within_FunctionDeclaration() { return function FunctionExpression_Within_FunctionExpression() { - return () => { // ArrowFunctionExpression_Within_FunctionExpression - return () => // ArrowFunctionExpression_Within_ArrowFunctionExpression - () => 1 // ArrowFunctionExpression_Within_ArrowFunctionExpression_WithNoBody - } - } - } + return () => { + // ArrowFunctionExpression_Within_FunctionExpression + return () => + // ArrowFunctionExpression_Within_ArrowFunctionExpression + () => 1; // ArrowFunctionExpression_Within_ArrowFunctionExpression_WithNoBody + }; + }; + }; } - `, + `, options: [{ allowHigherOrderFunctions: true }], errors: [ { messageId: 'missingReturnType', - line: 7, - endLine: 7, + line: 9, + endLine: 9, column: 11, endColumn: 16, }, @@ -787,15 +822,21 @@ function FunctionDeclaration() { }, { filename: 'test.ts', - code: '() => () => { return () => { return; } };', + code: ` +() => () => { + return () => { + return; + }; +}; + `, options: [{ allowHigherOrderFunctions: true }], errors: [ { messageId: 'missingReturnType', - line: 1, - endLine: 1, - column: 22, - endColumn: 27, + line: 3, + endLine: 3, + column: 10, + endColumn: 15, }, ], }, @@ -803,12 +844,12 @@ function FunctionDeclaration() { { filename: 'test.ts', code: ` -declare function foo(arg: () => void): void -foo(() => 1) -foo(() => {}) -foo(() => null) -foo(() => true) -foo(() => '') +declare function foo(arg: () => void): void; +foo(() => 1); +foo(() => {}); +foo(() => null); +foo(() => true); +foo(() => ''); `, options: [ { @@ -883,7 +924,7 @@ new Accumulator().accumulate(() => 1); }, { filename: 'test.ts', - code: '(() => true)()', + code: '(() => true)();', options: [ { allowTypedFunctionExpressions: false, @@ -902,22 +943,22 @@ new Accumulator().accumulate(() => 1); { filename: 'test.ts', code: ` -declare function foo(arg: { meth: () => number }): void +declare function foo(arg: { meth: () => number }): void; foo({ meth() { return 1; }, -}) +}); foo({ - meth: function () { + meth: function() { return 1; }, -}) +}); foo({ meth: () => { return 1; }, -}) +}); `, options: [ { @@ -937,7 +978,7 @@ foo({ line: 9, endLine: 9, column: 9, - endColumn: 20, + endColumn: 19, }, { messageId: 'missingReturnType', @@ -951,8 +992,8 @@ foo({ { filename: 'test.ts', code: ` -const func = (value: number) => ({ type: "X", value } as any); -const func = (value: number) => ({ type: "X", value } as Action); +const func = (value: number) => ({ type: 'X', value } as any); +const func = (value: number) => ({ type: 'X', value } as Action); `, options: [ { @@ -979,7 +1020,7 @@ const func = (value: number) => ({ type: "X", value } as Action); { filename: 'test.ts', code: ` -const func = (value: number) => ({ type: "X", value } as const); +const func = (value: number) => ({ type: 'X', value } as const); `, options: [ { diff --git a/packages/eslint-plugin/tests/rules/explicit-member-accessibility.test.ts b/packages/eslint-plugin/tests/rules/explicit-member-accessibility.test.ts index fe0a09dd4c16..906f1b6cc600 100644 --- a/packages/eslint-plugin/tests/rules/explicit-member-accessibility.test.ts +++ b/packages/eslint-plugin/tests/rules/explicit-member-accessibility.test.ts @@ -1,5 +1,5 @@ import rule from '../../src/rules/explicit-member-accessibility'; -import { RuleTester } from '../RuleTester'; +import { RuleTester, noFormat } from '../RuleTester'; const ruleTester = new RuleTester({ parser: '@typescript-eslint/parser', @@ -109,72 +109,72 @@ class Test { filename: 'test.ts', code: ` class Test { - protected name: string - private x: number - public getX () { - return this.x + protected name: string; + private x: number; + public getX() { + return this.x; } } - `, + `, }, { filename: 'test.ts', code: ` class Test { - protected name: string - protected foo?: string - public "foo-bar"?: string + protected name: string; + protected foo?: string; + public 'foo-bar'?: string; } - `, + `, }, { filename: 'test.ts', code: ` class Test { - public constructor({x, y}: {x: number; y: number;}) {} + public constructor({ x, y }: { x: number; y: number }) {} } - `, + `, }, { filename: 'test.ts', code: ` class Test { - protected name: string - protected foo?: string - public getX () { - return this.x + protected name: string; + protected foo?: string; + public getX() { + return this.x; } } - `, + `, options: [{ accessibility: 'explicit' }], }, { filename: 'test.ts', code: ` class Test { - protected name: string - protected foo?: string - getX () { - return this.x + protected name: string; + protected foo?: string; + getX() { + return this.x; } } - `, + `, options: [{ accessibility: 'no-public' }], }, { filename: 'test.ts', code: ` class Test { - name: string - foo?: string - getX () { - return this.x + name: string; + foo?: string; + getX() { + return this.x; } get fooName(): string { - return this.foo + ' ' + this.name + return this.foo + ' ' + this.name; } } - `, + `, options: [{ accessibility: 'no-public' }], }, { @@ -182,7 +182,7 @@ class Test { code: ` class Test { private x: number; - constructor (x: number) { + constructor(x: number) { this.x = x; } get internalValue() { @@ -191,7 +191,7 @@ class Test { private set internalValue(value: number) { this.x = value; } - public square (): number { + public square(): number { return this.x * this.x; } } @@ -203,7 +203,7 @@ class Test { code: ` class Test { private x: number; - public constructor (x: number) { + public constructor(x: number) { this.x = x; } public get internalValue() { @@ -212,10 +212,10 @@ class Test { public set internalValue(value: number) { this.x = value; } - public square (): number { + public square(): number { return this.x * this.x; } - half (): number { + half(): number { return this.x / 2; } } @@ -226,7 +226,7 @@ class Test { filename: 'test.ts', code: ` class Test { - constructor(private x: number){} + constructor(private x: number) {} } `, options: [{ accessibility: 'no-public' }], @@ -235,7 +235,7 @@ class Test { filename: 'test.ts', code: ` class Test { - constructor(public x: number){} + constructor(public x: number) {} } `, options: [ @@ -249,7 +249,7 @@ class Test { filename: 'test.ts', code: ` class Test { - constructor(public foo: number){} + constructor(public foo: number) {} } `, options: [{ accessibility: 'no-public' }], @@ -258,8 +258,8 @@ class Test { filename: 'test.ts', code: ` class Test { - public getX () { - return this.x + public getX() { + return this.x; } } `, @@ -269,8 +269,8 @@ class Test { filename: 'test.ts', code: ` class Test { - public static getX () { - return this.x + public static getX() { + return this.x; } } `, @@ -280,8 +280,8 @@ class Test { filename: 'test.ts', code: ` class Test { - get getX () { - return this.x + get getX() { + return this.x; } } `, @@ -291,8 +291,8 @@ class Test { filename: 'test.ts', code: ` class Test { - getX () { - return this.x + getX() { + return this.x; } } `, @@ -300,24 +300,38 @@ class Test { }, { filename: 'test.ts', - code: 'class Test { x = 2 }', + code: ` +class Test { + x = 2; +} + `, options: [{ overrides: { properties: 'off' } }], }, { filename: 'test.ts', - code: 'class Test { private x = 2 }', + code: ` +class Test { + private x = 2; +} + `, options: [{ overrides: { properties: 'explicit' } }], }, { filename: 'test.ts', - code: `class Test { - x = 2 - private x = 2 - }`, + code: ` +class Test { + x = 2; + private x = 2; +} + `, options: [{ overrides: { properties: 'no-public' } }], }, { - code: 'class Test { constructor(private { x }: any[]) { }}', + code: ` +class Test { + constructor(private { x }: any[]) {} +} + `, options: [{ accessibility: 'no-public' }], }, ], @@ -412,12 +426,12 @@ class Test { filename: 'test.ts', code: ` class Test { - x: number - public getX () { - return this.x + x: number; + public getX() { + return this.x; } } - `, + `, errors: [ { messageId: 'missingAccessibility', @@ -431,23 +445,23 @@ class Test { ], output: ` class Test { - x: number - public getX () { - return this.x + x: number; + public getX() { + return this.x; } } - `, + `, }, { filename: 'test.ts', code: ` class Test { - private x: number - getX () { - return this.x + private x: number; + getX() { + return this.x; } } - `, + `, errors: [ { messageId: 'missingAccessibility', @@ -461,23 +475,23 @@ class Test { ], output: ` class Test { - private x: number - getX () { - return this.x + private x: number; + getX() { + return this.x; } } - `, + `, }, { filename: 'test.ts', code: ` class Test { - x?: number - getX? () { - return this.x + x?: number; + getX?() { + return this.x; } } - `, + `, errors: [ { messageId: 'missingAccessibility', @@ -500,24 +514,24 @@ class Test { ], output: ` class Test { - x?: number - getX? () { - return this.x + x?: number; + getX?() { + return this.x; } } - `, + `, }, { filename: 'test.ts', code: ` class Test { - protected name: string - protected foo?: string - public getX () { - return this.x + protected name: string; + protected foo?: string; + public getX() { + return this.x; } } - `, + `, options: [{ accessibility: 'no-public' }], errors: [ { @@ -532,25 +546,25 @@ class Test { ], output: ` class Test { - protected name: string - protected foo?: string - getX () { - return this.x + protected name: string; + protected foo?: string; + getX() { + return this.x; } } - `, + `, }, { filename: 'test.ts', code: ` class Test { - protected name: string - public foo?: string - getX () { - return this.x + protected name: string; + public foo?: string; + getX() { + return this.x; } } - `, + `, options: [{ accessibility: 'no-public' }], errors: [ { @@ -565,24 +579,24 @@ class Test { ], output: ` class Test { - protected name: string - foo?: string - getX () { - return this.x + protected name: string; + foo?: string; + getX() { + return this.x; } } - `, + `, }, { filename: 'test.ts', code: ` class Test { - public x: number - public getX () { - return this.x + public x: number; + public getX() { + return this.x; } } - `, + `, errors: [ { messageId: 'unwantedPublicAccessibility', @@ -598,19 +612,19 @@ class Test { options: [{ accessibility: 'no-public' }], output: ` class Test { - x: number - getX () { - return this.x + x: number; + getX() { + return this.x; } } - `, + `, }, { filename: 'test.ts', code: ` class Test { private x: number; - constructor (x: number) { + constructor(x: number) { this.x = x; } get internalValue() { @@ -637,7 +651,7 @@ class Test { output: ` class Test { private x: number; - constructor (x: number) { + constructor(x: number) { this.x = x; } get internalValue() { @@ -654,7 +668,7 @@ class Test { code: ` class Test { private x: number; - constructor (x: number) { + constructor(x: number) { this.x = x; } get internalValue() { @@ -685,7 +699,7 @@ class Test { output: ` class Test { private x: number; - constructor (x: number) { + constructor(x: number) { this.x = x; } get internalValue() { @@ -701,7 +715,7 @@ class Test { filename: 'test.ts', code: ` class Test { - constructor(public x: number){} + constructor(public x: number) {} public foo(): string { return 'foo'; } @@ -721,7 +735,7 @@ class Test { ], output: ` class Test { - constructor(public x: number){} + constructor(public x: number) {} public foo(): string { return 'foo'; } @@ -732,7 +746,7 @@ class Test { filename: 'test.ts', code: ` class Test { - constructor(public x: number){} + constructor(public x: number) {} } `, errors: [ @@ -744,7 +758,7 @@ class Test { ], output: ` class Test { - constructor(public x: number){} + constructor(public x: number) {} } `, }, @@ -752,7 +766,7 @@ class Test { filename: 'test.ts', code: ` class Test { - constructor(public readonly x: number){} + constructor(public readonly x: number) {} } `, options: [ @@ -770,13 +784,17 @@ class Test { ], output: ` class Test { - constructor(readonly x: number){} + constructor(readonly x: number) {} } `, }, { filename: 'test.ts', - code: 'class Test { x = 2 }', + code: ` +class Test { + x = 2; +} + `, options: [ { accessibility: 'off', @@ -786,18 +804,24 @@ class Test { errors: [ { messageId: 'missingAccessibility', - line: 1, - column: 14, + line: 3, + column: 3, }, ], - output: 'class Test { x = 2 }', + output: ` +class Test { + x = 2; +} + `, }, { filename: 'test.ts', - code: `class Test { - public x = 2 - private x = 2 - }`, + code: ` +class Test { + public x = 2; + private x = 2; +} + `, options: [ { accessibility: 'off', @@ -807,30 +831,40 @@ class Test { errors: [ { messageId: 'unwantedPublicAccessibility', - line: 2, - column: 9, + line: 3, + column: 3, }, ], - output: `class Test { - x = 2 - private x = 2 - }`, + output: ` +class Test { + x = 2; + private x = 2; +} + `, }, { - code: 'class Test { constructor(public ...x: any[]) { }}', + code: ` +class Test { + constructor(public ...x: any[]) {} +} + `, options: [{ accessibility: 'explicit' }], errors: [ { messageId: 'missingAccessibility', - line: 1, - column: 14, + line: 3, + column: 3, }, ], - output: 'class Test { constructor(public ...x: any[]) { }}', + output: ` +class Test { + constructor(public ...x: any[]) {} +} + `, }, { filename: 'test.ts', - code: ` + code: noFormat` class Test { @public public /*public*/constructor(private foo: string) {} @@ -848,7 +882,7 @@ class Test { column: 3, }, ], - output: ` + output: noFormat` class Test { @public /*public*/constructor(private foo: string) {} @@ -914,7 +948,7 @@ class Test { filename: 'test.ts', code: ` class Test { - public foo = ""; + public foo = ''; } `, options: [ @@ -931,16 +965,16 @@ class Test { ], output: ` class Test { - foo = ""; + foo = ''; } `, }, { filename: 'test.ts', - code: ` + code: noFormat` class Test { - contructor(public/* Hi there */ readonly foo) + contructor(public/* Hi there */ readonly foo); } `, options: [ @@ -958,7 +992,7 @@ class Test { ], output: ` class Test { - contructor(/* Hi there */ readonly foo) + contructor(/* Hi there */ readonly foo); } `, }, @@ -966,7 +1000,7 @@ class Test { filename: 'test.ts', code: ` class Test { - contructor(public readonly foo: string) + contructor(public readonly foo: string); } `, options: [ @@ -983,33 +1017,17 @@ class Test { ], output: ` class Test { - contructor(readonly foo: string) + contructor(readonly foo: string); } `, }, { filename: 'test.ts', - code: - 'class EnsureWhiteSPaceSpan { public constructor() {}}', - options: [ - { - accessibility: 'no-public', - overrides: { parameterProperties: 'no-public' }, - }, - ], - errors: [ - { - messageId: 'unwantedPublicAccessibility', - line: 1, - column: 30, - }, - ], - output: 'class EnsureWhiteSPaceSpan { constructor() {}}', - }, - { - filename: 'test.ts', - code: - 'class EnsureWhiteSPaceSpan { public /* */ constructor() {}}', + code: ` +class EnsureWhiteSPaceSpan { + public constructor() {} +} + `, options: [ { accessibility: 'no-public', @@ -1019,17 +1037,23 @@ class Test { errors: [ { messageId: 'unwantedPublicAccessibility', - line: 1, - column: 30, + line: 3, + column: 3, }, ], - output: - 'class EnsureWhiteSPaceSpan { /* */ constructor() {}}', + output: ` +class EnsureWhiteSPaceSpan { + constructor() {} +} + `, }, { filename: 'test.ts', - code: - 'class EnsureWhiteSPaceSpan { public /* */ constructor() {}}', + code: ` +class EnsureWhiteSPaceSpan { + public /* */ constructor() {} +} + `, options: [ { accessibility: 'no-public', @@ -1039,11 +1063,15 @@ class Test { errors: [ { messageId: 'unwantedPublicAccessibility', - line: 1, - column: 30, + line: 3, + column: 3, }, ], - output: 'class EnsureWhiteSPaceSpan { /* */ constructor() {}}', + output: ` +class EnsureWhiteSPaceSpan { + /* */ constructor() {} +} + `, }, ], }); diff --git a/packages/eslint-plugin/tests/rules/explicit-module-boundary-types.test.ts b/packages/eslint-plugin/tests/rules/explicit-module-boundary-types.test.ts index 388adb994315..cdff53533b73 100644 --- a/packages/eslint-plugin/tests/rules/explicit-module-boundary-types.test.ts +++ b/packages/eslint-plugin/tests/rules/explicit-module-boundary-types.test.ts @@ -10,28 +10,28 @@ ruleTester.run('explicit-module-boundary-types', rule, { { code: ` function test(): void { - return; + return; } - `, + `, }, { code: ` export function test(): void { - return; + return; } - `, + `, }, { code: ` export var fn = function(): number { - return 1; + return 1; }; - `, + `, }, { code: ` export var arrowFn = (): string => 'test'; - `, + `, }, { code: ` @@ -46,7 +46,7 @@ class Test { } arrow = (): string => 'arrow'; } - `, + `, }, { code: ` @@ -61,42 +61,42 @@ export class Test { } arrow = (): string => 'arrow'; } - `, + `, }, { code: ` export function test(): void { - nested(); - return; + nested(); + return; - function nested() {} + function nested() {} } - `, + `, }, { code: ` export function test(): string { - const nested = () => 'value'; - return nested(); + const nested = () => 'value'; + return nested(); } - `, + `, }, { code: ` export function test(): string { - class Nested { - public method() { - return 'value'; - } + class Nested { + public method() { + return 'value'; } - return new Nested().method(); + } + return new Nested().method(); } - `, + `, }, { code: ` export var arrowFn: Foo = () => 'test'; - `, + `, options: [ { allowTypedFunctionExpressions: true, @@ -105,8 +105,10 @@ export var arrowFn: Foo = () => 'test'; }, { code: ` -export var funcExpr: Foo = function() { return 'test'; }; - `, +export var funcExpr: Foo = function() { + return 'test'; +}; + `, options: [ { allowTypedFunctionExpressions: true, @@ -114,18 +116,18 @@ export var funcExpr: Foo = function() { return 'test'; }; ], }, { - code: `const x = (() => {}) as Foo`, + code: 'const x = (() => {}) as Foo;', options: [{ allowTypedFunctionExpressions: true }], }, { - code: `const x = (() => {})`, + code: 'const x = (() => {});', options: [{ allowTypedFunctionExpressions: true }], }, { code: ` export const x = { foo: () => {}, -} as Foo +} as Foo; `, options: [{ allowTypedFunctionExpressions: true }], }, @@ -133,7 +135,7 @@ export const x = { code: ` export const x = { foo: () => {}, -} +}; `, options: [{ allowTypedFunctionExpressions: true }], }, @@ -141,7 +143,7 @@ export const x = { code: ` export const x: Foo = { foo: () => {}, -} +}; `, options: [{ allowTypedFunctionExpressions: true }], }, @@ -151,7 +153,7 @@ export const x: Foo = { type MethodType = () => void; export class App { - public method: MethodType = () => {} + public method: MethodType = () => {}; } `, options: [{ allowTypedFunctionExpressions: true }], @@ -169,37 +171,45 @@ export const myObj = { { code: ` export default () => (): void => {}; - `, + `, options: [{ allowHigherOrderFunctions: true }], }, { code: ` -export default () => function (): void {}; - `, +export default () => function(): void {}; + `, options: [{ allowHigherOrderFunctions: true }], }, { code: ` -export default () => { return (): void => {} }; - `, +export default () => { + return (): void => {}; +}; + `, options: [{ allowHigherOrderFunctions: true }], }, { code: ` -export default () => { return function (): void {} }; - `, +export default () => { + return function(): void {}; +}; + `, options: [{ allowHigherOrderFunctions: true }], }, { code: ` -export function fn() { return (): void => {} }; - `, +export function fn() { + return (): void => {}; +} + `, options: [{ allowHigherOrderFunctions: true }], }, { code: ` -export function fn() { return function (): void {} }; - `, +export function fn() { + return function(): void {}; +} + `, options: [{ allowHigherOrderFunctions: true }], }, { @@ -207,20 +217,26 @@ export function fn() { return function (): void {} }; export function FunctionDeclaration() { return function FunctionExpression_Within_FunctionDeclaration() { return function FunctionExpression_Within_FunctionExpression() { - return () => { // ArrowFunctionExpression_Within_FunctionExpression - return () => // ArrowFunctionExpression_Within_ArrowFunctionExpression - (): number => 1 // ArrowFunctionExpression_Within_ArrowFunctionExpression_WithNoBody - } - } - } + return () => { + // ArrowFunctionExpression_Within_FunctionExpression + return () => + // ArrowFunctionExpression_Within_ArrowFunctionExpression + (): number => 1; // ArrowFunctionExpression_Within_ArrowFunctionExpression_WithNoBody + }; + }; + }; } - `, + `, options: [{ allowHigherOrderFunctions: true }], }, { code: ` -export default () => () => { return (): void => { return; } }; - `, +export default () => () => { + return (): void => { + return; + }; +}; + `, options: [{ allowHigherOrderFunctions: true }], }, { @@ -243,9 +259,9 @@ new Accumulator().accumulate(() => 1); }, { code: ` -export const func1 = (value: number) => (({ type: "X", value }) as const); -export const func2 = (value: number) => ({ type: "X", value } as const); -export const func3 = (value: number) => (x as const); +export const func1 = (value: number) => ({ type: 'X', value } as const); +export const func2 = (value: number) => ({ type: 'X', value } as const); +export const func3 = (value: number) => x as const; export const func4 = (value: number) => x as const; `, options: [ @@ -257,7 +273,7 @@ export const func4 = (value: number) => x as const; { code: ` export const func1 = (value: string) => value; -export const func2 = (value: number) => ({ type: "X", value }); +export const func2 = (value: number) => ({ type: 'X', value }); `, options: [ { @@ -315,13 +331,8 @@ export class Test { { code: ` export const Foo: FC = () => ( -
{}} - b={function (e) {}} - c={function foo(e) {}} - > -
-) +
{}} b={function(e) {}} c={function foo(e) {}}>
+); `, parserOptions: { ecmaFeatures: { jsx: true }, @@ -329,13 +340,9 @@ export const Foo: FC = () => ( }, { code: ` -export const Foo: JSX.Element = -
{}} - b={function (e) {}} - c={function foo(e) {}} - > -
+export const Foo: JSX.Element = ( +
{}} b={function(e) {}} c={function foo(e) {}}>
+); `, parserOptions: { ecmaFeatures: { jsx: true }, @@ -345,10 +352,7 @@ export const Foo: JSX.Element = invalid: [ { code: ` -export function test( - a: number, - b: number, -) { +export function test(a: number, b: number) { return; } `, @@ -356,9 +360,9 @@ export function test( { messageId: 'missingReturnType', line: 2, - endLine: 5, + endLine: 2, column: 8, - endColumn: 2, + endColumn: 43, }, ], }, @@ -413,13 +417,13 @@ export var arrowFn = () => 'test'; export class Test { constructor() {} get prop() { - return 1; + return 1; } set prop(value) {} method() { return; } - arrow = (arg) => 'arrow'; + arrow = arg => 'arrow'; private method() { return; } @@ -452,14 +456,14 @@ export class Test { line: 11, endLine: 11, column: 11, - endColumn: 19, + endColumn: 17, }, { messageId: 'missingArgType', line: 11, endLine: 11, column: 11, - endColumn: 27, + endColumn: 25, }, ], }, @@ -467,11 +471,11 @@ export class Test { code: ` export class Foo { public a = () => {}; - public b = function () {}; + public b = function() {}; public c = function test() {}; static d = () => {}; - static e = function () {}; + static e = function() {}; } `, errors: [ @@ -487,7 +491,7 @@ export class Foo { line: 4, endLine: 4, column: 14, - endColumn: 25, + endColumn: 24, }, { messageId: 'missingReturnType', @@ -508,12 +512,12 @@ export class Foo { line: 8, endLine: 8, column: 14, - endColumn: 25, + endColumn: 24, }, ], }, { - code: 'export default () => true ? (() => {}) : ((): void => {});', + code: 'export default () => (true ? () => {} : (): void => {});', errors: [ { messageId: 'missingReturnType', @@ -545,20 +549,24 @@ export class Foo { ], }, { - code: "export var funcExpr = function() { return 'test'; };", + code: ` +export var funcExpr = function() { + return 'test'; +}; + `, options: [{ allowTypedFunctionExpressions: true }], errors: [ { messageId: 'missingReturnType', - line: 1, - endLine: 1, + line: 2, + endLine: 2, column: 23, endColumn: 33, }, ], }, { - code: 'export const x = (() => {}) as Foo', + code: 'export const x = (() => {}) as Foo;', options: [{ allowTypedFunctionExpressions: false }], errors: [ { @@ -575,7 +583,7 @@ export class Foo { interface Foo {} export const x = { foo: () => {}, -} as Foo +} as Foo; `, options: [{ allowTypedFunctionExpressions: false }], errors: [ @@ -593,7 +601,7 @@ export const x = { interface Foo {} export const x: Foo = { foo: () => {}, -} +}; `, options: [{ allowTypedFunctionExpressions: false }], errors: [ @@ -620,7 +628,7 @@ export const x: Foo = { ], }, { - code: 'export default () => function () {};', + code: 'export default () => function() {};', options: [{ allowHigherOrderFunctions: true }], errors: [ { @@ -628,59 +636,75 @@ export const x: Foo = { line: 1, endLine: 1, column: 22, - endColumn: 33, + endColumn: 32, }, ], }, { - code: 'export default () => { return () => {} };', + code: ` +export default () => { + return () => {}; +}; + `, options: [{ allowHigherOrderFunctions: true }], errors: [ { messageId: 'missingReturnType', - line: 1, - endLine: 1, - column: 31, - endColumn: 36, + line: 3, + endLine: 3, + column: 10, + endColumn: 15, }, ], }, { - code: 'export default () => { return function () {} };', + code: ` +export default () => { + return function() {}; +}; + `, options: [{ allowHigherOrderFunctions: true }], errors: [ { messageId: 'missingReturnType', - line: 1, - endLine: 1, - column: 31, - endColumn: 42, + line: 3, + endLine: 3, + column: 10, + endColumn: 20, }, ], }, { - code: 'export function fn() { return () => {} };', + code: ` +export function fn() { + return () => {}; +} + `, options: [{ allowHigherOrderFunctions: true }], errors: [ { messageId: 'missingReturnType', - line: 1, - endLine: 1, - column: 31, - endColumn: 36, + line: 3, + endLine: 3, + column: 10, + endColumn: 15, }, ], }, { - code: 'export function fn() { return function () {} };', + code: ` +export function fn() { + return function() {}; +} + `, options: [{ allowHigherOrderFunctions: true }], errors: [ { messageId: 'missingReturnType', - line: 1, - endLine: 1, - column: 31, - endColumn: 42, + line: 3, + endLine: 3, + column: 10, + endColumn: 20, }, ], }, @@ -689,40 +713,48 @@ export const x: Foo = { export function FunctionDeclaration() { return function FunctionExpression_Within_FunctionDeclaration() { return function FunctionExpression_Within_FunctionExpression() { - return () => { // ArrowFunctionExpression_Within_FunctionExpression - return () => // ArrowFunctionExpression_Within_ArrowFunctionExpression - () => 1 // ArrowFunctionExpression_Within_ArrowFunctionExpression_WithNoBody - } - } - } + return () => { + // ArrowFunctionExpression_Within_FunctionExpression + return () => + // ArrowFunctionExpression_Within_ArrowFunctionExpression + () => 1; // ArrowFunctionExpression_Within_ArrowFunctionExpression_WithNoBody + }; + }; + }; } - `, + `, options: [{ allowHigherOrderFunctions: true }], errors: [ { messageId: 'missingReturnType', - line: 7, - endLine: 7, + line: 9, + endLine: 9, column: 11, endColumn: 16, }, ], }, { - code: 'export default () => () => { return () => { return; } };', + code: ` +export default () => () => { + return () => { + return; + }; +}; + `, options: [{ allowHigherOrderFunctions: true }], errors: [ { messageId: 'missingReturnType', - line: 1, - endLine: 1, - column: 37, - endColumn: 42, + line: 3, + endLine: 3, + column: 10, + endColumn: 15, }, ], }, { - code: 'export default (() => true)()', + code: 'export default (() => true)();', options: [ { allowTypedFunctionExpressions: false, @@ -740,8 +772,8 @@ export function FunctionDeclaration() { }, { code: ` -export const func1 = (value: number) => ({ type: "X", value } as any); -export const func2 = (value: number) => ({ type: "X", value } as Action); +export const func1 = (value: number) => ({ type: 'X', value } as any); +export const func2 = (value: number) => ({ type: 'X', value } as Action); `, options: [ { @@ -767,7 +799,7 @@ export const func2 = (value: number) => ({ type: "X", value } as Action); }, { code: ` -export const func = (value: number) => ({ type: "X", value } as const); +export const func = (value: number) => ({ type: 'X', value } as const); `, options: [ { @@ -834,19 +866,23 @@ export const func2 = (value: number) => value; ], }, { - code: 'export function fn(test): string { return "123" };', + code: ` +export function fn(test): string { + return '123'; +} + `, errors: [ { messageId: 'missingArgType', - line: 1, - endLine: 1, + line: 2, + endLine: 4, column: 8, - endColumn: 50, + endColumn: 2, }, ], }, { - code: 'export const fn = (one: number, two): string => "123";', + code: "export const fn = (one: number, two): string => '123';", errors: [ { messageId: 'missingArgType', diff --git a/packages/eslint-plugin/tests/rules/func-call-spacing.test.ts b/packages/eslint-plugin/tests/rules/func-call-spacing.test.ts index e2250716a075..db884fd3cf12 100644 --- a/packages/eslint-plugin/tests/rules/func-call-spacing.test.ts +++ b/packages/eslint-plugin/tests/rules/func-call-spacing.test.ts @@ -1,3 +1,8 @@ +/* eslint-disable eslint-comments/no-use */ +// this rule tests the spacing, which prettier will want to fix and break the tests +/* eslint "@typescript-eslint/internal/plugin-test-formatting": ["error", { formatWithPrettier: false }] */ +/* eslint-enable eslint-comments/no-use */ + import { TSESLint } from '@typescript-eslint/experimental-utils'; import rule, { MessageIds, Options } from '../../src/rules/func-call-spacing'; import { RuleTester } from '../RuleTester'; @@ -180,7 +185,7 @@ ruleTester.run('func-call-spacing', rule, { this.cancelled.add(request) this.decrement(request) (request.reject(new api.Cancel())) - `, + `, output: null, // no change errors: [ { @@ -208,7 +213,7 @@ var a = foo code: ` var a = foo (baz()) - `, + `, output: null, // no change errors: [ { diff --git a/packages/eslint-plugin/tests/rules/generic-type-naming.test.ts b/packages/eslint-plugin/tests/rules/generic-type-naming.test.ts index 11f7d1618bb2..da26e9675b64 100644 --- a/packages/eslint-plugin/tests/rules/generic-type-naming.test.ts +++ b/packages/eslint-plugin/tests/rules/generic-type-naming.test.ts @@ -7,35 +7,60 @@ const ruleTester = new RuleTester({ ruleTester.run('generic-type-naming', rule, { valid: [ - { code: 'class { }', options: [] }, - { code: 'type ReadOnly = {}', options: [] }, - { code: 'interface SimpleMap { }', options: [] }, - { code: 'function get() {}', options: [] }, - { code: 'interface GenericIdentityFn { (arg: T): T }', options: [] }, - { code: 'class { }', options: ['^x+$'] }, - { code: 'class { }', options: ['^[A-Z]$'] }, - { - code: 'class extends B implements Foo { }', + { + code: 'class {}', + options: [], + }, + { + code: 'type ReadOnly = {};', + options: [], + }, + { + code: 'interface SimpleMap {}', + options: [], + }, + { + code: 'function get() {}', + options: [], + }, + { + code: ` +interface GenericIdentityFn { + (arg: T): T; +} + `, + options: [], + }, + { + code: 'class {}', + options: ['^x+$'], + }, + { + code: 'class {}', + options: ['^[A-Z]$'], + }, + { + code: 'class extends B implements Foo {}', options: ['^[A-Z]$'], }, { code: ` class extends B implements Foo { - test () { - type Foo = Bar - } + test() { + type Foo = Bar; + } } - `, + `, options: ['^[A-Z]$'], }, { - code: 'class CounterContainer extends Container { }', + code: 'class CounterContainer extends Container {}', options: ['^T$'], }, ], invalid: [ { - code: 'class { }', + code: 'class {}', options: [], errors: [ { @@ -49,7 +74,7 @@ class extends B implements Foo { ], }, { - code: 'class { }', + code: 'class {}', options: ['^[A-Z]+$'], errors: [ { @@ -61,7 +86,7 @@ class extends B implements Foo { ], }, { - code: 'interface SimpleMap { }', + code: 'interface SimpleMap {}', options: ['^[A-Z]+$'], errors: [ { @@ -73,7 +98,7 @@ class extends B implements Foo { ], }, { - code: 'type R = {}', + code: 'type R = {};', options: ['^[A-Z]+$'], errors: [ { @@ -97,25 +122,29 @@ class extends B implements Foo { ], }, { - code: 'interface GenericIdentityFn { (arg: x): x }', + code: ` +interface GenericIdentityFn { + (arg: x): x; +} + `, options: ['^[A-Z]+$'], errors: [ { messageId: 'paramNotMatchRule', data: { name: 'x', rule: '^[A-Z]+$' }, - line: 1, - column: 32, + line: 3, + column: 4, }, ], }, { code: ` class extends B implements Foo { - test () { - type Foo = Bar - } + test() { + type Foo = Bar; + } } - `, + `, options: ['^[A-Z][0-9]$'], errors: [ { @@ -128,24 +157,24 @@ class extends B implements Foo { messageId: 'paramNotMatchRule', data: { name: 'Z', rule: '^[A-Z][0-9]$' }, line: 3, - column: 10, + column: 8, }, { messageId: 'paramNotMatchRule', data: { name: 'T', rule: '^[A-Z][0-9]$' }, line: 4, - column: 18, + column: 14, }, ], }, { code: ` abstract class extends B implements Foo { - test () { - type Foo = Bar - } + test() { + type Foo = Bar; + } } - `, + `, options: ['^[A-Z][0-9]$'], errors: [ { @@ -164,13 +193,13 @@ abstract class extends B implements Foo { messageId: 'paramNotMatchRule', data: { name: 'Z', rule: '^[A-Z][0-9]$' }, line: 3, - column: 10, + column: 8, }, { messageId: 'paramNotMatchRule', data: { name: 'T', rule: '^[A-Z][0-9]$' }, line: 4, - column: 18, + column: 14, }, ], }, diff --git a/packages/eslint-plugin/tests/rules/indent/indent-eslint.test.ts b/packages/eslint-plugin/tests/rules/indent/indent-eslint.test.ts index d726a5e2c95f..a9dfda6b127b 100644 --- a/packages/eslint-plugin/tests/rules/indent/indent-eslint.test.ts +++ b/packages/eslint-plugin/tests/rules/indent/indent-eslint.test.ts @@ -4,6 +4,11 @@ // NOTE - this test suite is intentionally kept in a separate file to our // custom tests. This is to keep a clear boundary between the two. +/* eslint-disable eslint-comments/no-use */ +// this rule tests the spacing, which prettier will want to fix and break the tests +/* eslint "@typescript-eslint/internal/plugin-test-formatting": ["error", { formatWithPrettier: false }] */ +/* eslint-enable eslint-comments/no-use */ + import { AST_TOKEN_TYPES, AST_NODE_TYPES, diff --git a/packages/eslint-plugin/tests/rules/indent/indent.test.ts b/packages/eslint-plugin/tests/rules/indent/indent.test.ts index fe88d3de17a0..6cec699c053e 100644 --- a/packages/eslint-plugin/tests/rules/indent/indent.test.ts +++ b/packages/eslint-plugin/tests/rules/indent/indent.test.ts @@ -1,3 +1,8 @@ +/* eslint-disable eslint-comments/no-use */ +// this rule tests the spacing, which prettier will want to fix and break the tests +/* eslint "@typescript-eslint/internal/plugin-test-formatting": ["error", { formatWithPrettier: false }] */ +/* eslint-enable eslint-comments/no-use */ + import { AST_NODE_TYPES, TSESLint, @@ -704,7 +709,7 @@ export default class App extends Vue return this.$store.state.errorHandler.error } } - `, + `, // https://github.com/eslint/typescript-eslint-parser/issues/474 ` /** @@ -713,7 +718,7 @@ export default class App extends Vue * @returns {string} */ function foo(name: string, age: number): string {} - `, + `, ` const firebaseApp = firebase.apps.length ? firebase.app() @@ -725,7 +730,7 @@ const firebaseApp = firebase.apps.length storageBucket: __FIREBASE_STORAGE_BUCKET__, messagingSenderId: __FIREBASE_MESSAGING_SENDER_ID__, }) - `, + `, // https://github.com/bradzacher/eslint-plugin-typescript/issues/271 { code: ` @@ -734,7 +739,7 @@ const foo = { b: 2 }, bar = 1; - `, + `, options: [4, { VariableDeclarator: { const: 3 } }], }, { @@ -744,7 +749,7 @@ const foo : Foo = { b: 2 }, bar = 1; - `, + `, options: [4, { VariableDeclarator: { const: 3 } }], }, { @@ -756,7 +761,7 @@ const name: string = ' Typescript ' greeting: string = (" Hello " + name) .toUpperCase() .trim(); - `, + `, options: [2, { VariableDeclarator: { const: 3 } }], }, { @@ -768,15 +773,15 @@ const div: JQuery = $('
') button: JQuery = $('