From 24647f962ae913625d5015656bfe1f89b50814ba Mon Sep 17 00:00:00 2001 From: Miroslav Jonas Date: Wed, 12 Apr 2023 14:50:08 +0200 Subject: [PATCH 1/4] feat(linter): add internal rule to prevent deep import from plugins/js --- .eslintrc.json | 6 + tools/eslint-rules/index.ts | 9 +- .../restrict-js-plugin-deep-import.spec.ts | 11 ++ .../rules/restrict-js-plugin-deep-import.ts | 104 ++++++++++++++++++ 4 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 tools/eslint-rules/rules/restrict-js-plugin-deep-import.spec.ts create mode 100644 tools/eslint-rules/rules/restrict-js-plugin-deep-import.ts diff --git a/.eslintrc.json b/.eslintrc.json index c883c73986789..75453a444cc3b 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -18,6 +18,12 @@ "rules": { "@nrwl/nx/workspace/valid-schema-description": "error" } + }, + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": { + "@nrwl/nx/workspace/restrict-js-plugin-deep-import": "error" + } } ] } diff --git a/tools/eslint-rules/index.ts b/tools/eslint-rules/index.ts index 3a451ca03e015..1ff873b7a97c8 100644 --- a/tools/eslint-rules/index.ts +++ b/tools/eslint-rules/index.ts @@ -1,3 +1,7 @@ +import { + RULE_NAME as restrictJsPluginDeepImportName, + rule as restrictJsPluginDeepImport, +} from './rules/restrict-js-plugin-deep-import'; import { RULE_NAME as validSchemaDescriptionName, rule as validSchemaDescription, @@ -27,5 +31,8 @@ module.exports = { * [myCustomRuleName]: myCustomRule * } */ - rules: { [validSchemaDescriptionName]: validSchemaDescription }, + rules: { + [validSchemaDescriptionName]: validSchemaDescription, + [restrictJsPluginDeepImportName]: restrictJsPluginDeepImport, + }, }; diff --git a/tools/eslint-rules/rules/restrict-js-plugin-deep-import.spec.ts b/tools/eslint-rules/rules/restrict-js-plugin-deep-import.spec.ts new file mode 100644 index 0000000000000..5999ddf81faa2 --- /dev/null +++ b/tools/eslint-rules/rules/restrict-js-plugin-deep-import.spec.ts @@ -0,0 +1,11 @@ +import { TSESLint } from '@typescript-eslint/utils'; +import { rule, RULE_NAME } from './restrict-js-plugin-deep-import'; + +const ruleTester = new TSESLint.RuleTester({ + parser: require.resolve('@typescript-eslint/parser'), +}); + +ruleTester.run(RULE_NAME, rule, { + valid: [`const example = true;`], + invalid: [], +}); diff --git a/tools/eslint-rules/rules/restrict-js-plugin-deep-import.ts b/tools/eslint-rules/rules/restrict-js-plugin-deep-import.ts new file mode 100644 index 0000000000000..7bea688cce44e --- /dev/null +++ b/tools/eslint-rules/rules/restrict-js-plugin-deep-import.ts @@ -0,0 +1,104 @@ +/** + * This file sets you up with structure needed for an ESLint rule. + * + * It leverages utilities from @typescript-eslint to allow TypeScript to + * provide autocompletions etc for the configuration. + * + * Your rule's custom logic will live within the create() method below + * and you can learn more about writing ESLint rules on the official guide: + * + * https://eslint.org/docs/developer-guide/working-with-rules + * + * You can also view many examples of existing rules here: + * + * https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin/src/rules + */ + +import { normalizePath, workspaceRoot } from '@nrwl/devkit'; +import { + ESLintUtils, + AST_NODE_TYPES, + TSESTree, +} from '@typescript-eslint/utils'; + +// NOTE: The rule will be available in ESLint configs as "@nrwl/nx/workspace/restrict-js-plugin-deep-import" +export const RULE_NAME = 'restrict-js-plugin-deep-import'; + +export const rule = ESLintUtils.RuleCreator(() => __filename)({ + name: RULE_NAME, + meta: { + type: 'problem', + docs: { + description: `Ensure that there are no deep imports from nx/src/plugins/js`, + recommended: 'error', + }, + schema: [], + messages: { + noDeepImport: + 'Functions from "nx/src/plugins/js" should be imported via barrel import. Deep import found: {{imp}}', + noDeepRelativeImport: + 'Functions from "./plugins/js" should be imported via relative barrel import. Deep import found: {{imp}}', + }, + }, + defaultOptions: [], + create(context) { + function run( + node: + | TSESTree.ImportDeclaration + | TSESTree.ImportExpression + | TSESTree.ExportAllDeclaration + | TSESTree.ExportNamedDeclaration + ) { + // Ignoring ExportNamedDeclarations like: + // export class Foo {} + if (!node.source) { + return; + } + + // accept only literals because template literals have no value + if (node.source.type !== AST_NODE_TYPES.Literal) { + return; + } + const imp = node.source.value as string; + if (imp.includes('nx/src/plugins/js/')) { + context.report({ + node, + messageId: 'noDeepImport', + data: { + imp, + }, + }); + } + const fileName = normalizePath(context.getFilename()).slice( + workspaceRoot.length + 1 + ); + if ( + imp.includes('./plugins/js/') && + fileName.startsWith('packages/nx/') + ) { + context.report({ + node, + messageId: 'noDeepRelativeImport', + data: { + imp, + }, + }); + } + } + + return { + ImportDeclaration(node: TSESTree.ImportDeclaration) { + run(node); + }, + ImportExpression(node: TSESTree.ImportExpression) { + run(node); + }, + ExportAllDeclaration(node: TSESTree.ExportAllDeclaration) { + run(node); + }, + ExportNamedDeclaration(node: TSESTree.ExportNamedDeclaration) { + run(node); + }, + }; + }, +}); From b4dfb445560df28eeec48dc2943742a5707962dc Mon Sep 17 00:00:00 2001 From: Miroslav Jonas Date: Wed, 12 Apr 2023 15:29:25 +0200 Subject: [PATCH 2/4] feat(linter): add test --- .../restrict-js-plugin-deep-import.spec.ts | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/tools/eslint-rules/rules/restrict-js-plugin-deep-import.spec.ts b/tools/eslint-rules/rules/restrict-js-plugin-deep-import.spec.ts index 5999ddf81faa2..c58e510fdde5e 100644 --- a/tools/eslint-rules/rules/restrict-js-plugin-deep-import.spec.ts +++ b/tools/eslint-rules/rules/restrict-js-plugin-deep-import.spec.ts @@ -5,7 +5,32 @@ const ruleTester = new TSESLint.RuleTester({ parser: require.resolve('@typescript-eslint/parser'), }); +jest.mock('@nrwl/devkit', () => ({ + ...jest.requireActual('@nrwl/devkit'), + workspaceRoot: '/root', +})); + ruleTester.run(RULE_NAME, rule, { - valid: [`const example = true;`], - invalid: [], + valid: [ + { + code: `import { createLockFile } from 'nx/src/plugins/js';`, + filename: '/root/packages/devkit/src/path/to.ts', + }, + { + code: `import { createLockFile } from '../plugins/js';`, + filename: '/root/packages/nx/src/path/to.ts', + }, + ], + invalid: [ + { + errors: [{ messageId: 'noDeepImport' }], + code: `import { createLockFile } from 'nx/src/plugins/js/lock-file/lock-file';`, + filename: '/root/packages/devkit/src/path/to.ts', + }, + { + errors: [{ messageId: 'noDeepRelativeImport' }], + code: `import { createLockFile } from '../plugins/js/lock-file/lock-file';`, + filename: '/root/packages/nx/src/path/to.ts', + }, + ], }); From da674ce974f35edb6cd31880798b9b7b2f59973d Mon Sep 17 00:00:00 2001 From: Miroslav Jonas Date: Thu, 13 Apr 2023 10:59:51 +0200 Subject: [PATCH 3/4] feat(core): add another rule for circular nx --- .eslintrc.json | 2 +- .../src/rules/enforce-module-boundaries.spec.ts | 1 + .../src/rules/enforce-module-boundaries.ts | 10 +++++----- .../src/utils/package-json/update-package-json.ts | 7 ++----- .../src/generators/utils/project-configuration.ts | 4 ++-- .../migrations/update-15-1-0/set-project-names.ts | 2 +- .../update-depends-on-to-tokens.spec.ts | 4 +--- packages/nx/src/plugins/js/index.ts | 3 +++ .../src/plugins/js/lock-file/pnpm-parser.spec.ts | 2 +- .../build-nodes/workspace-projects.spec.ts | 2 +- tools/eslint-rules/index.ts | 8 ++++---- ...import.spec.ts => restrict-nx-imports.spec.ts} | 11 ++++++++++- ...ugin-deep-import.ts => restrict-nx-imports.ts} | 15 +++++++++++++-- 13 files changed, 45 insertions(+), 26 deletions(-) rename tools/eslint-rules/rules/{restrict-js-plugin-deep-import.spec.ts => restrict-nx-imports.spec.ts} (73%) rename tools/eslint-rules/rules/{restrict-js-plugin-deep-import.ts => restrict-nx-imports.ts} (87%) diff --git a/.eslintrc.json b/.eslintrc.json index 75453a444cc3b..c965b25aa1358 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -22,7 +22,7 @@ { "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], "rules": { - "@nrwl/nx/workspace/restrict-js-plugin-deep-import": "error" + "@nrwl/nx/workspace/restrict-nx-imports": "error" } } ] diff --git a/packages/eslint-plugin-nx/src/rules/enforce-module-boundaries.spec.ts b/packages/eslint-plugin-nx/src/rules/enforce-module-boundaries.spec.ts index d9f306f21e110..49e11ef227ef9 100644 --- a/packages/eslint-plugin-nx/src/rules/enforce-module-boundaries.spec.ts +++ b/packages/eslint-plugin-nx/src/rules/enforce-module-boundaries.spec.ts @@ -9,6 +9,7 @@ import { DependencyType } from '@nx/devkit'; import * as parser from '@typescript-eslint/parser'; import { TSESLint } from '@typescript-eslint/utils'; import { vol } from 'memfs'; +// eslint-disable-next-line @nrwl/nx/workspace/restrict-nx-imports import { TargetProjectLocator } from 'nx/src/plugins/js/project-graph/build-dependencies/target-project-locator'; import enforceModuleBoundaries, { RULE_NAME as enforceModuleBoundariesRuleName, diff --git a/packages/eslint-plugin-nx/src/rules/enforce-module-boundaries.ts b/packages/eslint-plugin-nx/src/rules/enforce-module-boundaries.ts index 9da65a2cc84aa..7325d313c76f7 100644 --- a/packages/eslint-plugin-nx/src/rules/enforce-module-boundaries.ts +++ b/packages/eslint-plugin-nx/src/rules/enforce-module-boundaries.ts @@ -360,9 +360,9 @@ export default createESLintRule({ relativePath === '' ? `./${basename(importPath)}` : joinPathFragments( - relativePath, - basename(importPath) - ); + relativePath, + basename(importPath) + ); importsToRemap.push({ member: importMember, @@ -445,8 +445,8 @@ export default createESLintRule({ .map((files) => files.length > 1 ? `[${files - .map((f) => `\n${spacer}${spacer}${f}`) - .join(',')}\n${spacer}]` + .map((f) => `\n${spacer}${spacer}${f}`) + .join(',')}\n${spacer}]` : files[0] ) .reduce( diff --git a/packages/js/src/utils/package-json/update-package-json.ts b/packages/js/src/utils/package-json/update-package-json.ts index 7727aaa6b67f8..99e2cf3cc1ba8 100644 --- a/packages/js/src/utils/package-json/update-package-json.ts +++ b/packages/js/src/utils/package-json/update-package-json.ts @@ -1,8 +1,5 @@ -import { - createLockFile, - getLockFileName, -} from 'nx/src/plugins/js/lock-file/lock-file'; -import { createPackageJson } from 'nx/src/plugins/js/package-json/create-package-json'; +import { createLockFile, getLockFileName } from 'nx/src/plugins/js'; +import { createPackageJson } from 'nx/src/plugins/js'; import { ExecutorContext, getOutputsForTargetAndConfiguration, diff --git a/packages/nx/src/generators/utils/project-configuration.ts b/packages/nx/src/generators/utils/project-configuration.ts index f10692404dc4d..d29c13f081a29 100644 --- a/packages/nx/src/generators/utils/project-configuration.ts +++ b/packages/nx/src/generators/utils/project-configuration.ts @@ -1,4 +1,4 @@ -import { basename, dirname, join, relative } from 'path'; +import { basename, join, relative } from 'path'; import { ProjectConfiguration, ProjectsConfigurations, @@ -18,7 +18,7 @@ import { readJson, writeJson } from './json'; import { PackageJson } from '../../utils/package-json'; import { readNxJson } from './nx-json'; import { output } from '../../utils/output'; -import { getNxRequirePaths } from 'nx/src/utils/installation-directory'; +import { getNxRequirePaths } from '../../utils/installation-directory'; export { readNxJson, updateNxJson } from './nx-json'; export { diff --git a/packages/nx/src/migrations/update-15-1-0/set-project-names.ts b/packages/nx/src/migrations/update-15-1-0/set-project-names.ts index af05b5d9f3339..3791d03d37493 100644 --- a/packages/nx/src/migrations/update-15-1-0/set-project-names.ts +++ b/packages/nx/src/migrations/update-15-1-0/set-project-names.ts @@ -7,7 +7,7 @@ import { import { dirname } from 'path'; import { readJson, writeJson } from '../../generators/utils/json'; import { formatChangedFilesWithPrettierIfAvailable } from '../../generators/internal-utils/format-changed-files-with-prettier-if-available'; -import { getNxRequirePaths } from 'nx/src/utils/installation-directory'; +import { getNxRequirePaths } from '../../utils/installation-directory'; export default async function (tree: Tree) { const nxJson = readNxJson(tree); diff --git a/packages/nx/src/migrations/update-16-0-0/update-depends-on-to-tokens.spec.ts b/packages/nx/src/migrations/update-16-0-0/update-depends-on-to-tokens.spec.ts index 86c66a9dbd3c2..8f80e43c9496f 100644 --- a/packages/nx/src/migrations/update-16-0-0/update-depends-on-to-tokens.spec.ts +++ b/packages/nx/src/migrations/update-16-0-0/update-depends-on-to-tokens.spec.ts @@ -1,13 +1,11 @@ import { addProjectConfiguration, - getProjects, readNxJson, readProjectConfiguration, } from '../../generators/utils/project-configuration'; -import { Tree } from '../../generators/tree'; import update from './update-depends-on-to-tokens'; -import { updateJson, writeJson } from 'nx/src/devkit-exports'; +import { updateJson, writeJson } from '../../generators/utils/json'; import { createTreeWithEmptyWorkspace } from '../../generators/testing-utils/create-tree-with-empty-workspace'; describe('update-depends-on-to-tokens', () => { diff --git a/packages/nx/src/plugins/js/index.ts b/packages/nx/src/plugins/js/index.ts index 1cc157454e037..2eb21e04d1e99 100644 --- a/packages/nx/src/plugins/js/index.ts +++ b/packages/nx/src/plugins/js/index.ts @@ -18,6 +18,9 @@ import { workspaceRoot } from '../../utils/workspace-root'; import { ensureDirSync } from 'fs-extra'; import { removeNpmNodes } from './lock-file/remove-npm-nodes'; +export { getLockFileName, createLockFile } from './lock-file/lock-file'; +export { createPackageJson } from './package-json/create-package-json'; + export const processProjectGraph: ProjectGraphProcessor = async ( graph, context diff --git a/packages/nx/src/plugins/js/lock-file/pnpm-parser.spec.ts b/packages/nx/src/plugins/js/lock-file/pnpm-parser.spec.ts index a2601fcbcbd86..258bd81de7af1 100644 --- a/packages/nx/src/plugins/js/lock-file/pnpm-parser.spec.ts +++ b/packages/nx/src/plugins/js/lock-file/pnpm-parser.spec.ts @@ -3,7 +3,7 @@ import { parsePnpmLockfile, stringifyPnpmLockfile } from './pnpm-parser'; import { ProjectGraph } from '../../../config/project-graph'; import { vol } from 'memfs'; import { pruneProjectGraph } from './project-graph-pruning'; -import { ProjectGraphBuilder } from 'nx/src/project-graph/project-graph-builder'; +import { ProjectGraphBuilder } from '../../../project-graph/project-graph-builder'; jest.mock('fs', () => require('memfs').fs); diff --git a/packages/nx/src/project-graph/build-nodes/workspace-projects.spec.ts b/packages/nx/src/project-graph/build-nodes/workspace-projects.spec.ts index 1e8a6d469b772..e69b0a3a0d141 100644 --- a/packages/nx/src/project-graph/build-nodes/workspace-projects.spec.ts +++ b/packages/nx/src/project-graph/build-nodes/workspace-projects.spec.ts @@ -1,4 +1,4 @@ -import { ProjectGraphProjectNode } from 'nx/src/config/project-graph'; +import { ProjectGraphProjectNode } from '../../config/project-graph'; import { normalizeImplicitDependencies } from './workspace-projects'; describe('workspace-projects', () => { diff --git a/tools/eslint-rules/index.ts b/tools/eslint-rules/index.ts index 1ff873b7a97c8..a39497596e9a5 100644 --- a/tools/eslint-rules/index.ts +++ b/tools/eslint-rules/index.ts @@ -1,7 +1,7 @@ import { - RULE_NAME as restrictJsPluginDeepImportName, - rule as restrictJsPluginDeepImport, -} from './rules/restrict-js-plugin-deep-import'; + RULE_NAME as restrictNxImportsName, + rule as restrictNxImports, +} from './rules/restrict-nx-imports'; import { RULE_NAME as validSchemaDescriptionName, rule as validSchemaDescription, @@ -33,6 +33,6 @@ module.exports = { */ rules: { [validSchemaDescriptionName]: validSchemaDescription, - [restrictJsPluginDeepImportName]: restrictJsPluginDeepImport, + [restrictNxImportsName]: restrictNxImports, }, }; diff --git a/tools/eslint-rules/rules/restrict-js-plugin-deep-import.spec.ts b/tools/eslint-rules/rules/restrict-nx-imports.spec.ts similarity index 73% rename from tools/eslint-rules/rules/restrict-js-plugin-deep-import.spec.ts rename to tools/eslint-rules/rules/restrict-nx-imports.spec.ts index c58e510fdde5e..197852ba4eefa 100644 --- a/tools/eslint-rules/rules/restrict-js-plugin-deep-import.spec.ts +++ b/tools/eslint-rules/rules/restrict-nx-imports.spec.ts @@ -1,5 +1,5 @@ import { TSESLint } from '@typescript-eslint/utils'; -import { rule, RULE_NAME } from './restrict-js-plugin-deep-import'; +import { rule, RULE_NAME } from './restrict-nx-imports'; const ruleTester = new TSESLint.RuleTester({ parser: require.resolve('@typescript-eslint/parser'), @@ -20,6 +20,10 @@ ruleTester.run(RULE_NAME, rule, { code: `import { createLockFile } from '../plugins/js';`, filename: '/root/packages/nx/src/path/to.ts', }, + { + code: `import { updateJson } from '../../generators/utils/json';`, + filename: '/root/packages/nx/src/path/to.ts', + }, ], invalid: [ { @@ -32,5 +36,10 @@ ruleTester.run(RULE_NAME, rule, { code: `import { createLockFile } from '../plugins/js/lock-file/lock-file';`, filename: '/root/packages/nx/src/path/to.ts', }, + { + errors: [{ messageId: 'noCircularNx' }], + code: `import { updateJson } from 'nx/src/devkit-exports';`, + filename: '/root/packages/nx/src/path/to.ts', + }, ], }); diff --git a/tools/eslint-rules/rules/restrict-js-plugin-deep-import.ts b/tools/eslint-rules/rules/restrict-nx-imports.ts similarity index 87% rename from tools/eslint-rules/rules/restrict-js-plugin-deep-import.ts rename to tools/eslint-rules/rules/restrict-nx-imports.ts index 7bea688cce44e..5a7b95eabac84 100644 --- a/tools/eslint-rules/rules/restrict-js-plugin-deep-import.ts +++ b/tools/eslint-rules/rules/restrict-nx-imports.ts @@ -21,8 +21,8 @@ import { TSESTree, } from '@typescript-eslint/utils'; -// NOTE: The rule will be available in ESLint configs as "@nrwl/nx/workspace/restrict-js-plugin-deep-import" -export const RULE_NAME = 'restrict-js-plugin-deep-import'; +// NOTE: The rule will be available in ESLint configs as "@nrwl/nx/workspace/restrict-nx-imports" +export const RULE_NAME = 'restrict-nx-imports'; export const rule = ESLintUtils.RuleCreator(() => __filename)({ name: RULE_NAME, @@ -34,6 +34,8 @@ export const rule = ESLintUtils.RuleCreator(() => __filename)({ }, schema: [], messages: { + noCircularNx: + 'Functions within "nx" should be imported with relative path. Alias import found: {{imp}}', noDeepImport: 'Functions from "nx/src/plugins/js" should be imported via barrel import. Deep import found: {{imp}}', noDeepRelativeImport: @@ -84,6 +86,15 @@ export const rule = ESLintUtils.RuleCreator(() => __filename)({ }, }); } + if (imp.includes('nx/src') && fileName.startsWith('packages/nx/')) { + context.report({ + node, + messageId: 'noCircularNx', + data: { + imp, + }, + }); + } } return { From de1816de5a5f47efd8409cea1bee693d48a30e5b Mon Sep 17 00:00:00 2001 From: Miroslav Jonas Date: Tue, 18 Apr 2023 17:32:55 +0200 Subject: [PATCH 4/4] fix(linter): fix files --- .../src/utils/module-federation/share.ts | 2 +- .../src/utils/module-federation/typescript.ts | 2 +- .../src/rules/enforce-module-boundaries.ts | 10 ++++---- .../eslint-plugin-nx/src/utils/ast-utils.ts | 2 +- .../rules/restrict-nx-imports.spec.ts | 11 +++------ .../eslint-rules/rules/restrict-nx-imports.ts | 24 +++++++------------ 6 files changed, 19 insertions(+), 32 deletions(-) diff --git a/packages/devkit/src/utils/module-federation/share.ts b/packages/devkit/src/utils/module-federation/share.ts index 0c91a911665ac..4bcad24c1112c 100644 --- a/packages/devkit/src/utils/module-federation/share.ts +++ b/packages/devkit/src/utils/module-federation/share.ts @@ -11,7 +11,7 @@ import { collectPackageSecondaryEntryPoints, collectWorkspaceLibrarySecondaryEntryPoints, } from './secondary-entry-points'; -// eslint-disable-next-line @typescript-eslint/no-restricted-imports +// eslint-disable-next-line @typescript-eslint/no-restricted-imports, @nrwl/nx/workspace/restrict-nx-imports import { getRootTsConfigPath } from 'nx/src/plugins/js/utils/typescript'; import type { ProjectGraph } from 'nx/src/config/project-graph'; import { requireNx } from '../../../nx'; diff --git a/packages/devkit/src/utils/module-federation/typescript.ts b/packages/devkit/src/utils/module-federation/typescript.ts index 8868312aee1eb..9ed48e7c3e44d 100644 --- a/packages/devkit/src/utils/module-federation/typescript.ts +++ b/packages/devkit/src/utils/module-federation/typescript.ts @@ -1,6 +1,6 @@ import { existsSync } from 'fs'; import { ParsedCommandLine } from 'typescript'; -// eslint-disable-next-line @typescript-eslint/no-restricted-imports +// eslint-disable-next-line @typescript-eslint/no-restricted-imports, @nrwl/nx/workspace/restrict-nx-imports import { getRootTsConfigPath } from 'nx/src/plugins/js/utils/typescript'; import { dirname } from 'path'; diff --git a/packages/eslint-plugin-nx/src/rules/enforce-module-boundaries.ts b/packages/eslint-plugin-nx/src/rules/enforce-module-boundaries.ts index 7325d313c76f7..9da65a2cc84aa 100644 --- a/packages/eslint-plugin-nx/src/rules/enforce-module-boundaries.ts +++ b/packages/eslint-plugin-nx/src/rules/enforce-module-boundaries.ts @@ -360,9 +360,9 @@ export default createESLintRule({ relativePath === '' ? `./${basename(importPath)}` : joinPathFragments( - relativePath, - basename(importPath) - ); + relativePath, + basename(importPath) + ); importsToRemap.push({ member: importMember, @@ -445,8 +445,8 @@ export default createESLintRule({ .map((files) => files.length > 1 ? `[${files - .map((f) => `\n${spacer}${spacer}${f}`) - .join(',')}\n${spacer}]` + .map((f) => `\n${spacer}${spacer}${f}`) + .join(',')}\n${spacer}]` : files[0] ) .reduce( diff --git a/packages/eslint-plugin-nx/src/utils/ast-utils.ts b/packages/eslint-plugin-nx/src/utils/ast-utils.ts index 36f3d25ee439a..f3fe1d4d4e3ed 100644 --- a/packages/eslint-plugin-nx/src/utils/ast-utils.ts +++ b/packages/eslint-plugin-nx/src/utils/ast-utils.ts @@ -3,7 +3,7 @@ import { ProjectGraphProjectNode, readJsonFile, } from '@nx/devkit'; -import { findNodes } from 'nx/src/plugins/js/utils/typescript'; +import { findNodes } from '@nx/js'; import { existsSync, readFileSync } from 'fs'; import { dirname } from 'path'; import ts = require('typescript'); diff --git a/tools/eslint-rules/rules/restrict-nx-imports.spec.ts b/tools/eslint-rules/rules/restrict-nx-imports.spec.ts index 197852ba4eefa..b0f37a0e3efc4 100644 --- a/tools/eslint-rules/rules/restrict-nx-imports.spec.ts +++ b/tools/eslint-rules/rules/restrict-nx-imports.spec.ts @@ -6,7 +6,7 @@ const ruleTester = new TSESLint.RuleTester({ }); jest.mock('@nrwl/devkit', () => ({ - ...jest.requireActual('@nrwl/devkit'), + normalizePath: (path: string) => path, workspaceRoot: '/root', })); @@ -27,14 +27,9 @@ ruleTester.run(RULE_NAME, rule, { ], invalid: [ { - errors: [{ messageId: 'noDeepImport' }], + errors: [{ messageId: 'noJsImport' }], code: `import { createLockFile } from 'nx/src/plugins/js/lock-file/lock-file';`, - filename: '/root/packages/devkit/src/path/to.ts', - }, - { - errors: [{ messageId: 'noDeepRelativeImport' }], - code: `import { createLockFile } from '../plugins/js/lock-file/lock-file';`, - filename: '/root/packages/nx/src/path/to.ts', + filename: '/root/packages/storybook/src/path/to.ts', }, { errors: [{ messageId: 'noCircularNx' }], diff --git a/tools/eslint-rules/rules/restrict-nx-imports.ts b/tools/eslint-rules/rules/restrict-nx-imports.ts index 5a7b95eabac84..9646a2e2a403f 100644 --- a/tools/eslint-rules/rules/restrict-nx-imports.ts +++ b/tools/eslint-rules/rules/restrict-nx-imports.ts @@ -36,10 +36,10 @@ export const rule = ESLintUtils.RuleCreator(() => __filename)({ messages: { noCircularNx: 'Functions within "nx" should be imported with relative path. Alias import found: {{imp}}', - noDeepImport: - 'Functions from "nx/src/plugins/js" should be imported via barrel import. Deep import found: {{imp}}', - noDeepRelativeImport: - 'Functions from "./plugins/js" should be imported via relative barrel import. Deep import found: {{imp}}', + noJsImport: + 'Functions from "nx/src/plugins/js" should be imported from "@nrwl/js". Direct import found: {{imp}}', + + // TODO add deep import check from non js to nx/src/plugins/js }, }, defaultOptions: [], @@ -62,25 +62,17 @@ export const rule = ESLintUtils.RuleCreator(() => __filename)({ return; } const imp = node.source.value as string; - if (imp.includes('nx/src/plugins/js/')) { - context.report({ - node, - messageId: 'noDeepImport', - data: { - imp, - }, - }); - } const fileName = normalizePath(context.getFilename()).slice( workspaceRoot.length + 1 ); + if ( - imp.includes('./plugins/js/') && - fileName.startsWith('packages/nx/') + imp.includes('nx/src/plugins/js/') && + !fileName.startsWith('packages/js/') ) { context.report({ node, - messageId: 'noDeepRelativeImport', + messageId: 'noJsImport', data: { imp, },