@smoothbricks/cli 0.10.5 → 0.10.7

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 (65) hide show
  1. package/dist/cli.js +3 -2
  2. package/dist/github-ci/index.d.ts +1 -0
  3. package/dist/github-ci/index.d.ts.map +1 -1
  4. package/dist/github-ci/index.js +28 -5
  5. package/dist/lib/json.d.ts +3 -1
  6. package/dist/lib/json.d.ts.map +1 -1
  7. package/dist/lib/json.js +5 -20
  8. package/dist/lib/workspace.d.ts.map +1 -1
  9. package/dist/lib/workspace.js +1 -0
  10. package/dist/monorepo/ci-workflow.d.ts +2 -0
  11. package/dist/monorepo/ci-workflow.d.ts.map +1 -1
  12. package/dist/monorepo/ci-workflow.js +10 -4
  13. package/dist/monorepo/github-runs-on.d.ts +14 -0
  14. package/dist/monorepo/github-runs-on.d.ts.map +1 -0
  15. package/dist/monorepo/github-runs-on.js +43 -0
  16. package/dist/monorepo/index.d.ts +2 -2
  17. package/dist/monorepo/index.d.ts.map +1 -1
  18. package/dist/monorepo/index.js +7 -7
  19. package/dist/monorepo/managed-files.d.ts +14 -3
  20. package/dist/monorepo/managed-files.d.ts.map +1 -1
  21. package/dist/monorepo/managed-files.js +54 -74
  22. package/dist/monorepo/package-policy.js +2 -2
  23. package/dist/monorepo/packs/index.d.ts.map +1 -1
  24. package/dist/monorepo/packs/index.js +3 -1
  25. package/dist/monorepo/publish-workflow.d.ts +3 -0
  26. package/dist/monorepo/publish-workflow.d.ts.map +1 -1
  27. package/dist/monorepo/publish-workflow.js +17 -14
  28. package/dist/monorepo/runtime.d.ts +2 -2
  29. package/dist/monorepo/runtime.d.ts.map +1 -1
  30. package/dist/monorepo/runtime.js +11 -16
  31. package/dist/monorepo/tool-validation.d.ts.map +1 -1
  32. package/dist/monorepo/tool-validation.js +20 -23
  33. package/dist/nx/index.d.ts +7 -4
  34. package/dist/nx/index.d.ts.map +1 -1
  35. package/dist/nx/index.js +117 -56
  36. package/managed/raw/tooling/devenv +71 -0
  37. package/managed/raw/tooling/direnv/github-actions-bootstrap.sh +24 -7
  38. package/managed/templates/github/actions/cache-nix-devenv/action.yml +13 -11
  39. package/managed/templates/github/actions/save-nix-devenv/action.yml +34 -3
  40. package/managed/templates/github/actions/setup-devenv/action.yml +44 -15
  41. package/managed/templates/github/workflows/managed-files.yml +64 -12
  42. package/package.json +4 -4
  43. package/src/cli.ts +10 -3
  44. package/src/github-ci/index.test.ts +53 -4
  45. package/src/github-ci/index.ts +37 -5
  46. package/src/lib/json.ts +3 -1
  47. package/src/lib/workspace.ts +1 -0
  48. package/src/monorepo/__tests__/ci-workflow.test.ts +37 -1
  49. package/src/monorepo/__tests__/publish-workflow.test.ts +39 -4
  50. package/src/monorepo/ci-workflow.ts +14 -4
  51. package/src/monorepo/github-runs-on.ts +45 -0
  52. package/src/monorepo/index.ts +7 -7
  53. package/src/monorepo/managed-files.test.ts +58 -0
  54. package/src/monorepo/managed-files.ts +59 -76
  55. package/src/monorepo/package-policy.test.ts +31 -0
  56. package/src/monorepo/package-policy.ts +2 -2
  57. package/src/monorepo/packs/index.ts +3 -1
  58. package/src/monorepo/publish-workflow.ts +28 -15
  59. package/src/monorepo/runtime.test.ts +23 -17
  60. package/src/monorepo/runtime.ts +12 -17
  61. package/src/monorepo/tool-validation.test.ts +15 -8
  62. package/src/monorepo/tool-validation.ts +20 -25
  63. package/src/nx/index.test.ts +45 -14
  64. package/src/nx/index.ts +133 -64
  65. package/managed/raw/patches/ttsc@0.19.3.patch +0 -67
package/src/nx/index.ts CHANGED
@@ -1,15 +1,11 @@
1
1
  import { existsSync } from 'node:fs';
2
2
  import { lstat, rm } from 'node:fs/promises';
3
3
  import { join } from 'node:path';
4
- import { $ } from 'bun';
5
- import {
6
- type NxDependsOn,
7
- type NxProjectJson,
8
- type NxTargetConfig,
9
- parseNxProjectJsonText,
10
- parseStringArrayText,
11
- } from '../lib/json.js';
12
- import { decode, run } from '../lib/run.js';
4
+ // Nx package exports are CLI-oriented; this is the module the CLI uses for graph + daemon IPC.
5
+ import { createProjectGraphAsync } from 'nx/src/project-graph/project-graph.js';
6
+ import { workspaceRoot as primaryWorkspaceRoot } from 'nx/src/utils/workspace-root.js';
7
+ import type { NxDependsOn, NxProjectJson, NxTargetConfig, NxTargetOptions } from '../lib/json.js';
8
+ import { run, runResult } from '../lib/run.js';
13
9
 
14
10
  export interface ProjectTargets {
15
11
  project: string;
@@ -18,6 +14,7 @@ export interface ProjectTargets {
18
14
  buildDependsOn?: string[];
19
15
  targetDependencies?: Map<string, string[]>;
20
16
  targetExecutors?: Map<string, string>;
17
+ targetOptions?: Map<string, NxTargetOptions>;
21
18
  targetOutputs?: Map<string, string[]>;
22
19
  targetScripts?: Map<string, string>;
23
20
  }
@@ -31,10 +28,6 @@ export function nxResetCommand(): CommandInvocation {
31
28
  return { command: 'nx', args: ['reset'] };
32
29
  }
33
30
 
34
- export function nxShowProjectCommand(project: string): CommandInvocation {
35
- return { command: 'nx', args: ['show', 'project', project, '--json'] };
36
- }
37
-
38
31
  export function nxCacheDirectories(root: string): string[] {
39
32
  return [join(root, '.nx/cache'), join(root, '.nx/workspace-data'), join(root, 'node_modules/.cache/nx')];
40
33
  }
@@ -48,10 +41,6 @@ export function projectRootFromNxProjectJson(value: NxProjectJson | null | undef
48
41
  return typeof value?.root === 'string' ? value.root : undefined;
49
42
  }
50
43
 
51
- export function buildDependsOnFromNxProjectJson(value: NxProjectJson | null | undefined): string[] | undefined {
52
- return targetDependenciesFromNxProjectJson(value).get('build');
53
- }
54
-
55
44
  export function targetDependenciesFromNxProjectJson(value: NxProjectJson | null | undefined): Map<string, string[]> {
56
45
  const targets = value?.targets;
57
46
  const dependencies = new Map<string, string[]>();
@@ -112,6 +101,20 @@ export function targetExecutorsFromNxProjectJson(value: NxProjectJson | null | u
112
101
  return executors;
113
102
  }
114
103
 
104
+ export function targetOptionsFromNxProjectJson(value: NxProjectJson | null | undefined): Map<string, NxTargetOptions> {
105
+ const targets = value?.targets;
106
+ const options = new Map<string, NxTargetOptions>();
107
+ if (!targets) {
108
+ return options;
109
+ }
110
+ for (const [targetName, target] of Object.entries(targets)) {
111
+ if (target.options) {
112
+ options.set(targetName, target.options);
113
+ }
114
+ }
115
+ return options;
116
+ }
117
+
115
118
  export function targetOutputsFromNxProjectJson(value: NxProjectJson | null | undefined): Map<string, string[]> {
116
119
  return targetStringArraysFromNxProjectJson(value, 'outputs');
117
120
  }
@@ -168,30 +171,6 @@ export function projectNamesWithTarget(projects: ProjectTargets[], target: strin
168
171
  .sort((a, b) => a.localeCompare(b));
169
172
  }
170
173
 
171
- export function projectNamesFromNxShowProjectsOutput(output: string): string[] {
172
- const trimmed = output.trim();
173
- if (!trimmed) {
174
- return [];
175
- }
176
-
177
- if (trimmed.startsWith('[')) {
178
- try {
179
- const parsed = parseStringArrayText(trimmed);
180
- if (parsed) {
181
- return parsed.sort((a, b) => a.localeCompare(b));
182
- }
183
- } catch {
184
- // Fall through to legacy newline parsing for older Nx output shapes.
185
- }
186
- }
187
-
188
- return trimmed
189
- .split('\n')
190
- .map((line) => line.trim())
191
- .filter(Boolean)
192
- .sort((a, b) => a.localeCompare(b));
193
- }
194
-
195
174
  export async function listTargets(root: string): Promise<void> {
196
175
  const output = formatProjectTargetLines(await readProjectTargets(root));
197
176
  if (output) {
@@ -229,34 +208,124 @@ export async function cleanCache(root: string): Promise<void> {
229
208
  }
230
209
  }
231
210
 
232
- export async function readProjectTargets(root: string): Promise<ProjectTargets[]> {
233
- const projects = await readNxProjectNames(root);
234
- return Promise.all(projects.map((project) => readProjectTarget(root, project)));
211
+ export type NxProjects = Readonly<Record<string, NxProjectJson>>;
212
+
213
+ /**
214
+ * Load the resolved project graph through Nx's API. The current workspace uses the
215
+ * daemon in-process; foreign roots use an isolated process because Nx snapshots its
216
+ * workspace cache paths when the module loads.
217
+ */
218
+ let graphLoadTail: Promise<void> = Promise.resolve();
219
+
220
+ export function loadNxProjects(root: string): Promise<NxProjects> {
221
+ const result = graphLoadTail.then(() => loadNxProjectsNow(root));
222
+ graphLoadTail = result.then(
223
+ () => undefined,
224
+ () => undefined,
225
+ );
226
+ return result;
235
227
  }
236
228
 
237
- async function readNxProjectNames(root: string): Promise<string[]> {
238
- const result = await $`nx show projects`.cwd(root).quiet();
239
- return projectNamesFromNxShowProjectsOutput(decode(result.stdout));
229
+ async function loadNxProjectsNow(root: string): Promise<NxProjects> {
230
+ if (root !== primaryWorkspaceRoot) {
231
+ return loadForeignNxProjects(root);
232
+ }
233
+ const graph = await createProjectGraphAsync({ exitOnError: false });
234
+ return nxProjectsFromNodes(graph.nodes);
240
235
  }
241
236
 
242
- async function readProjectTarget(root: string, project: string): Promise<ProjectTargets> {
243
- const command = nxShowProjectCommand(project);
244
- const result = await $`${command.command} ${command.args}`.cwd(root).quiet();
245
- const parsed = parseNxProjectJsonText(decode(result.stdout));
246
- if (!parsed) {
247
- throw new Error(`Unable to inspect Nx project ${project}.`);
237
+ const FOREIGN_GRAPH_SCRIPT = `
238
+ import('nx/src/project-graph/project-graph.js')
239
+ .then(async ({ createProjectGraphAsync }) => {
240
+ const graph = await createProjectGraphAsync({ exitOnError: false });
241
+ const projects = Object.fromEntries(
242
+ Object.entries(graph.nodes).map(([name, node]) => [
243
+ name,
244
+ { ...node.data, name: node.data?.name ?? name, targets: node.data?.targets ?? {} },
245
+ ]),
246
+ );
247
+ process.stdout.write(JSON.stringify(projects));
248
+ })
249
+ .catch((error) => {
250
+ console.error(error);
251
+ process.exitCode = 1;
252
+ });
253
+ `;
254
+
255
+ async function loadForeignNxProjects(root: string): Promise<NxProjects> {
256
+ const result = await runResult(process.execPath, ['--eval', FOREIGN_GRAPH_SCRIPT], root, {
257
+ NX_DAEMON: 'false',
258
+ NX_ISOLATE_PLUGINS: 'false',
259
+ NX_WORKSPACE_ROOT_PATH: root,
260
+ });
261
+ if (result.exitCode !== 0) {
262
+ throw new Error(`Failed to load Nx project graph for ${root}: ${result.stderr.trim()}`);
263
+ }
264
+ const parsed: unknown = JSON.parse(result.stdout);
265
+ if (!isNxProjects(parsed)) {
266
+ throw new Error(`Nx returned an invalid project graph for ${root}`);
248
267
  }
249
- const targetDependencies = targetDependenciesFromNxProjectJson(parsed);
250
- return {
251
- project,
252
- root: projectRootFromNxProjectJson(parsed),
253
- targets: targetNamesFromNxProjectJson(parsed),
254
- buildDependsOn: targetDependencies.get('build'),
255
- targetDependencies,
256
- targetExecutors: targetExecutorsFromNxProjectJson(parsed),
257
- targetOutputs: targetOutputsFromNxProjectJson(parsed),
258
- targetScripts: targetScriptsFromNxProjectJson(parsed),
259
- };
268
+ return parsed;
269
+ }
270
+
271
+ function nxProjectsFromNodes(nodes: Readonly<Record<string, { data: NxProjectJson }>>): NxProjects {
272
+ const projects: Record<string, NxProjectJson> = {};
273
+ for (const [name, node] of Object.entries(nodes)) {
274
+ projects[name] = {
275
+ ...node.data,
276
+ name: node.data.name ?? name,
277
+ targets: node.data.targets ?? {},
278
+ };
279
+ }
280
+ return projects;
281
+ }
282
+
283
+ function isNxProjects(value: unknown): value is NxProjects {
284
+ if (!isRecord(value)) return false;
285
+ return Object.values(value).every(
286
+ (project) =>
287
+ isRecord(project) &&
288
+ (project.name === undefined || typeof project.name === 'string') &&
289
+ (project.root === undefined || typeof project.root === 'string') &&
290
+ (project.targets === undefined || (isRecord(project.targets) && Object.values(project.targets).every(isRecord))),
291
+ );
292
+ }
293
+
294
+ function isRecord(value: unknown): value is Record<string, unknown> {
295
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
296
+ }
297
+
298
+ export function targetNamesFromProjects(projects: NxProjects): string[] {
299
+ const names = new Set<string>();
300
+ for (const project of Object.values(projects)) {
301
+ for (const targetName of targetNamesFromNxProjectJson(project)) {
302
+ names.add(targetName);
303
+ }
304
+ }
305
+ return [...names];
306
+ }
307
+
308
+ export function projectTargetsFromNxProjects(projects: NxProjects): ProjectTargets[] {
309
+ return Object.entries(projects)
310
+ .sort(([left], [right]) => left.localeCompare(right))
311
+ .map(([project, metadata]) => {
312
+ const targetDependencies = targetDependenciesFromNxProjectJson(metadata);
313
+ return {
314
+ project,
315
+ root: projectRootFromNxProjectJson(metadata),
316
+ targets: targetNamesFromNxProjectJson(metadata),
317
+ buildDependsOn: targetDependencies.get('build'),
318
+ targetDependencies,
319
+ targetExecutors: targetExecutorsFromNxProjectJson(metadata),
320
+ targetOptions: targetOptionsFromNxProjectJson(metadata),
321
+ targetOutputs: targetOutputsFromNxProjectJson(metadata),
322
+ targetScripts: targetScriptsFromNxProjectJson(metadata),
323
+ };
324
+ });
325
+ }
326
+
327
+ export async function readProjectTargets(root: string): Promise<ProjectTargets[]> {
328
+ return projectTargetsFromNxProjects(await loadNxProjects(root));
260
329
  }
261
330
 
262
331
  export type { NxProjectJson, NxTargetConfig };
@@ -1,67 +0,0 @@
1
- --- a/driver/emit_plugin.go
2
- +++ b/driver/emit_plugin.go
3
- @@ -163,6 +163,32 @@
4
- }
5
- host := &pluginEmitHost{program: p.TSProgram, emitResolver: p.Checker.GetEmitResolver()}
6
- options := p.TSProgram.Options()
7
- + // Declaration emit must observe the original program before plugin transforms
8
- + // can mutate source-file nodes while assembling JavaScript output.
9
- + if options.GetEmitDeclarations() {
10
- + var wfMu sync.Mutex
11
- + result := p.TSProgram.Emit(context.Background(), shimcompiler.EmitOptions{
12
- + EmitOnly: shimcompiler.EmitOnlyDts,
13
- + WriteFile: func(fileName string, text string, data *shimcompiler.WriteFileData) error {
14
- + wfMu.Lock()
15
- + defer wfMu.Unlock()
16
- + if p.outputEscapesOutDir(fileName) {
17
- + if data != nil {
18
- + data.SkippedDtsWrite = true
19
- + }
20
- + return nil
21
- + }
22
- + if writeFile != nil {
23
- + return writeFile(fileName, text, data)
24
- + }
25
- + return DefaultWriteFile(fileName, text)
26
- + },
27
- + })
28
- + if result != nil && len(result.Diagnostics) != 0 {
29
- + return convertDiagnostics(result.Diagnostics), nil
30
- + }
31
- + }
32
- +
33
- for _, sf := range shimcompiler.GetSourceFilesToEmit(host, nil, false) {
34
- paths := shimcompiler.GetOutputPathsFor(sf, options, host, false)
35
- if paths.JsFilePath() != "" && !p.outputEscapesOutDir(paths.JsFilePath()) {
36
- @@ -212,31 +238,6 @@
37
- }
38
- }
39
- }
40
- - if !options.GetEmitDeclarations() {
41
- - return nil, nil
42
- - }
43
- -
44
- - var wfMu sync.Mutex
45
- - result := p.TSProgram.Emit(context.Background(), shimcompiler.EmitOptions{
46
- - EmitOnly: shimcompiler.EmitOnlyDts,
47
- - WriteFile: func(fileName string, text string, data *shimcompiler.WriteFileData) error {
48
- - wfMu.Lock()
49
- - defer wfMu.Unlock()
50
- - if p.outputEscapesOutDir(fileName) {
51
- - if data != nil {
52
- - data.SkippedDtsWrite = true
53
- - }
54
- - return nil
55
- - }
56
- - if writeFile != nil {
57
- - return writeFile(fileName, text, data)
58
- - }
59
- - return DefaultWriteFile(fileName, text)
60
- - },
61
- - })
62
- - if result != nil && len(result.Diagnostics) != 0 {
63
- - return convertDiagnostics(result.Diagnostics), nil
64
- - }
65
- return nil, nil
66
- }
67
-