From 3628cc7f58be628ffb2d8ae519967d0629f3b846 Mon Sep 17 00:00:00 2001 From: Joshua J <31038284+joshuajaco@users.noreply.github.com> Date: Tue, 7 May 2024 19:35:23 +0200 Subject: [PATCH] Fix import detection for local files with the name of a workspace (#32) --- lib/rules/no-absolute-imports.js | 37 +++++++++++++++++------------- lib/rules/no-cross-imports.js | 9 ++++++-- lib/rules/require-dependency.js | 9 ++++++-- lib/utils.js | 6 +++++ tests/mocks.js | 6 +++++ tests/rules/no-absolute-imports.js | 4 ++++ tests/rules/no-cross-imports.js | 4 ++++ tests/rules/no-relative-imports.js | 4 ++++ tests/rules/require-dependency.js | 4 ++++ 9 files changed, 63 insertions(+), 20 deletions(-) diff --git a/lib/rules/no-absolute-imports.js b/lib/rules/no-absolute-imports.js index 109b9b0..37e6ebf 100644 --- a/lib/rules/no-absolute-imports.js +++ b/lib/rules/no-absolute-imports.js @@ -4,6 +4,7 @@ const { dirname, relative } = require("path"); const { getWorkspaces, isSubPath, + isWorkspacePath, getImport, pathToImport, } = require("../utils"); @@ -26,21 +27,25 @@ module.exports.meta = { module.exports.create = (context) => { const workspaces = getWorkspaces(context); const filename = context.getFilename(); - return getImport(workspaces, filename, ({ node, path, start, end }) => { - workspaces.forEach(({ package: { name }, location }) => { - if (isSubPath(location, filename) && isSubPath(name, path)) { - context.report({ - node, - messageId: "noAbsoluteImports", - fix: (fixer) => - fixer.replaceTextRange( - [start + 1, end - 1], - pathToImport( - relative(dirname(filename), path.replace(name, location)), + return getImport( + workspaces, + filename, + ({ node, path, value, start, end }) => { + workspaces.forEach(({ package: { name }, location }) => { + if (isSubPath(location, filename) && isWorkspacePath(name, value)) { + context.report({ + node, + messageId: "noAbsoluteImports", + fix: (fixer) => + fixer.replaceTextRange( + [start + 1, end - 1], + pathToImport( + relative(dirname(filename), path.replace(name, location)), + ), ), - ), - }); - } - }); - }); + }); + } + }); + }, + ); }; diff --git a/lib/rules/no-cross-imports.js b/lib/rules/no-cross-imports.js index f34182e..ca1fb51 100644 --- a/lib/rules/no-cross-imports.js +++ b/lib/rules/no-cross-imports.js @@ -1,6 +1,11 @@ "use strict"; -const { getWorkspaces, isSubPath, getImport } = require("../utils"); +const { + getWorkspaces, + isSubPath, + isWorkspacePath, + getImport, +} = require("../utils"); module.exports.meta = { type: "problem", @@ -109,7 +114,7 @@ module.exports.create = (context) => { .forEach(({ package: { name }, location }) => { if ( name !== currentWorkspace.package.name && - (isSubPath(name, value) || isSubPath(location, path)) + (isWorkspacePath(name, value) || isSubPath(location, path)) ) { context.report({ node, diff --git a/lib/rules/require-dependency.js b/lib/rules/require-dependency.js index 4c17bbd..7e2571b 100644 --- a/lib/rules/require-dependency.js +++ b/lib/rules/require-dependency.js @@ -1,6 +1,11 @@ "use strict"; -const { getWorkspaces, isSubPath, getImport } = require("../utils"); +const { + getWorkspaces, + isSubPath, + isWorkspacePath, + getImport, +} = require("../utils"); module.exports.meta = { type: "problem", @@ -32,7 +37,7 @@ module.exports.create = (context) => { if ( name !== currentWorkspace.package.name && - (isSubPath(name, value) || isSubPath(location, path)) && + (isWorkspacePath(name, value) || isSubPath(location, path)) && !Object.keys(dependencies).includes(name) && !Object.keys(peerDependencies).includes(name) && !Object.keys(optionalDependencies).includes(name) && diff --git a/lib/utils.js b/lib/utils.js index 77cde94..dfbf253 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -16,6 +16,11 @@ const isSubPath = (parent, path) => { return relativePath.split(sep)[0] !== ".." && !isAbsolute(relativePath); }; +const isWorkspacePath = (name, path) => + path === name || + path.startsWith(name + sep) || + path.startsWith(name + posix.sep); + const resolvePath = (parent, path) => { if (path[0] !== ".") return path; @@ -90,6 +95,7 @@ const getWorkspaces = (context) => { module.exports = { isSubPath, + isWorkspacePath, getImport, pathToImport, getWorkspaces, diff --git a/tests/mocks.js b/tests/mocks.js index daf8187..a1a423e 100644 --- a/tests/mocks.js +++ b/tests/mocks.js @@ -20,6 +20,12 @@ module.exports.findWorkspacesMock = () => [ name: "@test/third-workspace", }, }, + { + location: "/test/no-npm-scope-workspace", + package: { + name: "no-npm-scope-workspace", + }, + }, { location: "/test/peer-dependencies", package: { diff --git a/tests/rules/no-absolute-imports.js b/tests/rules/no-absolute-imports.js index 7048b58..3247bb9 100644 --- a/tests/rules/no-absolute-imports.js +++ b/tests/rules/no-absolute-imports.js @@ -40,6 +40,10 @@ describe("no-absolute-imports", () => { code: "import workspace from '@test/workspace';", filename: "/some/path.js", }, + { + filename: "/test/no-npm-scope-workspace/index.js", + code: "import './no-npm-scope-workspace';", + }, ], invalid: [ diff --git a/tests/rules/no-cross-imports.js b/tests/rules/no-cross-imports.js index 165e6b9..b105f1b 100644 --- a/tests/rules/no-cross-imports.js +++ b/tests/rules/no-cross-imports.js @@ -58,6 +58,10 @@ describe("no-cross-imports", () => { filename: "/test/scope/workspace/file.js", code: "import '@test/shared-in-scope';", }, + { + filename: "/test/workspace/index.js", + code: "import './no-npm-scope-workspace';", + }, ], invalid: [ diff --git a/tests/rules/no-relative-imports.js b/tests/rules/no-relative-imports.js index e7805aa..874c85c 100644 --- a/tests/rules/no-relative-imports.js +++ b/tests/rules/no-relative-imports.js @@ -40,6 +40,10 @@ describe("no-relative-imports", () => { filename: "/some/file.js", code: "import '../test/workspace';", }, + { + filename: "/test/workspace/index.js", + code: "import './no-npm-scope-workspace';", + }, ], invalid: [ { diff --git a/tests/rules/require-dependency.js b/tests/rules/require-dependency.js index dd58b87..d67cdd3 100644 --- a/tests/rules/require-dependency.js +++ b/tests/rules/require-dependency.js @@ -30,6 +30,10 @@ describe("require-dependency", () => { filename: "/test/optional-dependencies/test.js", code: "import '@test/optional-workspace'", }, + { + filename: "/test/workspace/index.js", + code: "import './no-npm-scope-workspace';", + }, ], invalid: [ {