@nx/devkit 23.1.0-canary.20260706-71a511d → 23.1.0-canary.20260709-b95c507

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.
@@ -0,0 +1,9 @@
1
+ import { type Tree } from 'nx/src/devkit-exports';
2
+ import type { CatalogDefinitions } from './types';
3
+ export declare function readCatalogConfigFromFs(filename: string, fullPath: string): CatalogDefinitions | null;
4
+ export declare function readCatalogConfigFromTree(filename: string, tree: Tree): CatalogDefinitions | null;
5
+ export declare function updateCatalogVersionsInFile(filename: string, treeOrRoot: Tree | string, updates: Array<{
6
+ packageName: string;
7
+ version: string;
8
+ catalogName?: string;
9
+ }>): void;
@@ -0,0 +1,215 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.readCatalogConfigFromFs = readCatalogConfigFromFs;
4
+ exports.readCatalogConfigFromTree = readCatalogConfigFromTree;
5
+ exports.updateCatalogVersionsInFile = updateCatalogVersionsInFile;
6
+ // Keep in sync with packages/nx/src/utils/catalog/manager-utils.ts; the body below
7
+ // the imports is duplicated because @nx/devkit supports a range of nx majors and
8
+ // this logic isn't part of the nx surface it can import across that range.
9
+ const js_yaml_1 = require("@zkochan/js-yaml");
10
+ const node_fs_1 = require("node:fs");
11
+ const node_path_1 = require("node:path");
12
+ const devkit_exports_1 = require("nx/src/devkit-exports");
13
+ const devkit_internals_1 = require("nx/src/devkit-internals");
14
+ const yaml_1 = require("yaml");
15
+ // Walks `path` resolving aliases at every step so structural checks can
16
+ // see through `key: *anchor` references. Neither `doc.getIn` nor
17
+ // `doc.hasIn` traverse aliases on their own. Returns the resolved node, or
18
+ // `undefined` if any ancestor isn't a map.
19
+ function resolveAt(doc, path) {
20
+ let node = doc.contents;
21
+ for (let i = 0; i < path.length; i++) {
22
+ if ((0, yaml_1.isAlias)(node))
23
+ node = node.resolve(doc);
24
+ if (!(0, yaml_1.isMap)(node))
25
+ return undefined;
26
+ node = node.get(path[i], true);
27
+ }
28
+ if ((0, yaml_1.isAlias)(node))
29
+ node = node.resolve(doc);
30
+ return node;
31
+ }
32
+ function isMapAt(doc, path) {
33
+ return (0, yaml_1.isMap)(resolveAt(doc, path));
34
+ }
35
+ function existsAt(doc, path) {
36
+ return resolveAt(doc, path) !== undefined;
37
+ }
38
+ // `doc.getIn` does not traverse aliases. For aliased paths it returns
39
+ // undefined even when the resolved node has a value. Use the alias-aware
40
+ // walk and unwrap scalar nodes to their JS value.
41
+ function getValueAt(doc, path) {
42
+ const node = resolveAt(doc, path);
43
+ return (0, yaml_1.isScalar)(node) ? node.value : node;
44
+ }
45
+ // Walks `targetPath` resolving aliases at every step and mutates the
46
+ // resolved map directly so anchors are preserved. When a step is missing
47
+ // or holds a null placeholder (`key:` with no value), creates a fresh map
48
+ // inside the current parent and carries over the placeholder's comments
49
+ // and anchor so they aren't dropped. A dropped anchor would leave any
50
+ // alias referencing it unresolved and make `String(doc)` throw. Falls back
51
+ // to `doc.setIn` when the current parent isn't a map: an empty-document
52
+ // root gets bootstrapped, while a non-map value where a catalog map was
53
+ // expected makes `setIn` throw, surfacing the malformed config.
54
+ function setThroughAliases(doc, targetPath, value) {
55
+ let parent = doc.contents;
56
+ if ((0, yaml_1.isAlias)(parent))
57
+ parent = parent.resolve(doc);
58
+ for (let i = 0; i < targetPath.length - 1; i++) {
59
+ if (!(0, yaml_1.isMap)(parent)) {
60
+ doc.setIn(targetPath, value);
61
+ return;
62
+ }
63
+ let next = parent.get(targetPath[i], true);
64
+ const nextWasAlias = (0, yaml_1.isAlias)(next);
65
+ if ((0, yaml_1.isAlias)(next))
66
+ next = next.resolve(doc);
67
+ const placeholder = (0, yaml_1.isScalar)(next) && next.value === null ? next : undefined;
68
+ if (next === undefined || placeholder) {
69
+ let cur = parent;
70
+ for (let j = i; j < targetPath.length - 1; j++) {
71
+ const fresh = new yaml_1.YAMLMap();
72
+ if (j === i && placeholder) {
73
+ if (placeholder.comment)
74
+ fresh.comment = placeholder.comment;
75
+ if (placeholder.commentBefore)
76
+ fresh.commentBefore = placeholder.commentBefore;
77
+ // Copy the anchor only for a directly-held placeholder. When it
78
+ // was reached through an alias, the anchor still lives on the
79
+ // definition node, so re-emitting it here would duplicate it.
80
+ if (!nextWasAlias && placeholder.anchor)
81
+ fresh.anchor = placeholder.anchor;
82
+ }
83
+ cur.set(targetPath[j], fresh);
84
+ cur = fresh;
85
+ }
86
+ cur.set(targetPath[targetPath.length - 1], value);
87
+ return;
88
+ }
89
+ parent = next;
90
+ }
91
+ if (!(0, yaml_1.isMap)(parent)) {
92
+ doc.setIn(targetPath, value);
93
+ return;
94
+ }
95
+ parent.set(targetPath[targetPath.length - 1], value);
96
+ }
97
+ function readCatalogConfigFromFs(filename, fullPath) {
98
+ try {
99
+ return (0, devkit_internals_1.readYamlFile)(fullPath);
100
+ }
101
+ catch (error) {
102
+ devkit_exports_1.output.warn({
103
+ title: `Unable to parse ${filename}`,
104
+ bodyLines: [error.toString()],
105
+ });
106
+ return null;
107
+ }
108
+ }
109
+ function readCatalogConfigFromTree(filename, tree) {
110
+ const content = tree.read(filename, 'utf-8');
111
+ try {
112
+ return (0, js_yaml_1.load)(content, { filename });
113
+ }
114
+ catch (error) {
115
+ devkit_exports_1.output.warn({
116
+ title: `Unable to parse ${filename}`,
117
+ bodyLines: [error.toString()],
118
+ });
119
+ return null;
120
+ }
121
+ }
122
+ function updateCatalogVersionsInFile(filename, treeOrRoot, updates) {
123
+ let checkExists;
124
+ let readYaml;
125
+ let writeYaml;
126
+ if (typeof treeOrRoot === 'string') {
127
+ const configPath = (0, node_path_1.join)(treeOrRoot, filename);
128
+ checkExists = () => (0, node_fs_1.existsSync)(configPath);
129
+ readYaml = () => (0, node_fs_1.readFileSync)(configPath, 'utf-8');
130
+ writeYaml = (content) => (0, node_fs_1.writeFileSync)(configPath, content, 'utf-8');
131
+ }
132
+ else {
133
+ checkExists = () => treeOrRoot.exists(filename);
134
+ readYaml = () => treeOrRoot.read(filename, 'utf-8');
135
+ writeYaml = (content) => treeOrRoot.write(filename, content);
136
+ }
137
+ if (!checkExists()) {
138
+ devkit_exports_1.output.warn({
139
+ title: `No ${filename} found`,
140
+ bodyLines: [
141
+ `Cannot update catalog versions without a ${filename} file.`,
142
+ `Create a ${filename} file to use catalogs.`,
143
+ ],
144
+ });
145
+ return;
146
+ }
147
+ try {
148
+ // parseDocument keeps comments and anchors so a catalog bump doesn't
149
+ // rewrite the user's config file.
150
+ const lineCounter = new yaml_1.LineCounter();
151
+ const doc = (0, yaml_1.parseDocument)(readYaml(), { lineCounter });
152
+ // parseDocument collects syntax errors instead of throwing; surface them
153
+ // now, with their line/column detail, rather than failing later in
154
+ // `String(doc)` with a generic message or skipping a no-op write on a
155
+ // malformed file (the previous js-yaml `load()` threw here).
156
+ if (doc.errors.length > 0) {
157
+ throw new Error(doc.errors.map((e) => e.message).join('\n'));
158
+ }
159
+ // A dangling alias (`*ref` with no matching `&ref`) is not a syntax error,
160
+ // so parseDocument leaves it out of doc.errors. Surface it here with the
161
+ // same line/column detail the old js-yaml `load()` reported; otherwise a
162
+ // broken reference is silently overwritten or written back untouched.
163
+ const unresolvedAliases = [];
164
+ (0, yaml_1.visit)(doc, {
165
+ Alias(_key, node) {
166
+ if (node.resolve(doc) !== undefined)
167
+ return;
168
+ const pos = node.range ? lineCounter.linePos(node.range[0]) : undefined;
169
+ unresolvedAliases.push(pos
170
+ ? `Unresolved alias "${node.source}" at line ${pos.line}, column ${pos.col}`
171
+ : `Unresolved alias "${node.source}"`);
172
+ },
173
+ });
174
+ if (unresolvedAliases.length > 0) {
175
+ throw new Error(unresolvedAliases.join('\n'));
176
+ }
177
+ let hasChanges = false;
178
+ for (const update of updates) {
179
+ const { packageName, version, catalogName } = update;
180
+ const normalizedCatalogName = catalogName === 'default' ? undefined : catalogName;
181
+ let targetPath;
182
+ if (!normalizedCatalogName) {
183
+ // An empty `catalog:` placeholder must not claim the default route
184
+ // when `catalogs.default` is populated; that would create a
185
+ // duplicate-default config rejected by pnpm.
186
+ if (isMapAt(doc, ['catalog'])) {
187
+ targetPath = ['catalog', packageName];
188
+ }
189
+ else if (existsAt(doc, ['catalogs', 'default'])) {
190
+ targetPath = ['catalogs', 'default', packageName];
191
+ }
192
+ else {
193
+ targetPath = ['catalog', packageName];
194
+ }
195
+ }
196
+ else {
197
+ targetPath = ['catalogs', normalizedCatalogName, packageName];
198
+ }
199
+ if (getValueAt(doc, targetPath) !== version) {
200
+ setThroughAliases(doc, targetPath, version);
201
+ hasChanges = true;
202
+ }
203
+ }
204
+ if (hasChanges) {
205
+ writeYaml(String(doc));
206
+ }
207
+ }
208
+ catch (error) {
209
+ devkit_exports_1.output.error({
210
+ title: 'Failed to update catalog versions',
211
+ bodyLines: [error instanceof Error ? error.message : String(error)],
212
+ });
213
+ throw error;
214
+ }
215
+ }
@@ -1,12 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PnpmCatalogManager = void 0;
4
- const js_yaml_1 = require("@zkochan/js-yaml");
5
4
  const node_fs_1 = require("node:fs");
6
5
  const node_path_1 = require("node:path");
7
- const devkit_exports_1 = require("nx/src/devkit-exports");
8
- const devkit_internals_1 = require("nx/src/devkit-internals");
9
6
  const manager_1 = require("./manager");
7
+ const manager_utils_1 = require("./manager-utils");
10
8
  const PNPM_WORKSPACE_FILENAME = 'pnpm-workspace.yaml';
11
9
  /**
12
10
  * PNPM-specific catalog manager implementation
@@ -40,13 +38,13 @@ class PnpmCatalogManager {
40
38
  if (!(0, node_fs_1.existsSync)(configPath)) {
41
39
  return null;
42
40
  }
43
- return readConfigFromFs(configPath);
41
+ return (0, manager_utils_1.readCatalogConfigFromFs)(PNPM_WORKSPACE_FILENAME, configPath);
44
42
  }
45
43
  else {
46
44
  if (!treeOrRoot.exists(PNPM_WORKSPACE_FILENAME)) {
47
45
  return null;
48
46
  }
49
- return readConfigFromTree(treeOrRoot, PNPM_WORKSPACE_FILENAME);
47
+ return (0, manager_utils_1.readCatalogConfigFromTree)(PNPM_WORKSPACE_FILENAME, treeOrRoot);
50
48
  }
51
49
  }
52
50
  resolveCatalogReference(treeOrRoot, packageName, version) {
@@ -147,103 +145,7 @@ class PnpmCatalogManager {
147
145
  }
148
146
  }
149
147
  updateCatalogVersions(treeOrRoot, updates) {
150
- let checkExists;
151
- let readYaml;
152
- let writeYaml;
153
- if (typeof treeOrRoot === 'string') {
154
- const configPath = (0, node_path_1.join)(treeOrRoot, PNPM_WORKSPACE_FILENAME);
155
- checkExists = () => (0, node_fs_1.existsSync)(configPath);
156
- readYaml = () => (0, node_fs_1.readFileSync)(configPath, 'utf-8');
157
- writeYaml = (content) => (0, node_fs_1.writeFileSync)(configPath, content, 'utf-8');
158
- }
159
- else {
160
- checkExists = () => treeOrRoot.exists(PNPM_WORKSPACE_FILENAME);
161
- readYaml = () => treeOrRoot.read(PNPM_WORKSPACE_FILENAME, 'utf-8');
162
- writeYaml = (content) => treeOrRoot.write(PNPM_WORKSPACE_FILENAME, content);
163
- }
164
- if (!checkExists()) {
165
- devkit_exports_1.output.warn({
166
- title: `No ${PNPM_WORKSPACE_FILENAME} found`,
167
- bodyLines: [
168
- `Cannot update catalog versions without a ${PNPM_WORKSPACE_FILENAME} file.`,
169
- `Create a ${PNPM_WORKSPACE_FILENAME} file to use catalogs.`,
170
- ],
171
- });
172
- return;
173
- }
174
- try {
175
- const configContent = readYaml();
176
- const configData = (0, js_yaml_1.load)(configContent) || {};
177
- let hasChanges = false;
178
- for (const update of updates) {
179
- const { packageName, version, catalogName } = update;
180
- const normalizedCatalogName = catalogName === 'default' ? undefined : catalogName;
181
- let targetCatalog;
182
- if (!normalizedCatalogName) {
183
- // Default catalog - update whichever exists, prefer catalog over catalogs.default
184
- if (configData.catalog) {
185
- targetCatalog = configData.catalog;
186
- }
187
- else if (configData.catalogs?.default) {
188
- targetCatalog = configData.catalogs.default;
189
- }
190
- else {
191
- // Neither exists, create catalog (shorthand syntax)
192
- configData.catalog ??= {};
193
- targetCatalog = configData.catalog;
194
- }
195
- }
196
- else {
197
- // Named catalog
198
- configData.catalogs ??= {};
199
- configData.catalogs[normalizedCatalogName] ??= {};
200
- targetCatalog = configData.catalogs[normalizedCatalogName];
201
- }
202
- if (targetCatalog[packageName] !== version) {
203
- targetCatalog[packageName] = version;
204
- hasChanges = true;
205
- }
206
- }
207
- if (hasChanges) {
208
- writeYaml((0, js_yaml_1.dump)(configData, {
209
- indent: 2,
210
- quotingType: '"',
211
- forceQuotes: true,
212
- }));
213
- }
214
- }
215
- catch (error) {
216
- devkit_exports_1.output.error({
217
- title: 'Failed to update catalog versions',
218
- bodyLines: [error instanceof Error ? error.message : String(error)],
219
- });
220
- throw error;
221
- }
148
+ (0, manager_utils_1.updateCatalogVersionsInFile)(PNPM_WORKSPACE_FILENAME, treeOrRoot, updates);
222
149
  }
223
150
  }
224
151
  exports.PnpmCatalogManager = PnpmCatalogManager;
225
- function readConfigFromFs(path) {
226
- try {
227
- return (0, devkit_internals_1.readYamlFile)(path);
228
- }
229
- catch (error) {
230
- devkit_exports_1.output.warn({
231
- title: `Unable to parse ${PNPM_WORKSPACE_FILENAME}`,
232
- bodyLines: [error.toString()],
233
- });
234
- return null;
235
- }
236
- }
237
- function readConfigFromTree(tree, path) {
238
- const content = tree.read(path, 'utf-8');
239
- try {
240
- return (0, js_yaml_1.load)(content, { filename: path });
241
- }
242
- catch (error) {
243
- devkit_exports_1.output.warn({
244
- title: `Unable to parse ${PNPM_WORKSPACE_FILENAME}`,
245
- bodyLines: [error.toString()],
246
- });
247
- return null;
248
- }
249
- }
@@ -1,12 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.YarnCatalogManager = void 0;
4
- const js_yaml_1 = require("@zkochan/js-yaml");
5
4
  const node_fs_1 = require("node:fs");
6
5
  const node_path_1 = require("node:path");
7
- const devkit_exports_1 = require("nx/src/devkit-exports");
8
- const devkit_internals_1 = require("nx/src/devkit-internals");
9
6
  const manager_1 = require("./manager");
7
+ const manager_utils_1 = require("./manager-utils");
10
8
  const YARNRC_FILENAME = '.yarnrc.yml';
11
9
  /**
12
10
  * Yarn Berry (v4+) catalog manager implementation
@@ -40,13 +38,13 @@ class YarnCatalogManager {
40
38
  if (!(0, node_fs_1.existsSync)(configPath)) {
41
39
  return null;
42
40
  }
43
- return readConfigFromFs(configPath);
41
+ return (0, manager_utils_1.readCatalogConfigFromFs)(YARNRC_FILENAME, configPath);
44
42
  }
45
43
  else {
46
44
  if (!treeOrRoot.exists(YARNRC_FILENAME)) {
47
45
  return null;
48
46
  }
49
- return readConfigFromTree(treeOrRoot, YARNRC_FILENAME);
47
+ return (0, manager_utils_1.readCatalogConfigFromTree)(YARNRC_FILENAME, treeOrRoot);
50
48
  }
51
49
  }
52
50
  resolveCatalogReference(treeOrRoot, packageName, version) {
@@ -147,103 +145,7 @@ class YarnCatalogManager {
147
145
  }
148
146
  }
149
147
  updateCatalogVersions(treeOrRoot, updates) {
150
- let checkExists;
151
- let readYaml;
152
- let writeYaml;
153
- if (typeof treeOrRoot === 'string') {
154
- const configPath = (0, node_path_1.join)(treeOrRoot, YARNRC_FILENAME);
155
- checkExists = () => (0, node_fs_1.existsSync)(configPath);
156
- readYaml = () => (0, node_fs_1.readFileSync)(configPath, 'utf-8');
157
- writeYaml = (content) => (0, node_fs_1.writeFileSync)(configPath, content, 'utf-8');
158
- }
159
- else {
160
- checkExists = () => treeOrRoot.exists(YARNRC_FILENAME);
161
- readYaml = () => treeOrRoot.read(YARNRC_FILENAME, 'utf-8');
162
- writeYaml = (content) => treeOrRoot.write(YARNRC_FILENAME, content);
163
- }
164
- if (!checkExists()) {
165
- devkit_exports_1.output.warn({
166
- title: `No ${YARNRC_FILENAME} found`,
167
- bodyLines: [
168
- `Cannot update catalog versions without a ${YARNRC_FILENAME} file.`,
169
- `Create a ${YARNRC_FILENAME} file to use catalogs.`,
170
- ],
171
- });
172
- return;
173
- }
174
- try {
175
- const configContent = readYaml();
176
- const configData = (0, js_yaml_1.load)(configContent) || {};
177
- let hasChanges = false;
178
- for (const update of updates) {
179
- const { packageName, version, catalogName } = update;
180
- const normalizedCatalogName = catalogName === 'default' ? undefined : catalogName;
181
- let targetCatalog;
182
- if (!normalizedCatalogName) {
183
- // Default catalog - update whichever exists, prefer catalog over catalogs.default
184
- if (configData.catalog) {
185
- targetCatalog = configData.catalog;
186
- }
187
- else if (configData.catalogs?.default) {
188
- targetCatalog = configData.catalogs.default;
189
- }
190
- else {
191
- // Neither exists, create catalog (shorthand syntax)
192
- configData.catalog ??= {};
193
- targetCatalog = configData.catalog;
194
- }
195
- }
196
- else {
197
- // Named catalog
198
- configData.catalogs ??= {};
199
- configData.catalogs[normalizedCatalogName] ??= {};
200
- targetCatalog = configData.catalogs[normalizedCatalogName];
201
- }
202
- if (targetCatalog[packageName] !== version) {
203
- targetCatalog[packageName] = version;
204
- hasChanges = true;
205
- }
206
- }
207
- if (hasChanges) {
208
- writeYaml((0, js_yaml_1.dump)(configData, {
209
- indent: 2,
210
- quotingType: '"',
211
- forceQuotes: true,
212
- }));
213
- }
214
- }
215
- catch (error) {
216
- devkit_exports_1.output.error({
217
- title: 'Failed to update catalog versions',
218
- bodyLines: [error instanceof Error ? error.message : String(error)],
219
- });
220
- throw error;
221
- }
148
+ (0, manager_utils_1.updateCatalogVersionsInFile)(YARNRC_FILENAME, treeOrRoot, updates);
222
149
  }
223
150
  }
224
151
  exports.YarnCatalogManager = YarnCatalogManager;
225
- function readConfigFromFs(path) {
226
- try {
227
- return (0, devkit_internals_1.readYamlFile)(path);
228
- }
229
- catch (error) {
230
- devkit_exports_1.output.warn({
231
- title: `Unable to parse ${YARNRC_FILENAME}`,
232
- bodyLines: [error.toString()],
233
- });
234
- return null;
235
- }
236
- }
237
- function readConfigFromTree(tree, path) {
238
- const content = tree.read(path, 'utf-8');
239
- try {
240
- return (0, js_yaml_1.load)(content, { filename: path });
241
- }
242
- catch (error) {
243
- devkit_exports_1.output.warn({
244
- title: `Unable to parse ${YARNRC_FILENAME}`,
245
- bodyLines: [error.toString()],
246
- });
247
- return null;
248
- }
249
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/devkit",
3
- "version": "23.1.0-canary.20260706-71a511d",
3
+ "version": "23.1.0-canary.20260709-b95c507",
4
4
  "private": false,
5
5
  "type": "commonjs",
6
6
  "files": [
@@ -56,11 +56,12 @@
56
56
  "semver": "^7.6.3",
57
57
  "yargs-parser": "21.1.1",
58
58
  "minimatch": "10.2.5",
59
- "enquirer": "~2.3.6"
59
+ "enquirer": "~2.3.6",
60
+ "yaml": "^2.8.3"
60
61
  },
61
62
  "devDependencies": {
62
63
  "jest": "30.3.0",
63
- "nx": "23.1.0-canary.20260706-71a511d"
64
+ "nx": "23.1.0-canary.20260709-b95c507"
64
65
  },
65
66
  "peerDependencies": {
66
67
  "nx": ">= 22 <= 24 || ^23.0.0-0"