UNPKG

13.1 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.updateBuildableProjectPackageJsonDependencies = exports.updatePaths = exports.findMissingBuildDependencies = exports.checkDependentProjectsHaveBeenBuilt = exports.createTmpTsConfig = exports.computeCompilerOptionsPaths = exports.calculateProjectDependencies = void 0;
4const path_1 = require("path");
5const fileutils_1 = require("./fileutils");
6const devkit_1 = require("@nrwl/devkit");
7const ts = require("typescript");
8const fs_1 = require("fs");
9const output_1 = require("./output");
10const operators_1 = require("nx/src/project-graph/operators");
11function isBuildable(target, node) {
12 return (node.data.targets &&
13 node.data.targets[target] &&
14 node.data.targets[target].executor !== '');
15}
16function calculateProjectDependencies(projGraph, root, projectName, targetName, configurationName, shallow) {
17 const target = projGraph.nodes[projectName];
18 // gather the library dependencies
19 const nonBuildableDependencies = [];
20 const topLevelDependencies = [];
21 const collectedDeps = collectDependencies(projectName, projGraph, [], shallow);
22 const missing = collectedDeps.reduce((missing, { name: dep }) => {
23 const depNode = projGraph.nodes[dep] || projGraph.externalNodes[dep];
24 if (!depNode) {
25 missing = missing || [];
26 missing.push(dep);
27 }
28 return missing;
29 }, null);
30 if (missing) {
31 throw new Error(`Unable to find ${missing.join(', ')} in project graph.`);
32 }
33 const dependencies = collectedDeps
34 .map(({ name: dep, isTopLevel }) => {
35 let project = null;
36 const depNode = projGraph.nodes[dep] || projGraph.externalNodes[dep];
37 if (depNode.type === 'lib') {
38 if (isBuildable(targetName, depNode)) {
39 const libPackageJsonPath = (0, path_1.join)(root, depNode.data.root, 'package.json');
40 project = {
41 name: (0, fileutils_1.fileExists)(libPackageJsonPath)
42 ? (0, devkit_1.readJsonFile)(libPackageJsonPath).name // i.e. @workspace/mylib
43 : dep,
44 outputs: (0, devkit_1.getOutputsForTargetAndConfiguration)({
45 overrides: {},
46 target: {
47 project: projectName,
48 target: targetName,
49 configuration: configurationName,
50 },
51 }, depNode),
52 node: depNode,
53 };
54 }
55 else {
56 nonBuildableDependencies.push(dep);
57 }
58 }
59 else if (depNode.type === 'npm') {
60 project = {
61 name: depNode.data.packageName,
62 outputs: [],
63 node: depNode,
64 };
65 }
66 if (project && isTopLevel) {
67 topLevelDependencies.push(project);
68 }
69 return project;
70 })
71 .filter((x) => !!x);
72 return {
73 target,
74 dependencies,
75 nonBuildableDependencies,
76 topLevelDependencies,
77 };
78}
79exports.calculateProjectDependencies = calculateProjectDependencies;
80function collectDependencies(project, projGraph, acc, shallow, areTopLevelDeps = true) {
81 (projGraph.dependencies[project] || []).forEach((dependency) => {
82 if (!acc.some((dep) => dep.name === dependency.target)) {
83 // Temporary skip this. Currently the set of external nodes is built from package.json, not lock file.
84 // As a result, some nodes might be missing. This should not cause any issues, we can just skip them.
85 if (dependency.target.startsWith('npm:') &&
86 !projGraph.externalNodes[dependency.target])
87 return;
88 acc.push({ name: dependency.target, isTopLevel: areTopLevelDeps });
89 const isInternalTarget = projGraph.nodes[dependency.target];
90 if (!shallow && isInternalTarget) {
91 collectDependencies(dependency.target, projGraph, acc, shallow, false);
92 }
93 }
94 });
95 return acc;
96}
97function readTsConfigWithRemappedPaths(tsConfig, generatedTsConfigPath, dependencies) {
98 const generatedTsConfig = { compilerOptions: {} };
99 generatedTsConfig.extends = (0, path_1.relative)((0, path_1.dirname)(generatedTsConfigPath), tsConfig);
100 generatedTsConfig.compilerOptions.paths = computeCompilerOptionsPaths(tsConfig, dependencies);
101 if (process.env.NX_VERBOSE_LOGGING_PATH_MAPPINGS === 'true') {
102 output_1.output.log({
103 title: 'TypeScript path mappings have been rewritten.',
104 });
105 console.log(JSON.stringify(generatedTsConfig.compilerOptions.paths, null, 2));
106 }
107 return generatedTsConfig;
108}
109/**
110 * Util function to create tsconfig compilerOptions object with support for workspace libs paths.
111 *
112 * @param tsConfig String of config path or object parsed via ts.parseJsonConfigFileContent.
113 * @param dependencies Dependencies calculated by Nx.
114 */
115function computeCompilerOptionsPaths(tsConfig, dependencies) {
116 const paths = readPaths(tsConfig) || {};
117 updatePaths(dependencies, paths);
118 return paths;
119}
120exports.computeCompilerOptionsPaths = computeCompilerOptionsPaths;
121function readPaths(tsConfig) {
122 var _a;
123 try {
124 let config;
125 if (typeof tsConfig === 'string') {
126 const configFile = ts.readConfigFile(tsConfig, ts.sys.readFile);
127 config = ts.parseJsonConfigFileContent(configFile.config, ts.sys, (0, path_1.dirname)(tsConfig));
128 }
129 else {
130 config = tsConfig;
131 }
132 if ((_a = config.options) === null || _a === void 0 ? void 0 : _a.paths) {
133 return config.options.paths;
134 }
135 else {
136 return null;
137 }
138 }
139 catch (e) {
140 return null;
141 }
142}
143function createTmpTsConfig(tsconfigPath, workspaceRoot, projectRoot, dependencies) {
144 const tmpTsConfigPath = (0, path_1.join)(workspaceRoot, 'tmp', projectRoot, 'tsconfig.generated.json');
145 const parsedTSConfig = readTsConfigWithRemappedPaths(tsconfigPath, tmpTsConfigPath, dependencies);
146 process.on('exit', () => cleanupTmpTsConfigFile(tmpTsConfigPath));
147 (0, devkit_1.writeJsonFile)(tmpTsConfigPath, parsedTSConfig);
148 return (0, path_1.join)(tmpTsConfigPath);
149}
150exports.createTmpTsConfig = createTmpTsConfig;
151function cleanupTmpTsConfigFile(tmpTsConfigPath) {
152 try {
153 if (tmpTsConfigPath) {
154 (0, fs_1.unlinkSync)(tmpTsConfigPath);
155 }
156 }
157 catch (e) { }
158}
159function checkDependentProjectsHaveBeenBuilt(root, projectName, targetName, projectDependencies) {
160 const missing = findMissingBuildDependencies(root, projectName, targetName, projectDependencies);
161 if (missing.length > 0) {
162 console.error((0, devkit_1.stripIndents) `
163 It looks like all of ${projectName}'s dependencies have not been built yet:
164 ${missing.map((x) => ` - ${x.node.name}`).join('\n')}
165
166 You might be missing a "targetDefaults" configuration in your root nx.json (https://nx.dev/reference/project-configuration#target-defaults),
167 or "dependsOn" configured in ${projectName}'s project.json (https://nx.dev/reference/project-configuration#dependson)
168 `);
169 return false;
170 }
171 else {
172 return true;
173 }
174}
175exports.checkDependentProjectsHaveBeenBuilt = checkDependentProjectsHaveBeenBuilt;
176function findMissingBuildDependencies(root, projectName, targetName, projectDependencies) {
177 const depLibsToBuildFirst = [];
178 // verify whether all dependent libraries have been built
179 projectDependencies.forEach((dep) => {
180 if (dep.node.type !== 'lib') {
181 return;
182 }
183 const paths = dep.outputs.map((p) => (0, path_1.join)(root, p));
184 if (!paths.some(fileutils_1.directoryExists)) {
185 depLibsToBuildFirst.push(dep);
186 }
187 });
188 return depLibsToBuildFirst;
189}
190exports.findMissingBuildDependencies = findMissingBuildDependencies;
191function updatePaths(dependencies, paths) {
192 const pathsKeys = Object.keys(paths);
193 // For each registered dependency
194 dependencies.forEach((dep) => {
195 var _a;
196 // If there are outputs
197 if (dep.outputs && dep.outputs.length > 0) {
198 // Directly map the dependency name to the output paths (dist/packages/..., etc.)
199 paths[dep.name] = dep.outputs;
200 // check for secondary entrypoints
201 // For each registered path
202 for (const path of pathsKeys) {
203 const nestedName = `${dep.name}/`;
204 // If the path points to the current dependency and is nested (/)
205 if (path.startsWith(nestedName)) {
206 const nestedPart = path.slice(nestedName.length);
207 // Bind secondary endpoints for ng-packagr projects
208 let mappedPaths = dep.outputs.map((output) => `${output}/${nestedPart}`);
209 // Get the dependency's package name
210 const { root } = ((_a = dep.node) === null || _a === void 0 ? void 0 : _a.data) || {};
211 if (root) {
212 // Update nested mappings to point to the dependency's output paths
213 mappedPaths = mappedPaths.concat(paths[path].flatMap((path) => dep.outputs.map((output) => path.replace(root, output))));
214 }
215 paths[path] = mappedPaths;
216 }
217 }
218 }
219 });
220}
221exports.updatePaths = updatePaths;
222/**
223 * Updates the peerDependencies section in the `dist/lib/xyz/package.json` with
224 * the proper dependency and version
225 */
226function updateBuildableProjectPackageJsonDependencies(root, projectName, targetName, configurationName, node, dependencies, typeOfDependency = 'dependencies') {
227 const outputs = (0, devkit_1.getOutputsForTargetAndConfiguration)({
228 overrides: {},
229 target: {
230 project: projectName,
231 target: targetName,
232 configuration: configurationName,
233 },
234 }, node);
235 const packageJsonPath = `${outputs[0]}/package.json`;
236 let packageJson;
237 let workspacePackageJson;
238 try {
239 packageJson = (0, devkit_1.readJsonFile)(packageJsonPath);
240 workspacePackageJson = (0, devkit_1.readJsonFile)(`${root}/package.json`);
241 }
242 catch (e) {
243 // cannot find or invalid package.json
244 return;
245 }
246 packageJson.dependencies = packageJson.dependencies || {};
247 packageJson.peerDependencies = packageJson.peerDependencies || {};
248 let updatePackageJson = false;
249 dependencies.forEach((entry) => {
250 var _a;
251 const packageName = (0, operators_1.isNpmProject)(entry.node)
252 ? entry.node.data.packageName
253 : entry.name;
254 if (!hasDependency(packageJson, 'dependencies', packageName) &&
255 !hasDependency(packageJson, 'devDependencies', packageName) &&
256 !hasDependency(packageJson, 'peerDependencies', packageName)) {
257 try {
258 let depVersion;
259 if (entry.node.type === 'lib') {
260 const outputs = (0, devkit_1.getOutputsForTargetAndConfiguration)({
261 overrides: {},
262 target: {
263 project: projectName,
264 target: targetName,
265 configuration: configurationName,
266 },
267 }, entry.node);
268 const depPackageJsonPath = (0, path_1.join)(root, outputs[0], 'package.json');
269 depVersion = (0, devkit_1.readJsonFile)(depPackageJsonPath).version;
270 packageJson[typeOfDependency][packageName] = depVersion;
271 }
272 else if ((0, operators_1.isNpmProject)(entry.node)) {
273 // If an npm dep is part of the workspace devDependencies, do not include it the library
274 if (!!((_a = workspacePackageJson.devDependencies) === null || _a === void 0 ? void 0 : _a[entry.node.data.packageName])) {
275 return;
276 }
277 depVersion = entry.node.data.version;
278 packageJson[typeOfDependency][entry.node.data.packageName] =
279 depVersion;
280 }
281 updatePackageJson = true;
282 }
283 catch (e) {
284 // skip if cannot find package.json
285 }
286 }
287 });
288 if (updatePackageJson) {
289 (0, devkit_1.writeJsonFile)(packageJsonPath, packageJson);
290 }
291}
292exports.updateBuildableProjectPackageJsonDependencies = updateBuildableProjectPackageJsonDependencies;
293// verify whether the package.json already specifies the dep
294function hasDependency(outputJson, depConfigName, packageName) {
295 if (outputJson[depConfigName]) {
296 return outputJson[depConfigName][packageName];
297 }
298 else {
299 return false;
300 }
301}
302//# sourceMappingURL=buildable-libs-utils.js.map
\No newline at end of file