/
project-graph-utils.ts
151 lines (133 loc) · 4.15 KB
/
project-graph-utils.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import { buildTargetFromScript, PackageJson } from './package-json';
import { join, relative } 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';
export function projectHasTarget(
project: ProjectGraphProjectNode,
target: string
) {
return !!(
project.data &&
project.data.targets &&
project.data.targets[target]
);
}
export function projectHasTargetAndConfiguration(
project: ProjectGraphProjectNode,
target: string,
configuration: string
) {
return (
projectHasTarget(project, target) &&
project.data.targets[target].configurations &&
project.data.targets[target].configurations[configuration]
);
}
export function mergeNpmScriptsWithTargets(
projectRoot: string,
targets
): Record<string, TargetConfiguration> {
try {
const { scripts, nx }: PackageJson = readJsonFile(
join(projectRoot, 'package.json')
);
const res: Record<string, TargetConfiguration> = {};
// handle no scripts
Object.keys(scripts || {}).forEach((script) => {
res[script] = buildTargetFromScript(script, nx);
});
return { ...res, ...(targets || {}) };
} catch (e) {
return targets;
}
}
export function getSourceDirOfDependentProjects(
projectName: string,
projectGraph = readCachedProjectGraph()
): string[] {
if (!projectGraph.nodes[projectName]) {
throw new Error(
`Couldn't find project "${projectName}" in this Nx workspace`
);
}
const nodeNames = findAllProjectNodeDependencies(projectName, projectGraph);
return nodeNames.map(
(nodeName) => projectGraph.nodes[nodeName].data.sourceRoot
);
}
/**
* 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
* @param {string} parentNodeName
* @param {ProjectGraph} projectGraph
* @returns {string[]}
*/
function findAllProjectNodeDependencies(
parentNodeName: string,
projectGraph = readCachedProjectGraph()
): string[] {
const dependencyNodeNames = new Set<string>();
collectDependentProjectNodesNames(
projectGraph as ProjectGraph,
dependencyNodeNames,
parentNodeName
);
return Array.from(dependencyNodeNames);
}
// Recursively get all the dependencies of the node
function collectDependentProjectNodesNames(
nxDeps: ProjectGraph,
dependencyNodeNames: Set<string>,
parentNodeName: string
) {
const dependencies = nxDeps.dependencies[parentNodeName];
if (!dependencies) {
// no dependencies for the given node, so silently return,
// as we probably wouldn't want to throw here
return;
}
for (const dependency of dependencies) {
const dependencyName = dependency.target;
// we're only intersted in project dependencies, not npm
if (dependencyName.startsWith('npm:')) {
continue;
}
dependencyNodeNames.add(dependencyName);
// Get the dependencies of the dependencies
collectDependentProjectNodesNames(
nxDeps,
dependencyNodeNames,
dependencyName
);
}
}