From d63194f02a13bb19350aed6e3c792c475243b191 Mon Sep 17 00:00:00 2001 From: Anix Date: Fri, 27 Mar 2020 14:50:25 +0000 Subject: [PATCH 01/19] feat(eslint-plugin): added init-declarations support --- packages/eslint-plugin/README.md | 1 + .../docs/rules/init-declarations.md | 140 ++++++ packages/eslint-plugin/src/configs/all.json | 2 + packages/eslint-plugin/src/rules/index.ts | 2 + .../src/rules/init-declarations.ts | 55 +++ .../tests/rules/init-declarations.test.ts | 402 ++++++++++++++++++ .../eslint-plugin/typings/eslint-rules.d.ts | 18 + 7 files changed, 620 insertions(+) create mode 100644 packages/eslint-plugin/docs/rules/init-declarations.md create mode 100644 packages/eslint-plugin/src/rules/init-declarations.ts create mode 100644 packages/eslint-plugin/tests/rules/init-declarations.test.ts diff --git a/packages/eslint-plugin/README.md b/packages/eslint-plugin/README.md index fa049b2cfb27..8e55edb162c8 100644 --- a/packages/eslint-plugin/README.md +++ b/packages/eslint-plugin/README.md @@ -179,6 +179,7 @@ In these cases, we create what we call an extension rule; a rule within our plug | [`@typescript-eslint/default-param-last`](./docs/rules/default-param-last.md) | Enforce default parameters to be last | | | | | [`@typescript-eslint/func-call-spacing`](./docs/rules/func-call-spacing.md) | Require or disallow spacing between function identifiers and their invocations | | :wrench: | | | [`@typescript-eslint/indent`](./docs/rules/indent.md) | Enforce consistent indentation | | :wrench: | | +| [`@typescript-eslint/init-declarations`](./docs/rules/init-declarations.md) | require or disallow initialization in variable declarations | | | | | [`@typescript-eslint/no-array-constructor`](./docs/rules/no-array-constructor.md) | Disallow generic `Array` constructors | :heavy_check_mark: | :wrench: | | | [`@typescript-eslint/no-dupe-class-members`](./docs/rules/no-dupe-class-members.md) | Disallow duplicate class members | | | | | [`@typescript-eslint/no-empty-function`](./docs/rules/no-empty-function.md) | Disallow empty functions | :heavy_check_mark: | | | diff --git a/packages/eslint-plugin/docs/rules/init-declarations.md b/packages/eslint-plugin/docs/rules/init-declarations.md new file mode 100644 index 000000000000..979e9775c401 --- /dev/null +++ b/packages/eslint-plugin/docs/rules/init-declarations.md @@ -0,0 +1,140 @@ +# require or disallow initialization in variable declarations (`init-declarations`) + +In Typescript, variables can be assigned during declaration, or at any point afterwards using an assignment statement. For example, in the following code, `foo` is initialized during declaration, while `bar` is initialized later. + +```ts +var foo: number = 1; +var bar: number; + +if (foo) { + bar = 1; +} else { + bar = 2; +} +``` + +## Rule Details + +This rule is aimed at enforcing or eliminating variable initializations during declaration. For example, in the following code, `foo` is initialized during declaration, while `bar` is not. + +```ts +var foo: number = 1; +var bar; + +bar: number = 2; +``` + +This rule aims to bring consistency to variable initializations and declarations. + +Variables must be initialized at declaration (default) + +```tson +{ + "@typescript-eslint/init-declarations": ["error", "always"], +} +``` + +Variables must not be initialized at declaration + +```tson +{ + "@typescript-eslint/init-declarations": ["error", "never"] +} +``` + +## Options + +```ts +{ + //Variables must not be initialized at declaration, except in for loops, where it is allowed + // Only applicable when the string options is 'never' + ignoreForLoopInit: Boolean; +} +``` + +```ts +export defaultOptions = { + ignoreForLoopInit : false +} + +``` + +### always + +Examples of **incorrect** code for the default `"always"` option: + +```ts +function foo() { + var bar: string; + let baz: string; +} +``` + +Examples of **correct** code for the default `"always"` option: + +```ts +function foo() { + var bar: number = 1; + let baz: number = 2; + const qux: number = 3; +} + +declare const foo: number; + +declare namespace myLib { + let numberOfGreetings: number; +} + +interface GreetingSettings { + greeting: string; + duration?: number; + color?: string; +} + +type GreetingLike = GreetingSettings; +``` + +### never + +Examples of **incorrect** code for the `"never"` option: + +```ts +function foo() { + var bar: number = 1; + let baz: number = 2; + + for (var i = 0; i < 1; i++) {} +} + +let arr: string[] = ['arr', 'ar']; +``` + +Examples of **correct** code for the `"never"` option: + +```ts +function foo() { + var bar: number; + let baz: number; + const buzz: number = 1; +} +``` + +The `"never"` option ignores `const` variable initializations. + +### ignoreForLoopInit + +Examples of **correct** code for the `"never", { "ignoreForLoopInit": true }` options: + +```ts +/*eslint @typescript-eslint/init-declarations: ["error", "never", { "ignoreForLoopInit": true }]*/ + +for (var i: number = 0; i < 1; i++) {} +``` + +## When Not To Use It + +When you are indifferent as to how your variables are initialized. + +This rule is fully compatible with base rule + +Taken with ❤️ [from ESLint core](https://github.com/eslint/eslint/blob/master/docs/rules/init-declarations.md) diff --git a/packages/eslint-plugin/src/configs/all.json b/packages/eslint-plugin/src/configs/all.json index c5575d4970d6..a28106c59d00 100644 --- a/packages/eslint-plugin/src/configs/all.json +++ b/packages/eslint-plugin/src/configs/all.json @@ -22,6 +22,8 @@ "@typescript-eslint/func-call-spacing": "error", "indent": "off", "@typescript-eslint/indent": "error", + "init-declarations": "off", + "@typescript-eslint/init-declarations": "error", "@typescript-eslint/member-delimiter-style": "error", "@typescript-eslint/member-ordering": "error", "@typescript-eslint/naming-convention": "error", diff --git a/packages/eslint-plugin/src/rules/index.ts b/packages/eslint-plugin/src/rules/index.ts index 29db58b681ab..630143d08491 100644 --- a/packages/eslint-plugin/src/rules/index.ts +++ b/packages/eslint-plugin/src/rules/index.ts @@ -82,6 +82,7 @@ import requireAwait from './require-await'; import restrictPlusOperands from './restrict-plus-operands'; import restrictTemplateExpressions from './restrict-template-expressions'; import returnAwait from './return-await'; +import initDeclarations from './init-declarations'; import semi from './semi'; import spaceBeforeFunctionParen from './space-before-function-paren'; import strictBooleanExpressions from './strict-boolean-expressions'; @@ -114,6 +115,7 @@ export default { 'func-call-spacing': funcCallSpacing, 'generic-type-naming': genericTypeNaming, indent: indent, + 'init-declarations': initDeclarations, 'interface-name-prefix': interfaceNamePrefix, 'member-delimiter-style': memberDelimiterStyle, 'member-naming': memberNaming, diff --git a/packages/eslint-plugin/src/rules/init-declarations.ts b/packages/eslint-plugin/src/rules/init-declarations.ts new file mode 100644 index 000000000000..bac1c8e20da0 --- /dev/null +++ b/packages/eslint-plugin/src/rules/init-declarations.ts @@ -0,0 +1,55 @@ +import { + TSESTree, + AST_NODE_TYPES, +} from '@typescript-eslint/experimental-utils'; +import baseRule from 'eslint/lib/rules/init-declarations'; +import * as util from '../util'; + +export type Options = util.InferOptionsTypeFromRule; +export type MessageIds = util.InferMessageIdsTypeFromRule; + +const schema = util.deepMerge( + Array.isArray(baseRule.meta.schema) + ? baseRule.meta.schema[0] + : baseRule.meta.schema, +); + +export default util.createRule({ + name: 'init-declarations', + meta: { + type: 'suggestion', + docs: { + description: + 'require or disallow initialization in variable declarations', + category: 'Variables', + recommended: false, + extendsBaseRule: true, + }, + schema, + messages: baseRule.meta.messages, + }, + defaultOptions: ['always'], + create(context, [options]) { + const rules = baseRule.create(context); + const mode = context.options[0] || 'always'; + const ignoreForLoopInit = context.options[1]?.ignoreForLoopInit || false; + + return { + 'VariableDeclaration:exit'(node: TSESTree.VariableDeclaration): void { + if (mode === 'always') { + if (node?.declare) { + return; + } + if ( + node?.parent.type === AST_NODE_TYPES.TSModuleBlock && + node?.parent?.parent?.declare + ) { + return; + } + } + + rules['VariableDeclaration:exit'](node); + }, + }; + }, +}); diff --git a/packages/eslint-plugin/tests/rules/init-declarations.test.ts b/packages/eslint-plugin/tests/rules/init-declarations.test.ts new file mode 100644 index 000000000000..b5013300195f --- /dev/null +++ b/packages/eslint-plugin/tests/rules/init-declarations.test.ts @@ -0,0 +1,402 @@ +import rule from '../../src/rules/init-declarations'; +import { RuleTester, getFixturesRootDir } from '../RuleTester'; + +const rootDir = getFixturesRootDir(); +const ruleTester = new RuleTester({ + parserOptions: { + ecmaVersion: 2018, + sourceType: 'module', + project: './tsconfig.json', + tsconfigRootDir: rootDir, + }, + parser: '@typescript-eslint/parser', +}); + +ruleTester.run('init-declarations', rule, { + valid: [ + // checking compatibility with base rule + 'var foo = null;', + 'foo = true;', + 'var foo = 1, bar = false, baz = {};', + 'function foo() { var foo = 0; var bar = []; }', + 'var fn = function() {};', + 'var foo = bar = 2;', + 'for (var i = 0; i < 1; i++) {}', + 'for (var foo in []) {}', + { code: 'for (var foo of []) {}', parserOptions: { ecmaVersion: 6 } }, + { + code: 'let a = true;', + options: ['always'], + parserOptions: { ecmaVersion: 6 }, + }, + { + code: 'const a = {};', + options: ['always'], + parserOptions: { ecmaVersion: 6 }, + }, + { + code: + 'function foo() { let a = 1, b = false; if (a) { let c = 3, d = null; } }', + options: ['always'], + parserOptions: { ecmaVersion: 6 }, + }, + { + code: + 'function foo() { const a = 1, b = true; if (a) { const c = 3, d = null; } }', + options: ['always'], + parserOptions: { ecmaVersion: 6 }, + }, + { + code: 'function foo() { let a = 1; const b = false; var c = true; }', + options: ['always'], + parserOptions: { ecmaVersion: 6 }, + }, + { + code: 'var foo;', + options: ['never'], + parserOptions: { ecmaVersion: 6 }, + }, + { + code: 'var foo, bar, baz;', + options: ['never'], + parserOptions: { ecmaVersion: 6 }, + }, + { + code: 'function foo() { var foo; var bar; }', + options: ['never'], + parserOptions: { ecmaVersion: 6 }, + }, + { + code: 'let a;', + options: ['never'], + parserOptions: { ecmaVersion: 6 }, + }, + { + code: 'const a = 1;', + options: ['never'], + parserOptions: { ecmaVersion: 6 }, + }, + { + code: 'function foo() { let a, b; if (a) { let c, d; } }', + options: ['never'], + parserOptions: { ecmaVersion: 6 }, + }, + { + code: + 'function foo() { const a = 1, b = true; if (a) { const c = 3, d = null; } }', + options: ['never'], + parserOptions: { ecmaVersion: 6 }, + }, + { + code: 'function foo() { let a; const b = false; var c; }', + options: ['never'], + parserOptions: { ecmaVersion: 6 }, + }, + { + code: 'for(var i = 0; i < 1; i++){}', + options: ['never', { ignoreForLoopInit: true }], + }, + { + code: 'for (var foo in []) {}', + options: ['never', { ignoreForLoopInit: true }], + }, + { + code: 'for (var foo of []) {}', + options: ['never', { ignoreForLoopInit: true }], + parserOptions: { ecmaVersion: 6 }, + }, + { + code: `function foo() { + var bar = 1; + let baz = 2; + const qux = 3; + }`, + options: ['always'], + }, + + // typescript-eslint + { + code: 'declare const foo: number;', + options: ['always'], + }, + { + code: 'declare const foo: number;', + options: ['never'], + }, + { + code: `declare namespace myLib { + let numberOfGreetings: number; + }`, + options: ['always'], + }, + { + code: `declare namespace myLib { + let numberOfGreetings: number; + }`, + options: ['never'], + }, + { + code: `interface GreetingSettings { + greeting: string; + duration?: number; + color?: string; + }`, + }, + { + code: `interface GreetingSettings { + greeting: string; + duration?: number; + color?: string; + }`, + options: ['never'], + }, + 'type GreetingLike = string | (() => string) | Greeter;', + { + code: 'type GreetingLike = string | (() => string) | Greeter;', + options: ['never'], + }, + ], + invalid: [ + // checking compatibility with base rule + { + code: 'var foo;', + options: ['always'], + errors: [ + { + messageId: 'initialized', + data: { idName: 'foo' }, + type: 'VariableDeclarator', + }, + ], + }, + { + code: 'for (var a in []) var foo;', + options: ['always'], + errors: [ + { + messageId: 'initialized', + data: { idName: 'foo' }, + type: 'VariableDeclarator', + }, + ], + }, + { + code: 'var foo, bar = false, baz;', + options: ['always'], + errors: [ + { + messageId: 'initialized', + data: { idName: 'foo' }, + type: 'VariableDeclarator', + }, + { + messageId: 'initialized', + data: { idName: 'baz' }, + type: 'VariableDeclarator', + }, + ], + }, + { + code: 'function foo() { var foo = 0; var bar; }', + options: ['always'], + errors: [ + { + messageId: 'initialized', + data: { idName: 'bar' }, + type: 'VariableDeclarator', + }, + ], + }, + { + code: 'function foo() { var foo; var bar = foo; }', + options: ['always'], + errors: [ + { + messageId: 'initialized', + data: { idName: 'foo' }, + type: 'VariableDeclarator', + }, + ], + }, + { + code: 'let a;', + options: ['always'], + errors: [ + { + messageId: 'initialized', + data: { idName: 'a' }, + type: 'VariableDeclarator', + }, + ], + }, + { + code: 'function foo() { let a = 1, b; if (a) { let c = 3, d = null; } }', + options: ['always'], + errors: [ + { + messageId: 'initialized', + data: { idName: 'b' }, + type: 'VariableDeclarator', + }, + ], + }, + { + code: 'function foo() { let a; const b = false; var c; }', + options: ['always'], + errors: [ + { + messageId: 'initialized', + data: { idName: 'a' }, + type: 'VariableDeclarator', + }, + { + messageId: 'initialized', + data: { idName: 'c' }, + type: 'VariableDeclarator', + }, + ], + }, + { + code: 'var foo = bar = 2;', + options: ['never'], + errors: [ + { + messageId: 'notInitialized', + data: { idName: 'foo' }, + type: 'VariableDeclarator', + }, + ], + }, + { + code: 'var foo = true;', + options: ['never'], + errors: [ + { + messageId: 'notInitialized', + data: { idName: 'foo' }, + type: 'VariableDeclarator', + }, + ], + }, + { + code: 'var foo, bar = 5, baz = 3;', + options: ['never'], + errors: [ + { + messageId: 'notInitialized', + data: { idName: 'bar' }, + type: 'VariableDeclarator', + }, + { + messageId: 'notInitialized', + data: { idName: 'baz' }, + type: 'VariableDeclarator', + }, + ], + }, + { + code: 'function foo() { var foo; var bar = foo; }', + options: ['never'], + errors: [ + { + messageId: 'notInitialized', + data: { idName: 'bar' }, + + type: 'VariableDeclarator', + }, + ], + }, + { + code: 'let a = 1;', + options: ['never'], + errors: [ + { + messageId: 'notInitialized', + data: { idName: 'a' }, + type: 'VariableDeclarator', + }, + ], + }, + { + code: "function foo() { let a = 'foo', b; if (a) { let c, d; } }", + options: ['never'], + errors: [ + { + messageId: 'notInitialized', + data: { idName: 'a' }, + type: 'VariableDeclarator', + }, + ], + }, + { + code: 'function foo() { let a; const b = false; var c = 1; }', + options: ['never'], + errors: [ + { + messageId: 'notInitialized', + data: { idName: 'c' }, + type: 'VariableDeclarator', + }, + ], + }, + { + code: 'for(var i = 0; i < 1; i++){}', + options: ['never'], + errors: [ + { + messageId: 'notInitialized', + data: { idName: 'i' }, + type: 'VariableDeclarator', + }, + ], + }, + { + code: 'for (var foo in []) {}', + options: ['never'], + errors: [ + { + messageId: 'notInitialized', + data: { idName: 'foo' }, + type: 'VariableDeclarator', + }, + ], + }, + { + code: 'for (var foo of []) {}', + options: ['never'], + errors: [ + { + messageId: 'notInitialized', + data: { idName: 'foo' }, + type: 'VariableDeclarator', + }, + ], + }, + { + code: `function foo() { + var bar; + }`, + options: ['always'], + errors: [ + { + messageId: 'initialized', + data: { idName: 'bar' }, + type: 'VariableDeclarator', + }, + ], + }, + + // typescript-eslint + { + code: 'let arr: string[] = ["arr","ar"];', + options: ['never'], + errors: [ + { + messageId: 'notInitialized', + data: { idName: 'arr' }, + type: 'VariableDeclarator', + }, + ], + }, + ], +}); diff --git a/packages/eslint-plugin/typings/eslint-rules.d.ts b/packages/eslint-plugin/typings/eslint-rules.d.ts index ea60d9b31697..84d9071ead65 100644 --- a/packages/eslint-plugin/typings/eslint-rules.d.ts +++ b/packages/eslint-plugin/typings/eslint-rules.d.ts @@ -543,3 +543,21 @@ declare module 'eslint/lib/rules/no-extra-semi' { >; export = rule; } + +declare module 'eslint/lib/rulesinit-declarations' { + import { TSESLint, TSESTree } from '@typescript-eslint/experimental-utils'; + + const rule: TSESLint.RuleModule< + never, + [ + 'always' | 'never', + { + ignoreForLoopInit?: boolean; + }?, + ], + { + 'VariableDeclaration:exit'(node: TSESTree.VariableDeclaration): void; + } + >; + export = rule; +} From 1b949b56cf1762bdf4dda41d65caa4a96952bbac Mon Sep 17 00:00:00 2001 From: Anix Date: Fri, 27 Mar 2020 17:54:38 +0000 Subject: [PATCH 02/19] docs: referring to base rule for init-declaratoins --- .../docs/rules/init-declarations.md | 130 ++---------------- 1 file changed, 8 insertions(+), 122 deletions(-) diff --git a/packages/eslint-plugin/docs/rules/init-declarations.md b/packages/eslint-plugin/docs/rules/init-declarations.md index 979e9775c401..5b49b99e3475 100644 --- a/packages/eslint-plugin/docs/rules/init-declarations.md +++ b/packages/eslint-plugin/docs/rules/init-declarations.md @@ -1,140 +1,26 @@ # require or disallow initialization in variable declarations (`init-declarations`) -In Typescript, variables can be assigned during declaration, or at any point afterwards using an assignment statement. For example, in the following code, `foo` is initialized during declaration, while `bar` is initialized later. - -```ts -var foo: number = 1; -var bar: number; - -if (foo) { - bar = 1; -} else { - bar = 2; -} -``` - ## Rule Details -This rule is aimed at enforcing or eliminating variable initializations during declaration. For example, in the following code, `foo` is initialized during declaration, while `bar` is not. - -```ts -var foo: number = 1; -var bar; - -bar: number = 2; -``` - -This rule aims to bring consistency to variable initializations and declarations. - -Variables must be initialized at declaration (default) - -```tson -{ - "@typescript-eslint/init-declarations": ["error", "always"], -} -``` +This rule extends the base [`eslint/init-declarations`](https://eslint.org/docs/rules/init-declarations) rule. +It supports all options and features of the base rule. -Variables must not be initialized at declaration +## How to use -```tson +```cjson { - "@typescript-eslint/init-declarations": ["error", "never"] + // note you must disable the base rule as it can report incorrect errors + "init-declarations": "off", + "@typescript-eslint/init-declarations": ["error"] } ``` ## Options -```ts -{ - //Variables must not be initialized at declaration, except in for loops, where it is allowed - // Only applicable when the string options is 'never' - ignoreForLoopInit: Boolean; -} -``` - -```ts -export defaultOptions = { - ignoreForLoopInit : false -} - -``` - -### always - -Examples of **incorrect** code for the default `"always"` option: - -```ts -function foo() { - var bar: string; - let baz: string; -} -``` - -Examples of **correct** code for the default `"always"` option: - -```ts -function foo() { - var bar: number = 1; - let baz: number = 2; - const qux: number = 3; -} - -declare const foo: number; - -declare namespace myLib { - let numberOfGreetings: number; -} - -interface GreetingSettings { - greeting: string; - duration?: number; - color?: string; -} - -type GreetingLike = GreetingSettings; -``` - -### never - -Examples of **incorrect** code for the `"never"` option: - -```ts -function foo() { - var bar: number = 1; - let baz: number = 2; - - for (var i = 0; i < 1; i++) {} -} - -let arr: string[] = ['arr', 'ar']; -``` - -Examples of **correct** code for the `"never"` option: - -```ts -function foo() { - var bar: number; - let baz: number; - const buzz: number = 1; -} -``` - -The `"never"` option ignores `const` variable initializations. - -### ignoreForLoopInit - -Examples of **correct** code for the `"never", { "ignoreForLoopInit": true }` options: - -```ts -/*eslint @typescript-eslint/init-declarations: ["error", "never", { "ignoreForLoopInit": true }]*/ - -for (var i: number = 0; i < 1; i++) {} -``` +See [`eslint/init-declarations` options](https://eslint.org/docs/rules/init-declarations#options). ## When Not To Use It When you are indifferent as to how your variables are initialized. -This rule is fully compatible with base rule - Taken with ❤️ [from ESLint core](https://github.com/eslint/eslint/blob/master/docs/rules/init-declarations.md) From e0b018b3d1a8379c1fd4b79ae5f648bc3343f130 Mon Sep 17 00:00:00 2001 From: Anix Date: Sun, 29 Mar 2020 14:38:02 +0000 Subject: [PATCH 03/19] chore: added messageid to rule typing --- packages/eslint-plugin/typings/eslint-rules.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin/typings/eslint-rules.d.ts b/packages/eslint-plugin/typings/eslint-rules.d.ts index 84d9071ead65..44c092e4cb53 100644 --- a/packages/eslint-plugin/typings/eslint-rules.d.ts +++ b/packages/eslint-plugin/typings/eslint-rules.d.ts @@ -548,7 +548,7 @@ declare module 'eslint/lib/rulesinit-declarations' { import { TSESLint, TSESTree } from '@typescript-eslint/experimental-utils'; const rule: TSESLint.RuleModule< - never, + 'initialized' | 'notInitialized', [ 'always' | 'never', { From b2edb04e7337e0a2c40797ad622c2db4fa34217c Mon Sep 17 00:00:00 2001 From: Anix Date: Mon, 30 Mar 2020 00:07:13 +0530 Subject: [PATCH 04/19] chore: updated the wrong module path for declaration file Co-Authored-By: Brad Zacher --- packages/eslint-plugin/typings/eslint-rules.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin/typings/eslint-rules.d.ts b/packages/eslint-plugin/typings/eslint-rules.d.ts index 44c092e4cb53..aeee155a7961 100644 --- a/packages/eslint-plugin/typings/eslint-rules.d.ts +++ b/packages/eslint-plugin/typings/eslint-rules.d.ts @@ -544,7 +544,7 @@ declare module 'eslint/lib/rules/no-extra-semi' { export = rule; } -declare module 'eslint/lib/rulesinit-declarations' { +declare module 'eslint/lib/rules/init-declarations' { import { TSESLint, TSESTree } from '@typescript-eslint/experimental-utils'; const rule: TSESLint.RuleModule< From 9bb2e64957392430da66b8a75bc77ff8a379b117 Mon Sep 17 00:00:00 2001 From: Anix Date: Mon, 30 Mar 2020 02:51:29 +0000 Subject: [PATCH 05/19] chore: minor type fixes --- .../src/rules/init-declarations.ts | 22 ++++++--- .../tests/rules/init-declarations.test.ts | 47 ++++++++++--------- 2 files changed, 39 insertions(+), 30 deletions(-) diff --git a/packages/eslint-plugin/src/rules/init-declarations.ts b/packages/eslint-plugin/src/rules/init-declarations.ts index bac1c8e20da0..00964dccf8c1 100644 --- a/packages/eslint-plugin/src/rules/init-declarations.ts +++ b/packages/eslint-plugin/src/rules/init-declarations.ts @@ -3,18 +3,24 @@ import { AST_NODE_TYPES, } from '@typescript-eslint/experimental-utils'; import baseRule from 'eslint/lib/rules/init-declarations'; -import * as util from '../util'; +import { + InferOptionsTypeFromRule, + InferMessageIdsTypeFromRule, + createRule, + deepMerge, +} from '../util'; +import * as ts from 'typescript'; -export type Options = util.InferOptionsTypeFromRule; -export type MessageIds = util.InferMessageIdsTypeFromRule; +export type Options = InferOptionsTypeFromRule; +export type MessageIds = InferMessageIdsTypeFromRule; -const schema = util.deepMerge( +const schema = deepMerge( Array.isArray(baseRule.meta.schema) ? baseRule.meta.schema[0] : baseRule.meta.schema, ); -export default util.createRule({ +export default createRule({ name: 'init-declarations', meta: { type: 'suggestion', @@ -29,13 +35,15 @@ export default util.createRule({ messages: baseRule.meta.messages, }, defaultOptions: ['always'], - create(context, [options]) { + create(context) { const rules = baseRule.create(context); const mode = context.options[0] || 'always'; const ignoreForLoopInit = context.options[1]?.ignoreForLoopInit || false; return { - 'VariableDeclaration:exit'(node: TSESTree.VariableDeclaration): void { + 'VariableDeclaration:exit'( + node: TSESTree.VariableDeclaration | ts.Node, + ): void { if (mode === 'always') { if (node?.declare) { return; diff --git a/packages/eslint-plugin/tests/rules/init-declarations.test.ts b/packages/eslint-plugin/tests/rules/init-declarations.test.ts index b5013300195f..7b85c4baccdb 100644 --- a/packages/eslint-plugin/tests/rules/init-declarations.test.ts +++ b/packages/eslint-plugin/tests/rules/init-declarations.test.ts @@ -1,3 +1,4 @@ +import { AST_NODE_TYPES } from '@typescript-eslint/experimental-utils'; import rule from '../../src/rules/init-declarations'; import { RuleTester, getFixturesRootDir } from '../RuleTester'; @@ -165,7 +166,7 @@ ruleTester.run('init-declarations', rule, { { messageId: 'initialized', data: { idName: 'foo' }, - type: 'VariableDeclarator', + type: AST_NODE_TYPES.VariableDeclarator, }, ], }, @@ -176,7 +177,7 @@ ruleTester.run('init-declarations', rule, { { messageId: 'initialized', data: { idName: 'foo' }, - type: 'VariableDeclarator', + type: AST_NODE_TYPES.VariableDeclarator, }, ], }, @@ -187,12 +188,12 @@ ruleTester.run('init-declarations', rule, { { messageId: 'initialized', data: { idName: 'foo' }, - type: 'VariableDeclarator', + type: AST_NODE_TYPES.VariableDeclarator, }, { messageId: 'initialized', data: { idName: 'baz' }, - type: 'VariableDeclarator', + type: AST_NODE_TYPES.VariableDeclarator, }, ], }, @@ -203,7 +204,7 @@ ruleTester.run('init-declarations', rule, { { messageId: 'initialized', data: { idName: 'bar' }, - type: 'VariableDeclarator', + type: AST_NODE_TYPES.VariableDeclarator, }, ], }, @@ -214,7 +215,7 @@ ruleTester.run('init-declarations', rule, { { messageId: 'initialized', data: { idName: 'foo' }, - type: 'VariableDeclarator', + type: AST_NODE_TYPES.VariableDeclarator, }, ], }, @@ -225,7 +226,7 @@ ruleTester.run('init-declarations', rule, { { messageId: 'initialized', data: { idName: 'a' }, - type: 'VariableDeclarator', + type: AST_NODE_TYPES.VariableDeclarator, }, ], }, @@ -236,7 +237,7 @@ ruleTester.run('init-declarations', rule, { { messageId: 'initialized', data: { idName: 'b' }, - type: 'VariableDeclarator', + type: AST_NODE_TYPES.VariableDeclarator, }, ], }, @@ -247,12 +248,12 @@ ruleTester.run('init-declarations', rule, { { messageId: 'initialized', data: { idName: 'a' }, - type: 'VariableDeclarator', + type: AST_NODE_TYPES.VariableDeclarator, }, { messageId: 'initialized', data: { idName: 'c' }, - type: 'VariableDeclarator', + type: AST_NODE_TYPES.VariableDeclarator, }, ], }, @@ -263,7 +264,7 @@ ruleTester.run('init-declarations', rule, { { messageId: 'notInitialized', data: { idName: 'foo' }, - type: 'VariableDeclarator', + type: AST_NODE_TYPES.VariableDeclarator, }, ], }, @@ -274,7 +275,7 @@ ruleTester.run('init-declarations', rule, { { messageId: 'notInitialized', data: { idName: 'foo' }, - type: 'VariableDeclarator', + type: AST_NODE_TYPES.VariableDeclarator, }, ], }, @@ -285,12 +286,12 @@ ruleTester.run('init-declarations', rule, { { messageId: 'notInitialized', data: { idName: 'bar' }, - type: 'VariableDeclarator', + type: AST_NODE_TYPES.VariableDeclarator, }, { messageId: 'notInitialized', data: { idName: 'baz' }, - type: 'VariableDeclarator', + type: AST_NODE_TYPES.VariableDeclarator, }, ], }, @@ -302,7 +303,7 @@ ruleTester.run('init-declarations', rule, { messageId: 'notInitialized', data: { idName: 'bar' }, - type: 'VariableDeclarator', + type: AST_NODE_TYPES.VariableDeclarator, }, ], }, @@ -313,7 +314,7 @@ ruleTester.run('init-declarations', rule, { { messageId: 'notInitialized', data: { idName: 'a' }, - type: 'VariableDeclarator', + type: AST_NODE_TYPES.VariableDeclarator, }, ], }, @@ -324,7 +325,7 @@ ruleTester.run('init-declarations', rule, { { messageId: 'notInitialized', data: { idName: 'a' }, - type: 'VariableDeclarator', + type: AST_NODE_TYPES.VariableDeclarator, }, ], }, @@ -335,7 +336,7 @@ ruleTester.run('init-declarations', rule, { { messageId: 'notInitialized', data: { idName: 'c' }, - type: 'VariableDeclarator', + type: AST_NODE_TYPES.VariableDeclarator, }, ], }, @@ -346,7 +347,7 @@ ruleTester.run('init-declarations', rule, { { messageId: 'notInitialized', data: { idName: 'i' }, - type: 'VariableDeclarator', + type: AST_NODE_TYPES.VariableDeclarator, }, ], }, @@ -357,7 +358,7 @@ ruleTester.run('init-declarations', rule, { { messageId: 'notInitialized', data: { idName: 'foo' }, - type: 'VariableDeclarator', + type: AST_NODE_TYPES.VariableDeclarator, }, ], }, @@ -368,7 +369,7 @@ ruleTester.run('init-declarations', rule, { { messageId: 'notInitialized', data: { idName: 'foo' }, - type: 'VariableDeclarator', + type: AST_NODE_TYPES.VariableDeclarator, }, ], }, @@ -381,7 +382,7 @@ ruleTester.run('init-declarations', rule, { { messageId: 'initialized', data: { idName: 'bar' }, - type: 'VariableDeclarator', + type: AST_NODE_TYPES.VariableDeclarator, }, ], }, @@ -394,7 +395,7 @@ ruleTester.run('init-declarations', rule, { { messageId: 'notInitialized', data: { idName: 'arr' }, - type: 'VariableDeclarator', + type: AST_NODE_TYPES.VariableDeclarator, }, ], }, From a8f0b8287f7f8d8b2fd28e391d0fb1eb513a4d7d Mon Sep 17 00:00:00 2001 From: Anix Date: Mon, 30 Mar 2020 03:14:25 +0000 Subject: [PATCH 06/19] chore: tyoe fixes --- packages/eslint-plugin/src/rules/init-declarations.ts | 6 ++---- packages/eslint-plugin/typings/eslint-rules.d.ts | 4 +++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/eslint-plugin/src/rules/init-declarations.ts b/packages/eslint-plugin/src/rules/init-declarations.ts index 00964dccf8c1..dcdb5fed37b3 100644 --- a/packages/eslint-plugin/src/rules/init-declarations.ts +++ b/packages/eslint-plugin/src/rules/init-declarations.ts @@ -9,7 +9,6 @@ import { createRule, deepMerge, } from '../util'; -import * as ts from 'typescript'; export type Options = InferOptionsTypeFromRule; export type MessageIds = InferMessageIdsTypeFromRule; @@ -38,18 +37,17 @@ export default createRule({ create(context) { const rules = baseRule.create(context); const mode = context.options[0] || 'always'; - const ignoreForLoopInit = context.options[1]?.ignoreForLoopInit || false; return { 'VariableDeclaration:exit'( - node: TSESTree.VariableDeclaration | ts.Node, + node: TSESTree.VariableDeclaration | TSESTree.Node, ): void { if (mode === 'always') { if (node?.declare) { return; } if ( - node?.parent.type === AST_NODE_TYPES.TSModuleBlock && + node?.parent?.type === AST_NODE_TYPES.TSModuleBlock && node?.parent?.parent?.declare ) { return; diff --git a/packages/eslint-plugin/typings/eslint-rules.d.ts b/packages/eslint-plugin/typings/eslint-rules.d.ts index aeee155a7961..deeece4c4a5c 100644 --- a/packages/eslint-plugin/typings/eslint-rules.d.ts +++ b/packages/eslint-plugin/typings/eslint-rules.d.ts @@ -556,7 +556,9 @@ declare module 'eslint/lib/rules/init-declarations' { }?, ], { - 'VariableDeclaration:exit'(node: TSESTree.VariableDeclaration): void; + 'VariableDeclaration:exit'( + node: TSESTree.VariableDeclaration | TSESTree.Node, + ): void; } >; export = rule; From 7d5d49c378ac4fd839b4a7152a2cd6dd5f0903da Mon Sep 17 00:00:00 2001 From: Anix Date: Mon, 30 Mar 2020 14:36:33 +0530 Subject: [PATCH 07/19] chore: removing union type ts.Node Co-Authored-By: Brad Zacher --- packages/eslint-plugin/src/rules/init-declarations.ts | 2 +- packages/eslint-plugin/typings/eslint-rules.d.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/eslint-plugin/src/rules/init-declarations.ts b/packages/eslint-plugin/src/rules/init-declarations.ts index dcdb5fed37b3..4161861c269d 100644 --- a/packages/eslint-plugin/src/rules/init-declarations.ts +++ b/packages/eslint-plugin/src/rules/init-declarations.ts @@ -40,7 +40,7 @@ export default createRule({ return { 'VariableDeclaration:exit'( - node: TSESTree.VariableDeclaration | TSESTree.Node, + node: TSESTree.VariableDeclaration, ): void { if (mode === 'always') { if (node?.declare) { diff --git a/packages/eslint-plugin/typings/eslint-rules.d.ts b/packages/eslint-plugin/typings/eslint-rules.d.ts index deeece4c4a5c..723515029bf4 100644 --- a/packages/eslint-plugin/typings/eslint-rules.d.ts +++ b/packages/eslint-plugin/typings/eslint-rules.d.ts @@ -557,7 +557,7 @@ declare module 'eslint/lib/rules/init-declarations' { ], { 'VariableDeclaration:exit'( - node: TSESTree.VariableDeclaration | TSESTree.Node, + node: TSESTree.VariableDeclaration, ): void; } >; From 25a791557d3fdcebf693612ca2c4191c2a7ce25a Mon Sep 17 00:00:00 2001 From: Anix Date: Wed, 1 Apr 2020 10:32:58 +0000 Subject: [PATCH 08/19] chore: formatting and typecheck fixes --- packages/eslint-plugin/src/rules/init-declarations.ts | 9 ++++----- packages/eslint-plugin/typings/eslint-rules.d.ts | 4 +--- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/packages/eslint-plugin/src/rules/init-declarations.ts b/packages/eslint-plugin/src/rules/init-declarations.ts index 4161861c269d..fb074c2f521c 100644 --- a/packages/eslint-plugin/src/rules/init-declarations.ts +++ b/packages/eslint-plugin/src/rules/init-declarations.ts @@ -39,16 +39,15 @@ export default createRule({ const mode = context.options[0] || 'always'; return { - 'VariableDeclaration:exit'( - node: TSESTree.VariableDeclaration, - ): void { + 'VariableDeclaration:exit'(node: TSESTree.VariableDeclaration): void { if (mode === 'always') { if (node?.declare) { return; } if ( - node?.parent?.type === AST_NODE_TYPES.TSModuleBlock && - node?.parent?.parent?.declare + node.parent?.type === AST_NODE_TYPES.TSModuleBlock && + node.parent?.parent?.type === AST_NODE_TYPES.TSModuleDeclaration && + node.parent?.parent?.declare ) { return; } diff --git a/packages/eslint-plugin/typings/eslint-rules.d.ts b/packages/eslint-plugin/typings/eslint-rules.d.ts index 723515029bf4..aeee155a7961 100644 --- a/packages/eslint-plugin/typings/eslint-rules.d.ts +++ b/packages/eslint-plugin/typings/eslint-rules.d.ts @@ -556,9 +556,7 @@ declare module 'eslint/lib/rules/init-declarations' { }?, ], { - 'VariableDeclaration:exit'( - node: TSESTree.VariableDeclaration, - ): void; + 'VariableDeclaration:exit'(node: TSESTree.VariableDeclaration): void; } >; export = rule; From b049e4773742d0c8c4b58ead1b93b34c4cfb23e5 Mon Sep 17 00:00:00 2001 From: Anix Date: Thu, 2 Apr 2020 11:23:53 +0000 Subject: [PATCH 09/19] chore: linting fixes --- .../tests/rules/init-declarations.test.ts | 254 ++++++++++++++---- 1 file changed, 198 insertions(+), 56 deletions(-) diff --git a/packages/eslint-plugin/tests/rules/init-declarations.test.ts b/packages/eslint-plugin/tests/rules/init-declarations.test.ts index 7b85c4baccdb..e975852cca6d 100644 --- a/packages/eslint-plugin/tests/rules/init-declarations.test.ts +++ b/packages/eslint-plugin/tests/rules/init-declarations.test.ts @@ -18,13 +18,31 @@ ruleTester.run('init-declarations', rule, { // checking compatibility with base rule 'var foo = null;', 'foo = true;', - 'var foo = 1, bar = false, baz = {};', - 'function foo() { var foo = 0; var bar = []; }', + ` +var foo = 1, + bar = false, + baz = {}; + `, + ` +function foo() { + var foo = 0; + var bar = []; +} + `, 'var fn = function() {};', - 'var foo = bar = 2;', + 'var foo = (bar = 2);', 'for (var i = 0; i < 1; i++) {}', - 'for (var foo in []) {}', - { code: 'for (var foo of []) {}', parserOptions: { ecmaVersion: 6 } }, + ` +for (var foo in []) { +} + `, + { + code: ` +for (var foo of []) { +} + `, + parserOptions: { ecmaVersion: 6 }, + }, { code: 'let a = true;', options: ['always'], @@ -36,19 +54,41 @@ ruleTester.run('init-declarations', rule, { parserOptions: { ecmaVersion: 6 }, }, { - code: - 'function foo() { let a = 1, b = false; if (a) { let c = 3, d = null; } }', + code: ` +function foo() { + let a = 1, + b = false; + if (a) { + let c = 3, + d = null; + } +} + `, options: ['always'], parserOptions: { ecmaVersion: 6 }, }, { - code: - 'function foo() { const a = 1, b = true; if (a) { const c = 3, d = null; } }', + code: ` +function foo() { + const a = 1, + b = true; + if (a) { + const c = 3, + d = null; + } +} + `, options: ['always'], parserOptions: { ecmaVersion: 6 }, }, { - code: 'function foo() { let a = 1; const b = false; var c = true; }', + code: ` +function foo() { + let a = 1; + const b = false; + var c = true; +} + `, options: ['always'], parserOptions: { ecmaVersion: 6 }, }, @@ -63,7 +103,12 @@ ruleTester.run('init-declarations', rule, { parserOptions: { ecmaVersion: 6 }, }, { - code: 'function foo() { var foo; var bar; }', + code: ` +function foo() { + var foo; + var bar; +} + `, options: ['never'], parserOptions: { ecmaVersion: 6 }, }, @@ -78,40 +123,69 @@ ruleTester.run('init-declarations', rule, { parserOptions: { ecmaVersion: 6 }, }, { - code: 'function foo() { let a, b; if (a) { let c, d; } }', + code: ` +function foo() { + let a, b; + if (a) { + let c, d; + } +} + `, options: ['never'], parserOptions: { ecmaVersion: 6 }, }, { - code: - 'function foo() { const a = 1, b = true; if (a) { const c = 3, d = null; } }', + code: ` +function foo() { + const a = 1, + b = true; + if (a) { + const c = 3, + d = null; + } +} + `, options: ['never'], parserOptions: { ecmaVersion: 6 }, }, { - code: 'function foo() { let a; const b = false; var c; }', + code: ` +function foo() { + let a; + const b = false; + var c; +} + `, options: ['never'], parserOptions: { ecmaVersion: 6 }, }, { - code: 'for(var i = 0; i < 1; i++){}', + code: 'for (var i = 0; i < 1; i++) {}', options: ['never', { ignoreForLoopInit: true }], }, { - code: 'for (var foo in []) {}', + code: ` +for (var foo in []) { +} + `, options: ['never', { ignoreForLoopInit: true }], }, { - code: 'for (var foo of []) {}', + code: ` +for (var foo of []) { +} + `, options: ['never', { ignoreForLoopInit: true }], parserOptions: { ecmaVersion: 6 }, }, { - code: `function foo() { - var bar = 1; - let baz = 2; - const qux = 3; - }`, + code: ` +function foo() { + var bar = 1; + let baz = 2; + const qux = 3; +} + `, options: ['always'], }, @@ -125,30 +199,38 @@ ruleTester.run('init-declarations', rule, { options: ['never'], }, { - code: `declare namespace myLib { - let numberOfGreetings: number; - }`, + code: ` +declare namespace myLib { + let numberOfGreetings: number; +} + `, options: ['always'], }, { - code: `declare namespace myLib { - let numberOfGreetings: number; - }`, + code: ` +declare namespace myLib { + let numberOfGreetings: number; +} + `, options: ['never'], }, { - code: `interface GreetingSettings { - greeting: string; - duration?: number; - color?: string; - }`, + code: ` +interface GreetingSettings { + greeting: string; + duration?: number; + color?: string; +} + `, }, { - code: `interface GreetingSettings { - greeting: string; - duration?: number; - color?: string; - }`, + code: ` +interface GreetingSettings { + greeting: string; + duration?: number; + color?: string; +} + `, options: ['never'], }, 'type GreetingLike = string | (() => string) | Greeter;', @@ -182,7 +264,11 @@ ruleTester.run('init-declarations', rule, { ], }, { - code: 'var foo, bar = false, baz;', + code: ` +var foo, + bar = false, + baz; + `, options: ['always'], errors: [ { @@ -198,7 +284,12 @@ ruleTester.run('init-declarations', rule, { ], }, { - code: 'function foo() { var foo = 0; var bar; }', + code: ` +function foo() { + var foo = 0; + var bar; +} + `, options: ['always'], errors: [ { @@ -209,7 +300,12 @@ ruleTester.run('init-declarations', rule, { ], }, { - code: 'function foo() { var foo; var bar = foo; }', + code: ` +function foo() { + var foo; + var bar = foo; +} + `, options: ['always'], errors: [ { @@ -231,7 +327,16 @@ ruleTester.run('init-declarations', rule, { ], }, { - code: 'function foo() { let a = 1, b; if (a) { let c = 3, d = null; } }', + code: ` +function foo() { + let a = 1, + b; + if (a) { + let c = 3, + d = null; + } +} + `, options: ['always'], errors: [ { @@ -242,7 +347,13 @@ ruleTester.run('init-declarations', rule, { ], }, { - code: 'function foo() { let a; const b = false; var c; }', + code: ` +function foo() { + let a; + const b = false; + var c; +} + `, options: ['always'], errors: [ { @@ -258,7 +369,7 @@ ruleTester.run('init-declarations', rule, { ], }, { - code: 'var foo = bar = 2;', + code: 'var foo = (bar = 2);', options: ['never'], errors: [ { @@ -280,7 +391,11 @@ ruleTester.run('init-declarations', rule, { ], }, { - code: 'var foo, bar = 5, baz = 3;', + code: ` +var foo, + bar = 5, + baz = 3; + `, options: ['never'], errors: [ { @@ -296,7 +411,12 @@ ruleTester.run('init-declarations', rule, { ], }, { - code: 'function foo() { var foo; var bar = foo; }', + code: ` +function foo() { + var foo; + var bar = foo; +} + `, options: ['never'], errors: [ { @@ -319,7 +439,15 @@ ruleTester.run('init-declarations', rule, { ], }, { - code: "function foo() { let a = 'foo', b; if (a) { let c, d; } }", + code: ` +function foo() { + let a = 'foo', + b; + if (a) { + let c, d; + } +} + `, options: ['never'], errors: [ { @@ -330,7 +458,13 @@ ruleTester.run('init-declarations', rule, { ], }, { - code: 'function foo() { let a; const b = false; var c = 1; }', + code: ` +function foo() { + let a; + const b = false; + var c = 1; +} + `, options: ['never'], errors: [ { @@ -341,7 +475,7 @@ ruleTester.run('init-declarations', rule, { ], }, { - code: 'for(var i = 0; i < 1; i++){}', + code: 'for (var i = 0; i < 1; i++) {}', options: ['never'], errors: [ { @@ -352,7 +486,10 @@ ruleTester.run('init-declarations', rule, { ], }, { - code: 'for (var foo in []) {}', + code: ` +for (var foo in []) { +} + `, options: ['never'], errors: [ { @@ -363,7 +500,10 @@ ruleTester.run('init-declarations', rule, { ], }, { - code: 'for (var foo of []) {}', + code: ` +for (var foo of []) { +} + `, options: ['never'], errors: [ { @@ -374,9 +514,11 @@ ruleTester.run('init-declarations', rule, { ], }, { - code: `function foo() { - var bar; - }`, + code: ` +function foo() { + var bar; +} + `, options: ['always'], errors: [ { @@ -389,7 +531,7 @@ ruleTester.run('init-declarations', rule, { // typescript-eslint { - code: 'let arr: string[] = ["arr","ar"];', + code: "let arr: string[] = ['arr', 'ar'];", options: ['never'], errors: [ { From 5e9f1e5bb705b89b4c37f0e3cf9de9b5c2086d53 Mon Sep 17 00:00:00 2001 From: Anix Date: Thu, 2 Apr 2020 11:47:33 +0000 Subject: [PATCH 10/19] chore: linting fixes --- .../eslint-plugin/tests/rules/init-declarations.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/eslint-plugin/tests/rules/init-declarations.test.ts b/packages/eslint-plugin/tests/rules/init-declarations.test.ts index e975852cca6d..32e6b663135f 100644 --- a/packages/eslint-plugin/tests/rules/init-declarations.test.ts +++ b/packages/eslint-plugin/tests/rules/init-declarations.test.ts @@ -40,7 +40,7 @@ for (var foo in []) { code: ` for (var foo of []) { } - `, + `, parserOptions: { ecmaVersion: 6 }, }, { @@ -63,7 +63,7 @@ function foo() { d = null; } } - `, + `, options: ['always'], parserOptions: { ecmaVersion: 6 }, }, @@ -77,7 +77,7 @@ function foo() { d = null; } } - `, + `, options: ['always'], parserOptions: { ecmaVersion: 6 }, }, @@ -144,7 +144,7 @@ function foo() { d = null; } } - `, + `, options: ['never'], parserOptions: { ecmaVersion: 6 }, }, From 281582a74b5b8ee403c5f661b8c3d534c1fa7528 Mon Sep 17 00:00:00 2001 From: Anix Date: Thu, 2 Apr 2020 12:24:53 +0000 Subject: [PATCH 11/19] chore: added tests to increase coverage --- .../tests/rules/init-declarations.test.ts | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/packages/eslint-plugin/tests/rules/init-declarations.test.ts b/packages/eslint-plugin/tests/rules/init-declarations.test.ts index 32e6b663135f..30e187b6d2da 100644 --- a/packages/eslint-plugin/tests/rules/init-declarations.test.ts +++ b/packages/eslint-plugin/tests/rules/init-declarations.test.ts @@ -238,6 +238,38 @@ interface GreetingSettings { code: 'type GreetingLike = string | (() => string) | Greeter;', options: ['never'], }, + { + code: ` +function foo() { + var bar: string; +} + `, + options: ['never'], + }, + { + code: 'var bar: string;', + options: ['never'], + }, + { + code: ` +var bar: string = function(): string { + return 'string'; +}; + `, + options: ['always'], + }, + { + code: ` +var bar: string = function(arg1: stirng): string { + return 'string'; +}; + `, + options: ['always'], + }, + { + code: "function foo(arg1: string = 'string'): void {}", + options: ['never'], + }, ], invalid: [ // checking compatibility with base rule @@ -541,5 +573,27 @@ function foo() { }, ], }, + { + code: 'let arr: string = function() {};', + options: ['never'], + errors: [ + { + messageId: 'notInitialized', + data: { idName: 'arr' }, + type: AST_NODE_TYPES.VariableDeclarator, + }, + ], + }, + { + code: 'let arr: string;', + options: ['always'], + errors: [ + { + messageId: 'initialized', + data: { idName: 'arr' }, + type: AST_NODE_TYPES.VariableDeclarator, + }, + ], + }, ], }); From f2b0294dcea05f9b9f7c09410680cd30dee2ad77 Mon Sep 17 00:00:00 2001 From: Anix Date: Thu, 2 Apr 2020 13:35:43 +0000 Subject: [PATCH 12/19] chore: added more tests --- .../tests/rules/init-declarations.test.ts | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/packages/eslint-plugin/tests/rules/init-declarations.test.ts b/packages/eslint-plugin/tests/rules/init-declarations.test.ts index 30e187b6d2da..8fe37d28b4ff 100644 --- a/packages/eslint-plugin/tests/rules/init-declarations.test.ts +++ b/packages/eslint-plugin/tests/rules/init-declarations.test.ts @@ -270,6 +270,55 @@ var bar: string = function(arg1: stirng): string { code: "function foo(arg1: string = 'string'): void {}", options: ['never'], }, + { + code: "const foo: string = 'hello';", + options: ['never'], + }, + { + code: ` +const class1 = class NAME { + constructor() { + var name1: string = 'hello'; + } +}; + `, + }, + { + code: ` +const class1 = class NAME { + static pi: number = 3.14; +}; + `, + }, + { + code: ` +const class1 = class NAME { + static pi: number = 3.14; +}; + `, + options: ['never'], + }, + { + code: ` +interface IEmployee { + empCode: number; + empName: string; + getSalary: (number) => number; // arrow function + getManagerName(number): string; +} + `, + }, + { + code: ` +interface IEmployee { + empCode: number; + empName: string; + getSalary: (number) => number; // arrow function + getManagerName(number): string; +} + `, + options: ['never'], + }, ], invalid: [ // checking compatibility with base rule @@ -584,6 +633,23 @@ function foo() { }, ], }, + { + code: ` +const class1 = class NAME { + constructor() { + var name1: string = 'hello'; + } +}; + `, + options: ['never'], + errors: [ + { + messageId: 'notInitialized', + data: { idName: 'name1' }, + type: AST_NODE_TYPES.VariableDeclarator, + }, + ], + }, { code: 'let arr: string;', options: ['always'], From 44f4f167bde67877dab6a2f29931bcec12b3c7d8 Mon Sep 17 00:00:00 2001 From: Anix Date: Fri, 10 Apr 2020 10:04:09 +0000 Subject: [PATCH 13/19] chore: imporved typecheck --- packages/eslint-plugin/src/rules/init-declarations.ts | 2 +- .../eslint-plugin/tests/rules/init-declarations.test.ts | 9 +-------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/packages/eslint-plugin/src/rules/init-declarations.ts b/packages/eslint-plugin/src/rules/init-declarations.ts index fb074c2f521c..2c012f208fd9 100644 --- a/packages/eslint-plugin/src/rules/init-declarations.ts +++ b/packages/eslint-plugin/src/rules/init-declarations.ts @@ -41,7 +41,7 @@ export default createRule({ return { 'VariableDeclaration:exit'(node: TSESTree.VariableDeclaration): void { if (mode === 'always') { - if (node?.declare) { + if (node.declare) { return; } if ( diff --git a/packages/eslint-plugin/tests/rules/init-declarations.test.ts b/packages/eslint-plugin/tests/rules/init-declarations.test.ts index 8fe37d28b4ff..8ff40c8045e4 100644 --- a/packages/eslint-plugin/tests/rules/init-declarations.test.ts +++ b/packages/eslint-plugin/tests/rules/init-declarations.test.ts @@ -1,15 +1,8 @@ import { AST_NODE_TYPES } from '@typescript-eslint/experimental-utils'; import rule from '../../src/rules/init-declarations'; -import { RuleTester, getFixturesRootDir } from '../RuleTester'; +import { RuleTester } from '../RuleTester'; -const rootDir = getFixturesRootDir(); const ruleTester = new RuleTester({ - parserOptions: { - ecmaVersion: 2018, - sourceType: 'module', - project: './tsconfig.json', - tsconfigRootDir: rootDir, - }, parser: '@typescript-eslint/parser', }); From da46af2af568643e423825eb0f180916e719d517 Mon Sep 17 00:00:00 2001 From: Anix Date: Fri, 10 Apr 2020 11:54:07 +0000 Subject: [PATCH 14/19] chore: refactored types --- packages/eslint-plugin/src/rules/init-declarations.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/eslint-plugin/src/rules/init-declarations.ts b/packages/eslint-plugin/src/rules/init-declarations.ts index 2c012f208fd9..b096ddd3e239 100644 --- a/packages/eslint-plugin/src/rules/init-declarations.ts +++ b/packages/eslint-plugin/src/rules/init-declarations.ts @@ -46,8 +46,8 @@ export default createRule({ } if ( node.parent?.type === AST_NODE_TYPES.TSModuleBlock && - node.parent?.parent?.type === AST_NODE_TYPES.TSModuleDeclaration && - node.parent?.parent?.declare + node.parent.parent?.type === AST_NODE_TYPES.TSModuleDeclaration && + node.parent.parent?.declare ) { return; } From 07950f6a8be75a49268f52f7af912dc8067b9fbc Mon Sep 17 00:00:00 2001 From: Anix Date: Fri, 10 Apr 2020 12:47:48 +0000 Subject: [PATCH 15/19] chore: added two more test --- .../tests/rules/init-declarations.test.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/eslint-plugin/tests/rules/init-declarations.test.ts b/packages/eslint-plugin/tests/rules/init-declarations.test.ts index 8ff40c8045e4..68511620cedc 100644 --- a/packages/eslint-plugin/tests/rules/init-declarations.test.ts +++ b/packages/eslint-plugin/tests/rules/init-declarations.test.ts @@ -312,6 +312,10 @@ interface IEmployee { `, options: ['never'], }, + { + code: 'declare const foo: number = "asd";', + options: ['always'], + }, ], invalid: [ // checking compatibility with base rule @@ -654,5 +658,16 @@ const class1 = class NAME { }, ], }, + { + code: 'declare var foo: number = "asd";', + options: ['never'], + errors: [ + { + messageId: 'notInitialized', + data: { idName: 'foo' }, + type: AST_NODE_TYPES.VariableDeclarator, + }, + ], + }, ], }); From dd41a77d94eb6af8542f72f16b5be6e03efedf5a Mon Sep 17 00:00:00 2001 From: Anix Date: Fri, 10 Apr 2020 12:55:40 +0000 Subject: [PATCH 16/19] chore: linting fixes --- packages/eslint-plugin/tests/rules/init-declarations.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/eslint-plugin/tests/rules/init-declarations.test.ts b/packages/eslint-plugin/tests/rules/init-declarations.test.ts index 68511620cedc..df1faed6e700 100644 --- a/packages/eslint-plugin/tests/rules/init-declarations.test.ts +++ b/packages/eslint-plugin/tests/rules/init-declarations.test.ts @@ -313,7 +313,7 @@ interface IEmployee { options: ['never'], }, { - code: 'declare const foo: number = "asd";', + code: "declare const foo: number = 'asd';", options: ['always'], }, ], @@ -659,7 +659,7 @@ const class1 = class NAME { ], }, { - code: 'declare var foo: number = "asd";', + code: "declare var foo: number = 'asd';", options: ['never'], errors: [ { From ed71f47f58ae02ec7dff6276faf113af909d5823 Mon Sep 17 00:00:00 2001 From: Anix Date: Fri, 10 Apr 2020 15:52:27 +0000 Subject: [PATCH 17/19] chore: some more tests --- .../tests/rules/init-declarations.test.ts | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/packages/eslint-plugin/tests/rules/init-declarations.test.ts b/packages/eslint-plugin/tests/rules/init-declarations.test.ts index df1faed6e700..701dbb2e00df 100644 --- a/packages/eslint-plugin/tests/rules/init-declarations.test.ts +++ b/packages/eslint-plugin/tests/rules/init-declarations.test.ts @@ -316,6 +316,22 @@ interface IEmployee { code: "declare const foo: number = 'asd';", options: ['always'], }, + { + code: ` +namespace myLib { + let numberOfGreetings: number; +} + `, + options: ['never'], + }, + { + code: ` +namespace myLib { + let numberOfGreetings: number = 2; +} + `, + options: ['always'], + }, ], invalid: [ // checking compatibility with base rule @@ -669,5 +685,35 @@ const class1 = class NAME { }, ], }, + { + code: ` +namespace myLib { + let numberOfGreetings: number; +} + `, + options: ['always'], + errors: [ + { + messageId: 'initialized', + data: { idName: 'numberOfGreetings' }, + type: AST_NODE_TYPES.VariableDeclarator, + }, + ], + }, + { + code: ` +namespace myLib { + let numberOfGreetings: number = 2; +} + `, + options: ['never'], + errors: [ + { + messageId: 'notInitialized', + data: { idName: 'numberOfGreetings' }, + type: AST_NODE_TYPES.VariableDeclarator, + }, + ], + }, ], }); From de1544f898f68589583a613b90076289ef5659f7 Mon Sep 17 00:00:00 2001 From: Anix Date: Fri, 10 Apr 2020 16:36:39 +0000 Subject: [PATCH 18/19] chore: tests and removed deepclone --- packages/eslint-plugin/src/rules/init-declarations.ts | 9 +-------- .../eslint-plugin/tests/rules/init-declarations.test.ts | 9 +++++++++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/packages/eslint-plugin/src/rules/init-declarations.ts b/packages/eslint-plugin/src/rules/init-declarations.ts index b096ddd3e239..b4368527e0cd 100644 --- a/packages/eslint-plugin/src/rules/init-declarations.ts +++ b/packages/eslint-plugin/src/rules/init-declarations.ts @@ -7,18 +7,11 @@ import { InferOptionsTypeFromRule, InferMessageIdsTypeFromRule, createRule, - deepMerge, } from '../util'; export type Options = InferOptionsTypeFromRule; export type MessageIds = InferMessageIdsTypeFromRule; -const schema = deepMerge( - Array.isArray(baseRule.meta.schema) - ? baseRule.meta.schema[0] - : baseRule.meta.schema, -); - export default createRule({ name: 'init-declarations', meta: { @@ -30,7 +23,7 @@ export default createRule({ recommended: false, extendsBaseRule: true, }, - schema, + schema: baseRule.meta.schema, messages: baseRule.meta.messages, }, defaultOptions: ['always'], diff --git a/packages/eslint-plugin/tests/rules/init-declarations.test.ts b/packages/eslint-plugin/tests/rules/init-declarations.test.ts index 701dbb2e00df..6f4c8f75ebbc 100644 --- a/packages/eslint-plugin/tests/rules/init-declarations.test.ts +++ b/packages/eslint-plugin/tests/rules/init-declarations.test.ts @@ -316,6 +316,15 @@ interface IEmployee { code: "declare const foo: number = 'asd';", options: ['always'], }, + + { + code: "const foo: number = 'asd';", + options: ['always'], + }, + { + code: 'const foo: number;', + options: ['never'], + }, { code: ` namespace myLib { From af0a09136e4fd43e2895a77eb2151144b80e104b Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Sun, 19 Apr 2020 22:15:27 -0700 Subject: [PATCH 19/19] Update init-declarations.md --- packages/eslint-plugin/docs/rules/init-declarations.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/eslint-plugin/docs/rules/init-declarations.md b/packages/eslint-plugin/docs/rules/init-declarations.md index 5b49b99e3475..8888e2efef27 100644 --- a/packages/eslint-plugin/docs/rules/init-declarations.md +++ b/packages/eslint-plugin/docs/rules/init-declarations.md @@ -3,7 +3,7 @@ ## Rule Details This rule extends the base [`eslint/init-declarations`](https://eslint.org/docs/rules/init-declarations) rule. -It supports all options and features of the base rule. +It adds support for TypeScript's `declare` variables. ## How to use @@ -19,8 +19,4 @@ It supports all options and features of the base rule. See [`eslint/init-declarations` options](https://eslint.org/docs/rules/init-declarations#options). -## When Not To Use It - -When you are indifferent as to how your variables are initialized. - Taken with ❤️ [from ESLint core](https://github.com/eslint/eslint/blob/master/docs/rules/init-declarations.md)