@fluojs/cli 2.0.1 → 3.0.0

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 (118) hide show
  1. package/README.ko.md +169 -21
  2. package/README.md +172 -21
  3. package/dist/cli.d.ts +5 -4
  4. package/dist/cli.d.ts.map +1 -1
  5. package/dist/cli.js +127 -35
  6. package/dist/commands/diagnostics.d.ts +35 -0
  7. package/dist/commands/diagnostics.d.ts.map +1 -1
  8. package/dist/commands/diagnostics.js +60 -0
  9. package/dist/commands/inspect.d.ts +5 -1
  10. package/dist/commands/inspect.d.ts.map +1 -1
  11. package/dist/commands/inspect.js +84 -17
  12. package/dist/commands/migrate.d.ts.map +1 -1
  13. package/dist/commands/migrate.js +27 -15
  14. package/dist/commands/migration-transform-tokens.d.ts +15 -0
  15. package/dist/commands/migration-transform-tokens.d.ts.map +1 -0
  16. package/dist/commands/migration-transform-tokens.js +41 -0
  17. package/dist/commands/new.d.ts.map +1 -1
  18. package/dist/commands/new.js +29 -9
  19. package/dist/commands/output-path-safety.d.ts +14 -0
  20. package/dist/commands/output-path-safety.d.ts.map +1 -0
  21. package/dist/commands/output-path-safety.js +34 -0
  22. package/dist/commands/scripts.js +2 -2
  23. package/dist/commands/typegen-artifact.d.ts +54 -0
  24. package/dist/commands/typegen-artifact.d.ts.map +1 -0
  25. package/dist/commands/typegen-artifact.js +117 -0
  26. package/dist/commands/typegen-generation-child.d.ts +2 -0
  27. package/dist/commands/typegen-generation-child.d.ts.map +1 -0
  28. package/dist/commands/typegen-generation-child.js +59 -0
  29. package/dist/commands/typegen-generation-process.d.ts +46 -0
  30. package/dist/commands/typegen-generation-process.d.ts.map +1 -0
  31. package/dist/commands/typegen-generation-process.js +131 -0
  32. package/dist/commands/typegen-generation-protocol.d.ts +16 -0
  33. package/dist/commands/typegen-generation-protocol.d.ts.map +1 -0
  34. package/dist/commands/typegen-generation-protocol.js +35 -0
  35. package/dist/commands/typegen-isolated-source.d.ts +10 -0
  36. package/dist/commands/typegen-isolated-source.d.ts.map +1 -0
  37. package/dist/commands/typegen-isolated-source.js +75 -0
  38. package/dist/commands/typegen-options.d.ts +20 -0
  39. package/dist/commands/typegen-options.d.ts.map +1 -0
  40. package/dist/commands/typegen-options.js +71 -0
  41. package/dist/commands/typegen-source.d.ts +59 -0
  42. package/dist/commands/typegen-source.d.ts.map +1 -0
  43. package/dist/commands/typegen-source.js +183 -0
  44. package/dist/commands/typegen-watch.d.ts +46 -0
  45. package/dist/commands/typegen-watch.d.ts.map +1 -0
  46. package/dist/commands/typegen-watch.js +212 -0
  47. package/dist/commands/typegen.d.ts +29 -0
  48. package/dist/commands/typegen.d.ts.map +1 -0
  49. package/dist/commands/typegen.js +119 -0
  50. package/dist/dev-runner/node-restart-runner.d.ts.map +1 -1
  51. package/dist/dev-runner/node-restart-runner.js +54 -7
  52. package/dist/fixtures/inspect-react-app.module.d.ts +4 -0
  53. package/dist/fixtures/inspect-react-app.module.d.ts.map +1 -0
  54. package/dist/fixtures/inspect-react-app.module.js +32 -0
  55. package/dist/fixtures/typegen-react-app.module.d.ts +4 -0
  56. package/dist/fixtures/typegen-react-app.module.d.ts.map +1 -0
  57. package/dist/fixtures/typegen-react-app.module.js +33 -0
  58. package/dist/index.d.ts +6 -5
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +3 -2
  61. package/dist/new/install.js +1 -1
  62. package/dist/new/package-spec-resolver.d.ts.map +1 -1
  63. package/dist/new/package-spec-resolver.js +50 -59
  64. package/dist/new/prompt.d.ts +1 -0
  65. package/dist/new/prompt.d.ts.map +1 -1
  66. package/dist/new/prompt.js +40 -12
  67. package/dist/new/published-internal-dependencies.d.ts +20 -0
  68. package/dist/new/published-internal-dependencies.d.ts.map +1 -0
  69. package/dist/new/published-internal-dependencies.js +20 -0
  70. package/dist/new/react-vite-ssr-scaffold.d.ts +19 -0
  71. package/dist/new/react-vite-ssr-scaffold.d.ts.map +1 -0
  72. package/dist/new/react-vite-ssr-scaffold.js +108 -0
  73. package/dist/new/resolver.d.ts +2 -2
  74. package/dist/new/resolver.d.ts.map +1 -1
  75. package/dist/new/resolver.js +5 -1
  76. package/dist/new/scaffold.d.ts.map +1 -1
  77. package/dist/new/scaffold.js +62 -31
  78. package/dist/new/starter-profiles.d.ts +8 -4
  79. package/dist/new/starter-profiles.d.ts.map +1 -1
  80. package/dist/new/starter-profiles.js +52 -18
  81. package/dist/new/templates/react-vite-ssr/README.md.ejs +74 -0
  82. package/dist/new/templates/react-vite-ssr/playwright.config.ts.ejs +26 -0
  83. package/dist/new/templates/react-vite-ssr/src/app.test.ts.ejs +82 -0
  84. package/dist/new/templates/react-vite-ssr/src/app.ts.ejs +91 -0
  85. package/dist/new/templates/react-vite-ssr/src/entry-client.tsx.ejs +29 -0
  86. package/dist/new/templates/react-vite-ssr/src/entry-server.tsx.ejs +52 -0
  87. package/dist/new/templates/react-vite-ssr/src/load-manifest.test.ts.ejs +55 -0
  88. package/dist/new/templates/react-vite-ssr/src/load-manifest.ts.ejs +53 -0
  89. package/dist/new/templates/react-vite-ssr/src/main.ts.ejs +18 -0
  90. package/dist/new/templates/react-vite-ssr/src/page.tsx.ejs +43 -0
  91. package/dist/new/templates/react-vite-ssr/src/react-app.test.tsx.ejs +67 -0
  92. package/dist/new/templates/react-vite-ssr/src/react-app.tsx.ejs +46 -0
  93. package/dist/new/templates/react-vite-ssr/src/styles.css.ejs +25 -0
  94. package/dist/new/templates/react-vite-ssr/src/styles.d.ts.ejs +1 -0
  95. package/dist/new/templates/react-vite-ssr/tests/production-hydration.spec.ts.ejs +54 -0
  96. package/dist/new/templates/react-vite-ssr/tsconfig.json.ejs +16 -0
  97. package/dist/new/templates/react-vite-ssr/vite.client.config.ts.ejs +24 -0
  98. package/dist/new/templates/react-vite-ssr/vite.server.config.ts.ejs +17 -0
  99. package/dist/new/templates/react-vite-ssr/vitest.config.ts.ejs +10 -0
  100. package/dist/new/types.d.ts +4 -0
  101. package/dist/new/types.d.ts.map +1 -1
  102. package/dist/public-typegen.d.ts +14 -0
  103. package/dist/public-typegen.d.ts.map +1 -0
  104. package/dist/public-typegen.js +17 -0
  105. package/dist/run-cli.d.ts +2 -1
  106. package/dist/run-cli.d.ts.map +1 -1
  107. package/dist/studio/sidecar.d.ts.map +1 -1
  108. package/dist/studio/sidecar.js +35 -9
  109. package/dist/transforms/nestjs-migrate.d.ts +4 -1
  110. package/dist/transforms/nestjs-migrate.d.ts.map +1 -1
  111. package/dist/transforms/nestjs-migrate.js +625 -65
  112. package/dist/typegen-contract.d.ts +10 -0
  113. package/dist/typegen-contract.d.ts.map +1 -0
  114. package/dist/typegen-contract.js +9 -0
  115. package/dist/usage.d.ts +6 -0
  116. package/dist/usage.d.ts.map +1 -1
  117. package/dist/usage.js +47 -0
  118. package/package.json +19 -10
@@ -205,7 +205,7 @@ export function createContentChangeGate(projectDirectory, ignorePatterns = DEFAU
205
205
  };
206
206
  }
207
207
  function getWatchTargets(projectDirectory) {
208
- return [join(projectDirectory, 'src'), ...WATCH_FILES.map(fileName => join(projectDirectory, fileName))].filter(target => existsSync(target));
208
+ return [join(projectDirectory, 'src'), ...WATCH_FILES.map(fileName => join(projectDirectory, fileName)).filter(target => existsSync(target))];
209
209
  }
210
210
  function stopChild(child, shutdownTimeoutMs = DEFAULT_CHILD_SHUTDOWN_TIMEOUT_MS) {
211
211
  if (child && child.exitCode === null) {
@@ -303,6 +303,7 @@ export async function runNodeRestartRunner(options) {
303
303
  const childShutdownTimeoutMs = Number(env.FLUO_DEV_CHILD_SHUTDOWN_TIMEOUT_MS ?? DEFAULT_CHILD_SHUTDOWN_TIMEOUT_MS);
304
304
  const ignorePatterns = parseIgnorePatterns(env);
305
305
  const gate = createContentChangeGate(projectDirectory, ignorePatterns);
306
+ const sourceDirectory = join(projectDirectory, 'src');
306
307
  const watchTargets = getWatchTargets(projectDirectory);
307
308
  let child;
308
309
  const pendingRestartPaths = new Set();
@@ -310,6 +311,7 @@ export async function runNodeRestartRunner(options) {
310
311
  let restartTimer;
311
312
  let restarting = false;
312
313
  let stopping = false;
314
+ let terminalExitCode;
313
315
  const startChild = (resolveExitCode, cleanup) => {
314
316
  ensureStudioEpoch(env);
315
317
  const appCommand = buildAppCommand(runnerRuntime, env, appArgs);
@@ -350,7 +352,7 @@ export async function runNodeRestartRunner(options) {
350
352
  reason: 'fluo dev runner stopped'
351
353
  });
352
354
  cleanup();
353
- resolveExitCode(code ?? 0);
355
+ resolveExitCode(terminalExitCode ?? code ?? 0);
354
356
  return;
355
357
  }
356
358
  publishStudioLifecycleEvent(env, runnerRuntime, 'disconnect', {
@@ -461,11 +463,33 @@ export async function runNodeRestartRunner(options) {
461
463
  signalTarget.off('SIGINT', stop);
462
464
  signalTarget.off('SIGTERM', stop);
463
465
  };
466
+ const failFromWatcher = (target, error) => {
467
+ if (stopping || resolved) {
468
+ return;
469
+ }
470
+ terminalExitCode = 1;
471
+ stopping = true;
472
+ stderr.write(`[fluo] watcher failed for ${target}: ${error.message}\n`);
473
+ cleanup();
474
+ const stoppingChild = child;
475
+ if (!stoppingChild || stoppingChild.exitCode !== null) {
476
+ resolveOnce(terminalExitCode);
477
+ return;
478
+ }
479
+ stoppingChild.once('close', () => resolveOnce(1));
480
+ if (!restarting) {
481
+ stopChild(stoppingChild, childShutdownTimeoutMs);
482
+ }
483
+ };
484
+ const registerWatcher = (target, watcher) => {
485
+ watchers.push(watcher);
486
+ watcher.on?.('error', error => failFromWatcher(target, error));
487
+ };
464
488
  startChild(resolveExitCode, cleanup);
465
489
  const watchedFallbackDirectories = new Set();
466
490
  const watchFallbackDirectory = directoryPath => {
467
491
  if (watchedFallbackDirectories.has(directoryPath) || shouldIgnorePath(directoryPath, projectDirectory, ignorePatterns)) {
468
- return;
492
+ return false;
469
493
  }
470
494
  watchedFallbackDirectories.add(directoryPath);
471
495
  const listener = (_event, filename) => {
@@ -473,14 +497,22 @@ export async function runNodeRestartRunner(options) {
473
497
  const changedPath = filename ? join(directoryPath, fileName) : directoryPath;
474
498
  scheduleRestart(changedPath, resolveExitCode, cleanup);
475
499
  for (const nextDirectoryPath of getFallbackWatchDirectories(changedPath, projectDirectory, ignorePatterns)) {
476
- watchFallbackDirectory(nextDirectoryPath);
500
+ if (watchedFallbackDirectories.has(nextDirectoryPath) || shouldIgnorePath(nextDirectoryPath, projectDirectory, ignorePatterns)) {
501
+ continue;
502
+ }
503
+ if (!watchFallbackDirectory(nextDirectoryPath)) {
504
+ failFromWatcher(nextDirectoryPath, new Error('required fallback watcher could not be acquired'));
505
+ return;
506
+ }
477
507
  }
478
508
  };
479
509
  try {
480
- watchers.push(watchTarget(directoryPath, listener));
510
+ registerWatcher(directoryPath, watchTarget(directoryPath, listener));
511
+ return true;
481
512
  } catch (error) {
482
513
  watchedFallbackDirectories.delete(directoryPath);
483
514
  stderr.write(`[fluo] unable to watch ${directoryPath}: ${error instanceof Error ? error.message : String(error)}\n`);
515
+ return false;
484
516
  }
485
517
  };
486
518
  for (const target of watchTargets) {
@@ -494,16 +526,31 @@ export async function runNodeRestartRunner(options) {
494
526
  scheduleRestart(stats.isDirectory() ? join(target, fileName) : target, resolveExitCode, cleanup);
495
527
  };
496
528
  try {
497
- watchers.push(watchTarget(target, watchOptions, listener));
529
+ registerWatcher(target, watchTarget(target, watchOptions, listener));
498
530
  } catch (error) {
499
531
  if (!stats.isDirectory()) {
500
532
  throw error;
501
533
  }
534
+ let sourceCoverageAcquired = false;
502
535
  for (const directoryPath of getFallbackWatchDirectories(target, projectDirectory, ignorePatterns)) {
503
- watchFallbackDirectory(directoryPath);
536
+ if (!watchFallbackDirectory(directoryPath)) {
537
+ const message = error instanceof Error ? error.message : String(error);
538
+ failFromWatcher(target, new Error(`${message}; required fallback watcher could not be acquired`));
539
+ return;
540
+ }
541
+ sourceCoverageAcquired ||= directoryPath === target;
542
+ }
543
+ if (!sourceCoverageAcquired) {
544
+ const message = error instanceof Error ? error.message : String(error);
545
+ failFromWatcher(target, new Error(`${message}; required fallback watcher could not be acquired`));
546
+ return;
504
547
  }
505
548
  }
506
549
  } catch (error) {
550
+ if (target === sourceDirectory) {
551
+ failFromWatcher(target, error instanceof Error ? error : new Error(String(error)));
552
+ return;
553
+ }
507
554
  stderr.write(`[fluo] unable to watch ${target}: ${error instanceof Error ? error.message : String(error)}\n`);
508
555
  }
509
556
  }
@@ -0,0 +1,4 @@
1
+ /** Fixture application module used by build-less React route inspection tests. */
2
+ export declare class AppModule {
3
+ }
4
+ //# sourceMappingURL=inspect-react-app.module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inspect-react-app.module.d.ts","sourceRoot":"","sources":["../../src/fixtures/inspect-react-app.module.ts"],"names":[],"mappings":"AASA,kFAAkF;AAClF,qBAAa,SAAS;CAAG"}
@@ -0,0 +1,32 @@
1
+ let _initProto, _initClass;
2
+ function _applyDecs(e, t, n, r, o, i) { var a, c, u, s, f, l, p, d = Symbol.metadata || Symbol.for("Symbol.metadata"), m = Object.defineProperty, h = Object.create, y = [h(null), h(null)], v = t.length; function g(t, n, r) { return function (o, i) { n && (i = o, o = e); for (var a = 0; a < t.length; a++) i = t[a].apply(o, r ? [i] : []); return r ? i : o; }; } function b(e, t, n, r) { if ("function" != typeof e && (r || void 0 !== e)) throw new TypeError(t + " must " + (n || "be") + " a function" + (r ? "" : " or undefined")); return e; } function applyDec(e, t, n, r, o, i, u, s, f, l, p) { function d(e) { if (!p(e)) throw new TypeError("Attempted to access private element on non-instance"); } var h = [].concat(t[0]), v = t[3], w = !u, D = 1 === o, S = 3 === o, j = 4 === o, E = 2 === o; function I(t, n, r) { return function (o, i) { return n && (i = o, o = e), r && r(o), P[t].call(o, i); }; } if (!w) { var P = {}, k = [], F = S ? "get" : j || D ? "set" : "value"; if (f ? (l || D ? P = { get: _setFunctionName(function () { return v(this); }, r, "get"), set: function (e) { t[4](this, e); } } : P[F] = v, l || _setFunctionName(P[F], r, E ? "" : F)) : l || (P = Object.getOwnPropertyDescriptor(e, r)), !l && !f) { if ((c = y[+s][r]) && 7 !== (c ^ o)) throw Error("Decorating two elements with the same name (" + P[F].name + ") is not supported yet"); y[+s][r] = o < 3 ? 1 : o; } } for (var N = e, O = h.length - 1; O >= 0; O -= n ? 2 : 1) { var T = b(h[O], "A decorator", "be", !0), z = n ? h[O - 1] : void 0, A = {}, H = { kind: ["field", "accessor", "method", "getter", "setter", "class"][o], name: r, metadata: a, addInitializer: function (e, t) { if (e.v) throw new TypeError("attempted to call addInitializer after decoration was finished"); b(t, "An initializer", "be", !0), i.push(t); }.bind(null, A) }; if (w) c = T.call(z, N, H), A.v = 1, b(c, "class decorators", "return") && (N = c);else if (H.static = s, H.private = f, c = H.access = { has: f ? p.bind() : function (e) { return r in e; } }, j || (c.get = f ? E ? function (e) { return d(e), P.value; } : I("get", 0, d) : function (e) { return e[r]; }), E || S || (c.set = f ? I("set", 0, d) : function (e, t) { e[r] = t; }), N = T.call(z, D ? { get: P.get, set: P.set } : P[F], H), A.v = 1, D) { if ("object" == typeof N && N) (c = b(N.get, "accessor.get")) && (P.get = c), (c = b(N.set, "accessor.set")) && (P.set = c), (c = b(N.init, "accessor.init")) && k.unshift(c);else if (void 0 !== N) throw new TypeError("accessor decorators must return an object with get, set, or init properties or undefined"); } else b(N, (l ? "field" : "method") + " decorators", "return") && (l ? k.unshift(N) : P[F] = N); } return o < 2 && u.push(g(k, s, 1), g(i, s, 0)), l || w || (f ? D ? u.splice(-1, 0, I("get", s), I("set", s)) : u.push(E ? P[F] : b.call.bind(P[F])) : m(e, r, P)), N; } function w(e) { return m(e, d, { configurable: !0, enumerable: !0, value: a }); } return void 0 !== i && (a = i[d]), a = h(null == a ? null : a), f = [], l = function (e) { e && f.push(g(e)); }, p = function (t, r) { for (var i = 0; i < n.length; i++) { var a = n[i], c = a[1], l = 7 & c; if ((8 & c) == t && !l == r) { var p = a[2], d = !!a[3], m = 16 & c; applyDec(t ? e : e.prototype, a, m, d ? "#" + p : _toPropertyKey(p), l, l < 2 ? [] : t ? s = s || [] : u = u || [], f, !!t, d, r, t && d ? function (t) { return _checkInRHS(t) === e; } : o); } } }, p(8, 0), p(0, 0), p(8, 1), p(0, 1), l(u), l(s), c = f, v || w(e), { e: c, get c() { var n = []; return v && [w(e = applyDec(e, [t], r, e.name, 5, n)), g(n, 1)]; } }; }
3
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
4
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
5
+ function _setFunctionName(e, t, n) { "symbol" == typeof t && (t = (t = t.description) ? "[" + t + "]" : ""); try { Object.defineProperty(e, "name", { configurable: !0, value: n ? n + " " + t : t }); } catch (e) {} return e; }
6
+ function _checkInRHS(e) { if (Object(e) !== e) throw TypeError("right-hand side of 'in' should be an object, got " + (null !== e ? typeof e : "null")); return e; }
7
+ import { defineModule } from '@fluojs/runtime';
8
+ import { Path, ReactModule, Router } from '@fluojs/react';
9
+ let _ProductRouter;
10
+ class ProductRouter {
11
+ static {
12
+ ({
13
+ e: [_initProto],
14
+ c: [_ProductRouter, _initClass]
15
+ } = _applyDecs(this, [Router('/products')], [[Path('/:productId'), 2, "show"]]));
16
+ }
17
+ constructor() {
18
+ _initProto(this);
19
+ }
20
+ show() {}
21
+ static {
22
+ _initClass();
23
+ }
24
+ }
25
+
26
+ /** Fixture application module used by build-less React route inspection tests. */
27
+ export class AppModule {}
28
+ defineModule(AppModule, {
29
+ imports: [ReactModule.forRoot({
30
+ controllers: [_ProductRouter]
31
+ })]
32
+ });
@@ -0,0 +1,4 @@
1
+ /** Fixture root module used by CLI React page typegen tests. */
2
+ export declare class AppModule {
3
+ }
4
+ //# sourceMappingURL=typegen-react-app.module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typegen-react-app.module.d.ts","sourceRoot":"","sources":["../../src/fixtures/typegen-react-app.module.ts"],"names":[],"mappings":"AAYA,gEAAgE;AAChE,qBAAa,SAAS;CAAG"}
@@ -0,0 +1,33 @@
1
+ let _initProto, _initClass;
2
+ function _applyDecs(e, t, n, r, o, i) { var a, c, u, s, f, l, p, d = Symbol.metadata || Symbol.for("Symbol.metadata"), m = Object.defineProperty, h = Object.create, y = [h(null), h(null)], v = t.length; function g(t, n, r) { return function (o, i) { n && (i = o, o = e); for (var a = 0; a < t.length; a++) i = t[a].apply(o, r ? [i] : []); return r ? i : o; }; } function b(e, t, n, r) { if ("function" != typeof e && (r || void 0 !== e)) throw new TypeError(t + " must " + (n || "be") + " a function" + (r ? "" : " or undefined")); return e; } function applyDec(e, t, n, r, o, i, u, s, f, l, p) { function d(e) { if (!p(e)) throw new TypeError("Attempted to access private element on non-instance"); } var h = [].concat(t[0]), v = t[3], w = !u, D = 1 === o, S = 3 === o, j = 4 === o, E = 2 === o; function I(t, n, r) { return function (o, i) { return n && (i = o, o = e), r && r(o), P[t].call(o, i); }; } if (!w) { var P = {}, k = [], F = S ? "get" : j || D ? "set" : "value"; if (f ? (l || D ? P = { get: _setFunctionName(function () { return v(this); }, r, "get"), set: function (e) { t[4](this, e); } } : P[F] = v, l || _setFunctionName(P[F], r, E ? "" : F)) : l || (P = Object.getOwnPropertyDescriptor(e, r)), !l && !f) { if ((c = y[+s][r]) && 7 !== (c ^ o)) throw Error("Decorating two elements with the same name (" + P[F].name + ") is not supported yet"); y[+s][r] = o < 3 ? 1 : o; } } for (var N = e, O = h.length - 1; O >= 0; O -= n ? 2 : 1) { var T = b(h[O], "A decorator", "be", !0), z = n ? h[O - 1] : void 0, A = {}, H = { kind: ["field", "accessor", "method", "getter", "setter", "class"][o], name: r, metadata: a, addInitializer: function (e, t) { if (e.v) throw new TypeError("attempted to call addInitializer after decoration was finished"); b(t, "An initializer", "be", !0), i.push(t); }.bind(null, A) }; if (w) c = T.call(z, N, H), A.v = 1, b(c, "class decorators", "return") && (N = c);else if (H.static = s, H.private = f, c = H.access = { has: f ? p.bind() : function (e) { return r in e; } }, j || (c.get = f ? E ? function (e) { return d(e), P.value; } : I("get", 0, d) : function (e) { return e[r]; }), E || S || (c.set = f ? I("set", 0, d) : function (e, t) { e[r] = t; }), N = T.call(z, D ? { get: P.get, set: P.set } : P[F], H), A.v = 1, D) { if ("object" == typeof N && N) (c = b(N.get, "accessor.get")) && (P.get = c), (c = b(N.set, "accessor.set")) && (P.set = c), (c = b(N.init, "accessor.init")) && k.unshift(c);else if (void 0 !== N) throw new TypeError("accessor decorators must return an object with get, set, or init properties or undefined"); } else b(N, (l ? "field" : "method") + " decorators", "return") && (l ? k.unshift(N) : P[F] = N); } return o < 2 && u.push(g(k, s, 1), g(i, s, 0)), l || w || (f ? D ? u.splice(-1, 0, I("get", s), I("set", s)) : u.push(E ? P[F] : b.call.bind(P[F])) : m(e, r, P)), N; } function w(e) { return m(e, d, { configurable: !0, enumerable: !0, value: a }); } return void 0 !== i && (a = i[d]), a = h(null == a ? null : a), f = [], l = function (e) { e && f.push(g(e)); }, p = function (t, r) { for (var i = 0; i < n.length; i++) { var a = n[i], c = a[1], l = 7 & c; if ((8 & c) == t && !l == r) { var p = a[2], d = !!a[3], m = 16 & c; applyDec(t ? e : e.prototype, a, m, d ? "#" + p : _toPropertyKey(p), l, l < 2 ? [] : t ? s = s || [] : u = u || [], f, !!t, d, r, t && d ? function (t) { return _checkInRHS(t) === e; } : o); } } }, p(8, 0), p(0, 0), p(8, 1), p(0, 1), l(u), l(s), c = f, v || w(e), { e: c, get c() { var n = []; return v && [w(e = applyDec(e, [t], r, e.name, 5, n)), g(n, 1)]; } }; }
3
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
4
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
5
+ function _setFunctionName(e, t, n) { "symbol" == typeof t && (t = (t = t.description) ? "[" + t + "]" : ""); try { Object.defineProperty(e, "name", { configurable: !0, value: n ? n + " " + t : t }); } catch (e) {} return e; }
6
+ function _checkInRHS(e) { if (Object(e) !== e) throw TypeError("right-hand side of 'in' should be an object, got " + (null !== e ? typeof e : "null")); return e; }
7
+ import { defineModule } from '@fluojs/runtime';
8
+ import { Path, ReactModule, Router } from '@fluojs/react';
9
+ let _ProductRouter;
10
+ class ProductRouter {
11
+ static {
12
+ ({
13
+ e: [_initProto],
14
+ c: [_ProductRouter, _initClass]
15
+ } = _applyDecs(this, [Router('/products')], [[Path('/'), 2, "index"], [Path('/:productId'), 2, "show"]]));
16
+ }
17
+ constructor() {
18
+ _initProto(this);
19
+ }
20
+ index() {}
21
+ show() {}
22
+ static {
23
+ _initClass();
24
+ }
25
+ }
26
+
27
+ /** Fixture root module used by CLI React page typegen tests. */
28
+ export class AppModule {}
29
+ defineModule(AppModule, {
30
+ imports: [ReactModule.forRoot({
31
+ controllers: [_ProductRouter]
32
+ })]
33
+ });
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
- export { runCli, type CliRuntimeOptions } from './run-cli.js';
2
- export { runGenerateCommand, type GeneratePlanAction, type GeneratePlanEntry, type GenerateResult } from './public-generate.js';
3
- export { inspectUsage, runInspectCommand, type InspectCommandRuntimeOptions } from './public-inspect.js';
4
- export { newUsage, runNewCommand, type NewCommandRuntimeOptions } from './public-new.js';
5
1
  export { CliPromptCancelledError } from './prompt-cancel.js';
6
- export type { GenerateOptions, GeneratedFile, GeneratorKind, ModuleRegistration } from './types.js';
2
+ export { type GeneratePlanAction, type GeneratePlanEntry, type GenerateResult, runGenerateCommand } from './public-generate.js';
3
+ export { type InspectCommandRuntimeOptions, inspectUsage, runInspectCommand } from './public-inspect.js';
4
+ export { type NewCommandRuntimeOptions, newUsage, runNewCommand } from './public-new.js';
5
+ export { runTypegenCommand, TYPEGEN_EXIT_CODES, type TypegenCommandRuntimeOptions, typegenUsage } from './public-typegen.js';
6
+ export { type CliRuntimeOptions, runCli } from './run-cli.js';
7
+ export type { GeneratedFile, GenerateOptions, GeneratorKind, ModuleRegistration } from './types.js';
7
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,KAAK,kBAAkB,EAAE,KAAK,iBAAiB,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAChI,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,KAAK,4BAA4B,EAAE,MAAM,qBAAqB,CAAC;AACzG,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,KAAK,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AACzF,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EAAE,KAAK,kBAAkB,EAAE,KAAK,iBAAiB,EAAE,KAAK,cAAc,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAChI,OAAO,EAAE,KAAK,4BAA4B,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACzG,OAAO,EAAE,KAAK,wBAAwB,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACzF,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,KAAK,4BAA4B,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAC7H,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC9D,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
- export { runCli } from './run-cli.js';
1
+ export { CliPromptCancelledError } from './prompt-cancel.js';
2
2
  export { runGenerateCommand } from './public-generate.js';
3
3
  export { inspectUsage, runInspectCommand } from './public-inspect.js';
4
4
  export { newUsage, runNewCommand } from './public-new.js';
5
- export { CliPromptCancelledError } from './prompt-cancel.js';
5
+ export { runTypegenCommand, TYPEGEN_EXIT_CODES, typegenUsage } from './public-typegen.js';
6
+ export { runCli } from './run-cli.js';
@@ -23,7 +23,7 @@ function appendStreamOutput(stream, output) {
23
23
  function waitForChildProcess(child, capturedOutput) {
24
24
  return new Promise((resolve, reject) => {
25
25
  child.on('error', reject);
26
- child.on('exit', code => {
26
+ child.on('close', code => {
27
27
  if (code === 0) {
28
28
  resolve();
29
29
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"package-spec-resolver.d.ts","sourceRoot":"","sources":["../../src/new/package-spec-resolver.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAkhBnD;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,gBAAgB,EACzB,aAAa,EAAE,qBAAqB,GACnC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAgCjC"}
1
+ {"version":3,"file":"package-spec-resolver.d.ts","sourceRoot":"","sources":["../../src/new/package-spec-resolver.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAshBnD;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,gBAAgB,EACzB,aAAa,EAAE,qBAAqB,GACnC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAiCjC"}
@@ -3,40 +3,35 @@ import { createHash } from 'node:crypto';
3
3
  import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
4
4
  import { tmpdir } from 'node:os';
5
5
  import { join, resolve } from 'node:path';
6
- const PACKAGE_DIRECTORY_BY_NAME = {
7
- '@fluojs/platform-bun': 'platform-bun',
8
- '@fluojs/cli': 'cli',
9
- '@fluojs/config': 'config',
10
- '@fluojs/core': 'core',
11
- '@fluojs/di': 'di',
12
- '@fluojs/http': 'http',
13
- '@fluojs/platform-cloudflare-workers': 'platform-cloudflare-workers',
14
- '@fluojs/platform-deno': 'platform-deno',
15
- '@fluojs/microservices': 'microservices',
16
- '@fluojs/platform-express': 'platform-express',
17
- '@fluojs/platform-fastify': 'platform-fastify',
18
- '@fluojs/platform-nodejs': 'platform-nodejs',
19
- '@fluojs/runtime': 'runtime',
20
- '@fluojs/testing': 'testing',
21
- '@fluojs/validation': 'validation'
22
- };
23
6
  const LOCAL_PACKAGE_CACHE_DIR = join(tmpdir(), 'fluo-cli-local-packages');
24
7
  const LOCAL_PACKAGE_CACHE_STAMP_FILE = 'cache-stamp.json';
25
8
  const LOCAL_PACKAGE_CACHE_FORMAT_VERSION = 2;
26
9
  function expectedTarballName(packageName, version) {
27
10
  return `${packageName.replace(/^@/, '').replace(/\//g, '-')}-${version}.tgz`;
28
11
  }
29
- function readLocalPackageVersion(repoRoot, packageName) {
30
- const packageDirectory = PACKAGE_DIRECTORY_BY_NAME[packageName];
31
- const packageJson = JSON.parse(readFileSync(join(repoRoot, 'packages', packageDirectory, 'package.json'), 'utf8'));
32
- return packageJson.version;
33
- }
34
- function readLocalPackageManifest(repoRoot, packageName) {
35
- const packageDirectory = PACKAGE_DIRECTORY_BY_NAME[packageName];
36
- return JSON.parse(readFileSync(join(repoRoot, 'packages', packageDirectory, 'package.json'), 'utf8'));
12
+ function collectLocalPackages(repoRoot) {
13
+ const packagesByName = new Map();
14
+ const packagesRoot = join(repoRoot, 'packages');
15
+ for (const entry of readdirSync(packagesRoot, {
16
+ withFileTypes: true
17
+ })) {
18
+ const packageJsonPath = join(packagesRoot, entry.name, 'package.json');
19
+ if (!entry.isDirectory() || !existsSync(packageJsonPath)) {
20
+ continue;
21
+ }
22
+ const manifest = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
23
+ if (typeof manifest.name !== 'string' || typeof manifest.version !== 'string') {
24
+ continue;
25
+ }
26
+ packagesByName.set(manifest.name, {
27
+ directory: entry.name,
28
+ manifest
29
+ });
30
+ }
31
+ return packagesByName;
37
32
  }
38
- function collectRequiredLocalPackages(repoRoot, bootstrapPlan) {
39
- const pending = [...bootstrapPlan.dependencies.dependencies, ...bootstrapPlan.dependencies.devDependencies].filter(packageName => packageName in PACKAGE_DIRECTORY_BY_NAME);
33
+ function collectRequiredLocalPackages(localPackages, bootstrapPlan) {
34
+ const pending = [...bootstrapPlan.dependencies.dependencies, ...bootstrapPlan.dependencies.devDependencies].filter(packageName => localPackages.has(packageName));
40
35
  const selected = new Set();
41
36
  while (pending.length > 0) {
42
37
  const packageName = pending.pop();
@@ -44,14 +39,13 @@ function collectRequiredLocalPackages(repoRoot, bootstrapPlan) {
44
39
  continue;
45
40
  }
46
41
  selected.add(packageName);
47
- const manifest = readLocalPackageManifest(repoRoot, packageName);
42
+ const manifest = localPackages.get(packageName)?.manifest;
43
+ if (!manifest) {
44
+ continue;
45
+ }
48
46
  for (const section of ['dependencies', 'optionalDependencies', 'peerDependencies']) {
49
- const dependencies = manifest[section];
50
- if (!dependencies) {
51
- continue;
52
- }
53
- for (const dependencyName of Object.keys(dependencies)) {
54
- if (dependencyName in PACKAGE_DIRECTORY_BY_NAME) {
47
+ for (const dependencyName of Object.keys(manifest[section] ?? {})) {
48
+ if (localPackages.has(dependencyName)) {
55
49
  pending.push(dependencyName);
56
50
  }
57
51
  }
@@ -59,12 +53,8 @@ function collectRequiredLocalPackages(repoRoot, bootstrapPlan) {
59
53
  }
60
54
  return Array.from(selected);
61
55
  }
62
- function collectLocalPackageVersions(repoRoot, packageNames) {
63
- const packageVersions = new Map();
64
- for (const packageName of packageNames) {
65
- packageVersions.set(packageName, readLocalPackageVersion(repoRoot, packageName));
66
- }
67
- return packageVersions;
56
+ function collectLocalPackageVersions(localPackages, packageNames) {
57
+ return new Map(packageNames.map(packageName => [packageName, localPackages.get(packageName).manifest.version]));
68
58
  }
69
59
  function getPackageVersionOrThrow(packageVersions, packageName) {
70
60
  const packageVersion = packageVersions.get(packageName);
@@ -91,10 +81,10 @@ function runGitCommand(repoRoot, args) {
91
81
  return undefined;
92
82
  }
93
83
  }
94
- function createPackagePathArguments(packageNames) {
84
+ function createPackagePathArguments(localPackages, packageNames) {
95
85
  const packagePaths = new Set();
96
86
  for (const packageName of packageNames) {
97
- const packageDirectory = PACKAGE_DIRECTORY_BY_NAME[packageName];
87
+ const packageDirectory = localPackages.get(packageName).directory;
98
88
  const packageRoot = join('packages', packageDirectory);
99
89
  packagePaths.add(packageRoot);
100
90
  packagePaths.add(join(packageRoot, 'src'));
@@ -139,8 +129,8 @@ function collectPackageStagePaths(packageRoot, manifest) {
139
129
  }
140
130
  return Array.from(stagePaths);
141
131
  }
142
- function stagePackageForPacking(repoRoot, packageName, packageVersions, outputDirectory) {
143
- const packageDirectory = PACKAGE_DIRECTORY_BY_NAME[packageName];
132
+ function stagePackageForPacking(repoRoot, localPackages, packageName, packageVersions, outputDirectory) {
133
+ const packageDirectory = localPackages.get(packageName).directory;
144
134
  const packageRoot = join(repoRoot, 'packages', packageDirectory);
145
135
  const stageDirectory = join(outputDirectory, `.stage-${packageDirectory}`);
146
136
  const manifest = JSON.parse(readFileSync(join(packageRoot, 'package.json'), 'utf8'));
@@ -158,12 +148,12 @@ function stagePackageForPacking(repoRoot, packageName, packageVersions, outputDi
158
148
  writeFileSync(join(stageDirectory, 'package.json'), `${JSON.stringify(manifest, null, 2)}\n`, 'utf8');
159
149
  return stageDirectory;
160
150
  }
161
- function computeLocalPackageCacheStamp(repoRoot, packageNames, packageVersions) {
151
+ function computeLocalPackageCacheStamp(repoRoot, localPackages, packageNames, packageVersions) {
162
152
  const headCommit = runGitCommand(repoRoot, ['rev-parse', 'HEAD']);
163
153
  if (!headCommit) {
164
154
  return undefined;
165
155
  }
166
- const packagePaths = createPackagePathArguments(packageNames);
156
+ const packagePaths = createPackagePathArguments(localPackages, packageNames);
167
157
  const dirtyFingerprint = runGitCommand(repoRoot, ['status', '--porcelain', '--', ...packagePaths]);
168
158
  if (dirtyFingerprint === undefined) {
169
159
  return undefined;
@@ -246,8 +236,8 @@ function latestModifiedTimeMs(path) {
246
236
  }
247
237
  return latest;
248
238
  }
249
- function packageHasOutdatedBuildOutput(repoRoot, packageName) {
250
- const packageDirectory = PACKAGE_DIRECTORY_BY_NAME[packageName];
239
+ function packageHasOutdatedBuildOutput(repoRoot, localPackages, packageName) {
240
+ const packageDirectory = localPackages.get(packageName).directory;
251
241
  const packageRoot = join(repoRoot, 'packages', packageDirectory);
252
242
  const distDirectory = join(packageRoot, 'dist');
253
243
  if (!existsSync(distDirectory)) {
@@ -264,8 +254,8 @@ function packageHasOutdatedBuildOutput(repoRoot, packageName) {
264
254
  const latestDist = latestModifiedTimeMs(distDirectory);
265
255
  return latestDist < latestSource;
266
256
  }
267
- function shouldRunWorkspaceBuild(repoRoot, packageNames) {
268
- return packageNames.some(packageName => packageHasOutdatedBuildOutput(repoRoot, packageName));
257
+ function shouldRunWorkspaceBuild(repoRoot, localPackages, packageNames) {
258
+ return packageNames.some(packageName => packageHasOutdatedBuildOutput(repoRoot, localPackages, packageName));
269
259
  }
270
260
  function runPackCommand(packageDirectory, outputDirectory) {
271
261
  return new Promise((resolvePromise, reject) => {
@@ -299,16 +289,16 @@ function runWorkspaceBuild(repoRoot) {
299
289
  });
300
290
  });
301
291
  }
302
- async function ensureWorkspaceBuildOutput(repoRoot, packageNames) {
303
- if (shouldRunWorkspaceBuild(repoRoot, packageNames)) {
292
+ async function ensureWorkspaceBuildOutput(repoRoot, localPackages, packageNames) {
293
+ if (shouldRunWorkspaceBuild(repoRoot, localPackages, packageNames)) {
304
294
  await runWorkspaceBuild(repoRoot);
305
295
  }
306
296
  }
307
- async function packLocalPackages(repoRoot, outputDirectory, packageNames, packageVersions) {
297
+ async function packLocalPackages(repoRoot, localPackages, outputDirectory, packageNames, packageVersions) {
308
298
  for (const packageName of packageNames) {
309
299
  const packageVersion = getPackageVersionOrThrow(packageVersions, packageName);
310
300
  const tarballName = expectedTarballName(packageName, packageVersion);
311
- const stageDirectory = stagePackageForPacking(repoRoot, packageName, packageVersions, outputDirectory);
301
+ const stageDirectory = stagePackageForPacking(repoRoot, localPackages, packageName, packageVersions, outputDirectory);
312
302
  try {
313
303
  await runPackCommand(stageDirectory, outputDirectory);
314
304
  } finally {
@@ -384,15 +374,16 @@ export async function resolvePackageSpecs(options, bootstrapPlan) {
384
374
  mkdirSync(outputDirectory, {
385
375
  recursive: true
386
376
  });
387
- const packageNames = collectRequiredLocalPackages(repoRoot, bootstrapPlan);
388
- const packageVersions = collectLocalPackageVersions(repoRoot, packageNames);
389
- const expectedCacheStamp = computeLocalPackageCacheStamp(repoRoot, packageNames, packageVersions);
377
+ const localPackages = collectLocalPackages(repoRoot);
378
+ const packageNames = collectRequiredLocalPackages(localPackages, bootstrapPlan);
379
+ const packageVersions = collectLocalPackageVersions(localPackages, packageNames);
380
+ const expectedCacheStamp = computeLocalPackageCacheStamp(repoRoot, localPackages, packageNames, packageVersions);
390
381
  const currentCacheStamp = readLocalPackageCacheStamp(cacheStampPath);
391
382
  const canReuseCachedTarballs = expectedCacheStamp ? cacheStampMatches(expectedCacheStamp, currentCacheStamp) && cacheContainsTarballs(outputDirectory, packageNames, packageVersions) : false;
392
383
  if (!canReuseCachedTarballs) {
393
- await ensureWorkspaceBuildOutput(repoRoot, packageNames);
384
+ await ensureWorkspaceBuildOutput(repoRoot, localPackages, packageNames);
394
385
  clearLocalPackageCacheArtifacts(outputDirectory);
395
- await packLocalPackages(repoRoot, outputDirectory, packageNames, packageVersions);
386
+ await packLocalPackages(repoRoot, localPackages, outputDirectory, packageNames, packageVersions);
396
387
  if (expectedCacheStamp) {
397
388
  writeFileSync(cacheStampPath, `${JSON.stringify(expectedCacheStamp, null, 2)}\n`, 'utf8');
398
389
  } else {
@@ -22,6 +22,7 @@ export interface BootstrapPrompter {
22
22
  export interface ResolveBootstrapAnswersOptions {
23
23
  completionMessage?: string | ((answers: BootstrapAnswers) => string);
24
24
  interactive?: boolean;
25
+ onInteractivePrompt?: () => void;
25
26
  prompt?: BootstrapPrompter;
26
27
  stdin?: ReadableStream;
27
28
  stdout?: WritableStream;
@@ -1 +1 @@
1
- {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../src/new/prompt.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAGnE,iEAAiE;AACjE,eAAO,MAAM,uBAAuB,EAAE,cAAuB,CAAC;AAI9D,KAAK,cAAc,GAAG;IACpB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC,CAAC;AAEF,KAAK,cAAc,GAAG;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,KAAK,YAAY,CAAC,CAAC,SAAS,MAAM,IAAI;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,CAAC,CAAC;CACV,CAAC;AAQF,iEAAiE;AACjE,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,IAAI,IAAI,CAAC;IACf,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClE,MAAM,CAAC,CAAC,SAAS,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,YAAY,CAAC,CAAC,CAAC,EAAE,EAAE,YAAY,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAC7G,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACxC;AAED,8EAA8E;AAC9E,MAAM,WAAW,8BAA8B;IAC7C,iBAAiB,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,gBAAgB,KAAK,MAAM,CAAC,CAAC;IACrE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,MAAM,CAAC,EAAE,cAAc,CAAC;CACzB;AAwPD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,cAAc,EAAE,MAAM,EACtB,SAAS,CAAC,EAAE,MAAM,GACjB,cAAc,CAIhB;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,OAAO,CAAC,gBAAgB,CAAC,EAClC,GAAG,EAAE,MAAM,EACX,SAAS,CAAC,EAAE,MAAM,GACjB,gBAAgB,CAgBlB;AAED;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,OAAO,CAAC,gBAAgB,CAAC,EAClC,GAAG,EAAE,MAAM,EACX,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,GAAE,8BAAmC,GAC3C,OAAO,CAAC,gBAAgB,CAAC,CA0B3B"}
1
+ {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../src/new/prompt.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEnE,iEAAiE;AACjE,eAAO,MAAM,uBAAuB,EAAE,cAAuB,CAAC;AAQ9D,KAAK,cAAc,GAAG;IACpB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC,CAAC;AAEF,KAAK,cAAc,GAAG;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,KAAK,YAAY,CAAC,CAAC,SAAS,MAAM,IAAI;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,CAAC,CAAC;CACV,CAAC;AAaF,iEAAiE;AACjE,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,IAAI,IAAI,CAAC;IACf,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClE,MAAM,CAAC,CAAC,SAAS,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,YAAY,CAAC,CAAC,CAAC,EAAE,EAAE,YAAY,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAC7G,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACxC;AAED,8EAA8E;AAC9E,MAAM,WAAW,8BAA8B;IAC7C,iBAAiB,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,gBAAgB,KAAK,MAAM,CAAC,CAAC;IACrE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,MAAM,CAAC,EAAE,cAAc,CAAC;CACzB;AAyRD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,cAAc,EAAE,MAAM,EACtB,SAAS,CAAC,EAAE,MAAM,GACjB,cAAc,CAIhB;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,OAAO,CAAC,gBAAgB,CAAC,EAClC,GAAG,EAAE,MAAM,EACX,SAAS,CAAC,EAAE,MAAM,GACjB,gBAAgB,CAiBlB;AAED;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,OAAO,CAAC,gBAAgB,CAAC,EAClC,GAAG,EAAE,MAAM,EACX,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,GAAE,8BAAmC,GAC3C,OAAO,CAAC,gBAAgB,CAAC,CA4B3B"}
@@ -1,14 +1,13 @@
1
1
  import { existsSync, readFileSync } from 'node:fs';
2
2
  import { dirname, join, resolve } from 'node:path';
3
- import * as clack from '@clack/prompts';
3
+ import { CliPromptCancelledError } from '../prompt-cancel.js';
4
4
  import { resolveBootstrapSchema } from './resolver.js';
5
5
  import { DOCUMENTED_MICROSERVICE_TRANSPORTS, getApplicationStarterProfiles } from './starter-profiles.js';
6
- import { CliPromptCancelledError } from '../prompt-cancel.js';
7
-
8
6
  /** Default package manager used when detection has no signal. */
9
7
  export const DEFAULT_PACKAGE_MANAGER = 'pnpm';
10
8
  const DEFAULT_INSTALL_DEPENDENCIES = true;
11
9
  const DEFAULT_INITIALIZE_GIT = false;
10
+ const CLACK_MISSING_MESSAGE = ['Interactive CLI commands require @clack/prompts, but it is not resolvable from this installation.', 'Install a version whose Node.js engine supports your current Node.js version and rerun the command.'].join('\n');
12
11
  const STARTER_SHAPE_CHOICES = [{
13
12
  label: 'Application',
14
13
  value: 'application'
@@ -19,6 +18,13 @@ const STARTER_SHAPE_CHOICES = [{
19
18
  label: 'Mixed',
20
19
  value: 'mixed'
21
20
  }];
21
+ const STARTER_CHOICES = [{
22
+ label: 'Standard backend',
23
+ value: 'standard'
24
+ }, {
25
+ label: 'React SSR + Vite',
26
+ value: 'react-vite-ssr'
27
+ }];
22
28
 
23
29
  /** Prompt contract used by the interactive `fluo new` wizard. */
24
30
 
@@ -33,7 +39,18 @@ function resolveCompletionMessage(completionMessage, answers) {
33
39
  function hasOwnValue(partial, key) {
34
40
  return partial[key] !== undefined;
35
41
  }
36
- function createBootstrapPrompter() {
42
+ async function loadClackPrompts() {
43
+ try {
44
+ return await import('@clack/prompts');
45
+ } catch (error) {
46
+ const code = typeof error === 'object' && error !== null && 'code' in error ? error.code : undefined;
47
+ if (code === 'MODULE_NOT_FOUND' || code === 'ERR_MODULE_NOT_FOUND') {
48
+ throw new Error(CLACK_MISSING_MESSAGE);
49
+ }
50
+ throw error;
51
+ }
52
+ }
53
+ async function createBootstrapPrompter(clack) {
37
54
  return {
38
55
  async confirm(message, defaultValue) {
39
56
  const result = await clack.confirm({
@@ -80,7 +97,8 @@ function createBootstrapPrompter() {
80
97
  }
81
98
  function shouldPromptForAnswers(partial, interactive) {
82
99
  const selectedRuntime = partial.runtime;
83
- return interactive && (!hasOwnValue(partial, 'projectName') || !hasOwnValue(partial, 'shape') || !hasOwnValue(partial, 'tooling') || !hasOwnValue(partial, 'packageManager') || !hasOwnValue(partial, 'installDependencies') || !hasOwnValue(partial, 'initializeGit') || partial.shape === 'application' && !hasOwnValue(partial, 'runtime') || partial.shape === 'application' && selectedRuntime === 'node' && !hasOwnValue(partial, 'platform') || partial.shape === 'microservice' && !hasOwnValue(partial, 'transport'));
100
+ const needsStarterSelection = !hasOwnValue(partial, 'starter') && !hasOwnValue(partial, 'shape') && !hasOwnValue(partial, 'runtime') && !hasOwnValue(partial, 'platform') && !hasOwnValue(partial, 'transport');
101
+ return interactive && (!hasOwnValue(partial, 'projectName') || needsStarterSelection || !hasOwnValue(partial, 'shape') || !hasOwnValue(partial, 'tooling') || !hasOwnValue(partial, 'packageManager') || !hasOwnValue(partial, 'installDependencies') || !hasOwnValue(partial, 'initializeGit') || partial.shape === 'application' && !hasOwnValue(partial, 'runtime') || partial.shape === 'application' && selectedRuntime === 'node' && !hasOwnValue(partial, 'platform') || partial.shape === 'microservice' && !hasOwnValue(partial, 'transport'));
84
102
  }
85
103
  async function resolveInteractiveBootstrapAnswers(partial, cwd, userAgent, prompt) {
86
104
  const answers = {
@@ -90,10 +108,17 @@ async function resolveInteractiveBootstrapAnswers(partial, cwd, userAgent, promp
90
108
  if (!answers.projectName) {
91
109
  answers.projectName = assertValidProjectName(await prompt.text('Project name'));
92
110
  }
93
- if (!answers.shape) {
111
+ if (!answers.starter) {
112
+ const hasSchemaSelection = answers.shape !== undefined || answers.runtime !== undefined || answers.platform !== undefined || answers.transport !== undefined;
113
+ answers.starter = hasSchemaSelection ? 'standard' : await prompt.select('Starter', STARTER_CHOICES, 'standard');
114
+ }
115
+ if (answers.starter === 'react-vite-ssr') {
116
+ Object.assign(answers, resolveBootstrapSchema(answers));
117
+ }
118
+ if (answers.starter === 'standard' && !answers.shape) {
94
119
  answers.shape = await prompt.select('Starter shape', STARTER_SHAPE_CHOICES, 'application');
95
120
  }
96
- if (answers.shape === 'application' && !answers.runtime) {
121
+ if (answers.starter === 'standard' && answers.shape === 'application' && !answers.runtime) {
97
122
  answers.runtime = await prompt.select('Runtime', [{
98
123
  label: 'Bun',
99
124
  value: 'bun'
@@ -108,7 +133,7 @@ async function resolveInteractiveBootstrapAnswers(partial, cwd, userAgent, promp
108
133
  value: 'node'
109
134
  }], 'node');
110
135
  }
111
- if (answers.shape === 'application' && !answers.platform) {
136
+ if (answers.starter === 'standard' && answers.shape === 'application' && !answers.platform) {
112
137
  if (answers.runtime === 'node') {
113
138
  const applicationProfiles = getApplicationStarterProfiles('node');
114
139
  answers.platform = await prompt.select('HTTP platform', applicationProfiles.map(profile => ({
@@ -119,7 +144,7 @@ async function resolveInteractiveBootstrapAnswers(partial, cwd, userAgent, promp
119
144
  answers.platform = answers.runtime;
120
145
  }
121
146
  }
122
- if (answers.shape === 'microservice' && !answers.transport) {
147
+ if (answers.starter === 'standard' && answers.shape === 'microservice' && !answers.transport) {
123
148
  answers.transport = await prompt.select('Microservice transport', DOCUMENTED_MICROSERVICE_TRANSPORTS.map(transport => ({
124
149
  label: transport,
125
150
  value: transport
@@ -251,6 +276,7 @@ export function resolveBootstrapAnswers(partial, cwd, userAgent) {
251
276
  packageManager: partial.packageManager ?? detectPackageManager(cwd, userAgent),
252
277
  ...schema,
253
278
  projectName,
279
+ starter: partial.starter ?? 'standard',
254
280
  targetDirectory: partial.targetDirectory ?? `./${projectName}`
255
281
  };
256
282
  }
@@ -269,15 +295,17 @@ export async function collectBootstrapAnswers(partial, cwd, userAgent, options =
269
295
  if (!shouldPromptForAnswers(partial, interactive)) {
270
296
  return resolveBootstrapAnswers(partial, cwd, userAgent);
271
297
  }
272
- const prompt = options.prompt ?? createBootstrapPrompter();
273
298
  const isInteractiveShell = options.prompt === undefined;
299
+ options.onInteractivePrompt?.();
300
+ const clack = isInteractiveShell ? await loadClackPrompts() : undefined;
301
+ const prompt = options.prompt ?? (await createBootstrapPrompter(clack ?? (await loadClackPrompts())));
274
302
  try {
275
303
  if (isInteractiveShell) {
276
- clack.intro('fluo new');
304
+ clack?.intro('fluo new');
277
305
  }
278
306
  const answers = await resolveInteractiveBootstrapAnswers(partial, cwd, userAgent, prompt);
279
307
  if (isInteractiveShell) {
280
- clack.outro(resolveCompletionMessage(options.completionMessage, answers));
308
+ clack?.outro(resolveCompletionMessage(options.completionMessage, answers));
281
309
  }
282
310
  return answers;
283
311
  } finally {