From 6b03d251986feffda4721de182bb0fdc5b7a272d Mon Sep 17 00:00:00 2001 From: Miroslav Jonas Date: Fri, 18 Nov 2022 13:59:26 +0100 Subject: [PATCH 1/2] feat(core): simplify project graph file mapping for linter rule --- packages/angular/plugins/component-testing.ts | 10 +++--- packages/cypress/plugins/cypress-preset.ts | 6 ++-- .../src/rules/enforce-module-boundaries.ts | 16 +++++++-- .../src/rules/nx-plugin-checks.ts | 9 +++-- .../src/utils/project-graph-utils.ts | 28 +++++++++------ .../src/utils/runtime-lint-utils.ts | 35 +++++++++++++------ .../nx/src/utils/target-project-locator.ts | 24 ++++--------- 7 files changed, 78 insertions(+), 50 deletions(-) diff --git a/packages/angular/plugins/component-testing.ts b/packages/angular/plugins/component-testing.ts index bce2cbab5bc05..977ebe2c3de5a 100644 --- a/packages/angular/plugins/component-testing.ts +++ b/packages/angular/plugins/component-testing.ts @@ -21,7 +21,7 @@ import { stripIndents, workspaceRoot, } from '@nrwl/devkit'; -import { mapProjectGraphFiles } from 'nx/src/utils/target-project-locator'; +import { createProjectFileMappings } from 'nx/src/utils/target-project-locator'; import { lstatSync, mkdirSync, writeFileSync } from 'fs'; import { dirname, join, relative } from 'path'; import type { BrowserBuilderSchema } from '../src/builders/webpack-browser/webpack-browser.impl'; @@ -279,14 +279,16 @@ function withSchemaDefaults(options: any): BrowserBuilderSchema { * this file should get cleaned up via the cypress executor */ function getTempStylesForTailwind(ctExecutorContext: ExecutorContext) { - const mappedGraph = mapProjectGraphFiles(ctExecutorContext.projectGraph); + const mappedGraphFiles = createProjectFileMappings( + ctExecutorContext.projectGraph + ); const ctProjectConfig = ctExecutorContext.projectGraph.nodes[ ctExecutorContext.projectName ].data as ProjectConfiguration; // angular only supports `tailwind.config.{js,cjs}` const ctProjectTailwindConfig = join(ctProjectConfig.root, 'tailwind.config'); - const isTailWindInCtProject = !!mappedGraph.allFiles[ctProjectTailwindConfig]; - const isTailWindInRoot = !!mappedGraph.allFiles['tailwind.config']; + const isTailWindInCtProject = !!mappedGraphFiles[ctProjectTailwindConfig]; + const isTailWindInRoot = !!mappedGraphFiles['tailwind.config']; if (isTailWindInRoot || isTailWindInCtProject) { const pathToStyle = getTempTailwindPath(ctExecutorContext); diff --git a/packages/cypress/plugins/cypress-preset.ts b/packages/cypress/plugins/cypress-preset.ts index 22375f866cbef..d5a44a031e8d5 100644 --- a/packages/cypress/plugins/cypress-preset.ts +++ b/packages/cypress/plugins/cypress-preset.ts @@ -9,7 +9,7 @@ import { workspaceRoot, } from '@nrwl/devkit'; import { readProjectsConfigurationFromProjectGraph } from 'nx/src/project-graph/project-graph'; -import { mapProjectGraphFiles } from 'nx/src/utils/target-project-locator'; +import { createProjectFileMappings } from 'nx/src/utils/target-project-locator'; import { dirname, extname, join, relative } from 'path'; import { lstatSync } from 'fs'; @@ -90,9 +90,9 @@ export function getProjectConfigByPath( : configFileFromWorkspaceRoot ); - const mappedGraph = mapProjectGraphFiles(graph); + const mappedGraphFiles = createProjectFileMappings(graph); const componentTestingProjectName = - mappedGraph.allFiles[normalizedPathFromWorkspaceRoot]; + mappedGraphFiles[normalizedPathFromWorkspaceRoot]; if ( !componentTestingProjectName || !graph.nodes[componentTestingProjectName]?.data 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 6d1c7af5d57c8..fe57742c52e0b 100644 --- a/packages/eslint-plugin-nx/src/rules/enforce-module-boundaries.ts +++ b/packages/eslint-plugin-nx/src/rules/enforce-module-boundaries.ts @@ -154,7 +154,8 @@ export default createESLintRule({ ); const fileName = normalizePath(context.getFilename()); - const projectGraph = readProjectGraph(RULE_NAME); + const { projectGraph, projectGraphFileMappings } = + readProjectGraph(RULE_NAME); if (!projectGraph) { return {}; @@ -198,7 +199,11 @@ export default createESLintRule({ const sourceFilePath = getSourceFilePath(fileName, projectPath); - const sourceProject = findSourceProject(projectGraph, sourceFilePath); + const sourceProject = findSourceProject( + projectGraph, + projectGraphFileMappings, + sourceFilePath + ); // If source is not part of an nx workspace, return. if (!sourceProject) { return; @@ -210,12 +215,17 @@ export default createESLintRule({ let targetProject: ProjectGraphProjectNode | ProjectGraphExternalNode; if (isAbsoluteImportIntoAnotherProj) { - targetProject = findTargetProject(projectGraph, imp); + targetProject = findTargetProject( + projectGraph, + projectGraphFileMappings, + imp + ); } else { targetProject = getTargetProjectBasedOnRelativeImport( imp, projectPath, projectGraph, + projectGraphFileMappings, sourceFilePath ); } diff --git a/packages/eslint-plugin-nx/src/rules/nx-plugin-checks.ts b/packages/eslint-plugin-nx/src/rules/nx-plugin-checks.ts index a7024277e46d5..15be457135401 100644 --- a/packages/eslint-plugin-nx/src/rules/nx-plugin-checks.ts +++ b/packages/eslint-plugin-nx/src/rules/nx-plugin-checks.ts @@ -87,14 +87,19 @@ export default createESLintRule({ return {}; } - const projectGraph = readProjectGraph(RULE_NAME); + const { projectGraph, projectGraphFileMappings } = + readProjectGraph(RULE_NAME); const sourceFilePath = getSourceFilePath( context.getFilename(), workspaceRoot ); - const sourceProject = findSourceProject(projectGraph, sourceFilePath); + const sourceProject = findSourceProject( + projectGraph, + projectGraphFileMappings, + sourceFilePath + ); // If source is not part of an nx workspace, return. if (!sourceProject) { return {}; diff --git a/packages/eslint-plugin-nx/src/utils/project-graph-utils.ts b/packages/eslint-plugin-nx/src/utils/project-graph-utils.ts index ad7ec951a087c..37bd244bc9f4b 100644 --- a/packages/eslint-plugin-nx/src/utils/project-graph-utils.ts +++ b/packages/eslint-plugin-nx/src/utils/project-graph-utils.ts @@ -1,8 +1,5 @@ -import { readCachedProjectGraph, readNxJson } from '@nrwl/devkit'; -import { - mapProjectGraphFiles, - MappedProjectGraph, -} from 'nx/src/utils/target-project-locator'; +import { ProjectGraph, readCachedProjectGraph, readNxJson } from '@nrwl/devkit'; +import { createProjectFileMappings } from 'nx/src/utils/target-project-locator'; import { isTerminalRun } from './runtime-lint-utils'; import * as chalk from 'chalk'; @@ -11,7 +8,11 @@ export function ensureGlobalProjectGraph(ruleName: string) { * Only reuse graph when running from terminal * Enforce every IDE change to get a fresh nxdeps.json */ - if (!(global as any).projectGraph || !isTerminalRun()) { + if ( + !(global as any).projectGraph || + !(global as any).projectGraphFileMappings || + !isTerminalRun() + ) { const nxJson = readNxJson(); (global as any).workspaceLayout = nxJson.workspaceLayout; @@ -20,8 +21,9 @@ export function ensureGlobalProjectGraph(ruleName: string) { * the ProjectGraph may or may not exist by the time the lint rule is invoked for the first time. */ try { - (global as any).projectGraph = mapProjectGraphFiles( - readCachedProjectGraph() + (global as any).projectGraph = readCachedProjectGraph(); + (global as any).projectGraphFileMappings = createProjectFileMappings( + (global as any).projectGraph ); } catch { const WARNING_PREFIX = `${chalk.reset.keyword('orange')('warning')}`; @@ -34,7 +36,13 @@ export function ensureGlobalProjectGraph(ruleName: string) { } } -export function readProjectGraph(ruleName: string) { +export function readProjectGraph(ruleName: string): { + projectGraph: ProjectGraph; + projectGraphFileMappings: Record; +} { ensureGlobalProjectGraph(ruleName); - return (global as any).projectGraph as MappedProjectGraph; + return { + projectGraph: (global as any).projectGraph, + projectGraphFileMappings: (global as any).projectGraphFileMappings, + }; } diff --git a/packages/eslint-plugin-nx/src/utils/runtime-lint-utils.ts b/packages/eslint-plugin-nx/src/utils/runtime-lint-utils.ts index 0bcb72f6a1c52..ce099cf37d636 100644 --- a/packages/eslint-plugin-nx/src/utils/runtime-lint-utils.ts +++ b/packages/eslint-plugin-nx/src/utils/runtime-lint-utils.ts @@ -16,7 +16,6 @@ import { existsSync } from 'fs'; import { readFileIfExisting } from 'nx/src/project-graph/file-utils'; import { TargetProjectLocator, - MappedProjectGraph, removeExt, } from 'nx/src/utils/target-project-locator'; @@ -99,7 +98,8 @@ export function isRelative(s: string) { export function getTargetProjectBasedOnRelativeImport( imp: string, projectPath: string, - projectGraph: MappedProjectGraph, + projectGraph: ProjectGraph, + projectGraphFileMappings: Record, sourceFilePath: string ): ProjectGraphProjectNode | undefined { if (!isRelative(imp)) { @@ -111,38 +111,51 @@ export function getTargetProjectBasedOnRelativeImport( projectPath.length + 1 ); - return findTargetProject(projectGraph, targetFile); + return findTargetProject(projectGraph, projectGraphFileMappings, targetFile); } -export function findProjectUsingFile( - projectGraph: MappedProjectGraph, +function findProjectUsingFile( + projectGraph: ProjectGraph, + projectGraphFileMappings: Record, file: string ): ProjectGraphProjectNode { - return projectGraph.nodes[projectGraph.allFiles[file]]; + return projectGraph.nodes[projectGraphFileMappings[file]]; } export function findSourceProject( - projectGraph: MappedProjectGraph, + projectGraph: ProjectGraph, + projectGraphFileMappings: Record, sourceFilePath: string ) { const targetFile = removeExt(sourceFilePath); - return findProjectUsingFile(projectGraph, targetFile); + return findProjectUsingFile( + projectGraph, + projectGraphFileMappings, + targetFile + ); } export function findTargetProject( - projectGraph: MappedProjectGraph, + projectGraph: ProjectGraph, + projectGraphFileMappings: Record, targetFile: string ) { - let targetProject = findProjectUsingFile(projectGraph, targetFile); + let targetProject = findProjectUsingFile( + projectGraph, + projectGraphFileMappings, + targetFile + ); if (!targetProject) { targetProject = findProjectUsingFile( projectGraph, + projectGraphFileMappings, normalizePath(path.join(targetFile, 'index')) ); } if (!targetProject) { targetProject = findProjectUsingFile( projectGraph, + projectGraphFileMappings, normalizePath(path.join(targetFile, 'src', 'index')) ); } @@ -162,7 +175,7 @@ export function isAbsoluteImportIntoAnotherProject( } export function findProjectUsingImport( - projectGraph: MappedProjectGraph, + projectGraph: ProjectGraph, targetProjectLocator: TargetProjectLocator, filePath: string, imp: string diff --git a/packages/nx/src/utils/target-project-locator.ts b/packages/nx/src/utils/target-project-locator.ts index 59ded7b6c6988..fb365c8572690 100644 --- a/packages/nx/src/utils/target-project-locator.ts +++ b/packages/nx/src/utils/target-project-locator.ts @@ -206,7 +206,7 @@ function filterRootExternalDependencies( */ export function createProjectRootMappings( nodes: Record -) { +): Map { const projectRootMappings = new Map(); for (const projectName of Object.keys(nodes)) { const root = nodes[projectName].data.root; @@ -218,10 +218,6 @@ export function createProjectRootMappings( return projectRootMappings; } -export type MappedProjectGraph = ProjectGraph & { - allFiles: Record; -}; - /** * Strips the file extension from the file path * @param file @@ -237,26 +233,20 @@ export function removeExt(file: string): string { * @param projectGraph * @returns */ -export function mapProjectGraphFiles( - projectGraph: ProjectGraph -): MappedProjectGraph | null { - if (!projectGraph) { - return null; - } - const allFiles: Record = {}; +export function createProjectFileMappings( + projectGraph: ProjectGraph +): Record { + const result: Record = {}; Object.entries( projectGraph.nodes as Record ).forEach(([name, node]) => { node.data.files.forEach(({ file }) => { const fileName = removeExt(file); - allFiles[fileName] = name; + result[fileName] = name; }); }); - return { - ...projectGraph, - allFiles, - }; + return result; } /** From be43e0c01242ff3be3d62d4c90241eb874648337 Mon Sep 17 00:00:00 2001 From: Miroslav Jonas Date: Fri, 18 Nov 2022 14:06:39 +0100 Subject: [PATCH 2/2] chore(linter): fix leftover tests --- .../src/rules/enforce-module-boundaries.spec.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 389d6fab160bc..190009b98d982 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 @@ -5,7 +5,7 @@ import { TSESLint } from '@typescript-eslint/utils'; import { vol } from 'memfs'; import { TargetProjectLocator, - mapProjectGraphFiles, + createProjectFileMappings, } from 'nx/src/utils/target-project-locator'; import enforceModuleBoundaries, { RULE_NAME as enforceModuleBoundariesRuleName, @@ -1885,7 +1885,9 @@ function runRule( projectGraph: ProjectGraph ): TSESLint.Linter.LintMessage[] { (global as any).projectPath = `${process.cwd()}/proj`; - (global as any).projectGraph = mapProjectGraphFiles(projectGraph); + (global as any).projectGraph = projectGraph; + (global as any).projectGraphFileMappings = + createProjectFileMappings(projectGraph); (global as any).targetProjectLocator = new TargetProjectLocator( projectGraph.nodes, projectGraph.externalNodes