@flux-lang/cli 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin/flux.js CHANGED
@@ -1,7 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import fs from "node:fs/promises";
3
+ import path from "node:path";
3
4
  import { stdin as nodeStdin } from "node:process";
4
- import { parseDocument, initRuntimeState, checkDocument, } from "@flux-lang/core";
5
+ import { createRuntime, parseDocument, initRuntimeState, checkDocument } from "@flux-lang/core";
6
+ import { runViewer } from "../view/runViewer.js";
5
7
  const VERSION = "0.1.0";
6
8
  // Entry
7
9
  void (async () => {
@@ -54,6 +56,9 @@ async function main(argv) {
54
56
  if (cmd === "check") {
55
57
  return runCheck(rest);
56
58
  }
59
+ if (cmd === "view") {
60
+ return runView(rest);
61
+ }
57
62
  console.error(`Unknown command '${cmd}'.`);
58
63
  printGlobalHelp();
59
64
  return 1;
@@ -68,10 +73,12 @@ function printGlobalHelp() {
68
73
  "Usage:",
69
74
  " flux parse [options] <files...>",
70
75
  " flux check [options] <files...>",
76
+ " flux view <file>",
71
77
  "",
72
78
  "Commands:",
73
79
  " parse Parse Flux source files and print their IR as JSON.",
74
80
  " check Parse and run basic static checks.",
81
+ " view View a Flux document in a simple docstep viewer.",
75
82
  "",
76
83
  "Global options:",
77
84
  " -h, --help Show this help message.",
@@ -282,6 +289,31 @@ async function runCheck(args) {
282
289
  return 0;
283
290
  }
284
291
  /* -------------------------------------------------------------------------- */
292
+ /* flux view */
293
+ /* -------------------------------------------------------------------------- */
294
+ async function runView(args) {
295
+ if (args.length === 0) {
296
+ console.error("flux view: No input file specified.");
297
+ return 1;
298
+ }
299
+ const docPath = path.resolve(args[0]);
300
+ try {
301
+ const source = await fs.readFile(docPath, "utf8");
302
+ const doc = parseDocument(source);
303
+ const runtime = createRuntime(doc, { clock: "manual" });
304
+ const labels = new Map();
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;
310
+ }
311
+ catch (error) {
312
+ console.error(`flux view: ${String(error?.message ?? error)}`);
313
+ return 1;
314
+ }
315
+ }
316
+ /* -------------------------------------------------------------------------- */
285
317
  /* I/O + errors */
286
318
  /* -------------------------------------------------------------------------- */
287
319
  async function readSource(file) {
@@ -0,0 +1,67 @@
1
+ import readline from "node:readline";
2
+ import path from "node:path";
3
+ export async function runViewer(runtime, options) {
4
+ const materialLabels = options.materialLabels ?? new Map();
5
+ let snapshot = runtime.getSnapshot();
6
+ const redraw = (snap) => {
7
+ const grid = snap.grids[0];
8
+ const headerTitle = options.title ? `${options.title} (${path.basename(options.docPath)})` : options.docPath;
9
+ process.stdout.write("\x1Bc");
10
+ console.log(headerTitle);
11
+ if (grid) {
12
+ console.log(`docstep ${snap.docstep} · grid ${grid.name}`);
13
+ }
14
+ else {
15
+ console.log(`docstep ${snap.docstep}`);
16
+ }
17
+ const paramsStr = Object.entries(snap.params)
18
+ .map(([k, v]) => `${k}: ${v}`)
19
+ .join(", ");
20
+ console.log(`params: { ${paramsStr} }`);
21
+ console.log("");
22
+ if (grid) {
23
+ for (let r = 0; r < grid.rows; r++) {
24
+ const rowCells = grid.cells.filter((cell) => cell.row === r);
25
+ const line = rowCells
26
+ .map((cell) => formatCell(cell.content, materialLabels))
27
+ .map((text) => text.padEnd(6, " "))
28
+ .join(" ");
29
+ console.log(` ${line}`);
30
+ }
31
+ }
32
+ console.log("");
33
+ console.log("[Enter/space] step · [q] quit");
34
+ };
35
+ redraw(snapshot);
36
+ readline.emitKeypressEvents(process.stdin);
37
+ if (process.stdin.isTTY) {
38
+ process.stdin.setRawMode(true);
39
+ }
40
+ await new Promise((resolve) => {
41
+ const onKeypress = (_, key) => {
42
+ if (key.name === "q" || (key.ctrl && key.name === "c")) {
43
+ cleanup();
44
+ resolve();
45
+ return;
46
+ }
47
+ if (key.name === "return" || key.name === "enter" || key.name === "space") {
48
+ const { snapshot: next } = runtime.stepDocstep();
49
+ snapshot = next;
50
+ redraw(snapshot);
51
+ }
52
+ };
53
+ const cleanup = () => {
54
+ process.stdin.off("keypress", onKeypress);
55
+ if (process.stdin.isTTY) {
56
+ process.stdin.setRawMode(false);
57
+ }
58
+ };
59
+ process.stdin.on("keypress", onKeypress);
60
+ });
61
+ }
62
+ function formatCell(content, labels) {
63
+ if (!content)
64
+ return ".";
65
+ const label = labels.get(content) ?? content;
66
+ return label.slice(0, 6);
67
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flux-lang/cli",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "CLI tooling for the Flux score language",
5
5
  "license": "MIT",
6
6
  "author": "Sebastian Suarez-Solis",
@@ -14,8 +14,7 @@
14
14
  },
15
15
  "files": [
16
16
  "dist",
17
- "README.md",
18
- "LICENSE"
17
+ "README.md"
19
18
  ],
20
19
  "scripts": {
21
20
  "build": "tsc -p tsconfig.json",
@@ -25,7 +24,7 @@
25
24
  "prepublishOnly": "npm run build && chmod +x dist/bin/flux.js"
26
25
  },
27
26
  "dependencies": {
28
- "@flux-lang/core": "0.1.0"
27
+ "@flux-lang/core": "0.1.1"
29
28
  },
30
29
  "devDependencies": {
31
30
  "execa": "^8.0.0",