@nx/js 23.0.0-beta.21 → 23.0.0-beta.23

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.
@@ -8,17 +8,24 @@ const expectedNpmPublishJsonKeys = [
8
8
  'size',
9
9
  'filename',
10
10
  ];
11
- // Regular expression to match JSON-like objects, including nested objects (which the expected npm publish output will have, e.g. in its "files" array)
12
- // /{(?:[^{}]|{[^{}]*})*}/g
13
- // /{ : Matches the opening brace of a JSON object
14
- // (?: ) : Non-capturing group to apply quantifiers
15
- // [^{}] : Matches any character except for braces
16
- // | : OR
17
- // {[^{}]*} : Matches nested JSON objects
18
- // * : The non-capturing group (i.e. any character except for braces OR nested JSON objects) can repeat zero or more times
19
- // } : Matches the closing brace of a JSON object
20
- // /g : Global flag to match all occurrences in the string
21
- const jsonRegex = /{(?:[^{}]|{[^{}]*})*}/g;
11
+ // Regular expression to match JSON-like objects, including up to two levels of
12
+ // nested objects.
13
+ // /{(?:[^{}]|{(?:[^{}]|{[^{}]*})*})*}/g
14
+ // Two levels of nesting are required to support both shapes of npm/pnpm publish
15
+ // output:
16
+ // - Older npm (<= 11.13) prints the publish summary as a flat object whose only
17
+ // nesting is its own "files" array (one level deep).
18
+ // - Newer npm (>= 11.16, bundled with Node 26) nests that same summary under the
19
+ // package name, e.g. { "@scope/pkg": { ...id/name/files... } }, adding a
20
+ // second level. pnpm publish nests the same way when run from the workspace
21
+ // root. Matching two levels lets us capture the wrapper object in the nested
22
+ // case so its braces are not left behind in beforeJsonData/afterJsonData.
23
+ const jsonRegex = /{(?:[^{}]|{(?:[^{}]|{[^{}]*})*})*}/g;
24
+ function isNpmPublishSummary(value) {
25
+ return (typeof value === 'object' &&
26
+ value !== null &&
27
+ expectedNpmPublishJsonKeys.every((key) => value[key] !== undefined));
28
+ }
22
29
  function extractNpmPublishJsonData(str) {
23
30
  const jsonMatches = str.match(jsonRegex);
24
31
  if (jsonMatches) {
@@ -28,21 +35,39 @@ function extractNpmPublishJsonData(str) {
28
35
  continue;
29
36
  }
30
37
  // Full JSON parsing to identify the JSON object
38
+ let parsedJson;
31
39
  try {
32
- const parsedJson = JSON.parse(match);
33
- if (!expectedNpmPublishJsonKeys.every((key) => parsedJson[key] !== undefined)) {
34
- continue;
35
- }
36
- const jsonStartIndex = str.indexOf(match);
37
- return {
38
- beforeJsonData: str.slice(0, jsonStartIndex),
39
- jsonData: parsedJson,
40
- afterJsonData: str.slice(jsonStartIndex + match.length),
41
- };
40
+ parsedJson = JSON.parse(match);
42
41
  }
43
42
  catch {
44
43
  // Ignore parsing errors for unrelated JSON blocks
44
+ continue;
45
+ }
46
+ // npm <= 11.13 emits the summary as a flat object, while npm >= 11.16 (and
47
+ // pnpm publish run from the workspace root) nest it one level deep under the
48
+ // package name. Support both by unwrapping a single level when the matched
49
+ // object isn't itself the summary.
50
+ let publishData = null;
51
+ if (isNpmPublishSummary(parsedJson)) {
52
+ publishData = parsedJson;
53
+ }
54
+ else if (typeof parsedJson === 'object' && parsedJson !== null) {
55
+ for (const value of Object.values(parsedJson)) {
56
+ if (isNpmPublishSummary(value)) {
57
+ publishData = value;
58
+ break;
59
+ }
60
+ }
61
+ }
62
+ if (!publishData) {
63
+ continue;
45
64
  }
65
+ const jsonStartIndex = str.indexOf(match);
66
+ return {
67
+ beforeJsonData: str.slice(0, jsonStartIndex),
68
+ jsonData: publishData,
69
+ afterJsonData: str.slice(jsonStartIndex + match.length),
70
+ };
46
71
  }
47
72
  }
48
73
  // No applicable jsonData detected, the whole contents is the beforeJsonData
@@ -21,6 +21,23 @@ function processEnv(color) {
21
21
  }
22
22
  return env;
23
23
  }
24
+ function isAlreadyPublishedPublishError(stdoutData, stderr = '', stdout = '') {
25
+ const error = stdoutData?.error;
26
+ const errorMessage = [
27
+ error?.summary,
28
+ error?.detail,
29
+ error?.message,
30
+ error?.body?.error,
31
+ stderr,
32
+ stdout,
33
+ ]
34
+ .filter(Boolean)
35
+ .join('\n');
36
+ return (error?.code === 'EPUBLISHCONFLICT' ||
37
+ errorMessage.includes('You cannot publish over the previously published versions') ||
38
+ (error?.code === 'E409' &&
39
+ errorMessage.includes('this package is already present')));
40
+ }
24
41
  async function runExecutor(options, context) {
25
42
  const pm = (0, devkit_1.detectPackageManager)();
26
43
  // Check if npm is installed (needed for dist-tag management and as fallback for view command)
@@ -278,10 +295,11 @@ Please update the local dependency on "${depName}" to be a valid semantic versio
278
295
  tag,
279
296
  isDryRun,
280
297
  isNpmInstalled,
298
+ packageTxt,
281
299
  });
282
300
  }
283
301
  function runPublish(ctx) {
284
- const { pm, options, context, packageRoot, packageJson, registry, registryConfigKey, tag, isDryRun, isNpmInstalled, } = ctx;
302
+ const { pm, options, context, packageRoot, packageJson, registry, registryConfigKey, tag, isDryRun, isNpmInstalled, packageTxt, } = ctx;
285
303
  const pmCommand = (0, devkit_1.getPackageManagerCommand)(pm);
286
304
  const publishCommandSegments = [
287
305
  pmCommand.publish(packageRoot, registry, registryConfigKey, tag),
@@ -382,12 +400,26 @@ function runPublish(ctx) {
382
400
  stdoutData = JSON.parse(err.stdout?.toString() || '{}');
383
401
  }
384
402
  catch {
403
+ const stderr = err.stderr?.toString() || '';
404
+ const stdout = err.stdout?.toString() || '';
405
+ if (isAlreadyPublishedPublishError(undefined, stderr, stdout)) {
406
+ console.warn(`Skipped ${packageTxt}, as v${packageJson.version} has already been published to ${registry} with tag "${tag}"`);
407
+ return {
408
+ success: true,
409
+ };
410
+ }
385
411
  console.error(err.stderr?.toString() || '');
386
412
  console.error(err.stdout?.toString() || '');
387
413
  return {
388
414
  success: false,
389
415
  };
390
416
  }
417
+ if (isAlreadyPublishedPublishError(stdoutData, err.stderr?.toString() || '', err.stdout?.toString() || '')) {
418
+ console.warn(`Skipped ${packageTxt}, as v${packageJson.version} has already been published to ${registry} with tag "${tag}"`);
419
+ return {
420
+ success: true,
421
+ };
422
+ }
391
423
  console.error(`${pm} publish error:`);
392
424
  // npm returns error.summary and error.detail
393
425
  if (stdoutData.error?.summary) {
@@ -1,4 +1,4 @@
1
- import { type CreateDependencies, type CreateNodesV2 } from '@nx/devkit';
1
+ import { type CreateDependencies, type CreateNodes } from '@nx/devkit';
2
2
  export interface TscPluginOptions {
3
3
  compiler?: 'tsc' | 'tsgo';
4
4
  typecheck?: boolean | {
@@ -19,5 +19,5 @@ export interface TscPluginOptions {
19
19
  */
20
20
  export declare const createDependencies: CreateDependencies;
21
21
  export declare const PLUGIN_NAME = "@nx/js/typescript";
22
- export declare const createNodesV2: CreateNodesV2<TscPluginOptions>;
23
- export declare const createNodes: CreateNodesV2<TscPluginOptions>;
22
+ export declare const createNodesV2: CreateNodes<TscPluginOptions>;
23
+ export declare const createNodes: CreateNodes<TscPluginOptions>;
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ensureProjectIsIncludedInPluginRegistrations = ensureProjectIsIncludedInPluginRegistrations;
4
4
  const devkit_internals_1 = require("nx/src/devkit-internals");
5
+ const picomatch = require("picomatch");
5
6
  function ensureProjectIsIncludedInPluginRegistrations(nxJson, projectRoot, buildTargetName) {
6
7
  nxJson.plugins ??= [];
7
8
  let isIncluded = false;
@@ -26,7 +27,13 @@ function ensureProjectIsIncludedInPluginRegistrations(nxJson, projectRoot, build
26
27
  }
27
28
  else {
28
29
  // check if the project would be included by the plugin registration
29
- const matchingConfigFiles = (0, devkit_internals_1.findMatchingConfigFiles)([`${projectRoot}/tsconfig.json`], '**/tsconfig.json', registration.include, registration.exclude);
30
+ // Only consider the tsconfig if the @nx/js/typescript plugin would
31
+ // actually process it (its path matches the plugin's createNodes glob)
32
+ // before the registration's include/exclude filters are applied.
33
+ const tsconfigPath = `${projectRoot}/tsconfig.json`;
34
+ const matchingConfigFiles = picomatch('**/tsconfig.json', { dot: true })(tsconfigPath)
35
+ ? (0, devkit_internals_1.findMatchingConfigFiles)([tsconfigPath], registration.include, registration.exclude)
36
+ : [];
30
37
  if (matchingConfigFiles.length) {
31
38
  // it's included by the plugin registration, check if the user-specified options would result
32
39
  // in the appropriate build task being inferred, if not, we need to exclude it
@@ -96,7 +96,7 @@ function resolvePathsBaseUrl(tsconfigPath) {
96
96
  const absolute = (0, path_1.resolve)(queue.shift());
97
97
  const dir = (0, path_1.dirname)(absolute);
98
98
  try {
99
- const raw = JSON.parse((0, fs_1.readFileSync)(absolute, 'utf-8'));
99
+ const raw = (0, devkit_1.readJsonFile)(absolute);
100
100
  chain.push({ dir, raw });
101
101
  const exts = raw.extends
102
102
  ? Array.isArray(raw.extends)
package/migrations.json CHANGED
@@ -3,17 +3,20 @@
3
3
  "migrate-development-custom-condition": {
4
4
  "version": "21.5.0-beta.2",
5
5
  "description": "Migrate the legacy 'development' custom condition to a workspace-unique custom condition name.",
6
- "factory": "./dist/src/migrations/update-21-5-0/migrate-development-custom-condition"
6
+ "factory": "./dist/src/migrations/update-21-5-0/migrate-development-custom-condition",
7
+ "documentation": "./dist/src/migrations/update-21-5-0/migrate-development-custom-condition.md"
7
8
  },
8
9
  "remove-external-options-from-js-executors": {
9
10
  "version": "22.0.0-beta.0",
10
11
  "description": "Remove the deprecated `external` and `externalBuildTargets` options from the `@nx/js:swc` and `@nx/js:tsc` executors.",
11
- "factory": "./dist/src/migrations/update-22-0-0/remove-external-options-from-js-executors"
12
+ "factory": "./dist/src/migrations/update-22-0-0/remove-external-options-from-js-executors",
13
+ "documentation": "./dist/src/migrations/update-22-0-0/remove-external-options-from-js-executors.md"
12
14
  },
13
15
  "remove-redundant-ts-project-references": {
14
16
  "version": "22.1.0-rc.1",
15
17
  "description": "Removes redundant TypeScript project references from project's tsconfig.json files when runtime tsconfig files (e.g., tsconfig.lib.json, tsconfig.app.json) exist.",
16
- "factory": "./dist/src/migrations/update-22-1-0/remove-redundant-ts-project-references"
18
+ "factory": "./dist/src/migrations/update-22-1-0/remove-redundant-ts-project-references",
19
+ "documentation": "./dist/src/migrations/update-22-1-0/remove-redundant-ts-project-references.md"
17
20
  },
18
21
  "23-0-0-rewrite-internal-subpath-imports": {
19
22
  "version": "23.0.0-beta.14",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/js",
3
- "version": "23.0.0-beta.21",
3
+ "version": "23.0.0-beta.23",
4
4
  "private": false,
5
5
  "type": "commonjs",
6
6
  "files": [
@@ -144,11 +144,11 @@
144
144
  "source-map-support": "0.5.19",
145
145
  "tinyglobby": "^0.2.12",
146
146
  "tslib": "^2.3.0",
147
- "@nx/workspace": "23.0.0-beta.21",
148
- "@nx/devkit": "23.0.0-beta.21"
147
+ "@nx/workspace": "23.0.0-beta.23",
148
+ "@nx/devkit": "23.0.0-beta.23"
149
149
  },
150
150
  "devDependencies": {
151
- "nx": "23.0.0-beta.21"
151
+ "nx": "23.0.0-beta.23"
152
152
  },
153
153
  "peerDependencies": {
154
154
  "@swc/cli": ">=0.6.0 <0.9.0",