UNPKG

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