@flux-lang/cli 0.1.5 → 0.1.6-canary.18d439adc
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.md +43 -4
- package/dist/bin/flux.js +1205 -223
- package/dist/ui-routing.js +5 -0
- package/dist/version.js +1 -1
- package/dist/view/runViewer.js +101 -53
- package/package.json +8 -3
package/dist/bin/flux.js
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import fs from "node:fs/promises";
|
|
3
2
|
import path from "node:path";
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
|
+
import { spawn } from "node:child_process";
|
|
5
|
+
import { parseCommand, checkCommand, renderCommand, tickCommand, stepCommand, viewCommand, pdfCommand, configCommand, newCommand, addCommand, updateRecents, resolveConfig, formatCommand, } from "@flux-lang/cli-core";
|
|
6
6
|
import { runViewer } from "../view/runViewer.js";
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
import { createRuntime, parseDocument } from "@flux-lang/core";
|
|
8
|
+
import { shouldLaunchUi } from "../ui-routing.js";
|
|
9
|
+
import { computeBuildId, defaultEmbeddedDir, VIEWER_VERSION as VIEWER_PACKAGE_VERSION, } from "@flux-lang/viewer";
|
|
10
|
+
import { FLUX_CLI_VERSION } from "../version.js";
|
|
11
|
+
const CLI_VERSION = FLUX_CLI_VERSION;
|
|
9
12
|
void (async () => {
|
|
10
13
|
try {
|
|
11
14
|
const code = await main(process.argv.slice(2));
|
|
12
|
-
if (code !== 0)
|
|
15
|
+
if (code !== 0)
|
|
13
16
|
process.exit(code);
|
|
14
|
-
}
|
|
15
17
|
}
|
|
16
18
|
catch (error) {
|
|
17
19
|
const msg = error?.message ?? String(error);
|
|
@@ -20,69 +22,227 @@ void (async () => {
|
|
|
20
22
|
}
|
|
21
23
|
})();
|
|
22
24
|
async function main(argv) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
const parsed = parseGlobalArgs(argv);
|
|
26
|
+
const args = parsed.args;
|
|
27
|
+
const uiEnabled = shouldLaunchUi({
|
|
28
|
+
stdoutIsTTY: Boolean(process.stdout.isTTY),
|
|
29
|
+
stdinIsTTY: process.stdin.isTTY,
|
|
30
|
+
json: parsed.json,
|
|
31
|
+
noUi: parsed.noUi,
|
|
32
|
+
env: process.env,
|
|
33
|
+
});
|
|
34
|
+
if (uiEnabled) {
|
|
35
|
+
return launchUi({
|
|
36
|
+
cwd: process.cwd(),
|
|
37
|
+
initialArgs: args,
|
|
38
|
+
detach: parsed.detach,
|
|
39
|
+
helpCommand: parsed.help ? args[0] : undefined,
|
|
40
|
+
version: parsed.version ? `flux v${CLI_VERSION}` : undefined,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
if (parsed.version) {
|
|
44
|
+
await printVersion(parsed.json);
|
|
25
45
|
return 0;
|
|
26
46
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const idx = argv.findIndex((a) => a === "-h" || a === "--help");
|
|
30
|
-
// No subcommand yet → global
|
|
31
|
-
if (idx === 0) {
|
|
47
|
+
if (parsed.help) {
|
|
48
|
+
if (args.length === 0) {
|
|
32
49
|
printGlobalHelp();
|
|
33
50
|
return 0;
|
|
34
51
|
}
|
|
35
|
-
|
|
36
|
-
if (cmd === "parse") {
|
|
37
|
-
printParseHelp();
|
|
38
|
-
}
|
|
39
|
-
else if (cmd === "check") {
|
|
40
|
-
printCheckHelp();
|
|
41
|
-
}
|
|
42
|
-
else {
|
|
43
|
-
printGlobalHelp();
|
|
44
|
-
}
|
|
52
|
+
printCommandHelp(args[0]);
|
|
45
53
|
return 0;
|
|
46
54
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
console.log(`flux v${VERSION}`);
|
|
55
|
+
if (args.length === 0) {
|
|
56
|
+
printGlobalHelp();
|
|
50
57
|
return 0;
|
|
51
58
|
}
|
|
52
|
-
const [cmd, ...rest] =
|
|
53
|
-
|
|
54
|
-
|
|
59
|
+
const [cmd, ...rest] = args;
|
|
60
|
+
switch (cmd) {
|
|
61
|
+
case "parse":
|
|
62
|
+
return runParse(rest);
|
|
63
|
+
case "check":
|
|
64
|
+
return runCheck(rest, parsed);
|
|
65
|
+
case "render":
|
|
66
|
+
return runRender(rest);
|
|
67
|
+
case "fmt":
|
|
68
|
+
return runFormat(rest, parsed);
|
|
69
|
+
case "tick":
|
|
70
|
+
return runTick(rest);
|
|
71
|
+
case "step":
|
|
72
|
+
return runStep(rest);
|
|
73
|
+
case "view":
|
|
74
|
+
return runView(rest, parsed);
|
|
75
|
+
case "edit":
|
|
76
|
+
return runEdit(rest, parsed);
|
|
77
|
+
case "pdf":
|
|
78
|
+
return runPdf(rest, parsed);
|
|
79
|
+
case "config":
|
|
80
|
+
return runConfig(rest, parsed);
|
|
81
|
+
case "new":
|
|
82
|
+
return runNew(rest, parsed);
|
|
83
|
+
case "add":
|
|
84
|
+
return runAdd(rest, parsed);
|
|
85
|
+
default:
|
|
86
|
+
console.error(`Unknown command '${cmd}'.`);
|
|
87
|
+
printGlobalHelp();
|
|
88
|
+
return 1;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function isInteractive() {
|
|
92
|
+
return Boolean(process.stdout.isTTY && process.stdin.isTTY);
|
|
93
|
+
}
|
|
94
|
+
function parseGlobalArgs(argv) {
|
|
95
|
+
const flags = {
|
|
96
|
+
help: false,
|
|
97
|
+
version: false,
|
|
98
|
+
noUi: false,
|
|
99
|
+
ui: false,
|
|
100
|
+
detach: false,
|
|
101
|
+
json: false,
|
|
102
|
+
quiet: false,
|
|
103
|
+
verbose: false,
|
|
104
|
+
};
|
|
105
|
+
const args = [];
|
|
106
|
+
let passthrough = false;
|
|
107
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
108
|
+
const arg = argv[i];
|
|
109
|
+
if (arg === "--") {
|
|
110
|
+
passthrough = true;
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
if (!passthrough) {
|
|
114
|
+
if (arg === "-h" || arg === "--help") {
|
|
115
|
+
flags.help = true;
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (arg === "-v" || arg === "--version") {
|
|
119
|
+
flags.version = true;
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (arg === "--no-ui") {
|
|
123
|
+
flags.noUi = true;
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (arg === "--ui") {
|
|
127
|
+
flags.ui = true;
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
if (arg === "--detach") {
|
|
131
|
+
flags.detach = true;
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (arg === "--json") {
|
|
135
|
+
flags.json = true;
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
if (arg === "--quiet" || arg === "-q") {
|
|
139
|
+
flags.quiet = true;
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
if (arg === "--verbose" || arg === "-V") {
|
|
143
|
+
flags.verbose = true;
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
args.push(arg);
|
|
148
|
+
}
|
|
149
|
+
return { ...flags, args };
|
|
150
|
+
}
|
|
151
|
+
async function collectComponentVersions() {
|
|
152
|
+
let editorBuildId = null;
|
|
153
|
+
try {
|
|
154
|
+
const embedded = defaultEmbeddedDir();
|
|
155
|
+
const indexPath = path.join(embedded, "index.html");
|
|
156
|
+
editorBuildId = await computeBuildId(embedded, indexPath);
|
|
55
157
|
}
|
|
56
|
-
|
|
57
|
-
|
|
158
|
+
catch {
|
|
159
|
+
editorBuildId = null;
|
|
58
160
|
}
|
|
59
|
-
|
|
60
|
-
|
|
161
|
+
return {
|
|
162
|
+
cli: CLI_VERSION,
|
|
163
|
+
viewer: VIEWER_PACKAGE_VERSION,
|
|
164
|
+
editorBuildId,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
async function printVersion(asJson) {
|
|
168
|
+
const info = await collectComponentVersions();
|
|
169
|
+
if (asJson) {
|
|
170
|
+
console.log(JSON.stringify(info));
|
|
171
|
+
return;
|
|
61
172
|
}
|
|
62
|
-
console.
|
|
63
|
-
|
|
64
|
-
|
|
173
|
+
console.log(`cli ${info.cli}`);
|
|
174
|
+
console.log(`viewer ${info.viewer}`);
|
|
175
|
+
console.log(`editor ${info.editorBuildId ?? "unknown"}`);
|
|
176
|
+
}
|
|
177
|
+
function printCommandHelp(cmd) {
|
|
178
|
+
if (cmd === "parse")
|
|
179
|
+
return printParseHelp();
|
|
180
|
+
if (cmd === "check")
|
|
181
|
+
return printCheckHelp();
|
|
182
|
+
if (cmd === "render")
|
|
183
|
+
return printRenderHelp();
|
|
184
|
+
if (cmd === "fmt")
|
|
185
|
+
return printFormatHelp();
|
|
186
|
+
if (cmd === "tick")
|
|
187
|
+
return printTickHelp();
|
|
188
|
+
if (cmd === "step")
|
|
189
|
+
return printStepHelp();
|
|
190
|
+
if (cmd === "view")
|
|
191
|
+
return printViewHelp();
|
|
192
|
+
if (cmd === "edit")
|
|
193
|
+
return printEditHelp();
|
|
194
|
+
if (cmd === "pdf")
|
|
195
|
+
return printPdfHelp();
|
|
196
|
+
if (cmd === "config")
|
|
197
|
+
return printConfigHelp();
|
|
198
|
+
if (cmd === "new")
|
|
199
|
+
return printNewHelp();
|
|
200
|
+
if (cmd === "add")
|
|
201
|
+
return printAddHelp();
|
|
202
|
+
return printGlobalHelp();
|
|
65
203
|
}
|
|
66
|
-
/* -------------------------------------------------------------------------- */
|
|
67
|
-
/* Help text */
|
|
68
|
-
/* -------------------------------------------------------------------------- */
|
|
69
204
|
function printGlobalHelp() {
|
|
70
205
|
console.log([
|
|
71
|
-
`Flux CLI v${
|
|
206
|
+
`Flux CLI v${CLI_VERSION}`,
|
|
72
207
|
"",
|
|
73
208
|
"Usage:",
|
|
209
|
+
" flux (launch UI in TTY)",
|
|
74
210
|
" flux parse [options] <files...>",
|
|
75
211
|
" flux check [options] <files...>",
|
|
212
|
+
" flux render [options] <file>",
|
|
213
|
+
" flux fmt <file>",
|
|
214
|
+
" flux tick [options] <file>",
|
|
215
|
+
" flux step [options] <file>",
|
|
76
216
|
" flux view <file>",
|
|
217
|
+
" flux edit <file>",
|
|
218
|
+
" flux pdf <file> --out <file.pdf>",
|
|
219
|
+
" flux config [set <key> <value>]",
|
|
220
|
+
" flux new <template> [options]",
|
|
221
|
+
" flux add <kind> [options]",
|
|
77
222
|
"",
|
|
78
223
|
"Commands:",
|
|
79
224
|
" parse Parse Flux source files and print their IR as JSON.",
|
|
80
225
|
" check Parse and run basic static checks.",
|
|
81
|
-
"
|
|
226
|
+
" render Render a Flux document to canonical Render IR JSON.",
|
|
227
|
+
" fmt Format a Flux document in-place.",
|
|
228
|
+
" tick Advance time and render the updated document.",
|
|
229
|
+
" step Advance docsteps and render the updated document.",
|
|
230
|
+
" view View a Flux document in a local web preview.",
|
|
231
|
+
" edit Edit a Flux document in the local web editor.",
|
|
232
|
+
" pdf Export a Flux document snapshot to PDF.",
|
|
233
|
+
" config View or edit configuration.",
|
|
234
|
+
" new Create a new Flux document.",
|
|
235
|
+
" add Apply structured edits to a Flux document.",
|
|
82
236
|
"",
|
|
83
237
|
"Global options:",
|
|
84
238
|
" -h, --help Show this help message.",
|
|
85
239
|
" -v, --version Show CLI version.",
|
|
240
|
+
" --no-ui Disable Ink UI launch.",
|
|
241
|
+
" --ui Force Ink UI launch (TTY only).",
|
|
242
|
+
" --detach Keep viewer running on UI exit.",
|
|
243
|
+
" --json Emit machine-readable JSON where applicable.",
|
|
244
|
+
" -q, --quiet Reduce non-essential output.",
|
|
245
|
+
" -V, --verbose Show verbose logs.",
|
|
86
246
|
"",
|
|
87
247
|
].join("\n"));
|
|
88
248
|
}
|
|
@@ -117,239 +277,1061 @@ function printCheckHelp() {
|
|
|
117
277
|
"",
|
|
118
278
|
].join("\n"));
|
|
119
279
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
280
|
+
function printRenderHelp() {
|
|
281
|
+
console.log([
|
|
282
|
+
"Usage:",
|
|
283
|
+
" flux render [options] <file>",
|
|
284
|
+
"",
|
|
285
|
+
"Description:",
|
|
286
|
+
" Render a Flux document to canonical Render IR JSON.",
|
|
287
|
+
"",
|
|
288
|
+
"Options:",
|
|
289
|
+
" --format ir Output format. (required; currently only 'ir')",
|
|
290
|
+
" --seed N Deterministic RNG seed (default: 0).",
|
|
291
|
+
" --time T Render time in seconds (default: 0).",
|
|
292
|
+
" --docstep D Render at docstep D (default: 0).",
|
|
293
|
+
" -h, --help Show this message.",
|
|
294
|
+
"",
|
|
295
|
+
].join("\n"));
|
|
296
|
+
}
|
|
297
|
+
function printFormatHelp() {
|
|
298
|
+
console.log([
|
|
299
|
+
"Usage:",
|
|
300
|
+
" flux fmt <file>",
|
|
301
|
+
"",
|
|
302
|
+
"Description:",
|
|
303
|
+
" Apply a minimal formatter to a Flux document.",
|
|
304
|
+
"",
|
|
305
|
+
"Options:",
|
|
306
|
+
" -h, --help Show this message.",
|
|
307
|
+
"",
|
|
308
|
+
].join("\n"));
|
|
309
|
+
}
|
|
310
|
+
function printTickHelp() {
|
|
311
|
+
console.log([
|
|
312
|
+
"Usage:",
|
|
313
|
+
" flux tick [options] <file>",
|
|
314
|
+
"",
|
|
315
|
+
"Description:",
|
|
316
|
+
" Advance time by a number of seconds and render the updated IR.",
|
|
317
|
+
"",
|
|
318
|
+
"Options:",
|
|
319
|
+
" --seconds S Seconds to advance time by.",
|
|
320
|
+
" --seed N Deterministic RNG seed (default: 0).",
|
|
321
|
+
" -h, --help Show this message.",
|
|
322
|
+
"",
|
|
323
|
+
].join("\n"));
|
|
324
|
+
}
|
|
325
|
+
function printStepHelp() {
|
|
326
|
+
console.log([
|
|
327
|
+
"Usage:",
|
|
328
|
+
" flux step [options] <file>",
|
|
329
|
+
"",
|
|
330
|
+
"Description:",
|
|
331
|
+
" Advance docsteps and render the updated IR.",
|
|
332
|
+
"",
|
|
333
|
+
"Options:",
|
|
334
|
+
" --n N Docsteps to advance by (default: 1).",
|
|
335
|
+
" --seed N Deterministic RNG seed (default: 0).",
|
|
336
|
+
" -h, --help Show this message.",
|
|
337
|
+
"",
|
|
338
|
+
].join("\n"));
|
|
339
|
+
}
|
|
340
|
+
function printViewHelp() {
|
|
341
|
+
console.log([
|
|
342
|
+
"Usage:",
|
|
343
|
+
" flux view [options] <file>",
|
|
344
|
+
"",
|
|
345
|
+
"Description:",
|
|
346
|
+
" Open a local web viewer for a Flux document.",
|
|
347
|
+
"",
|
|
348
|
+
"Options:",
|
|
349
|
+
" --port <n> Port for the local server (default: auto).",
|
|
350
|
+
" --docstep-ms <n> Docstep interval in milliseconds.",
|
|
351
|
+
" --time-rate <n> Time multiplier for viewer ticks (default: 1).",
|
|
352
|
+
" --seed <n> Seed for deterministic rendering.",
|
|
353
|
+
" --allow-net <orig> Allow remote assets for origin (repeatable or comma-separated).",
|
|
354
|
+
" --editor-dist <p> Serve editor assets from this dist folder.",
|
|
355
|
+
" --no-time Disable automatic time advancement.",
|
|
356
|
+
" --tty Use the legacy TTY grid viewer.",
|
|
357
|
+
" -h, --help Show this message.",
|
|
358
|
+
"",
|
|
359
|
+
].join("\n"));
|
|
360
|
+
}
|
|
361
|
+
function printEditHelp() {
|
|
362
|
+
console.log([
|
|
363
|
+
"Usage:",
|
|
364
|
+
" flux edit [options] <file>",
|
|
365
|
+
"",
|
|
366
|
+
"Description:",
|
|
367
|
+
" Open the local web editor for a Flux document.",
|
|
368
|
+
"",
|
|
369
|
+
"Options:",
|
|
370
|
+
" --port <n> Port for the local server (default: auto).",
|
|
371
|
+
" --docstep-ms <n> Docstep interval in milliseconds.",
|
|
372
|
+
" --time-rate <n> Time multiplier for viewer ticks (default: 1).",
|
|
373
|
+
" --seed <n> Seed for deterministic rendering.",
|
|
374
|
+
" --allow-net <orig> Allow remote assets for origin (repeatable or comma-separated).",
|
|
375
|
+
" --editor-dist <p> Serve editor assets from this dist folder.",
|
|
376
|
+
" --no-time Disable automatic time advancement.",
|
|
377
|
+
" -h, --help Show this message.",
|
|
378
|
+
"",
|
|
379
|
+
].join("\n"));
|
|
380
|
+
}
|
|
381
|
+
function printPdfHelp() {
|
|
382
|
+
console.log([
|
|
383
|
+
"Usage:",
|
|
384
|
+
" flux pdf [options] <file> --out <file.pdf>",
|
|
385
|
+
"",
|
|
386
|
+
"Description:",
|
|
387
|
+
" Render a Flux document snapshot to PDF.",
|
|
388
|
+
"",
|
|
389
|
+
"Options:",
|
|
390
|
+
" --out <file> Output PDF path. (required)",
|
|
391
|
+
" --seed <n> Seed for deterministic rendering.",
|
|
392
|
+
" --docstep <n> Docstep to render.",
|
|
393
|
+
" -h, --help Show this message.",
|
|
394
|
+
"",
|
|
395
|
+
].join("\n"));
|
|
396
|
+
}
|
|
397
|
+
function printConfigHelp() {
|
|
398
|
+
console.log([
|
|
399
|
+
"Usage:",
|
|
400
|
+
" flux config",
|
|
401
|
+
" flux config set <key> <value> [--init]",
|
|
402
|
+
"",
|
|
403
|
+
"Options:",
|
|
404
|
+
" --json Emit JSON.",
|
|
405
|
+
" --init Create flux.config.json if missing.",
|
|
406
|
+
"",
|
|
407
|
+
].join("\n"));
|
|
408
|
+
}
|
|
409
|
+
function printNewHelp() {
|
|
410
|
+
console.log([
|
|
411
|
+
"Usage:",
|
|
412
|
+
" flux new (launch wizard)",
|
|
413
|
+
" flux new <template> --out <dir> --page Letter|A4 --theme print|screen|both --fonts tech|bookish",
|
|
414
|
+
" --fallback system|none --assets yes|no --chapters N --live yes|no",
|
|
415
|
+
"",
|
|
416
|
+
"Templates:",
|
|
417
|
+
" demo, article, spec, zine, paper, blank",
|
|
418
|
+
"",
|
|
419
|
+
].join("\n"));
|
|
420
|
+
}
|
|
421
|
+
function printAddHelp() {
|
|
422
|
+
console.log([
|
|
423
|
+
"Usage:",
|
|
424
|
+
" flux add <kind> [options] <file>",
|
|
425
|
+
"",
|
|
426
|
+
"Kinds:",
|
|
427
|
+
" title, page, section, figure, callout, table, slot, inline-slot, bibliography-stub",
|
|
428
|
+
"",
|
|
429
|
+
"Options:",
|
|
430
|
+
" --text <value> Text value for title/callout.",
|
|
431
|
+
" --heading <value> Heading text for sections.",
|
|
432
|
+
" --label <value> Optional label for figure/callout.",
|
|
433
|
+
" --no-heading Omit section heading.",
|
|
434
|
+
" --no-check Skip check after editing.",
|
|
435
|
+
"",
|
|
436
|
+
].join("\n"));
|
|
437
|
+
}
|
|
123
438
|
async function runParse(args) {
|
|
124
|
-
const opts = {
|
|
125
|
-
ndjson: false,
|
|
126
|
-
pretty: false,
|
|
127
|
-
compact: false,
|
|
128
|
-
};
|
|
129
|
-
const files = [];
|
|
439
|
+
const opts = { ndjson: false, pretty: false, compact: false, files: [] };
|
|
130
440
|
for (const arg of args) {
|
|
131
|
-
if (arg === "--ndjson")
|
|
441
|
+
if (arg === "--ndjson")
|
|
132
442
|
opts.ndjson = true;
|
|
133
|
-
|
|
134
|
-
else if (arg === "--pretty") {
|
|
443
|
+
else if (arg === "--pretty")
|
|
135
444
|
opts.pretty = true;
|
|
136
|
-
|
|
137
|
-
else if (arg === "--compact") {
|
|
445
|
+
else if (arg === "--compact")
|
|
138
446
|
opts.compact = true;
|
|
447
|
+
else
|
|
448
|
+
opts.files.push(arg);
|
|
449
|
+
}
|
|
450
|
+
const result = await parseCommand(opts);
|
|
451
|
+
if (!result.ok || !result.data) {
|
|
452
|
+
console.error(result.error?.message ?? "flux parse failed");
|
|
453
|
+
if (result.error?.code === "NO_INPUT")
|
|
454
|
+
printParseHelp();
|
|
455
|
+
return 1;
|
|
456
|
+
}
|
|
457
|
+
if (result.data.ndjson) {
|
|
458
|
+
for (const item of result.data.docs) {
|
|
459
|
+
process.stdout.write(JSON.stringify({ file: item.file, doc: item.doc }) + "\n");
|
|
460
|
+
}
|
|
461
|
+
return 0;
|
|
462
|
+
}
|
|
463
|
+
const doc = result.data.docs[0].doc;
|
|
464
|
+
const space = result.data.compact ? 0 : 2;
|
|
465
|
+
process.stdout.write(JSON.stringify(doc, null, space) + "\n");
|
|
466
|
+
return 0;
|
|
467
|
+
}
|
|
468
|
+
async function runCheck(args, globals) {
|
|
469
|
+
const files = args.filter((arg) => !arg.startsWith("-"));
|
|
470
|
+
const result = await checkCommand({ files, json: globals.json });
|
|
471
|
+
if (!result.ok || !result.data) {
|
|
472
|
+
console.error(result.error?.message ?? "flux check failed");
|
|
473
|
+
printCheckHelp();
|
|
474
|
+
return 1;
|
|
475
|
+
}
|
|
476
|
+
const results = result.data.results;
|
|
477
|
+
const failed = results.filter((r) => !r.ok);
|
|
478
|
+
if (globals.json) {
|
|
479
|
+
for (const r of results) {
|
|
480
|
+
const payload = {
|
|
481
|
+
file: r.file,
|
|
482
|
+
ok: r.ok,
|
|
483
|
+
};
|
|
484
|
+
if (r.errors)
|
|
485
|
+
payload.errors = r.errors.map((message) => ({ message }));
|
|
486
|
+
process.stdout.write(JSON.stringify(payload) + "\n");
|
|
487
|
+
}
|
|
488
|
+
return failed.length ? 1 : 0;
|
|
489
|
+
}
|
|
490
|
+
for (const r of results) {
|
|
491
|
+
if (!r.errors)
|
|
492
|
+
continue;
|
|
493
|
+
for (const msg of r.errors)
|
|
494
|
+
console.error(msg);
|
|
495
|
+
}
|
|
496
|
+
if (failed.length) {
|
|
497
|
+
if (!globals.quiet)
|
|
498
|
+
console.log(`✗ ${failed.length} of ${results.length} files failed checks`);
|
|
499
|
+
return 1;
|
|
500
|
+
}
|
|
501
|
+
if (!globals.quiet)
|
|
502
|
+
console.log(`✓ ${results.length} files OK`);
|
|
503
|
+
return 0;
|
|
504
|
+
}
|
|
505
|
+
async function runRender(args) {
|
|
506
|
+
let format = "ir";
|
|
507
|
+
let seed;
|
|
508
|
+
let time;
|
|
509
|
+
let docstep;
|
|
510
|
+
let file;
|
|
511
|
+
try {
|
|
512
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
513
|
+
const arg = args[i];
|
|
514
|
+
if (arg === "--format") {
|
|
515
|
+
format = args[i + 1] ?? "";
|
|
516
|
+
i += 1;
|
|
517
|
+
}
|
|
518
|
+
else if (arg.startsWith("--format=")) {
|
|
519
|
+
format = arg.slice("--format=".length);
|
|
520
|
+
}
|
|
521
|
+
else if (arg === "--seed") {
|
|
522
|
+
seed = parseNumberFlag("--seed", args[i + 1]);
|
|
523
|
+
i += 1;
|
|
524
|
+
}
|
|
525
|
+
else if (arg.startsWith("--seed=")) {
|
|
526
|
+
seed = parseNumberFlag("--seed", arg.slice("--seed=".length));
|
|
527
|
+
}
|
|
528
|
+
else if (arg === "--time") {
|
|
529
|
+
time = parseNumberFlag("--time", args[i + 1]);
|
|
530
|
+
i += 1;
|
|
531
|
+
}
|
|
532
|
+
else if (arg.startsWith("--time=")) {
|
|
533
|
+
time = parseNumberFlag("--time", arg.slice("--time=".length));
|
|
534
|
+
}
|
|
535
|
+
else if (arg === "--docstep") {
|
|
536
|
+
docstep = parseNumberFlag("--docstep", args[i + 1]);
|
|
537
|
+
i += 1;
|
|
538
|
+
}
|
|
539
|
+
else if (arg.startsWith("--docstep=")) {
|
|
540
|
+
docstep = parseNumberFlag("--docstep", arg.slice("--docstep=".length));
|
|
541
|
+
}
|
|
542
|
+
else if (!arg.startsWith("-")) {
|
|
543
|
+
file = arg;
|
|
544
|
+
}
|
|
139
545
|
}
|
|
140
|
-
|
|
141
|
-
|
|
546
|
+
}
|
|
547
|
+
catch (error) {
|
|
548
|
+
console.error(`flux render: ${error?.message ?? error}`);
|
|
549
|
+
return 1;
|
|
550
|
+
}
|
|
551
|
+
if (!file) {
|
|
552
|
+
console.error("flux render: No input file specified.");
|
|
553
|
+
printRenderHelp();
|
|
554
|
+
return 1;
|
|
555
|
+
}
|
|
556
|
+
const result = await renderCommand({ file, format: format, seed, time, docstep });
|
|
557
|
+
if (!result.ok || !result.data) {
|
|
558
|
+
console.error(result.error?.message ?? "flux render failed");
|
|
559
|
+
return 1;
|
|
560
|
+
}
|
|
561
|
+
process.stdout.write(JSON.stringify(result.data.rendered, null, 2) + "\n");
|
|
562
|
+
return 0;
|
|
563
|
+
}
|
|
564
|
+
async function runFormat(args, globals) {
|
|
565
|
+
const file = args.find((arg) => !arg.startsWith("-"));
|
|
566
|
+
if (!file) {
|
|
567
|
+
console.error("flux fmt: No input file specified.");
|
|
568
|
+
printFormatHelp();
|
|
569
|
+
return 1;
|
|
570
|
+
}
|
|
571
|
+
const result = await formatCommand({ file });
|
|
572
|
+
if (!result.ok || !result.data) {
|
|
573
|
+
console.error(result.error?.message ?? "flux fmt failed");
|
|
574
|
+
return 1;
|
|
575
|
+
}
|
|
576
|
+
if (globals.json) {
|
|
577
|
+
process.stdout.write(JSON.stringify(result.data) + "\n");
|
|
578
|
+
}
|
|
579
|
+
else if (!globals.quiet) {
|
|
580
|
+
console.log(`Formatted ${file}`);
|
|
581
|
+
}
|
|
582
|
+
return 0;
|
|
583
|
+
}
|
|
584
|
+
async function runTick(args) {
|
|
585
|
+
let seconds;
|
|
586
|
+
let seed;
|
|
587
|
+
let file;
|
|
588
|
+
try {
|
|
589
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
590
|
+
const arg = args[i];
|
|
591
|
+
if (arg === "--seconds") {
|
|
592
|
+
seconds = parseNumberFlag("--seconds", args[i + 1]);
|
|
593
|
+
i += 1;
|
|
594
|
+
}
|
|
595
|
+
else if (arg.startsWith("--seconds=")) {
|
|
596
|
+
seconds = parseNumberFlag("--seconds", arg.slice("--seconds=".length));
|
|
597
|
+
}
|
|
598
|
+
else if (arg === "--seed") {
|
|
599
|
+
seed = parseNumberFlag("--seed", args[i + 1]);
|
|
600
|
+
i += 1;
|
|
601
|
+
}
|
|
602
|
+
else if (arg.startsWith("--seed=")) {
|
|
603
|
+
seed = parseNumberFlag("--seed", arg.slice("--seed=".length));
|
|
604
|
+
}
|
|
605
|
+
else if (!arg.startsWith("-")) {
|
|
606
|
+
file = arg;
|
|
607
|
+
}
|
|
142
608
|
}
|
|
143
609
|
}
|
|
144
|
-
|
|
145
|
-
console.error(
|
|
146
|
-
printParseHelp();
|
|
610
|
+
catch (error) {
|
|
611
|
+
console.error(`flux tick: ${error?.message ?? error}`);
|
|
147
612
|
return 1;
|
|
148
613
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
614
|
+
if (!file) {
|
|
615
|
+
console.error("flux tick: No input file specified.");
|
|
616
|
+
printTickHelp();
|
|
152
617
|
return 1;
|
|
153
618
|
}
|
|
154
|
-
if (
|
|
155
|
-
console.error("flux
|
|
619
|
+
if (seconds === undefined) {
|
|
620
|
+
console.error("flux tick: --seconds is required.");
|
|
621
|
+
printTickHelp();
|
|
156
622
|
return 1;
|
|
157
623
|
}
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
624
|
+
const result = await tickCommand({ file, seconds, seed });
|
|
625
|
+
if (!result.ok || !result.data) {
|
|
626
|
+
console.error(result.error?.message ?? "flux tick failed");
|
|
627
|
+
return 1;
|
|
628
|
+
}
|
|
629
|
+
process.stdout.write(JSON.stringify(result.data.rendered, null, 2) + "\n");
|
|
630
|
+
return 0;
|
|
631
|
+
}
|
|
632
|
+
async function runStep(args) {
|
|
633
|
+
let count;
|
|
634
|
+
let seed;
|
|
635
|
+
let file;
|
|
636
|
+
try {
|
|
637
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
638
|
+
const arg = args[i];
|
|
639
|
+
if (arg === "--n") {
|
|
640
|
+
count = parseNumberFlag("--n", args[i + 1]);
|
|
641
|
+
i += 1;
|
|
642
|
+
}
|
|
643
|
+
else if (arg.startsWith("--n=")) {
|
|
644
|
+
count = parseNumberFlag("--n", arg.slice("--n=".length));
|
|
645
|
+
}
|
|
646
|
+
else if (arg === "--seed") {
|
|
647
|
+
seed = parseNumberFlag("--seed", args[i + 1]);
|
|
648
|
+
i += 1;
|
|
649
|
+
}
|
|
650
|
+
else if (arg.startsWith("--seed=")) {
|
|
651
|
+
seed = parseNumberFlag("--seed", arg.slice("--seed=".length));
|
|
652
|
+
}
|
|
653
|
+
else if (!arg.startsWith("-")) {
|
|
654
|
+
file = arg;
|
|
655
|
+
}
|
|
163
656
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
657
|
+
}
|
|
658
|
+
catch (error) {
|
|
659
|
+
console.error(`flux step: ${error?.message ?? error}`);
|
|
660
|
+
return 1;
|
|
661
|
+
}
|
|
662
|
+
if (!file) {
|
|
663
|
+
console.error("flux step: No input file specified.");
|
|
664
|
+
printStepHelp();
|
|
665
|
+
return 1;
|
|
666
|
+
}
|
|
667
|
+
const result = await stepCommand({ file, steps: count, seed });
|
|
668
|
+
if (!result.ok || !result.data) {
|
|
669
|
+
console.error(result.error?.message ?? "flux step failed");
|
|
670
|
+
return 1;
|
|
671
|
+
}
|
|
672
|
+
process.stdout.write(JSON.stringify(result.data.rendered, null, 2) + "\n");
|
|
673
|
+
return 0;
|
|
674
|
+
}
|
|
675
|
+
async function runView(args, globals) {
|
|
676
|
+
let port;
|
|
677
|
+
let docstepMs;
|
|
678
|
+
let timeRate;
|
|
679
|
+
let seed;
|
|
680
|
+
let useTty = false;
|
|
681
|
+
let editorDist;
|
|
682
|
+
const allowNet = [];
|
|
683
|
+
let file;
|
|
684
|
+
let advanceTime = true;
|
|
685
|
+
let advanceTimeExplicit = false;
|
|
686
|
+
try {
|
|
687
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
688
|
+
const arg = args[i];
|
|
689
|
+
if (arg === "--tty") {
|
|
690
|
+
useTty = true;
|
|
691
|
+
}
|
|
692
|
+
else if (arg === "--no-time") {
|
|
693
|
+
advanceTime = false;
|
|
694
|
+
advanceTimeExplicit = true;
|
|
695
|
+
}
|
|
696
|
+
else if (arg === "--port") {
|
|
697
|
+
port = parseNumberFlag("--port", args[i + 1]);
|
|
698
|
+
i += 1;
|
|
699
|
+
}
|
|
700
|
+
else if (arg.startsWith("--port=")) {
|
|
701
|
+
port = parseNumberFlag("--port", arg.slice("--port=".length));
|
|
702
|
+
}
|
|
703
|
+
else if (arg === "--docstep-ms") {
|
|
704
|
+
docstepMs = parseNumberFlag("--docstep-ms", args[i + 1]);
|
|
705
|
+
i += 1;
|
|
706
|
+
}
|
|
707
|
+
else if (arg.startsWith("--docstep-ms=")) {
|
|
708
|
+
docstepMs = parseNumberFlag("--docstep-ms", arg.slice("--docstep-ms=".length));
|
|
709
|
+
}
|
|
710
|
+
else if (arg === "--time-rate") {
|
|
711
|
+
timeRate = parseNumberFlag("--time-rate", args[i + 1]);
|
|
712
|
+
i += 1;
|
|
713
|
+
}
|
|
714
|
+
else if (arg.startsWith("--time-rate=")) {
|
|
715
|
+
timeRate = parseNumberFlag("--time-rate", arg.slice("--time-rate=".length));
|
|
716
|
+
}
|
|
717
|
+
else if (arg === "--seed") {
|
|
718
|
+
seed = parseNumberFlag("--seed", args[i + 1]);
|
|
719
|
+
i += 1;
|
|
720
|
+
}
|
|
721
|
+
else if (arg.startsWith("--seed=")) {
|
|
722
|
+
seed = parseNumberFlag("--seed", arg.slice("--seed=".length));
|
|
723
|
+
}
|
|
724
|
+
else if (arg === "--allow-net") {
|
|
725
|
+
const raw = args[i + 1] ?? "";
|
|
726
|
+
allowNet.push(...raw.split(",").map((item) => item.trim()).filter(Boolean));
|
|
727
|
+
i += 1;
|
|
728
|
+
}
|
|
729
|
+
else if (arg.startsWith("--allow-net=")) {
|
|
730
|
+
const raw = arg.slice("--allow-net=".length);
|
|
731
|
+
allowNet.push(...raw.split(",").map((item) => item.trim()).filter(Boolean));
|
|
732
|
+
}
|
|
733
|
+
else if (arg === "--editor-dist") {
|
|
734
|
+
editorDist = args[i + 1];
|
|
735
|
+
i += 1;
|
|
736
|
+
}
|
|
737
|
+
else if (arg.startsWith("--editor-dist=")) {
|
|
738
|
+
editorDist = arg.slice("--editor-dist=".length);
|
|
739
|
+
}
|
|
740
|
+
else if (!arg.startsWith("-")) {
|
|
741
|
+
file = arg;
|
|
742
|
+
}
|
|
168
743
|
}
|
|
744
|
+
}
|
|
745
|
+
catch (error) {
|
|
746
|
+
console.error(`flux view: ${error?.message ?? error}`);
|
|
747
|
+
return 1;
|
|
748
|
+
}
|
|
749
|
+
const resolved = await resolveConfig({ cwd: process.cwd(), env: process.env });
|
|
750
|
+
if (docstepMs === undefined) {
|
|
751
|
+
docstepMs = resolved.config.docstepMs;
|
|
752
|
+
}
|
|
753
|
+
if (!advanceTimeExplicit) {
|
|
754
|
+
advanceTime = resolved.config.advanceTime;
|
|
755
|
+
}
|
|
756
|
+
if (!file) {
|
|
757
|
+
console.error("flux view: No input file specified.");
|
|
758
|
+
printViewHelp();
|
|
759
|
+
return 1;
|
|
760
|
+
}
|
|
761
|
+
if (file === "-") {
|
|
762
|
+
console.error("flux view: stdin input is not supported for the web viewer.");
|
|
763
|
+
return 1;
|
|
764
|
+
}
|
|
765
|
+
if (useTty) {
|
|
169
766
|
try {
|
|
170
|
-
const
|
|
171
|
-
|
|
767
|
+
const source = await fs.readFile(file, "utf8");
|
|
768
|
+
const doc = parseFlux(source, file);
|
|
769
|
+
const runtime = createRuntime(doc, { clock: "manual" });
|
|
770
|
+
await runViewer(runtime, { docPath: file, title: doc.meta.title, materialLabels: new Map() });
|
|
771
|
+
return 0;
|
|
172
772
|
}
|
|
173
773
|
catch (error) {
|
|
174
|
-
|
|
175
|
-
console.error(msg);
|
|
774
|
+
console.error(`flux view: ${String(error?.message ?? error)}`);
|
|
176
775
|
return 1;
|
|
177
776
|
}
|
|
178
777
|
}
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
778
|
+
const result = await viewCommand({
|
|
779
|
+
cwd: process.cwd(),
|
|
780
|
+
docPath: file,
|
|
781
|
+
port,
|
|
782
|
+
docstepMs,
|
|
783
|
+
seed,
|
|
784
|
+
allowNet,
|
|
785
|
+
advanceTime,
|
|
786
|
+
timeRate,
|
|
787
|
+
editorDist,
|
|
788
|
+
});
|
|
789
|
+
if (!result.ok || !result.data) {
|
|
790
|
+
console.error(result.error?.message ?? "flux view failed");
|
|
791
|
+
return 1;
|
|
792
|
+
}
|
|
793
|
+
await updateRecents(process.cwd(), path.resolve(file));
|
|
794
|
+
const session = result.data.session;
|
|
795
|
+
if (globals.json) {
|
|
796
|
+
process.stdout.write(JSON.stringify(session) + "\n");
|
|
797
|
+
}
|
|
798
|
+
else if (!globals.quiet) {
|
|
799
|
+
console.log(`Flux viewer running at ${session.url}`);
|
|
800
|
+
if (session.attached) {
|
|
801
|
+
console.log("Attached to existing viewer.");
|
|
184
802
|
}
|
|
185
|
-
|
|
803
|
+
console.log("Press Ctrl+C to stop.");
|
|
804
|
+
}
|
|
805
|
+
if (!globals.quiet) {
|
|
806
|
+
openBrowser(session.url);
|
|
807
|
+
}
|
|
808
|
+
if (session.close) {
|
|
809
|
+
await new Promise((resolve) => {
|
|
810
|
+
const shutdown = async () => {
|
|
811
|
+
await session.close?.();
|
|
812
|
+
resolve();
|
|
813
|
+
};
|
|
814
|
+
process.on("SIGINT", shutdown);
|
|
815
|
+
process.on("SIGTERM", shutdown);
|
|
816
|
+
});
|
|
186
817
|
}
|
|
187
|
-
// Single file → pretty by default unless compact explicitly requested
|
|
188
|
-
const doc = docs[0].doc;
|
|
189
|
-
const space = opts.compact ? 0 : 2;
|
|
190
|
-
const json = JSON.stringify(doc, null, space);
|
|
191
|
-
process.stdout.write(json + "\n");
|
|
192
818
|
return 0;
|
|
193
819
|
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
820
|
+
async function runEdit(args, globals) {
|
|
821
|
+
let port;
|
|
822
|
+
let docstepMs;
|
|
823
|
+
let timeRate;
|
|
824
|
+
let seed;
|
|
825
|
+
let editorDist;
|
|
826
|
+
const allowNet = [];
|
|
827
|
+
let file;
|
|
828
|
+
let advanceTime = true;
|
|
829
|
+
let advanceTimeExplicit = false;
|
|
830
|
+
try {
|
|
831
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
832
|
+
const arg = args[i];
|
|
833
|
+
if (arg === "--no-time") {
|
|
834
|
+
advanceTime = false;
|
|
835
|
+
advanceTimeExplicit = true;
|
|
836
|
+
}
|
|
837
|
+
else if (arg === "--port") {
|
|
838
|
+
port = parseNumberFlag("--port", args[i + 1]);
|
|
839
|
+
i += 1;
|
|
840
|
+
}
|
|
841
|
+
else if (arg.startsWith("--port=")) {
|
|
842
|
+
port = parseNumberFlag("--port", arg.slice("--port=".length));
|
|
843
|
+
}
|
|
844
|
+
else if (arg === "--docstep-ms") {
|
|
845
|
+
docstepMs = parseNumberFlag("--docstep-ms", args[i + 1]);
|
|
846
|
+
i += 1;
|
|
847
|
+
}
|
|
848
|
+
else if (arg.startsWith("--docstep-ms=")) {
|
|
849
|
+
docstepMs = parseNumberFlag("--docstep-ms", arg.slice("--docstep-ms=".length));
|
|
850
|
+
}
|
|
851
|
+
else if (arg === "--time-rate") {
|
|
852
|
+
timeRate = parseNumberFlag("--time-rate", args[i + 1]);
|
|
853
|
+
i += 1;
|
|
854
|
+
}
|
|
855
|
+
else if (arg.startsWith("--time-rate=")) {
|
|
856
|
+
timeRate = parseNumberFlag("--time-rate", arg.slice("--time-rate=".length));
|
|
857
|
+
}
|
|
858
|
+
else if (arg === "--seed") {
|
|
859
|
+
seed = parseNumberFlag("--seed", args[i + 1]);
|
|
860
|
+
i += 1;
|
|
861
|
+
}
|
|
862
|
+
else if (arg.startsWith("--seed=")) {
|
|
863
|
+
seed = parseNumberFlag("--seed", arg.slice("--seed=".length));
|
|
864
|
+
}
|
|
865
|
+
else if (arg === "--allow-net") {
|
|
866
|
+
const raw = args[i + 1] ?? "";
|
|
867
|
+
allowNet.push(...raw.split(",").map((item) => item.trim()).filter(Boolean));
|
|
868
|
+
i += 1;
|
|
869
|
+
}
|
|
870
|
+
else if (arg.startsWith("--allow-net=")) {
|
|
871
|
+
const raw = arg.slice("--allow-net=".length);
|
|
872
|
+
allowNet.push(...raw.split(",").map((item) => item.trim()).filter(Boolean));
|
|
873
|
+
}
|
|
874
|
+
else if (arg === "--editor-dist") {
|
|
875
|
+
editorDist = args[i + 1];
|
|
876
|
+
i += 1;
|
|
877
|
+
}
|
|
878
|
+
else if (arg.startsWith("--editor-dist=")) {
|
|
879
|
+
editorDist = arg.slice("--editor-dist=".length);
|
|
880
|
+
}
|
|
881
|
+
else if (!arg.startsWith("-")) {
|
|
882
|
+
file = arg;
|
|
883
|
+
}
|
|
208
884
|
}
|
|
209
885
|
}
|
|
210
|
-
|
|
211
|
-
console.error(
|
|
212
|
-
printCheckHelp();
|
|
886
|
+
catch (error) {
|
|
887
|
+
console.error(`flux edit: ${error?.message ?? error}`);
|
|
213
888
|
return 1;
|
|
214
889
|
}
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
890
|
+
const resolved = await resolveConfig({ cwd: process.cwd(), env: process.env });
|
|
891
|
+
if (docstepMs === undefined) {
|
|
892
|
+
docstepMs = resolved.config.docstepMs;
|
|
893
|
+
}
|
|
894
|
+
if (!advanceTimeExplicit) {
|
|
895
|
+
advanceTime = resolved.config.advanceTime;
|
|
896
|
+
}
|
|
897
|
+
if (!file) {
|
|
898
|
+
console.error("flux edit: No input file specified.");
|
|
899
|
+
printEditHelp();
|
|
900
|
+
return 1;
|
|
901
|
+
}
|
|
902
|
+
if (file === "-") {
|
|
903
|
+
console.error("flux edit: stdin input is not supported for the web editor.");
|
|
904
|
+
return 1;
|
|
905
|
+
}
|
|
906
|
+
const result = await viewCommand({
|
|
907
|
+
cwd: process.cwd(),
|
|
908
|
+
docPath: file,
|
|
909
|
+
port,
|
|
910
|
+
docstepMs,
|
|
911
|
+
seed,
|
|
912
|
+
allowNet,
|
|
913
|
+
advanceTime,
|
|
914
|
+
timeRate,
|
|
915
|
+
editorDist,
|
|
916
|
+
});
|
|
917
|
+
if (!result.ok || !result.data) {
|
|
918
|
+
console.error(result.error?.message ?? "flux edit failed");
|
|
919
|
+
return 1;
|
|
920
|
+
}
|
|
921
|
+
await updateRecents(process.cwd(), path.resolve(file));
|
|
922
|
+
const session = result.data.session;
|
|
923
|
+
const absolutePath = path.resolve(file);
|
|
924
|
+
const editorUrl = `${session.url}/edit?file=${encodeURIComponent(absolutePath)}`;
|
|
925
|
+
let buildId = session.buildId;
|
|
926
|
+
let editorDistPath = session.editorDist;
|
|
927
|
+
if (!buildId) {
|
|
928
|
+
const fetchImpl = globalThis?.fetch;
|
|
929
|
+
if (fetchImpl) {
|
|
930
|
+
try {
|
|
931
|
+
const res = await fetchImpl(`${session.url}/edit/build-id.json`, { cache: "no-store" });
|
|
932
|
+
if (res.ok) {
|
|
933
|
+
const json = await res.json();
|
|
934
|
+
buildId = json?.buildId ?? null;
|
|
935
|
+
editorDistPath = json?.editorDist ?? editorDistPath;
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
catch {
|
|
939
|
+
// ignore
|
|
940
|
+
}
|
|
233
941
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
});
|
|
241
|
-
continue;
|
|
942
|
+
}
|
|
943
|
+
if (globals.json) {
|
|
944
|
+
process.stdout.write(JSON.stringify({ ...session, editorUrl }) + "\n");
|
|
945
|
+
}
|
|
946
|
+
else if (!globals.quiet) {
|
|
947
|
+
if (buildId || editorDistPath) {
|
|
948
|
+
console.log(`[flux] editor build ${buildId ?? "unknown"} (${editorDistPath ?? "unknown"})`);
|
|
242
949
|
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
initRuntimeState(doc);
|
|
950
|
+
console.log(`Flux editor running at ${editorUrl}`);
|
|
951
|
+
if (session.attached) {
|
|
952
|
+
console.log("Attached to existing editor.");
|
|
247
953
|
}
|
|
248
|
-
|
|
249
|
-
const detail = error?.message ?? String(error);
|
|
250
|
-
errors.push(`${file}:0:0: Check error: initRuntimeState failed: ${detail}`);
|
|
251
|
-
}
|
|
252
|
-
// Static checks (grids, neighbors, timers, etc.)
|
|
253
|
-
errors.push(...checkDocument(file, doc));
|
|
254
|
-
results.push({
|
|
255
|
-
file,
|
|
256
|
-
ok: errors.length === 0,
|
|
257
|
-
errors: errors.length ? errors : undefined,
|
|
258
|
-
});
|
|
954
|
+
console.log("Press Ctrl+C to stop.");
|
|
259
955
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
if (
|
|
264
|
-
|
|
265
|
-
const
|
|
266
|
-
|
|
267
|
-
|
|
956
|
+
if (!globals.quiet) {
|
|
957
|
+
openBrowser(editorUrl);
|
|
958
|
+
}
|
|
959
|
+
if (session.close) {
|
|
960
|
+
await new Promise((resolve) => {
|
|
961
|
+
const shutdown = async () => {
|
|
962
|
+
await session.close?.();
|
|
963
|
+
resolve();
|
|
268
964
|
};
|
|
269
|
-
|
|
270
|
-
|
|
965
|
+
process.on("SIGINT", shutdown);
|
|
966
|
+
process.on("SIGTERM", shutdown);
|
|
967
|
+
});
|
|
968
|
+
}
|
|
969
|
+
return 0;
|
|
970
|
+
}
|
|
971
|
+
async function runPdf(args, globals) {
|
|
972
|
+
let seed;
|
|
973
|
+
let docstep;
|
|
974
|
+
let outPath;
|
|
975
|
+
let file;
|
|
976
|
+
try {
|
|
977
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
978
|
+
const arg = args[i];
|
|
979
|
+
if (arg === "--out") {
|
|
980
|
+
outPath = args[i + 1];
|
|
981
|
+
i += 1;
|
|
982
|
+
}
|
|
983
|
+
else if (arg.startsWith("--out=")) {
|
|
984
|
+
outPath = arg.slice("--out=".length);
|
|
985
|
+
}
|
|
986
|
+
else if (arg === "--seed") {
|
|
987
|
+
seed = parseNumberFlag("--seed", args[i + 1]);
|
|
988
|
+
i += 1;
|
|
989
|
+
}
|
|
990
|
+
else if (arg.startsWith("--seed=")) {
|
|
991
|
+
seed = parseNumberFlag("--seed", arg.slice("--seed=".length));
|
|
992
|
+
}
|
|
993
|
+
else if (arg === "--docstep") {
|
|
994
|
+
docstep = parseNumberFlag("--docstep", args[i + 1]);
|
|
995
|
+
i += 1;
|
|
996
|
+
}
|
|
997
|
+
else if (arg.startsWith("--docstep=")) {
|
|
998
|
+
docstep = parseNumberFlag("--docstep", arg.slice("--docstep=".length));
|
|
999
|
+
}
|
|
1000
|
+
else if (!arg.startsWith("-")) {
|
|
1001
|
+
file = arg;
|
|
271
1002
|
}
|
|
272
|
-
process.stdout.write(JSON.stringify(payload) + "\n");
|
|
273
1003
|
}
|
|
274
|
-
return hasFailure ? 1 : 0;
|
|
275
1004
|
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
1005
|
+
catch (error) {
|
|
1006
|
+
console.error(`flux pdf: ${error?.message ?? error}`);
|
|
1007
|
+
return 1;
|
|
1008
|
+
}
|
|
1009
|
+
if (!file || !outPath) {
|
|
1010
|
+
console.error("flux pdf: --out <file.pdf> is required.");
|
|
1011
|
+
printPdfHelp();
|
|
1012
|
+
return 1;
|
|
283
1013
|
}
|
|
284
|
-
|
|
285
|
-
|
|
1014
|
+
const result = await pdfCommand({ file, outPath, seed, docstep });
|
|
1015
|
+
if (!result.ok || !result.data) {
|
|
1016
|
+
console.error(result.error?.message ?? "flux pdf failed");
|
|
286
1017
|
return 1;
|
|
287
1018
|
}
|
|
288
|
-
|
|
1019
|
+
if (globals.json) {
|
|
1020
|
+
process.stdout.write(JSON.stringify(result.data) + "\n");
|
|
1021
|
+
}
|
|
1022
|
+
else if (!globals.quiet) {
|
|
1023
|
+
console.log(`Wrote PDF to ${outPath}`);
|
|
1024
|
+
}
|
|
289
1025
|
return 0;
|
|
290
1026
|
}
|
|
291
|
-
|
|
292
|
-
/* flux view */
|
|
293
|
-
/* -------------------------------------------------------------------------- */
|
|
294
|
-
async function runView(args) {
|
|
1027
|
+
async function runConfig(args, globals) {
|
|
295
1028
|
if (args.length === 0) {
|
|
296
|
-
|
|
1029
|
+
const result = await configCommand({
|
|
1030
|
+
cwd: process.cwd(),
|
|
1031
|
+
action: "view",
|
|
1032
|
+
env: process.env,
|
|
1033
|
+
});
|
|
1034
|
+
if (!result.ok || !result.data) {
|
|
1035
|
+
console.error(result.error?.message ?? "flux config failed");
|
|
1036
|
+
return 1;
|
|
1037
|
+
}
|
|
1038
|
+
return printConfig(result.data.config, globals);
|
|
1039
|
+
}
|
|
1040
|
+
if (args[0] === "set") {
|
|
1041
|
+
const key = args[1];
|
|
1042
|
+
const value = args[2];
|
|
1043
|
+
const init = args.includes("--init");
|
|
1044
|
+
if (!key || value === undefined) {
|
|
1045
|
+
printConfigHelp();
|
|
1046
|
+
return 1;
|
|
1047
|
+
}
|
|
1048
|
+
const parsedValue = parseConfigValue(key, value);
|
|
1049
|
+
const result = await configCommand({
|
|
1050
|
+
cwd: process.cwd(),
|
|
1051
|
+
action: "set",
|
|
1052
|
+
key: parsedValue.key,
|
|
1053
|
+
value: parsedValue.value,
|
|
1054
|
+
init,
|
|
1055
|
+
env: process.env,
|
|
1056
|
+
});
|
|
1057
|
+
if (!result.ok || !result.data) {
|
|
1058
|
+
console.error(result.error?.message ?? "flux config set failed");
|
|
1059
|
+
return 1;
|
|
1060
|
+
}
|
|
1061
|
+
return printConfig(result.data.config, globals);
|
|
1062
|
+
}
|
|
1063
|
+
printConfigHelp();
|
|
1064
|
+
return 1;
|
|
1065
|
+
}
|
|
1066
|
+
async function runNew(args, globals) {
|
|
1067
|
+
const [template, ...rest] = args;
|
|
1068
|
+
if (!template) {
|
|
1069
|
+
printNewHelp();
|
|
297
1070
|
return 1;
|
|
298
1071
|
}
|
|
299
|
-
const
|
|
300
|
-
|
|
301
|
-
const
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
for (const mat of doc.materials?.materials ?? []) {
|
|
306
|
-
labels.set(mat.name, mat.label ?? mat.name);
|
|
307
|
-
}
|
|
308
|
-
await runViewer(runtime, { docPath, title: doc.meta.title, materialLabels: labels });
|
|
309
|
-
return 0;
|
|
1072
|
+
const opts = parseNewArgs(rest);
|
|
1073
|
+
if (!opts.out) {
|
|
1074
|
+
const resolved = await resolveConfig({ cwd: process.cwd(), env: process.env });
|
|
1075
|
+
if (resolved.config.defaultOutputDir && resolved.config.defaultOutputDir !== ".") {
|
|
1076
|
+
opts.out = resolved.config.defaultOutputDir;
|
|
1077
|
+
}
|
|
310
1078
|
}
|
|
311
|
-
|
|
312
|
-
|
|
1079
|
+
const result = await newCommand({
|
|
1080
|
+
cwd: process.cwd(),
|
|
1081
|
+
template: template,
|
|
1082
|
+
out: opts.out,
|
|
1083
|
+
page: opts.page,
|
|
1084
|
+
theme: opts.theme,
|
|
1085
|
+
fonts: opts.fonts,
|
|
1086
|
+
fontFallback: opts.fontFallback,
|
|
1087
|
+
assets: opts.assets,
|
|
1088
|
+
chapters: opts.chapters,
|
|
1089
|
+
live: opts.live,
|
|
1090
|
+
});
|
|
1091
|
+
if (!result.ok || !result.data) {
|
|
1092
|
+
console.error(result.error?.message ?? "flux new failed");
|
|
313
1093
|
return 1;
|
|
314
1094
|
}
|
|
1095
|
+
await updateRecents(process.cwd(), result.data.docPath);
|
|
1096
|
+
if (globals.json) {
|
|
1097
|
+
process.stdout.write(JSON.stringify(result.data) + "\n");
|
|
1098
|
+
}
|
|
1099
|
+
else if (!globals.quiet) {
|
|
1100
|
+
console.log(`Created ${result.data.docPath}`);
|
|
1101
|
+
printNewNextSteps(result.data.docPath);
|
|
1102
|
+
}
|
|
1103
|
+
return 0;
|
|
315
1104
|
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
1105
|
+
async function runAdd(args, globals) {
|
|
1106
|
+
const [kind, ...rest] = args;
|
|
1107
|
+
if (!kind) {
|
|
1108
|
+
printAddHelp();
|
|
1109
|
+
return 1;
|
|
1110
|
+
}
|
|
1111
|
+
const parsed = parseAddArgs(rest);
|
|
1112
|
+
if (!parsed.file) {
|
|
1113
|
+
console.error("flux add: missing <file>");
|
|
1114
|
+
printAddHelp();
|
|
1115
|
+
return 1;
|
|
1116
|
+
}
|
|
1117
|
+
const result = await addCommand({
|
|
1118
|
+
cwd: process.cwd(),
|
|
1119
|
+
file: parsed.file,
|
|
1120
|
+
kind: kind,
|
|
1121
|
+
text: parsed.text,
|
|
1122
|
+
heading: parsed.heading,
|
|
1123
|
+
label: parsed.label,
|
|
1124
|
+
noHeading: parsed.noHeading,
|
|
1125
|
+
noCheck: parsed.noCheck,
|
|
1126
|
+
});
|
|
1127
|
+
if (!result.ok || !result.data) {
|
|
1128
|
+
console.error(result.error?.message ?? "flux add failed");
|
|
1129
|
+
return 1;
|
|
1130
|
+
}
|
|
1131
|
+
if (globals.json) {
|
|
1132
|
+
process.stdout.write(JSON.stringify(result.data) + "\n");
|
|
1133
|
+
}
|
|
1134
|
+
else if (!globals.quiet) {
|
|
1135
|
+
console.log(`Updated ${result.data.file}`);
|
|
322
1136
|
}
|
|
323
|
-
return
|
|
1137
|
+
return 0;
|
|
324
1138
|
}
|
|
325
|
-
function
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
1139
|
+
function parseNewArgs(args) {
|
|
1140
|
+
const opts = {};
|
|
1141
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
1142
|
+
const arg = args[i];
|
|
1143
|
+
if (arg === "--out") {
|
|
1144
|
+
opts.out = args[i + 1];
|
|
1145
|
+
i += 1;
|
|
1146
|
+
}
|
|
1147
|
+
else if (arg.startsWith("--out=")) {
|
|
1148
|
+
opts.out = arg.slice("--out=".length);
|
|
1149
|
+
}
|
|
1150
|
+
else if (arg === "--page") {
|
|
1151
|
+
opts.page = args[i + 1];
|
|
1152
|
+
i += 1;
|
|
1153
|
+
}
|
|
1154
|
+
else if (arg.startsWith("--page=")) {
|
|
1155
|
+
opts.page = arg.slice("--page=".length);
|
|
1156
|
+
}
|
|
1157
|
+
else if (arg === "--theme") {
|
|
1158
|
+
opts.theme = args[i + 1];
|
|
1159
|
+
i += 1;
|
|
1160
|
+
}
|
|
1161
|
+
else if (arg.startsWith("--theme=")) {
|
|
1162
|
+
opts.theme = arg.slice("--theme=".length);
|
|
1163
|
+
}
|
|
1164
|
+
else if (arg === "--fonts") {
|
|
1165
|
+
opts.fonts = args[i + 1];
|
|
1166
|
+
i += 1;
|
|
1167
|
+
}
|
|
1168
|
+
else if (arg.startsWith("--fonts=")) {
|
|
1169
|
+
opts.fonts = arg.slice("--fonts=".length);
|
|
1170
|
+
}
|
|
1171
|
+
else if (arg === "--fallback" || arg === "--font-fallback") {
|
|
1172
|
+
opts.fontFallback = parseFontFallback(args[i + 1]);
|
|
1173
|
+
i += 1;
|
|
1174
|
+
}
|
|
1175
|
+
else if (arg.startsWith("--fallback=")) {
|
|
1176
|
+
opts.fontFallback = parseFontFallback(arg.slice("--fallback=".length));
|
|
1177
|
+
}
|
|
1178
|
+
else if (arg.startsWith("--font-fallback=")) {
|
|
1179
|
+
opts.fontFallback = parseFontFallback(arg.slice("--font-fallback=".length));
|
|
1180
|
+
}
|
|
1181
|
+
else if (arg === "--assets") {
|
|
1182
|
+
opts.assets = parseYesNo(args[i + 1]);
|
|
1183
|
+
i += 1;
|
|
1184
|
+
}
|
|
1185
|
+
else if (arg.startsWith("--assets=")) {
|
|
1186
|
+
opts.assets = parseYesNo(arg.slice("--assets=".length));
|
|
1187
|
+
}
|
|
1188
|
+
else if (arg === "--chapters") {
|
|
1189
|
+
opts.chapters = parseNumberFlag("--chapters", args[i + 1]);
|
|
1190
|
+
i += 1;
|
|
1191
|
+
}
|
|
1192
|
+
else if (arg.startsWith("--chapters=")) {
|
|
1193
|
+
opts.chapters = parseNumberFlag("--chapters", arg.slice("--chapters=".length));
|
|
1194
|
+
}
|
|
1195
|
+
else if (arg === "--live") {
|
|
1196
|
+
opts.live = parseYesNo(args[i + 1]);
|
|
1197
|
+
i += 1;
|
|
1198
|
+
}
|
|
1199
|
+
else if (arg.startsWith("--live=")) {
|
|
1200
|
+
opts.live = parseYesNo(arg.slice("--live=".length));
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
return opts;
|
|
1204
|
+
}
|
|
1205
|
+
function parseAddArgs(args) {
|
|
1206
|
+
const opts = {};
|
|
1207
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
1208
|
+
const arg = args[i];
|
|
1209
|
+
if (arg === "--text") {
|
|
1210
|
+
opts.text = args[i + 1];
|
|
1211
|
+
i += 1;
|
|
1212
|
+
}
|
|
1213
|
+
else if (arg.startsWith("--text=")) {
|
|
1214
|
+
opts.text = arg.slice("--text=".length);
|
|
1215
|
+
}
|
|
1216
|
+
else if (arg === "--heading") {
|
|
1217
|
+
opts.heading = args[i + 1];
|
|
1218
|
+
i += 1;
|
|
1219
|
+
}
|
|
1220
|
+
else if (arg.startsWith("--heading=")) {
|
|
1221
|
+
opts.heading = arg.slice("--heading=".length);
|
|
1222
|
+
}
|
|
1223
|
+
else if (arg === "--label") {
|
|
1224
|
+
opts.label = args[i + 1];
|
|
1225
|
+
i += 1;
|
|
1226
|
+
}
|
|
1227
|
+
else if (arg.startsWith("--label=")) {
|
|
1228
|
+
opts.label = arg.slice("--label=".length);
|
|
1229
|
+
}
|
|
1230
|
+
else if (arg === "--no-heading") {
|
|
1231
|
+
opts.noHeading = true;
|
|
1232
|
+
}
|
|
1233
|
+
else if (arg === "--no-check") {
|
|
1234
|
+
opts.noCheck = true;
|
|
1235
|
+
}
|
|
1236
|
+
else if (!arg.startsWith("-")) {
|
|
1237
|
+
opts.file = arg;
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
return opts;
|
|
1241
|
+
}
|
|
1242
|
+
function parseYesNo(raw) {
|
|
1243
|
+
if (!raw)
|
|
1244
|
+
return true;
|
|
1245
|
+
return !(raw === "no" || raw === "false" || raw === "0");
|
|
1246
|
+
}
|
|
1247
|
+
function parseFontFallback(raw) {
|
|
1248
|
+
if (!raw)
|
|
1249
|
+
return "system";
|
|
1250
|
+
if (raw === "none" || raw === "off" || raw === "false" || raw === "0")
|
|
1251
|
+
return "none";
|
|
1252
|
+
return "system";
|
|
1253
|
+
}
|
|
1254
|
+
function parseConfigValue(key, raw) {
|
|
1255
|
+
switch (key) {
|
|
1256
|
+
case "docstepMs":
|
|
1257
|
+
case "docstep-ms":
|
|
1258
|
+
return { key: "docstepMs", value: Number(raw) };
|
|
1259
|
+
case "advanceTime":
|
|
1260
|
+
case "advance-time":
|
|
1261
|
+
return { key: "advanceTime", value: raw !== "0" && raw !== "false" };
|
|
1262
|
+
case "defaultPageSize":
|
|
1263
|
+
case "page":
|
|
1264
|
+
return { key: "defaultPageSize", value: (raw === "A4" ? "A4" : "Letter") };
|
|
1265
|
+
case "defaultTheme":
|
|
1266
|
+
case "theme":
|
|
1267
|
+
return { key: "defaultTheme", value: raw };
|
|
1268
|
+
case "defaultFonts":
|
|
1269
|
+
case "fonts":
|
|
1270
|
+
return { key: "defaultFonts", value: raw };
|
|
1271
|
+
case "defaultOutputDir":
|
|
1272
|
+
case "output":
|
|
1273
|
+
return { key: "defaultOutputDir", value: raw };
|
|
1274
|
+
default:
|
|
1275
|
+
return { key: key, value: raw };
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
async function printConfig(config, globals) {
|
|
1279
|
+
if (globals.json) {
|
|
1280
|
+
process.stdout.write(JSON.stringify(config, null, 2) + "\n");
|
|
1281
|
+
return 0;
|
|
1282
|
+
}
|
|
1283
|
+
if (!globals.quiet) {
|
|
1284
|
+
console.log(JSON.stringify(config, null, 2));
|
|
1285
|
+
}
|
|
1286
|
+
return 0;
|
|
1287
|
+
}
|
|
1288
|
+
function printNewNextSteps(docPath) {
|
|
1289
|
+
const pdfPath = docPath.replace(/\.flux$/i, ".pdf");
|
|
1290
|
+
console.log([
|
|
1291
|
+
"",
|
|
1292
|
+
"Next steps:",
|
|
1293
|
+
` flux view ${docPath}`,
|
|
1294
|
+
` flux check ${docPath}`,
|
|
1295
|
+
` flux pdf ${docPath} --out ${pdfPath}`,
|
|
1296
|
+
"",
|
|
1297
|
+
].join("\n"));
|
|
1298
|
+
}
|
|
1299
|
+
function parseNumberFlag(flag, raw) {
|
|
1300
|
+
const value = Number(raw);
|
|
1301
|
+
if (!Number.isFinite(value)) {
|
|
1302
|
+
throw new Error(`${flag} expects a finite number`);
|
|
1303
|
+
}
|
|
1304
|
+
return value;
|
|
1305
|
+
}
|
|
1306
|
+
function openBrowser(url) {
|
|
1307
|
+
const command = process.platform === "darwin"
|
|
1308
|
+
? "open"
|
|
1309
|
+
: process.platform === "win32"
|
|
1310
|
+
? "cmd"
|
|
1311
|
+
: "xdg-open";
|
|
1312
|
+
const args = process.platform === "win32" ? ["/c", "start", url.replace(/&/g, "^&")] : [url];
|
|
1313
|
+
spawn(command, args, { stdio: "ignore", detached: true });
|
|
1314
|
+
}
|
|
1315
|
+
async function launchUi(options) {
|
|
1316
|
+
const { runCliUi } = await import("@flux-lang/cli-ui");
|
|
1317
|
+
await runCliUi({
|
|
1318
|
+
cwd: options.cwd,
|
|
1319
|
+
mode: options.mode,
|
|
1320
|
+
initialArgs: options.initialArgs,
|
|
1321
|
+
detach: options.detach,
|
|
1322
|
+
helpCommand: options.helpCommand,
|
|
1323
|
+
version: options.version,
|
|
334
1324
|
});
|
|
1325
|
+
return 0;
|
|
335
1326
|
}
|
|
336
|
-
function
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
const [, line, column, near, detail] = parseMatch;
|
|
347
|
-
return `${file}:${line}:${column}: Parse error near '${near}': ${detail}`;
|
|
348
|
-
}
|
|
349
|
-
const lexMatch = /Lexer error at (\d+):(\d+)\s*-\s*(.*)/.exec(message);
|
|
350
|
-
if (lexMatch) {
|
|
351
|
-
const [, line, column, detail] = lexMatch;
|
|
352
|
-
return `${file}:${line}:${column}: Lexer error: ${detail}`;
|
|
353
|
-
}
|
|
354
|
-
return `${file}:0:0: ${message}`;
|
|
1327
|
+
function parseFlux(source, filePath) {
|
|
1328
|
+
if (!filePath || filePath === "-") {
|
|
1329
|
+
return parseDocument(source);
|
|
1330
|
+
}
|
|
1331
|
+
const resolved = path.resolve(filePath);
|
|
1332
|
+
return parseDocument(source, {
|
|
1333
|
+
sourcePath: resolved,
|
|
1334
|
+
docRoot: path.dirname(resolved),
|
|
1335
|
+
resolveIncludes: true,
|
|
1336
|
+
});
|
|
355
1337
|
}
|