@smoothbricks/cli 0.10.2 → 0.10.4

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 (133) hide show
  1. package/README.md +31 -23
  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 +36 -4
  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 +17 -2
  9. package/dist/github-ci/index.d.ts.map +1 -1
  10. package/dist/github-ci/index.js +192 -26
  11. package/dist/github-ci/outputs.d.ts +22 -0
  12. package/dist/github-ci/outputs.d.ts.map +1 -0
  13. package/dist/github-ci/outputs.js +648 -0
  14. package/dist/lib/cli-package.js +2 -2
  15. package/dist/lib/json.d.ts +118 -11
  16. package/dist/lib/json.d.ts.map +1 -1
  17. package/dist/lib/json.js +317 -29
  18. package/dist/lib/workspace.d.ts +7 -14
  19. package/dist/lib/workspace.d.ts.map +1 -1
  20. package/dist/lib/workspace.js +76 -82
  21. package/dist/monorepo/ci-workflow.d.ts +2 -0
  22. package/dist/monorepo/ci-workflow.d.ts.map +1 -1
  23. package/dist/monorepo/ci-workflow.js +28 -2
  24. package/dist/monorepo/git-config.js +2 -2
  25. package/dist/monorepo/index.d.ts +3 -1
  26. package/dist/monorepo/index.d.ts.map +1 -1
  27. package/dist/monorepo/index.js +6 -2
  28. package/dist/monorepo/lockfile.d.ts +13 -1
  29. package/dist/monorepo/lockfile.d.ts.map +1 -1
  30. package/dist/monorepo/lockfile.js +33 -21
  31. package/dist/monorepo/managed-files.d.ts +12 -0
  32. package/dist/monorepo/managed-files.d.ts.map +1 -1
  33. package/dist/monorepo/managed-files.js +86 -28
  34. package/dist/monorepo/package-policy.d.ts.map +1 -1
  35. package/dist/monorepo/package-policy.js +78 -45
  36. package/dist/monorepo/packed-manifest.d.ts +5 -2
  37. package/dist/monorepo/packed-manifest.d.ts.map +1 -1
  38. package/dist/monorepo/packed-manifest.js +16 -47
  39. package/dist/monorepo/packed-package.d.ts.map +1 -1
  40. package/dist/monorepo/packed-package.js +28 -16
  41. package/dist/monorepo/packs/index.d.ts +3 -0
  42. package/dist/monorepo/packs/index.d.ts.map +1 -1
  43. package/dist/monorepo/packs/index.js +18 -6
  44. package/dist/monorepo/publish-workflow.d.ts +1 -0
  45. package/dist/monorepo/publish-workflow.d.ts.map +1 -1
  46. package/dist/monorepo/publish-workflow.js +242 -3
  47. package/dist/monorepo/runtime.d.ts +15 -0
  48. package/dist/monorepo/runtime.d.ts.map +1 -1
  49. package/dist/monorepo/runtime.js +66 -12
  50. package/dist/monorepo/tool-validation.d.ts.map +1 -1
  51. package/dist/monorepo/tool-validation.js +32 -23
  52. package/dist/monorepo/wrangler.d.ts.map +1 -1
  53. package/dist/monorepo/wrangler.js +13 -13
  54. package/dist/nx/index.d.ts +12 -4
  55. package/dist/nx/index.d.ts.map +1 -1
  56. package/dist/nx/index.js +86 -19
  57. package/dist/pr/index.d.ts.map +1 -1
  58. package/dist/pr/index.js +28 -32
  59. package/dist/release/candidates.d.ts +3 -2
  60. package/dist/release/candidates.d.ts.map +1 -1
  61. package/dist/release/candidates.js +4 -5
  62. package/dist/release/github-release.d.ts +3 -0
  63. package/dist/release/github-release.d.ts.map +1 -1
  64. package/dist/release/github-release.js +11 -0
  65. package/dist/release/index.d.ts +20 -1
  66. package/dist/release/index.d.ts.map +1 -1
  67. package/dist/release/index.js +221 -89
  68. package/dist/release/orchestration.d.ts +8 -1
  69. package/dist/release/orchestration.d.ts.map +1 -1
  70. package/dist/release/orchestration.js +38 -1
  71. package/dist/wrangler/prepare-env.d.ts +0 -1
  72. package/dist/wrangler/prepare-env.d.ts.map +1 -1
  73. package/dist/wrangler/prepare-env.js +100 -51
  74. package/dist/wrangler/scaffold.d.ts.map +1 -1
  75. package/dist/wrangler/scaffold.js +12 -12
  76. package/managed/raw/git-format-staged.yml +19 -1
  77. package/managed/raw/tooling/direnv/github-actions-bootstrap.sh +6 -0
  78. package/managed/raw/tooling/direnv/merge-newer-pins.sh +3 -3
  79. package/managed/raw/tooling/direnv/setup-environment.ts +187 -19
  80. package/managed/raw/tooling/git-hooks/pre-commit.sh +0 -6
  81. package/managed/templates/github/actions/cache-nix-devenv/action.yml +12 -10
  82. package/managed/templates/github/actions/cache-node-modules/action.yml +6 -2
  83. package/managed/templates/github/actions/cache-nx/action.yml +2 -2
  84. package/managed/templates/github/actions/cache-ttsc-plugins/action.yml +19 -0
  85. package/managed/templates/github/actions/save-nix-devenv/action.yml +11 -3
  86. package/managed/templates/github/actions/setup-devenv/action.yml +5 -0
  87. package/managed/templates/github/workflows/managed-files.yml +80 -0
  88. package/package.json +18 -4
  89. package/src/bun/preload.ts +12 -0
  90. package/src/cli.ts +49 -11
  91. package/src/generate/index.ts +0 -6
  92. package/src/github-ci/index.test.ts +486 -0
  93. package/src/github-ci/index.ts +220 -30
  94. package/src/github-ci/outputs.ts +505 -0
  95. package/src/lib/cli-package.ts +2 -2
  96. package/src/lib/json.ts +291 -32
  97. package/src/lib/workspace.ts +88 -100
  98. package/src/monorepo/__tests__/ci-workflow.test.ts +14 -3
  99. package/src/monorepo/__tests__/publish-workflow.test.ts +222 -1
  100. package/src/monorepo/ci-workflow.ts +28 -2
  101. package/src/monorepo/git-config.ts +2 -2
  102. package/src/monorepo/index.ts +6 -2
  103. package/src/monorepo/lockfile.test.ts +35 -36
  104. package/src/monorepo/lockfile.ts +48 -24
  105. package/src/monorepo/managed-files.test.ts +63 -0
  106. package/src/monorepo/managed-files.ts +94 -34
  107. package/src/monorepo/package-policy.test.ts +70 -51
  108. package/src/monorepo/package-policy.ts +104 -59
  109. package/src/monorepo/packed-manifest.ts +18 -52
  110. package/src/monorepo/packed-package.ts +43 -22
  111. package/src/monorepo/packs/index.test.ts +18 -1
  112. package/src/monorepo/packs/index.ts +20 -7
  113. package/src/monorepo/publish-workflow.ts +482 -3
  114. package/src/monorepo/runtime.test.ts +42 -3
  115. package/src/monorepo/runtime.ts +90 -12
  116. package/src/monorepo/tool-validation.ts +35 -25
  117. package/src/monorepo/wrangler.test.ts +11 -15
  118. package/src/monorepo/wrangler.ts +15 -15
  119. package/src/nx/index.test.ts +43 -0
  120. package/src/nx/index.ts +110 -23
  121. package/src/pr/index.ts +42 -36
  122. package/src/release/__tests__/candidates.test.ts +5 -4
  123. package/src/release/__tests__/fixture-repo.test.ts +18 -16
  124. package/src/release/__tests__/github-release.test.ts +11 -0
  125. package/src/release/__tests__/orchestration.test.ts +57 -2
  126. package/src/release/__tests__/trust-publisher.test.ts +98 -2
  127. package/src/release/candidates.ts +10 -17
  128. package/src/release/github-release.ts +12 -0
  129. package/src/release/index.ts +321 -112
  130. package/src/release/orchestration.ts +55 -3
  131. package/src/wrangler/prepare-env.ts +75 -54
  132. package/src/wrangler/scaffold.test.ts +9 -12
  133. package/src/wrangler/scaffold.ts +13 -13
@@ -1,26 +1,32 @@
1
1
  import { existsSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
3
  import { $ } from 'bun';
4
- import { getOrCreateRecord, readJsonObject, setStringProperty, writeJsonObject } from '../lib/json.js';
4
+ import { ensureDependencyMap, ensureEngines, parseStringArrayText, readJsonObject, setPackageStringField, setStringProperty, writeJsonObject, } from '../lib/json.js';
5
+ /** Live runtime versions from the shell PATH — the single source sync AND validate derive from. */
6
+ export async function runtimeVersionsFromPath(root) {
7
+ const node = runtimeCommand(root, 'node');
8
+ const bun = runtimeCommand(root, 'bun');
9
+ return {
10
+ node: (await $ `${node} --version`.cwd(root).text()).trim().replace(/^v/, ''),
11
+ bun: (await $ `${bun} --version`.cwd(root).text()).trim(),
12
+ };
13
+ }
5
14
  export async function syncRootRuntimeVersions(root) {
6
15
  const packageJsonPath = join(root, 'package.json');
7
16
  const packageJson = readJsonObject(packageJsonPath);
8
17
  if (!packageJson) {
9
18
  throw new Error('package.json not found or invalid');
10
19
  }
11
- const node = runtimeCommand(root, 'node');
12
- const bun = runtimeCommand(root, 'bun');
13
- const nodeVersion = (await $ `${node} --version`.cwd(root).text()).trim().replace(/^v/, '');
14
- const bunVersion = (await $ `${bun} --version`.cwd(root).text()).trim();
20
+ const { node: nodeVersion, bun: bunVersion } = await runtimeVersionsFromPath(root);
15
21
  const nodeMajor = nodeVersion.split('.', 1)[0];
16
22
  if (!nodeMajor) {
17
23
  throw new Error(`Unable to derive Node major version from ${nodeVersion}`);
18
24
  }
19
25
  let changed = false;
20
- const engines = getOrCreateRecord(packageJson, 'engines');
26
+ const engines = ensureEngines(packageJson);
21
27
  changed = setStringProperty(engines, 'node', `>=${nodeMajor}.0.0`) || changed;
22
- changed = setStringProperty(packageJson, 'packageManager', `bun@${bunVersion}`) || changed;
23
- const devDependencies = getOrCreateRecord(packageJson, 'devDependencies');
28
+ changed = setPackageStringField(packageJson, 'packageManager', `bun@${bunVersion}`) || changed;
29
+ const devDependencies = ensureDependencyMap(packageJson, 'devDependencies');
24
30
  changed =
25
31
  setStringProperty(devDependencies, '@types/node', await runtimeTypesRange(root, '@types/node', nodeVersion, 'major')) || changed;
26
32
  changed =
@@ -30,10 +36,53 @@ export async function syncRootRuntimeVersions(root) {
30
36
  console.log('updated package.json runtime versions');
31
37
  }
32
38
  }
39
+ /**
40
+ * Validate that package.json runtime pins agree with the LIVE PATH runtimes,
41
+ * never a stored template. Offline by design: structural alignment only
42
+ * (majors, exact bun pin, no `~major.0.0` floor) — the registry is not
43
+ * consulted. Repair: `smoo monorepo init --runtime-only` inside the devenv shell.
44
+ */
45
+ export async function validateRootRuntimeVersions(root) {
46
+ const packageJson = readJsonObject(join(root, 'package.json'));
47
+ if (!packageJson) {
48
+ console.error('package.json not found or invalid');
49
+ return 1;
50
+ }
51
+ return validateRuntimePins(packageJson, await runtimeVersionsFromPath(root));
52
+ }
53
+ export function validateRuntimePins(packageJson, runtime) {
54
+ const nodeMajor = runtime.node.split('.', 1)[0];
55
+ if (!nodeMajor) {
56
+ throw new Error(`Unable to derive Node major version from ${runtime.node}`);
57
+ }
58
+ let failures = 0;
59
+ const repair = 'run `smoo monorepo init --runtime-only` inside the devenv shell';
60
+ const enginesNode = packageJson.engines?.node ?? null;
61
+ if (enginesNode !== `>=${nodeMajor}.0.0`) {
62
+ console.error(`package.json engines.node is ${enginesNode ?? 'missing'} but the PATH node is v${runtime.node} — expected >=${nodeMajor}.0.0; ${repair}`);
63
+ failures++;
64
+ }
65
+ const packageManager = packageJson.packageManager ?? null;
66
+ if (packageManager !== `bun@${runtime.bun}`) {
67
+ console.error(`package.json packageManager is ${packageManager ?? 'missing'} but the PATH bun is ${runtime.bun} — expected bun@${runtime.bun}; ${repair}`);
68
+ failures++;
69
+ }
70
+ const typesNode = packageJson.devDependencies?.['@types/node'] ?? null;
71
+ const typesNodeParts = typesNode ? /^~(\d+)\.(\d+)\.(\d+)$/.exec(typesNode) : null;
72
+ if (!typesNodeParts || typesNodeParts[1] !== nodeMajor) {
73
+ console.error(`package.json @types/node is ${typesNode ?? 'missing'} but the PATH node is v${runtime.node} — types track the runtime major (~${nodeMajor}.x.y, newest published minor); ${repair}`);
74
+ failures++;
75
+ }
76
+ else if (typesNodeParts[2] === '0' && typesNodeParts[3] === '0') {
77
+ console.error(`package.json @types/node is pinned to the ~${nodeMajor}.0.0 floor — tilde locks the first patch line and strands the repo on early broken releases; ${repair} to repin to the newest published ${nodeMajor}.x`);
78
+ failures++;
79
+ }
80
+ return failures;
81
+ }
33
82
  async function runtimeTypesRange(root, packageName, runtimeVersion, pinMode) {
34
83
  const versionsText = await $ `bun pm view ${packageName} versions --json`.cwd(root).text();
35
- const versions = JSON.parse(versionsText);
36
- if (!Array.isArray(versions) || !versions.every((version) => typeof version === 'string')) {
84
+ const versions = parseStringArrayText(versionsText);
85
+ if (!versions) {
37
86
  throw new Error(`Unable to read published ${packageName} versions`);
38
87
  }
39
88
  return runtimeTypesRangeForPublishedVersions(packageName, runtimeVersion, pinMode, versions);
@@ -45,8 +94,13 @@ export function runtimeTypesRangeForPublishedVersions(packageName, runtimeVersio
45
94
  }
46
95
  if (pinMode === 'major') {
47
96
  const runtimeMajor = parsedRuntimeVersion[0].toString();
48
- if (latestVersion(versions.filter((version) => versionMajor(version) === runtimeMajor))) {
49
- return `~${runtimeMajor}.0.0`;
97
+ // Newest published types WITHIN the runtime major — never the `~major.0.0`
98
+ // floor: tilde locks the patch line, so the floor can strand consumers on a
99
+ // broken early release (e.g. @types/node 24.0.x's URLPattern/DOM TS2403
100
+ // conflict, fixed in 24.13) with no path to the repaired minors.
101
+ const latestInMajor = latestVersion(versions.filter((version) => versionMajor(version) === runtimeMajor));
102
+ if (latestInMajor) {
103
+ return `~${latestInMajor}`;
50
104
  }
51
105
  }
52
106
  else if (versions.includes(runtimeVersion)) {
@@ -1 +1 @@
1
- {"version":3,"file":"tool-validation.d.ts","sourceRoot":"","sources":["../../src/monorepo/tool-validation.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,WAAW,EAAyB,MAAM,qBAAqB,CAAC;AAU9E,MAAM,WAAW,UAAU;IACzB,sBAAsB,EAAE,OAAO,CAAC;IAChC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,WAAW,GAAG,IAAI,CAAC;IAChC,MAAM,EAAE,UAAU,CAAC;CACpB;AAiCD,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKzE;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQvD;AAED,wBAAsB,8BAA8B,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBtG;AAoCD,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAkBlF;AAED,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAY/D;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CA0B7D;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,GAAG,IAAI,GAAG,MAAM,CAyBvG;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,CAoB/E;AAED,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,GAAG,MAAM,CAWhF;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAmB3D;AA0DD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAQzD"}
1
+ {"version":3,"file":"tool-validation.d.ts","sourceRoot":"","sources":["../../src/monorepo/tool-validation.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,KAAK,WAAW,EAAyB,MAAM,qBAAqB,CAAC;AAU9E,MAAM,WAAW,UAAU;IACzB,sBAAsB,EAAE,OAAO,CAAC;IAChC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,WAAW,GAAG,IAAI,CAAC;IAChC,MAAM,EAAE,UAAU,CAAC;CACpB;AA0CD,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKzE;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQvD;AAED,wBAAsB,8BAA8B,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBtG;AAoCD,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAkBlF;AAED,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAY/D;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CA0B7D;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,GAAG,IAAI,GAAG,MAAM,CAyBvG;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,CAoB/E;AAED,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,GAAG,MAAM,CAWhF;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAqB3D;AA0DD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAQzD"}
@@ -1,8 +1,19 @@
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);
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
+ return input => "object" === typeof input && null !== input && _io0(input);
16
+ })();
6
17
  const rootDevDependencies = [
7
18
  { name: '@biomejs/biome', fallbackVersion: '^2.3.5', minimumVersion: '2.3.0', prefix: '^' },
8
19
  { name: '@nx/js', fallbackVersion: '23.1.0', minimumVersion: '23.1.0' },
@@ -24,13 +35,17 @@ const rootDevDependencies = [
24
35
  { name: 'nx', fallbackVersion: '23.1.0', minimumVersion: '23.1.0' },
25
36
  { name: 'prettier', fallbackVersion: '^3.6.1', minimumVersion: '3.6.0', prefix: '^' },
26
37
  { name: 'ttsc', fallbackVersion: '^0.18.4', minimumVersion: '0.18.4', prefix: '^' },
27
- // Nx and typescript-eslint still load the TypeScript 5.x JavaScript API.
38
+ // Nx and typescript-eslint still load the TypeScript JS API (6.x).
28
39
  // Compilation is exclusively delegated to ttsc by the Nx plugin targets.
29
40
  { name: 'typescript', fallbackVersion: '^5.9.3', minimumVersion: '5.9.0', prefix: '^' },
30
41
  ];
31
42
  const cliPackageName = '@smoothbricks/cli';
32
43
  const requiredDevenvPackages = ['bun', 'git', 'git-format-staged', 'jq', 'alejandra', 'coreutils', 'gnutar'];
33
- const allowedNodePackages = ['nodejs_24', 'nodejs_latest'];
44
+ // Any explicit nodejs provider is fine — the pinned major is the repo's choice
45
+ // (Lambda parity, org convergence, …). Whether the pins in package.json agree
46
+ // with the runtime is validated against the live PATH (validateRootRuntimeVersions),
47
+ // never against a version template here.
48
+ const nodePackagePattern = /(^|\s)nodejs(_\d+|_latest)?(\s|#|$)/m;
34
49
  export async function applyToolConfigDefaults(root) {
35
50
  const context = readToolContext(root);
36
51
  await applyRootPackageToolDefaults(root, context);
@@ -50,7 +65,7 @@ export async function applyRootDevDependencyDefaults(root, context) {
50
65
  return;
51
66
  }
52
67
  let changed = false;
53
- const devDependencies = getOrCreateRecord(pkg, 'devDependencies');
68
+ const devDependencies = ensureDependencyMap(pkg, 'devDependencies');
54
69
  for (const dependency of rootDevDependencies) {
55
70
  const current = devDependencies[dependency.name];
56
71
  if (typeof current !== 'string' || !satisfiesDependencyPolicy(context.policy, current, dependency)) {
@@ -76,7 +91,7 @@ async function applyRootPackageToolDefaults(root, context) {
76
91
  }
77
92
  let dependencyChanged = false;
78
93
  let workspaceChanged = false;
79
- const devDependencies = getOrCreateRecord(pkg, 'devDependencies');
94
+ const devDependencies = ensureDependencyMap(pkg, 'devDependencies');
80
95
  for (const dependency of rootDevDependencies) {
81
96
  const current = devDependencies[dependency.name];
82
97
  if (typeof current !== 'string' || !satisfiesDependencyPolicy(context.policy, current, dependency)) {
@@ -102,12 +117,12 @@ export function applyToolingPackageDefaults(root, policy) {
102
117
  const path = join(root, 'tooling', 'package.json');
103
118
  const pkg = readJsonObject(path) ?? { name: policy.toolingPackageName, private: true, dependencies: {} };
104
119
  let changed = false;
105
- changed = setStringProperty(pkg, 'name', policy.toolingPackageName) || changed;
120
+ changed = setPackageStringField(pkg, 'name', policy.toolingPackageName) || changed;
106
121
  if (pkg.private !== true) {
107
122
  pkg.private = true;
108
123
  changed = true;
109
124
  }
110
- const dependencies = getOrCreateRecord(pkg, 'dependencies');
125
+ const dependencies = ensureDependencyMap(pkg, 'dependencies');
111
126
  changed = setStringProperty(dependencies, cliPackageName, policy.cliDependencyRange) || changed;
112
127
  if (changed || !existsSync(path)) {
113
128
  mkdirSync(dirname(path), { recursive: true });
@@ -139,7 +154,7 @@ export function applyDevenvPackageDefaults(root) {
139
154
  }
140
155
  let content = readFileSync(path, 'utf8');
141
156
  let changed = false;
142
- if (!allowedNodePackages.some((name) => hasNixPackage(content, name))) {
157
+ if (!nodePackagePattern.test(content)) {
143
158
  const next = addNixPackage(content, 'nodejs_latest', '# Node.js for workspace tooling');
144
159
  changed = next !== content || changed;
145
160
  content = next;
@@ -166,7 +181,7 @@ export function validateRootDevDependencies(policy, rootPackage) {
166
181
  console.error('package.json not found or invalid');
167
182
  return 1;
168
183
  }
169
- const devDependencies = recordProperty(pkg, 'devDependencies');
184
+ const devDependencies = pkg.devDependencies;
170
185
  let failures = 0;
171
186
  for (const dependency of rootDevDependencies) {
172
187
  const version = devDependencies?.[dependency.name];
@@ -192,9 +207,9 @@ export function validateToolingPackage(root, policy) {
192
207
  console.error('tooling/package.json not found or invalid');
193
208
  return 1;
194
209
  }
195
- const dependencies = recordProperty(pkg, 'dependencies');
210
+ const dependencies = pkg.dependencies;
196
211
  let failures = 0;
197
- const actualName = typeof pkg.name === 'string' ? pkg.name : null;
212
+ const actualName = pkg.name ?? null;
198
213
  if (actualName !== policy.toolingPackageName) {
199
214
  console.error(`tooling/package.json name must be ${policy.toolingPackageName}`);
200
215
  failures++;
@@ -226,8 +241,8 @@ export function validateDevenvPackages(root) {
226
241
  }
227
242
  const content = readFileSync(path, 'utf8');
228
243
  let failures = 0;
229
- if (!allowedNodePackages.some((name) => hasNixPackage(content, name))) {
230
- console.error(`tooling/direnv/devenv.nix packages must include ${allowedNodePackages.join(' or ')}`);
244
+ if (!nodePackagePattern.test(content)) {
245
+ console.error('tooling/direnv/devenv.nix packages must include a nodejs provider (nodejs_<major> or nodejs_latest)');
231
246
  failures++;
232
247
  }
233
248
  for (const name of requiredDevenvPackages) {
@@ -291,14 +306,14 @@ function formatExpectedDependency(policy, dependency) {
291
306
  export function readToolContext(root) {
292
307
  const rootPackage = readPackageJsonObject(join(root, 'package.json'));
293
308
  const toolingPackage = readJsonObject(join(root, 'tooling', 'package.json'));
294
- const configuredCliRange = recordProperty(toolingPackage ?? {}, 'dependencies')?.[cliPackageName];
309
+ const configuredCliRange = toolingPackage?.dependencies?.[cliPackageName];
295
310
  return {
296
311
  rootPackage,
297
312
  policy: toolPolicy(rootPackage, typeof configuredCliRange === 'string' ? configuredCliRange : null),
298
313
  };
299
314
  }
300
315
  function toolPolicy(rootPackage, configuredCliRange) {
301
- const name = typeof rootPackage?.name === 'string' ? rootPackage.name : null;
316
+ const name = rootPackage?.name ?? null;
302
317
  const isCodebase = isSmoothBricksCodebasePackageName(name ?? undefined);
303
318
  const toolingName = toolingPackageName(name);
304
319
  // A locally linked prerelease can be newer than every published CLI. Keep an existing
@@ -375,12 +390,6 @@ function latestVersionInSameMajorMinor(versions, minimum) {
375
390
  function compareVersions(left, right) {
376
391
  return left.major - right.major || left.minor - right.minor || left.patch - right.patch;
377
392
  }
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
393
  function stripRangePrefix(version) {
385
394
  return version.replace(/^[~^]/, '');
386
395
  }
@@ -393,7 +402,7 @@ function addWorkspacePattern(pkg, pattern) {
393
402
  workspaces.push(pattern);
394
403
  return true;
395
404
  }
396
- if (isObjectRecord(workspaces) && Array.isArray(workspaces.packages)) {
405
+ if (workspaces && Array.isArray(workspaces.packages)) {
397
406
  if (workspaces.packages.includes(pattern)) {
398
407
  return false;
399
408
  }
@@ -408,5 +417,5 @@ function hasWorkspacePattern(pkg, pattern) {
408
417
  if (Array.isArray(workspaces)) {
409
418
  return workspaces.includes(pattern);
410
419
  }
411
- return isObjectRecord(workspaces) && Array.isArray(workspaces.packages) && workspaces.packages.includes(pattern);
420
+ return Boolean(workspaces && Array.isArray(workspaces.packages) && workspaces.packages.includes(pattern));
412
421
  }
@@ -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,8 +1,12 @@
1
+ import { type NxProjectJson, type NxTargetConfig } from '../lib/json.js';
1
2
  export interface ProjectTargets {
2
3
  project: string;
4
+ root?: string;
3
5
  targets: string[];
4
6
  buildDependsOn?: string[];
7
+ targetDependencies?: Map<string, string[]>;
5
8
  targetExecutors?: Map<string, string>;
9
+ targetOutputs?: Map<string, string[]>;
6
10
  targetScripts?: Map<string, string>;
7
11
  }
8
12
  export interface CommandInvocation {
@@ -12,10 +16,13 @@ export interface CommandInvocation {
12
16
  export declare function nxResetCommand(): CommandInvocation;
13
17
  export declare function nxShowProjectCommand(project: string): CommandInvocation;
14
18
  export declare function nxCacheDirectories(root: string): string[];
15
- export declare function targetNamesFromNxProjectJson(value: unknown): string[];
16
- export declare function buildDependsOnFromNxProjectJson(value: unknown): string[] | undefined;
17
- export declare function targetExecutorsFromNxProjectJson(value: unknown): Map<string, string>;
18
- 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>;
19
26
  export declare function formatProjectTargetLines(projects: ProjectTargets[]): string;
20
27
  export declare function projectNamesWithTarget(projects: ProjectTargets[], target: string): string[];
21
28
  export declare function projectNamesFromNxShowProjectsOutput(output: string): string[];
@@ -26,4 +33,5 @@ export declare function listProjects(root: string, options: {
26
33
  export declare function resetCache(root: string): Promise<void>;
27
34
  export declare function cleanCache(root: string): Promise<void>;
28
35
  export declare function readProjectTargets(root: string): Promise<ProjectTargets[]>;
36
+ export type { NxProjectJson, NxTargetConfig };
29
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,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,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,+BAA+B,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,GAAG,SAAS,CAOpF;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,CAAC,CAgBlF;AAED,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,47 +14,107 @@ 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
+ export function projectRootFromNxProjectJson(value) {
21
+ return typeof value?.root === 'string' ? value.root : undefined;
22
+ }
20
23
  export function buildDependsOnFromNxProjectJson(value) {
21
- const targets = isRecord(value) ? recordProperty(value, 'targets') : null;
22
- const build = targets ? recordProperty(targets, 'build') : null;
23
- if (!Array.isArray(build?.dependsOn) || !build.dependsOn.every((entry) => typeof entry === 'string')) {
24
+ return targetDependenciesFromNxProjectJson(value).get('build');
25
+ }
26
+ export function targetDependenciesFromNxProjectJson(value) {
27
+ const targets = value?.targets;
28
+ const dependencies = new Map();
29
+ if (!targets) {
30
+ return dependencies;
31
+ }
32
+ for (const [targetName, target] of Object.entries(targets)) {
33
+ if (!target.dependsOn) {
34
+ continue;
35
+ }
36
+ const entries = [];
37
+ for (const dependency of target.dependsOn) {
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
+ }
43
+ continue;
44
+ }
45
+ entries.push(local);
46
+ }
47
+ dependencies.set(targetName, entries);
48
+ }
49
+ return dependencies;
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.
24
62
  return undefined;
25
63
  }
26
- return build.dependsOn;
64
+ return dependency.target;
65
+ }
66
+ function isInvalidDependsOn(dependency) {
67
+ return typeof dependency !== 'string' && typeof dependency.target !== 'string';
27
68
  }
28
69
  export function targetExecutorsFromNxProjectJson(value) {
29
- const targets = isRecord(value) ? recordProperty(value, 'targets') : null;
70
+ const targets = value?.targets;
30
71
  const executors = new Map();
31
72
  if (!targets) {
32
73
  return executors;
33
74
  }
34
75
  for (const [targetName, target] of Object.entries(targets)) {
35
- if (isRecord(target) && typeof target.executor === 'string') {
76
+ if (typeof target.executor === 'string') {
36
77
  executors.set(targetName, target.executor);
37
78
  }
38
79
  }
39
80
  return executors;
40
81
  }
82
+ export function targetOutputsFromNxProjectJson(value) {
83
+ return targetStringArraysFromNxProjectJson(value, 'outputs');
84
+ }
41
85
  export function targetScriptsFromNxProjectJson(value) {
42
- const targets = isRecord(value) ? recordProperty(value, 'targets') : null;
86
+ const targets = value?.targets;
43
87
  const scripts = new Map();
44
88
  if (!targets) {
45
89
  return scripts;
46
90
  }
47
91
  for (const [targetName, target] of Object.entries(targets)) {
48
- if (!isRecord(target)) {
49
- continue;
50
- }
51
- const options = recordProperty(target, 'options');
52
- if (typeof options?.script === 'string') {
53
- scripts.set(targetName, options.script);
92
+ if (typeof target.options?.script === 'string') {
93
+ scripts.set(targetName, target.options.script);
54
94
  }
55
95
  }
56
96
  return scripts;
57
97
  }
98
+ function targetStringArraysFromNxProjectJson(value, property) {
99
+ const targets = value?.targets;
100
+ const values = new Map();
101
+ if (!targets) {
102
+ return values;
103
+ }
104
+ for (const [targetName, target] of Object.entries(targets)) {
105
+ const entries = target[property];
106
+ if (Array.isArray(entries)) {
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);
114
+ }
115
+ }
116
+ return values;
117
+ }
58
118
  export function formatProjectTargetLines(projects) {
59
119
  return projects
60
120
  .flatMap((project) => project.targets.map((target) => `${project.project}:${target}`))
@@ -74,8 +134,8 @@ export function projectNamesFromNxShowProjectsOutput(output) {
74
134
  }
75
135
  if (trimmed.startsWith('[')) {
76
136
  try {
77
- const parsed = JSON.parse(trimmed);
78
- if (Array.isArray(parsed) && parsed.every((entry) => typeof entry === 'string')) {
137
+ const parsed = parseStringArrayText(trimmed);
138
+ if (parsed) {
79
139
  return parsed.sort((a, b) => a.localeCompare(b));
80
140
  }
81
141
  }
@@ -133,12 +193,19 @@ async function readNxProjectNames(root) {
133
193
  async function readProjectTarget(root, project) {
134
194
  const command = nxShowProjectCommand(project);
135
195
  const result = await $ `${command.command} ${command.args}`.cwd(root).quiet();
136
- 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
+ }
200
+ const targetDependencies = targetDependenciesFromNxProjectJson(parsed);
137
201
  return {
138
202
  project,
203
+ root: projectRootFromNxProjectJson(parsed),
139
204
  targets: targetNamesFromNxProjectJson(parsed),
140
- buildDependsOn: buildDependsOnFromNxProjectJson(parsed),
205
+ buildDependsOn: targetDependencies.get('build'),
206
+ targetDependencies,
141
207
  targetExecutors: targetExecutorsFromNxProjectJson(parsed),
208
+ targetOutputs: targetOutputsFromNxProjectJson(parsed),
142
209
  targetScripts: targetScriptsFromNxProjectJson(parsed),
143
210
  };
144
211
  }
@@ -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"}