@danielsimonjr/mathts-workbook 0.4.13 → 0.5.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.md +44 -17
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +21 -337
- package/dist/{formatter-8ja3r-YP.js → formatter-Dwrza-un.js} +18 -9
- package/dist/graph.d.ts +6 -0
- package/dist/graph.d.ts.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/run-worker.js +1 -1
- package/dist/tex.d.ts +9 -1
- package/dist/tex.d.ts.map +1 -1
- package/dist/{timeout-runner-5b5WJXJi.js → timeout-runner-C249B3OS.js} +308 -3
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -20,6 +20,7 @@ mtsw run example.mtsw -v # also print the execution event stream
|
|
|
20
20
|
mtsw run example.mtsw --json # machine-readable envelope on stdout
|
|
21
21
|
mtsw run example.mtsw -c gauss # run one cell + its transitive deps (stateless)
|
|
22
22
|
mtsw run example.mtsw --timeout 5000 # run in a worker; killed (exit 1) if it exceeds 5s
|
|
23
|
+
mtsw run example.mtsw --expect-hash <sha256> # refuse unless file SHA-256 matches
|
|
23
24
|
|
|
24
25
|
# Describe the structured document model (cells, outputs, dependency graph).
|
|
25
26
|
mtsw describe example.mtsw --json
|
|
@@ -30,6 +31,7 @@ mtsw validate example.mtsw [--json]
|
|
|
30
31
|
# Print the dependency graph (human only; use `describe --json` for structured data).
|
|
31
32
|
mtsw graph example.mtsw # text adjacency
|
|
32
33
|
mtsw graph example.mtsw -f mermaid # Mermaid `graph TD`
|
|
34
|
+
mtsw graph example.mtsw -f dot # Graphviz `digraph deps { ... }`
|
|
33
35
|
|
|
34
36
|
# Engine introspection (for tooling / GUIs).
|
|
35
37
|
mtsw capabilities --json # version, supported cell types, feature flags
|
|
@@ -72,6 +74,7 @@ mtsw import doc.json --json # validates (ids/deps/cycles); stdout
|
|
|
72
74
|
# Render to a self-contained HTML document (runs first, then renders).
|
|
73
75
|
mtsw export example.mtsw -o example.html # one offline file; stdout if no -o
|
|
74
76
|
mtsw export example.mtsw --no-run # render cached outputs without executing
|
|
77
|
+
mtsw export example.mtsw --format tex --fragment -o body.tex # TeX body only (no preamble)
|
|
75
78
|
mtsw export example.mtsw --json # envelope: { data: { path, bytes } }
|
|
76
79
|
|
|
77
80
|
# Other export formats: --format tex|pdf|json|ipynb (html is the default).
|
|
@@ -79,20 +82,40 @@ mtsw export example.mtsw --format ipynb -o example.ipynb # Jupyter notebook (n
|
|
|
79
82
|
|
|
80
83
|
# Persistent session for a GUI/tooling: JSON-RPC 2.0 over stdio (NDJSON).
|
|
81
84
|
mtsw serve
|
|
85
|
+
# then JSON-RPC method "open" with params.path — the CLI ignores a file operand
|
|
82
86
|
# -> {"jsonrpc":"2.0","id":1,"method":"open","params":{"path":"example.mtsw"}}
|
|
83
87
|
# <- {"jsonrpc":"2.0","id":1,"result":{...describe doc...}}
|
|
84
88
|
# -> {"jsonrpc":"2.0","id":2,"method":"run"} # streams cell/event notifications
|
|
85
89
|
# methods: open/describe/validate/graph/run/cell.*/meta.*/save/capabilities/functions/shutdown
|
|
86
90
|
```
|
|
87
91
|
|
|
92
|
+
**`export --format tex` (programmatic).** The same `RenderDoc` the CLI builds for TeX
|
|
93
|
+
export is available as `toTeX` from the package entry (with `RenderDoc`, `RenderCell`,
|
|
94
|
+
and `ToTexOptions`). A fragment omits the LaTeX preamble — the same shape as
|
|
95
|
+
`mtsw export … --format tex --fragment`:
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
import { toTeX } from '@danielsimonjr/mathts-workbook';
|
|
99
|
+
|
|
100
|
+
const body = toTeX(
|
|
101
|
+
{ title: 'Notes', cells: [{ type: 'markdown', content: 'Energy $E=mc^2$' }] },
|
|
102
|
+
{ fragment: true }
|
|
103
|
+
);
|
|
104
|
+
// → markdown cell text only; no \\documentclass
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Use `buildDependencyGraph` + `toDOT` when you need Graphviz DOT instead of Mermaid
|
|
108
|
+
(`mtsw graph -f dot`).
|
|
109
|
+
|
|
88
110
|
**`export` (self-contained HTML).** `mtsw export <file> --format html` renders a
|
|
89
111
|
notebook to a single offline `.html` with **no external requests**: markdown prose,
|
|
90
112
|
**equations typeset as MathML** (rendered natively by modern browsers — Chromium ≥109,
|
|
91
113
|
Firefox, Safari), code cells with their embedded outputs, ✓/✗ test badges, and (as of
|
|
92
|
-
the chart slice) inline SVG plots.
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
114
|
+
the chart slice) inline SVG plots. Per-node `.toMathML()` / `.toTex()` / `.toHTML()`
|
|
115
|
+
and `mathMLDocument` come from `@danielsimonjr/mathts-expression`; the workbook
|
|
116
|
+
runtime assembles full HTML with `toHTML` / `toCSS` / `markdownToHtml` / `renderChart`
|
|
117
|
+
(workbook modules used by the CLI — not on the workbook package entry except
|
|
118
|
+
`mathMLToSVG`). Equation cells contain MathTS expression syntax (e.g.
|
|
96
119
|
`c = 1 / sqrt(eps0 * mu0)`), not raw LaTeX; they are display-only and rendered via
|
|
97
120
|
`toMathML`. By default `export` runs the workbook first (use `--no-run` for cached
|
|
98
121
|
outputs); a whole-run failure such as a dependency cycle fails loudly rather than
|
|
@@ -121,7 +144,7 @@ matrices, …) don't survive the worker's `postMessage`.
|
|
|
121
144
|
|
|
122
145
|
**`serve` (persistent session).** One long-lived process holds the workbook in memory with a per-cell result cache and a **stale set**: a `cell.*` edit marks that cell and its transitive dependents stale, and a `run` re-executes **only** the stale cells (reusing cached outputs for the rest) — the incremental latency win a GUI needs. Requests are processed strictly in order; `run` streams `cell/event` notifications (flushed before that run's response in v1, not mid-run). Edits stay in memory until `save`. Single-document per process; concurrent writers are last-write-wins.
|
|
123
146
|
|
|
124
|
-
**Editing notes.** Cell edits are validity-preserving: an op that would create a duplicate/invalid id, a missing dependency, or a **dependency cycle** is rejected and the file is left byte-for-byte unchanged. Editing a cell clears its (now-stale) persisted output; `--at N` is the cell's final 0-based index; `--force` detaches dependents (clearing their outputs) but does not rewrite cell _content_, so a dependent that still references the removed id by name will error at run. Concurrent editors are last-write-wins (
|
|
147
|
+
**Editing notes.** Cell edits are validity-preserving: an op that would create a duplicate/invalid id, a missing dependency, or a **dependency cycle** is rejected and the file is left byte-for-byte unchanged. Editing a cell clears its (now-stale) persisted output; `--at N` is the cell's final 0-based index; `--force` detaches dependents (clearing their outputs) but does not rewrite cell _content_, so a dependent that still references the removed id by name will error at run. Concurrent editors are last-write-wins in `serve` (last accepted `cell.*` op wins; use `save` to persist).
|
|
125
148
|
|
|
126
149
|
Diagnostics and errors are written to stderr; results (including `--json`) go to stdout, so the exit code can be used in scripts independently of the output.
|
|
127
150
|
|
|
@@ -133,8 +156,8 @@ should read `ok` and treat a missing/unparseable envelope as the only transport
|
|
|
133
156
|
error. Compatibility rule: ignore unknown fields when `major` matches; refuse on
|
|
134
157
|
a `major` mismatch. `run --cell <id>` is stateless (it recomputes the target's
|
|
135
158
|
transitive deps each call; `run --cell --write` persists only the executed
|
|
136
|
-
cells).
|
|
137
|
-
|
|
159
|
+
cells). Stateful editing and incremental re-execution live in `mtsw serve` (see
|
|
160
|
+
above); one-shot commands use this envelope only.
|
|
138
161
|
|
|
139
162
|
**Saving / round-trip.** `serializeWorkbook` (and the write commands above) round-trips a workbook through the parser: structure is preserved exactly, and persisted `output` values round-trip best-effort (plain numbers/strings/arrays/objects exactly; exotic types to their plain shape). All writes are **atomic** (temp file + rename). Note that any write path is parse→serialize and therefore **drops YAML comments and re-orders keys** — a CST-preserving in-place rewrite is a future enhancement.
|
|
140
163
|
|
|
@@ -224,19 +247,23 @@ A `test` cell's expression must evaluate to a **boolean**: `true` passes, `false
|
|
|
224
247
|
|
|
225
248
|
## Cell types (v1)
|
|
226
249
|
|
|
227
|
-
| Type
|
|
228
|
-
|
|
|
229
|
-
| `markdown`
|
|
230
|
-
| `code`
|
|
231
|
-
| `data`
|
|
232
|
-
| `test`
|
|
233
|
-
| `
|
|
250
|
+
| Type | Status | Description |
|
|
251
|
+
| --------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
252
|
+
| `markdown` | ✅ | Documentation (passed through verbatim) |
|
|
253
|
+
| `code` | ✅ | MathTS expression script; last value is the result |
|
|
254
|
+
| `data` | ✅ | Structured YAML, parsed (hardened) into a value |
|
|
255
|
+
| `test` | ✅ | Boolean assertion (`true` = pass) |
|
|
256
|
+
| `equation` | ✅ | MathTS expression syntax; display-only (content echoed, not evaluated) |
|
|
257
|
+
| `visualization` | ✅ | Chart/visual spec; display-only (content echoed, not evaluated) |
|
|
258
|
+
| `tensor` | ⏳ | Deferred — parse fails: `type 'tensor' is reserved but not yet supported (supported: code, markdown, data, test, equation, visualization)` |
|
|
259
|
+
| `export` | ⏳ | Same as `tensor` (`export` is reserved; not in the supported list) |
|
|
234
260
|
|
|
235
261
|
## Execution modes
|
|
236
262
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
- **manual**
|
|
263
|
+
All modes execute cells in dependency order (`graph.executionOrder`). The only
|
|
264
|
+
runtime difference is **reactive**, which emits `cell:stale` for dependents when a
|
|
265
|
+
cell is edited or re-run. **Sequential** and **manual** use the same execution order
|
|
266
|
+
without stale events (both still run the full graph on `run` / `runReport`).
|
|
240
267
|
|
|
241
268
|
## Security
|
|
242
269
|
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG;AAsCH;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG;AAsCH;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AA8OD;;;;;;;;;;;;GAYG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,aAAa,CAAC,CAqHvE;AAqDD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,aAAa,CAoC7D;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,aAAa,CA+C7D;AAkBD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,aAAa,CASjE;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,aAAa,CAO9D;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,aAAa,CAO9D;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,aAAa,CA2DzD;AAoFD;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,aAAa,CAAC,CA8H1E;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CACvB,KAAK,GAAE,MAAM,CAAC,cAA8B,EAC5C,MAAM,GAAE,MAAM,CAAC,cAA+B,GAC7C,OAAO,CAAC,IAAI,CAAC,CAuEf;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,aAAa,CAAC,CAG3D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,aAAa,CAsC1D;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,aAAa,CA0B1D;AAuDD;;;;;;;;;;;;GAYG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,aAAa,CAqFxD;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,aAAa,CAiD3D;AAyED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,aAAa,CA4HzD;AAED;;GAEG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,aAAa,CAAC,CAuDrE"}
|
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { c as parseWorkbook, d as buildDependencyGraph, f as detectCycles, g as toMermaid, h as toDOT, l as serializeWorkbook, o as importWorkbook, r as createExecutor, t as formatResult, u as stripOutputs, v as parseYamlSafe } from "./formatter-
|
|
3
|
-
import { a as capabilitiesInfo, c as writeFileAtomic, d as addCell, f as editCell, g as setMetadata, h as renameCell, i as describeData, l as SCHEMA_VERSION, m as removeCell, n as runWorkbookWithTimeout, o as listFunctions, p as moveCell, r as handleRequest, s as Session, u as VERSION } from "./timeout-runner-
|
|
2
|
+
import { c as parseWorkbook, d as buildDependencyGraph, f as detectCycles, g as toMermaid, h as toDOT, l as serializeWorkbook, o as importWorkbook, r as createExecutor, t as formatResult, u as stripOutputs, v as parseYamlSafe } from "./formatter-Dwrza-un.js";
|
|
3
|
+
import { _ as toTeX, a as capabilitiesInfo, c as writeFileAtomic, d as addCell, f as editCell, g as setMetadata, h as renameCell, i as describeData, l as SCHEMA_VERSION, m as removeCell, n as runWorkbookWithTimeout, o as listFunctions, p as moveCell, r as handleRequest, s as Session, u as VERSION, v as markdownToHtml, y as renderChart } from "./timeout-runner-C249B3OS.js";
|
|
4
4
|
import * as mathFunctions from "@danielsimonjr/mathts-functions";
|
|
5
5
|
import { lstatSync, readFileSync, realpathSync, writeFileSync } from "node:fs";
|
|
6
6
|
import { createHash } from "node:crypto";
|
|
@@ -8,253 +8,7 @@ import { pathToFileURL } from "node:url";
|
|
|
8
8
|
import { basename } from "node:path";
|
|
9
9
|
import { createInterface } from "node:readline";
|
|
10
10
|
import { mathMLDocument, mathMLError } from "@danielsimonjr/mathts-expression";
|
|
11
|
-
import { bar, line, scatter } from "@danielsimonjr/mathts-plot";
|
|
12
11
|
import { latexToPdf } from "@danielsimonjr/mathts-plot/render";
|
|
13
|
-
//#region src/markdown.ts
|
|
14
|
-
function esc$1(s) {
|
|
15
|
-
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
16
|
-
}
|
|
17
|
-
function sanitizeHrefRaw(href) {
|
|
18
|
-
const h = href.trim();
|
|
19
|
-
let probe = h.replace(/&/g, "&");
|
|
20
|
-
try {
|
|
21
|
-
probe = decodeURIComponent(probe);
|
|
22
|
-
} catch {}
|
|
23
|
-
if (probe.startsWith("//")) return null;
|
|
24
|
-
try {
|
|
25
|
-
const url = new URL(probe);
|
|
26
|
-
if (url.protocol === "http:" || url.protocol === "https:" || url.protocol === "mailto:") return h;
|
|
27
|
-
return null;
|
|
28
|
-
} catch {
|
|
29
|
-
if (probe.startsWith("/") || probe.startsWith("./") || probe.startsWith("../") || probe.startsWith("#")) return h;
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
function sanitizeHref(href) {
|
|
34
|
-
const raw = sanitizeHrefRaw(href);
|
|
35
|
-
return raw === null ? null : raw.replace(/"/g, """);
|
|
36
|
-
}
|
|
37
|
-
function inline(escaped) {
|
|
38
|
-
let s = escaped.replace(/`([^`]+)`/g, (_m, code) => `<code>${code}</code>`);
|
|
39
|
-
s = s.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>");
|
|
40
|
-
s = s.replace(/\*([^*]+)\*/g, "<em>$1</em>");
|
|
41
|
-
s = s.replace(/\[([^\]]*)\]\(([^)\s]+)\)/g, (_m, text, href) => {
|
|
42
|
-
const safe = sanitizeHref(href);
|
|
43
|
-
return safe ? `<a href="${safe}">${text}</a>` : text;
|
|
44
|
-
});
|
|
45
|
-
return s;
|
|
46
|
-
}
|
|
47
|
-
const HR = /^ {0,3}(-{3,}|\*{3,}|_{3,})\s*$/;
|
|
48
|
-
const HEADING = /^(#{1,6})\s+(.*)$/;
|
|
49
|
-
const UL = /^\s*[-*+]\s+/;
|
|
50
|
-
const OL = /^\s*\d+\.\s+/;
|
|
51
|
-
function isBlockStart(line) {
|
|
52
|
-
return line.trim() === "" || /^```/.test(line.trim()) || HEADING.test(line) || UL.test(line) || OL.test(line) || HR.test(line);
|
|
53
|
-
}
|
|
54
|
-
function markdownToHtml(src) {
|
|
55
|
-
if (!src) return "";
|
|
56
|
-
const lines = src.replace(/\r\n?/g, "\n").split("\n");
|
|
57
|
-
const out = [];
|
|
58
|
-
let i = 0;
|
|
59
|
-
while (i < lines.length) {
|
|
60
|
-
const line = lines[i];
|
|
61
|
-
if (/^```/.test(line.trim())) {
|
|
62
|
-
const buf = [];
|
|
63
|
-
i++;
|
|
64
|
-
while (i < lines.length && !/^```/.test(lines[i].trim())) {
|
|
65
|
-
buf.push(lines[i]);
|
|
66
|
-
i++;
|
|
67
|
-
}
|
|
68
|
-
i++;
|
|
69
|
-
out.push(`<pre><code>${esc$1(buf.join("\n"))}</code></pre>`);
|
|
70
|
-
continue;
|
|
71
|
-
}
|
|
72
|
-
if (line.trim() === "") {
|
|
73
|
-
i++;
|
|
74
|
-
continue;
|
|
75
|
-
}
|
|
76
|
-
if (HR.test(line)) {
|
|
77
|
-
out.push("<hr>");
|
|
78
|
-
i++;
|
|
79
|
-
continue;
|
|
80
|
-
}
|
|
81
|
-
const h = HEADING.exec(line);
|
|
82
|
-
if (h) {
|
|
83
|
-
const lvl = h[1].length;
|
|
84
|
-
out.push(`<h${lvl}>${inline(esc$1(h[2].trim()))}</h${lvl}>`);
|
|
85
|
-
i++;
|
|
86
|
-
continue;
|
|
87
|
-
}
|
|
88
|
-
if (UL.test(line)) {
|
|
89
|
-
const items = [];
|
|
90
|
-
while (i < lines.length && UL.test(lines[i])) {
|
|
91
|
-
items.push(`<li>${inline(esc$1(lines[i].replace(UL, "")))}</li>`);
|
|
92
|
-
i++;
|
|
93
|
-
}
|
|
94
|
-
out.push(`<ul>${items.join("")}</ul>`);
|
|
95
|
-
continue;
|
|
96
|
-
}
|
|
97
|
-
if (OL.test(line)) {
|
|
98
|
-
const items = [];
|
|
99
|
-
while (i < lines.length && OL.test(lines[i])) {
|
|
100
|
-
items.push(`<li>${inline(esc$1(lines[i].replace(OL, "")))}</li>`);
|
|
101
|
-
i++;
|
|
102
|
-
}
|
|
103
|
-
out.push(`<ol>${items.join("")}</ol>`);
|
|
104
|
-
continue;
|
|
105
|
-
}
|
|
106
|
-
const para = [];
|
|
107
|
-
while (i < lines.length && !isBlockStart(lines[i])) {
|
|
108
|
-
para.push(lines[i]);
|
|
109
|
-
i++;
|
|
110
|
-
}
|
|
111
|
-
out.push(`<p>${inline(esc$1(para.join(" ")))}</p>`);
|
|
112
|
-
}
|
|
113
|
-
return out.join("\n");
|
|
114
|
-
}
|
|
115
|
-
function texEscape(s) {
|
|
116
|
-
return s.replace(/[\\&%$#_{}~^]/g, (c) => {
|
|
117
|
-
switch (c) {
|
|
118
|
-
case "\\": return "\\textbackslash{}";
|
|
119
|
-
case "~": return "\\textasciitilde{}";
|
|
120
|
-
case "^": return "\\textasciicircum{}";
|
|
121
|
-
default: return `\\${c}`;
|
|
122
|
-
}
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
function verbatimBody(body, env) {
|
|
126
|
-
return body.split(`\\end{${env}}`).join(`\\end {${env}}`);
|
|
127
|
-
}
|
|
128
|
-
function escapeInlineNonLink(text) {
|
|
129
|
-
let s = texEscape(text);
|
|
130
|
-
s = s.replace(/`([^`]+)`/g, (_m, code) => `\\texttt{${code}}`);
|
|
131
|
-
s = s.replace(/\*\*([^*]+)\*\*/g, "\\textbf{$1}");
|
|
132
|
-
s = s.replace(/\*([^*]+)\*/g, "\\emph{$1}");
|
|
133
|
-
return s;
|
|
134
|
-
}
|
|
135
|
-
function inlineTex(text) {
|
|
136
|
-
const linkRe = /\[([^\]]*)\]\(([^)\s]+)\)/g;
|
|
137
|
-
let out = "";
|
|
138
|
-
let last = 0;
|
|
139
|
-
let m;
|
|
140
|
-
while ((m = linkRe.exec(text)) !== null) {
|
|
141
|
-
out += escapeInlineNonLink(text.slice(last, m.index));
|
|
142
|
-
const raw = sanitizeHrefRaw(m[2]);
|
|
143
|
-
out += raw ? `\\href{${texEscape(raw)}}{${escapeInlineNonLink(m[1])}}` : escapeInlineNonLink(m[1]);
|
|
144
|
-
last = linkRe.lastIndex;
|
|
145
|
-
}
|
|
146
|
-
out += escapeInlineNonLink(text.slice(last));
|
|
147
|
-
return out;
|
|
148
|
-
}
|
|
149
|
-
function markdownToTex(src) {
|
|
150
|
-
if (!src) return "";
|
|
151
|
-
const lines = src.replace(/\r\n?/g, "\n").split("\n");
|
|
152
|
-
const out = [];
|
|
153
|
-
let i = 0;
|
|
154
|
-
const SEC = [
|
|
155
|
-
"\\section*",
|
|
156
|
-
"\\subsection*",
|
|
157
|
-
"\\subsubsection*",
|
|
158
|
-
"\\paragraph"
|
|
159
|
-
];
|
|
160
|
-
while (i < lines.length) {
|
|
161
|
-
const line = lines[i];
|
|
162
|
-
if (/^```/.test(line.trim())) {
|
|
163
|
-
const buf = [];
|
|
164
|
-
i++;
|
|
165
|
-
while (i < lines.length && !/^```/.test(lines[i].trim())) {
|
|
166
|
-
buf.push(lines[i]);
|
|
167
|
-
i++;
|
|
168
|
-
}
|
|
169
|
-
i++;
|
|
170
|
-
out.push(`\\begin{lstlisting}\n${verbatimBody(buf.join("\n"), "lstlisting")}\n\\end{lstlisting}`);
|
|
171
|
-
continue;
|
|
172
|
-
}
|
|
173
|
-
if (line.trim() === "") {
|
|
174
|
-
i++;
|
|
175
|
-
continue;
|
|
176
|
-
}
|
|
177
|
-
if (HR.test(line)) {
|
|
178
|
-
out.push("\\par\\noindent\\rule{\\linewidth}{0.4pt}\\par");
|
|
179
|
-
i++;
|
|
180
|
-
continue;
|
|
181
|
-
}
|
|
182
|
-
const h = HEADING.exec(line);
|
|
183
|
-
if (h) {
|
|
184
|
-
const lvl = Math.min(h[1].length, 4);
|
|
185
|
-
out.push(`${SEC[lvl - 1]}{${inlineTex(h[2].trim())}}`);
|
|
186
|
-
i++;
|
|
187
|
-
continue;
|
|
188
|
-
}
|
|
189
|
-
if (UL.test(line)) {
|
|
190
|
-
const items = [];
|
|
191
|
-
while (i < lines.length && UL.test(lines[i])) {
|
|
192
|
-
items.push(` \\item ${inlineTex(lines[i].replace(UL, ""))}`);
|
|
193
|
-
i++;
|
|
194
|
-
}
|
|
195
|
-
out.push(`\\begin{itemize}\n${items.join("\n")}\n\\end{itemize}`);
|
|
196
|
-
continue;
|
|
197
|
-
}
|
|
198
|
-
if (OL.test(line)) {
|
|
199
|
-
const items = [];
|
|
200
|
-
while (i < lines.length && OL.test(lines[i])) {
|
|
201
|
-
items.push(` \\item ${inlineTex(lines[i].replace(OL, ""))}`);
|
|
202
|
-
i++;
|
|
203
|
-
}
|
|
204
|
-
out.push(`\\begin{enumerate}\n${items.join("\n")}\n\\end{enumerate}`);
|
|
205
|
-
continue;
|
|
206
|
-
}
|
|
207
|
-
const para = [];
|
|
208
|
-
while (i < lines.length && !isBlockStart(lines[i])) {
|
|
209
|
-
para.push(lines[i]);
|
|
210
|
-
i++;
|
|
211
|
-
}
|
|
212
|
-
out.push(inlineTex(para.join(" ")));
|
|
213
|
-
}
|
|
214
|
-
return out.join("\n\n");
|
|
215
|
-
}
|
|
216
|
-
//#endregion
|
|
217
|
-
//#region src/svg.ts
|
|
218
|
-
function coerce(v) {
|
|
219
|
-
if (typeof v === "number") return v;
|
|
220
|
-
if (typeof v === "bigint") return Number(v);
|
|
221
|
-
const u = v;
|
|
222
|
-
if (u && typeof u.toNumeric === "function") try {
|
|
223
|
-
return Number(u.toNumeric());
|
|
224
|
-
} catch {
|
|
225
|
-
return NaN;
|
|
226
|
-
}
|
|
227
|
-
return Number(v);
|
|
228
|
-
}
|
|
229
|
-
function toNums(raw) {
|
|
230
|
-
let arr = raw;
|
|
231
|
-
const m = raw;
|
|
232
|
-
if (m && typeof m.toArray === "function") try {
|
|
233
|
-
arr = m.toArray();
|
|
234
|
-
} catch {
|
|
235
|
-
arr = raw;
|
|
236
|
-
}
|
|
237
|
-
return Array.isArray(arr) ? arr.flat(Infinity).map(coerce) : [];
|
|
238
|
-
}
|
|
239
|
-
function renderChart(spec, xRaw, yRaw, format = "svg") {
|
|
240
|
-
const xs = toNums(xRaw);
|
|
241
|
-
const ys = toNums(yRaw);
|
|
242
|
-
const opts = format === "tikz" ? {
|
|
243
|
-
title: spec.title,
|
|
244
|
-
xLabel: spec.xLabel,
|
|
245
|
-
yLabel: spec.yLabel,
|
|
246
|
-
format: "tikz",
|
|
247
|
-
tikz: { standalone: false }
|
|
248
|
-
} : {
|
|
249
|
-
title: spec.title,
|
|
250
|
-
xLabel: spec.xLabel,
|
|
251
|
-
yLabel: spec.yLabel
|
|
252
|
-
};
|
|
253
|
-
if (spec.type === "scatter") return scatter(xs, ys, opts);
|
|
254
|
-
if (spec.type === "bar") return bar(xs, ys, opts);
|
|
255
|
-
return line(xs, ys, opts);
|
|
256
|
-
}
|
|
257
|
-
//#endregion
|
|
258
12
|
//#region src/html.ts
|
|
259
13
|
function esc(s) {
|
|
260
14
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
@@ -366,65 +120,6 @@ function toHTML(doc, options = {}) {
|
|
|
366
120
|
].join("\n");
|
|
367
121
|
}
|
|
368
122
|
//#endregion
|
|
369
|
-
//#region src/tex.ts
|
|
370
|
-
const PREAMBLE = [
|
|
371
|
-
"\\documentclass{article}",
|
|
372
|
-
"\\usepackage{amsmath}",
|
|
373
|
-
"\\usepackage{tikz}",
|
|
374
|
-
"\\usepackage{listings}",
|
|
375
|
-
"\\usepackage{xcolor}",
|
|
376
|
-
"\\usepackage[margin=1in]{geometry}",
|
|
377
|
-
"\\usepackage{hyperref}"
|
|
378
|
-
].join("\n");
|
|
379
|
-
function renderEquationTex(content, parse) {
|
|
380
|
-
if (parse) try {
|
|
381
|
-
return `\\[ ${parse(content).toTex()} \\]`;
|
|
382
|
-
} catch {}
|
|
383
|
-
return `\\texttt{${texEscape(content)}}`;
|
|
384
|
-
}
|
|
385
|
-
function renderCellTex(cell, parse) {
|
|
386
|
-
switch (cell.type) {
|
|
387
|
-
case "markdown": return markdownToTex(cell.content);
|
|
388
|
-
case "equation": return renderEquationTex(cell.content, parse);
|
|
389
|
-
case "code": {
|
|
390
|
-
const cap = cell.id ? `\\textit{${texEscape(cell.id)}}\\\\\n` : "";
|
|
391
|
-
const src = `\\begin{lstlisting}\n${verbatimBody(cell.content, "lstlisting")}\n\\end{lstlisting}`;
|
|
392
|
-
let res = "";
|
|
393
|
-
if (cell.error !== void 0) res = `\n\n\\textcolor{red}{\\texttt{${texEscape(cell.error)}}}`;
|
|
394
|
-
else if (cell.output !== void 0) res = `\n\n\\begin{verbatim}\n${verbatimBody(cell.output, "verbatim")}\n\\end{verbatim}`;
|
|
395
|
-
return `${cap}${src}${res}`;
|
|
396
|
-
}
|
|
397
|
-
case "test": {
|
|
398
|
-
const label = `\\texttt{${texEscape(cell.content)}}`;
|
|
399
|
-
if (cell.error !== void 0) return `\\textcolor{orange}{[ERROR]} ${label} --- ${texEscape(cell.error)}`;
|
|
400
|
-
if (cell.passed === true) return `\\textcolor{green!60!black}{[PASS]} ${label}`;
|
|
401
|
-
if (cell.passed === false) return `\\textcolor{red}{[FAIL]} ${label}`;
|
|
402
|
-
return `\\textcolor{gray}{[NOT RUN]} ${label}`;
|
|
403
|
-
}
|
|
404
|
-
case "data": {
|
|
405
|
-
const val = cell.error !== void 0 ? cell.error : cell.output ?? "";
|
|
406
|
-
return `${cell.id ? `\\textit{${texEscape(cell.id)}}\\\\\n` : ""}\\begin{verbatim}\n${verbatimBody(val, "verbatim")}\n\\end{verbatim}`;
|
|
407
|
-
}
|
|
408
|
-
case "chart": return `\\begin{center}\n${cell.chart ? renderChart(cell.chart.spec, cell.chart.x, cell.chart.y, "tikz") : "% no chart"}\n\\end{center}${cell.note ? `\n\n\\textit{${texEscape(cell.note)}}` : ""}`;
|
|
409
|
-
default: return `\\begin{verbatim}\n${verbatimBody(cell.content, "verbatim")}\n\\end{verbatim}`;
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
function toTeX(doc, options = {}) {
|
|
413
|
-
const body = doc.cells.map((c) => renderCellTex(c, options.parse)).join("\n\n");
|
|
414
|
-
if (options.fragment) return body;
|
|
415
|
-
const meta = [];
|
|
416
|
-
if (doc.title) meta.push(`\\title{${texEscape(doc.title)}}`);
|
|
417
|
-
if (doc.author) meta.push(`\\author{${texEscape(doc.author)}}`);
|
|
418
|
-
const maketitle = doc.title ? "\\maketitle\n" : "";
|
|
419
|
-
return [
|
|
420
|
-
PREAMBLE,
|
|
421
|
-
...meta,
|
|
422
|
-
"\\begin{document}",
|
|
423
|
-
`${maketitle}${body}`,
|
|
424
|
-
"\\end{document}"
|
|
425
|
-
].join("\n");
|
|
426
|
-
}
|
|
427
|
-
//#endregion
|
|
428
123
|
//#region src/pdf.ts
|
|
429
124
|
function toPDF(doc, outPath, options = {}) {
|
|
430
125
|
const { parse, ...renderOpts } = options;
|
|
@@ -595,7 +290,10 @@ function jsonEnvelope(command, ok, data, problems = []) {
|
|
|
595
290
|
return value;
|
|
596
291
|
};
|
|
597
292
|
return JSON.stringify({
|
|
598
|
-
schemaVersion:
|
|
293
|
+
schemaVersion: {
|
|
294
|
+
major: SCHEMA_VERSION.major,
|
|
295
|
+
minor: SCHEMA_VERSION.minor
|
|
296
|
+
},
|
|
599
297
|
command,
|
|
600
298
|
ok,
|
|
601
299
|
data,
|
|
@@ -934,52 +632,38 @@ function describeCommand(args) {
|
|
|
934
632
|
exitCode: ok ? 0 : 1
|
|
935
633
|
};
|
|
936
634
|
}
|
|
937
|
-
function
|
|
938
|
-
const data = capabilitiesInfo();
|
|
635
|
+
function renderInfoCommand(args, command, data, lines) {
|
|
939
636
|
if (args.includes("--json")) return {
|
|
940
|
-
stdout: jsonEnvelope(
|
|
637
|
+
stdout: jsonEnvelope(command, true, data, []),
|
|
941
638
|
stderr: "",
|
|
942
639
|
exitCode: 0
|
|
943
640
|
};
|
|
944
641
|
return {
|
|
945
|
-
stdout:
|
|
946
|
-
`mtsw ${data.version} (schema ${SCHEMA_VERSION.major}.${SCHEMA_VERSION.minor})`,
|
|
947
|
-
`supported cells: ${data.cellTypes.supported.join(", ")}`,
|
|
948
|
-
`deferred cells: ${data.cellTypes.deferred.join(", ")}`,
|
|
949
|
-
`commands: ${data.commands.join(", ")}`
|
|
950
|
-
].join("\n"),
|
|
642
|
+
stdout: lines.join("\n"),
|
|
951
643
|
stderr: "",
|
|
952
644
|
exitCode: 0
|
|
953
645
|
};
|
|
954
646
|
}
|
|
647
|
+
function capabilitiesCommand(args) {
|
|
648
|
+
const data = capabilitiesInfo();
|
|
649
|
+
return renderInfoCommand(args, "capabilities", data, [
|
|
650
|
+
`mtsw ${data.version} (schema ${SCHEMA_VERSION.major}.${SCHEMA_VERSION.minor})`,
|
|
651
|
+
`supported cells: ${data.cellTypes.supported.join(", ")}`,
|
|
652
|
+
`deferred cells: ${data.cellTypes.deferred.join(", ")}`,
|
|
653
|
+
`commands: ${data.commands.join(", ")}`
|
|
654
|
+
]);
|
|
655
|
+
}
|
|
955
656
|
function templatesCommand(args) {
|
|
956
657
|
const templates = Object.entries(TEMPLATES).map(([name, t]) => ({
|
|
957
658
|
name,
|
|
958
659
|
description: t.description
|
|
959
660
|
}));
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
stderr: "",
|
|
963
|
-
exitCode: 0
|
|
964
|
-
};
|
|
965
|
-
return {
|
|
966
|
-
stdout: templates.map((t) => `${t.name} - ${t.description}`).join("\n"),
|
|
967
|
-
stderr: "",
|
|
968
|
-
exitCode: 0
|
|
969
|
-
};
|
|
661
|
+
const lines = templates.map((t) => `${t.name} - ${t.description}`);
|
|
662
|
+
return renderInfoCommand(args, "templates", { templates }, lines);
|
|
970
663
|
}
|
|
971
664
|
function functionsCommand(args) {
|
|
972
665
|
const data = listFunctions();
|
|
973
|
-
|
|
974
|
-
stdout: jsonEnvelope("functions", true, data, []),
|
|
975
|
-
stderr: "",
|
|
976
|
-
exitCode: 0
|
|
977
|
-
};
|
|
978
|
-
return {
|
|
979
|
-
stdout: [`functions (${data.functions.length}): ${data.functions.join(", ")}`, `constants (${data.constants.length}): ${data.constants.join(", ")}`].join("\n"),
|
|
980
|
-
stderr: "",
|
|
981
|
-
exitCode: 0
|
|
982
|
-
};
|
|
666
|
+
return renderInfoCommand(args, "functions", data, [`functions (${data.functions.length}): ${data.functions.join(", ")}`, `constants (${data.constants.length}): ${data.constants.join(", ")}`]);
|
|
983
667
|
}
|
|
984
668
|
function metaCommand(args) {
|
|
985
669
|
const json = args.includes("--json");
|
|
@@ -102,18 +102,27 @@ function getAncestors(graph, id) {
|
|
|
102
102
|
visit(id);
|
|
103
103
|
return graph.executionOrder.filter((nodeId) => result.has(nodeId));
|
|
104
104
|
}
|
|
105
|
-
function
|
|
106
|
-
const lines = [
|
|
107
|
-
for (const id of graph.nodes.keys()) lines.push(
|
|
108
|
-
for (const [id, node] of graph.nodes) for (const dep of node.dependencies) lines.push(
|
|
105
|
+
function renderDependencyGraph(graph, format) {
|
|
106
|
+
const lines = [format.header];
|
|
107
|
+
for (const id of graph.nodes.keys()) lines.push(format.node(id));
|
|
108
|
+
for (const [id, node] of graph.nodes) for (const dep of node.dependencies) lines.push(format.edge(dep, id));
|
|
109
|
+
if (format.footer !== void 0) lines.push(format.footer);
|
|
109
110
|
return lines.join("\n");
|
|
110
111
|
}
|
|
112
|
+
function toMermaid(graph) {
|
|
113
|
+
return renderDependencyGraph(graph, {
|
|
114
|
+
header: "graph TD",
|
|
115
|
+
node: (id) => ` ${id}["${id}"]`,
|
|
116
|
+
edge: (dep, id) => ` ${dep} --> ${id}`
|
|
117
|
+
});
|
|
118
|
+
}
|
|
111
119
|
function toDOT(graph) {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
120
|
+
return renderDependencyGraph(graph, {
|
|
121
|
+
header: "digraph deps {",
|
|
122
|
+
node: (id) => ` ${id} [label="${id}"];`,
|
|
123
|
+
edge: (dep, id) => ` ${dep} -> ${id};`,
|
|
124
|
+
footer: "}"
|
|
125
|
+
});
|
|
117
126
|
}
|
|
118
127
|
function detectCycles(graph) {
|
|
119
128
|
const cycles = [];
|
package/dist/graph.d.ts
CHANGED
|
@@ -32,6 +32,12 @@ export declare function toMermaid(graph: DependencyGraph): string;
|
|
|
32
32
|
* Render the dependency graph as Graphviz DOT (the DOT analog of toMermaid).
|
|
33
33
|
* Cell ids are validated identifiers ([A-Za-z_][A-Za-z0-9_]*), safe verbatim as
|
|
34
34
|
* both node id and quoted label; no cell content appears in the output.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```ts
|
|
38
|
+
* import { buildDependencyGraph, toDOT } from '@danielsimonjr/mathts-workbook';
|
|
39
|
+
* toDOT(buildDependencyGraph(cells)); // digraph deps { … }
|
|
40
|
+
* ```
|
|
35
41
|
*/
|
|
36
42
|
export declare function toDOT(graph: DependencyGraph): string;
|
|
37
43
|
/**
|
package/dist/graph.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../src/graph.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAExE;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,eAAe,CA0BnE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,GAAG,MAAM,EAAE,CAuB5E;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAmB9E;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,eAAe,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAezE;
|
|
1
|
+
{"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../src/graph.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAExE;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,eAAe,CA0BnE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,GAAG,MAAM,EAAE,CAuB5E;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAmB9E;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,eAAe,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAezE;AAkCD;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAMxD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAOpD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,EAAE,EAAE,CAoC/D"}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,11 +2,14 @@
|
|
|
2
2
|
* @danielsimonjr/mathts-workbook - Scientific workbook runtime
|
|
3
3
|
* @packageDocumentation
|
|
4
4
|
*/
|
|
5
|
-
export type { Workbook, Cell, CellType, ExecutionMode, WorkbookMetadata, RuntimeConfig, ParseResult, WorkbookEvent, CellResult, RunResult, } from './types.js';
|
|
5
|
+
export type { Workbook, Cell, CellType, ExecutionMode, WorkbookMetadata, RuntimeConfig, ParseResult, WorkbookEvent, CellResult, RunResult, DependencyNode, DependencyGraph, } from './types.js';
|
|
6
6
|
export { parseWorkbook, serializeWorkbook, stripOutputs, detectCellType } from './parser.js';
|
|
7
|
-
export { buildDependencyGraph, topologicalSort, getDependents, detectCycles, getAncestors, toMermaid, } from './graph.js';
|
|
7
|
+
export { buildDependencyGraph, topologicalSort, getDependents, detectCycles, getAncestors, toMermaid, toDOT, } from './graph.js';
|
|
8
8
|
export { WorkbookExecutor, createExecutor } from './executor.js';
|
|
9
9
|
export { formatResult } from './formatter.js';
|
|
10
|
+
export { toTeX } from './tex.js';
|
|
11
|
+
export type { ToTexOptions } from './tex.js';
|
|
12
|
+
export type { RenderDoc, RenderCell } from './html.js';
|
|
10
13
|
export { addCell, editCell, removeCell, moveCell, renameCell, setMetadata } from './edit.js';
|
|
11
14
|
export type { CellPosition, RemoveResult } from './edit.js';
|
|
12
15
|
export { SCHEMA_VERSION, VERSION } from './contract.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,YAAY,EACV,QAAQ,EACR,IAAI,EACJ,QAAQ,EACR,aAAa,EACb,gBAAgB,EAChB,aAAa,EACb,WAAW,EACX,aAAa,EACb,UAAU,EACV,SAAS,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,YAAY,EACV,QAAQ,EACR,IAAI,EACJ,QAAQ,EACR,aAAa,EACb,gBAAgB,EAChB,aAAa,EACb,WAAW,EACX,aAAa,EACb,UAAU,EACV,SAAS,EACT,cAAc,EACd,eAAe,GAChB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAG7F,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,KAAK,GACN,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAGjE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG9C,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AACjC,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAGvD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7F,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAG5D,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAGxD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAGzC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAGpD,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AACnF,YAAY,EACV,6BAA6B,EAC7B,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,qBAAqB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { _ as topologicalSort, a as detectCellType, c as parseWorkbook, d as buildDependencyGraph, f as detectCycles, g as toMermaid, l as serializeWorkbook, m as getDependents, n as WorkbookExecutor, p as getAncestors, r as createExecutor, t as formatResult, u as stripOutputs } from "./formatter-
|
|
2
|
-
import { d as addCell, f as editCell, g as setMetadata, h as renameCell, l as SCHEMA_VERSION, m as removeCell, n as runWorkbookWithTimeout, p as moveCell, r as handleRequest, s as Session, t as WorkbookTimeoutError, u as VERSION } from "./timeout-runner-
|
|
1
|
+
import { _ as topologicalSort, a as detectCellType, c as parseWorkbook, d as buildDependencyGraph, f as detectCycles, g as toMermaid, h as toDOT, l as serializeWorkbook, m as getDependents, n as WorkbookExecutor, p as getAncestors, r as createExecutor, t as formatResult, u as stripOutputs } from "./formatter-Dwrza-un.js";
|
|
2
|
+
import { _ as toTeX, d as addCell, f as editCell, g as setMetadata, h as renameCell, l as SCHEMA_VERSION, m as removeCell, n as runWorkbookWithTimeout, p as moveCell, r as handleRequest, s as Session, t as WorkbookTimeoutError, u as VERSION } from "./timeout-runner-C249B3OS.js";
|
|
3
3
|
//#region src/svg-math.ts
|
|
4
4
|
function mathMLToSVG(mathml, options = {}) {
|
|
5
5
|
const display = options.display ?? "block";
|
|
@@ -17,4 +17,4 @@ function mathMLToSVG(mathml, options = {}) {
|
|
|
17
17
|
].join("");
|
|
18
18
|
}
|
|
19
19
|
//#endregion
|
|
20
|
-
export { SCHEMA_VERSION, Session, VERSION, WorkbookExecutor, WorkbookTimeoutError, addCell, buildDependencyGraph, createExecutor, detectCellType, detectCycles, editCell, formatResult, getAncestors, getDependents, handleRequest, mathMLToSVG, moveCell, parseWorkbook, removeCell, renameCell, runWorkbookWithTimeout, serializeWorkbook, setMetadata, stripOutputs, toMermaid, topologicalSort };
|
|
20
|
+
export { SCHEMA_VERSION, Session, VERSION, WorkbookExecutor, WorkbookTimeoutError, addCell, buildDependencyGraph, createExecutor, detectCellType, detectCycles, editCell, formatResult, getAncestors, getDependents, handleRequest, mathMLToSVG, moveCell, parseWorkbook, removeCell, renameCell, runWorkbookWithTimeout, serializeWorkbook, setMetadata, stripOutputs, toDOT, toMermaid, toTeX, topologicalSort };
|
package/dist/run-worker.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as parseWorkbook, r as createExecutor, t as formatResult } from "./formatter-
|
|
1
|
+
import { c as parseWorkbook, r as createExecutor, t as formatResult } from "./formatter-Dwrza-un.js";
|
|
2
2
|
import { parentPort, workerData } from "node:worker_threads";
|
|
3
3
|
//#region src/run-worker.ts
|
|
4
4
|
async function main() {
|
package/dist/tex.d.ts
CHANGED
|
@@ -15,6 +15,14 @@ export interface ToTexOptions {
|
|
|
15
15
|
/** Emit only the cell bodies (for \input) instead of a standalone document. */
|
|
16
16
|
fragment?: boolean;
|
|
17
17
|
}
|
|
18
|
-
/**
|
|
18
|
+
/**
|
|
19
|
+
* Render a document structure to a standalone (or fragment) LaTeX string. Never throws.
|
|
20
|
+
*
|
|
21
|
+
* @example Fragment body for `\input` (no preamble):
|
|
22
|
+
* ```ts
|
|
23
|
+
* import { toTeX } from '@danielsimonjr/mathts-workbook';
|
|
24
|
+
* toTeX({ cells: [{ type: 'markdown', content: 'hi' }] }, { fragment: true });
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
19
27
|
export declare function toTeX(doc: RenderDoc, options?: ToTexOptions): string;
|
|
20
28
|
//# sourceMappingURL=tex.d.ts.map
|
package/dist/tex.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tex.d.ts","sourceRoot":"","sources":["../src/tex.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAc,MAAM,WAAW,CAAC;AAIvD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,4EAA4E;IAC5E,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IAClC,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAiED
|
|
1
|
+
{"version":3,"file":"tex.d.ts","sourceRoot":"","sources":["../src/tex.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAc,MAAM,WAAW,CAAC;AAIvD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,4EAA4E;IAC5E,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IAClC,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAiED;;;;;;;;GAQG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,SAAS,EAAE,OAAO,GAAE,YAAiB,GAAG,MAAM,CAUxE"}
|
|
@@ -1,7 +1,312 @@
|
|
|
1
|
-
import { c as parseWorkbook, d as buildDependencyGraph, f as detectCycles, i as SUPPORTED_CELL_TYPES, l as serializeWorkbook, m as getDependents, n as WorkbookExecutor, p as getAncestors, s as isValidIdentifier } from "./formatter-
|
|
1
|
+
import { c as parseWorkbook, d as buildDependencyGraph, f as detectCycles, i as SUPPORTED_CELL_TYPES, l as serializeWorkbook, m as getDependents, n as WorkbookExecutor, p as getAncestors, s as isValidIdentifier } from "./formatter-Dwrza-un.js";
|
|
2
2
|
import * as mathFunctions from "@danielsimonjr/mathts-functions";
|
|
3
|
+
import { bar, line, scatter } from "@danielsimonjr/mathts-plot";
|
|
3
4
|
import { readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
|
|
4
5
|
import { Worker } from "node:worker_threads";
|
|
6
|
+
//#region src/svg.ts
|
|
7
|
+
function coerce(v) {
|
|
8
|
+
if (typeof v === "number") return v;
|
|
9
|
+
if (typeof v === "bigint") return Number(v);
|
|
10
|
+
const u = v;
|
|
11
|
+
if (u && typeof u.toNumeric === "function") try {
|
|
12
|
+
return Number(u.toNumeric());
|
|
13
|
+
} catch {
|
|
14
|
+
return NaN;
|
|
15
|
+
}
|
|
16
|
+
return Number(v);
|
|
17
|
+
}
|
|
18
|
+
function toNums(raw) {
|
|
19
|
+
let arr = raw;
|
|
20
|
+
const m = raw;
|
|
21
|
+
if (m && typeof m.toArray === "function") try {
|
|
22
|
+
arr = m.toArray();
|
|
23
|
+
} catch {
|
|
24
|
+
arr = raw;
|
|
25
|
+
}
|
|
26
|
+
return Array.isArray(arr) ? arr.flat(Infinity).map(coerce) : [];
|
|
27
|
+
}
|
|
28
|
+
function renderChart(spec, xRaw, yRaw, format = "svg") {
|
|
29
|
+
const xs = toNums(xRaw);
|
|
30
|
+
const ys = toNums(yRaw);
|
|
31
|
+
const opts = format === "tikz" ? {
|
|
32
|
+
title: spec.title,
|
|
33
|
+
xLabel: spec.xLabel,
|
|
34
|
+
yLabel: spec.yLabel,
|
|
35
|
+
format: "tikz",
|
|
36
|
+
tikz: { standalone: false }
|
|
37
|
+
} : {
|
|
38
|
+
title: spec.title,
|
|
39
|
+
xLabel: spec.xLabel,
|
|
40
|
+
yLabel: spec.yLabel
|
|
41
|
+
};
|
|
42
|
+
if (spec.type === "scatter") return scatter(xs, ys, opts);
|
|
43
|
+
if (spec.type === "bar") return bar(xs, ys, opts);
|
|
44
|
+
return line(xs, ys, opts);
|
|
45
|
+
}
|
|
46
|
+
//#endregion
|
|
47
|
+
//#region src/markdown.ts
|
|
48
|
+
function esc(s) {
|
|
49
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
50
|
+
}
|
|
51
|
+
function sanitizeHrefRaw(href) {
|
|
52
|
+
const h = href.trim();
|
|
53
|
+
let probe = h.replace(/&/g, "&");
|
|
54
|
+
try {
|
|
55
|
+
probe = decodeURIComponent(probe);
|
|
56
|
+
} catch {}
|
|
57
|
+
if (probe.startsWith("//")) return null;
|
|
58
|
+
try {
|
|
59
|
+
const url = new URL(probe);
|
|
60
|
+
if (url.protocol === "http:" || url.protocol === "https:" || url.protocol === "mailto:") return h;
|
|
61
|
+
return null;
|
|
62
|
+
} catch {
|
|
63
|
+
if (probe.startsWith("/") || probe.startsWith("./") || probe.startsWith("../") || probe.startsWith("#")) return h;
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function sanitizeHref(href) {
|
|
68
|
+
const raw = sanitizeHrefRaw(href);
|
|
69
|
+
return raw === null ? null : raw.replace(/"/g, """);
|
|
70
|
+
}
|
|
71
|
+
function inline(escaped) {
|
|
72
|
+
let s = escaped.replace(/`([^`]+)`/g, (_m, code) => `<code>${code}</code>`);
|
|
73
|
+
s = s.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>");
|
|
74
|
+
s = s.replace(/\*([^*]+)\*/g, "<em>$1</em>");
|
|
75
|
+
s = s.replace(/\[([^\]]*)\]\(([^)\s]+)\)/g, (_m, text, href) => {
|
|
76
|
+
const safe = sanitizeHref(href);
|
|
77
|
+
return safe ? `<a href="${safe}">${text}</a>` : text;
|
|
78
|
+
});
|
|
79
|
+
return s;
|
|
80
|
+
}
|
|
81
|
+
const HR = /^ {0,3}(-{3,}|\*{3,}|_{3,})\s*$/;
|
|
82
|
+
const HEADING = /^(#{1,6})\s+(.*)$/;
|
|
83
|
+
const UL = /^\s*[-*+]\s+/;
|
|
84
|
+
const OL = /^\s*\d+\.\s+/;
|
|
85
|
+
function isBlockStart(line) {
|
|
86
|
+
return line.trim() === "" || /^```/.test(line.trim()) || HEADING.test(line) || UL.test(line) || OL.test(line) || HR.test(line);
|
|
87
|
+
}
|
|
88
|
+
function markdownToHtml(src) {
|
|
89
|
+
if (!src) return "";
|
|
90
|
+
const lines = src.replace(/\r\n?/g, "\n").split("\n");
|
|
91
|
+
const out = [];
|
|
92
|
+
let i = 0;
|
|
93
|
+
while (i < lines.length) {
|
|
94
|
+
const line = lines[i];
|
|
95
|
+
if (/^```/.test(line.trim())) {
|
|
96
|
+
const buf = [];
|
|
97
|
+
i++;
|
|
98
|
+
while (i < lines.length && !/^```/.test(lines[i].trim())) {
|
|
99
|
+
buf.push(lines[i]);
|
|
100
|
+
i++;
|
|
101
|
+
}
|
|
102
|
+
i++;
|
|
103
|
+
out.push(`<pre><code>${esc(buf.join("\n"))}</code></pre>`);
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (line.trim() === "") {
|
|
107
|
+
i++;
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (HR.test(line)) {
|
|
111
|
+
out.push("<hr>");
|
|
112
|
+
i++;
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
const h = HEADING.exec(line);
|
|
116
|
+
if (h) {
|
|
117
|
+
const lvl = h[1].length;
|
|
118
|
+
out.push(`<h${lvl}>${inline(esc(h[2].trim()))}</h${lvl}>`);
|
|
119
|
+
i++;
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (UL.test(line)) {
|
|
123
|
+
const items = [];
|
|
124
|
+
while (i < lines.length && UL.test(lines[i])) {
|
|
125
|
+
items.push(`<li>${inline(esc(lines[i].replace(UL, "")))}</li>`);
|
|
126
|
+
i++;
|
|
127
|
+
}
|
|
128
|
+
out.push(`<ul>${items.join("")}</ul>`);
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (OL.test(line)) {
|
|
132
|
+
const items = [];
|
|
133
|
+
while (i < lines.length && OL.test(lines[i])) {
|
|
134
|
+
items.push(`<li>${inline(esc(lines[i].replace(OL, "")))}</li>`);
|
|
135
|
+
i++;
|
|
136
|
+
}
|
|
137
|
+
out.push(`<ol>${items.join("")}</ol>`);
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
const para = [];
|
|
141
|
+
while (i < lines.length && !isBlockStart(lines[i])) {
|
|
142
|
+
para.push(lines[i]);
|
|
143
|
+
i++;
|
|
144
|
+
}
|
|
145
|
+
out.push(`<p>${inline(esc(para.join(" ")))}</p>`);
|
|
146
|
+
}
|
|
147
|
+
return out.join("\n");
|
|
148
|
+
}
|
|
149
|
+
function texEscape(s) {
|
|
150
|
+
return s.replace(/[\\&%$#_{}~^]/g, (c) => {
|
|
151
|
+
switch (c) {
|
|
152
|
+
case "\\": return "\\textbackslash{}";
|
|
153
|
+
case "~": return "\\textasciitilde{}";
|
|
154
|
+
case "^": return "\\textasciicircum{}";
|
|
155
|
+
default: return `\\${c}`;
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
function verbatimBody(body, env) {
|
|
160
|
+
return body.split(`\\end{${env}}`).join(`\\end {${env}}`);
|
|
161
|
+
}
|
|
162
|
+
function escapeInlineNonLink(text) {
|
|
163
|
+
let s = texEscape(text);
|
|
164
|
+
s = s.replace(/`([^`]+)`/g, (_m, code) => `\\texttt{${code}}`);
|
|
165
|
+
s = s.replace(/\*\*([^*]+)\*\*/g, "\\textbf{$1}");
|
|
166
|
+
s = s.replace(/\*([^*]+)\*/g, "\\emph{$1}");
|
|
167
|
+
return s;
|
|
168
|
+
}
|
|
169
|
+
function inlineTex(text) {
|
|
170
|
+
const linkRe = /\[([^\]]*)\]\(([^)\s]+)\)/g;
|
|
171
|
+
let out = "";
|
|
172
|
+
let last = 0;
|
|
173
|
+
let m;
|
|
174
|
+
while ((m = linkRe.exec(text)) !== null) {
|
|
175
|
+
out += escapeInlineNonLink(text.slice(last, m.index));
|
|
176
|
+
const raw = sanitizeHrefRaw(m[2]);
|
|
177
|
+
out += raw ? `\\href{${texEscape(raw)}}{${escapeInlineNonLink(m[1])}}` : escapeInlineNonLink(m[1]);
|
|
178
|
+
last = linkRe.lastIndex;
|
|
179
|
+
}
|
|
180
|
+
out += escapeInlineNonLink(text.slice(last));
|
|
181
|
+
return out;
|
|
182
|
+
}
|
|
183
|
+
function markdownToTex(src) {
|
|
184
|
+
if (!src) return "";
|
|
185
|
+
const lines = src.replace(/\r\n?/g, "\n").split("\n");
|
|
186
|
+
const out = [];
|
|
187
|
+
let i = 0;
|
|
188
|
+
const SEC = [
|
|
189
|
+
"\\section*",
|
|
190
|
+
"\\subsection*",
|
|
191
|
+
"\\subsubsection*",
|
|
192
|
+
"\\paragraph"
|
|
193
|
+
];
|
|
194
|
+
while (i < lines.length) {
|
|
195
|
+
const line = lines[i];
|
|
196
|
+
if (/^```/.test(line.trim())) {
|
|
197
|
+
const buf = [];
|
|
198
|
+
i++;
|
|
199
|
+
while (i < lines.length && !/^```/.test(lines[i].trim())) {
|
|
200
|
+
buf.push(lines[i]);
|
|
201
|
+
i++;
|
|
202
|
+
}
|
|
203
|
+
i++;
|
|
204
|
+
out.push(`\\begin{lstlisting}\n${verbatimBody(buf.join("\n"), "lstlisting")}\n\\end{lstlisting}`);
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
if (line.trim() === "") {
|
|
208
|
+
i++;
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
if (HR.test(line)) {
|
|
212
|
+
out.push("\\par\\noindent\\rule{\\linewidth}{0.4pt}\\par");
|
|
213
|
+
i++;
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
const h = HEADING.exec(line);
|
|
217
|
+
if (h) {
|
|
218
|
+
const lvl = Math.min(h[1].length, 4);
|
|
219
|
+
out.push(`${SEC[lvl - 1]}{${inlineTex(h[2].trim())}}`);
|
|
220
|
+
i++;
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
if (UL.test(line)) {
|
|
224
|
+
const items = [];
|
|
225
|
+
while (i < lines.length && UL.test(lines[i])) {
|
|
226
|
+
items.push(` \\item ${inlineTex(lines[i].replace(UL, ""))}`);
|
|
227
|
+
i++;
|
|
228
|
+
}
|
|
229
|
+
out.push(`\\begin{itemize}\n${items.join("\n")}\n\\end{itemize}`);
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
if (OL.test(line)) {
|
|
233
|
+
const items = [];
|
|
234
|
+
while (i < lines.length && OL.test(lines[i])) {
|
|
235
|
+
items.push(` \\item ${inlineTex(lines[i].replace(OL, ""))}`);
|
|
236
|
+
i++;
|
|
237
|
+
}
|
|
238
|
+
out.push(`\\begin{enumerate}\n${items.join("\n")}\n\\end{enumerate}`);
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
const para = [];
|
|
242
|
+
while (i < lines.length && !isBlockStart(lines[i])) {
|
|
243
|
+
para.push(lines[i]);
|
|
244
|
+
i++;
|
|
245
|
+
}
|
|
246
|
+
out.push(inlineTex(para.join(" ")));
|
|
247
|
+
}
|
|
248
|
+
return out.join("\n\n");
|
|
249
|
+
}
|
|
250
|
+
//#endregion
|
|
251
|
+
//#region src/tex.ts
|
|
252
|
+
const PREAMBLE = [
|
|
253
|
+
"\\documentclass{article}",
|
|
254
|
+
"\\usepackage{amsmath}",
|
|
255
|
+
"\\usepackage{tikz}",
|
|
256
|
+
"\\usepackage{listings}",
|
|
257
|
+
"\\usepackage{xcolor}",
|
|
258
|
+
"\\usepackage[margin=1in]{geometry}",
|
|
259
|
+
"\\usepackage{hyperref}"
|
|
260
|
+
].join("\n");
|
|
261
|
+
function renderEquationTex(content, parse) {
|
|
262
|
+
if (parse) try {
|
|
263
|
+
return `\\[ ${parse(content).toTex()} \\]`;
|
|
264
|
+
} catch {}
|
|
265
|
+
return `\\texttt{${texEscape(content)}}`;
|
|
266
|
+
}
|
|
267
|
+
function renderCellTex(cell, parse) {
|
|
268
|
+
switch (cell.type) {
|
|
269
|
+
case "markdown": return markdownToTex(cell.content);
|
|
270
|
+
case "equation": return renderEquationTex(cell.content, parse);
|
|
271
|
+
case "code": {
|
|
272
|
+
const cap = cell.id ? `\\textit{${texEscape(cell.id)}}\\\\\n` : "";
|
|
273
|
+
const src = `\\begin{lstlisting}\n${verbatimBody(cell.content, "lstlisting")}\n\\end{lstlisting}`;
|
|
274
|
+
let res = "";
|
|
275
|
+
if (cell.error !== void 0) res = `\n\n\\textcolor{red}{\\texttt{${texEscape(cell.error)}}}`;
|
|
276
|
+
else if (cell.output !== void 0) res = `\n\n\\begin{verbatim}\n${verbatimBody(cell.output, "verbatim")}\n\\end{verbatim}`;
|
|
277
|
+
return `${cap}${src}${res}`;
|
|
278
|
+
}
|
|
279
|
+
case "test": {
|
|
280
|
+
const label = `\\texttt{${texEscape(cell.content)}}`;
|
|
281
|
+
if (cell.error !== void 0) return `\\textcolor{orange}{[ERROR]} ${label} --- ${texEscape(cell.error)}`;
|
|
282
|
+
if (cell.passed === true) return `\\textcolor{green!60!black}{[PASS]} ${label}`;
|
|
283
|
+
if (cell.passed === false) return `\\textcolor{red}{[FAIL]} ${label}`;
|
|
284
|
+
return `\\textcolor{gray}{[NOT RUN]} ${label}`;
|
|
285
|
+
}
|
|
286
|
+
case "data": {
|
|
287
|
+
const val = cell.error !== void 0 ? cell.error : cell.output ?? "";
|
|
288
|
+
return `${cell.id ? `\\textit{${texEscape(cell.id)}}\\\\\n` : ""}\\begin{verbatim}\n${verbatimBody(val, "verbatim")}\n\\end{verbatim}`;
|
|
289
|
+
}
|
|
290
|
+
case "chart": return `\\begin{center}\n${cell.chart ? renderChart(cell.chart.spec, cell.chart.x, cell.chart.y, "tikz") : "% no chart"}\n\\end{center}${cell.note ? `\n\n\\textit{${texEscape(cell.note)}}` : ""}`;
|
|
291
|
+
default: return `\\begin{verbatim}\n${verbatimBody(cell.content, "verbatim")}\n\\end{verbatim}`;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
function toTeX(doc, options = {}) {
|
|
295
|
+
const body = doc.cells.map((c) => renderCellTex(c, options.parse)).join("\n\n");
|
|
296
|
+
if (options.fragment) return body;
|
|
297
|
+
const meta = [];
|
|
298
|
+
if (doc.title) meta.push(`\\title{${texEscape(doc.title)}}`);
|
|
299
|
+
if (doc.author) meta.push(`\\author{${texEscape(doc.author)}}`);
|
|
300
|
+
const maketitle = doc.title ? "\\maketitle\n" : "";
|
|
301
|
+
return [
|
|
302
|
+
PREAMBLE,
|
|
303
|
+
...meta,
|
|
304
|
+
"\\begin{document}",
|
|
305
|
+
`${maketitle}${body}`,
|
|
306
|
+
"\\end{document}"
|
|
307
|
+
].join("\n");
|
|
308
|
+
}
|
|
309
|
+
//#endregion
|
|
5
310
|
//#region src/edit.ts
|
|
6
311
|
function cloneWorkbook(wb) {
|
|
7
312
|
return {
|
|
@@ -151,7 +456,7 @@ const SCHEMA_VERSION = {
|
|
|
151
456
|
major: 1,
|
|
152
457
|
minor: 0
|
|
153
458
|
};
|
|
154
|
-
const VERSION = "0.
|
|
459
|
+
const VERSION = "0.5.0";
|
|
155
460
|
const COMMAND_NAMES = [
|
|
156
461
|
"run",
|
|
157
462
|
"describe",
|
|
@@ -564,4 +869,4 @@ function runWorkbookWithTimeout(source, options) {
|
|
|
564
869
|
});
|
|
565
870
|
}
|
|
566
871
|
//#endregion
|
|
567
|
-
export { capabilitiesInfo as a, writeFileAtomic as c, addCell as d, editCell as f, setMetadata as g, renameCell as h, describeData as i, SCHEMA_VERSION as l, removeCell as m, runWorkbookWithTimeout as n, listFunctions as o, moveCell as p, handleRequest as r, Session as s, WorkbookTimeoutError as t, VERSION as u };
|
|
872
|
+
export { toTeX as _, capabilitiesInfo as a, writeFileAtomic as c, addCell as d, editCell as f, setMetadata as g, renameCell as h, describeData as i, SCHEMA_VERSION as l, removeCell as m, runWorkbookWithTimeout as n, listFunctions as o, moveCell as p, handleRequest as r, Session as s, WorkbookTimeoutError as t, VERSION as u, markdownToHtml as v, renderChart as y };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@danielsimonjr/mathts-workbook",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Scientific workbook runtime for MathTS (.mtsw format)",
|
|
5
5
|
"author": "Daniel Simon Jr.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -34,10 +34,10 @@
|
|
|
34
34
|
"build:prod": "tsdown --minify && tsc -p tsconfig.dts.json"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@danielsimonjr/mathts-core": "^0.
|
|
38
|
-
"@danielsimonjr/mathts-expression": "^0.
|
|
39
|
-
"@danielsimonjr/mathts-functions": "^0.
|
|
40
|
-
"@danielsimonjr/mathts-plot": "^0.4.
|
|
37
|
+
"@danielsimonjr/mathts-core": "^0.20.0",
|
|
38
|
+
"@danielsimonjr/mathts-expression": "^0.11.0",
|
|
39
|
+
"@danielsimonjr/mathts-functions": "^0.70.0",
|
|
40
|
+
"@danielsimonjr/mathts-plot": "^0.4.14",
|
|
41
41
|
"yaml": "^2.3.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|