From 6d35fd4d85ca86d39a7518630f069b4d24fab887 Mon Sep 17 00:00:00 2001 From: Jason Jean Date: Thu, 24 Nov 2022 11:02:32 -0500 Subject: [PATCH] chore(core): reconcile functions to find project of a path (#13364) --- packages/angular/plugins/component-testing.ts | 23 ++-- .../component/lib/normalize-options.ts | 18 ++-- .../utils/storybook-ast/storybook-inputs.ts | 3 +- packages/cypress/plugins/cypress-preset.ts | 17 +-- packages/eslint-plugin-nx/.eslintrc.json | 1 + .../rules/enforce-module-boundaries.spec.ts | 24 ++--- .../src/rules/enforce-module-boundaries.ts | 18 ++-- .../src/rules/nx-plugin-checks.ts | 12 +-- .../src/utils/project-graph-utils.ts | 17 ++- .../src/utils/runtime-lint-utils.ts | 71 +++---------- .../utils/config/legacy/functions.ts | 3 +- .../locators/workspace-projects.spec.ts | 26 ++--- .../affected/locators/workspace-projects.ts | 17 +-- .../nx/src/project-graph/file-map-utils.ts | 76 ++++--------- .../utils/find-project-for-path.spec.ts | 85 +++++++++++++++ .../utils/find-project-for-path.ts | 64 +++++++++++ packages/nx/src/utils/nx-plugin.ts | 27 ++--- .../nx/src/utils/project-graph-utils.spec.ts | 21 ---- packages/nx/src/utils/project-graph-utils.ts | 35 +----- .../src/utils/target-project-locator.spec.ts | 65 +++++++----- .../nx/src/utils/target-project-locator.ts | 100 ++---------------- packages/nx/src/utils/typescript.ts | 9 +- packages/storybook/src/executors/utils.ts | 4 +- packages/workspace/index.ts | 2 +- .../workspace/src/utilities/generate-globs.ts | 20 ++-- .../workspace/src/utilities/typescript.ts | 1 + .../src/utilities/typescript/find-nodes.ts | 16 +++ packages/workspace/src/utils/ast-utils.ts | 10 +- 28 files changed, 373 insertions(+), 412 deletions(-) create mode 100644 packages/nx/src/project-graph/utils/find-project-for-path.spec.ts create mode 100644 packages/nx/src/project-graph/utils/find-project-for-path.ts create mode 100644 packages/workspace/src/utilities/typescript/find-nodes.ts diff --git a/packages/angular/plugins/component-testing.ts b/packages/angular/plugins/component-testing.ts index d949c1a90cbc1..d43b2adf88f57 100644 --- a/packages/angular/plugins/component-testing.ts +++ b/packages/angular/plugins/component-testing.ts @@ -21,8 +21,7 @@ import { stripIndents, workspaceRoot, } from '@nrwl/devkit'; -import { createProjectFileMappings } from 'nx/src/utils/target-project-locator'; -import { lstatSync, mkdirSync, writeFileSync } from 'fs'; +import { existsSync, lstatSync, mkdirSync, writeFileSync } from 'fs'; import { dirname, join, relative } from 'path'; import type { BrowserBuilderSchema } from '../src/builders/webpack-browser/webpack-browser.impl'; @@ -74,7 +73,7 @@ ${e.stack ? e.stack : e}` const buildTarget = getBuildableTarget(ctContext); if (!buildTarget.project && !graph.nodes?.[buildTarget.project]?.data) { - throw new Error(stripIndents`Unable to find project configuration for build target. + throw new Error(stripIndents`Unable to find project configuration for build target. Project Name? ${buildTarget.project} Has project config? ${!!graph.nodes?.[buildTarget.project]?.data}`); } @@ -279,16 +278,22 @@ function withSchemaDefaults(options: any): BrowserBuilderSchema { * this file should get cleaned up via the cypress executor */ function getTempStylesForTailwind(ctExecutorContext: ExecutorContext) { - const mappedGraphFiles = createProjectFileMappings( - ctExecutorContext.projectGraph.nodes - ); 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 = !!mappedGraphFiles[ctProjectTailwindConfig]; - const isTailWindInRoot = !!mappedGraphFiles['tailwind.config']; + const ctProjectTailwindConfig = join( + ctExecutorContext.root, + ctProjectConfig.root, + 'tailwind.config' + ); + const isTailWindInCtProject = + existsSync(ctProjectTailwindConfig + '.js') || + existsSync(ctProjectTailwindConfig + '.cjs'); + const rootTailwindPath = join(ctExecutorContext.root, 'tailwind.config'); + const isTailWindInRoot = + existsSync(rootTailwindPath + '.js') || + existsSync(rootTailwindPath + '.cjs'); if (isTailWindInRoot || isTailWindInCtProject) { const pathToStyle = getTempTailwindPath(ctExecutorContext); diff --git a/packages/angular/src/generators/component/lib/normalize-options.ts b/packages/angular/src/generators/component/lib/normalize-options.ts index 7a308f429a663..587e68b18272f 100644 --- a/packages/angular/src/generators/component/lib/normalize-options.ts +++ b/packages/angular/src/generators/component/lib/normalize-options.ts @@ -1,27 +1,25 @@ import type { Tree } from '@nrwl/devkit'; import { joinPathFragments, + readCachedProjectGraph, readProjectConfiguration, readWorkspaceConfiguration, } from '@nrwl/devkit'; import type { NormalizedSchema, Schema } from '../schema'; -import { getProjectNameFromDirPath } from 'nx/src/utils/project-graph-utils'; - -function getProjectFromPath(path: string) { - try { - return getProjectNameFromDirPath(path); - } catch { - return null; - } -} +import { + createProjectRootMappings, + findProjectForPath, +} from 'nx/src/project-graph/utils/find-project-for-path'; export function normalizeOptions( tree: Tree, options: Schema ): NormalizedSchema { + const projectGraph = readCachedProjectGraph(); + const projectRootMappings = createProjectRootMappings(projectGraph.nodes); const project = options.project ?? - getProjectFromPath(options.path) ?? + findProjectForPath(options.path, projectRootMappings) ?? readWorkspaceConfiguration(tree).defaultProject; const { projectType, root, sourceRoot } = readProjectConfiguration( tree, diff --git a/packages/angular/src/generators/utils/storybook-ast/storybook-inputs.ts b/packages/angular/src/generators/utils/storybook-ast/storybook-inputs.ts index 5c65d8bd996f6..3bd28dc526111 100644 --- a/packages/angular/src/generators/utils/storybook-ast/storybook-inputs.ts +++ b/packages/angular/src/generators/utils/storybook-ast/storybook-inputs.ts @@ -1,7 +1,6 @@ import type { Tree } from '@nrwl/devkit'; -import { getSourceNodes } from '@nrwl/workspace/src/utilities/typescript'; import { findNodes } from 'nx/src/utils/typescript'; - +import { getSourceNodes } from '@nrwl/workspace/src/utilities/typescript'; import type { PropertyDeclaration } from 'typescript'; import { SyntaxKind } from 'typescript'; import { getTsSourceFile } from '../../../utils/nx-devkit/ast-utils'; diff --git a/packages/cypress/plugins/cypress-preset.ts b/packages/cypress/plugins/cypress-preset.ts index 578e688c5eea4..6b3230c848bca 100644 --- a/packages/cypress/plugins/cypress-preset.ts +++ b/packages/cypress/plugins/cypress-preset.ts @@ -9,9 +9,12 @@ import { workspaceRoot, } from '@nrwl/devkit'; import { readProjectsConfigurationFromProjectGraph } from 'nx/src/project-graph/project-graph'; -import { createProjectFileMappings } from 'nx/src/utils/target-project-locator'; import { dirname, extname, join, relative } from 'path'; import { lstatSync } from 'fs'; +import { + createProjectRootMappings, + findProjectForPath, +} from 'nx/src/project-graph/utils/find-project-for-path'; interface BaseCypressPreset { videosFolder: string; @@ -90,16 +93,18 @@ export function getProjectConfigByPath( : configFileFromWorkspaceRoot ); - const mappedGraphFiles = createProjectFileMappings(graph.nodes); - const componentTestingProjectName = - mappedGraphFiles[normalizedPathFromWorkspaceRoot]; + const projectRootMappings = createProjectRootMappings(graph.nodes); + const componentTestingProjectName = findProjectForPath( + normalizedPathFromWorkspaceRoot, + projectRootMappings + ); if ( !componentTestingProjectName || !graph.nodes[componentTestingProjectName]?.data ) { throw new Error( - stripIndents`Unable to find the project configuration that includes ${normalizedPathFromWorkspaceRoot}. - Found project name? ${componentTestingProjectName}. + stripIndents`Unable to find the project configuration that includes ${normalizedPathFromWorkspaceRoot}. + Found project name? ${componentTestingProjectName}. Graph has data? ${!!graph.nodes[componentTestingProjectName]?.data}` ); } diff --git a/packages/eslint-plugin-nx/.eslintrc.json b/packages/eslint-plugin-nx/.eslintrc.json index 5b07d3871cec9..ff47ddace4d51 100644 --- a/packages/eslint-plugin-nx/.eslintrc.json +++ b/packages/eslint-plugin-nx/.eslintrc.json @@ -3,6 +3,7 @@ "rules": { "no-restricted-imports": [ "error", + "@nrwl/workspace", "@angular-devkit/core", "@angular-devkit/architect", "@angular-devkit/schematics" 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 56ee3ea47cecf..294b8218d4682 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 @@ -3,13 +3,11 @@ import { DependencyType } from '@nrwl/devkit'; import * as parser from '@typescript-eslint/parser'; import { TSESLint } from '@typescript-eslint/utils'; import { vol } from 'memfs'; -import { - TargetProjectLocator, - createProjectFileMappings, -} from 'nx/src/utils/target-project-locator'; +import { TargetProjectLocator } from 'nx/src/utils/target-project-locator'; import enforceModuleBoundaries, { RULE_NAME as enforceModuleBoundariesRuleName, -} from './enforce-module-boundaries'; +} from '../../src/rules/enforce-module-boundaries'; +import { createProjectRootMappings } from 'nx/src/project-graph/utils/find-project-for-path'; jest.mock('fs', () => require('memfs').fs); @@ -1015,7 +1013,7 @@ Violation detected in: tags: [], implicitDependencies: [], architect: {}, - files: [createFile(`libs/other/src/index.ts`)], + files: [createFile(`libs/other/index.ts`)], }, }, }, @@ -1033,7 +1031,6 @@ Violation detected in: if (importKind === 'type') { expect(failures.length).toEqual(0); } else { - expect(failures.length).toEqual(1); expect(failures[0].message).toEqual( 'Imports of lazy-loaded libraries are forbidden' ); @@ -1145,10 +1142,7 @@ Violation detected in: tags: [], implicitDependencies: [], architect: {}, - files: [ - createFile(`libs/mylib/src/main.ts`), - createFile(`libs/mylib/src/index.ts`), - ], + files: [createFile(`libs/mylib/src/main.ts`)], }, }, anotherlibName: { @@ -1272,10 +1266,7 @@ Violation detected in: tags: [], implicitDependencies: [], architect: {}, - files: [ - createFile(`libs/mylib/src/main.ts`, ['anotherlibName']), - createFile(`libs/mylib/src/index.ts`), - ], + files: [createFile(`libs/mylib/src/main.ts`, ['anotherlibName'])], }, }, anotherlibName: { @@ -1370,7 +1361,6 @@ Circular file chain: architect: {}, files: [ createFile(`libs/badcirclelib/src/main.ts`, ['anotherlibName']), - createFile(`libs/badcirclelib/src/index.ts`), ], }, }, @@ -1894,7 +1884,7 @@ function runRule( ): TSESLint.Linter.LintMessage[] { (global as any).projectPath = `${process.cwd()}/proj`; (global as any).projectGraph = projectGraph; - (global as any).projectGraphFileMappings = createProjectFileMappings( + (global as any).projectRootMappings = createProjectRootMappings( projectGraph.nodes ); (global as any).targetProjectLocator = new TargetProjectLocator( 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 fe57742c52e0b..ecc6b523a1522 100644 --- a/packages/eslint-plugin-nx/src/rules/enforce-module-boundaries.ts +++ b/packages/eslint-plugin-nx/src/rules/enforce-module-boundaries.ts @@ -15,9 +15,8 @@ import { findConstraintsFor, findDependenciesWithTags, findProjectUsingImport, - findSourceProject, + findProject, findTransitiveExternalDependencies, - findTargetProject, getSourceFilePath, getTargetProjectBasedOnRelativeImport, groupImports, @@ -154,8 +153,7 @@ export default createESLintRule({ ); const fileName = normalizePath(context.getFilename()); - const { projectGraph, projectGraphFileMappings } = - readProjectGraph(RULE_NAME); + const { projectGraph, projectRootMappings } = readProjectGraph(RULE_NAME); if (!projectGraph) { return {}; @@ -199,9 +197,9 @@ export default createESLintRule({ const sourceFilePath = getSourceFilePath(fileName, projectPath); - const sourceProject = findSourceProject( + const sourceProject = findProject( projectGraph, - projectGraphFileMappings, + projectRootMappings, sourceFilePath ); // If source is not part of an nx workspace, return. @@ -215,17 +213,13 @@ export default createESLintRule({ let targetProject: ProjectGraphProjectNode | ProjectGraphExternalNode; if (isAbsoluteImportIntoAnotherProj) { - targetProject = findTargetProject( - projectGraph, - projectGraphFileMappings, - imp - ); + targetProject = findProject(projectGraph, projectRootMappings, imp); } else { targetProject = getTargetProjectBasedOnRelativeImport( imp, projectPath, projectGraph, - projectGraphFileMappings, + projectRootMappings, 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 15be457135401..239d71c952698 100644 --- a/packages/eslint-plugin-nx/src/rules/nx-plugin-checks.ts +++ b/packages/eslint-plugin-nx/src/rules/nx-plugin-checks.ts @@ -6,10 +6,7 @@ import { readJsonFile, workspaceRoot, } from '@nrwl/devkit'; -import { - findSourceProject, - getSourceFilePath, -} from '../utils/runtime-lint-utils'; +import { findProject, getSourceFilePath } from '../utils/runtime-lint-utils'; import { existsSync } from 'fs'; import { registerTsProject } from 'nx/src/utils/register'; import * as path from 'path'; @@ -87,17 +84,16 @@ export default createESLintRule({ return {}; } - const { projectGraph, projectGraphFileMappings } = - readProjectGraph(RULE_NAME); + const { projectGraph, projectRootMappings } = readProjectGraph(RULE_NAME); const sourceFilePath = getSourceFilePath( context.getFilename(), workspaceRoot ); - const sourceProject = findSourceProject( + const sourceProject = findProject( projectGraph, - projectGraphFileMappings, + projectRootMappings, sourceFilePath ); // If source is not part of an nx workspace, 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 1a5956435dd41..0684b7dbd5cf2 100644 --- a/packages/eslint-plugin-nx/src/utils/project-graph-utils.ts +++ b/packages/eslint-plugin-nx/src/utils/project-graph-utils.ts @@ -1,18 +1,17 @@ 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'; +import { + createProjectRootMappings, + ProjectRootMappings, +} from 'nx/src/project-graph/utils/find-project-for-path'; 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 || - !(global as any).projectGraphFileMappings || - !isTerminalRun() - ) { + if (!(global as any).projectGraph || !isTerminalRun()) { const nxJson = readNxJson(); (global as any).workspaceLayout = nxJson.workspaceLayout; @@ -22,7 +21,7 @@ export function ensureGlobalProjectGraph(ruleName: string) { */ try { (global as any).projectGraph = readCachedProjectGraph(); - (global as any).projectGraphFileMappings = createProjectFileMappings( + (global as any).projectRootMappings = createProjectRootMappings( (global as any).projectGraph.nodes ); } catch { @@ -38,11 +37,11 @@ export function ensureGlobalProjectGraph(ruleName: string) { export function readProjectGraph(ruleName: string): { projectGraph: ProjectGraph; - projectGraphFileMappings: Record; + projectRootMappings: ProjectRootMappings; } { ensureGlobalProjectGraph(ruleName); return { projectGraph: (global as any).projectGraph, - projectGraphFileMappings: (global as any).projectGraphFileMappings, + projectRootMappings: (global as any).projectRootMappings, }; } 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 ce099cf37d636..09faa14803001 100644 --- a/packages/eslint-plugin-nx/src/utils/runtime-lint-utils.ts +++ b/packages/eslint-plugin-nx/src/utils/runtime-lint-utils.ts @@ -1,23 +1,24 @@ import * as path from 'path'; +import { join } from 'path'; import { - ProjectGraph, - ProjectGraphDependency, - ProjectGraphProjectNode, - normalizePath, DependencyType, + joinPathFragments, + normalizePath, parseJson, + ProjectGraph, + ProjectGraphDependency, ProjectGraphExternalNode, - joinPathFragments, + ProjectGraphProjectNode, workspaceRoot, } from '@nrwl/devkit'; -import { join } from 'path'; import { getPath, pathExists } from './graph-utils'; import { existsSync } from 'fs'; import { readFileIfExisting } from 'nx/src/project-graph/file-utils'; +import { TargetProjectLocator } from 'nx/src/utils/target-project-locator'; import { - TargetProjectLocator, - removeExt, -} from 'nx/src/utils/target-project-locator'; + findProjectForPath, + ProjectRootMappings, +} from 'nx/src/project-graph/utils/find-project-for-path'; export type Deps = { [projectName: string]: ProjectGraphDependency[] }; export type DepConstraint = { @@ -99,7 +100,7 @@ export function getTargetProjectBasedOnRelativeImport( imp: string, projectPath: string, projectGraph: ProjectGraph, - projectGraphFileMappings: Record, + projectRootMappings: ProjectRootMappings, sourceFilePath: string ): ProjectGraphProjectNode | undefined { if (!isRelative(imp)) { @@ -111,55 +112,17 @@ export function getTargetProjectBasedOnRelativeImport( projectPath.length + 1 ); - return findTargetProject(projectGraph, projectGraphFileMappings, targetFile); + return findProject(projectGraph, projectRootMappings, targetFile); } -function findProjectUsingFile( +export function findProject( projectGraph: ProjectGraph, - projectGraphFileMappings: Record, - file: string -): ProjectGraphProjectNode { - return projectGraph.nodes[projectGraphFileMappings[file]]; -} - -export function findSourceProject( - projectGraph: ProjectGraph, - projectGraphFileMappings: Record, + projectRootMappings: ProjectRootMappings, sourceFilePath: string ) { - const targetFile = removeExt(sourceFilePath); - return findProjectUsingFile( - projectGraph, - projectGraphFileMappings, - targetFile - ); -} - -export function findTargetProject( - projectGraph: ProjectGraph, - projectGraphFileMappings: Record, - targetFile: string -) { - 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')) - ); - } - return targetProject; + return projectGraph.nodes[ + findProjectForPath(sourceFilePath, projectRootMappings) + ]; } export function isAbsoluteImportIntoAnotherProject( diff --git a/packages/jest/src/migrations/utils/config/legacy/functions.ts b/packages/jest/src/migrations/utils/config/legacy/functions.ts index 281ebc454168c..44ba45124415d 100644 --- a/packages/jest/src/migrations/utils/config/legacy/functions.ts +++ b/packages/jest/src/migrations/utils/config/legacy/functions.ts @@ -1,5 +1,6 @@ import * as ts from 'typescript'; -import { findNodes, InsertChange, ReplaceChange } from '@nrwl/workspace'; +import { InsertChange, ReplaceChange } from '@nrwl/workspace'; +import { findNodes } from 'nx/src/utils/typescript'; import { Tree } from '@angular-devkit/schematics'; import { stripJsonComments } from '@nrwl/devkit'; import { Config } from '@jest/types'; diff --git a/packages/nx/src/project-graph/affected/locators/workspace-projects.spec.ts b/packages/nx/src/project-graph/affected/locators/workspace-projects.spec.ts index 60a9f7613e613..3e6e2c82b1da9 100644 --- a/packages/nx/src/project-graph/affected/locators/workspace-projects.spec.ts +++ b/packages/nx/src/project-graph/affected/locators/workspace-projects.spec.ts @@ -22,9 +22,9 @@ describe('getTouchedProjects', () => { it('should return a list of projects for the given changes', () => { const fileChanges = getFileChanges(['libs/a/index.ts', 'libs/b/index.ts']); const projects = { - a: { root: 'libs/a', files: [{ file: 'libs/a/index.ts' }] }, - b: { root: 'libs/b', files: [{ file: 'libs/b/index.ts' }] }, - c: { root: 'libs/c', files: [{ file: 'libs/c/index.ts' }] }, + a: { root: 'libs/a' }, + b: { root: 'libs/b' }, + c: { root: 'libs/c' }, }; expect( getTouchedProjects(fileChanges, buildProjectGraphNodes(projects)) @@ -34,9 +34,9 @@ describe('getTouchedProjects', () => { it('should return projects with the root matching a whole directory name in the file path', () => { const fileChanges = getFileChanges(['libs/a-b/index.ts']); const projects = { - a: { root: 'libs/a', files: [{ file: 'libs/a/index.ts' }] }, - abc: { root: 'libs/a-b-c', files: [{ file: 'libs/a-b-c/index.ts' }] }, - ab: { root: 'libs/a-b', files: [{ file: 'libs/a-b/index.ts' }] }, + a: { root: 'libs/a' }, + abc: { root: 'libs/a-b-c' }, + ab: { root: 'libs/a-b' }, }; expect( getTouchedProjects(fileChanges, buildProjectGraphNodes(projects)) @@ -46,9 +46,9 @@ describe('getTouchedProjects', () => { it('should return projects with the root matching a whole directory name in the file path', () => { const fileChanges = getFileChanges(['libs/a-b/index.ts']); const projects = { - aaaaa: { root: 'libs/a', files: [{ file: 'libs/a/index.ts' }] }, - abc: { root: 'libs/a-b-c', files: [{ file: 'libs/a-b-c/index.ts' }] }, - ab: { root: 'libs/a-b', files: [{ file: 'libs/a-b/index.ts' }] }, + aaaaa: { root: 'libs/a' }, + abc: { root: 'libs/a-b-c' }, + ab: { root: 'libs/a-b' }, }; expect( getTouchedProjects(fileChanges, buildProjectGraphNodes(projects)) @@ -58,8 +58,8 @@ describe('getTouchedProjects', () => { it('should return the most qualifying match with the file path', () => { const fileChanges = getFileChanges(['libs/a/b/index.ts']); const projects = { - aaaaa: { root: 'libs/a', files: [{ file: 'libs/a/index.ts' }] }, - ab: { root: 'libs/a/b', files: [{ file: 'libs/a/b/index.ts' }] }, + aaaaa: { root: 'libs/a' }, + ab: { root: 'libs/a/b' }, }; expect( getTouchedProjects(fileChanges, buildProjectGraphNodes(projects)) @@ -69,8 +69,8 @@ describe('getTouchedProjects', () => { it('should not return parent project if nested project is touched', () => { const fileChanges = getFileChanges(['libs/a/b/index.ts']); const projects = { - a: { root: 'libs/a', files: [{ file: 'libs/a/index.ts' }] }, - b: { root: 'libs/a/b', files: [{ file: 'libs/a/b/index.ts' }] }, + a: { root: 'libs/a' }, + b: { root: 'libs/a/b' }, }; expect( getTouchedProjects(fileChanges, buildProjectGraphNodes(projects)) diff --git a/packages/nx/src/project-graph/affected/locators/workspace-projects.ts b/packages/nx/src/project-graph/affected/locators/workspace-projects.ts index 0b4dd5de469d1..44aa9ee5041a5 100644 --- a/packages/nx/src/project-graph/affected/locators/workspace-projects.ts +++ b/packages/nx/src/project-graph/affected/locators/workspace-projects.ts @@ -2,23 +2,24 @@ import * as minimatch from 'minimatch'; import { TouchedProjectLocator } from '../affected-project-graph-models'; import { NxJsonConfiguration } from '../../../config/nx-json'; import { ProjectGraphProjectNode } from '../../../config/project-graph'; -import { createProjectFileMappings } from '../../../utils/target-project-locator'; +import { + createProjectRootMappings, + findProjectForPath, +} from '../../utils/find-project-for-path'; export const getTouchedProjects: TouchedProjectLocator = ( touchedFiles, projectGraphNodes ): string[] => { - const allProjectFiles = createProjectFileMappings(projectGraphNodes); - const affected = []; + const projectRootMap = createProjectRootMappings(projectGraphNodes); - touchedFiles.forEach((f) => { - const matchingProject = allProjectFiles[f.file]; + return touchedFiles.reduce((affected, f) => { + const matchingProject = findProjectForPath(f.file, projectRootMap); if (matchingProject) { affected.push(matchingProject); } - }); - - return affected; + return affected; + }, []); }; export const getImplicitlyTouchedProjects: TouchedProjectLocator = ( diff --git a/packages/nx/src/project-graph/file-map-utils.ts b/packages/nx/src/project-graph/file-map-utils.ts index cd72190078174..0ae505fa3ca1d 100644 --- a/packages/nx/src/project-graph/file-map-utils.ts +++ b/packages/nx/src/project-graph/file-map-utils.ts @@ -1,57 +1,23 @@ -import { dirname } from 'path'; import { FileData, ProjectFileMap } from '../config/project-graph'; - -function createProjectRootMappings( - workspaceJson: any, - projectFileMap: ProjectFileMap -) { - const projectRootMappings = new Map(); - for (const projectName of Object.keys(workspaceJson.projects)) { - if (!projectFileMap[projectName]) { - projectFileMap[projectName] = []; - } - const root = - workspaceJson.projects[projectName].root === '' - ? '.' - : workspaceJson.projects[projectName].root; - projectRootMappings.set( - root.endsWith('/') ? root.substring(0, root.length - 1) : root, - projectFileMap[projectName] - ); - } - return projectRootMappings; -} - -function findMatchingProjectFiles( - projectRootMappings: Map, - file: string -) { - let currentPath = file; - do { - currentPath = dirname(currentPath); - const p = projectRootMappings.get(currentPath); - if (p) { - return p; - } - } while (currentPath != dirname(currentPath)); - - return null; -} +import { + createProjectRootMappingsFromProjectConfigurations, + findProjectForPath, +} from './utils/find-project-for-path'; export function createProjectFileMap( workspaceJson: any, allWorkspaceFiles: FileData[] ): { projectFileMap: ProjectFileMap; allWorkspaceFiles: FileData[] } { const projectFileMap: ProjectFileMap = {}; - const projectRootMappings = createProjectRootMappings( - workspaceJson, - projectFileMap - ); + const projectRootMappings = + createProjectRootMappingsFromProjectConfigurations(workspaceJson.projects); + + for (const projectName of Object.keys(workspaceJson.projects)) { + projectFileMap[projectName] ??= []; + } for (const f of allWorkspaceFiles) { - const matchingProjectFiles = findMatchingProjectFiles( - projectRootMappings, - f.file - ); + const matchingProjectFiles = + projectFileMap[findProjectForPath(f.file, projectRootMappings)]; if (matchingProjectFiles) { matchingProjectFiles.push(f); } @@ -66,16 +32,12 @@ export function updateProjectFileMap( updatedFiles: Map, deletedFiles: string[] ): { projectFileMap: ProjectFileMap; allWorkspaceFiles: FileData[] } { - const projectRootMappings = createProjectRootMappings( - workspaceJson, - projectFileMap - ); + const projectRootMappings = + createProjectRootMappingsFromProjectConfigurations(workspaceJson.projects); for (const f of updatedFiles.keys()) { - const matchingProjectFiles = findMatchingProjectFiles( - projectRootMappings, - f - ); + const matchingProjectFiles = + projectFileMap[findProjectForPath(f, projectRootMappings)] ?? []; if (matchingProjectFiles) { const fileData: FileData = matchingProjectFiles.find((t) => t.file === f); if (fileData) { @@ -100,10 +62,8 @@ export function updateProjectFileMap( } for (const f of deletedFiles) { - const matchingProjectFiles = findMatchingProjectFiles( - projectRootMappings, - f - ); + const matchingProjectFiles = + projectFileMap[findProjectForPath(f, projectRootMappings)] ?? []; if (matchingProjectFiles) { const index = matchingProjectFiles.findIndex((t) => t.file === f); if (index > -1) { diff --git a/packages/nx/src/project-graph/utils/find-project-for-path.spec.ts b/packages/nx/src/project-graph/utils/find-project-for-path.spec.ts new file mode 100644 index 0000000000000..b52879e2ca6d2 --- /dev/null +++ b/packages/nx/src/project-graph/utils/find-project-for-path.spec.ts @@ -0,0 +1,85 @@ +import { + createProjectRootMappings, + findProjectForPath, +} from './find-project-for-path'; +import { ProjectGraph } from 'nx/src/config/project-graph'; + +describe('get project utils', () => { + let projectGraph: ProjectGraph; + let projectRootMappings: Map; + describe('findProject', () => { + beforeEach(() => { + projectGraph = { + nodes: { + 'demo-app': { + name: 'demo-app', + type: 'app', + data: { + root: 'apps/demo-app', + }, + }, + ui: { + name: 'ui', + type: 'lib', + data: { + root: 'libs/ui', + sourceRoot: 'libs/ui/src', + projectType: 'library', + targets: {}, + }, + }, + core: { + name: 'core', + type: 'lib', + data: { + root: 'libs/core', + sourceRoot: 'libs/core/src', + projectType: 'library', + targets: {}, + }, + }, + 'implicit-lib': { + name: 'implicit-lib', + type: 'lib', + data: {}, + }, + }, + dependencies: { + 'demo-app': [ + { + type: 'static', + source: 'demo-app', + target: 'ui', + }, + { + type: 'static', + source: 'demo-app', + target: 'npm:chalk', + }, + { + type: 'static', + source: 'demo-app', + target: 'core', + }, + ], + }, + }; + + projectRootMappings = createProjectRootMappings(projectGraph.nodes); + }); + + it('should find the project given a file within its src root', () => { + expect(findProjectForPath('apps/demo-app', projectRootMappings)).toEqual( + 'demo-app' + ); + + expect( + findProjectForPath('apps/demo-app/src', projectRootMappings) + ).toEqual('demo-app'); + + expect( + findProjectForPath('apps/demo-app/src/subdir/bla', projectRootMappings) + ).toEqual('demo-app'); + }); + }); +}); diff --git a/packages/nx/src/project-graph/utils/find-project-for-path.ts b/packages/nx/src/project-graph/utils/find-project-for-path.ts new file mode 100644 index 0000000000000..5b172c5202528 --- /dev/null +++ b/packages/nx/src/project-graph/utils/find-project-for-path.ts @@ -0,0 +1,64 @@ +import { dirname } from 'path'; +import { ProjectGraphProjectNode } from '../../config/project-graph'; +import { ProjectConfiguration } from '../../config/workspace-json-project-json'; + +export type ProjectRootMappings = Map; + +/** + * This creates a map of project roots to project names to easily look up the project of a file + * @param projects This is the map of project configurations commonly found in "workspace.json" + */ +export function createProjectRootMappingsFromProjectConfigurations( + projects: Record +) { + const projectRootMappings: ProjectRootMappings = new Map(); + for (const projectName of Object.keys(projects)) { + const root = projects[projectName].root; + projectRootMappings.set(normalizeProjectRoot(root), projectName); + } + return projectRootMappings; +} + +/** + * This creates a map of project roots to project names to easily look up the project of a file + * @param nodes This is the nodes from the project graph + */ +export function createProjectRootMappings( + nodes: Record +): ProjectRootMappings { + const projectRootMappings = new Map(); + for (const projectName of Object.keys(nodes)) { + let root = nodes[projectName].data.root; + + projectRootMappings.set(normalizeProjectRoot(root), projectName); + } + return projectRootMappings; +} + +/** + * Locates a project in projectRootMap based on a file within it + * @param filePath path that is inside of projectName. This should be relative from the workspace root + * @param projectRootMap Map Use {@link createProjectRootMappings} to create this + */ +export function findProjectForPath( + filePath: string, + projectRootMap: ProjectRootMappings +): string | null { + let currentPath = filePath; + for ( + ; + currentPath != dirname(currentPath); + currentPath = dirname(currentPath) + ) { + const p = projectRootMap.get(currentPath); + if (p) { + return p; + } + } + return projectRootMap.get(currentPath); +} + +function normalizeProjectRoot(root: string) { + root = root === '' ? '.' : root; + return root && root.endsWith('/') ? root.substring(0, root.length - 1) : root; +} diff --git a/packages/nx/src/utils/nx-plugin.ts b/packages/nx/src/utils/nx-plugin.ts index fd054e38d030c..0b706a6f7f499 100644 --- a/packages/nx/src/utils/nx-plugin.ts +++ b/packages/nx/src/utils/nx-plugin.ts @@ -13,11 +13,14 @@ import { import { registerTsProject } from './register'; import { ProjectConfiguration, - TargetConfiguration, ProjectsConfigurations, + TargetConfiguration, } from '../config/workspace-json-project-json'; -import { findMatchingProjectForPath } from './target-project-locator'; import { logger } from './logger'; +import { + createProjectRootMappingsFromProjectConfigurations, + findProjectForPath, +} from '../project-graph/utils/find-project-for-path'; export type ProjectTargetConfigurator = ( file: string @@ -192,15 +195,13 @@ function findNxProjectForImportPath( ): string | null { const tsConfigPaths: Record = readTsConfigPaths(root); const possiblePaths = tsConfigPaths[importPath]?.map((p) => - path.resolve(root, p) + path.relative(root, path.join(root, p)) ); if (possiblePaths?.length) { - const projectRootMappings = buildProjectRootMap(workspace.projects, root); + const projectRootMappings = + createProjectRootMappingsFromProjectConfigurations(workspace.projects); for (const tsConfigPath of possiblePaths) { - const nxProject = findMatchingProjectForPath( - tsConfigPath, - projectRootMappings - ); + const nxProject = findProjectForPath(tsConfigPath, projectRootMappings); if (nxProject) { return nxProject; } @@ -218,16 +219,6 @@ function findNxProjectForImportPath( } } -function buildProjectRootMap( - projects: Record, - root: string -) { - return Object.entries(projects).reduce((m, [project, config]) => { - m.set(path.resolve(root, config.root), project); - return m; - }, new Map()); -} - let tsconfigPaths: Record; function readTsConfigPaths(root: string = workspaceRoot) { if (!tsconfigPaths) { diff --git a/packages/nx/src/utils/project-graph-utils.spec.ts b/packages/nx/src/utils/project-graph-utils.spec.ts index c46aba480595d..5a29ca13173cf 100644 --- a/packages/nx/src/utils/project-graph-utils.spec.ts +++ b/packages/nx/src/utils/project-graph-utils.spec.ts @@ -13,7 +13,6 @@ jest.mock('nx/src/utils/fileutils', () => ({ import { PackageJson } from './package-json'; import { ProjectGraph } from '../config/project-graph'; import { - getProjectNameFromDirPath, getSourceDirOfDependentProjects, mergeNpmScriptsWithTargets, } from './project-graph-utils'; @@ -116,26 +115,6 @@ describe('project graph utils', () => { expect(warnings).toContain('implicit-lib'); }); }); - - it('should find the project given a file within its src root', () => { - expect(getProjectNameFromDirPath('apps/demo-app', projGraph)).toEqual( - 'demo-app' - ); - - expect(getProjectNameFromDirPath('apps/demo-app/src', projGraph)).toEqual( - 'demo-app' - ); - - expect( - getProjectNameFromDirPath('apps/demo-app/src/subdir/bla', projGraph) - ).toEqual('demo-app'); - }); - - it('should throw an error if the project name has not been found', () => { - expect(() => { - getProjectNameFromDirPath('apps/demo-app-unknown'); - }).toThrowError(); - }); }); describe('mergeNpmScriptsWithTargets', () => { diff --git a/packages/nx/src/utils/project-graph-utils.ts b/packages/nx/src/utils/project-graph-utils.ts index 90a88709d396c..a38bda4abf5bc 100644 --- a/packages/nx/src/utils/project-graph-utils.ts +++ b/packages/nx/src/utils/project-graph-utils.ts @@ -1,8 +1,7 @@ import { buildTargetFromScript, PackageJson } from './package-json'; -import { join, relative } from 'path'; +import { join } from 'path'; import { ProjectGraph, ProjectGraphProjectNode } from '../config/project-graph'; import { readJsonFile } from './fileutils'; -import { normalizePath } from './path'; import { readCachedProjectGraph } from '../project-graph/project-graph'; import { TargetConfiguration } from '../config/workspace-json-project-json'; @@ -74,38 +73,6 @@ export function getSourceDirOfDependentProjects( ); } -/** - * Finds the project node name by a file that lives within it's src root - * @param projRelativeDirPath directory path relative to the workspace root - * @param projectGraph - */ -export function getProjectNameFromDirPath( - projRelativeDirPath: string, - projectGraph = readCachedProjectGraph() -) { - let parentNodeName = null; - for (const [nodeName, node] of Object.entries(projectGraph.nodes)) { - const normalizedRootPath = normalizePath(node.data.root); - const normalizedProjRelPath = normalizePath(projRelativeDirPath); - - const relativePath = relative(normalizedRootPath, normalizedProjRelPath); - const isMatch = relativePath && !relativePath.startsWith('..'); - - if (isMatch || normalizedRootPath === normalizedProjRelPath) { - parentNodeName = nodeName; - break; - } - } - - if (!parentNodeName) { - throw new Error( - `Could not find any project containing the file "${projRelativeDirPath}" among it's project files` - ); - } - - return parentNodeName; -} - /** * Find all internal project dependencies. * All the external (npm) dependencies will be filtered out diff --git a/packages/nx/src/utils/target-project-locator.spec.ts b/packages/nx/src/utils/target-project-locator.spec.ts index e660f442bd2d4..8ea60158e5d0f 100644 --- a/packages/nx/src/utils/target-project-locator.spec.ts +++ b/packages/nx/src/utils/target-project-locator.spec.ts @@ -75,13 +75,15 @@ describe('findTargetProjectWithImport', () => { ...nxJson, } as any, fileMap: { - proj: [ + rootProj: [ { - file: 'libs/proj/index.ts', + file: 'index.ts', hash: 'some-hash', }, + ], + proj: [ { - file: 'libs/proj/class.ts', + file: 'libs/proj/index.ts', hash: 'some-hash', }, ], @@ -151,12 +153,20 @@ describe('findTargetProjectWithImport', () => { } as any; projects = { + rootProj: { + name: 'rootProj', + type: 'lib', + data: { + root: '.', + files: [], + }, + }, proj3a: { name: 'proj3a', type: 'lib', data: { root: 'libs/proj3a', - files: ctx.fileMap['proj3a'], + files: [], }, }, proj2: { @@ -164,7 +174,7 @@ describe('findTargetProjectWithImport', () => { type: 'lib', data: { root: 'libs/proj2', - files: ctx.fileMap['proj2'], + files: [], }, }, proj: { @@ -172,7 +182,7 @@ describe('findTargetProjectWithImport', () => { type: 'lib', data: { root: 'libs/proj', - files: ctx.fileMap['proj'], + files: [], }, }, proj1234: { @@ -180,7 +190,7 @@ describe('findTargetProjectWithImport', () => { type: 'lib', data: { root: 'libs/proj1234', - files: ctx.fileMap['proj1234'], + files: [], }, }, proj123: { @@ -188,7 +198,7 @@ describe('findTargetProjectWithImport', () => { type: 'lib', data: { root: 'libs/proj123', - files: ctx.fileMap['proj123'], + files: [], }, }, proj4ab: { @@ -196,7 +206,7 @@ describe('findTargetProjectWithImport', () => { type: 'lib', data: { root: 'libs/proj4ab', - files: ctx.fileMap['proj4ab'], + files: [], }, }, proj5: { @@ -204,7 +214,7 @@ describe('findTargetProjectWithImport', () => { type: 'lib', data: { root: 'libs/proj5', - files: ctx.fileMap['proj5'], + files: [], }, }, proj6: { @@ -212,7 +222,7 @@ describe('findTargetProjectWithImport', () => { type: 'lib', data: { root: 'libs/proj6', - files: ctx.fileMap['proj6'], + files: [], }, }, proj7: { @@ -220,7 +230,7 @@ describe('findTargetProjectWithImport', () => { type: 'lib', data: { root: 'libs/proj7', - files: ctx.fileMap['proj7'], + files: [], }, }, 'proj1234-child': { @@ -228,7 +238,7 @@ describe('findTargetProjectWithImport', () => { type: 'lib', data: { root: 'libs/proj1234-child', - files: ctx.fileMap['proj1234-child'], + files: [], }, }, }; @@ -319,11 +329,16 @@ describe('findTargetProjectWithImport', () => { '../proj/../index.ts', 'libs/proj/src/index.ts' ); + const res5 = targetProjectLocator.findProjectWithImport( + '../../../index.ts', + 'libs/proj/src/index.ts' + ); expect(res1).toEqual('proj'); expect(res2).toEqual('proj'); expect(res3).toEqual('proj2'); expect(res4).toEqual('proj'); + expect(res5).toEqual('rootProj'); }); it('should be able to resolve a module by using tsConfig paths', () => { @@ -512,10 +527,6 @@ describe('findTargetProjectWithImport (without tsconfig.json)', () => { file: 'libs/proj/index.ts', hash: 'some-hash', }, - { - file: 'libs/proj/class.ts', - hash: 'some-hash', - }, ], proj2: [ { @@ -588,7 +599,7 @@ describe('findTargetProjectWithImport (without tsconfig.json)', () => { type: 'lib', data: { root: 'libs/proj3a', - files: ctx.fileMap.proj3a, + files: [], }, }, proj2: { @@ -596,7 +607,7 @@ describe('findTargetProjectWithImport (without tsconfig.json)', () => { type: 'lib', data: { root: 'libs/proj2', - files: ctx.fileMap.proj2, + files: [], }, }, proj: { @@ -604,7 +615,7 @@ describe('findTargetProjectWithImport (without tsconfig.json)', () => { type: 'lib', data: { root: 'libs/proj', - files: ctx.fileMap.proj, + files: [], }, }, proj1234: { @@ -612,7 +623,7 @@ describe('findTargetProjectWithImport (without tsconfig.json)', () => { type: 'lib', data: { root: 'libs/proj1234', - files: ctx.fileMap.proj1234, + files: [], }, }, proj123: { @@ -620,7 +631,7 @@ describe('findTargetProjectWithImport (without tsconfig.json)', () => { type: 'lib', data: { root: 'libs/proj123', - files: ctx.fileMap.proj123, + files: [], }, }, proj4ab: { @@ -628,7 +639,7 @@ describe('findTargetProjectWithImport (without tsconfig.json)', () => { type: 'lib', data: { root: 'libs/proj4ab', - files: ctx.fileMap.proj4ab, + files: [], }, }, proj5: { @@ -636,7 +647,7 @@ describe('findTargetProjectWithImport (without tsconfig.json)', () => { type: 'lib', data: { root: 'libs/proj5', - files: ctx.fileMap.proj5, + files: [], }, }, proj6: { @@ -644,7 +655,7 @@ describe('findTargetProjectWithImport (without tsconfig.json)', () => { type: 'lib', data: { root: 'libs/proj6', - files: ctx.fileMap.proj6, + files: [], }, }, proj7: { @@ -652,7 +663,7 @@ describe('findTargetProjectWithImport (without tsconfig.json)', () => { type: 'lib', data: { root: 'libs/proj7', - files: ctx.fileMap.proj7, + files: [], }, }, 'proj1234-child': { @@ -660,7 +671,7 @@ describe('findTargetProjectWithImport (without tsconfig.json)', () => { type: 'lib', data: { root: 'libs/proj1234-child', - files: ctx.fileMap['proj1234-child'], + files: [], }, }, }; diff --git a/packages/nx/src/utils/target-project-locator.ts b/packages/nx/src/utils/target-project-locator.ts index 784aeeabb99e1..42b8dffcdff71 100644 --- a/packages/nx/src/utils/target-project-locator.ts +++ b/packages/nx/src/utils/target-project-locator.ts @@ -6,9 +6,13 @@ import { ProjectGraphExternalNode, ProjectGraphProjectNode, } from '../config/project-graph'; +import { + createProjectRootMappings, + findProjectForPath, +} from '../project-graph/utils/find-project-for-path'; export class TargetProjectLocator { - private allProjectsFiles = createProjectFileMappings(this.nodes); + private projectRootMappings = createProjectRootMappings(this.nodes); private npmProjects = filterRootExternalDependencies(this.externalNodes); private tsConfig = this.getRootTsConfig(); private paths = this.tsConfig.config?.compilerOptions?.paths; @@ -145,19 +149,10 @@ export class TargetProjectLocator { const normalizedResolvedModule = resolvedModule.startsWith('./') ? resolvedModule.substring(2) : resolvedModule; - - // for wildcard paths, we need to find file that starts with resolvedModule - if (normalizedResolvedModule.endsWith('*')) { - const matchingFile = Object.keys(this.allProjectsFiles).find((f) => - f.startsWith(normalizedResolvedModule.slice(0, -1)) - ); - return matchingFile && this.allProjectsFiles[matchingFile]; - } - - return ( - this.allProjectsFiles[normalizedResolvedModule] || - this.allProjectsFiles[`${normalizedResolvedModule}/index`] + const importedProject = this.findMatchingProjectFiles( + normalizedResolvedModule ); + return importedProject ? importedProject.name : void 0; } private getAbsolutePath(path: string) { @@ -183,8 +178,8 @@ export class TargetProjectLocator { } private findMatchingProjectFiles(file: string) { - const project = this.allProjectsFiles[file]; - return project && this.nodes[project]; + const project = findProjectForPath(file, this.projectRootMappings); + return this.nodes[project]; } } @@ -206,78 +201,3 @@ function filterRootExternalDependencies( } return nodes; } - -/** - * @deprecated This function will be removed in v16. Use {@link createProjectFileMappings} instead. - * - * Mapps the project root paths to the project name - * @param nodes - * @returns - */ -export function createProjectRootMappings( - nodes: Record -): Map { - const projectRootMappings = new Map(); - for (const projectName of Object.keys(nodes)) { - const root = nodes[projectName].data.root; - projectRootMappings.set( - root && root.endsWith('/') ? root.substring(0, root.length - 1) : root, - projectName - ); - } - return projectRootMappings; -} - -/** - * Strips the file extension from the file path - * @param file - * @returns - */ -export function removeExt(file: string): string { - return file.replace(/(? { 'apps/myapp/src/main': 'myapp', 'apps/myapp/src/main.ts': 'myapp' } - * @param projectGraph - * @returns - */ -export function createProjectFileMappings( - nodes: Record -): Record { - const result: Record = {}; - Object.entries(nodes).forEach(([name, node]) => { - node.data.files.forEach(({ file }) => { - const fileName = removeExt(file); - result[fileName] = name; - result[file] = name; - }); - }); - - return result; -} - -/** - * @deprecated This function will be removed in v16. Use {@link createProjectFileMappings} instead. - * - * Locates a project in projectRootMap based on a file within it - * @param filePath path that is inside of projectName - * @param projectRootMap Map - */ -export function findMatchingProjectForPath( - filePath: string, - projectRootMap: Map -): string | null { - for ( - let currentPath = filePath; - currentPath != dirname(currentPath); - currentPath = dirname(currentPath) - ) { - const p = projectRootMap.get(currentPath); - if (p) { - return p; - } - } - return null; -} diff --git a/packages/nx/src/utils/typescript.ts b/packages/nx/src/utils/typescript.ts index a6e4b98537f53..9a49c1cf47038 100644 --- a/packages/nx/src/utils/typescript.ts +++ b/packages/nx/src/utils/typescript.ts @@ -2,6 +2,7 @@ import { workspaceRoot } from './workspace-root'; import { existsSync } from 'fs'; import { dirname, join } from 'path'; import type * as ts from 'typescript'; +import type { Node, SyntaxKind } from 'typescript'; const normalizedAppRoot = workspaceRoot.replace(/\\/g, '/'); @@ -106,15 +107,15 @@ export function getRootTsConfigPath(): string | null { } export function findNodes( - node: ts.Node, - kind: ts.SyntaxKind | ts.SyntaxKind[], + node: Node, + kind: SyntaxKind | SyntaxKind[], max = Infinity -): ts.Node[] { +): Node[] { if (!node || max == 0) { return []; } - const arr: ts.Node[] = []; + const arr: Node[] = []; const hasMatch = Array.isArray(kind) ? kind.includes(node.kind) : node.kind === kind; diff --git a/packages/storybook/src/executors/utils.ts b/packages/storybook/src/executors/utils.ts index 7bff48af67d38..480bbf77c6405 100644 --- a/packages/storybook/src/executors/utils.ts +++ b/packages/storybook/src/executors/utils.ts @@ -58,9 +58,9 @@ function reactWebpack5Check(options: CommonNxStorybookConfig) { It looks like you use Webpack 5 but your Storybook setup is not configured to leverage that and thus falls back to Webpack 4. Make sure you upgrade your Storybook config to use Webpack 5. - + - https://gist.github.com/shilman/8856ea1786dcd247139b47b270912324#upgrade - + `); } } diff --git a/packages/workspace/index.ts b/packages/workspace/index.ts index 4120e588e51ac..1ba4b96075eca 100644 --- a/packages/workspace/index.ts +++ b/packages/workspace/index.ts @@ -21,7 +21,6 @@ export { readPackageJson, } from 'nx/src/project-graph/file-utils'; export { ProjectGraphCache } from 'nx/src/project-graph/nx-deps-cache'; -export { findNodes } from 'nx/src/utils/typescript'; export { readJsonInTree, updateJsonInTree, @@ -35,6 +34,7 @@ export { getProjectConfig, addParameterToConstructor, createOrUpdate, + findNodes, // TODO(v16): remove this updatePackageJsonDependencies, readWorkspace, renameSyncInTree, diff --git a/packages/workspace/src/utilities/generate-globs.ts b/packages/workspace/src/utilities/generate-globs.ts index 775bbf98fb9d6..5892014c1bee5 100644 --- a/packages/workspace/src/utilities/generate-globs.ts +++ b/packages/workspace/src/utilities/generate-globs.ts @@ -2,12 +2,13 @@ import { joinPathFragments, logger } from '@nrwl/devkit'; import { workspaceRoot } from 'nx/src/utils/workspace-root'; import { dirname, join, relative, resolve } from 'path'; import { readCachedProjectGraph } from 'nx/src/project-graph/project-graph'; -import { - getProjectNameFromDirPath, - getSourceDirOfDependentProjects, -} from 'nx/src/utils/project-graph-utils'; +import { getSourceDirOfDependentProjects } from 'nx/src/utils/project-graph-utils'; import { existsSync, lstatSync, readdirSync, readFileSync } from 'fs'; import ignore, { Ignore } from 'ignore'; +import { + createProjectRootMappings, + findProjectForPath, +} from 'nx/src/project-graph/utils/find-project-for-path'; function configureIgnore() { let ig: Ignore; @@ -31,14 +32,21 @@ export function createGlobPatternsForDependencies( let ig = configureIgnore(); const filenameRelativeToWorkspaceRoot = relative(workspaceRoot, dirPath); const projectGraph = readCachedProjectGraph(); + const projectRootMappings = createProjectRootMappings(projectGraph.nodes); // find the project let projectName; try { - projectName = getProjectNameFromDirPath( + projectName = findProjectForPath( filenameRelativeToWorkspaceRoot, - projectGraph + projectRootMappings ); + + if (!projectName) { + throw new Error( + `Could not find any project containing the file "${filenameRelativeToWorkspaceRoot}" among it's project files` + ); + } } catch (e) { throw new Error( `createGlobPatternsForDependencies: Error when trying to determine main project.\n${e?.message}` diff --git a/packages/workspace/src/utilities/typescript.ts b/packages/workspace/src/utilities/typescript.ts index 988450dc88db1..98a6cbfffa3e0 100644 --- a/packages/workspace/src/utilities/typescript.ts +++ b/packages/workspace/src/utilities/typescript.ts @@ -5,6 +5,7 @@ import { dirname, join } from 'path'; import type * as ts from 'typescript'; export { compileTypeScript } from './typescript/compilation'; export type { TypeScriptCompilationOptions } from './typescript/compilation'; +export { findNodes } from './typescript/find-nodes'; // TODO(v16): remove this export { getSourceNodes } from './typescript/get-source-nodes'; const normalizedAppRoot = workspaceRoot.replace(/\\/g, '/'); diff --git a/packages/workspace/src/utilities/typescript/find-nodes.ts b/packages/workspace/src/utilities/typescript/find-nodes.ts new file mode 100644 index 0000000000000..32169f92dbcec --- /dev/null +++ b/packages/workspace/src/utilities/typescript/find-nodes.ts @@ -0,0 +1,16 @@ +import { findNodes as _findNodes } from 'nx/src/utils/typescript'; +import type { Node, SyntaxKind } from 'typescript'; + +// TODO(v16): This should be removed. + +/** + * @deprecated This function is deprecated and no longer supported. + */ +export function findNodes( + node: Node, + kind: SyntaxKind | SyntaxKind[], + max = Infinity +) { + console.warn('"findNodes" is deprecated and no longer supported.'); + return _findNodes(node, kind, max); +} diff --git a/packages/workspace/src/utils/ast-utils.ts b/packages/workspace/src/utils/ast-utils.ts index 59c774e4ecf25..161094dfd52da 100644 --- a/packages/workspace/src/utils/ast-utils.ts +++ b/packages/workspace/src/utils/ast-utils.ts @@ -18,10 +18,15 @@ import { Tree, } from '@angular-devkit/schematics'; import * as ts from 'typescript'; -import { parseJson, serializeJson, FileData } from '@nrwl/devkit'; +import { + parseJson, + ProjectConfiguration, + serializeJson, + FileData, +} from '@nrwl/devkit'; import { getWorkspacePath } from './cli-config-utils'; import { extname, join, normalize, Path } from '@angular-devkit/core'; -import type { NxJsonConfiguration } from '@nrwl/devkit'; +import type { NxJsonConfiguration, ProjectsConfigurations } from '@nrwl/devkit'; import { addInstallTask } from './rules/add-install-task'; import { findNodes } from 'nx/src/utils/typescript'; import { getSourceNodes } from '../utilities/typescript/get-source-nodes'; @@ -66,6 +71,7 @@ export function sortObjectByKeys(obj: unknown) { }, {}); } +export { findNodes } from '../utilities/typescript/find-nodes'; // TODO(v16): Remove this export { getSourceNodes } from '../utilities/typescript/get-source-nodes'; export interface Change {