From 66cb10f302a23c0b72c4a3ead26374a6729a9017 Mon Sep 17 00:00:00 2001 From: Kinland <16787581+kinland@users.noreply.github.com> Date: Mon, 25 Sep 2023 19:16:00 -0700 Subject: [PATCH] [Fix] `newline-after-import`: fix `exactCount` with `considerComments` false positive, when there is a leading comment Fixes #2882. --- CHANGELOG.md | 5 +- src/rules/newline-after-import.js | 2 +- tests/src/rules/newline-after-import.js | 133 ++++++++++++++++++++++++ 3 files changed, 138 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 567ed2645..6af7f748a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange ### Added - TypeScript config: add .cts and .mts extensions ([#2851], thanks [@Zamiell]) - [`newline-after-import`]: new option `exactCount` and docs update ([#1933], thanks [@anikethsaha] and [@reosarevok]) +- [`newline-after-import`]: fix `exactCount` with `considerComments` false positive, when there is a leading comment ([#2884], thanks [@kinland]) ## [2.28.1] - 2023-08-18 @@ -1091,6 +1092,7 @@ for info on changes for earlier releases. [`memo-parser`]: ./memo-parser/README.md +[#2884]: https://github.com/import-js/eslint-plugin-import/pull/2884 [#2854]: https://github.com/import-js/eslint-plugin-import/pull/2854 [#2851]: https://github.com/import-js/eslint-plugin-import/pull/2851 [#2850]: https://github.com/import-js/eslint-plugin-import/pull/2850 @@ -1769,6 +1771,7 @@ for info on changes for earlier releases. [@kentcdodds]: https://github.com/kentcdodds [@kevin940726]: https://github.com/kevin940726 [@kgregory]: https://github.com/kgregory +[@kinland]: https://github.com/kinland [@kirill-konshin]: https://github.com/kirill-konshin [@kiwka]: https://github.com/kiwka [@klimashkin]: https://github.com/klimashkin @@ -1776,8 +1779,8 @@ for info on changes for earlier releases. [@knpwrs]: https://github.com/knpwrs [@KostyaZgara]: https://github.com/KostyaZgara [@kylemh]: https://github.com/kylemh -[@laysent]: https://github.com/laysent [@laurens-dg]: https://github.com/laurens-dg +[@laysent]: https://github.com/laysent [@le0nik]: https://github.com/le0nik [@leipert]: https://github.com/leipert [@lemonmade]: https://github.com/lemonmade diff --git a/src/rules/newline-after-import.js b/src/rules/newline-after-import.js index 9b469110b..a33bb615b 100644 --- a/src/rules/newline-after-import.js +++ b/src/rules/newline-after-import.js @@ -169,7 +169,7 @@ module.exports = { let nextComment; if (typeof parent.comments !== 'undefined' && options.considerComments) { - nextComment = parent.comments.find((o) => o.loc.start.line === endLine + 1); + nextComment = parent.comments.find((o) => o.loc.start.line >= endLine && o.loc.start.line <= endLine + options.count + 1); } // skip "export import"s diff --git a/tests/src/rules/newline-after-import.js b/tests/src/rules/newline-after-import.js index bd11da419..6a8fb83e4 100644 --- a/tests/src/rules/newline-after-import.js +++ b/tests/src/rules/newline-after-import.js @@ -142,6 +142,31 @@ ruleTester.run('newline-after-import', require('rules/newline-after-import'), { parserOptions: { ecmaVersion: 2015, sourceType: 'module' }, options: [{ count: 1, exactCount: true }], }, + { + code: `import foo from 'foo';\n\n// Some random comment\nvar bar = 'bar';`, + parserOptions: { ecmaVersion: 2015, sourceType: 'module' }, + options: [{ count: 2, exactCount: true }], + }, + { + code: `import foo from 'foo';\n// Some random comment\nvar bar = 'bar';`, + parserOptions: { ecmaVersion: 2015, sourceType: 'module' }, + options: [{ count: 1, exactCount: true }], + }, + { + code: `import foo from 'foo';\n\n\n// Some random comment\nvar bar = 'bar';`, + parserOptions: { ecmaVersion: 2015, sourceType: 'module' }, + options: [{ count: 2, exactCount: true, considerComments: true }], + }, + { + code: `import foo from 'foo';\n\n// Some random comment\nvar bar = 'bar';`, + parserOptions: { ecmaVersion: 2015, sourceType: 'module' }, + options: [{ count: 1, exactCount: true, considerComments: true }], + }, + { + code: `/**\n * A leading comment\n */\nimport foo from 'foo';\n\n// Some random comment\nexport {foo};`, + parserOptions: { ecmaVersion: 2015, sourceType: 'module' }, + options: [{ count: 2, exactCount: true }], + }, { code: `import foo from 'foo';\n\n\nvar bar = 'bar';`, parserOptions: { ecmaVersion: 2015, sourceType: 'module' }, @@ -171,6 +196,16 @@ ruleTester.run('newline-after-import', require('rules/newline-after-import'), { parserOptions: { ecmaVersion: 2015, sourceType: 'module' }, options: [{ count: 4, exactCount: true }], }, + { + code: `var foo = require('foo-module');\n\n// Some random comment\n\n\nvar foo = 'bar';`, + parserOptions: { ecmaVersion: 2015, sourceType: 'module' }, + options: [{ count: 4, exactCount: true }], + }, + { + code: `var foo = require('foo-module');\n\n\n\n// Some random comment\nvar foo = 'bar';`, + parserOptions: { ecmaVersion: 2015, sourceType: 'module' }, + options: [{ count: 4, exactCount: true, considerComments: true }], + }, { code: `require('foo-module');\n\nvar foo = 'bar';`, parserOptions: { ecmaVersion: 2015, sourceType: 'module' }, @@ -683,6 +718,72 @@ ruleTester.run('newline-after-import', require('rules/newline-after-import'), { }], parserOptions: { ecmaVersion: 2015, sourceType: 'module' }, }, + { + code: `import foo from 'foo';\n// some random comment\nexport default function() {};`, + output: `import foo from 'foo';\n\n// some random comment\nexport default function() {};`, + options: [{ count: 2, exactCount: true }], + errors: [{ + line: 1, + column: 1, + message: IMPORT_ERROR_MESSAGE_MULTIPLE(2), + }], + parserOptions: { ecmaVersion: 2015, sourceType: 'module' }, + }, + { + code: `import foo from 'foo';\n// some random comment\n\n\nexport default function() {};`, + output: `import foo from 'foo';\n// some random comment\n\n\nexport default function() {};`, + options: [{ count: 2, exactCount: true }], + errors: [{ + line: 1, + column: 1, + message: IMPORT_ERROR_MESSAGE_MULTIPLE(2), + }], + parserOptions: { ecmaVersion: 2015, sourceType: 'module' }, + }, + { + code: `import foo from 'foo';\n// some random comment\n\n\n\nexport default function() {};`, + output: `import foo from 'foo';\n// some random comment\n\n\n\nexport default function() {};`, + options: [{ count: 2, exactCount: true }], + errors: [{ + line: 1, + column: 1, + message: IMPORT_ERROR_MESSAGE_MULTIPLE(2), + }], + parserOptions: { ecmaVersion: 2015, sourceType: 'module' }, + }, + { + code: `import foo from 'foo';\n// some random comment\nexport default function() {};`, + output: `import foo from 'foo';\n\n\n// some random comment\nexport default function() {};`, + options: [{ count: 2, exactCount: true, considerComments: true }], + errors: [{ + line: 1, + column: 1, + message: IMPORT_ERROR_MESSAGE_MULTIPLE(2), + }], + parserOptions: { ecmaVersion: 2015, sourceType: 'module' }, + }, + { + code: `import foo from 'foo';\n\n// some random comment\nexport default function() {};`, + output: `import foo from 'foo';\n\n\n// some random comment\nexport default function() {};`, + options: [{ count: 2, exactCount: true, considerComments: true }], + errors: [{ + line: 1, + column: 1, + message: IMPORT_ERROR_MESSAGE_MULTIPLE(2), + }], + parserOptions: { ecmaVersion: 2015, sourceType: 'module' }, + }, + { + code: `import foo from 'foo';\n\n\n\n// some random comment\nexport default function() {};`, + output: `import foo from 'foo';\n\n\n\n// some random comment\nexport default function() {};`, + options: [{ count: 2, exactCount: true, considerComments: true }], + errors: [{ + line: 1, + column: 1, + message: IMPORT_ERROR_MESSAGE_MULTIPLE(2), + }], + parserOptions: { ecmaVersion: 2015, sourceType: 'module' }, + }, { code: ` import foo from 'foo'; @@ -728,5 +829,37 @@ ruleTester.run('newline-after-import', require('rules/newline-after-import'), { }], parserOptions: { ecmaVersion: 2015 }, }, + { + code: `const foo = require('foo');\n\n\n\n// some random comment\nconst bar = function() {};`, + output: `const foo = require('foo');\n\n\n\n// some random comment\nconst bar = function() {};`, + options: [{ count: 2, exactCount: true }], + errors: [{ + line: 1, + column: 1, + message: 'Expected 2 empty lines after require statement not followed by another require.', + }], + parserOptions: { ecmaVersion: 2015 }, + }, + { + code: `import foo from 'foo';// some random comment\nexport default function() {};`, + output: `import foo from 'foo';\n\n// some random comment\nexport default function() {};`, + options: [{ count: 1, exactCount: true, considerComments: true }], + errors: [{ + line: 1, + column: 1, + message: IMPORT_ERROR_MESSAGE, + }], + parserOptions: { ecmaVersion: 2015, considerComments: true, sourceType: 'module' }, + }, + { + code: `const foo = require('foo');\n\n\n// some random comment\nconst bar = function() {};`, + options: [{ count: 2, exactCount: true, considerComments: true }], + errors: [{ + line: 1, + column: 1, + message: 'Expected 2 empty lines after require statement not followed by another require.', + }], + parserOptions: { ecmaVersion: 2015 }, + }, ), });