feat(core): use createProjectFileMappings in TargetProjectLocator (#13268)
This commit is contained in:
parent
41c320cb07
commit
bd4f4a23c2
@ -280,7 +280,7 @@ function withSchemaDefaults(options: any): BrowserBuilderSchema {
|
||||
*/
|
||||
function getTempStylesForTailwind(ctExecutorContext: ExecutorContext) {
|
||||
const mappedGraphFiles = createProjectFileMappings(
|
||||
ctExecutorContext.projectGraph
|
||||
ctExecutorContext.projectGraph.nodes
|
||||
);
|
||||
const ctProjectConfig = ctExecutorContext.projectGraph.nodes[
|
||||
ctExecutorContext.projectName
|
||||
|
||||
@ -90,7 +90,7 @@ export function getProjectConfigByPath(
|
||||
: configFileFromWorkspaceRoot
|
||||
);
|
||||
|
||||
const mappedGraphFiles = createProjectFileMappings(graph);
|
||||
const mappedGraphFiles = createProjectFileMappings(graph.nodes);
|
||||
const componentTestingProjectName =
|
||||
mappedGraphFiles[normalizedPathFromWorkspaceRoot];
|
||||
if (
|
||||
|
||||
@ -1015,7 +1015,7 @@ Violation detected in:
|
||||
tags: [],
|
||||
implicitDependencies: [],
|
||||
architect: {},
|
||||
files: [createFile(`libs/other/index.ts`)],
|
||||
files: [createFile(`libs/other/src/index.ts`)],
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -1033,6 +1033,7 @@ 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'
|
||||
);
|
||||
@ -1144,7 +1145,10 @@ Violation detected in:
|
||||
tags: [],
|
||||
implicitDependencies: [],
|
||||
architect: {},
|
||||
files: [createFile(`libs/mylib/src/main.ts`)],
|
||||
files: [
|
||||
createFile(`libs/mylib/src/main.ts`),
|
||||
createFile(`libs/mylib/src/index.ts`),
|
||||
],
|
||||
},
|
||||
},
|
||||
anotherlibName: {
|
||||
@ -1268,7 +1272,10 @@ Violation detected in:
|
||||
tags: [],
|
||||
implicitDependencies: [],
|
||||
architect: {},
|
||||
files: [createFile(`libs/mylib/src/main.ts`, ['anotherlibName'])],
|
||||
files: [
|
||||
createFile(`libs/mylib/src/main.ts`, ['anotherlibName']),
|
||||
createFile(`libs/mylib/src/index.ts`),
|
||||
],
|
||||
},
|
||||
},
|
||||
anotherlibName: {
|
||||
@ -1363,6 +1370,7 @@ Circular file chain:
|
||||
architect: {},
|
||||
files: [
|
||||
createFile(`libs/badcirclelib/src/main.ts`, ['anotherlibName']),
|
||||
createFile(`libs/badcirclelib/src/index.ts`),
|
||||
],
|
||||
},
|
||||
},
|
||||
@ -1886,8 +1894,9 @@ function runRule(
|
||||
): TSESLint.Linter.LintMessage[] {
|
||||
(global as any).projectPath = `${process.cwd()}/proj`;
|
||||
(global as any).projectGraph = projectGraph;
|
||||
(global as any).projectGraphFileMappings =
|
||||
createProjectFileMappings(projectGraph);
|
||||
(global as any).projectGraphFileMappings = createProjectFileMappings(
|
||||
projectGraph.nodes
|
||||
);
|
||||
(global as any).targetProjectLocator = new TargetProjectLocator(
|
||||
projectGraph.nodes,
|
||||
projectGraph.externalNodes
|
||||
|
||||
@ -23,7 +23,7 @@ export function ensureGlobalProjectGraph(ruleName: string) {
|
||||
try {
|
||||
(global as any).projectGraph = readCachedProjectGraph();
|
||||
(global as any).projectGraphFileMappings = createProjectFileMappings(
|
||||
(global as any).projectGraph
|
||||
(global as any).projectGraph.nodes
|
||||
);
|
||||
} catch {
|
||||
const WARNING_PREFIX = `${chalk.reset.keyword('orange')('warning')}`;
|
||||
|
||||
@ -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' },
|
||||
b: { root: 'libs/b' },
|
||||
c: { root: 'libs/c' },
|
||||
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' }] },
|
||||
};
|
||||
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' },
|
||||
abc: { root: 'libs/a-b-c' },
|
||||
ab: { root: 'libs/a-b' },
|
||||
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' }] },
|
||||
};
|
||||
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' },
|
||||
abc: { root: 'libs/a-b-c' },
|
||||
ab: { root: 'libs/a-b' },
|
||||
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' }] },
|
||||
};
|
||||
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' },
|
||||
ab: { root: 'libs/a/b' },
|
||||
aaaaa: { root: 'libs/a', files: [{ file: 'libs/a/index.ts' }] },
|
||||
ab: { root: 'libs/a/b', files: [{ file: 'libs/a/b/index.ts' }] },
|
||||
};
|
||||
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' },
|
||||
b: { root: 'libs/a/b' },
|
||||
a: { root: 'libs/a', files: [{ file: 'libs/a/index.ts' }] },
|
||||
b: { root: 'libs/a/b', files: [{ file: 'libs/a/b/index.ts' }] },
|
||||
};
|
||||
expect(
|
||||
getTouchedProjects(fileChanges, buildProjectGraphNodes(projects))
|
||||
|
||||
@ -2,24 +2,23 @@ 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 {
|
||||
createProjectRootMappings,
|
||||
findMatchingProjectForPath,
|
||||
} from '../../../utils/target-project-locator';
|
||||
import { createProjectFileMappings } from '../../../utils/target-project-locator';
|
||||
|
||||
export const getTouchedProjects: TouchedProjectLocator = (
|
||||
touchedFiles,
|
||||
projectGraphNodes
|
||||
): string[] => {
|
||||
const projectRootMap = createProjectRootMappings(projectGraphNodes);
|
||||
const allProjectFiles = createProjectFileMappings(projectGraphNodes);
|
||||
const affected = [];
|
||||
|
||||
return touchedFiles.reduce((affected, f) => {
|
||||
const matchingProject = findMatchingProjectForPath(f.file, projectRootMap);
|
||||
touchedFiles.forEach((f) => {
|
||||
const matchingProject = allProjectFiles[f.file];
|
||||
if (matchingProject) {
|
||||
affected.push(matchingProject);
|
||||
}
|
||||
return affected;
|
||||
}, []);
|
||||
});
|
||||
|
||||
return affected;
|
||||
};
|
||||
|
||||
export const getImplicitlyTouchedProjects: TouchedProjectLocator = (
|
||||
|
||||
@ -8,7 +8,6 @@ import { workspaceRoot } from './workspace-root';
|
||||
import { readJsonFile } from '../utils/fileutils';
|
||||
import {
|
||||
PackageJson,
|
||||
readModulePackageJson,
|
||||
readModulePackageJsonWithoutFallbacks,
|
||||
} from './package-json';
|
||||
import { registerTsProject } from './register';
|
||||
|
||||
@ -80,6 +80,10 @@ describe('findTargetProjectWithImport', () => {
|
||||
file: 'libs/proj/index.ts',
|
||||
hash: 'some-hash',
|
||||
},
|
||||
{
|
||||
file: 'libs/proj/class.ts',
|
||||
hash: 'some-hash',
|
||||
},
|
||||
],
|
||||
proj2: [
|
||||
{
|
||||
@ -152,7 +156,7 @@ describe('findTargetProjectWithImport', () => {
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: 'libs/proj3a',
|
||||
files: [],
|
||||
files: ctx.fileMap['proj3a'],
|
||||
},
|
||||
},
|
||||
proj2: {
|
||||
@ -160,7 +164,7 @@ describe('findTargetProjectWithImport', () => {
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: 'libs/proj2',
|
||||
files: [],
|
||||
files: ctx.fileMap['proj2'],
|
||||
},
|
||||
},
|
||||
proj: {
|
||||
@ -168,7 +172,7 @@ describe('findTargetProjectWithImport', () => {
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: 'libs/proj',
|
||||
files: [],
|
||||
files: ctx.fileMap['proj'],
|
||||
},
|
||||
},
|
||||
proj1234: {
|
||||
@ -176,7 +180,7 @@ describe('findTargetProjectWithImport', () => {
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: 'libs/proj1234',
|
||||
files: [],
|
||||
files: ctx.fileMap['proj1234'],
|
||||
},
|
||||
},
|
||||
proj123: {
|
||||
@ -184,7 +188,7 @@ describe('findTargetProjectWithImport', () => {
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: 'libs/proj123',
|
||||
files: [],
|
||||
files: ctx.fileMap['proj123'],
|
||||
},
|
||||
},
|
||||
proj4ab: {
|
||||
@ -192,7 +196,7 @@ describe('findTargetProjectWithImport', () => {
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: 'libs/proj4ab',
|
||||
files: [],
|
||||
files: ctx.fileMap['proj4ab'],
|
||||
},
|
||||
},
|
||||
proj5: {
|
||||
@ -200,7 +204,7 @@ describe('findTargetProjectWithImport', () => {
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: 'libs/proj5',
|
||||
files: [],
|
||||
files: ctx.fileMap['proj5'],
|
||||
},
|
||||
},
|
||||
proj6: {
|
||||
@ -208,7 +212,7 @@ describe('findTargetProjectWithImport', () => {
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: 'libs/proj6',
|
||||
files: [],
|
||||
files: ctx.fileMap['proj6'],
|
||||
},
|
||||
},
|
||||
proj7: {
|
||||
@ -216,7 +220,7 @@ describe('findTargetProjectWithImport', () => {
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: 'libs/proj7',
|
||||
files: [],
|
||||
files: ctx.fileMap['proj7'],
|
||||
},
|
||||
},
|
||||
'proj1234-child': {
|
||||
@ -224,7 +228,7 @@ describe('findTargetProjectWithImport', () => {
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: 'libs/proj1234-child',
|
||||
files: [],
|
||||
files: ctx.fileMap['proj1234-child'],
|
||||
},
|
||||
},
|
||||
};
|
||||
@ -508,6 +512,10 @@ describe('findTargetProjectWithImport (without tsconfig.json)', () => {
|
||||
file: 'libs/proj/index.ts',
|
||||
hash: 'some-hash',
|
||||
},
|
||||
{
|
||||
file: 'libs/proj/class.ts',
|
||||
hash: 'some-hash',
|
||||
},
|
||||
],
|
||||
proj2: [
|
||||
{
|
||||
@ -580,7 +588,7 @@ describe('findTargetProjectWithImport (without tsconfig.json)', () => {
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: 'libs/proj3a',
|
||||
files: [],
|
||||
files: ctx.fileMap.proj3a,
|
||||
},
|
||||
},
|
||||
proj2: {
|
||||
@ -588,7 +596,7 @@ describe('findTargetProjectWithImport (without tsconfig.json)', () => {
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: 'libs/proj2',
|
||||
files: [],
|
||||
files: ctx.fileMap.proj2,
|
||||
},
|
||||
},
|
||||
proj: {
|
||||
@ -596,7 +604,7 @@ describe('findTargetProjectWithImport (without tsconfig.json)', () => {
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: 'libs/proj',
|
||||
files: [],
|
||||
files: ctx.fileMap.proj,
|
||||
},
|
||||
},
|
||||
proj1234: {
|
||||
@ -604,7 +612,7 @@ describe('findTargetProjectWithImport (without tsconfig.json)', () => {
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: 'libs/proj1234',
|
||||
files: [],
|
||||
files: ctx.fileMap.proj1234,
|
||||
},
|
||||
},
|
||||
proj123: {
|
||||
@ -612,7 +620,7 @@ describe('findTargetProjectWithImport (without tsconfig.json)', () => {
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: 'libs/proj123',
|
||||
files: [],
|
||||
files: ctx.fileMap.proj123,
|
||||
},
|
||||
},
|
||||
proj4ab: {
|
||||
@ -620,7 +628,7 @@ describe('findTargetProjectWithImport (without tsconfig.json)', () => {
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: 'libs/proj4ab',
|
||||
files: [],
|
||||
files: ctx.fileMap.proj4ab,
|
||||
},
|
||||
},
|
||||
proj5: {
|
||||
@ -628,7 +636,7 @@ describe('findTargetProjectWithImport (without tsconfig.json)', () => {
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: 'libs/proj5',
|
||||
files: [],
|
||||
files: ctx.fileMap.proj5,
|
||||
},
|
||||
},
|
||||
proj6: {
|
||||
@ -636,7 +644,7 @@ describe('findTargetProjectWithImport (without tsconfig.json)', () => {
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: 'libs/proj6',
|
||||
files: [],
|
||||
files: ctx.fileMap.proj6,
|
||||
},
|
||||
},
|
||||
proj7: {
|
||||
@ -644,7 +652,7 @@ describe('findTargetProjectWithImport (without tsconfig.json)', () => {
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: 'libs/proj7',
|
||||
files: [],
|
||||
files: ctx.fileMap.proj7,
|
||||
},
|
||||
},
|
||||
'proj1234-child': {
|
||||
@ -652,7 +660,7 @@ describe('findTargetProjectWithImport (without tsconfig.json)', () => {
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: 'libs/proj1234-child',
|
||||
files: [],
|
||||
files: ctx.fileMap['proj1234-child'],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@ -3,13 +3,12 @@ import { isRelativePath, readJsonFile } from './fileutils';
|
||||
import { dirname, join, posix } from 'path';
|
||||
import { workspaceRoot } from './workspace-root';
|
||||
import {
|
||||
ProjectGraph,
|
||||
ProjectGraphExternalNode,
|
||||
ProjectGraphProjectNode,
|
||||
} from '../config/project-graph';
|
||||
|
||||
export class TargetProjectLocator {
|
||||
private projectRootMappings = createProjectRootMappings(this.nodes);
|
||||
private allProjectsFiles = createProjectFileMappings(this.nodes);
|
||||
private npmProjects = filterRootExternalDependencies(this.externalNodes);
|
||||
private tsConfig = this.getRootTsConfig();
|
||||
private paths = this.tsConfig.config?.compilerOptions?.paths;
|
||||
@ -146,10 +145,19 @@ export class TargetProjectLocator {
|
||||
const normalizedResolvedModule = resolvedModule.startsWith('./')
|
||||
? resolvedModule.substring(2)
|
||||
: resolvedModule;
|
||||
const importedProject = this.findMatchingProjectFiles(
|
||||
normalizedResolvedModule
|
||||
|
||||
// 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`]
|
||||
);
|
||||
return importedProject ? importedProject.name : void 0;
|
||||
}
|
||||
|
||||
private getAbsolutePath(path: string) {
|
||||
@ -175,8 +183,8 @@ export class TargetProjectLocator {
|
||||
}
|
||||
|
||||
private findMatchingProjectFiles(file: string) {
|
||||
const project = findMatchingProjectForPath(file, this.projectRootMappings);
|
||||
return this.nodes[project];
|
||||
const project = this.allProjectsFiles[file];
|
||||
return project && this.nodes[project];
|
||||
}
|
||||
}
|
||||
|
||||
@ -200,6 +208,8 @@ function filterRootExternalDependencies(
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This function will be removed in v16. Use {@link createProjectFileMappings} instead.
|
||||
*
|
||||
* Mapps the project root paths to the project name
|
||||
* @param nodes
|
||||
* @returns
|
||||
@ -228,21 +238,20 @@ export function removeExt(file: string): string {
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the project graph to a format that makes it easier to find the project
|
||||
* based on the file path.
|
||||
* Maps the file paths to the project name, both with and without the file extension
|
||||
* apps/myapp/src/main.ts -> { 'apps/myapp/src/main': 'myapp', 'apps/myapp/src/main.ts': 'myapp' }
|
||||
* @param projectGraph
|
||||
* @returns
|
||||
*/
|
||||
export function createProjectFileMappings(
|
||||
projectGraph: ProjectGraph
|
||||
nodes: Record<string, ProjectGraphProjectNode>
|
||||
): Record<string, string> {
|
||||
const result: Record<string, string> = {};
|
||||
Object.entries(
|
||||
projectGraph.nodes as Record<string, ProjectGraphProjectNode>
|
||||
).forEach(([name, node]) => {
|
||||
Object.entries(nodes).forEach(([name, node]) => {
|
||||
node.data.files.forEach(({ file }) => {
|
||||
const fileName = removeExt(file);
|
||||
result[fileName] = name;
|
||||
result[file] = name;
|
||||
});
|
||||
});
|
||||
|
||||
@ -250,6 +259,8 @@ export function createProjectFileMappings(
|
||||
}
|
||||
|
||||
/**
|
||||
* @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<projectRoot, projectName>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user