@nx/js 22.6.0-pr.34764.c1c3b27 → 22.6.0-pr.34876.039ddae

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/js",
3
- "version": "22.6.0-pr.34764.c1c3b27",
3
+ "version": "22.6.0-pr.34876.039ddae",
4
4
  "private": false,
5
5
  "description": "The JS plugin for Nx contains executors and generators that provide the best experience for developing JavaScript and TypeScript projects. ",
6
6
  "repository": {
@@ -39,8 +39,8 @@
39
39
  "@babel/preset-env": "^7.23.2",
40
40
  "@babel/preset-typescript": "^7.22.5",
41
41
  "@babel/runtime": "^7.22.6",
42
- "@nx/devkit": "22.6.0-pr.34764.c1c3b27",
43
- "@nx/workspace": "22.6.0-pr.34764.c1c3b27",
42
+ "@nx/devkit": "22.6.0-pr.34876.039ddae",
43
+ "@nx/workspace": "22.6.0-pr.34876.039ddae",
44
44
  "@zkochan/js-yaml": "0.0.7",
45
45
  "babel-plugin-const-enum": "^1.0.1",
46
46
  "babel-plugin-macros": "^3.1.0",
@@ -60,7 +60,7 @@
60
60
  "tslib": "^2.3.0"
61
61
  },
62
62
  "devDependencies": {
63
- "nx": "22.6.0-pr.34764.c1c3b27"
63
+ "nx": "22.6.0-pr.34876.039ddae"
64
64
  },
65
65
  "peerDependencies": {
66
66
  "verdaccio": "^6.0.5"
@@ -1 +1 @@
1
- {"version":3,"file":"release-publish.impl.d.ts","sourceRoot":"","sources":["../../../../../../packages/js/src/executors/release-publish/release-publish.impl.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,eAAe,EAEhB,MAAM,YAAY,CAAC;AAQpB,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAiBjD,wBAA8B,WAAW,CACvC,OAAO,EAAE,qBAAqB,EAC9B,OAAO,EAAE,eAAe;;GAsYzB"}
1
+ {"version":3,"file":"release-publish.impl.d.ts","sourceRoot":"","sources":["../../../../../../packages/js/src/executors/release-publish/release-publish.impl.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,eAAe,EAEhB,MAAM,YAAY,CAAC;AAQpB,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAiBjD,wBAA8B,WAAW,CACvC,OAAO,EAAE,qBAAqB,EAC9B,OAAO,EAAE,eAAe;;GAkdzB"}
@@ -23,6 +23,25 @@ function processEnv(color) {
23
23
  }
24
24
  async function runExecutor(options, context) {
25
25
  const pm = (0, devkit_1.detectPackageManager)();
26
+ // Check if npm is installed (needed for dist-tag management and as fallback for view command)
27
+ let isNpmInstalled = false;
28
+ try {
29
+ isNpmInstalled =
30
+ (0, child_process_1.execSync)('npm --version', {
31
+ encoding: 'utf-8',
32
+ windowsHide: true,
33
+ stdio: ['ignore', 'pipe', 'ignore'],
34
+ }).trim() !== '';
35
+ }
36
+ catch {
37
+ // Allow missing npm only when using bun
38
+ if (pm !== 'bun') {
39
+ console.error(`npm was not found in the current environment. This is only supported when using \`bun\` as a package manager, but your detected package manager is "${pm}"`);
40
+ return {
41
+ success: false,
42
+ };
43
+ }
44
+ }
26
45
  /**
27
46
  * We need to check both the env var and the option because the executor may have been triggered
28
47
  * indirectly via dependsOn, in which case the env var will be set, but the option will not.
@@ -83,6 +102,20 @@ Please update the local dependency on "${depName}" to be a valid semantic versio
83
102
  success: true,
84
103
  };
85
104
  }
105
+ /**
106
+ * If version data was provided by the nx release version step, check if this project
107
+ * actually had a new version resolved. If not (newVersion is null), there is nothing
108
+ * to publish, so we can skip this project entirely.
109
+ */
110
+ if (options.nxReleaseVersionData) {
111
+ const projectVersionData = options.nxReleaseVersionData[context.projectName];
112
+ if (projectVersionData && projectVersionData.newVersion === null) {
113
+ console.warn(`Skipped ${packageTxt}, because no new version was resolved for this project`);
114
+ return {
115
+ success: true,
116
+ };
117
+ }
118
+ }
86
119
  const warnFn = (message) => {
87
120
  console.log(chalk.keyword('orange')(message));
88
121
  };
@@ -93,9 +126,13 @@ Please update the local dependency on "${depName}" to be a valid semantic versio
93
126
  registry: options.registry,
94
127
  tag: options.tag,
95
128
  }, warnFn);
96
- const npmViewCommandSegments = [
97
- `npm view ${packageName} versions dist-tags --json --"${registryConfigKey}=${registry}"`,
98
- ];
129
+ // Use bun info when bun is the package manager, otherwise use npm view
130
+ // (npm view works across npm/pnpm/yarn environments and is the established default)
131
+ const npmViewCommandSegments = pm === 'bun'
132
+ ? ['bun info', packageName, `--json --"${registryConfigKey}=${registry}"`]
133
+ : [
134
+ `npm view ${packageName} versions dist-tags --json --"${registryConfigKey}=${registry}"`,
135
+ ];
99
136
  const npmDistTagAddCommandSegments = [
100
137
  `npm dist-tag add ${packageName}@${packageJson.version} ${tag} --"${registryConfigKey}=${registry}"`,
101
138
  ];
@@ -124,80 +161,101 @@ Please update the local dependency on "${depName}" to be a valid semantic versio
124
161
  success: true,
125
162
  };
126
163
  }
127
- // If only one version of a package exists in the registry, versions will be a string instead of an array.
128
- const versions = Array.isArray(resultJson.versions)
129
- ? resultJson.versions
130
- : [resultJson.versions];
131
- if (versions.includes(currentVersion)) {
132
- try {
133
- if (!isDryRun) {
134
- (0, child_process_1.execSync)(npmDistTagAddCommandSegments.join(' '), {
135
- env: processEnv(true),
136
- cwd: context.root,
137
- stdio: 'ignore',
138
- windowsHide: false,
139
- });
140
- console.log(`Added the dist-tag ${tag} to v${currentVersion} for registry ${registry}.\n`);
141
- }
142
- else {
143
- console.log(`Would add the dist-tag ${tag} to v${currentVersion} for registry ${registry}, but ${chalk.keyword('orange')('[dry-run]')} was set.\n`);
144
- }
145
- return {
146
- success: true,
147
- };
148
- }
149
- catch (err) {
164
+ if (isNpmInstalled) {
165
+ // If only one version of a package exists in the registry, versions will be a string instead of an array.
166
+ const versions = Array.isArray(resultJson.versions)
167
+ ? resultJson.versions
168
+ : [resultJson.versions];
169
+ if (versions.includes(currentVersion)) {
150
170
  try {
151
- const stdoutData = JSON.parse(err.stdout?.toString() || '{}');
152
- // If the error is that the package doesn't exist, then we can ignore it because we will be publishing it for the first time in the next step
153
- if (!(stdoutData.error?.code?.includes('E404') &&
154
- stdoutData.error?.summary?.includes('no such package available')) &&
155
- !(err.stderr?.toString().includes('E404') &&
156
- err.stderr?.toString().includes('no such package available'))) {
157
- console.error('npm dist-tag add error:');
158
- // npm returns error.summary and error.detail
159
- if (stdoutData.error?.summary) {
160
- console.error(stdoutData.error.summary);
161
- }
162
- if (stdoutData.error?.detail) {
163
- console.error(stdoutData.error.detail);
164
- }
165
- // pnpm returns error.code and error.message
166
- if (stdoutData.error?.code && !stdoutData.error?.summary) {
167
- console.error(`Error code: ${stdoutData.error.code}`);
168
- }
169
- if (stdoutData.error?.message && !stdoutData.error?.summary) {
170
- console.error(stdoutData.error.message);
171
- }
172
- if (context.isVerbose) {
173
- console.error('npm dist-tag add stdout:');
174
- console.error(JSON.stringify(stdoutData, null, 2));
171
+ if (!isDryRun) {
172
+ (0, child_process_1.execSync)(npmDistTagAddCommandSegments.join(' '), {
173
+ env: processEnv(true),
174
+ cwd: context.root,
175
+ stdio: 'ignore',
176
+ windowsHide: false,
177
+ });
178
+ console.log(`Added the dist-tag ${tag} to v${currentVersion} for registry ${registry}.\n`);
179
+ }
180
+ else {
181
+ console.log(`Would add the dist-tag ${tag} to v${currentVersion} for registry ${registry}, but ${chalk.keyword('orange')('[dry-run]')} was set.\n`);
182
+ }
183
+ return {
184
+ success: true,
185
+ };
186
+ }
187
+ catch (err) {
188
+ try {
189
+ const stdoutData = JSON.parse(err.stdout?.toString() || '{}');
190
+ // If the error is that the package doesn't exist, then we can ignore it because we will be publishing it for the first time in the next step
191
+ if (!(stdoutData.error?.code?.includes('E404') &&
192
+ stdoutData.error?.summary?.includes('no such package available')) &&
193
+ !(err.stderr?.toString().includes('E404') &&
194
+ err.stderr?.toString().includes('no such package available'))) {
195
+ console.error('npm dist-tag add error:');
196
+ // npm returns error.summary and error.detail
197
+ if (stdoutData.error?.summary) {
198
+ console.error(stdoutData.error.summary);
199
+ }
200
+ if (stdoutData.error?.detail) {
201
+ console.error(stdoutData.error.detail);
202
+ }
203
+ // pnpm returns error.code and error.message
204
+ if (stdoutData.error?.code && !stdoutData.error?.summary) {
205
+ console.error(`Error code: ${stdoutData.error.code}`);
206
+ }
207
+ if (stdoutData.error?.message && !stdoutData.error?.summary) {
208
+ console.error(stdoutData.error.message);
209
+ }
210
+ if (context.isVerbose) {
211
+ console.error('npm dist-tag add stdout:');
212
+ console.error(JSON.stringify(stdoutData, null, 2));
213
+ }
214
+ return {
215
+ success: false,
216
+ };
175
217
  }
218
+ }
219
+ catch (err) {
220
+ console.error('Something unexpected went wrong when processing the npm dist-tag add output\n', err);
176
221
  return {
177
222
  success: false,
178
223
  };
179
224
  }
180
225
  }
181
- catch (err) {
182
- console.error('Something unexpected went wrong when processing the npm dist-tag add output\n', err);
183
- return {
184
- success: false,
185
- };
186
- }
187
226
  }
188
227
  }
189
228
  }
190
229
  catch (err) {
191
- const stdoutData = JSON.parse(err.stdout?.toString() || '{}');
192
- // If the error is that the package doesn't exist, then we can ignore it because we will be publishing it for the first time in the next step
193
- if (!(stdoutData.error?.code?.includes('E404') &&
194
- stdoutData.error?.summary?.toLowerCase().includes('not found')) &&
195
- !(err.stderr?.toString().includes('E404') &&
196
- err.stderr?.toString().toLowerCase().includes('not found'))) {
197
- console.error(`Something unexpected went wrong when checking for existing dist-tags.\n`, err);
198
- return {
199
- success: false,
200
- };
230
+ try {
231
+ const stdoutData = JSON.parse(err.stdout?.toString() || '{}');
232
+ // If the error is that the package doesn't exist, then we can ignore it because we will be publishing it for the first time in the next step
233
+ if (!(stdoutData.error?.code?.includes('E404') &&
234
+ stdoutData.error?.summary?.toLowerCase().includes('not found')) &&
235
+ !(err.stderr?.toString().includes('E404') &&
236
+ err.stderr?.toString().toLowerCase().includes('not found')) &&
237
+ // bun uses plain '404' instead of 'E404'
238
+ !(err.stderr?.toString().includes('404') &&
239
+ err.stderr?.toString().toLowerCase().includes('not found'))) {
240
+ console.error(`Something unexpected went wrong when checking for existing dist-tags.\n`, err);
241
+ return {
242
+ success: false,
243
+ };
244
+ }
245
+ }
246
+ catch {
247
+ // JSON parse failed entirely — check stderr/stdout for plain 404
248
+ const stderrStr = err.stderr?.toString() || '';
249
+ const stdoutStr = err.stdout?.toString() || '';
250
+ if (!((stderrStr.includes('404') &&
251
+ stderrStr.toLowerCase().includes('not found')) ||
252
+ (stdoutStr.includes('404') &&
253
+ stdoutStr.toLowerCase().includes('not found')))) {
254
+ console.error(`Something unexpected went wrong when checking for existing dist-tags.\n`, err);
255
+ return {
256
+ success: false,
257
+ };
258
+ }
201
259
  }
202
260
  }
203
261
  }
@@ -6,4 +6,8 @@ export interface PublishExecutorSchema {
6
6
  dryRun?: boolean;
7
7
  access?: 'public' | 'restricted';
8
8
  firstRelease?: boolean;
9
+ nxReleaseVersionData?: Record<
10
+ string,
11
+ { currentVersion: string; newVersion: string | null; [key: string]: any }
12
+ >;
9
13
  }
@@ -456,16 +456,17 @@ function getInputs(namedInputs, config, tsConfig, internalProjectReferences, wor
456
456
  if (excludePaths.size) {
457
457
  inputs.push(...Array.from(excludePaths).map((p) => `!${pathToInputOrOutput((0, devkit_1.joinPathFragments)(config.project.root, p), workspaceRoot, config.project)}`));
458
458
  }
459
- if (hasExternalProjectReferences(config.originalPath, tsConfig, workspaceRoot, config.project, cache)) {
460
- // tsc --build reads .d.ts and .tsbuildinfo files from referenced projects
461
- // https://www.typescriptlang.org/docs/handbook/project-references.html#what-is-a-project-reference
462
- inputs.push({
463
- dependentTasksOutputFiles: '**/*.{d.ts,tsbuildinfo}',
464
- });
465
- }
466
- else {
467
- inputs.push('production' in namedInputs ? '^production' : '^default');
468
- }
459
+ // tsc --build reads .d.ts and .tsbuildinfo files from dependent tasks, not
460
+ // the source files of dependencies. This correctly tracks build outputs from
461
+ // both external project references and same-project task dependencies (e.g.
462
+ // build-native producing .d.ts files that may be excluded from file watching
463
+ // via .nxignore).
464
+ inputs.push({
465
+ dependentTasksOutputFiles: '**/*.{d.ts,tsbuildinfo}',
466
+ transitive: true,
467
+ });
468
+ const externalRefPatterns = getExternalProjectReferenceTsconfigPatterns(tsConfig, internalProjectReferences, workspaceRoot, config.project, cache);
469
+ inputs.push(...externalRefPatterns);
469
470
  // inputs.push({ externalDependencies });
470
471
  return inputs;
471
472
  }
@@ -617,33 +618,68 @@ function resolveShallowExternalProjectReferences(tsConfig, workspaceRoot, projec
617
618
  }
618
619
  return projectReferences;
619
620
  }
620
- function hasExternalProjectReferences(tsConfigPath, tsConfig, workspaceRoot, project, cache, seen = new Set()) {
621
- if (!tsConfig.projectReferences?.length) {
622
- return false;
621
+ /**
622
+ * Collects unique tsconfig paths (relative to their project root) from the
623
+ * project reference chain and returns them as `^{projectRoot}/...` input
624
+ * patterns. We only need to discover the full set of distinct relative paths
625
+ * from the reference chain.
626
+ */
627
+ function getExternalProjectReferenceTsconfigPatterns(tsConfig, internalProjectReferences, workspaceRoot, project, cache) {
628
+ const externalRefs = {};
629
+ // Collect direct external references from the root tsconfig
630
+ resolveShallowExternalProjectReferences(tsConfig, workspaceRoot, project, cache, externalRefs);
631
+ // Collect external references from internal project references
632
+ for (const refTsConfig of Object.values(internalProjectReferences)) {
633
+ resolveShallowExternalProjectReferences(refTsConfig, workspaceRoot, project, cache, externalRefs);
634
+ }
635
+ // Collect unique tsconfig paths (relative to project root) from the
636
+ // reference chain, seeded with the external refs.
637
+ const uniqueRelPaths = new Set();
638
+ const visited = new Set();
639
+ const worklist = [];
640
+ for (const refConfigPath of Object.keys(externalRefs)) {
641
+ const refContext = getConfigContext(refConfigPath, workspaceRoot, cache);
642
+ uniqueRelPaths.add(posixRelative(refContext.project.absolute, refConfigPath));
643
+ worklist.push({
644
+ configPath: refConfigPath,
645
+ ownerProject: refContext.project,
646
+ });
623
647
  }
624
- seen.add(tsConfigPath);
625
- for (const ref of tsConfig.projectReferences) {
626
- let refConfigPath = ref.path;
627
- if (seen.has(refConfigPath)) {
648
+ for (let i = 0; i < worklist.length; i++) {
649
+ const { configPath, ownerProject } = worklist[i];
650
+ if (visited.has(configPath)) {
628
651
  continue;
629
652
  }
630
- if (!(0, node_fs_1.existsSync)(refConfigPath)) {
653
+ visited.add(configPath);
654
+ const wsRelPath = posixRelative(workspaceRoot, configPath);
655
+ const tsConfigData = tsConfigCacheData[wsRelPath]?.data;
656
+ if (!tsConfigData?.projectReferences?.length) {
631
657
  continue;
632
658
  }
633
- if (!refConfigPath.endsWith('.json')) {
634
- refConfigPath = (0, node_path_1.join)(refConfigPath, 'tsconfig.json');
635
- }
636
- const refContext = getConfigContext(refConfigPath, workspaceRoot, cache);
637
- if (isExternalProjectReference(refContext, project, workspaceRoot, cache)) {
638
- return true;
639
- }
640
- const refTsConfig = retrieveTsConfigFromCache(refConfigPath, workspaceRoot, cache);
641
- const result = hasExternalProjectReferences(refConfigPath, refTsConfig, workspaceRoot, project, cache, seen);
642
- if (result) {
643
- return true;
659
+ for (const ref of tsConfigData.projectReferences) {
660
+ let refPath = ref.path;
661
+ if (!refPath.endsWith('.json')) {
662
+ refPath = (0, node_path_1.join)(refPath, 'tsconfig.json');
663
+ }
664
+ // Skip references not found in the tsconfig cache
665
+ const refWsRelPath = posixRelative(workspaceRoot, refPath);
666
+ if (!tsConfigCacheData[refWsRelPath]) {
667
+ continue;
668
+ }
669
+ const refContext = getConfigContext(refPath, workspaceRoot, cache);
670
+ // Collect paths for references within the same project
671
+ if (!isExternalProjectReference(refContext, ownerProject, workspaceRoot, cache)) {
672
+ uniqueRelPaths.add(posixRelative(ownerProject.absolute, refPath));
673
+ }
674
+ if (!visited.has(refPath)) {
675
+ worklist.push({
676
+ configPath: refPath,
677
+ ownerProject: refContext.project,
678
+ });
679
+ }
644
680
  }
645
681
  }
646
- return false;
682
+ return Array.from(uniqueRelPaths).map((relPath) => `^{projectRoot}/${relPath}`);
647
683
  }
648
684
  function isExternalProjectReference(refConfig, project, workspaceRoot, cache) {
649
685
  const owner = cache.configOwners.get(refConfig.relativePath);