@smoothbricks/cli 0.10.3 → 0.10.5

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.
Files changed (115) hide show
  1. package/README.md +9 -13
  2. package/dist/bun/preload.d.ts +13 -0
  3. package/dist/bun/preload.d.ts.map +1 -0
  4. package/dist/bun/preload.js +12 -0
  5. package/dist/cli.js +13 -5
  6. package/dist/generate/index.d.ts.map +1 -1
  7. package/dist/generate/index.js +0 -6
  8. package/dist/github-ci/index.d.ts.map +1 -1
  9. package/dist/github-ci/index.js +52 -16
  10. package/dist/github-ci/outputs.d.ts.map +1 -1
  11. package/dist/github-ci/outputs.js +1 -2
  12. package/dist/lib/cli-package.js +2 -2
  13. package/dist/lib/json.d.ts +120 -11
  14. package/dist/lib/json.d.ts.map +1 -1
  15. package/dist/lib/json.js +319 -29
  16. package/dist/lib/workspace.d.ts +7 -14
  17. package/dist/lib/workspace.d.ts.map +1 -1
  18. package/dist/lib/workspace.js +76 -82
  19. package/dist/monorepo/ci-workflow.d.ts +2 -0
  20. package/dist/monorepo/ci-workflow.d.ts.map +1 -1
  21. package/dist/monorepo/ci-workflow.js +27 -1
  22. package/dist/monorepo/git-config.js +2 -2
  23. package/dist/monorepo/index.d.ts +4 -2
  24. package/dist/monorepo/index.d.ts.map +1 -1
  25. package/dist/monorepo/index.js +19 -3
  26. package/dist/monorepo/lockfile.d.ts +14 -1
  27. package/dist/monorepo/lockfile.d.ts.map +1 -1
  28. package/dist/monorepo/lockfile.js +33 -21
  29. package/dist/monorepo/managed-files.d.ts +11 -0
  30. package/dist/monorepo/managed-files.d.ts.map +1 -1
  31. package/dist/monorepo/managed-files.js +57 -32
  32. package/dist/monorepo/package-policy.d.ts.map +1 -1
  33. package/dist/monorepo/package-policy.js +52 -45
  34. package/dist/monorepo/packed-manifest.d.ts +5 -2
  35. package/dist/monorepo/packed-manifest.d.ts.map +1 -1
  36. package/dist/monorepo/packed-manifest.js +16 -47
  37. package/dist/monorepo/packed-package.d.ts.map +1 -1
  38. package/dist/monorepo/packed-package.js +28 -16
  39. package/dist/monorepo/packs/index.d.ts.map +1 -1
  40. package/dist/monorepo/packs/index.js +14 -5
  41. package/dist/monorepo/publish-workflow.js +3 -1
  42. package/dist/monorepo/runtime.d.ts +15 -0
  43. package/dist/monorepo/runtime.d.ts.map +1 -1
  44. package/dist/monorepo/runtime.js +66 -12
  45. package/dist/monorepo/tool-validation.d.ts +2 -2
  46. package/dist/monorepo/tool-validation.d.ts.map +1 -1
  47. package/dist/monorepo/tool-validation.js +141 -38
  48. package/dist/monorepo/wrangler.d.ts.map +1 -1
  49. package/dist/monorepo/wrangler.js +13 -13
  50. package/dist/nx/index.d.ts +9 -7
  51. package/dist/nx/index.d.ts.map +1 -1
  52. package/dist/nx/index.js +48 -31
  53. package/dist/pr/index.d.ts.map +1 -1
  54. package/dist/pr/index.js +28 -32
  55. package/dist/release/candidates.d.ts +3 -2
  56. package/dist/release/candidates.d.ts.map +1 -1
  57. package/dist/release/candidates.js +4 -5
  58. package/dist/release/index.d.ts +1 -0
  59. package/dist/release/index.d.ts.map +1 -1
  60. package/dist/release/index.js +88 -59
  61. package/dist/wrangler/prepare-env.d.ts +0 -1
  62. package/dist/wrangler/prepare-env.d.ts.map +1 -1
  63. package/dist/wrangler/prepare-env.js +100 -51
  64. package/dist/wrangler/scaffold.d.ts.map +1 -1
  65. package/dist/wrangler/scaffold.js +12 -12
  66. package/managed/raw/envrc +5 -3
  67. package/managed/raw/git-format-staged.yml +19 -1
  68. package/managed/raw/patches/ttsc@0.19.3.patch +67 -0
  69. package/managed/raw/tooling/direnv/github-actions-bootstrap.sh +2 -1
  70. package/managed/raw/tooling/direnv/merge-newer-pins.sh +3 -3
  71. package/managed/raw/tooling/direnv/setup-environment.ts +170 -19
  72. package/managed/raw/tooling/git-hooks/pre-commit.sh +0 -6
  73. package/managed/templates/github/actions/cache-node-modules/action.yml +5 -2
  74. package/managed/templates/github/actions/cache-ttsc-plugins/action.yml +19 -0
  75. package/managed/templates/github/actions/setup-devenv/action.yml +5 -0
  76. package/managed/templates/github/workflows/managed-files.yml +80 -0
  77. package/package.json +15 -4
  78. package/src/bun/preload.ts +12 -0
  79. package/src/cli.ts +20 -8
  80. package/src/generate/index.ts +0 -6
  81. package/src/github-ci/index.ts +49 -18
  82. package/src/github-ci/outputs.ts +1 -2
  83. package/src/lib/cli-package.ts +2 -2
  84. package/src/lib/json.ts +293 -32
  85. package/src/lib/workspace.ts +88 -100
  86. package/src/monorepo/__tests__/ci-workflow.test.ts +3 -3
  87. package/src/monorepo/ci-workflow.ts +27 -1
  88. package/src/monorepo/git-config.ts +2 -2
  89. package/src/monorepo/index.ts +19 -3
  90. package/src/monorepo/lockfile.test.ts +35 -36
  91. package/src/monorepo/lockfile.ts +49 -24
  92. package/src/monorepo/managed-files.test.ts +1 -0
  93. package/src/monorepo/managed-files.ts +62 -38
  94. package/src/monorepo/package-policy.test.ts +20 -50
  95. package/src/monorepo/package-policy.ts +76 -59
  96. package/src/monorepo/packed-manifest.ts +18 -52
  97. package/src/monorepo/packed-package.ts +43 -22
  98. package/src/monorepo/packs/index.ts +14 -5
  99. package/src/monorepo/publish-workflow.ts +3 -1
  100. package/src/monorepo/runtime.test.ts +42 -3
  101. package/src/monorepo/runtime.ts +90 -12
  102. package/src/monorepo/tool-validation.test.ts +38 -16
  103. package/src/monorepo/tool-validation.ts +149 -41
  104. package/src/monorepo/wrangler.test.ts +11 -15
  105. package/src/monorepo/wrangler.ts +15 -15
  106. package/src/nx/index.test.ts +9 -5
  107. package/src/nx/index.ts +69 -42
  108. package/src/pr/index.ts +42 -36
  109. package/src/release/__tests__/candidates.test.ts +5 -4
  110. package/src/release/__tests__/trust-publisher.test.ts +7 -0
  111. package/src/release/candidates.ts +10 -17
  112. package/src/release/index.ts +110 -73
  113. package/src/wrangler/prepare-env.ts +75 -54
  114. package/src/wrangler/scaffold.test.ts +9 -12
  115. package/src/wrangler/scaffold.ts +13 -13
@@ -1,8 +1,25 @@
1
1
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
2
  import { dirname, join } from 'node:path';
3
+ import typia from 'typia';
3
4
  import { cliPackageVersion, isSmoothBricksCodebasePackageName } from '../lib/cli-package.js';
4
- import { getOrCreateRecord, readJsonObject, recordProperty, setStringProperty, writeJsonObject } from '../lib/json.js';
5
+ import { ensureDependencyMap, readJsonObject, setPackageStringField, setStringProperty, writeJsonObject, } from '../lib/json.js';
5
6
  import { readPackageJsonObject } from '../lib/workspace.js';
7
+ const isRegistryPackument = (() => {
8
+ const _io0 = input => "object" === typeof input.versions && null !== input.versions && false === Array.isArray(input.versions) && _io1(input.versions) && (undefined === input["dist-tags"] || "object" === typeof input["dist-tags"] && null !== input["dist-tags"] && false === Array.isArray(input["dist-tags"]) && _io2(input["dist-tags"]));
9
+ const _io1 = input => Object.keys(input).every(key => {
10
+ const value = input[key];
11
+ if (undefined === value)
12
+ return true;
13
+ return true;
14
+ });
15
+ const _io2 = input => Object.keys(input).every(key => {
16
+ const value = input[key];
17
+ if (undefined === value)
18
+ return true;
19
+ return "string" === typeof value;
20
+ });
21
+ return input => "object" === typeof input && null !== input && _io0(input);
22
+ })();
6
23
  const rootDevDependencies = [
7
24
  { name: '@biomejs/biome', fallbackVersion: '^2.3.5', minimumVersion: '2.3.0', prefix: '^' },
8
25
  { name: '@nx/js', fallbackVersion: '23.1.0', minimumVersion: '23.1.0' },
@@ -23,23 +40,34 @@ const rootDevDependencies = [
23
40
  },
24
41
  { name: 'nx', fallbackVersion: '23.1.0', minimumVersion: '23.1.0' },
25
42
  { name: 'prettier', fallbackVersion: '^3.6.1', minimumVersion: '3.6.0', prefix: '^' },
26
- { name: 'ttsc', fallbackVersion: '^0.18.4', minimumVersion: '0.18.4', prefix: '^' },
27
- // Nx and typescript-eslint still load the TypeScript 5.x JavaScript API.
43
+ // Exact pin: Bun patchedDependencies keys are version-locked (see patches/ttsc@0.19.3.patch).
44
+ { name: 'ttsc', fallbackVersion: '0.19.3' },
45
+ // Nx and typescript-eslint still load the TypeScript JS API (6.x).
28
46
  // Compilation is exclusively delegated to ttsc by the Nx plugin targets.
29
- { name: 'typescript', fallbackVersion: '^5.9.3', minimumVersion: '5.9.0', prefix: '^' },
47
+ { name: 'typescript', fallbackVersion: '^6.0.3', minimumVersion: '6.0.0', prefix: '^' },
48
+ // TS7 native compiler for ttsc (TTSC_TSGO_BINARY). Not the unscoped API package.
49
+ // npm alias form required — Bun cannot install @typescript/typescript6 cleanly (bun#33834).
50
+ { name: '@typescript/native', fallbackVersion: 'npm:typescript@^7.0.2' },
30
51
  ];
31
52
  const cliPackageName = '@smoothbricks/cli';
32
53
  const requiredDevenvPackages = ['bun', 'git', 'git-format-staged', 'jq', 'alejandra', 'coreutils', 'gnutar'];
33
- const allowedNodePackages = ['nodejs_24', 'nodejs_latest'];
54
+ // Any explicit nodejs provider is fine — the pinned major is the repo's choice
55
+ // (Lambda parity, org convergence, …). Whether the pins in package.json agree
56
+ // with the runtime is validated against the live PATH (validateRootRuntimeVersions),
57
+ // never against a version template here.
58
+ const nodePackagePattern = /(^|\s)nodejs(_\d+|_latest)?(\s|#|$)/m;
59
+ const TTSC_PATCHED_DEPENDENCY_KEY = 'ttsc@0.19.3';
60
+ const TTSC_PATCH_PATH = 'patches/ttsc@0.19.3.patch';
34
61
  export async function applyToolConfigDefaults(root) {
35
- const context = readToolContext(root);
62
+ const context = await readToolContext(root);
36
63
  await applyRootPackageToolDefaults(root, context);
37
64
  applyToolingPackageDefaults(root, context.policy);
38
65
  applyDevenvPackageDefaults(root);
39
66
  }
40
- export function validateToolConfig(root) {
41
- const context = readToolContext(root);
67
+ export async function validateToolConfig(root) {
68
+ const context = await readToolContext(root);
42
69
  return (validateRootDevDependencies(context.policy, context.rootPackage) +
70
+ validateTtscPatchedDependency(context.rootPackage) +
43
71
  validateToolingPackage(root, context.policy) +
44
72
  validateToolingWorkspace(context.rootPackage) +
45
73
  validateDevenvPackages(root));
@@ -50,7 +78,7 @@ export async function applyRootDevDependencyDefaults(root, context) {
50
78
  return;
51
79
  }
52
80
  let changed = false;
53
- const devDependencies = getOrCreateRecord(pkg, 'devDependencies');
81
+ const devDependencies = ensureDependencyMap(pkg, 'devDependencies');
54
82
  for (const dependency of rootDevDependencies) {
55
83
  const current = devDependencies[dependency.name];
56
84
  if (typeof current !== 'string' || !satisfiesDependencyPolicy(context.policy, current, dependency)) {
@@ -61,6 +89,7 @@ export async function applyRootDevDependencyDefaults(root, context) {
61
89
  if (delete devDependencies['@smoothbricks/cli']) {
62
90
  changed = true;
63
91
  }
92
+ changed = ensureTtscPatchedDependency(pkg) || changed;
64
93
  if (changed) {
65
94
  writeJsonObject(join(root, 'package.json'), pkg);
66
95
  console.log('updated package.json workspace tool dependencies');
@@ -76,7 +105,8 @@ async function applyRootPackageToolDefaults(root, context) {
76
105
  }
77
106
  let dependencyChanged = false;
78
107
  let workspaceChanged = false;
79
- const devDependencies = getOrCreateRecord(pkg, 'devDependencies');
108
+ let patchChanged = false;
109
+ const devDependencies = ensureDependencyMap(pkg, 'devDependencies');
80
110
  for (const dependency of rootDevDependencies) {
81
111
  const current = devDependencies[dependency.name];
82
112
  if (typeof current !== 'string' || !satisfiesDependencyPolicy(context.policy, current, dependency)) {
@@ -88,7 +118,8 @@ async function applyRootPackageToolDefaults(root, context) {
88
118
  dependencyChanged = true;
89
119
  }
90
120
  workspaceChanged = addWorkspacePattern(pkg, 'tooling');
91
- if (dependencyChanged || workspaceChanged) {
121
+ patchChanged = ensureTtscPatchedDependency(pkg);
122
+ if (dependencyChanged || workspaceChanged || patchChanged) {
92
123
  writeJsonObject(join(root, 'package.json'), pkg);
93
124
  }
94
125
  console.log(dependencyChanged
@@ -97,17 +128,20 @@ async function applyRootPackageToolDefaults(root, context) {
97
128
  console.log(workspaceChanged
98
129
  ? 'updated package.json tooling workspace'
99
130
  : 'unchanged package.json tooling workspace');
131
+ console.log(patchChanged
132
+ ? 'updated package.json patchedDependencies for ttsc'
133
+ : 'unchanged package.json patchedDependencies for ttsc');
100
134
  }
101
135
  export function applyToolingPackageDefaults(root, policy) {
102
136
  const path = join(root, 'tooling', 'package.json');
103
137
  const pkg = readJsonObject(path) ?? { name: policy.toolingPackageName, private: true, dependencies: {} };
104
138
  let changed = false;
105
- changed = setStringProperty(pkg, 'name', policy.toolingPackageName) || changed;
139
+ changed = setPackageStringField(pkg, 'name', policy.toolingPackageName) || changed;
106
140
  if (pkg.private !== true) {
107
141
  pkg.private = true;
108
142
  changed = true;
109
143
  }
110
- const dependencies = getOrCreateRecord(pkg, 'dependencies');
144
+ const dependencies = ensureDependencyMap(pkg, 'dependencies');
111
145
  changed = setStringProperty(dependencies, cliPackageName, policy.cliDependencyRange) || changed;
112
146
  if (changed || !existsSync(path)) {
113
147
  mkdirSync(dirname(path), { recursive: true });
@@ -139,7 +173,7 @@ export function applyDevenvPackageDefaults(root) {
139
173
  }
140
174
  let content = readFileSync(path, 'utf8');
141
175
  let changed = false;
142
- if (!allowedNodePackages.some((name) => hasNixPackage(content, name))) {
176
+ if (!nodePackagePattern.test(content)) {
143
177
  const next = addNixPackage(content, 'nodejs_latest', '# Node.js for workspace tooling');
144
178
  changed = next !== content || changed;
145
179
  content = next;
@@ -166,7 +200,7 @@ export function validateRootDevDependencies(policy, rootPackage) {
166
200
  console.error('package.json not found or invalid');
167
201
  return 1;
168
202
  }
169
- const devDependencies = recordProperty(pkg, 'devDependencies');
203
+ const devDependencies = pkg.devDependencies;
170
204
  let failures = 0;
171
205
  for (const dependency of rootDevDependencies) {
172
206
  const version = devDependencies?.[dependency.name];
@@ -185,6 +219,22 @@ export function validateRootDevDependencies(policy, rootPackage) {
185
219
  }
186
220
  return failures;
187
221
  }
222
+ function ensureTtscPatchedDependency(pkg) {
223
+ const patched = ensureDependencyMap(pkg, 'patchedDependencies');
224
+ return setStringProperty(patched, TTSC_PATCHED_DEPENDENCY_KEY, TTSC_PATCH_PATH);
225
+ }
226
+ function validateTtscPatchedDependency(rootPackage) {
227
+ if (!rootPackage) {
228
+ return 0;
229
+ }
230
+ const actual = rootPackage.patchedDependencies?.[TTSC_PATCHED_DEPENDENCY_KEY];
231
+ if (actual === TTSC_PATCH_PATH) {
232
+ return 0;
233
+ }
234
+ console.error(`package.json patchedDependencies.${TTSC_PATCHED_DEPENDENCY_KEY} must be ${TTSC_PATCH_PATH}` +
235
+ (typeof actual === 'string' ? `; found ${actual}` : ' (required for declaration-emit fix)'));
236
+ return 1;
237
+ }
188
238
  export function validateToolingPackage(root, policy) {
189
239
  const path = join(root, 'tooling', 'package.json');
190
240
  const pkg = readJsonObject(path);
@@ -192,9 +242,9 @@ export function validateToolingPackage(root, policy) {
192
242
  console.error('tooling/package.json not found or invalid');
193
243
  return 1;
194
244
  }
195
- const dependencies = recordProperty(pkg, 'dependencies');
245
+ const dependencies = pkg.dependencies;
196
246
  let failures = 0;
197
- const actualName = typeof pkg.name === 'string' ? pkg.name : null;
247
+ const actualName = pkg.name ?? null;
198
248
  if (actualName !== policy.toolingPackageName) {
199
249
  console.error(`tooling/package.json name must be ${policy.toolingPackageName}`);
200
250
  failures++;
@@ -226,8 +276,8 @@ export function validateDevenvPackages(root) {
226
276
  }
227
277
  const content = readFileSync(path, 'utf8');
228
278
  let failures = 0;
229
- if (!allowedNodePackages.some((name) => hasNixPackage(content, name))) {
230
- console.error(`tooling/direnv/devenv.nix packages must include ${allowedNodePackages.join(' or ')}`);
279
+ if (!nodePackagePattern.test(content)) {
280
+ console.error('tooling/direnv/devenv.nix packages must include a nodejs provider (nodejs_<major> or nodejs_latest)');
231
281
  failures++;
232
282
  }
233
283
  for (const name of requiredDevenvPackages) {
@@ -272,6 +322,10 @@ function satisfiesDependencyPolicy(policy, version, dependency) {
272
322
  if (workspaceDependencyExpected(policy, dependency)) {
273
323
  return version === 'workspace:*';
274
324
  }
325
+ // Dual-package native compiler: must stay an npm:typescript@7 alias, never unscoped "typescript".
326
+ if (dependency.name === '@typescript/native') {
327
+ return isTypeScriptNativeAlias(version);
328
+ }
275
329
  if (dependency.minimumVersion === undefined) {
276
330
  return version === dependency.fallbackVersion;
277
331
  }
@@ -282,34 +336,38 @@ function satisfiesDependencyPolicy(policy, version, dependency) {
282
336
  }
283
337
  return compareVersions(parsed, minimum) >= 0;
284
338
  }
339
+ function isTypeScriptNativeAlias(version) {
340
+ // Accept npm:typescript@7, npm:typescript@^7.0.2, npm:typescript@~7.0.2, etc.
341
+ return /^npm:typescript@(?:\^|~)?7(?:\.|$)/.test(version.trim());
342
+ }
285
343
  function formatExpectedDependency(policy, dependency) {
286
344
  if (workspaceDependencyExpected(policy, dependency)) {
287
345
  return 'workspace:*';
288
346
  }
347
+ if (dependency.name === '@typescript/native') {
348
+ return 'npm:typescript@^7 (TypeScript 7 native compiler alias for ttsc)';
349
+ }
289
350
  return dependency.minimumVersion ? `>= ${dependency.minimumVersion}` : dependency.fallbackVersion;
290
351
  }
291
- export function readToolContext(root) {
352
+ export async function readToolContext(root) {
292
353
  const rootPackage = readPackageJsonObject(join(root, 'package.json'));
293
354
  const toolingPackage = readJsonObject(join(root, 'tooling', 'package.json'));
294
- const configuredCliRange = recordProperty(toolingPackage ?? {}, 'dependencies')?.[cliPackageName];
355
+ const configuredCliRange = toolingPackage?.dependencies?.[cliPackageName];
295
356
  return {
296
357
  rootPackage,
297
- policy: toolPolicy(rootPackage, typeof configuredCliRange === 'string' ? configuredCliRange : null),
358
+ policy: await toolPolicy(rootPackage, typeof configuredCliRange === 'string' ? configuredCliRange : null),
298
359
  };
299
360
  }
300
- function toolPolicy(rootPackage, configuredCliRange) {
301
- const name = typeof rootPackage?.name === 'string' ? rootPackage.name : null;
361
+ async function toolPolicy(rootPackage, configuredCliRange) {
362
+ const name = rootPackage?.name ?? null;
302
363
  const isCodebase = isSmoothBricksCodebasePackageName(name ?? undefined);
303
364
  const toolingName = toolingPackageName(name);
304
- // A locally linked prerelease can be newer than every published CLI. Keep an existing
305
- // installable range instead of rewriting the consumer manifest to an unpublished version.
306
- const publishedCliRange = cliPackageVersion.includes('-') && configuredCliRange && parseVersion(configuredCliRange)
307
- ? configuredCliRange
308
- : `^${cliPackageVersion}`;
309
365
  return {
310
366
  isSmoothBricksCodebase: isCodebase,
311
367
  toolingPackageName: toolingName,
312
- cliDependencyRange: isCodebase ? 'workspace:*' : publishedCliRange,
368
+ // Consumers pin the latest *published* CLI. Running a linked prerelease must not
369
+ // freeze tooling/package.json on an older range or rewrite it to an unpublished -next.
370
+ cliDependencyRange: isCodebase ? 'workspace:*' : await resolvePublishedCliDependencyRange(configuredCliRange),
313
371
  };
314
372
  }
315
373
  function toolingPackageName(rootName) {
@@ -330,6 +388,57 @@ async function resolveDependencyVersion(policy, dependency) {
330
388
  const latest = await fetchLatestPatchVersion(dependency.name, dependency.minimumVersion);
331
389
  return `${dependency.prefix ?? ''}${latest ?? stripRangePrefix(dependency.fallbackVersion)}`;
332
390
  }
391
+ /**
392
+ * Consumer monorepos pin `@smoothbricks/cli` to the latest stable release.
393
+ * Prefer npm `dist-tags.latest`. Never write a running `-next` package version into
394
+ * consumer manifests; never leave an older pin just because the running CLI is prerelease.
395
+ */
396
+ async function resolvePublishedCliDependencyRange(configuredCliRange) {
397
+ const latest = await fetchLatestStableVersion(cliPackageName);
398
+ if (latest) {
399
+ return `^${latest}`;
400
+ }
401
+ // Registry unavailable: if the running CLI is a stable publish, use it.
402
+ if (!cliPackageVersion.includes('-')) {
403
+ return `^${cliPackageVersion}`;
404
+ }
405
+ // Linked prerelease + offline down: keep an existing installable stable pin.
406
+ if (configuredCliRange && parseVersion(configuredCliRange)) {
407
+ return configuredCliRange;
408
+ }
409
+ // Last resort: caret of the prerelease base (0.10.5-next.0 → ^0.10.5) so manifests stay valid.
410
+ const base = parseVersion(cliPackageVersion);
411
+ return base ? `^${base.major}.${base.minor}.${base.patch}` : `^${cliPackageVersion}`;
412
+ }
413
+ async function fetchLatestStableVersion(packageName) {
414
+ const url = `https://registry.npmjs.org/${encodeURIComponent(packageName).replace('%40', '@')}`;
415
+ const response = await fetch(url, { headers: { accept: 'application/vnd.npm.install-v1+json' } });
416
+ if (!response.ok) {
417
+ return null;
418
+ }
419
+ const body = await response.json();
420
+ if (!isRegistryPackument(body)) {
421
+ return null;
422
+ }
423
+ const tagged = body['dist-tags']?.latest;
424
+ if (typeof tagged === 'string' && parseVersion(tagged) && !tagged.includes('-')) {
425
+ return tagged;
426
+ }
427
+ let latest = null;
428
+ for (const raw of Object.keys(body.versions)) {
429
+ if (raw.includes('-')) {
430
+ continue;
431
+ }
432
+ const version = parseVersion(raw);
433
+ if (!version) {
434
+ continue;
435
+ }
436
+ if (!latest || compareVersions(version, latest) > 0) {
437
+ latest = version;
438
+ }
439
+ }
440
+ return latest ? `${latest.major}.${latest.minor}.${latest.patch}` : null;
441
+ }
333
442
  async function fetchLatestPatchVersion(packageName, minimumVersion) {
334
443
  const minorRange = sameMajorMinorRange(minimumVersion);
335
444
  const url = `https://registry.npmjs.org/${encodeURIComponent(packageName).replace('%40', '@')}`;
@@ -375,12 +484,6 @@ function latestVersionInSameMajorMinor(versions, minimum) {
375
484
  function compareVersions(left, right) {
376
485
  return left.major - right.major || left.minor - right.minor || left.patch - right.patch;
377
486
  }
378
- function isRegistryPackument(value) {
379
- return typeof value === 'object' && value !== null && 'versions' in value && isObjectRecord(value.versions);
380
- }
381
- function isObjectRecord(value) {
382
- return typeof value === 'object' && value !== null && !Array.isArray(value);
383
- }
384
487
  function stripRangePrefix(version) {
385
488
  return version.replace(/^[~^]/, '');
386
489
  }
@@ -393,7 +496,7 @@ function addWorkspacePattern(pkg, pattern) {
393
496
  workspaces.push(pattern);
394
497
  return true;
395
498
  }
396
- if (isObjectRecord(workspaces) && Array.isArray(workspaces.packages)) {
499
+ if (workspaces && Array.isArray(workspaces.packages)) {
397
500
  if (workspaces.packages.includes(pattern)) {
398
501
  return false;
399
502
  }
@@ -408,5 +511,5 @@ function hasWorkspacePattern(pkg, pattern) {
408
511
  if (Array.isArray(workspaces)) {
409
512
  return workspaces.includes(pattern);
410
513
  }
411
- return isObjectRecord(workspaces) && Array.isArray(workspaces.packages) && workspaces.packages.includes(pattern);
514
+ return Boolean(workspaces && Array.isArray(workspaces.packages) && workspaces.packages.includes(pattern));
412
515
  }
@@ -1 +1 @@
1
- {"version":3,"file":"wrangler.d.ts","sourceRoot":"","sources":["../../src/monorepo/wrangler.ts"],"names":[],"mappings":"AAaA,4HAA4H;AAC5H,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGhE;AAkCD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAiDxD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAgCrD"}
1
+ {"version":3,"file":"wrangler.d.ts","sourceRoot":"","sources":["../../src/monorepo/wrangler.ts"],"names":[],"mappings":"AAaA,4HAA4H;AAC5H,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGhE;AAmCD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAiDxD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA+BrD"}
@@ -1,6 +1,6 @@
1
1
  import { existsSync, readFileSync, writeFileSync } from 'node:fs';
2
- import { join, relative } from 'node:path';
3
- import { getOrCreateRecord, recordProperty, writeJsonObject } from '../lib/json.js';
2
+ import { join } from 'node:path';
3
+ import { ensureNx, ensureNxTargets, writeJsonObject } from '../lib/json.js';
4
4
  import { getWorkspacePackageManifests } from '../lib/workspace.js';
5
5
  /** First `[env.<name>]` header in a wrangler.toml, or `null` when the config declares no envs (top-level bindings only). */
6
6
  export function firstWranglerEnv(tomlText) {
@@ -10,13 +10,14 @@ export function firstWranglerEnv(tomlText) {
10
10
  function wranglerProjects(root) {
11
11
  const projects = [];
12
12
  for (const pkg of getWorkspacePackageManifests(root)) {
13
- const tomlPath = join(pkg.path, 'wrangler.toml');
13
+ const dir = join(root, pkg.path);
14
+ const tomlPath = join(dir, 'wrangler.toml');
14
15
  if (!existsSync(tomlPath)) {
15
16
  continue;
16
17
  }
17
18
  projects.push({
18
- label: relative(root, pkg.path) || '.',
19
- dir: pkg.path,
19
+ label: pkg.path || '.',
20
+ dir,
20
21
  packageJsonPath: pkg.packageJsonPath,
21
22
  json: pkg.json,
22
23
  tomlPath,
@@ -44,8 +45,8 @@ export function applyWranglerDefaults(root) {
44
45
  }
45
46
  for (const project of projects) {
46
47
  const env = firstWranglerEnv(readFileSync(project.tomlPath, 'utf8'));
47
- const nx = getOrCreateRecord(project.json, 'nx');
48
- const targets = getOrCreateRecord(nx, 'targets');
48
+ const nx = ensureNx(project.json);
49
+ const targets = ensureNxTargets(nx);
49
50
  const desired = {
50
51
  executor: 'nx:run-commands',
51
52
  cache: true,
@@ -57,14 +58,14 @@ export function applyWranglerDefaults(root) {
57
58
  },
58
59
  };
59
60
  let changed = false;
60
- const existing = recordProperty(targets, 'wrangler-types');
61
+ const existing = targets['wrangler-types'];
61
62
  if (!existing || JSON.stringify(existing) !== JSON.stringify(desired)) {
62
63
  targets['wrangler-types'] = desired;
63
64
  changed = true;
64
65
  }
65
- const typecheck = recordProperty(targets, 'typecheck');
66
+ const typecheck = targets.typecheck;
66
67
  if (typecheck) {
67
- const dependsOn = Array.isArray(typecheck.dependsOn) ? typecheck.dependsOn : [];
68
+ const dependsOn = Array.isArray(typecheck.dependsOn) ? [...typecheck.dependsOn] : [];
68
69
  if (!dependsOn.includes('wrangler-types')) {
69
70
  dependsOn.push('wrangler-types');
70
71
  typecheck.dependsOn = dependsOn;
@@ -103,9 +104,8 @@ export function validateWrangler(root) {
103
104
  console.log(`⨯ ${project.label}: missing .dev.vars.example`);
104
105
  projectProblems++;
105
106
  }
106
- const nx = recordProperty(project.json, 'nx');
107
- const targets = nx ? recordProperty(nx, 'targets') : null;
108
- if (!targets || !recordProperty(targets, 'wrangler-types')) {
107
+ const targets = project.json.nx?.targets;
108
+ if (!targets?.['wrangler-types']) {
109
109
  console.log(`⨯ ${project.label}: missing wrangler-types nx target`);
110
110
  projectProblems++;
111
111
  }
@@ -1,3 +1,4 @@
1
+ import { type NxProjectJson, type NxTargetConfig } from '../lib/json.js';
1
2
  export interface ProjectTargets {
2
3
  project: string;
3
4
  root?: string;
@@ -15,13 +16,13 @@ export interface CommandInvocation {
15
16
  export declare function nxResetCommand(): CommandInvocation;
16
17
  export declare function nxShowProjectCommand(project: string): CommandInvocation;
17
18
  export declare function nxCacheDirectories(root: string): string[];
18
- export declare function targetNamesFromNxProjectJson(value: unknown): string[];
19
- export declare function projectRootFromNxProjectJson(value: unknown): string | undefined;
20
- export declare function buildDependsOnFromNxProjectJson(value: unknown): string[] | undefined;
21
- export declare function targetDependenciesFromNxProjectJson(value: unknown): Map<string, string[]>;
22
- export declare function targetExecutorsFromNxProjectJson(value: unknown): Map<string, string>;
23
- export declare function targetOutputsFromNxProjectJson(value: unknown): Map<string, string[]>;
24
- export declare function targetScriptsFromNxProjectJson(value: unknown): Map<string, string>;
19
+ export declare function targetNamesFromNxProjectJson(value: NxProjectJson | null | undefined): string[];
20
+ export declare function projectRootFromNxProjectJson(value: NxProjectJson | null | undefined): string | undefined;
21
+ export declare function buildDependsOnFromNxProjectJson(value: NxProjectJson | null | undefined): string[] | undefined;
22
+ export declare function targetDependenciesFromNxProjectJson(value: NxProjectJson | null | undefined): Map<string, string[]>;
23
+ export declare function targetExecutorsFromNxProjectJson(value: NxProjectJson | null | undefined): Map<string, string>;
24
+ export declare function targetOutputsFromNxProjectJson(value: NxProjectJson | null | undefined): Map<string, string[]>;
25
+ export declare function targetScriptsFromNxProjectJson(value: NxProjectJson | null | undefined): Map<string, string>;
25
26
  export declare function formatProjectTargetLines(projects: ProjectTargets[]): string;
26
27
  export declare function projectNamesWithTarget(projects: ProjectTargets[], target: string): string[];
27
28
  export declare function projectNamesFromNxShowProjectsOutput(output: string): string[];
@@ -32,4 +33,5 @@ export declare function listProjects(root: string, options: {
32
33
  export declare function resetCache(root: string): Promise<void>;
33
34
  export declare function cleanCache(root: string): Promise<void>;
34
35
  export declare function readProjectTargets(root: string): Promise<ProjectTargets[]>;
36
+ export type { NxProjectJson, NxTargetConfig };
35
37
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/nx/index.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,kBAAkB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC3C,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACtC,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,wBAAgB,cAAc,IAAI,iBAAiB,CAElD;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,CAEvE;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAEzD;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,CAGrE;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAE/E;AAED,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,GAAG,SAAS,CAEpF;AAED,wBAAgB,mCAAmC,CAAC,KAAK,EAAE,OAAO,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CA2BzF;AAED,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,OAAO,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAYpF;AAED,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,OAAO,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAEpF;AAED,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,OAAO,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAgBlF;AAuBD,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,cAAc,EAAE,GAAG,MAAM,CAK3E;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,cAAc,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAK3F;AAED,wBAAgB,oCAAoC,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAsB7E;AAED,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAK7D;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAQhG;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG5D;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAa5D;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAGhF"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/nx/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,cAAc,EAGpB,MAAM,gBAAgB,CAAC;AAGxB,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,kBAAkB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC3C,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACtC,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,wBAAgB,cAAc,IAAI,iBAAiB,CAElD;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,CAEvE;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAEzD;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,EAAE,CAG9F;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAExG;AAED,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,EAAE,GAAG,SAAS,CAE7G;AAED,wBAAgB,mCAAmC,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,GAAG,SAAS,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAwBlH;AAsBD,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,GAAG,SAAS,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAY7G;AAED,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,GAAG,SAAS,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAE7G;AAED,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,GAAG,SAAS,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAY3G;AA0BD,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,cAAc,EAAE,GAAG,MAAM,CAK3E;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,cAAc,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAK3F;AAED,wBAAgB,oCAAoC,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAsB7E;AAED,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAK7D;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAQhG;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG5D;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAa5D;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAGhF;AA2BD,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,CAAC"}
package/dist/nx/index.js CHANGED
@@ -2,7 +2,7 @@ import { existsSync } from 'node:fs';
2
2
  import { lstat, rm } from 'node:fs/promises';
3
3
  import { join } from 'node:path';
4
4
  import { $ } from 'bun';
5
- import { isRecord, recordProperty } from '../lib/json.js';
5
+ import { parseNxProjectJsonText, parseStringArrayText, } from '../lib/json.js';
6
6
  import { decode, run } from '../lib/run.js';
7
7
  export function nxResetCommand() {
8
8
  return { command: 'nx', args: ['reset'] };
@@ -14,51 +14,66 @@ export function nxCacheDirectories(root) {
14
14
  return [join(root, '.nx/cache'), join(root, '.nx/workspace-data'), join(root, 'node_modules/.cache/nx')];
15
15
  }
16
16
  export function targetNamesFromNxProjectJson(value) {
17
- const targets = isRecord(value) ? recordProperty(value, 'targets') : null;
17
+ const targets = value?.targets;
18
18
  return targets ? Object.keys(targets).sort((a, b) => a.localeCompare(b)) : [];
19
19
  }
20
20
  export function projectRootFromNxProjectJson(value) {
21
- return isRecord(value) && typeof value.root === 'string' ? value.root : undefined;
21
+ return typeof value?.root === 'string' ? value.root : undefined;
22
22
  }
23
23
  export function buildDependsOnFromNxProjectJson(value) {
24
24
  return targetDependenciesFromNxProjectJson(value).get('build');
25
25
  }
26
26
  export function targetDependenciesFromNxProjectJson(value) {
27
- const targets = isRecord(value) ? recordProperty(value, 'targets') : null;
27
+ const targets = value?.targets;
28
28
  const dependencies = new Map();
29
29
  if (!targets) {
30
30
  return dependencies;
31
31
  }
32
32
  for (const [targetName, target] of Object.entries(targets)) {
33
- if (!isRecord(target) || !Array.isArray(target.dependsOn)) {
33
+ if (!target.dependsOn) {
34
34
  continue;
35
35
  }
36
36
  const entries = [];
37
37
  for (const dependency of target.dependsOn) {
38
- if (typeof dependency === 'string') {
39
- entries.push(dependency);
38
+ const local = localDependsOnTarget(dependency);
39
+ if (local === undefined) {
40
+ if (isInvalidDependsOn(dependency)) {
41
+ throw new Error(`Nx target ${targetName} has an invalid dependsOn entry.`);
42
+ }
40
43
  continue;
41
44
  }
42
- if (!isRecord(dependency) || typeof dependency.target !== 'string') {
43
- throw new Error(`Nx target ${targetName} has an invalid dependsOn entry.`);
44
- }
45
- if (dependency.projects !== undefined && dependency.projects !== 'self') {
46
- throw new Error(`Nx target ${targetName} uses unsupported cross-project dependsOn for ${dependency.target}.`);
47
- }
48
- entries.push(dependency.target);
45
+ entries.push(local);
49
46
  }
50
47
  dependencies.set(targetName, entries);
51
48
  }
52
49
  return dependencies;
53
50
  }
51
+ function localDependsOnTarget(dependency) {
52
+ if (typeof dependency === 'string') {
53
+ return dependency;
54
+ }
55
+ if (typeof dependency.target !== 'string') {
56
+ return undefined;
57
+ }
58
+ if (dependency.projects !== undefined && dependency.projects !== 'self') {
59
+ // Target closures are intentionally project-local. Nx schedules explicit
60
+ // cross-project prerequisites itself; treating them as local targets
61
+ // would collect or verify outputs from the wrong project.
62
+ return undefined;
63
+ }
64
+ return dependency.target;
65
+ }
66
+ function isInvalidDependsOn(dependency) {
67
+ return typeof dependency !== 'string' && typeof dependency.target !== 'string';
68
+ }
54
69
  export function targetExecutorsFromNxProjectJson(value) {
55
- const targets = isRecord(value) ? recordProperty(value, 'targets') : null;
70
+ const targets = value?.targets;
56
71
  const executors = new Map();
57
72
  if (!targets) {
58
73
  return executors;
59
74
  }
60
75
  for (const [targetName, target] of Object.entries(targets)) {
61
- if (isRecord(target) && typeof target.executor === 'string') {
76
+ if (typeof target.executor === 'string') {
62
77
  executors.set(targetName, target.executor);
63
78
  }
64
79
  }
@@ -68,35 +83,34 @@ export function targetOutputsFromNxProjectJson(value) {
68
83
  return targetStringArraysFromNxProjectJson(value, 'outputs');
69
84
  }
70
85
  export function targetScriptsFromNxProjectJson(value) {
71
- const targets = isRecord(value) ? recordProperty(value, 'targets') : null;
86
+ const targets = value?.targets;
72
87
  const scripts = new Map();
73
88
  if (!targets) {
74
89
  return scripts;
75
90
  }
76
91
  for (const [targetName, target] of Object.entries(targets)) {
77
- if (!isRecord(target)) {
78
- continue;
79
- }
80
- const options = recordProperty(target, 'options');
81
- if (typeof options?.script === 'string') {
82
- scripts.set(targetName, options.script);
92
+ if (typeof target.options?.script === 'string') {
93
+ scripts.set(targetName, target.options.script);
83
94
  }
84
95
  }
85
96
  return scripts;
86
97
  }
87
98
  function targetStringArraysFromNxProjectJson(value, property) {
88
- const targets = isRecord(value) ? recordProperty(value, 'targets') : null;
99
+ const targets = value?.targets;
89
100
  const values = new Map();
90
101
  if (!targets) {
91
102
  return values;
92
103
  }
93
104
  for (const [targetName, target] of Object.entries(targets)) {
94
- if (!isRecord(target)) {
95
- continue;
96
- }
97
105
  const entries = target[property];
98
106
  if (Array.isArray(entries)) {
99
- values.set(targetName, entries.filter((entry) => typeof entry === 'string'));
107
+ const strings = [];
108
+ for (const entry of entries) {
109
+ if (typeof entry === 'string') {
110
+ strings.push(entry);
111
+ }
112
+ }
113
+ values.set(targetName, strings);
100
114
  }
101
115
  }
102
116
  return values;
@@ -120,8 +134,8 @@ export function projectNamesFromNxShowProjectsOutput(output) {
120
134
  }
121
135
  if (trimmed.startsWith('[')) {
122
136
  try {
123
- const parsed = JSON.parse(trimmed);
124
- if (Array.isArray(parsed) && parsed.every((entry) => typeof entry === 'string')) {
137
+ const parsed = parseStringArrayText(trimmed);
138
+ if (parsed) {
125
139
  return parsed.sort((a, b) => a.localeCompare(b));
126
140
  }
127
141
  }
@@ -179,7 +193,10 @@ async function readNxProjectNames(root) {
179
193
  async function readProjectTarget(root, project) {
180
194
  const command = nxShowProjectCommand(project);
181
195
  const result = await $ `${command.command} ${command.args}`.cwd(root).quiet();
182
- const parsed = JSON.parse(decode(result.stdout));
196
+ const parsed = parseNxProjectJsonText(decode(result.stdout));
197
+ if (!parsed) {
198
+ throw new Error(`Unable to inspect Nx project ${project}.`);
199
+ }
183
200
  const targetDependencies = targetDependenciesFromNxProjectJson(parsed);
184
201
  return {
185
202
  project,
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pr/index.ts"],"names":[],"mappings":"AAMA,mFAAmF;AACnF,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAEtC,MAAM,WAAW,gBAAgB;IAC/B,qFAAqF;IACrF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gFAAgF;IAChF,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,CACP,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,GACV,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjE,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAClE;AA6BD;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,OAAO,EAAE,gBAAgB,EACzB,KAAK,GAAE,cAA6B,GACnC,OAAO,CAAC,aAAa,CAAC,CAWxB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pr/index.ts"],"names":[],"mappings":"AAOA,mFAAmF;AACnF,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAEtC,MAAM,WAAW,gBAAgB;IAC/B,qFAAqF;IACrF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gFAAgF;IAChF,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,CACP,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,GACV,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjE,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAClE;AAoDD;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,OAAO,EAAE,gBAAgB,EACzB,KAAK,GAAE,cAA6B,GACnC,OAAO,CAAC,aAAa,CAAC,CAWxB"}