@danielsimonjr/mathts-workbook 0.1.8 → 0.2.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/dist/index.d.ts CHANGED
@@ -68,6 +68,23 @@ interface WorkbookEvent {
68
68
  error?: string;
69
69
  timestamp: number;
70
70
  }
71
+ /**
72
+ * Result of executing a single cell in a run report.
73
+ */
74
+ interface CellResult {
75
+ id: string;
76
+ type: CellType;
77
+ status: 'success' | 'error' | 'pass' | 'fail';
78
+ output?: unknown;
79
+ error?: string;
80
+ }
81
+ /**
82
+ * Aggregated result of running an entire workbook (continue-on-error).
83
+ */
84
+ interface RunResult {
85
+ cells: CellResult[];
86
+ ok: boolean;
87
+ }
71
88
  /**
72
89
  * Dependency graph node
73
90
  */
@@ -89,13 +106,23 @@ interface DependencyGraph {
89
106
  */
90
107
 
91
108
  /**
92
- * Parse a workbook from YAML content
109
+ * Detect cell type from YAML keys (first match by precedence).
110
+ */
111
+ declare function detectCellType(cell: Record<string, unknown>): CellType;
112
+ /**
113
+ * Parse a workbook from YAML content.
93
114
  */
94
115
  declare function parseWorkbook(content: string): ParseResult;
95
116
  /**
96
- * Serialize a workbook to YAML
117
+ * Serialize a workbook to YAML that round-trips through {@link parseWorkbook}.
118
+ *
119
+ * Structural fidelity (version/metadata/runtime/cells: id/type/content/dependsOn/
120
+ * metadata) is exact. Persisted `output` values are best-effort: plain
121
+ * primitives/arrays/objects round-trip exactly (the YAML serializer quotes
122
+ * scalars that would otherwise re-type); exotic class instances serialize to
123
+ * their plain shape. Throws only on a structurally invalid workbook.
97
124
  */
98
- declare function serializeWorkbook(_workbook: Workbook): string;
125
+ declare function serializeWorkbook(workbook: Workbook): string;
99
126
  /**
100
127
  * Strip outputs from workbook (for git)
101
128
  */
@@ -117,6 +144,24 @@ declare function topologicalSort(nodes: Map<string, DependencyNode>): string[];
117
144
  * Get all cells that depend on a given cell
118
145
  */
119
146
  declare function getDependents(graph: DependencyGraph, cellId: string): string[];
147
+ /**
148
+ * All transitive dependencies of `id` plus `id` itself (its ancestor closure).
149
+ * Used to run a single cell together with everything it needs. Cycle-safe via
150
+ * a visited set; returns `[]` if `id` is not in the graph.
151
+ */
152
+ declare function getAncestors(graph: DependencyGraph, id: string): string[];
153
+ /**
154
+ * Render the dependency graph as a Mermaid `graph TD` diagram.
155
+ *
156
+ * Cell ids are validated identifiers (`[A-Za-z_][A-Za-z0-9_]*`), so they are
157
+ * safe to use verbatim as both the node id and its quoted label — Mermaid
158
+ * syntax injection is impossible and no cell content appears in the output.
159
+ */
160
+ declare function toMermaid(graph: DependencyGraph): string;
161
+ /**
162
+ * Detect circular dependencies
163
+ */
164
+ declare function detectCycles(graph: DependencyGraph): string[][];
120
165
 
121
166
  /**
122
167
  * Workbook executor
@@ -155,20 +200,56 @@ declare class WorkbookExecutor {
155
200
  * Execute a single cell
156
201
  */
157
202
  private executeCell;
203
+ /**
204
+ * Build the evaluation scope from a cell's DIRECT dependency outputs.
205
+ *
206
+ * Dependency outputs are injected as named variables keyed by the
207
+ * dependency's cell id, so a cell can reference an earlier cell's result by
208
+ * that id. Injection is non-transitive: only ids in `cell.dependsOn` are
209
+ * injected (a dependency's own dependencies are not). An output of
210
+ * `undefined` (cell never ran) is skipped, so the reference fails loudly.
211
+ */
212
+ private buildScope;
158
213
  /**
159
214
  * Execute a code cell by evaluating its content as a MathTS expression.
160
215
  *
161
- * Dependency outputs are injected as named variables in the evaluation
162
- * scope, so a cell can reference the result of an earlier cell by its id.
163
216
  * Evaluation goes through the MathTS expression engine — property and
164
217
  * method access route through the expression sandbox, so this does not
165
218
  * have the arbitrary-code-execution exposure of the `Function` constructor.
166
219
  */
167
220
  private executeCode;
168
221
  /**
169
- * Execute a data cell parse its content as YAML (a superset of JSON).
222
+ * Execute a test cell: evaluate its assertion expression in the dependency
223
+ * scope. The result must be a boolean — `runReport` classifies `true` as a
224
+ * pass and `false` as a fail. A non-boolean result is a usage error (a test
225
+ * that doesn't assert), surfaced via throw like any other evaluation error.
226
+ */
227
+ private executeTest;
228
+ /**
229
+ * Execute a data cell — parse its content as YAML (a superset of JSON) using
230
+ * the same hardened options + prototype-pollution guard as the document
231
+ * parser, so both YAML entry points are consistent.
170
232
  */
171
233
  private executeData;
234
+ /**
235
+ * Run every cell in dependency order and return a structured report.
236
+ *
237
+ * Unlike {@link runAll} (the event-stream API, which throws on the first cell
238
+ * error), `runReport` is the headless/report API: it is **continue-on-error**
239
+ * (one failing cell does not abort the rest) and never throws on a cell
240
+ * failure. A dependency cycle is refused up front. Test cells are classified
241
+ * as `pass`/`fail`/`error`; all other cells as `success`/`error`.
242
+ */
243
+ /**
244
+ * Seed the output cache (for incremental session runs): non-stale cells'
245
+ * outputs are provided so downstream cells can read them as scope without
246
+ * re-execution. Replaces any existing cached outputs.
247
+ */
248
+ seedOutputs(entries: Map<string, unknown>): void;
249
+ runReport(options?: {
250
+ only?: string;
251
+ runIds?: Set<string>;
252
+ }): Promise<RunResult>;
172
253
  /**
173
254
  * Get output from a previous cell
174
255
  */
@@ -180,10 +261,175 @@ declare class WorkbookExecutor {
180
261
  declare function createExecutor(workbook: Workbook): WorkbookExecutor;
181
262
 
182
263
  /**
183
- * @danielsimonjr/mathts-workbook - Scientific workbook runtime
184
- * @packageDocumentation
264
+ * Human-readable rendering of cell results for terminal output.
265
+ *
266
+ * `formatResult` is called inside the executor's continue-on-error loop, so it
267
+ * MUST NOT throw — circular references, BigInt, and unserializable values all
268
+ * fall back to safe markers rather than crashing the run.
269
+ */
270
+ declare function formatResult(value: unknown): string;
271
+
272
+ /**
273
+ * Pure, immutable cell-mutation operations on a Workbook.
274
+ *
275
+ * Every op returns a NEW workbook (the input is never mutated) and enforces the
276
+ * runnable-valid invariants — unique + identifier-safe ids, supported cell
277
+ * types, existing `depends_on` references, no self-dependency, and no dependency
278
+ * cycle. An op that would break an invariant throws; callers must not write the
279
+ * file on a throw.
185
280
  */
186
281
 
282
+ interface CellPosition {
283
+ before?: string;
284
+ after?: string;
285
+ at?: number;
286
+ }
287
+ interface RemoveResult {
288
+ workbook: Workbook;
289
+ /** Cells whose `depends_on` was edited to detach the removed cell (force). */
290
+ changedCells: string[];
291
+ }
292
+ declare function addCell(wb: Workbook, spec: {
293
+ id: string;
294
+ type: CellType;
295
+ content?: string;
296
+ dependsOn?: string[];
297
+ }, position?: CellPosition): Workbook;
298
+ declare function editCell(wb: Workbook, id: string, changes: {
299
+ content?: string;
300
+ type?: CellType;
301
+ dependsOn?: string[];
302
+ }): Workbook;
303
+ declare function removeCell(wb: Workbook, id: string, options?: {
304
+ force?: boolean;
305
+ }): RemoveResult;
306
+ declare function moveCell(wb: Workbook, id: string, position: CellPosition): Workbook;
307
+ declare function renameCell(wb: Workbook, oldId: string, newId: string): Workbook;
308
+ /** Update workbook-level metadata fields (only the provided ones). */
309
+ declare function setMetadata(wb: Workbook, changes: {
310
+ title?: string;
311
+ author?: string;
312
+ description?: string;
313
+ tags?: string[];
314
+ }): Workbook;
315
+
316
+ /**
317
+ * Machine-contract constants shared by the CLI and the public API.
318
+ *
319
+ * `SCHEMA_VERSION` is the version of the `--json` envelope shape. Clients
320
+ * negotiate with the rule: ignore unknown fields when `major` matches; refuse
321
+ * on a `major` mismatch. Additive fields bump `minor`; breaking changes bump
322
+ * `major`.
323
+ */
324
+ declare const SCHEMA_VERSION: {
325
+ readonly major: 1;
326
+ readonly minor: 0;
327
+ };
328
+ /** Package/engine version reported by `--version`, `capabilities`, and serve. */
187
329
  declare const VERSION = "0.1.0";
188
330
 
189
- export { type Cell, type CellType, type ExecutionMode, type ParseResult, type RuntimeConfig, VERSION, type Workbook, type WorkbookEvent, WorkbookExecutor, type WorkbookMetadata, buildDependencyGraph, createExecutor, getDependents, parseWorkbook, serializeWorkbook, stripOutputs, topologicalSort };
331
+ /**
332
+ * In-memory editing/execution session for a single workbook — the stateful
333
+ * core behind `mtsw serve`. Holds the workbook, a per-cell result cache, and a
334
+ * stale set so a `run` only re-executes what an edit invalidated.
335
+ *
336
+ * File I/O is limited to `open`/`save`; everything else is in-memory. Edits are
337
+ * not persisted until `save`.
338
+ */
339
+
340
+ declare class Session {
341
+ workbook: Workbook | null;
342
+ path: string | null;
343
+ dirty: boolean;
344
+ private cache;
345
+ private stale;
346
+ private require;
347
+ /** A cell has a usable, up-to-date result (the basis for "not stale"). */
348
+ private hasValidResult;
349
+ /** Load a workbook file into the session. Refuses to discard unsaved edits. */
350
+ open(path: string, options?: {
351
+ force?: boolean;
352
+ }): void;
353
+ /** Replace the workbook and recompute the stale set by diffing old vs new. */
354
+ private commit;
355
+ addCell(spec: {
356
+ id: string;
357
+ type: CellType;
358
+ content?: string;
359
+ dependsOn?: string[];
360
+ }, position?: CellPosition): void;
361
+ editCell(id: string, changes: {
362
+ content?: string;
363
+ type?: CellType;
364
+ dependsOn?: string[];
365
+ }): void;
366
+ removeCell(id: string, options?: {
367
+ force?: boolean;
368
+ }): string[];
369
+ moveCell(id: string, position: CellPosition): void;
370
+ renameCell(oldId: string, newId: string): void;
371
+ setMetadata(changes: {
372
+ title?: string;
373
+ author?: string;
374
+ description?: string;
375
+ tags?: string[];
376
+ }): void;
377
+ /**
378
+ * Incremental run: execute only stale cells in the target set (`only` + its
379
+ * ancestors, or the whole workbook), reusing cached outputs for the rest.
380
+ * Returns the merged report over the target plus the streamed events.
381
+ */
382
+ run(only?: string): Promise<{
383
+ result: RunResult;
384
+ events: WorkbookEventLite[];
385
+ }>;
386
+ /** The set of cells awaiting (re-)execution. */
387
+ staleIds(): string[];
388
+ /** Serialize the current workbook and write it atomically. */
389
+ save(path?: string): string;
390
+ }
391
+ /** Slimmed event for streaming (avoids leaking timestamps / handler internals). */
392
+ interface WorkbookEventLite {
393
+ type: string;
394
+ cellId?: string;
395
+ error?: string;
396
+ }
397
+
398
+ /**
399
+ * Pure JSON-RPC 2.0 router for `mtsw serve`. `handleRequest(session, request)`
400
+ * maps a request to a Session call and returns the response plus any streamed
401
+ * `cell/event` notifications — no stdio, so the protocol logic is unit-testable.
402
+ */
403
+
404
+ interface JsonRpcRequest {
405
+ jsonrpc?: string;
406
+ id?: string | number | null;
407
+ method?: string;
408
+ params?: Record<string, unknown>;
409
+ }
410
+ interface JsonRpcResponse {
411
+ jsonrpc: '2.0';
412
+ id: string | number | null;
413
+ result?: unknown;
414
+ error?: {
415
+ code: number;
416
+ message: string;
417
+ };
418
+ }
419
+ interface JsonRpcEvent {
420
+ jsonrpc: '2.0';
421
+ method: 'cell/event';
422
+ params: {
423
+ type: string;
424
+ cellId?: string;
425
+ error?: string;
426
+ };
427
+ }
428
+ interface HandleResult {
429
+ response: JsonRpcResponse;
430
+ events: JsonRpcEvent[];
431
+ shutdown: boolean;
432
+ }
433
+ declare function handleRequest(session: Session, request: JsonRpcRequest): Promise<HandleResult>;
434
+
435
+ export { type Cell, type CellPosition, type CellResult, type CellType, type ExecutionMode, type ParseResult, type RemoveResult, type RunResult, type RuntimeConfig, SCHEMA_VERSION, Session, VERSION, type Workbook, type WorkbookEvent, WorkbookExecutor, type WorkbookMetadata, addCell, buildDependencyGraph, createExecutor, detectCellType, detectCycles, editCell, formatResult, getAncestors, getDependents, handleRequest, moveCell, parseWorkbook, removeCell, renameCell, serializeWorkbook, setMetadata, stripOutputs, toMermaid, topologicalSort };
package/dist/index.js CHANGED
@@ -1,22 +1,50 @@
1
1
  import {
2
+ SCHEMA_VERSION,
3
+ Session,
2
4
  VERSION,
3
5
  WorkbookExecutor,
6
+ addCell,
4
7
  buildDependencyGraph,
5
8
  createExecutor,
9
+ detectCellType,
10
+ detectCycles,
11
+ editCell,
12
+ formatResult,
13
+ getAncestors,
6
14
  getDependents,
15
+ handleRequest,
16
+ moveCell,
7
17
  parseWorkbook,
18
+ removeCell,
19
+ renameCell,
8
20
  serializeWorkbook,
21
+ setMetadata,
9
22
  stripOutputs,
23
+ toMermaid,
10
24
  topologicalSort
11
- } from "./chunk-L7UWFWMV.js";
25
+ } from "./chunk-TS2WDJ7W.js";
12
26
  export {
27
+ SCHEMA_VERSION,
28
+ Session,
13
29
  VERSION,
14
30
  WorkbookExecutor,
31
+ addCell,
15
32
  buildDependencyGraph,
16
33
  createExecutor,
34
+ detectCellType,
35
+ detectCycles,
36
+ editCell,
37
+ formatResult,
38
+ getAncestors,
17
39
  getDependents,
40
+ handleRequest,
41
+ moveCell,
18
42
  parseWorkbook,
43
+ removeCell,
44
+ renameCell,
19
45
  serializeWorkbook,
46
+ setMetadata,
20
47
  stripOutputs,
48
+ toMermaid,
21
49
  topologicalSort
22
50
  };
package/package.json CHANGED
@@ -1,62 +1,64 @@
1
- {
2
- "name": "@danielsimonjr/mathts-workbook",
3
- "version": "0.1.8",
4
- "description": "Scientific workbook runtime for MathTS (.mtsw format)",
5
- "author": "Daniel Simon Jr.",
6
- "license": "MIT",
7
- "type": "module",
8
- "main": "./dist/index.js",
9
- "module": "./dist/index.js",
10
- "types": "./dist/index.d.ts",
11
- "bin": {
12
- "mtsw": "./dist/cli.js"
13
- },
14
- "exports": {
15
- ".": {
16
- "import": "./dist/index.js",
17
- "types": "./dist/index.d.ts"
18
- }
19
- },
20
- "files": [
21
- "dist",
22
- "README.md"
23
- ],
24
- "scripts": {
25
- "build": "tsup src/index.ts src/cli.ts --format esm --dts --clean",
26
- "dev": "tsup src/index.ts src/cli.ts --format esm --dts --watch",
27
- "test": "vitest run",
28
- "test:watch": "vitest",
29
- "test:coverage": "vitest run --coverage",
30
- "typecheck": "tsc --noEmit",
31
- "lint": "eslint src --ext .ts",
32
- "lint:fix": "eslint src --ext .ts --fix",
33
- "clean": "rm -rf dist",
34
- "build:prod": "tsup src/index.ts src/cli.ts --format esm --dts --clean --minify --treeshake"
35
- },
36
- "dependencies": {
37
- "@danielsimonjr/mathts-core": "^0.1.4",
38
- "@danielsimonjr/mathts-functions": "^0.2.7",
39
- "yaml": "^2.3.0"
40
- },
41
- "devDependencies": {
42
- "@types/node": "^25.5.2",
43
- "tsup": "^8.0.0",
44
- "typescript": "^5.3.0",
45
- "vitest": "^4.1.5"
46
- },
47
- "publishConfig": {
48
- "access": "public"
49
- },
50
- "repository": {
51
- "type": "git",
52
- "url": "https://github.com/danielsimonjr/mathts",
53
- "directory": "workbook"
54
- },
55
- "keywords": [
56
- "notebook",
57
- "workbook",
58
- "scientific-computing",
59
- "reactive",
60
- "yaml"
61
- ]
62
- }
1
+ {
2
+ "name": "@danielsimonjr/mathts-workbook",
3
+ "version": "0.2.0",
4
+ "description": "Scientific workbook runtime for MathTS (.mtsw format)",
5
+ "author": "Daniel Simon Jr.",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "main": "./dist/index.js",
9
+ "module": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "bin": {
12
+ "mtsw": "./dist/cli.js"
13
+ },
14
+ "exports": {
15
+ ".": {
16
+ "import": "./dist/index.js",
17
+ "types": "./dist/index.d.ts"
18
+ }
19
+ },
20
+ "files": [
21
+ "dist",
22
+ "README.md"
23
+ ],
24
+ "scripts": {
25
+ "build": "tsup src/index.ts src/cli.ts --format esm --dts --clean",
26
+ "dev": "tsup src/index.ts src/cli.ts --format esm --dts --watch",
27
+ "test": "vitest run",
28
+ "test:watch": "vitest",
29
+ "test:coverage": "vitest run --coverage",
30
+ "typecheck": "tsc --noEmit",
31
+ "lint": "eslint src --ext .ts",
32
+ "lint:fix": "eslint src --ext .ts --fix",
33
+ "clean": "rm -rf dist",
34
+ "build:prod": "tsup src/index.ts src/cli.ts --format esm --dts --clean --minify --treeshake"
35
+ },
36
+ "dependencies": {
37
+ "@danielsimonjr/mathts-core": "^0.10.0",
38
+ "@danielsimonjr/mathts-expression": "^0.6.4",
39
+ "@danielsimonjr/mathts-functions": "^0.42.0",
40
+ "@danielsimonjr/mathts-plot": "^0.3.26",
41
+ "yaml": "^2.3.0"
42
+ },
43
+ "devDependencies": {
44
+ "@types/node": "^25.5.2",
45
+ "tsup": "^8.0.0",
46
+ "typescript": "^5.3.0",
47
+ "vitest": "^4.1.5"
48
+ },
49
+ "publishConfig": {
50
+ "access": "public"
51
+ },
52
+ "repository": {
53
+ "type": "git",
54
+ "url": "https://github.com/danielsimonjr/mathts",
55
+ "directory": "workbook"
56
+ },
57
+ "keywords": [
58
+ "notebook",
59
+ "workbook",
60
+ "scientific-computing",
61
+ "reactive",
62
+ "yaml"
63
+ ]
64
+ }