@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.
- package/README.ko.md +169 -21
- package/README.md +172 -21
- package/dist/cli.d.ts +5 -4
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +127 -35
- package/dist/commands/diagnostics.d.ts +35 -0
- package/dist/commands/diagnostics.d.ts.map +1 -1
- package/dist/commands/diagnostics.js +60 -0
- package/dist/commands/inspect.d.ts +5 -1
- package/dist/commands/inspect.d.ts.map +1 -1
- package/dist/commands/inspect.js +84 -17
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +27 -15
- package/dist/commands/migration-transform-tokens.d.ts +15 -0
- package/dist/commands/migration-transform-tokens.d.ts.map +1 -0
- package/dist/commands/migration-transform-tokens.js +41 -0
- package/dist/commands/new.d.ts.map +1 -1
- package/dist/commands/new.js +29 -9
- package/dist/commands/output-path-safety.d.ts +14 -0
- package/dist/commands/output-path-safety.d.ts.map +1 -0
- package/dist/commands/output-path-safety.js +34 -0
- package/dist/commands/scripts.js +2 -2
- package/dist/commands/typegen-artifact.d.ts +54 -0
- package/dist/commands/typegen-artifact.d.ts.map +1 -0
- package/dist/commands/typegen-artifact.js +117 -0
- package/dist/commands/typegen-generation-child.d.ts +2 -0
- package/dist/commands/typegen-generation-child.d.ts.map +1 -0
- package/dist/commands/typegen-generation-child.js +59 -0
- package/dist/commands/typegen-generation-process.d.ts +46 -0
- package/dist/commands/typegen-generation-process.d.ts.map +1 -0
- package/dist/commands/typegen-generation-process.js +131 -0
- package/dist/commands/typegen-generation-protocol.d.ts +16 -0
- package/dist/commands/typegen-generation-protocol.d.ts.map +1 -0
- package/dist/commands/typegen-generation-protocol.js +35 -0
- package/dist/commands/typegen-isolated-source.d.ts +10 -0
- package/dist/commands/typegen-isolated-source.d.ts.map +1 -0
- package/dist/commands/typegen-isolated-source.js +75 -0
- package/dist/commands/typegen-options.d.ts +20 -0
- package/dist/commands/typegen-options.d.ts.map +1 -0
- package/dist/commands/typegen-options.js +71 -0
- package/dist/commands/typegen-source.d.ts +59 -0
- package/dist/commands/typegen-source.d.ts.map +1 -0
- package/dist/commands/typegen-source.js +183 -0
- package/dist/commands/typegen-watch.d.ts +46 -0
- package/dist/commands/typegen-watch.d.ts.map +1 -0
- package/dist/commands/typegen-watch.js +212 -0
- package/dist/commands/typegen.d.ts +29 -0
- package/dist/commands/typegen.d.ts.map +1 -0
- package/dist/commands/typegen.js +119 -0
- package/dist/dev-runner/node-restart-runner.d.ts.map +1 -1
- package/dist/dev-runner/node-restart-runner.js +54 -7
- package/dist/fixtures/inspect-react-app.module.d.ts +4 -0
- package/dist/fixtures/inspect-react-app.module.d.ts.map +1 -0
- package/dist/fixtures/inspect-react-app.module.js +32 -0
- package/dist/fixtures/typegen-react-app.module.d.ts +4 -0
- package/dist/fixtures/typegen-react-app.module.d.ts.map +1 -0
- package/dist/fixtures/typegen-react-app.module.js +33 -0
- package/dist/index.d.ts +6 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/new/install.js +1 -1
- package/dist/new/package-spec-resolver.d.ts.map +1 -1
- package/dist/new/package-spec-resolver.js +50 -59
- package/dist/new/prompt.d.ts +1 -0
- package/dist/new/prompt.d.ts.map +1 -1
- package/dist/new/prompt.js +40 -12
- package/dist/new/published-internal-dependencies.d.ts +20 -0
- package/dist/new/published-internal-dependencies.d.ts.map +1 -0
- package/dist/new/published-internal-dependencies.js +20 -0
- package/dist/new/react-vite-ssr-scaffold.d.ts +19 -0
- package/dist/new/react-vite-ssr-scaffold.d.ts.map +1 -0
- package/dist/new/react-vite-ssr-scaffold.js +108 -0
- package/dist/new/resolver.d.ts +2 -2
- package/dist/new/resolver.d.ts.map +1 -1
- package/dist/new/resolver.js +5 -1
- package/dist/new/scaffold.d.ts.map +1 -1
- package/dist/new/scaffold.js +62 -31
- package/dist/new/starter-profiles.d.ts +8 -4
- package/dist/new/starter-profiles.d.ts.map +1 -1
- package/dist/new/starter-profiles.js +52 -18
- package/dist/new/templates/react-vite-ssr/README.md.ejs +74 -0
- package/dist/new/templates/react-vite-ssr/playwright.config.ts.ejs +26 -0
- package/dist/new/templates/react-vite-ssr/src/app.test.ts.ejs +82 -0
- package/dist/new/templates/react-vite-ssr/src/app.ts.ejs +91 -0
- package/dist/new/templates/react-vite-ssr/src/entry-client.tsx.ejs +29 -0
- package/dist/new/templates/react-vite-ssr/src/entry-server.tsx.ejs +52 -0
- package/dist/new/templates/react-vite-ssr/src/load-manifest.test.ts.ejs +55 -0
- package/dist/new/templates/react-vite-ssr/src/load-manifest.ts.ejs +53 -0
- package/dist/new/templates/react-vite-ssr/src/main.ts.ejs +18 -0
- package/dist/new/templates/react-vite-ssr/src/page.tsx.ejs +43 -0
- package/dist/new/templates/react-vite-ssr/src/react-app.test.tsx.ejs +67 -0
- package/dist/new/templates/react-vite-ssr/src/react-app.tsx.ejs +46 -0
- package/dist/new/templates/react-vite-ssr/src/styles.css.ejs +25 -0
- package/dist/new/templates/react-vite-ssr/src/styles.d.ts.ejs +1 -0
- package/dist/new/templates/react-vite-ssr/tests/production-hydration.spec.ts.ejs +54 -0
- package/dist/new/templates/react-vite-ssr/tsconfig.json.ejs +16 -0
- package/dist/new/templates/react-vite-ssr/vite.client.config.ts.ejs +24 -0
- package/dist/new/templates/react-vite-ssr/vite.server.config.ts.ejs +17 -0
- package/dist/new/templates/react-vite-ssr/vitest.config.ts.ejs +10 -0
- package/dist/new/types.d.ts +4 -0
- package/dist/new/types.d.ts.map +1 -1
- package/dist/public-typegen.d.ts +14 -0
- package/dist/public-typegen.d.ts.map +1 -0
- package/dist/public-typegen.js +17 -0
- package/dist/run-cli.d.ts +2 -1
- package/dist/run-cli.d.ts.map +1 -1
- package/dist/studio/sidecar.d.ts.map +1 -1
- package/dist/studio/sidecar.js +35 -9
- package/dist/transforms/nestjs-migrate.d.ts +4 -1
- package/dist/transforms/nestjs-migrate.d.ts.map +1 -1
- package/dist/transforms/nestjs-migrate.js +625 -65
- package/dist/typegen-contract.d.ts +10 -0
- package/dist/typegen-contract.d.ts.map +1 -0
- package/dist/typegen-contract.js +9 -0
- package/dist/usage.d.ts +6 -0
- package/dist/usage.d.ts.map +1 -1
- package/dist/usage.js +47 -0
- package/package.json +19 -10
package/dist/commands/inspect.js
CHANGED
|
@@ -1,20 +1,24 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
1
2
|
import { mkdir, writeFile } from 'node:fs/promises';
|
|
2
3
|
import { createRequire } from 'node:module';
|
|
3
4
|
import { dirname, extname, resolve } from 'node:path';
|
|
4
5
|
import { pathToFileURL } from 'node:url';
|
|
5
|
-
import * as clack from '@clack/prompts';
|
|
6
|
-
import { FluoFactory, PLATFORM_SHELL } from '@fluojs/runtime';
|
|
7
6
|
import { tsImport } from 'tsx/esm/api';
|
|
8
7
|
import { CliPromptCancelledError, isCliPromptCancelledError } from '../prompt-cancel.js';
|
|
9
8
|
import { inspectUsage } from '../usage.js';
|
|
9
|
+
import { createCliDiagnosticsLogger } from './diagnostics.js';
|
|
10
|
+
import { assertOutputDoesNotAliasModule } from './output-path-safety.js';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Runtime options for the inspect command when used programmatically.
|
|
13
14
|
*/
|
|
14
15
|
|
|
15
16
|
const STUDIO_CONTRACT_ENTRYPOINT = '@fluojs/studio/contracts';
|
|
17
|
+
const RUNTIME_ENTRYPOINT = '@fluojs/runtime';
|
|
16
18
|
const TYPESCRIPT_MODULE_EXTENSIONS = new Set(['.ts', '.tsx', '.mts', '.cts']);
|
|
19
|
+
const RUNTIME_MISSING_MESSAGE = ['Runtime inspection requires @fluojs/runtime, but it is not resolvable from this project.', 'Install a version whose Node.js engine supports your current Node.js version (for example: pnpm add -D @fluojs/runtime) and rerun fluo inspect.'].join('\n');
|
|
17
20
|
const STUDIO_MISSING_MESSAGE = ['Mermaid graph rendering is owned by @fluojs/studio, but @fluojs/studio is not resolvable from this project.', 'Install @fluojs/studio explicitly (for example: pnpm add -D @fluojs/studio) and rerun fluo inspect --mermaid.'].join('\n');
|
|
21
|
+
const CLACK_MISSING_MESSAGE = ['Interactive inspect guidance requires @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 fluo inspect.'].join('\n');
|
|
18
22
|
function isHelpFlag(value) {
|
|
19
23
|
return value === '--help' || value === '-h';
|
|
20
24
|
}
|
|
@@ -35,6 +39,18 @@ function parseInspectArgs(argv) {
|
|
|
35
39
|
json = true;
|
|
36
40
|
continue;
|
|
37
41
|
}
|
|
42
|
+
if (option === '--format') {
|
|
43
|
+
const format = argv[index + 1];
|
|
44
|
+
if (!format || format.startsWith('-')) {
|
|
45
|
+
throw new Error('Expected --format to have a value of "json".');
|
|
46
|
+
}
|
|
47
|
+
if (format !== 'json') {
|
|
48
|
+
throw new Error(`Invalid --format value "${format}". Use "json".`);
|
|
49
|
+
}
|
|
50
|
+
json = true;
|
|
51
|
+
index += 1;
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
38
54
|
if (option === '--mermaid') {
|
|
39
55
|
mermaid = true;
|
|
40
56
|
continue;
|
|
@@ -105,6 +121,13 @@ function resolveRootModule(exportedValue, exportName) {
|
|
|
105
121
|
async function importInspectModule(modulePath) {
|
|
106
122
|
const moduleUrl = pathToFileURL(modulePath).href;
|
|
107
123
|
if (TYPESCRIPT_MODULE_EXTENSIONS.has(extname(modulePath))) {
|
|
124
|
+
const adjacentTsconfigPath = resolve(dirname(modulePath), 'tsconfig.json');
|
|
125
|
+
if (existsSync(adjacentTsconfigPath)) {
|
|
126
|
+
return tsImport(moduleUrl, {
|
|
127
|
+
parentURL: import.meta.url,
|
|
128
|
+
tsconfig: adjacentTsconfigPath
|
|
129
|
+
});
|
|
130
|
+
}
|
|
108
131
|
return tsImport(moduleUrl, import.meta.url);
|
|
109
132
|
}
|
|
110
133
|
return import(moduleUrl);
|
|
@@ -145,18 +168,26 @@ function stringifySnapshotWithTiming(snapshot, timing) {
|
|
|
145
168
|
timing: timing ?? createEmptyTimingDiagnostics()
|
|
146
169
|
}, null, 2);
|
|
147
170
|
}
|
|
148
|
-
async function emitInspectPayload(payload,
|
|
149
|
-
if (!
|
|
171
|
+
async function emitInspectPayload(payload, outputPath, stdout) {
|
|
172
|
+
if (!outputPath) {
|
|
150
173
|
stdout.write(`${payload}\n`);
|
|
151
174
|
return;
|
|
152
175
|
}
|
|
153
|
-
const outputPath = resolve(cwd, parsed.outputPath);
|
|
154
176
|
await mkdir(dirname(outputPath), {
|
|
155
177
|
recursive: true
|
|
156
178
|
});
|
|
157
179
|
await writeFile(outputPath, `${payload}\n`, 'utf8');
|
|
158
180
|
}
|
|
159
|
-
function createInspectPrompter() {
|
|
181
|
+
async function createInspectPrompter() {
|
|
182
|
+
let clack;
|
|
183
|
+
try {
|
|
184
|
+
clack = await import('@clack/prompts');
|
|
185
|
+
} catch (error) {
|
|
186
|
+
if (isModuleNotFoundError(error)) {
|
|
187
|
+
throw new Error(CLACK_MISSING_MESSAGE);
|
|
188
|
+
}
|
|
189
|
+
throw error;
|
|
190
|
+
}
|
|
160
191
|
return {
|
|
161
192
|
async confirm(message, defaultValue) {
|
|
162
193
|
const result = await clack.confirm({
|
|
@@ -180,6 +211,29 @@ function shouldPromptForStudio(runtime) {
|
|
|
180
211
|
}
|
|
181
212
|
return runtime.stdout === undefined && runtime.stderr === undefined && (runtime.interactive ?? true) && Boolean(runtime.stdin?.isTTY ?? process.stdin.isTTY);
|
|
182
213
|
}
|
|
214
|
+
function isModuleNotFoundError(error) {
|
|
215
|
+
const code = typeof error === 'object' && error !== null && 'code' in error ? error.code : undefined;
|
|
216
|
+
return code === 'MODULE_NOT_FOUND' || code === 'ERR_MODULE_NOT_FOUND';
|
|
217
|
+
}
|
|
218
|
+
async function loadRuntimeInspectionModule(cwd) {
|
|
219
|
+
const resolver = createRequire(resolve(cwd, 'package.json'));
|
|
220
|
+
try {
|
|
221
|
+
const resolvedEntrypoint = resolver.resolve(RUNTIME_ENTRYPOINT);
|
|
222
|
+
return await import(pathToFileURL(resolvedEntrypoint).href);
|
|
223
|
+
} catch (error) {
|
|
224
|
+
if (isModuleNotFoundError(error)) {
|
|
225
|
+
return undefined;
|
|
226
|
+
}
|
|
227
|
+
throw error;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
async function resolveRuntimeInspectionModule(cwd, runtime) {
|
|
231
|
+
const runtimeModule = await (runtime.loadRuntimeInspectionModule ?? loadRuntimeInspectionModule)(cwd);
|
|
232
|
+
if (!runtimeModule) {
|
|
233
|
+
throw new Error(RUNTIME_MISSING_MESSAGE);
|
|
234
|
+
}
|
|
235
|
+
return runtimeModule;
|
|
236
|
+
}
|
|
183
237
|
async function loadStudioMermaidRenderer(cwd) {
|
|
184
238
|
const resolvers = [createRequire(resolve(cwd, 'package.json')), createRequire(import.meta.url)];
|
|
185
239
|
for (const resolver of resolvers) {
|
|
@@ -191,8 +245,7 @@ async function loadStudioMermaidRenderer(cwd) {
|
|
|
191
245
|
}
|
|
192
246
|
return importedContract.renderMermaid;
|
|
193
247
|
} catch (error) {
|
|
194
|
-
|
|
195
|
-
if (code !== 'MODULE_NOT_FOUND' && code !== 'ERR_MODULE_NOT_FOUND') {
|
|
248
|
+
if (!isModuleNotFoundError(error)) {
|
|
196
249
|
throw error;
|
|
197
250
|
}
|
|
198
251
|
}
|
|
@@ -207,7 +260,7 @@ async function resolveStudioMermaidRenderer(cwd, runtime) {
|
|
|
207
260
|
if (!shouldPromptForStudio(runtime)) {
|
|
208
261
|
throw new Error(STUDIO_MISSING_MESSAGE);
|
|
209
262
|
}
|
|
210
|
-
const prompt = runtime.prompt ?? createInspectPrompter();
|
|
263
|
+
const prompt = runtime.prompt ?? (await createInspectPrompter());
|
|
211
264
|
try {
|
|
212
265
|
const approvedInstall = await prompt.confirm('Install @fluojs/studio before rendering Mermaid output?', false);
|
|
213
266
|
if (!approvedInstall) {
|
|
@@ -237,28 +290,42 @@ export async function runInspectCommand(argv, runtime = {}) {
|
|
|
237
290
|
}
|
|
238
291
|
const parsed = parseInspectArgs(argv);
|
|
239
292
|
const modulePath = resolve(cwd, parsed.modulePath);
|
|
293
|
+
const outputPath = parsed.outputPath === undefined ? undefined : resolve(cwd, parsed.outputPath);
|
|
294
|
+
if (outputPath !== undefined) {
|
|
295
|
+
await assertOutputDoesNotAliasModule(modulePath, outputPath);
|
|
296
|
+
}
|
|
297
|
+
const {
|
|
298
|
+
createRuntimeInspectionSnapshot,
|
|
299
|
+
FluoFactory,
|
|
300
|
+
PLATFORM_SHELL
|
|
301
|
+
} = await resolveRuntimeInspectionModule(cwd, runtime);
|
|
240
302
|
const importedModule = await importInspectModule(modulePath);
|
|
241
303
|
const rootModule = resolveRootModule(importedModule[parsed.exportName], parsed.exportName);
|
|
242
|
-
const
|
|
304
|
+
const application = await FluoFactory.create(rootModule, {
|
|
243
305
|
diagnostics: parsed.timing || parsed.report ? {
|
|
244
306
|
timing: true
|
|
245
|
-
} : undefined
|
|
307
|
+
} : undefined,
|
|
308
|
+
...(parsed.json || parsed.report ? {
|
|
309
|
+
logger: createCliDiagnosticsLogger(stderr)
|
|
310
|
+
} : {})
|
|
246
311
|
});
|
|
247
312
|
try {
|
|
248
|
-
const platformShell = await
|
|
249
|
-
const
|
|
313
|
+
const platformShell = await application.get(PLATFORM_SHELL);
|
|
314
|
+
const platformSnapshot = await platformShell.snapshot();
|
|
315
|
+
const routes = application.dispatcher.describeRoutes?.() ?? [];
|
|
316
|
+
const snapshot = createRuntimeInspectionSnapshot(platformSnapshot, routes);
|
|
250
317
|
if (parsed.json) {
|
|
251
|
-
await emitInspectPayload(parsed.timing ? stringifySnapshotWithTiming(snapshot,
|
|
318
|
+
await emitInspectPayload(parsed.timing ? stringifySnapshotWithTiming(snapshot, application.bootstrapTiming) : stringifySnapshot(snapshot), outputPath, stdout);
|
|
252
319
|
}
|
|
253
320
|
if (parsed.report) {
|
|
254
|
-
await emitInspectPayload(JSON.stringify(createInspectReport(snapshot,
|
|
321
|
+
await emitInspectPayload(JSON.stringify(createInspectReport(snapshot, application.bootstrapTiming), null, 2), outputPath, stdout);
|
|
255
322
|
}
|
|
256
323
|
if (parsed.mermaid) {
|
|
257
324
|
const renderMermaid = await resolveStudioMermaidRenderer(cwd, runtime);
|
|
258
|
-
await emitInspectPayload(renderMermaid(snapshot),
|
|
325
|
+
await emitInspectPayload(renderMermaid(snapshot), outputPath, stdout);
|
|
259
326
|
}
|
|
260
327
|
} finally {
|
|
261
|
-
await
|
|
328
|
+
await application.close();
|
|
262
329
|
}
|
|
263
330
|
return 0;
|
|
264
331
|
} catch (error) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../src/commands/migrate.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../src/commands/migrate.ts"],"names":[],"mappings":"AAgBA,KAAK,SAAS,GAAG;IACf,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC3C,qDAAqD;IACrD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,sCAAsC;IACtC,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,yCAAyC;IACzC,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB;AAqLD;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAgBrC;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,4BAAiC,GAAG,OAAO,CAAC,MAAM,CAAC,CAyEnH"}
|
package/dist/commands/migrate.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { resolve } from 'node:path';
|
|
2
2
|
import { renderAliasList, renderHelpTable } from '../help.js';
|
|
3
|
-
import {
|
|
3
|
+
import { getWarningCategoryLabel, groupWarningsByCategory, MIGRATION_TRANSFORMS, renderTransformList, runNestJsMigration } from '../transforms/nestjs-migrate.js';
|
|
4
|
+
import { MIGRATION_TRANSFORM_CLI_TOKENS, parseMigrationTransformList } from './migration-transform-tokens.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Runtime configuration for the migrate command.
|
|
@@ -16,12 +17,16 @@ const MIGRATE_OPTION_HELP = [{
|
|
|
16
17
|
option: '--json'
|
|
17
18
|
}, {
|
|
18
19
|
aliases: [],
|
|
19
|
-
description: `Run only selected transforms. Available: ${
|
|
20
|
+
description: `Run only selected transforms. Available: ${MIGRATION_TRANSFORM_CLI_TOKENS.join(', ')}.`,
|
|
20
21
|
option: '--only <comma-list>'
|
|
21
22
|
}, {
|
|
22
23
|
aliases: [],
|
|
23
|
-
description: `Skip selected transforms. Available: ${
|
|
24
|
+
description: `Skip selected transforms. Available: ${MIGRATION_TRANSFORM_CLI_TOKENS.join(', ')}.`,
|
|
24
25
|
option: '--skip <comma-list>'
|
|
26
|
+
}, {
|
|
27
|
+
aliases: [],
|
|
28
|
+
description: 'Select the HTTP platform for bootstrap rewrites. Required for automatic bootstrap migration; supported: express.',
|
|
29
|
+
option: '--platform <name>'
|
|
25
30
|
}, {
|
|
26
31
|
aliases: ['-h'],
|
|
27
32
|
description: 'Show help for the migrate command.',
|
|
@@ -30,22 +35,12 @@ const MIGRATE_OPTION_HELP = [{
|
|
|
30
35
|
function isHelpFlag(value) {
|
|
31
36
|
return value === '--help' || value === '-h';
|
|
32
37
|
}
|
|
33
|
-
function parseTransformList(rawValue, optionName) {
|
|
34
|
-
const values = rawValue.split(',').map(value => value.trim()).filter(value => value.length > 0);
|
|
35
|
-
if (values.length === 0) {
|
|
36
|
-
throw new Error(`${optionName} requires a non-empty comma-separated transform list.`);
|
|
37
|
-
}
|
|
38
|
-
const invalid = values.filter(value => !MIGRATION_TRANSFORMS.includes(value));
|
|
39
|
-
if (invalid.length > 0) {
|
|
40
|
-
throw new Error(`Unknown transform(s): ${invalid.join(', ')}. Available transforms: ${MIGRATION_TRANSFORMS.join(', ')}.`);
|
|
41
|
-
}
|
|
42
|
-
return values;
|
|
43
|
-
}
|
|
44
38
|
function parseArgs(argv) {
|
|
45
39
|
let pathArgument;
|
|
46
40
|
let apply = false;
|
|
47
41
|
let json = false;
|
|
48
42
|
let onlyTransforms;
|
|
43
|
+
let platform;
|
|
49
44
|
let skipTransforms = [];
|
|
50
45
|
for (let index = 0; index < argv.length; index += 1) {
|
|
51
46
|
const arg = argv[index];
|
|
@@ -65,7 +60,7 @@ function parseArgs(argv) {
|
|
|
65
60
|
if (!rawValue || rawValue.startsWith('-')) {
|
|
66
61
|
throw new Error(`Expected ${arg} to have a comma-separated value.`);
|
|
67
62
|
}
|
|
68
|
-
const parsed =
|
|
63
|
+
const parsed = parseMigrationTransformList(rawValue, arg);
|
|
69
64
|
if (arg === '--only') {
|
|
70
65
|
if (onlyTransforms) {
|
|
71
66
|
throw new Error('Duplicate --only option.');
|
|
@@ -77,6 +72,21 @@ function parseArgs(argv) {
|
|
|
77
72
|
index += 1;
|
|
78
73
|
continue;
|
|
79
74
|
}
|
|
75
|
+
if (arg === '--platform') {
|
|
76
|
+
const rawValue = argv[index + 1];
|
|
77
|
+
if (!rawValue || rawValue.startsWith('-')) {
|
|
78
|
+
throw new Error('Expected --platform to have a platform name.');
|
|
79
|
+
}
|
|
80
|
+
if (platform) {
|
|
81
|
+
throw new Error('Duplicate --platform option.');
|
|
82
|
+
}
|
|
83
|
+
if (rawValue !== 'express') {
|
|
84
|
+
throw new Error(`Unsupported bootstrap platform: ${rawValue}. Supported platform: express.`);
|
|
85
|
+
}
|
|
86
|
+
platform = rawValue;
|
|
87
|
+
index += 1;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
80
90
|
if (arg.startsWith('-')) {
|
|
81
91
|
throw new Error(`Unknown option for migrate command: ${arg}`);
|
|
82
92
|
}
|
|
@@ -99,6 +109,7 @@ function parseArgs(argv) {
|
|
|
99
109
|
apply,
|
|
100
110
|
json,
|
|
101
111
|
path: pathArgument,
|
|
112
|
+
platform,
|
|
102
113
|
transforms: enabled
|
|
103
114
|
};
|
|
104
115
|
}
|
|
@@ -166,6 +177,7 @@ export async function runMigrateCommand(argv, runtime = {}) {
|
|
|
166
177
|
const transforms = [...parsed.transforms];
|
|
167
178
|
const report = runNestJsMigration({
|
|
168
179
|
apply: parsed.apply,
|
|
180
|
+
bootstrapPlatform: parsed.platform,
|
|
169
181
|
enabledTransforms: parsed.transforms,
|
|
170
182
|
targetPath
|
|
171
183
|
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type MigrationTransformKind } from '../transforms/nestjs-migrate.js';
|
|
2
|
+
/**
|
|
3
|
+
* Provides canonical migration transform tokens accepted by CLI options.
|
|
4
|
+
*/
|
|
5
|
+
export declare const MIGRATION_TRANSFORM_CLI_TOKENS: readonly ["imports", "inject-params", "scope", "bootstrap", "tests", "tsconfig"];
|
|
6
|
+
/**
|
|
7
|
+
* Parse canonical or legacy migration transform tokens from one CLI option.
|
|
8
|
+
*
|
|
9
|
+
* @param rawValue Comma-separated transform tokens passed to the CLI.
|
|
10
|
+
* @param optionName CLI option that supplied the transform tokens.
|
|
11
|
+
* @returns Canonical migration transform kinds.
|
|
12
|
+
* @throws When the option has no tokens or includes an unsupported token.
|
|
13
|
+
*/
|
|
14
|
+
export declare function parseMigrationTransformList(rawValue: string, optionName: '--only' | '--skip'): MigrationTransformKind[];
|
|
15
|
+
//# sourceMappingURL=migration-transform-tokens.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migration-transform-tokens.d.ts","sourceRoot":"","sources":["../../src/commands/migration-transform-tokens.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAEpG;;GAEG;AACH,eAAO,MAAM,8BAA8B,kFAAmF,CAAC;AAS/H;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,QAAQ,GAAG,QAAQ,GAC9B,sBAAsB,EAAE,CA2B1B"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { MIGRATION_TRANSFORMS } from '../transforms/nestjs-migrate.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Provides canonical migration transform tokens accepted by CLI options.
|
|
5
|
+
*/
|
|
6
|
+
export const MIGRATION_TRANSFORM_CLI_TOKENS = ['imports', 'inject-params', 'scope', 'bootstrap', 'tests', 'tsconfig'];
|
|
7
|
+
const MIGRATION_TRANSFORM_ALIASES = {
|
|
8
|
+
'inject-params': 'injectable',
|
|
9
|
+
injectable: 'injectable',
|
|
10
|
+
tests: 'testing',
|
|
11
|
+
testing: 'testing'
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Parse canonical or legacy migration transform tokens from one CLI option.
|
|
16
|
+
*
|
|
17
|
+
* @param rawValue Comma-separated transform tokens passed to the CLI.
|
|
18
|
+
* @param optionName CLI option that supplied the transform tokens.
|
|
19
|
+
* @returns Canonical migration transform kinds.
|
|
20
|
+
* @throws When the option has no tokens or includes an unsupported token.
|
|
21
|
+
*/
|
|
22
|
+
export function parseMigrationTransformList(rawValue, optionName) {
|
|
23
|
+
const values = rawValue.split(',').map(value => value.trim()).filter(value => value.length > 0);
|
|
24
|
+
if (values.length === 0) {
|
|
25
|
+
throw new Error(`${optionName} requires a non-empty comma-separated transform list.`);
|
|
26
|
+
}
|
|
27
|
+
const transforms = [];
|
|
28
|
+
const invalid = [];
|
|
29
|
+
for (const value of values) {
|
|
30
|
+
const transform = MIGRATION_TRANSFORMS.find(candidate => candidate === value) ?? (Object.hasOwn(MIGRATION_TRANSFORM_ALIASES, value) ? MIGRATION_TRANSFORM_ALIASES[value] : undefined);
|
|
31
|
+
if (transform) {
|
|
32
|
+
transforms.push(transform);
|
|
33
|
+
} else {
|
|
34
|
+
invalid.push(value);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (invalid.length > 0) {
|
|
38
|
+
throw new Error(`Unknown transform(s): ${invalid.join(', ')}. Available transforms: ${MIGRATION_TRANSFORM_CLI_TOKENS.join(', ')}.`);
|
|
39
|
+
}
|
|
40
|
+
return transforms;
|
|
41
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"new.d.ts","sourceRoot":"","sources":["../../src/commands/new.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"new.d.ts","sourceRoot":"","sources":["../../src/commands/new.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,iBAAiB,EAA2B,MAAM,kBAAkB,CAAC;AAYnF,OAAO,KAAK,EAAsC,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAI7F,KAAK,SAAS,GAAG;IACf,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC,CAAC;AAmCF;;GAEG;AACH,MAAM,WAAW,wBAAyB,SAAQ,iBAAiB;IACjE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,KAAK,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAC5B,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA+PD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,wBAA6B,GAAG,OAAO,CAAC,MAAM,CAAC,CA6H3G"}
|
package/dist/commands/new.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { resolve } from 'node:path';
|
|
2
|
-
import { log as clackLog, spinner as clackSpinner } from '@clack/prompts';
|
|
3
2
|
import { installDependencies } from '../new/install.js';
|
|
4
3
|
import { collectBootstrapAnswers } from '../new/prompt.js';
|
|
5
4
|
import { resolveBootstrapPlan } from '../new/resolver.js';
|
|
6
5
|
import { scaffoldBootstrapApp } from '../new/scaffold.js';
|
|
7
|
-
import { SUPPORTED_BOOTSTRAP_PLATFORMS, SUPPORTED_BOOTSTRAP_RUNTIMES, SUPPORTED_BOOTSTRAP_SHAPES, SUPPORTED_BOOTSTRAP_TOOLING_PRESETS, SUPPORTED_BOOTSTRAP_TOPOLOGY_MODES, SUPPORTED_BOOTSTRAP_TRANSPORTS } from '../new/starter-profiles.js';
|
|
6
|
+
import { SUPPORTED_BOOTSTRAP_PLATFORMS, SUPPORTED_BOOTSTRAP_RUNTIMES, SUPPORTED_BOOTSTRAP_SHAPES, SUPPORTED_BOOTSTRAP_STARTERS, SUPPORTED_BOOTSTRAP_TOOLING_PRESETS, SUPPORTED_BOOTSTRAP_TOPOLOGY_MODES, SUPPORTED_BOOTSTRAP_TRANSPORTS } from '../new/starter-profiles.js';
|
|
8
7
|
import { isCliPromptCancelledError } from '../prompt-cancel.js';
|
|
9
8
|
import { newUsage } from '../usage.js';
|
|
10
9
|
function shouldUseInteractiveShell(runtime) {
|
|
@@ -35,6 +34,7 @@ function readInternalScaffoldOverrides(runtime) {
|
|
|
35
34
|
|
|
36
35
|
const SUPPORTED_PACKAGE_MANAGERS = new Set(['bun', 'npm', 'pnpm', 'yarn']);
|
|
37
36
|
const SUPPORTED_SHAPES = new Set(SUPPORTED_BOOTSTRAP_SHAPES);
|
|
37
|
+
const SUPPORTED_STARTERS = new Set(SUPPORTED_BOOTSTRAP_STARTERS);
|
|
38
38
|
const SUPPORTED_TRANSPORTS = new Set(SUPPORTED_BOOTSTRAP_TRANSPORTS);
|
|
39
39
|
const SUPPORTED_RUNTIMES = new Set(SUPPORTED_BOOTSTRAP_RUNTIMES);
|
|
40
40
|
const SUPPORTED_PLATFORMS = new Set(SUPPORTED_BOOTSTRAP_PLATFORMS);
|
|
@@ -86,6 +86,16 @@ function parseArgs(argv) {
|
|
|
86
86
|
}
|
|
87
87
|
index += 1;
|
|
88
88
|
break;
|
|
89
|
+
case '--starter':
|
|
90
|
+
if (parsed.starter) {
|
|
91
|
+
throw new Error('Duplicate --starter option.');
|
|
92
|
+
}
|
|
93
|
+
parsed.starter = readOptionValue(argv, index, '--starter');
|
|
94
|
+
if (!SUPPORTED_STARTERS.has(parsed.starter)) {
|
|
95
|
+
throw new Error(`Invalid --starter value "${parsed.starter}". Use one of: standard, react-vite-ssr.`);
|
|
96
|
+
}
|
|
97
|
+
index += 1;
|
|
98
|
+
break;
|
|
89
99
|
case '--transport':
|
|
90
100
|
if (parsed.transport) {
|
|
91
101
|
throw new Error('Duplicate --transport option.');
|
|
@@ -189,7 +199,7 @@ function renderDependencyList(dependencies) {
|
|
|
189
199
|
}
|
|
190
200
|
function renderScaffoldPlanPreview(answers, resolvedTargetDirectory) {
|
|
191
201
|
const bootstrapPlan = resolveBootstrapPlan(answers);
|
|
192
|
-
return ['fluo new scaffold plan', '', `Project name: ${answers.projectName}`, `Target directory: ${answers.targetDirectory}`, `Resolved target: ${resolvedTargetDirectory}`, `Shape: ${answers.shape}`, `Runtime: ${answers.runtime}`, `Platform: ${answers.platform}`, `Transport: ${answers.transport}`, `Tooling preset: ${answers.tooling}`, `Topology: ${answers.topology.mode}${answers.topology.deferred ? ' (deferred)' : ''}`, `Starter recipe: ${bootstrapPlan.profile.id}`, `Emitter: ${bootstrapPlan.emitter.type}`, `Package manager: ${answers.packageManager}`, `Install dependencies: ${answers.installDependencies ? 'yes' : 'no'}`, `Initialize git: ${answers.initializeGit ? 'yes' : 'no'}`, '', 'Dependencies:', ` runtime: ${renderDependencyList(bootstrapPlan.dependencies.dependencies)}`, ` dev: ${renderDependencyList(bootstrapPlan.dependencies.devDependencies)}`, '', 'Side effects: none. Preview mode does not create files, install dependencies, or initialize git.'].join('\n');
|
|
202
|
+
return ['fluo new scaffold plan', '', `Project name: ${answers.projectName}`, `Target directory: ${answers.targetDirectory}`, `Resolved target: ${resolvedTargetDirectory}`, `Starter: ${answers.starter}`, `Shape: ${answers.shape}`, `Runtime: ${answers.runtime}`, `Platform: ${answers.platform}`, `Transport: ${answers.transport}`, `Tooling preset: ${answers.tooling}`, `Topology: ${answers.topology.mode}${answers.topology.deferred ? ' (deferred)' : ''}`, `Starter recipe: ${bootstrapPlan.profile.id}`, `Emitter: ${bootstrapPlan.emitter.type}`, `Package manager: ${answers.packageManager}`, `Install dependencies: ${answers.installDependencies ? 'yes' : 'no'}`, `Initialize git: ${answers.initializeGit ? 'yes' : 'no'}`, '', 'Dependencies:', ` runtime: ${renderDependencyList(bootstrapPlan.dependencies.dependencies)}`, ` dev: ${renderDependencyList(bootstrapPlan.dependencies.devDependencies)}`, '', 'Side effects: none. Preview mode does not create files, install dependencies, or initialize git.'].join('\n');
|
|
193
203
|
}
|
|
194
204
|
|
|
195
205
|
/**
|
|
@@ -226,9 +236,13 @@ export async function runNewCommand(argv, runtime = {}) {
|
|
|
226
236
|
if (!partialAnswers.projectName && !(runtime.interactive ?? runtime.prompt ?? runtime.stdin?.isTTY ?? process.stdin.isTTY)) {
|
|
227
237
|
throw new Error(newUsage());
|
|
228
238
|
}
|
|
239
|
+
let usedInteractivePrompt = false;
|
|
229
240
|
const answers = await collectBootstrapAnswers(partialAnswers, runtime.cwd ?? process.cwd(), runtime.userAgent, {
|
|
230
241
|
interactive: runtime.interactive,
|
|
231
242
|
completionMessage: parsed.printPlan ? 'Scaffold plan resolved. No files were written.' : undefined,
|
|
243
|
+
onInteractivePrompt: () => {
|
|
244
|
+
usedInteractivePrompt = true;
|
|
245
|
+
},
|
|
232
246
|
prompt: runtime.prompt,
|
|
233
247
|
stdin: runtime.stdin,
|
|
234
248
|
stdout
|
|
@@ -249,14 +263,15 @@ export async function runNewCommand(argv, runtime = {}) {
|
|
|
249
263
|
skipInstall: true,
|
|
250
264
|
targetDirectory
|
|
251
265
|
};
|
|
252
|
-
const isInteractiveShell = shouldUseInteractiveShell(runtime);
|
|
266
|
+
const isInteractiveShell = usedInteractivePrompt && shouldUseInteractiveShell(runtime);
|
|
267
|
+
const clack = isInteractiveShell ? await import('@clack/prompts') : undefined;
|
|
253
268
|
let scaffoldSpinner;
|
|
254
269
|
if (!answers.installDependencies && !isInteractiveShell) {
|
|
255
270
|
stdout.write('Skipping dependency installation.\n');
|
|
256
271
|
}
|
|
257
272
|
if (isInteractiveShell) {
|
|
258
|
-
scaffoldSpinner =
|
|
259
|
-
scaffoldSpinner
|
|
273
|
+
scaffoldSpinner = clack?.spinner();
|
|
274
|
+
scaffoldSpinner?.start('Scaffolding project files');
|
|
260
275
|
}
|
|
261
276
|
await scaffoldBootstrapApp(options);
|
|
262
277
|
if (scaffoldSpinner) {
|
|
@@ -269,7 +284,10 @@ export async function runNewCommand(argv, runtime = {}) {
|
|
|
269
284
|
stderr
|
|
270
285
|
});
|
|
271
286
|
} else {
|
|
272
|
-
const installSpinner =
|
|
287
|
+
const installSpinner = clack?.spinner();
|
|
288
|
+
if (!installSpinner) {
|
|
289
|
+
throw new Error('Interactive dependency installation requires @clack/prompts.');
|
|
290
|
+
}
|
|
273
291
|
installSpinner.start(`Installing dependencies with ${answers.packageManager}`);
|
|
274
292
|
try {
|
|
275
293
|
await installDependencies(targetDirectory, answers.packageManager, {
|
|
@@ -287,10 +305,12 @@ export async function runNewCommand(argv, runtime = {}) {
|
|
|
287
305
|
}
|
|
288
306
|
}
|
|
289
307
|
} else if (isInteractiveShell) {
|
|
290
|
-
|
|
308
|
+
clack?.log.step('Dependency installation skipped');
|
|
291
309
|
}
|
|
310
|
+
const devCommand = answers.packageManager === 'npm' ? 'npm run dev' : answers.packageManager === 'bun' ? 'bun run dev' : `${answers.packageManager} dev`;
|
|
311
|
+
const devDescription = answers.starter === 'react-vite-ssr' ? 'builds and starts the React SSR app' : 'runs fluo dev';
|
|
292
312
|
stdout.write('Done.\n');
|
|
293
|
-
stdout.write(`Next steps:\n cd ${answers.targetDirectory}\n ${
|
|
313
|
+
stdout.write(`Next steps:\n cd ${answers.targetDirectory}\n ${devCommand} # ${devDescription}\n`);
|
|
294
314
|
return 0;
|
|
295
315
|
} catch (error) {
|
|
296
316
|
if (isCliPromptCancelledError(error)) {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Raised when an artifact output resolves to its input application module. */
|
|
2
|
+
export declare class OutputPathAliasesModuleError extends Error {
|
|
3
|
+
readonly name = "OutputPathAliasesModuleError";
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Rejects an artifact path that directly or through a symlink resolves to the input module.
|
|
7
|
+
*
|
|
8
|
+
* @param modulePath Absolute application module path.
|
|
9
|
+
* @param outputPath Absolute artifact output path.
|
|
10
|
+
* @returns Resolves when the output path does not identify the input application module.
|
|
11
|
+
* @throws {OutputPathAliasesModuleError} When the paths identify the same file.
|
|
12
|
+
*/
|
|
13
|
+
export declare function assertOutputDoesNotAliasModule(modulePath: string, outputPath: string): Promise<void>;
|
|
14
|
+
//# sourceMappingURL=output-path-safety.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output-path-safety.d.ts","sourceRoot":"","sources":["../../src/commands/output-path-safety.ts"],"names":[],"mappings":"AAEA,+EAA+E;AAC/E,qBAAa,4BAA6B,SAAQ,KAAK;IACrD,QAAQ,CAAC,IAAI,kCAAkC;CAChD;AAMD;;;;;;;GAOG;AACH,wBAAsB,8BAA8B,CAClD,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAgBf"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { realpath } from 'node:fs/promises';
|
|
2
|
+
|
|
3
|
+
/** Raised when an artifact output resolves to its input application module. */
|
|
4
|
+
export class OutputPathAliasesModuleError extends Error {
|
|
5
|
+
name = 'OutputPathAliasesModuleError';
|
|
6
|
+
}
|
|
7
|
+
function isMissingPathError(error) {
|
|
8
|
+
return typeof error === 'object' && error !== null && 'code' in error && error.code === 'ENOENT';
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Rejects an artifact path that directly or through a symlink resolves to the input module.
|
|
13
|
+
*
|
|
14
|
+
* @param modulePath Absolute application module path.
|
|
15
|
+
* @param outputPath Absolute artifact output path.
|
|
16
|
+
* @returns Resolves when the output path does not identify the input application module.
|
|
17
|
+
* @throws {OutputPathAliasesModuleError} When the paths identify the same file.
|
|
18
|
+
*/
|
|
19
|
+
export async function assertOutputDoesNotAliasModule(modulePath, outputPath) {
|
|
20
|
+
if (modulePath === outputPath) {
|
|
21
|
+
throw new OutputPathAliasesModuleError('Output path must not identify the input application module.');
|
|
22
|
+
}
|
|
23
|
+
const resolvedModulePath = await realpath(modulePath);
|
|
24
|
+
try {
|
|
25
|
+
const resolvedOutputPath = await realpath(outputPath);
|
|
26
|
+
if (resolvedModulePath === resolvedOutputPath) {
|
|
27
|
+
throw new OutputPathAliasesModuleError('Output path must not identify the input application module.');
|
|
28
|
+
}
|
|
29
|
+
} catch (error) {
|
|
30
|
+
if (error instanceof OutputPathAliasesModuleError || !isMissingPathError(error)) {
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
package/dist/commands/scripts.js
CHANGED
|
@@ -403,7 +403,7 @@ function assertStudioSupport(command, studio, projectRuntime, devRunner, rawWatc
|
|
|
403
403
|
throw new Error('--studio is only supported for fluo dev.');
|
|
404
404
|
}
|
|
405
405
|
if (projectRuntime !== 'node') {
|
|
406
|
-
throw new Error(`fluo dev --studio
|
|
406
|
+
throw new Error(`fluo dev --studio supports Node dev runner projects only. ${projectRuntime} projects can generate Studio-compatible artifacts with fluo inspect <module-path> --json --output <path> or fluo inspect <module-path> --report --output <path>.`);
|
|
407
407
|
}
|
|
408
408
|
if (devRunner !== 'fluo' || rawWatch) {
|
|
409
409
|
throw new Error('fluo dev --studio requires the fluo-owned Node restart runner. Remove --raw-watch and use --runner fluo so Studio lifecycle events stay attached to the CLI restart boundary.');
|
|
@@ -597,7 +597,7 @@ async function runScriptWithStudioSidecar(command, projectDirectory, projectRunt
|
|
|
597
597
|
*/
|
|
598
598
|
export function scriptUsage(command) {
|
|
599
599
|
const nodeEnv = command === 'dev' ? 'development' : 'production';
|
|
600
|
-
return [`Usage: fluo ${command} [options] [-- <args>]`, '', `Run the generated fluo project ${command} lifecycle with NODE_ENV defaulting to ${nodeEnv} when unset.`, '', 'Default output forwards child stdout/stderr without fluo lifecycle UI.', 'Use --reporter pretty for fluo lifecycle status + app │ prefixes.', 'Use --verbose (or FLUO_VERBOSE=1) to expose raw runtime/tooling output.', '', 'Options', ' --dry-run Print the command without running it.', command === 'dev' ? ' --raw-watch Use the runtime-native Node watcher instead of the fluo restart runner.' : undefined, command === 'dev' ? ' --runner <fluo|native> Select fluo restart supervision or runtime-native watch (default: fluo for Node, native for non-Node runtimes).' : undefined, command === 'dev' ? ' --studio Start the local Fluo Studio sidecar
|
|
600
|
+
return [`Usage: fluo ${command} [options] [-- <args>]`, '', `Run the generated fluo project ${command} lifecycle with NODE_ENV defaulting to ${nodeEnv} when unset.`, '', 'Default output forwards child stdout/stderr without fluo lifecycle UI.', 'Use --reporter pretty for fluo lifecycle status + app │ prefixes.', 'Use --verbose (or FLUO_VERBOSE=1) to expose raw runtime/tooling output.', '', 'Options', ' --dry-run Print the command without running it.', command === 'dev' ? ' --raw-watch Use the runtime-native Node watcher instead of the fluo restart runner.' : undefined, command === 'dev' ? ' --runner <fluo|native> Select fluo restart supervision or runtime-native watch (default: fluo for Node, native for non-Node runtimes).' : undefined, command === 'dev' ? ' --studio Start the local Fluo Studio sidecar for Node dev runner projects only.' : undefined, command === 'dev' ? ' --studio-port <port> Bind the Studio sidecar to a specific local port (default: 0).' : undefined, ' --reporter <auto|pretty|stream|silent> Choose lifecycle reporter output mode (default: auto).', ' --verbose Expose raw child process output; also honored by FLUO_VERBOSE=1.', ` --help Show help for the ${command} command.`].filter(line => typeof line === 'string').join('\n');
|
|
601
601
|
}
|
|
602
602
|
|
|
603
603
|
/**
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/** Filesystem boundary used by deterministic typegen artifact commits. */
|
|
2
|
+
export type TypegenArtifactFileSystem = {
|
|
3
|
+
readonly mkdir: (path: string) => Promise<void>;
|
|
4
|
+
readonly readFile: (path: string) => Promise<string>;
|
|
5
|
+
readonly rename: (source: string, destination: string) => undefined;
|
|
6
|
+
readonly rm: (path: string) => Promise<void>;
|
|
7
|
+
readonly writeFile: (path: string, content: string) => Promise<void>;
|
|
8
|
+
};
|
|
9
|
+
type ArtifactInspection = {
|
|
10
|
+
readonly status: 'malformed';
|
|
11
|
+
} | {
|
|
12
|
+
readonly status: 'unsupported-version';
|
|
13
|
+
readonly version: number;
|
|
14
|
+
} | {
|
|
15
|
+
readonly status: 'valid';
|
|
16
|
+
readonly version: number;
|
|
17
|
+
};
|
|
18
|
+
/** Stable non-mutating comparison result for an existing typegen target. */
|
|
19
|
+
export type TypegenArtifactCheck = {
|
|
20
|
+
readonly status: 'MALFORMED';
|
|
21
|
+
} | {
|
|
22
|
+
readonly status: 'MISSING';
|
|
23
|
+
} | {
|
|
24
|
+
readonly status: 'STALE';
|
|
25
|
+
} | {
|
|
26
|
+
readonly status: 'UNCHANGED';
|
|
27
|
+
} | {
|
|
28
|
+
readonly status: 'UNSUPPORTED_VERSION';
|
|
29
|
+
readonly version: number;
|
|
30
|
+
};
|
|
31
|
+
/** Stable write action reported after an atomic typegen artifact commit. */
|
|
32
|
+
export type TypegenArtifactWriteAction = 'CREATE' | 'UNCHANGED' | 'UPDATE';
|
|
33
|
+
/**
|
|
34
|
+
* Compares an existing artifact with expected generated bytes without writing.
|
|
35
|
+
*
|
|
36
|
+
* @param outputPath Target artifact path.
|
|
37
|
+
* @param expectedSource Authoritative generated source.
|
|
38
|
+
* @param inspect Structural artifact classifier.
|
|
39
|
+
* @param fileSystem Filesystem boundary used to read the target.
|
|
40
|
+
* @returns A stable unchanged, missing, stale, malformed, or unsupported-version result.
|
|
41
|
+
*/
|
|
42
|
+
export declare function checkTypegenArtifact(outputPath: string, expectedSource: string, inspect: (source: string) => ArtifactInspection, fileSystem?: TypegenArtifactFileSystem): Promise<TypegenArtifactCheck>;
|
|
43
|
+
/**
|
|
44
|
+
* Atomically publishes generated source while skipping byte-identical rewrites.
|
|
45
|
+
*
|
|
46
|
+
* @param outputPath Target artifact path.
|
|
47
|
+
* @param source Complete generated source to publish.
|
|
48
|
+
* @param fileSystem Filesystem boundary used for the atomic replacement.
|
|
49
|
+
* @param signal Optional owner cancellation signal checked before publication.
|
|
50
|
+
* @returns The stable create, update, or unchanged action.
|
|
51
|
+
*/
|
|
52
|
+
export declare function writeTypegenArtifact(outputPath: string, source: string, fileSystem?: TypegenArtifactFileSystem, signal?: AbortSignal): Promise<TypegenArtifactWriteAction>;
|
|
53
|
+
export {};
|
|
54
|
+
//# sourceMappingURL=typegen-artifact.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typegen-artifact.d.ts","sourceRoot":"","sources":["../../src/commands/typegen-artifact.ts"],"names":[],"mappings":"AAIA,0EAA0E;AAC1E,MAAM,MAAM,yBAAyB,GAAG;IACtC,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,QAAQ,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,SAAS,CAAC;IACpE,QAAQ,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,QAAQ,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACtE,CAAC;AAEF,KAAK,kBAAkB,GACnB;IAAE,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;CAAE,GAChC;IAAE,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACpE;IAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3D,4EAA4E;AAC5E,MAAM,MAAM,oBAAoB,GAC5B;IAAE,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;CAAE,GAChC;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAA;CAAE,GAC9B;IAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;CAAE,GAC5B;IAAE,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;CAAE,GAChC;IAAE,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzE,4EAA4E;AAC5E,MAAM,MAAM,0BAA0B,GAAG,QAAQ,GAAG,WAAW,GAAG,QAAQ,CAAC;AAuC3E;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,kBAAkB,EAC/C,UAAU,GAAE,yBAA4C,GACvD,OAAO,CAAC,oBAAoB,CAAC,CAiB/B;AAED;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,UAAU,GAAE,yBAA4C,EACxD,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,0BAA0B,CAAC,CA0BrC"}
|