nx 19.2.0-beta.0 → 19.2.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nx",
3
- "version": "19.2.0-beta.0",
3
+ "version": "19.2.0-beta.2",
4
4
  "private": false,
5
5
  "description": "The core Nx plugin contains the core functionality of Nx like the project graph, nx commands and task orchestration.",
6
6
  "repository": {
@@ -69,7 +69,7 @@
69
69
  "yargs-parser": "21.1.1",
70
70
  "node-machine-id": "1.1.12",
71
71
  "ora": "5.3.0",
72
- "@nrwl/tao": "19.2.0-beta.0"
72
+ "@nrwl/tao": "19.2.0-beta.2"
73
73
  },
74
74
  "peerDependencies": {
75
75
  "@swc-node/register": "^1.8.0",
@@ -84,16 +84,16 @@
84
84
  }
85
85
  },
86
86
  "optionalDependencies": {
87
- "@nx/nx-darwin-x64": "19.2.0-beta.0",
88
- "@nx/nx-darwin-arm64": "19.2.0-beta.0",
89
- "@nx/nx-linux-x64-gnu": "19.2.0-beta.0",
90
- "@nx/nx-linux-x64-musl": "19.2.0-beta.0",
91
- "@nx/nx-win32-x64-msvc": "19.2.0-beta.0",
92
- "@nx/nx-linux-arm64-gnu": "19.2.0-beta.0",
93
- "@nx/nx-linux-arm64-musl": "19.2.0-beta.0",
94
- "@nx/nx-linux-arm-gnueabihf": "19.2.0-beta.0",
95
- "@nx/nx-win32-arm64-msvc": "19.2.0-beta.0",
96
- "@nx/nx-freebsd-x64": "19.2.0-beta.0"
87
+ "@nx/nx-darwin-x64": "19.2.0-beta.2",
88
+ "@nx/nx-darwin-arm64": "19.2.0-beta.2",
89
+ "@nx/nx-linux-x64-gnu": "19.2.0-beta.2",
90
+ "@nx/nx-linux-x64-musl": "19.2.0-beta.2",
91
+ "@nx/nx-win32-x64-msvc": "19.2.0-beta.2",
92
+ "@nx/nx-linux-arm64-gnu": "19.2.0-beta.2",
93
+ "@nx/nx-linux-arm64-musl": "19.2.0-beta.2",
94
+ "@nx/nx-linux-arm-gnueabihf": "19.2.0-beta.2",
95
+ "@nx/nx-win32-arm64-msvc": "19.2.0-beta.2",
96
+ "@nx/nx-freebsd-x64": "19.2.0-beta.2"
97
97
  },
98
98
  "nx-migrations": {
99
99
  "migrations": "./migrations.json",
@@ -23,3 +23,4 @@ export { retrieveProjectConfigurations } from './project-graph/utils/retrieve-wo
23
23
  export { LoadedNxPlugin } from './project-graph/plugins/internal-api';
24
24
  export * from './project-graph/error-types';
25
25
  export { registerTsProject } from './plugins/js/utils/register';
26
+ export { interpolate } from './tasks-runner/utils';
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.registerTsProject = exports.LoadedNxPlugin = exports.retrieveProjectConfigurations = exports.findProjectForPath = exports.createProjectRootMappingsFromProjectConfigurations = exports.hashWithWorkspaceContext = exports.hashObject = exports.splitByColons = exports.readModulePackageJson = exports.stripIndent = exports.sortObjectByKeys = exports.combineOptionsForExecutor = exports.splitTarget = exports.readProjectConfigurationsFromRootMap = exports.mergeTargetConfigurations = exports.retrieveProjectConfigurationsWithAngularProjects = exports.calculateDefaultProjectName = exports.readNxJsonFromDisk = exports.getExecutorInformation = exports.createTempNpmDirectory = void 0;
3
+ exports.interpolate = exports.registerTsProject = exports.LoadedNxPlugin = exports.retrieveProjectConfigurations = exports.findProjectForPath = exports.createProjectRootMappingsFromProjectConfigurations = exports.hashWithWorkspaceContext = exports.hashObject = exports.splitByColons = exports.readModulePackageJson = exports.stripIndent = exports.sortObjectByKeys = exports.combineOptionsForExecutor = exports.splitTarget = exports.readProjectConfigurationsFromRootMap = exports.mergeTargetConfigurations = exports.retrieveProjectConfigurationsWithAngularProjects = exports.calculateDefaultProjectName = exports.readNxJsonFromDisk = exports.getExecutorInformation = exports.createTempNpmDirectory = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  /**
6
6
  * Note to developers: STOP! These exports are available via requireNx in @nx/devkit.
@@ -47,3 +47,5 @@ Object.defineProperty(exports, "LoadedNxPlugin", { enumerable: true, get: functi
47
47
  tslib_1.__exportStar(require("./project-graph/error-types"), exports);
48
48
  var register_1 = require("./plugins/js/utils/register");
49
49
  Object.defineProperty(exports, "registerTsProject", { enumerable: true, get: function () { return register_1.registerTsProject; } });
50
+ var utils_1 = require("./tasks-runner/utils");
51
+ Object.defineProperty(exports, "interpolate", { enumerable: true, get: function () { return utils_1.interpolate; } });
@@ -233,7 +233,7 @@ function getNodes(data, keyMap, isV5) {
233
233
  function getHoistedVersion(hoistedDependencies, packageName, isV5) {
234
234
  let version = (0, package_json_1.getHoistedPackageVersion)(packageName);
235
235
  if (!version) {
236
- const key = Object.keys(hoistedDependencies).find((k) => k.startsWith(isV5 ? `/${packageName}/` : `/${packageName}@`));
236
+ const key = Object.keys(hoistedDependencies).find((k) => k.startsWith(`/${packageName}/`));
237
237
  if (key) {
238
238
  version = parseBaseVersion(getVersion(key.slice(1), packageName), isV5);
239
239
  }
@@ -1,12 +1,25 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.buildExplicitDependencies = void 0;
4
- const explicit_project_dependencies_1 = require("./explicit-project-dependencies");
5
4
  const explicit_package_json_dependencies_1 = require("./explicit-package-json-dependencies");
5
+ const explicit_project_dependencies_1 = require("./explicit-project-dependencies");
6
+ const target_project_locator_1 = require("./target-project-locator");
6
7
  function buildExplicitDependencies(jsPluginConfig, ctx) {
7
8
  if (totalNumberOfFilesToProcess(ctx) === 0)
8
9
  return [];
9
10
  let dependencies = [];
11
+ // TODO: TargetProjectLocator is a public API, so we can't change the shape of it
12
+ // We should eventually let it accept Record<string, ProjectConfiguration> s.t. we
13
+ // don't have to reshape the CreateDependenciesContext here.
14
+ const nodes = Object.fromEntries(Object.entries(ctx.projects).map(([key, config]) => [
15
+ key,
16
+ {
17
+ name: key,
18
+ type: null,
19
+ data: config,
20
+ },
21
+ ]));
22
+ const targetProjectLocator = new target_project_locator_1.TargetProjectLocator(nodes, ctx.externalNodes);
10
23
  if (jsPluginConfig.analyzeSourceFiles === undefined ||
11
24
  jsPluginConfig.analyzeSourceFiles === true) {
12
25
  let tsExists = false;
@@ -16,12 +29,12 @@ function buildExplicitDependencies(jsPluginConfig, ctx) {
16
29
  }
17
30
  catch { }
18
31
  if (tsExists) {
19
- dependencies = dependencies.concat((0, explicit_project_dependencies_1.buildExplicitTypeScriptDependencies)(ctx));
32
+ dependencies = dependencies.concat((0, explicit_project_dependencies_1.buildExplicitTypeScriptDependencies)(ctx, targetProjectLocator));
20
33
  }
21
34
  }
22
35
  if (jsPluginConfig.analyzePackageJson === undefined ||
23
36
  jsPluginConfig.analyzePackageJson === true) {
24
- dependencies = dependencies.concat((0, explicit_package_json_dependencies_1.buildExplicitPackageJsonDependencies)(ctx));
37
+ dependencies = dependencies.concat((0, explicit_package_json_dependencies_1.buildExplicitPackageJsonDependencies)(ctx, targetProjectLocator));
25
38
  }
26
39
  return dependencies;
27
40
  }
@@ -1,3 +1,4 @@
1
1
  import { CreateDependenciesContext } from '../../../../project-graph/plugins';
2
2
  import { RawProjectGraphDependency } from '../../../../project-graph/project-graph-builder';
3
- export declare function buildExplicitPackageJsonDependencies(ctx: CreateDependenciesContext): RawProjectGraphDependency[];
3
+ import { TargetProjectLocator } from './target-project-locator';
4
+ export declare function buildExplicitPackageJsonDependencies(ctx: CreateDependenciesContext, targetProjectLocator: TargetProjectLocator): RawProjectGraphDependency[];
@@ -1,13 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.buildExplicitPackageJsonDependencies = void 0;
4
- const file_utils_1 = require("../../../../project-graph/file-utils");
5
- const path_1 = require("path");
4
+ const node_path_1 = require("node:path");
6
5
  const project_graph_1 = require("../../../../config/project-graph");
7
- const json_1 = require("../../../../utils/json");
8
- const path_2 = require("../../../../utils/path");
6
+ const file_utils_1 = require("../../../../project-graph/file-utils");
9
7
  const project_graph_builder_1 = require("../../../../project-graph/project-graph-builder");
10
- function buildExplicitPackageJsonDependencies(ctx) {
8
+ const json_1 = require("../../../../utils/json");
9
+ const path_1 = require("../../../../utils/path");
10
+ function buildExplicitPackageJsonDependencies(ctx, targetProjectLocator) {
11
11
  const res = [];
12
12
  let packageNameMap = undefined;
13
13
  const nodes = Object.values(ctx.projects);
@@ -16,7 +16,7 @@ function buildExplicitPackageJsonDependencies(ctx) {
16
16
  if (isPackageJsonAtProjectRoot(nodes, f.file)) {
17
17
  // we only create the package name map once and only if a package.json file changes
18
18
  packageNameMap = packageNameMap || createPackageNameMap(ctx.projects);
19
- processPackageJson(source, f.file, ctx, res, packageNameMap);
19
+ processPackageJson(source, f.file, ctx, targetProjectLocator, res, packageNameMap);
20
20
  }
21
21
  });
22
22
  });
@@ -27,7 +27,7 @@ function createPackageNameMap(projects) {
27
27
  const res = {};
28
28
  for (let projectName of Object.keys(projects)) {
29
29
  try {
30
- const packageJson = (0, json_1.parseJson)((0, file_utils_1.defaultFileRead)((0, path_1.join)(projects[projectName].root, 'package.json')));
30
+ const packageJson = (0, json_1.parseJson)((0, file_utils_1.defaultFileRead)((0, node_path_1.join)(projects[projectName].root, 'package.json')));
31
31
  res[packageJson.name ?? projectName] = projectName;
32
32
  }
33
33
  catch (e) { }
@@ -36,13 +36,12 @@ function createPackageNameMap(projects) {
36
36
  }
37
37
  function isPackageJsonAtProjectRoot(nodes, fileName) {
38
38
  return (fileName.endsWith('package.json') &&
39
- nodes.find((projectNode) => (0, path_2.joinPathFragments)(projectNode.root, 'package.json') === fileName));
39
+ nodes.find((projectNode) => (0, path_1.joinPathFragments)(projectNode.root, 'package.json') === fileName));
40
40
  }
41
- function processPackageJson(sourceProject, fileName, ctx, collectedDeps, packageNameMap) {
41
+ function processPackageJson(sourceProject, fileName, ctx, targetProjectLocator, collectedDeps, packageNameMap) {
42
42
  try {
43
43
  const deps = readDeps((0, json_1.parseJson)((0, file_utils_1.defaultFileRead)(fileName)));
44
- // the name matches the import path
45
- deps.forEach((d) => {
44
+ for (const d of Object.keys(deps)) {
46
45
  // package.json refers to another project in the monorepo
47
46
  if (packageNameMap[d]) {
48
47
  const dependency = {
@@ -53,30 +52,44 @@ function processPackageJson(sourceProject, fileName, ctx, collectedDeps, package
53
52
  };
54
53
  (0, project_graph_builder_1.validateDependency)(dependency, ctx);
55
54
  collectedDeps.push(dependency);
55
+ continue;
56
56
  }
57
- else if (ctx.externalNodes[`npm:${d}`]) {
58
- const dependency = {
59
- source: sourceProject,
60
- target: `npm:${d}`,
61
- sourceFile: fileName,
62
- type: project_graph_1.DependencyType.static,
63
- };
64
- (0, project_graph_builder_1.validateDependency)(dependency, ctx);
65
- collectedDeps.push(dependency);
57
+ const externalNodeName = targetProjectLocator.findNpmProjectFromImport(d, fileName);
58
+ if (!externalNodeName) {
59
+ continue;
66
60
  }
67
- });
61
+ const dependency = {
62
+ source: sourceProject,
63
+ target: externalNodeName,
64
+ sourceFile: fileName,
65
+ type: project_graph_1.DependencyType.static,
66
+ };
67
+ (0, project_graph_builder_1.validateDependency)(dependency, ctx);
68
+ collectedDeps.push(dependency);
69
+ }
68
70
  }
69
71
  catch (e) {
70
72
  if (process.env.NX_VERBOSE_LOGGING === 'true') {
71
- console.log(e);
73
+ console.error(e);
72
74
  }
73
75
  }
74
76
  }
75
77
  function readDeps(packageJson) {
76
- return [
77
- ...Object.keys(packageJson?.dependencies ?? {}),
78
- ...Object.keys(packageJson?.devDependencies ?? {}),
79
- ...Object.keys(packageJson?.peerDependencies ?? {}),
80
- ...Object.keys(packageJson?.optionalDependencies ?? {}),
78
+ const deps = {};
79
+ /**
80
+ * We process dependencies in a rough order of increasing importance such that if a dependency is listed in multiple
81
+ * sections, the version listed under the "most important" one wins, with production dependencies being the most important.
82
+ */
83
+ const depType = [
84
+ 'optionalDependencies',
85
+ 'peerDependencies',
86
+ 'devDependencies',
87
+ 'dependencies',
81
88
  ];
89
+ for (const type of depType) {
90
+ for (const [depName, depVersion] of Object.entries(packageJson[type] || {})) {
91
+ deps[depName] = depVersion;
92
+ }
93
+ }
94
+ return deps;
82
95
  }
@@ -1,3 +1,4 @@
1
1
  import { CreateDependenciesContext } from '../../../../project-graph/plugins';
2
2
  import { RawProjectGraphDependency } from '../../../../project-graph/project-graph-builder';
3
- export declare function buildExplicitTypeScriptDependencies(ctx: CreateDependenciesContext): RawProjectGraphDependency[];
3
+ import { TargetProjectLocator } from './target-project-locator';
4
+ export declare function buildExplicitTypeScriptDependencies(ctx: CreateDependenciesContext, targetProjectLocator: TargetProjectLocator): RawProjectGraphDependency[];
@@ -1,18 +1,19 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.buildExplicitTypeScriptDependencies = void 0;
4
- const target_project_locator_1 = require("./target-project-locator");
5
- const project_graph_1 = require("../../../../config/project-graph");
6
4
  const path_1 = require("path");
7
- const workspace_root_1 = require("../../../../utils/workspace-root");
8
- const path_2 = require("../../../../utils/path");
5
+ const project_graph_1 = require("../../../../config/project-graph");
9
6
  const project_graph_builder_1 = require("../../../../project-graph/project-graph-builder");
7
+ const path_2 = require("../../../../utils/path");
8
+ const workspace_root_1 = require("../../../../utils/workspace-root");
10
9
  function isRoot(projects, projectName) {
11
10
  return projects[projectName]?.root === '.';
12
11
  }
13
12
  function convertImportToDependency(importExpr, sourceFile, source, type, targetProjectLocator) {
14
- const target = targetProjectLocator.findProjectWithImport(importExpr, sourceFile) ??
15
- `npm:${importExpr}`;
13
+ const target = targetProjectLocator.findProjectFromImport(importExpr, sourceFile);
14
+ if (!target) {
15
+ return;
16
+ }
16
17
  return {
17
18
  source,
18
19
  target,
@@ -20,19 +21,7 @@ function convertImportToDependency(importExpr, sourceFile, source, type, targetP
20
21
  type,
21
22
  };
22
23
  }
23
- function buildExplicitTypeScriptDependencies(ctx) {
24
- // TODO: TargetProjectLocator is a public API, so we can't change the shape of it
25
- // We should eventually let it accept Record<string, ProjectConfiguration> s.t. we
26
- // don't have to reshape the CreateDependenciesContext here.
27
- const nodes = Object.fromEntries(Object.entries(ctx.projects).map(([key, config]) => [
28
- key,
29
- {
30
- name: key,
31
- type: null,
32
- data: config,
33
- },
34
- ]));
35
- const targetProjectLocator = new target_project_locator_1.TargetProjectLocator(nodes, ctx.externalNodes);
24
+ function buildExplicitTypeScriptDependencies(ctx, targetProjectLocator) {
36
25
  const res = [];
37
26
  const filesToProcess = {};
38
27
  const moduleExtensions = [
@@ -63,6 +52,9 @@ function buildExplicitTypeScriptDependencies(ctx) {
63
52
  const normalizedFilePath = (0, path_2.normalizePath)((0, path_1.relative)(workspace_root_1.workspaceRoot, file));
64
53
  for (const importExpr of staticImportExpressions) {
65
54
  const dependency = convertImportToDependency(importExpr, normalizedFilePath, sourceProject, project_graph_1.DependencyType.static, targetProjectLocator);
55
+ if (!dependency) {
56
+ continue;
57
+ }
66
58
  // TODO: These edges technically should be allowed but we need to figure out how to separate config files out from root
67
59
  if (isRoot(ctx.projects, dependency.source) ||
68
60
  !isRoot(ctx.projects, dependency.target)) {
@@ -71,6 +63,9 @@ function buildExplicitTypeScriptDependencies(ctx) {
71
63
  }
72
64
  for (const importExpr of dynamicImportExpressions) {
73
65
  const dependency = convertImportToDependency(importExpr, normalizedFilePath, sourceProject, project_graph_1.DependencyType.dynamic, targetProjectLocator);
66
+ if (!dependency) {
67
+ continue;
68
+ }
74
69
  // TODO: These edges technically should be allowed but we need to figure out how to separate config files out from root
75
70
  if (isRoot(ctx.projects, dependency.source) ||
76
71
  !isRoot(ctx.projects, dependency.target)) {
@@ -1,21 +1,37 @@
1
1
  import { ProjectGraphExternalNode, ProjectGraphProjectNode } from '../../../../config/project-graph';
2
+ /**
3
+ * The key is a combination of the package name and the workspace relative directory
4
+ * containing the file importing it e.g. `lodash__packages/my-lib`, the value is the
5
+ * resolved external node name from the project graph.
6
+ */
7
+ type NpmResolutionCache = Map<string, string>;
8
+ export declare function isBuiltinModuleImport(importExpr: string): boolean;
2
9
  export declare class TargetProjectLocator {
3
10
  private readonly nodes;
4
- private readonly externalNodes;
11
+ readonly externalNodes: Record<string, ProjectGraphExternalNode>;
12
+ private readonly npmResolutionCache;
5
13
  private projectRootMappings;
6
14
  private npmProjects;
7
15
  private tsConfig;
8
16
  private paths;
9
17
  private typescriptResolutionCache;
10
- private npmResolutionCache;
11
- constructor(nodes: Record<string, ProjectGraphProjectNode>, externalNodes: Record<string, ProjectGraphExternalNode>);
18
+ constructor(nodes: Record<string, ProjectGraphProjectNode>, externalNodes?: Record<string, ProjectGraphExternalNode>, npmResolutionCache?: NpmResolutionCache);
12
19
  /**
13
- * Find a project based on its import
20
+ * Resolve any workspace or external project that matches the given import expression,
21
+ * originating from the given filePath.
14
22
  *
15
23
  * @param importExpr
16
24
  * @param filePath
17
25
  */
18
- findProjectWithImport(importExpr: string, filePath: string): string;
26
+ findProjectFromImport(importExpr: string, filePath: string): string;
27
+ /**
28
+ * Resolve any external project that matches the given import expression,
29
+ * relative to the given file path.
30
+ *
31
+ * @param importExpr
32
+ * @param projectRoot
33
+ */
34
+ findNpmProjectFromImport(importExpr: string, fromFilePath: string): string | undefined;
19
35
  /**
20
36
  * Return file paths matching the import relative to the repo root
21
37
  * @param normalizedImportExpr
@@ -24,9 +40,9 @@ export declare class TargetProjectLocator {
24
40
  findPaths(normalizedImportExpr: string): string[] | undefined;
25
41
  private resolveImportWithTypescript;
26
42
  private resolveImportWithRequire;
27
- private findNpmPackage;
28
43
  private findProjectOfResolvedModule;
29
44
  private getAbsolutePath;
30
45
  private getRootTsConfig;
31
46
  private findMatchingProjectFiles;
32
47
  }
48
+ export {};
@@ -1,36 +1,60 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TargetProjectLocator = void 0;
4
- const typescript_1 = require("../../utils/typescript");
3
+ exports.TargetProjectLocator = exports.isBuiltinModuleImport = void 0;
4
+ const node_module_1 = require("node:module");
5
+ const node_path_1 = require("node:path");
6
+ const find_project_for_path_1 = require("../../../../project-graph/utils/find-project-for-path");
5
7
  const fileutils_1 = require("../../../../utils/fileutils");
6
- const path_1 = require("path");
7
8
  const workspace_root_1 = require("../../../../utils/workspace-root");
8
- const module_1 = require("module");
9
- const find_project_for_path_1 = require("../../../../project-graph/utils/find-project-for-path");
9
+ const find_external_package_json_path_1 = require("../../utils/find-external-package-json-path");
10
+ const typescript_1 = require("../../utils/typescript");
11
+ /**
12
+ * Use a shared cache to avoid repeated npm package resolution work within the TargetProjectLocator.
13
+ */
14
+ const defaultNpmResolutionCache = new Map();
10
15
  const builtInModuleSet = new Set([
11
- ...module_1.builtinModules,
12
- ...module_1.builtinModules.map((x) => `node:${x}`),
16
+ ...node_module_1.builtinModules,
17
+ ...node_module_1.builtinModules.map((x) => `node:${x}`),
13
18
  ]);
19
+ function isBuiltinModuleImport(importExpr) {
20
+ const packageName = parsePackageNameFromImportExpression(importExpr);
21
+ return builtInModuleSet.has(packageName);
22
+ }
23
+ exports.isBuiltinModuleImport = isBuiltinModuleImport;
14
24
  class TargetProjectLocator {
15
- constructor(nodes, externalNodes) {
25
+ constructor(nodes, externalNodes = {}, npmResolutionCache = defaultNpmResolutionCache) {
16
26
  this.nodes = nodes;
17
27
  this.externalNodes = externalNodes;
28
+ this.npmResolutionCache = npmResolutionCache;
18
29
  this.projectRootMappings = (0, find_project_for_path_1.createProjectRootMappings)(this.nodes);
19
- this.npmProjects = filterRootExternalDependencies(this.externalNodes);
20
30
  this.tsConfig = this.getRootTsConfig();
21
31
  this.paths = this.tsConfig.config?.compilerOptions?.paths;
22
32
  this.typescriptResolutionCache = new Map();
23
- this.npmResolutionCache = new Map();
33
+ this.npmProjects = externalNodes;
34
+ /**
35
+ * Only the npm external nodes should be included.
36
+ *
37
+ * Unlike the raw externalNodes, ensure that the version is always set in the key
38
+ * for optimal lookup.
39
+ */
40
+ this.npmProjects = Object.values(externalNodes).reduce((acc, node) => {
41
+ if (node.type === 'npm') {
42
+ const key = `npm:${node.data.packageName}@${node.data.version}`;
43
+ acc[key] = node;
44
+ }
45
+ return acc;
46
+ }, {});
24
47
  }
25
48
  /**
26
- * Find a project based on its import
49
+ * Resolve any workspace or external project that matches the given import expression,
50
+ * originating from the given filePath.
27
51
  *
28
52
  * @param importExpr
29
53
  * @param filePath
30
54
  */
31
- findProjectWithImport(importExpr, filePath) {
55
+ findProjectFromImport(importExpr, filePath) {
32
56
  if ((0, fileutils_1.isRelativePath)(importExpr)) {
33
- const resolvedModule = path_1.posix.join((0, path_1.dirname)(filePath), importExpr);
57
+ const resolvedModule = node_path_1.posix.join((0, node_path_1.dirname)(filePath), importExpr);
34
58
  return this.findProjectOfResolvedModule(resolvedModule);
35
59
  }
36
60
  // find project using tsconfig paths
@@ -39,7 +63,7 @@ class TargetProjectLocator {
39
63
  const [path, paths] = results;
40
64
  for (let p of paths) {
41
65
  const r = p.endsWith('/*')
42
- ? (0, path_1.join)((0, path_1.dirname)(p), (0, path_1.relative)(path.replace(/\*$/, ''), importExpr))
66
+ ? (0, node_path_1.join)((0, node_path_1.dirname)(p), (0, node_path_1.relative)(path.replace(/\*$/, ''), importExpr))
43
67
  : p;
44
68
  const maybeResolvedProject = this.findProjectOfResolvedModule(r);
45
69
  if (maybeResolvedProject) {
@@ -47,14 +71,14 @@ class TargetProjectLocator {
47
71
  }
48
72
  }
49
73
  }
50
- if (builtInModuleSet.has(importExpr)) {
74
+ if (isBuiltinModuleImport(importExpr)) {
51
75
  this.npmResolutionCache.set(importExpr, null);
52
76
  return null;
53
77
  }
54
78
  // try to find npm package before using expensive typescript resolution
55
- const npmProject = this.findNpmPackage(importExpr);
56
- if (npmProject) {
57
- return npmProject;
79
+ const externalProject = this.findNpmProjectFromImport(importExpr, filePath);
80
+ if (externalProject) {
81
+ return externalProject;
58
82
  }
59
83
  if (this.tsConfig.config) {
60
84
  // TODO(meeroslav): this block is probably obsolete
@@ -74,6 +98,52 @@ class TargetProjectLocator {
74
98
  this.npmResolutionCache.set(importExpr, null);
75
99
  return null;
76
100
  }
101
+ /**
102
+ * Resolve any external project that matches the given import expression,
103
+ * relative to the given file path.
104
+ *
105
+ * @param importExpr
106
+ * @param projectRoot
107
+ */
108
+ findNpmProjectFromImport(importExpr, fromFilePath) {
109
+ const packageName = parsePackageNameFromImportExpression(importExpr);
110
+ let fullFilePath = fromFilePath;
111
+ let workspaceRelativeFilePath = fromFilePath;
112
+ if (fromFilePath.startsWith(workspace_root_1.workspaceRoot)) {
113
+ workspaceRelativeFilePath = fromFilePath.replace(workspace_root_1.workspaceRoot, '');
114
+ }
115
+ else {
116
+ fullFilePath = (0, node_path_1.join)(workspace_root_1.workspaceRoot, fromFilePath);
117
+ }
118
+ const fullDirPath = (0, node_path_1.dirname)(fullFilePath);
119
+ const workspaceRelativeDirPath = (0, node_path_1.dirname)(workspaceRelativeFilePath);
120
+ const npmImportForProject = `${packageName}__${workspaceRelativeDirPath}`;
121
+ if (this.npmResolutionCache.has(npmImportForProject)) {
122
+ return this.npmResolutionCache.get(npmImportForProject);
123
+ }
124
+ try {
125
+ // package.json refers to an external package, we do not match against the version found in there, we instead try and resolve the relevant package how node would
126
+ const externalPackageJsonPath = (0, find_external_package_json_path_1.findExternalPackageJsonPath)(packageName, fullDirPath);
127
+ // The external package.json path might be not be resolvable, e.g. if a reference has been added to a project package.json, but the install command has not been run yet.
128
+ if (!externalPackageJsonPath) {
129
+ return undefined;
130
+ }
131
+ const externalPackageJson = (0, fileutils_1.readJsonFile)(externalPackageJsonPath);
132
+ const npmProjectKey = `npm:${externalPackageJson.name}@${externalPackageJson.version}`;
133
+ if (!this.npmProjects[npmProjectKey]) {
134
+ return undefined;
135
+ }
136
+ const matchingExternalNode = this.npmProjects[npmProjectKey];
137
+ this.npmResolutionCache.set(npmImportForProject, matchingExternalNode.name);
138
+ return matchingExternalNode.name;
139
+ }
140
+ catch (e) {
141
+ if (process.env.NX_VERBOSE_LOGGING === 'true') {
142
+ console.error(e);
143
+ }
144
+ return undefined;
145
+ }
146
+ }
77
147
  /**
78
148
  * Return file paths matching the import relative to the repo root
79
149
  * @param normalizedImportExpr
@@ -113,23 +183,10 @@ class TargetProjectLocator {
113
183
  return;
114
184
  }
115
185
  resolveImportWithRequire(normalizedImportExpr, filePath) {
116
- return path_1.posix.relative(workspace_root_1.workspaceRoot, require.resolve(normalizedImportExpr, {
117
- paths: [(0, path_1.dirname)(filePath)],
186
+ return node_path_1.posix.relative(workspace_root_1.workspaceRoot, require.resolve(normalizedImportExpr, {
187
+ paths: [(0, node_path_1.dirname)(filePath)],
118
188
  }));
119
189
  }
120
- findNpmPackage(npmImport) {
121
- if (this.npmResolutionCache.has(npmImport)) {
122
- return this.npmResolutionCache.get(npmImport);
123
- }
124
- else {
125
- const pkg = this.npmProjects.find((pkg) => npmImport === pkg.data.packageName ||
126
- npmImport.startsWith(`${pkg.data.packageName}/`));
127
- if (pkg) {
128
- this.npmResolutionCache.set(npmImport, pkg.name);
129
- return pkg.name;
130
- }
131
- }
132
- }
133
190
  findProjectOfResolvedModule(resolvedModule) {
134
191
  if (resolvedModule.startsWith('node_modules/') ||
135
192
  resolvedModule.includes('/node_modules/')) {
@@ -142,7 +199,7 @@ class TargetProjectLocator {
142
199
  return importedProject ? importedProject.name : void 0;
143
200
  }
144
201
  getAbsolutePath(path) {
145
- return (0, path_1.join)(workspace_root_1.workspaceRoot, path);
202
+ return (0, node_path_1.join)(workspace_root_1.workspaceRoot, path);
146
203
  }
147
204
  getRootTsConfig() {
148
205
  const path = (0, typescript_1.getRootTsConfigFileName)();
@@ -166,18 +223,12 @@ class TargetProjectLocator {
166
223
  }
167
224
  }
168
225
  exports.TargetProjectLocator = TargetProjectLocator;
169
- // matches `npm:@scope/name`, `npm:name` but not `npm:@scope/name@version` and `npm:name@version`
170
- const ROOT_VERSION_PACKAGE_NAME_REGEX = /^npm:(?!.+@.+)/;
171
- function filterRootExternalDependencies(externalNodes) {
172
- if (!externalNodes) {
173
- return [];
174
- }
175
- const keys = Object.keys(externalNodes);
176
- const nodes = [];
177
- for (let i = 0; i < keys.length; i++) {
178
- if (keys[i].match(ROOT_VERSION_PACKAGE_NAME_REGEX)) {
179
- nodes.push(externalNodes[keys[i]]);
180
- }
226
+ function parsePackageNameFromImportExpression(importExpression) {
227
+ // Check if the package is scoped
228
+ if (importExpression.startsWith('@')) {
229
+ // For scoped packages, the package name is up to the second '/'
230
+ return importExpression.split('/').slice(0, 2).join('/');
181
231
  }
182
- return nodes;
232
+ // For unscoped packages, the package name is up to the first '/'
233
+ return importExpression.split('/')[0];
183
234
  }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * In many cases the package.json will be directly resolvable, so we try that first.
3
+ * If, however, package exports are used and the package.json is not defined, we will
4
+ * need to resolve the main entry point of the package and traverse upwards to find the
5
+ * package.json.
6
+ *
7
+ * NOTE: Unit testing this code is currently impractical as it is not possible to mock
8
+ * require.resolve in jest https://github.com/jestjs/jest/issues/9543
9
+ */
10
+ export declare function findExternalPackageJsonPath(packageName: string, relativeToDir: string): string | null;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.findExternalPackageJsonPath = void 0;
4
+ const node_fs_1 = require("node:fs");
5
+ const node_path_1 = require("node:path");
6
+ /**
7
+ * In many cases the package.json will be directly resolvable, so we try that first.
8
+ * If, however, package exports are used and the package.json is not defined, we will
9
+ * need to resolve the main entry point of the package and traverse upwards to find the
10
+ * package.json.
11
+ *
12
+ * NOTE: Unit testing this code is currently impractical as it is not possible to mock
13
+ * require.resolve in jest https://github.com/jestjs/jest/issues/9543
14
+ */
15
+ function findExternalPackageJsonPath(packageName, relativeToDir) {
16
+ try {
17
+ return require.resolve((0, node_path_1.join)(packageName, 'package.json'), {
18
+ paths: [relativeToDir],
19
+ });
20
+ }
21
+ catch {
22
+ try {
23
+ // Resolve the main entry point of the package
24
+ const mainPath = require.resolve(packageName, {
25
+ paths: [relativeToDir],
26
+ });
27
+ let dir = (0, node_path_1.dirname)(mainPath);
28
+ while (dir !== (0, node_path_1.parse)(dir).root) {
29
+ const packageJsonPath = (0, node_path_1.join)(dir, 'package.json');
30
+ if ((0, node_fs_1.existsSync)(packageJsonPath)) {
31
+ return packageJsonPath;
32
+ }
33
+ dir = (0, node_path_1.dirname)(dir);
34
+ }
35
+ throw new Error(`Could not find package.json for ${packageName}`);
36
+ }
37
+ catch {
38
+ return null;
39
+ }
40
+ }
41
+ }
42
+ exports.findExternalPackageJsonPath = findExternalPackageJsonPath;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.unparse = exports.isCacheableTask = exports.shouldStreamOutput = exports.getSerializedArgsForTask = exports.getPrintableCommandArgsForTask = exports.getCliPath = exports.calculateReverseDeps = exports.removeIdsFromGraph = exports.removeTasksFromTaskGraph = exports.getCustomHasher = exports.getExecutorForTask = exports.getExecutorNameForTask = exports.getTargetConfigurationForTask = exports.interpolate = exports.getOutputsForTargetAndConfiguration = exports.transformLegacyOutputs = exports.validateOutputs = exports.getOutputs = exports.expandDependencyConfigSyntaxSugar = exports.getDependencyConfigs = void 0;
4
4
  const output_1 = require("../utils/output");
5
5
  const path_1 = require("path");
6
+ const posix_1 = require("path/posix");
6
7
  const workspace_root_1 = require("../utils/workspace-root");
7
8
  const path_2 = require("../utils/path");
8
9
  const fileutils_1 = require("../utils/fileutils");
@@ -166,18 +167,32 @@ function getOutputsForTargetAndConfiguration(taskTargetOrTask, overridesOrNode,
166
167
  }
167
168
  }
168
169
  exports.getOutputsForTargetAndConfiguration = getOutputsForTargetAndConfiguration;
170
+ /**
171
+ * Matches portions of a string which need to be interpolated.
172
+ * Matches anything within curly braces, excluding the braces.
173
+ */
174
+ const replacementRegex = /{([\s\S]+?)}/g;
169
175
  function interpolate(template, data) {
176
+ // Path is absolute or doesn't need interpolation
177
+ if (template.startsWith('/') || !replacementRegex.test(template)) {
178
+ return template;
179
+ }
170
180
  if (template.includes('{workspaceRoot}', 1)) {
171
181
  throw new Error(`Output '${template}' is invalid. {workspaceRoot} can only be used at the beginning of the expression.`);
172
182
  }
173
183
  if (data.projectRoot == '.' && template.includes('{projectRoot}', 1)) {
174
184
  throw new Error(`Output '${template}' is invalid. When {projectRoot} is '.', it can only be used at the beginning of the expression.`);
175
185
  }
176
- let res = template.replace('{workspaceRoot}/', '');
186
+ const parts = template.split('/').map((s) => _interpolate(s, data));
187
+ return (0, posix_1.join)(...parts).replace('{workspaceRoot}/', '');
188
+ }
189
+ exports.interpolate = interpolate;
190
+ function _interpolate(template, data) {
191
+ let res = template;
177
192
  if (data.projectRoot == '.') {
178
- res = res.replace('{projectRoot}/', '');
193
+ res = res.replace('{projectRoot}', '');
179
194
  }
180
- return res.replace(/{([\s\S]+?)}/g, (match) => {
195
+ return res.replace(replacementRegex, (match) => {
181
196
  let value = data;
182
197
  let path = match.slice(1, -1).trim().split('.');
183
198
  for (let idx = 0; idx < path.length; idx++) {
@@ -189,7 +204,6 @@ function interpolate(template, data) {
189
204
  return value;
190
205
  });
191
206
  }
192
- exports.interpolate = interpolate;
193
207
  function getTargetConfigurationForTask(task, projectGraph) {
194
208
  const project = projectGraph.nodes[task.target.project].data;
195
209
  return project.targets[task.target.target];
@@ -226,7 +226,7 @@ function generateLinkOutput({ pluginName, name, type, }) {
226
226
  !pluginName.startsWith(nrwlPackagePrefix)) {
227
227
  return '';
228
228
  }
229
- const link = `https://nx.dev/packages/${pluginName.substring(pluginName.startsWith(nxPackagePrefix)
229
+ const link = `https://nx.dev/nx-api/${pluginName.substring(pluginName.startsWith(nxPackagePrefix)
230
230
  ? nxPackagePrefix.length
231
231
  : nrwlPackagePrefix.length)}/${type}/${name}`;
232
232
  return `\n\n${chalk.dim('Find more information and examples at:')} ${chalk.bold(link)}`;