@nx/devkit 23.3.0-pr.36841.f66e88b → 23.3.0-pr.37036.2b7abf9

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.
@@ -13,11 +13,12 @@ export { determineProjectNameAndRootOptions, ensureRootProjectName, resolveImpor
13
13
  export { isInteractive } from './src/generators/prompt';
14
14
  export { addBuildTargetDefaults, addE2eCiTargetDefaults, findTargetDefault, readTargetDefaultsForTarget, updateTargetDefault, upsertTargetDefault, } from './src/generators/target-defaults-utils';
15
15
  export { addPlugin } from './src/utils/add-plugin';
16
- export { getDeclaredPackageVersion, getInstalledPackageVersion, } from './src/utils/installed-version';
17
- export { assertSupportedInstalledPackageVersion, assertSupportedPackageVersion, } from './src/utils/version-floor';
16
+ export { getDeclaredPackageVersion, getInstalledPackageVersion, getInstalledPackageVersionFromTree, } from './src/utils/installed-version';
17
+ export { assertSupportedInstalledPackageVersion, assertSupportedPackageVersion, getResolvedPackageVersion, getSatisfyingInstalledPackageVersion, } from './src/utils/version-floor';
18
18
  export { createAsyncIterable, combineAsyncIterables, mapAsyncIterable, } from './src/utils/async-iterable';
19
19
  export { calculateHashForCreateNodes, calculateHashesForCreateNodes, } from './src/utils/calculate-hash-for-create-nodes';
20
20
  export { loadConfigFile, clearRequireCache } from './src/utils/config-utils';
21
+ export { isRequireEsmRaceError, retryOnRequireEsmRace, } from './src/utils/require-esm-race';
21
22
  export { findPluginForConfigFile } from './src/utils/find-plugin-for-config-file';
22
23
  export { getNamedInputs } from './src/utils/get-named-inputs';
23
24
  export { logShowProjectCommand } from './src/utils/log-show-project-command';
package/dist/internal.js CHANGED
@@ -1,10 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createAsyncIterable = exports.assertSupportedPackageVersion = exports.assertSupportedInstalledPackageVersion = exports.getInstalledPackageVersion = exports.getDeclaredPackageVersion = exports.addPlugin = exports.upsertTargetDefault = exports.updateTargetDefault = exports.readTargetDefaultsForTarget = exports.findTargetDefault = exports.addE2eCiTargetDefaults = exports.addBuildTargetDefaults = exports.isInteractive = exports.resolveImportPath = exports.ensureRootProjectName = exports.determineProjectNameAndRootOptions = exports.toProjectRelativePath = exports.deleteMatchingProperties = exports.processTargetOutputs = exports.NoTargetsToMigrateError = exports.migrateProjectExecutorsToPluginV1 = exports.migrateProjectExecutorsToPlugin = exports.openBatchConversionSession = exports.finalizeBatchConversion = exports.AggregatedLog = exports.forEachExecutorOptions = exports.getE2EWebServerInfo = exports.getRelativeCwd = exports.determineArtifactNameAndDirectoryOptions = exports.oxfmtConfigFiles = exports.prettierConfigFiles = exports.detectFormatterInTree = exports.hashDaemonClientEnv = exports.getGraphTimeDotEnvForTask = exports.applyDaemonEnvFromClient = exports.getAppliedDaemonClientEnv = exports.getDaemonClientEnvGeneration = exports.getCatalogManager = exports.acknowledgeBuildScripts = exports.PromptResolutionError = exports.resolvePrompt = exports.SchemaResolutionError = exports.ImplementationResolutionError = exports.resolveSchema = exports.resolveImplementation = exports.emitPluginWorkerLog = exports.safeWriteFileCache = exports.PluginCache = exports.createProjectRootMappingsFromProjectConfigurations = exports.signalToCode = void 0;
4
- exports.deduceDefaultBase = exports.daemonClient = exports.createTaskId = exports.createTargetDefaultsResults = exports.createRunManyDynamicOutputRenderer = exports.createProjectRootMappings = exports.createProjectGraphAndSourceMapsAsync = exports.createPackageJson = exports.createNxCloudOnboardingURLForWelcomeApp = exports.createNxCloudOnboardingURL = exports.createLockFile = exports.createDirectory = exports.connectToNxCloud = exports.combineGlobPatterns = exports.codeFrameColumns = exports.calculateReverseDeps = exports.calculateFileChanges = exports.buildProjectGraphAndSourceMapsWithoutDaemon = exports.buildPackageJsonWorkspacesMatcher = exports.buildPackageJsonPatterns = exports.WholeFileChange = exports.TargetProjectLocator = exports.TEN_MEGABYTES = exports.SyncError = exports.RemoteCacheV2 = exports.NX_PREFIX = exports.LockFileChange = exports.LARGE_BUFFER = exports.FsTree = exports.confirmationPrompt = exports.DeletedFileChange = exports.CompositeLifeCycle = exports.Cache = exports.BatchFunctionRunner = exports.runCommandsExecutor = exports.dasherize = exports.classify = exports.capitalize = exports.camelize = exports.checkAndCleanWithSemver = exports.eachValueFrom = exports.logShowProjectCommand = exports.getNamedInputs = exports.findPluginForConfigFile = exports.clearRequireCache = exports.loadConfigFile = exports.calculateHashesForCreateNodes = exports.calculateHashForCreateNodes = exports.mapAsyncIterable = exports.combineAsyncIterables = void 0;
5
- exports.hashFile = exports.handleProjectGraphError = exports.handleImport = exports.globWithWorkspaceContext = exports.getWorkspacePackagesFromGraph = exports.getUnparsedOverrideArgs = exports.getTargetInputs = exports.getTargetConfigurationForTask = exports.getSourceDirOfDependentProjects = exports.getSerializedArgsForTask = exports.getRelativeProjectJsonSchemaPath = exports.getPrintableCommandArgsForTask = exports.getOutputs = exports.getNxRequirePaths = exports.getNxCloudUrl = exports.getNxCloudAppOnBoardingUrl = exports.getLockFileName = exports.getLatestCommitSha = exports.getLastValueFromAsyncIterableIterator = exports.getGlobPatternsFromPackageManagerWorkspaces = exports.getGeneratorInformation = exports.getFilesInDirectoryUsingContext = exports.getExecutorNameForTask = exports.getExecutorInformation = exports.getExecutorForTask = exports.getEnvPathsForTask = exports.getEnvFilesForTask = exports.getDependencyConfigs = exports.getCustomHasher = exports.getCliPath = exports.generatePrunedDeployOutput = exports.forceRegisterEsmLoader = exports.findProjectsNpmDependencies = exports.findProjectForPath = exports.findMatchingTargetNames = exports.findMatchingProjects = exports.findMatchingConfigFiles = exports.findInstalledPlugins = exports.findAllProjectNodeDependencies = exports.filterUsingGlobPatterns = exports.fileExists = exports.fileDataDepType = exports.fileDataDepTarget = exports.expandWildcardTargetConfiguration = exports.expandInitiatingTasksThroughNoop = exports.expandDependencyConfigSyntaxSugar = exports.dropEmptyPeerDependencySections = exports.directoryExists = exports.deriveGroupNameFromTarget = exports.defaultFileRead = void 0;
6
- exports.setupAiAgentsGenerator = exports.setWorkspaceRoot = exports.selectPrompt = exports.safeSpawn = exports.safeExecFileSync = exports.runNxSync = exports.resolveCommandSyntacticSugar = exports.resetWorkspaceContext = exports.requireWithTsconfigFallback = exports.removeTasksFromTaskGraph = exports.relocatePrunedLocalPathSpec = exports.registerTsProject = exports.registerTsConfigPaths = exports.readProjectAndTargetFromTargetString = exports.readPackageJson = exports.readNxMigrateConfig = exports.readNxJsonFromDisk = exports.readModulePackageJson = exports.readFileMapCache = exports.readFileIfExisting = exports.readCachedProjectConfiguration = exports.quoteShellArg = exports.preventRecursionInGraphConstruction = exports.parseVersionFromPackageManagerField = exports.parseExecutor = exports.orange = exports.nxVersion = exports.normalizeTargetDependencyWithStringProjects = exports.normalizeDependencyConfigProjects = exports.normalizeDependencyConfigDefinition = exports.multiselectPrompt = exports.movePeerDependencyToDependencies = exports.mergeTargetConfigurations = exports.loadTsFile = exports.killProcessTreeGraceful = exports.killChildOnHostExit = exports.isWholeFileChange = exports.isRelativePath = exports.isProjectGraphProjectNode = exports.isProjectGraphExternalNode = exports.isNxCloudUsed = exports.isNpmProject = exports.isLockFileChange = exports.isDeletedFileChange = exports.isCacheableTask = exports.isCI = exports.isBuiltinModuleImport = exports.interpolate = exports.hashWithWorkspaceContext = exports.hashObject = void 0;
7
- exports.workspaceRootInner = exports.workspaceDataDirectory = exports.warnUnshippableLocalPathSpec = exports.validateOutputs = exports.unparse = exports.textPrompt = exports.transformLegacyOutputs = exports.toOldFormat = exports.toNewFormat = exports.shouldStreamOutput = exports.setupWorkspaceContext = void 0;
3
+ exports.assertSupportedPackageVersion = exports.assertSupportedInstalledPackageVersion = exports.getInstalledPackageVersionFromTree = exports.getInstalledPackageVersion = exports.getDeclaredPackageVersion = exports.addPlugin = exports.upsertTargetDefault = exports.updateTargetDefault = exports.readTargetDefaultsForTarget = exports.findTargetDefault = exports.addE2eCiTargetDefaults = exports.addBuildTargetDefaults = exports.isInteractive = exports.resolveImportPath = exports.ensureRootProjectName = exports.determineProjectNameAndRootOptions = exports.toProjectRelativePath = exports.deleteMatchingProperties = exports.processTargetOutputs = exports.NoTargetsToMigrateError = exports.migrateProjectExecutorsToPluginV1 = exports.migrateProjectExecutorsToPlugin = exports.openBatchConversionSession = exports.finalizeBatchConversion = exports.AggregatedLog = exports.forEachExecutorOptions = exports.getE2EWebServerInfo = exports.getRelativeCwd = exports.determineArtifactNameAndDirectoryOptions = exports.oxfmtConfigFiles = exports.prettierConfigFiles = exports.detectFormatterInTree = exports.hashDaemonClientEnv = exports.getGraphTimeDotEnvForTask = exports.applyDaemonEnvFromClient = exports.getAppliedDaemonClientEnv = exports.getDaemonClientEnvGeneration = exports.getCatalogManager = exports.acknowledgeBuildScripts = exports.PromptResolutionError = exports.resolvePrompt = exports.SchemaResolutionError = exports.ImplementationResolutionError = exports.resolveSchema = exports.resolveImplementation = exports.emitPluginWorkerLog = exports.safeWriteFileCache = exports.PluginCache = exports.createProjectRootMappingsFromProjectConfigurations = exports.signalToCode = void 0;
4
+ exports.createProjectRootMappings = exports.createProjectGraphAndSourceMapsAsync = exports.createPackageJson = exports.createNxCloudOnboardingURLForWelcomeApp = exports.createNxCloudOnboardingURL = exports.createLockFile = exports.createDirectory = exports.connectToNxCloud = exports.combineGlobPatterns = exports.codeFrameColumns = exports.calculateReverseDeps = exports.calculateFileChanges = exports.buildProjectGraphAndSourceMapsWithoutDaemon = exports.buildPackageJsonWorkspacesMatcher = exports.buildPackageJsonPatterns = exports.WholeFileChange = exports.TargetProjectLocator = exports.TEN_MEGABYTES = exports.SyncError = exports.RemoteCacheV2 = exports.NX_PREFIX = exports.LockFileChange = exports.LARGE_BUFFER = exports.FsTree = exports.confirmationPrompt = exports.DeletedFileChange = exports.CompositeLifeCycle = exports.Cache = exports.BatchFunctionRunner = exports.runCommandsExecutor = exports.dasherize = exports.classify = exports.capitalize = exports.camelize = exports.checkAndCleanWithSemver = exports.eachValueFrom = exports.logShowProjectCommand = exports.getNamedInputs = exports.findPluginForConfigFile = exports.retryOnRequireEsmRace = exports.isRequireEsmRaceError = exports.clearRequireCache = exports.loadConfigFile = exports.calculateHashesForCreateNodes = exports.calculateHashForCreateNodes = exports.mapAsyncIterable = exports.combineAsyncIterables = exports.createAsyncIterable = exports.getSatisfyingInstalledPackageVersion = exports.getResolvedPackageVersion = void 0;
5
+ exports.getUnparsedOverrideArgs = exports.getTargetInputs = exports.getTargetConfigurationForTask = exports.getSourceDirOfDependentProjects = exports.getSerializedArgsForTask = exports.getRelativeProjectJsonSchemaPath = exports.getPrintableCommandArgsForTask = exports.getOutputs = exports.getNxRequirePaths = exports.getNxCloudUrl = exports.getNxCloudAppOnBoardingUrl = exports.getLockFileName = exports.getLatestCommitSha = exports.getLastValueFromAsyncIterableIterator = exports.getGlobPatternsFromPackageManagerWorkspaces = exports.getGeneratorInformation = exports.getFilesInDirectoryUsingContext = exports.getExecutorNameForTask = exports.getExecutorInformation = exports.getExecutorForTask = exports.getEnvPathsForTask = exports.getEnvFilesForTask = exports.getDependencyConfigs = exports.getCustomHasher = exports.getCliPath = exports.generatePrunedDeployOutput = exports.forceRegisterEsmLoader = exports.findProjectsNpmDependencies = exports.findProjectForPath = exports.findMatchingTargetNames = exports.findMatchingProjects = exports.findMatchingConfigFiles = exports.findInstalledPlugins = exports.findAllProjectNodeDependencies = exports.filterUsingGlobPatterns = exports.fileExists = exports.fileDataDepType = exports.fileDataDepTarget = exports.expandWildcardTargetConfiguration = exports.expandInitiatingTasksThroughNoop = exports.expandDependencyConfigSyntaxSugar = exports.dropEmptyPeerDependencySections = exports.directoryExists = exports.deriveGroupNameFromTarget = exports.defaultFileRead = exports.deduceDefaultBase = exports.daemonClient = exports.createTaskId = exports.createTargetDefaultsResults = exports.createRunManyDynamicOutputRenderer = void 0;
6
+ exports.runNxSync = exports.resolveCommandSyntacticSugar = exports.resetWorkspaceContext = exports.requireWithTsconfigFallback = exports.removeTasksFromTaskGraph = exports.relocatePrunedLocalPathSpec = exports.registerTsProject = exports.registerTsConfigPaths = exports.readProjectAndTargetFromTargetString = exports.readPackageJson = exports.readNxMigrateConfig = exports.readNxJsonFromDisk = exports.readModulePackageJson = exports.readFileMapCache = exports.readFileIfExisting = exports.readCachedProjectConfiguration = exports.quoteShellArg = exports.preventRecursionInGraphConstruction = exports.parseVersionFromPackageManagerField = exports.parseExecutor = exports.orange = exports.nxVersion = exports.normalizeTargetDependencyWithStringProjects = exports.normalizeDependencyConfigProjects = exports.normalizeDependencyConfigDefinition = exports.multiselectPrompt = exports.movePeerDependencyToDependencies = exports.mergeTargetConfigurations = exports.loadTsFile = exports.killProcessTreeGraceful = exports.killChildOnHostExit = exports.isWholeFileChange = exports.isRelativePath = exports.isProjectGraphProjectNode = exports.isProjectGraphExternalNode = exports.isNxCloudUsed = exports.isNpmProject = exports.isLockFileChange = exports.isDeletedFileChange = exports.isCacheableTask = exports.isCI = exports.isBuiltinModuleImport = exports.interpolate = exports.hashWithWorkspaceContext = exports.hashObject = exports.hashFile = exports.handleProjectGraphError = exports.handleImport = exports.globWithWorkspaceContext = exports.getWorkspacePackagesFromGraph = void 0;
7
+ exports.workspaceRootInner = exports.workspaceDataDirectory = exports.warnUnshippableLocalPathSpec = exports.validateOutputs = exports.unparse = exports.textPrompt = exports.transformLegacyOutputs = exports.toOldFormat = exports.toNewFormat = exports.shouldStreamOutput = exports.setupWorkspaceContext = exports.setupAiAgentsGenerator = exports.setWorkspaceRoot = exports.selectPrompt = exports.safeSpawn = exports.safeExecFileSync = void 0;
8
8
  var devkit_internals_1 = require("nx/src/devkit-internals");
9
9
  Object.defineProperty(exports, "signalToCode", { enumerable: true, get: function () { return devkit_internals_1.signalToCode; } });
10
10
  Object.defineProperty(exports, "createProjectRootMappingsFromProjectConfigurations", { enumerable: true, get: function () { return devkit_internals_1.createProjectRootMappingsFromProjectConfigurations; } });
@@ -80,9 +80,12 @@ Object.defineProperty(exports, "addPlugin", { enumerable: true, get: function ()
80
80
  var installed_version_1 = require("./src/utils/installed-version");
81
81
  Object.defineProperty(exports, "getDeclaredPackageVersion", { enumerable: true, get: function () { return installed_version_1.getDeclaredPackageVersion; } });
82
82
  Object.defineProperty(exports, "getInstalledPackageVersion", { enumerable: true, get: function () { return installed_version_1.getInstalledPackageVersion; } });
83
+ Object.defineProperty(exports, "getInstalledPackageVersionFromTree", { enumerable: true, get: function () { return installed_version_1.getInstalledPackageVersionFromTree; } });
83
84
  var version_floor_1 = require("./src/utils/version-floor");
84
85
  Object.defineProperty(exports, "assertSupportedInstalledPackageVersion", { enumerable: true, get: function () { return version_floor_1.assertSupportedInstalledPackageVersion; } });
85
86
  Object.defineProperty(exports, "assertSupportedPackageVersion", { enumerable: true, get: function () { return version_floor_1.assertSupportedPackageVersion; } });
87
+ Object.defineProperty(exports, "getResolvedPackageVersion", { enumerable: true, get: function () { return version_floor_1.getResolvedPackageVersion; } });
88
+ Object.defineProperty(exports, "getSatisfyingInstalledPackageVersion", { enumerable: true, get: function () { return version_floor_1.getSatisfyingInstalledPackageVersion; } });
86
89
  var async_iterable_1 = require("./src/utils/async-iterable");
87
90
  Object.defineProperty(exports, "createAsyncIterable", { enumerable: true, get: function () { return async_iterable_1.createAsyncIterable; } });
88
91
  Object.defineProperty(exports, "combineAsyncIterables", { enumerable: true, get: function () { return async_iterable_1.combineAsyncIterables; } });
@@ -93,6 +96,9 @@ Object.defineProperty(exports, "calculateHashesForCreateNodes", { enumerable: tr
93
96
  var config_utils_1 = require("./src/utils/config-utils");
94
97
  Object.defineProperty(exports, "loadConfigFile", { enumerable: true, get: function () { return config_utils_1.loadConfigFile; } });
95
98
  Object.defineProperty(exports, "clearRequireCache", { enumerable: true, get: function () { return config_utils_1.clearRequireCache; } });
99
+ var require_esm_race_1 = require("./src/utils/require-esm-race");
100
+ Object.defineProperty(exports, "isRequireEsmRaceError", { enumerable: true, get: function () { return require_esm_race_1.isRequireEsmRaceError; } });
101
+ Object.defineProperty(exports, "retryOnRequireEsmRace", { enumerable: true, get: function () { return require_esm_race_1.retryOnRequireEsmRace; } });
96
102
  var find_plugin_for_config_file_1 = require("./src/utils/find-plugin-for-config-file");
97
103
  Object.defineProperty(exports, "findPluginForConfigFile", { enumerable: true, get: function () { return find_plugin_for_config_file_1.findPluginForConfigFile; } });
98
104
  var get_named_inputs_1 = require("./src/utils/get-named-inputs");
@@ -0,0 +1,2 @@
1
+ export declare function isRequireEsmRaceError(e: unknown): boolean;
2
+ export declare function retryOnRequireEsmRace<T>(load: () => Promise<T>, importModule?: (modulePath: string) => Promise<any>): Promise<T>;
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isRequireEsmRaceError = isRequireEsmRaceError;
4
+ exports.retryOnRequireEsmRace = retryOnRequireEsmRace;
5
+ const node_url_1 = require("node:url");
6
+ const dynamicImport = (modulePath) => import(modulePath);
7
+ const REQUIRE_ESM_RACE_MESSAGE = /Cannot require\(\) ES Module (.+) because it is not yet fully loaded\.(?:\r?\n|$)/;
8
+ const MAX_RETRIES = 20;
9
+ const CONFIG_EXTENSION_HINT = 'Rename your Vite or Vitest config file to use the .mts or .mjs extension to avoid this error.';
10
+ // Node rejects require() of an ES module while an import() of it is still
11
+ // linking. Newer Node versions expose ERR_REQUIRE_ESM_RACE_CONDITION
12
+ // (https://github.com/nodejs/node/pull/62462). Older versions report an
13
+ // ERR_INTERNAL_ASSERTION, so its known message is the only way to distinguish
14
+ // this race from unrelated internal assertions. Matching that legacy format is
15
+ // safe for the releases that emitted it.
16
+ function isRequireEsmRaceError(e) {
17
+ const { code, message } = (e ?? {});
18
+ return (code === 'ERR_REQUIRE_ESM_RACE_CONDITION' ||
19
+ (code === 'ERR_INTERNAL_ASSERTION' &&
20
+ /not yet fully loaded/.test(message ?? '')));
21
+ }
22
+ function getRacedModulePath(e) {
23
+ if (!isRequireEsmRaceError(e)) {
24
+ return;
25
+ }
26
+ const { message } = e;
27
+ return message?.match(REQUIRE_ESM_RACE_MESSAGE)?.[1];
28
+ }
29
+ async function retryOnRequireEsmRace(load, importModule = dynamicImport) {
30
+ let retries = 0;
31
+ while (true) {
32
+ try {
33
+ return await load();
34
+ }
35
+ catch (e) {
36
+ if (!isRequireEsmRaceError(e) || retries >= MAX_RETRIES) {
37
+ throw e;
38
+ }
39
+ const racedModulePath = getRacedModulePath(e);
40
+ if (!racedModulePath) {
41
+ const error = e;
42
+ error.message += `\n\n${CONFIG_EXTENSION_HINT}`;
43
+ throw error;
44
+ }
45
+ retries++;
46
+ // This joins the cached module job instead of guessing when it settles.
47
+ await importModule((0, node_url_1.pathToFileURL)(racedModulePath).href);
48
+ }
49
+ }
50
+ }
@@ -20,7 +20,8 @@ export declare function throwForUnsupportedVersion(packageName: string, installe
20
20
  * Resolution order:
21
21
  * - When the installed version satisfies the declared range, the installed
22
22
  * version decides. This resolves open ranges (e.g. `>=4.8.4 <6.1.0`) to
23
- * what is actually installed.
23
+ * what is actually installed. An install behind a declaration that is not a
24
+ * range (e.g. `file:../pkg`) decides as well.
24
25
  * - An exact declared version is compared to the floor directly.
25
26
  * - A declared range that cannot reach the floor throws as unsupported. A
26
27
  * range that straddles the floor cannot be judged without an installed
@@ -35,6 +36,37 @@ export declare function throwForUnsupportedVersion(packageName: string, installe
35
36
  * before writing any incompatible config.
36
37
  */
37
38
  export declare function assertSupportedPackageVersion(tree: Tree, packageName: string, minSupportedVersion: string): void;
39
+ /**
40
+ * Resolves the version of a package a generator should target.
41
+ *
42
+ * Resolution order:
43
+ * - When the installed version satisfies the declared range, the installed
44
+ * version decides. This resolves open ranges (e.g. `>=15.0.0 <17.0.0`) to
45
+ * what is actually installed. A declaration that is not a range (`latest`,
46
+ * `file:../pkg`) resolved to the installed version, so that version decides
47
+ * as well.
48
+ * - Otherwise the declared range's floor (`semver.minVersion`, a prerelease
49
+ * when the range starts at one). This is the fresh-workspace path (nothing
50
+ * installed yet) and the case where a generator is mid-flight re-pinning
51
+ * the package: the new range no longer satisfies the still-installed
52
+ * version, so intent wins. A dist tag with nothing installed resolves to
53
+ * `latestKnownVersion`.
54
+ *
55
+ * Returns `null` when the package is not declared and no
56
+ * `latestKnownVersion` is provided; an install that is not declared in the
57
+ * workspace `package.json` (e.g. a hoisted transitive dependency) is ignored.
58
+ */
59
+ export declare function getResolvedPackageVersion(tree: Tree, packageName: string, latestKnownVersion?: string): string | null;
60
+ /**
61
+ * Returns the installed version of a package when it satisfies the declared
62
+ * range, `null` when nothing is installed or the install does not match the
63
+ * declaration. An `npm:<name>@<range>` alias is matched against its range. A
64
+ * declaration without a range, such as a dist tag (`latest`) or a `file:`,
65
+ * `link:` or `workspace:` specifier, admits whatever is installed: it has no
66
+ * version to compare. Use it to gate on what actually runs while keeping the
67
+ * declared-range fallback for the fresh-install path.
68
+ */
69
+ export declare function getSatisfyingInstalledPackageVersion(tree: Tree, packageName: string, declared: string): string | null;
38
70
  /**
39
71
  * Asserts that a package installed in the workspace is at or above the
40
72
  * plugin's supported floor. No-op when the package is not resolvable from
@@ -2,6 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.throwForUnsupportedVersion = throwForUnsupportedVersion;
4
4
  exports.assertSupportedPackageVersion = assertSupportedPackageVersion;
5
+ exports.getResolvedPackageVersion = getResolvedPackageVersion;
6
+ exports.getSatisfyingInstalledPackageVersion = getSatisfyingInstalledPackageVersion;
5
7
  exports.assertSupportedInstalledPackageVersion = assertSupportedInstalledPackageVersion;
6
8
  const devkit_exports_1 = require("nx/src/devkit-exports");
7
9
  const semver_1 = require("semver");
@@ -33,7 +35,8 @@ function throwForUnsupportedVersion(packageName, installedVersion, floor) {
33
35
  * Resolution order:
34
36
  * - When the installed version satisfies the declared range, the installed
35
37
  * version decides. This resolves open ranges (e.g. `>=4.8.4 <6.1.0`) to
36
- * what is actually installed.
38
+ * what is actually installed. An install behind a declaration that is not a
39
+ * range (e.g. `file:../pkg`) decides as well.
37
40
  * - An exact declared version is compared to the floor directly.
38
41
  * - A declared range that cannot reach the floor throws as unsupported. A
39
42
  * range that straddles the floor cannot be judged without an installed
@@ -52,18 +55,13 @@ function assertSupportedPackageVersion(tree, packageName, minSupportedVersion) {
52
55
  if (!declared || (0, installed_version_1.isNonSemverDistTag)(declared)) {
53
56
  return;
54
57
  }
55
- const installed = (0, installed_version_1.getInstalledPackageVersionFromTree)(tree, packageName) ??
56
- getInstalledPackageVersionFromProcess(tree, packageName);
58
+ const installed = getSatisfyingInstalledPackageVersion(tree, packageName, declared);
57
59
  if (installed) {
58
- // An installed prerelease can match the declared range in either form:
59
- // raw (a same-tuple prerelease comparator) or as its release version.
60
60
  const release = (0, semver_1.coerce)(installed)?.version ?? installed;
61
- if ((0, semver_1.satisfies)(installed, declared) || (0, semver_1.satisfies)(release, declared)) {
62
- if ((0, semver_1.lt)(release, minSupportedVersion)) {
63
- throwForUnsupportedVersion(packageName, installed, minSupportedVersion);
64
- }
65
- return;
61
+ if ((0, semver_1.lt)(release, minSupportedVersion)) {
62
+ throwForUnsupportedVersion(packageName, installed, minSupportedVersion);
66
63
  }
64
+ return;
67
65
  }
68
66
  const cleaned = (0, semver_1.clean)(declared);
69
67
  if (cleaned) {
@@ -96,6 +94,78 @@ function assertSupportedPackageVersion(tree, packageName, minSupportedVersion) {
96
94
  throwForUnsupportedVersion(packageName, declared, minSupportedVersion);
97
95
  }
98
96
  }
97
+ /**
98
+ * Resolves the version of a package a generator should target.
99
+ *
100
+ * Resolution order:
101
+ * - When the installed version satisfies the declared range, the installed
102
+ * version decides. This resolves open ranges (e.g. `>=15.0.0 <17.0.0`) to
103
+ * what is actually installed. A declaration that is not a range (`latest`,
104
+ * `file:../pkg`) resolved to the installed version, so that version decides
105
+ * as well.
106
+ * - Otherwise the declared range's floor (`semver.minVersion`, a prerelease
107
+ * when the range starts at one). This is the fresh-workspace path (nothing
108
+ * installed yet) and the case where a generator is mid-flight re-pinning
109
+ * the package: the new range no longer satisfies the still-installed
110
+ * version, so intent wins. A dist tag with nothing installed resolves to
111
+ * `latestKnownVersion`.
112
+ *
113
+ * Returns `null` when the package is not declared and no
114
+ * `latestKnownVersion` is provided; an install that is not declared in the
115
+ * workspace `package.json` (e.g. a hoisted transitive dependency) is ignored.
116
+ */
117
+ function getResolvedPackageVersion(tree, packageName, latestKnownVersion) {
118
+ const declared = (0, package_json_1.getDependencyVersionFromPackageJson)(tree, packageName);
119
+ if (declared) {
120
+ const installed = getSatisfyingInstalledPackageVersion(tree, packageName, declared);
121
+ if (installed) {
122
+ return installed;
123
+ }
124
+ // `minVersion` reads the whole range, so `<16 >=15.8.0` floors at 15.8.0.
125
+ // It is null for a range nothing satisfies.
126
+ const floor = (0, semver_1.validRange)(declared) ? (0, semver_1.minVersion)(declared)?.version : null;
127
+ if (floor) {
128
+ return floor;
129
+ }
130
+ }
131
+ return (0, installed_version_1.getDeclaredPackageVersion)(tree, packageName, latestKnownVersion);
132
+ }
133
+ /**
134
+ * Returns the installed version of a package when it satisfies the declared
135
+ * range, `null` when nothing is installed or the install does not match the
136
+ * declaration. An `npm:<name>@<range>` alias is matched against its range. A
137
+ * declaration without a range, such as a dist tag (`latest`) or a `file:`,
138
+ * `link:` or `workspace:` specifier, admits whatever is installed: it has no
139
+ * version to compare. Use it to gate on what actually runs while keeping the
140
+ * declared-range fallback for the fresh-install path.
141
+ */
142
+ function getSatisfyingInstalledPackageVersion(tree, packageName, declared) {
143
+ const installed = (0, installed_version_1.getInstalledPackageVersionFromTree)(tree, packageName) ??
144
+ getInstalledPackageVersionFromProcess(tree, packageName);
145
+ if (!installed) {
146
+ return null;
147
+ }
148
+ const range = getNpmAliasRange(declared) ?? declared;
149
+ if (!(0, semver_1.validRange)(range)) {
150
+ return installed;
151
+ }
152
+ // An installed prerelease can match the declared range in either form:
153
+ // raw (a same-tuple prerelease comparator) or as its release version.
154
+ const release = (0, semver_1.coerce)(installed)?.version ?? installed;
155
+ return (0, semver_1.satisfies)(installed, range) || (0, semver_1.satisfies)(release, range)
156
+ ? installed
157
+ : null;
158
+ }
159
+ // The range follows the last `@`. In `npm:@scope/pkg` that `@` starts the
160
+ // scope, so there is no range.
161
+ function getNpmAliasRange(declared) {
162
+ const prefix = 'npm:';
163
+ if (!declared.startsWith(prefix)) {
164
+ return null;
165
+ }
166
+ const at = declared.lastIndexOf('@');
167
+ return at > prefix.length ? declared.slice(at + 1) : null;
168
+ }
99
169
  /**
100
170
  * Module-resolution fallback for installs without a `node_modules` layout
101
171
  * (e.g. Yarn PnP). Only valid when the tree is the running process's
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/devkit",
3
- "version": "23.3.0-pr.36841.f66e88b",
3
+ "version": "23.3.0-pr.37036.2b7abf9",
4
4
  "private": false,
5
5
  "type": "commonjs",
6
6
  "files": [
@@ -67,7 +67,7 @@
67
67
  },
68
68
  "devDependencies": {
69
69
  "jest": "30.3.0",
70
- "nx": "23.3.0-pr.36841.f66e88b"
70
+ "nx": "23.3.0-pr.37036.2b7abf9"
71
71
  },
72
72
  "peerDependencies": {
73
73
  "nx": ">= 22 <= 24 || ^23.0.0-0"