@quillmark/wasm 0.88.0 → 0.90.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/CHANGELOG.md +127 -0
- package/README.md +79 -27
- package/{bundler → backends/typst}/wasm.d.ts +60 -24
- package/{bundler → backends/typst}/wasm_bg.js +119 -55
- package/{bundler → backends/typst}/wasm_bg.wasm +0 -0
- package/{bundler → backends/typst}/wasm_bg.wasm.d.ts +6 -4
- package/core/wasm.d.ts +439 -0
- package/core/wasm.js +9 -0
- package/core/wasm_bg.js +1496 -0
- package/core/wasm_bg.wasm +0 -0
- package/core/wasm_bg.wasm.d.ts +62 -0
- package/package.json +13 -13
- package/runtime/runtime.d.ts +212 -0
- package/runtime/runtime.js +378 -0
- /package/{bundler → backends/typst}/wasm.js +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,132 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v0.90.0 - 2026-06-10
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
## v0.89.1 - 2026-06-10
|
|
8
|
+
|
|
9
|
+
- chore(release): v0.89.1-rc.1 (#714)
|
|
10
|
+
- feat(wasm)!: 0.90 canonical API — engine-free Quill, single root export, typed errors; Python parity (#713)
|
|
11
|
+
- Proposal: WASM bindings split (core + render) via backend-decoupled Quill (#710)
|
|
12
|
+
- Add version selector matching and mismatch warnings (#708)
|
|
13
|
+
- docs: density-optimization pass on user-facing docs (#703)
|
|
14
|
+
- Remove role annotation from root block metadata header (#707)
|
|
15
|
+
- canon: audit and correct all prose/canon/ docs (#704)
|
|
16
|
+
- Fix makeCard fields/body typed as required in WASM .d.ts (#702)
|
|
17
|
+
- Update CLAUDE.md
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
## v0.89.1-rc.1 - 2026-06-10
|
|
21
|
+
|
|
22
|
+
- feat(wasm)!: 0.90 canonical API — engine-free Quill, single root export, typed errors; Python parity (#713)
|
|
23
|
+
- Proposal: WASM bindings split (core + render) via backend-decoupled Quill (#710)
|
|
24
|
+
- Add version selector matching and mismatch warnings (#708)
|
|
25
|
+
- docs: density-optimization pass on user-facing docs (#703)
|
|
26
|
+
- Remove role annotation from root block metadata header (#707)
|
|
27
|
+
- canon: audit and correct all prose/canon/ docs (#704)
|
|
28
|
+
- Fix makeCard fields/body typed as required in WASM .d.ts (#702)
|
|
29
|
+
- Update CLAUDE.md
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
## Unreleased
|
|
33
|
+
|
|
34
|
+
- **Breaking (Rust API + bindings):** `Quill` is now engine-free, validated
|
|
35
|
+
data. It no longer holds a backend; the `Quillmark` engine becomes a backend
|
|
36
|
+
registry + render dispatcher. Rendering and capability move onto the engine:
|
|
37
|
+
`render` / `open` / `supported_formats` / `supports_canvas` take `&quill`
|
|
38
|
+
(JS: `engine.render(quill, doc)` etc.). The `engine.quill` / `quill_from_path`
|
|
39
|
+
factory is removed — construct with `Quill::from_tree` (JS `Quill.fromTree`)
|
|
40
|
+
or `quillmark::quill_from_path`. The backend-existence
|
|
41
|
+
check moves from load time to render time (`UnsupportedBackend` now surfaces
|
|
42
|
+
from the first engine call). `supportedFormats` leaves `Quill.metadata` (now
|
|
43
|
+
pure config) for `engine.supportedFormats(quill)`. `Backend` gains a
|
|
44
|
+
`supports_canvas()` capability method (default `false`; Typst `true`),
|
|
45
|
+
retiring the `backend_id == "typst"` magic string. See
|
|
46
|
+
[migration guide](docs/migrations/0.89-to-0.90.md).
|
|
47
|
+
- **Breaking (WASM/JS types):** `QuillMetadata` drops its `[key: string]: unknown`
|
|
48
|
+
index signature. Code reading removed or unknown metadata properties (e.g.
|
|
49
|
+
`quill.metadata.supportedFormats`) now fails at compile time with "Property
|
|
50
|
+
does not exist" instead of silently returning `undefined` at runtime. Cast to
|
|
51
|
+
`Record<string, unknown>` to reach extra `quill:` YAML keys if needed.
|
|
52
|
+
- **Breaking (Python API):** the Python binding adopts the engine-free shape.
|
|
53
|
+
Render and capability move onto the `Quillmark` engine, taking a quill:
|
|
54
|
+
`engine.render(quill, doc)` / `engine.open(quill, doc)` /
|
|
55
|
+
`engine.supported_formats(quill)` / `engine.supports_canvas(quill)` (were
|
|
56
|
+
`quill.render(doc)` etc.). `Quill.from_path(path)` replaces
|
|
57
|
+
`Quillmark.quill_from_path(path)` — the engine is no longer a loader, and the
|
|
58
|
+
loaded `Quill` is engine-free. `quill.metadata` no longer contains
|
|
59
|
+
`supportedFormats` (read `engine.supported_formats(quill)`) and is now a pure,
|
|
60
|
+
infallible config read. Backend resolution moves from load to render time:
|
|
61
|
+
`UnsupportedBackend` surfaces from the first engine call, not from `from_path`.
|
|
62
|
+
See the [migration guide](docs/migrations/0.89-to-0.90.md#python).
|
|
63
|
+
- **Breaking (Rust API):** `QuillSource` and the orchestration `Quill` collapse
|
|
64
|
+
into one core type, `quillmark_core::Quill` (held by value; the vestigial
|
|
65
|
+
`Arc` is dropped). `Backend::open` now takes `&Quill`; the consumer methods
|
|
66
|
+
and the `seed` module move into core; `quill.source()` is gone
|
|
67
|
+
(`quill.config()` is direct). Bindings already hid `QuillSource`, so JS/Python
|
|
68
|
+
consumers are unaffected by the rename.
|
|
69
|
+
- **WASM packaging (single root export):** the root `@quillmark/wasm` import is
|
|
70
|
+
now a hand-written **canonical layer** (`pkg/runtime/`) — it re-exports the
|
|
71
|
+
Typst-less core's `Quill` / `Document` **verbatim** (same classes, no wrappers)
|
|
72
|
+
and adds an async **`Engine`** (`render` / `open` / `supportedFormats` /
|
|
73
|
+
`supportsCanvas`) as the canonical render API. The package `exports` map has
|
|
74
|
+
exactly **one** public entry point, `.` (the canonical layer); the old
|
|
75
|
+
`./render` and `./core` subpath exports are both **removed**. Engine-free
|
|
76
|
+
editor/validation code (`Quill.fromTree`, `Document.fromMarkdown`) still loads
|
|
77
|
+
only the small internal core binary (~0.66 MB gzip) — no backend is loaded
|
|
78
|
+
until you render. The Typst backend binary is **private**
|
|
79
|
+
(`pkg/backends/typst/`, not in the `exports` map): the `Engine`
|
|
80
|
+
lazy-`import()`s it on first render, clones the quill/document into its memory as
|
|
81
|
+
data (`Quill.toTree` → `fromTree`, `doc.toJson` → `fromJson`), and manages
|
|
82
|
+
those clones internally (the validated quill clone is cached per instance;
|
|
83
|
+
per-render document clones are freed) — consumers never import the backend or
|
|
84
|
+
cross a WASM memory boundary themselves. `Quill.toTree()` is added to core for that crossing. A release-time
|
|
85
|
+
size budget still guards the core artifact against Typst regressions.
|
|
86
|
+
- **WASM `Engine` (descriptor-only backend registry):** `new Engine({ backends })`
|
|
87
|
+
takes backend entries in **descriptor form only** — `{ load, formats, canvas }`
|
|
88
|
+
with `formats` and `canvas` **required**. The constructor validates each entry
|
|
89
|
+
and throws (naming the backend id) at construction. The capability probes
|
|
90
|
+
`supportedFormats` / `supportsCanvas` answer from this required manifest
|
|
91
|
+
**unconditionally**, never loading a backend binary or cloning the quill. The
|
|
92
|
+
bare-thunk loader form and its load+clone fallback path are removed.
|
|
93
|
+
- **WASM `Engine` (no invalidation API):** the unreleased
|
|
94
|
+
`Engine.invalidate(quill)` / `invalidateAll()` methods are removed before
|
|
95
|
+
release. The backend-clone cache is keyed on the canonical `Quill` instance in
|
|
96
|
+
a `WeakMap`; a quill's contents never change after construction, so the only
|
|
97
|
+
invalidation semantic is to drop/replace the instance (the clone is freed with
|
|
98
|
+
it via the `WeakMap` + wasm-bindgen weak-refs). An explicit invalidation API
|
|
99
|
+
will ship with its first real consumer. The load-bearing invariant — a
|
|
100
|
+
canonical ref is immutable content within a runtime's lifespan — is now
|
|
101
|
+
recorded in `prose/canon/VERSIONING.md` (Ref Immutability).
|
|
102
|
+
- **WASM `Engine` (session/canvas surface marked experimental):** `Engine.open`,
|
|
103
|
+
`RenderSession`, `paint`, `PaintOptions`, `PaintResult`, `PageSize`, and the
|
|
104
|
+
`supportsCanvas` probe are tagged `@experimental` in the shipped types and
|
|
105
|
+
README: they ship ahead of their first production consumer (the designed
|
|
106
|
+
canvas live-preview path) and may change shape in any 0.x release.
|
|
107
|
+
`Engine.render` and `supportedFormats` are the stable surface.
|
|
108
|
+
- **WASM (typed error contract):** the root exports `QuillmarkError` — a
|
|
109
|
+
structural interface (`Error & { diagnostics: Diagnostic[] }`) naming the
|
|
110
|
+
shape every fallible method already throws — and an `isQuillmarkError(e)`
|
|
111
|
+
guard to narrow caught `unknown`s. No runtime behavior change: the WASM
|
|
112
|
+
layer still throws a plain `Error` with `diagnostics` attached (there is
|
|
113
|
+
deliberately no error class — a structural check works across builds and
|
|
114
|
+
WASM instances). Consumers can delete their hand-rolled
|
|
115
|
+
`.diagnostics`-extraction casts.
|
|
116
|
+
- **Breaking (Rust API + bindings):** a document's `$quill` reference is now
|
|
117
|
+
**enforced** against the loaded quill. Rendering with a quill whose *name*
|
|
118
|
+
differs (`quill::name_mismatch`) or whose *version* falls outside the selector
|
|
119
|
+
(`quill::version_mismatch`) is a hard error via the new
|
|
120
|
+
`RenderError::QuillMismatch`, in both `render` and `dry_run`. Previously a name
|
|
121
|
+
mismatch was only the `quill::ref_mismatch` warning and the version selector
|
|
122
|
+
was unchecked. See [migration guide](docs/migrations/0.88-to-0.89.md).
|
|
123
|
+
- **Fix (WASM bindings):** `Document.makeCard`'s generated TypeScript now marks
|
|
124
|
+
`fields` (and `body`) as optional (`fields?: Record<string, unknown>`,
|
|
125
|
+
`body?: string`), matching the doc comment and runtime behavior. They were
|
|
126
|
+
typed as required because `unchecked_param_type` drops the `?` marker; the
|
|
127
|
+
bindings now use `unchecked_optional_param_type`. Callers can build a bare
|
|
128
|
+
card with `Document.makeCard('kind')`.
|
|
129
|
+
|
|
3
130
|
## v0.88.0 - 2026-06-05
|
|
4
131
|
|
|
5
132
|
- **Breaking (bindings + Rust API):** a single canonical **`Card` wire shape** now
|
package/README.md
CHANGED
|
@@ -8,6 +8,20 @@ Maintained by [TTQ](https://tonguetoquill.com).
|
|
|
8
8
|
|
|
9
9
|
Use Quillmark in browsers/Node.js with explicit in-memory trees (`Map<string, Uint8Array>` / `Record<string, Uint8Array>`).
|
|
10
10
|
|
|
11
|
+
The package exposes **one import surface**:
|
|
12
|
+
|
|
13
|
+
- `@quillmark/wasm` (the root) — the **canonical API**: `Quill`, `Document`, and
|
|
14
|
+
an `Engine` that renders them.
|
|
15
|
+
|
|
16
|
+
`Quill` and `Document` are re-exported verbatim from the internal Typst-less
|
|
17
|
+
core build, so engine-free editor/validation code (`Quill.fromTree`,
|
|
18
|
+
`Document.fromMarkdown`) loads only that small core binary — no backend is
|
|
19
|
+
loaded until you render. The `Engine` hides everything else: each backend (Typst
|
|
20
|
+
today) is a separate, private WASM binary with its own linear memory, lazily
|
|
21
|
+
loaded on the first render. The Engine clones a `Quill` / `Document` into the
|
|
22
|
+
backend's memory as data and frees the clones — you never hold a backend object
|
|
23
|
+
or cross a memory boundary yourself.
|
|
24
|
+
|
|
11
25
|
## Build
|
|
12
26
|
|
|
13
27
|
```bash
|
|
@@ -29,10 +43,10 @@ npm test
|
|
|
29
43
|
## Usage
|
|
30
44
|
|
|
31
45
|
```ts
|
|
32
|
-
import { Document,
|
|
46
|
+
import { Document, Quill, Engine } from "@quillmark/wasm";
|
|
33
47
|
|
|
34
|
-
const
|
|
35
|
-
const
|
|
48
|
+
const quill = Quill.fromTree(tree); // engine-free: build + validate
|
|
49
|
+
const engine = new Engine(); // loads a backend lazily on first render
|
|
36
50
|
|
|
37
51
|
const markdown = `~~~
|
|
38
52
|
$quill: my_quill
|
|
@@ -43,16 +57,31 @@ title: My Document
|
|
|
43
57
|
# Hello`;
|
|
44
58
|
|
|
45
59
|
const parsed = Document.fromMarkdown(markdown);
|
|
46
|
-
const result =
|
|
60
|
+
const result = await engine.render(quill, parsed, { format: "pdf" });
|
|
47
61
|
```
|
|
48
62
|
|
|
49
63
|
## API
|
|
50
64
|
|
|
51
|
-
### `new
|
|
52
|
-
Create
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
65
|
+
### `new Engine(options?)`
|
|
66
|
+
Create the render dispatcher. Routes each quill to its backend by
|
|
67
|
+
`quill.backendId`, lazily loads that backend binary, and renders — cloning the
|
|
68
|
+
quill/document into the backend's memory and freeing the clones internally.
|
|
69
|
+
`render`, `open`, `supportedFormats`, and `supportsCanvas` are **async** (the
|
|
70
|
+
first call may load a backend). Pass `{ backends }` to register or override
|
|
71
|
+
backend descriptors. Each entry is a descriptor
|
|
72
|
+
(`{ [backendId]: { load, formats, canvas } }`) where `load` is the lazy thunk
|
|
73
|
+
returning the backend module and `formats`/`canvas` are the **required** static
|
|
74
|
+
capability manifest. A malformed descriptor throws at `new Engine(...)`, naming
|
|
75
|
+
the backend id.
|
|
76
|
+
|
|
77
|
+
**Capability probes are always free.** `supportedFormats` and `supportsCanvas`
|
|
78
|
+
depend only on `quill.backendId`, and answer from the descriptor's required
|
|
79
|
+
`formats`/`canvas` manifest — never loading the multi-MB backend binary and
|
|
80
|
+
never cloning the quill. Use them as non-failing pre-render probes.
|
|
81
|
+
|
|
82
|
+
### `Quill.fromTree(tree)`
|
|
83
|
+
Build + validate a `Quill` from an in-memory tree. Pure — the declared backend
|
|
84
|
+
is resolved at render time, not here. Loads no backend binary.
|
|
56
85
|
|
|
57
86
|
### `Document.fromMarkdown(markdown)`
|
|
58
87
|
Parse markdown to a parsed document. Throws a JS `Error` (with `.diagnostics`
|
|
@@ -206,18 +235,25 @@ There is one `Card` shape in both directions — `pushCard` / `insertCard` take
|
|
|
206
235
|
exactly what `cards` / `removeCard` / `seedCard` return. Build a fresh card
|
|
207
236
|
from a flat field map with `Document.makeCard(kind, fields?, body?)`.
|
|
208
237
|
|
|
209
|
-
### `
|
|
238
|
+
### `engine.render(quill, parsed, opts?)` vs. `engine.open(quill, parsed)`
|
|
239
|
+
|
|
240
|
+
> **Experimental:** the entire session surface — `engine.open`,
|
|
241
|
+
> `RenderSession`, `paint`, `PaintOptions`, `PaintResult`, `PageSize`, and the
|
|
242
|
+
> `supportsCanvas` probe — ships ahead of its first production consumer and
|
|
243
|
+
> may change shape in any 0.x release. `engine.render` is the stable path.
|
|
210
244
|
|
|
211
|
-
Use **`
|
|
212
|
-
artifacts, done. Use **`RenderSession`** (returned by `
|
|
213
|
-
reactive previews where
|
|
214
|
-
|
|
215
|
-
calls skip recompilation. Don't open
|
|
245
|
+
Use **`engine.render`** for one-shot exports (PDF/SVG/PNG) — compiles, emits
|
|
246
|
+
artifacts, done. Use **`RenderSession`** (returned by `engine.open`) for
|
|
247
|
+
reactive previews where
|
|
248
|
+
you'll paint or re-emit pages multiple times: the session retains the compiled
|
|
249
|
+
snapshot so subsequent `paint` / `render` calls skip recompilation. Don't open
|
|
250
|
+
a session per export.
|
|
216
251
|
|
|
217
|
-
### `
|
|
218
|
-
Render
|
|
252
|
+
### `engine.render(quill, parsed, opts?)`
|
|
253
|
+
Render a pre-parsed `Document` against `quill`. Throws `UnsupportedBackend` if
|
|
254
|
+
no registered backend matches the quill's declared backend.
|
|
219
255
|
|
|
220
|
-
### `
|
|
256
|
+
### `engine.open(quill, parsed)` + `session.render(opts?)`
|
|
221
257
|
Open once, render all or selected pages (`opts.pages`).
|
|
222
258
|
|
|
223
259
|
The session also exposes `pageCount`, `backendId`, `supportsCanvas`,
|
|
@@ -273,8 +309,8 @@ canvas.style.height = `${result.layoutHeight}px`;
|
|
|
273
309
|
`densityScale`. Loading the WASM module inside a Worker is the host's
|
|
274
310
|
responsibility.
|
|
275
311
|
- Backend support: gated by `supportsCanvas`. Probe upfront with
|
|
276
|
-
`
|
|
277
|
-
canvas-based UI; the throw on `paint` / `pageSize` remains the
|
|
312
|
+
`engine.supportsCanvas(quill)` (or `session.supportsCanvas`) before mounting
|
|
313
|
+
a canvas-based UI; the throw on `paint` / `pageSize` remains the
|
|
278
314
|
enforcement contract and includes the resolved `backendId` for
|
|
279
315
|
debugging.
|
|
280
316
|
|
|
@@ -287,7 +323,7 @@ A field's *cell* is inferred from whether its schema declares a `default:`:
|
|
|
287
323
|
(`validation::field_absent`) — the render path zero-fills it
|
|
288
324
|
silently. A surviving `<must-fill>` sentinel is fatal
|
|
289
325
|
(`validation::must_fill_sentinel`). Partial documents are
|
|
290
|
-
first-class; `
|
|
326
|
+
first-class; `engine.render(quill, doc)` only throws for malformed input.
|
|
291
327
|
- **Endorsed** (with `default:`) — `quill.blueprint` renders the
|
|
292
328
|
default value followed by a `; delete-ok` annotation, and the default
|
|
293
329
|
is used when the document omits the field.
|
|
@@ -299,12 +335,28 @@ code covers unreplaced sentinels.
|
|
|
299
335
|
|
|
300
336
|
### Errors
|
|
301
337
|
|
|
302
|
-
Every method that can fail throws a JS `Error` with
|
|
338
|
+
Every method that can fail throws a **`QuillmarkError`** — a JS `Error` with
|
|
339
|
+
`.diagnostics` attached. The type and a guard are exported from the root:
|
|
303
340
|
|
|
304
341
|
```ts
|
|
305
|
-
{
|
|
342
|
+
import { isQuillmarkError, type QuillmarkError } from "@quillmark/wasm";
|
|
343
|
+
|
|
344
|
+
try {
|
|
345
|
+
const result = await engine.render(quill, doc);
|
|
346
|
+
} catch (e) {
|
|
347
|
+
if (isQuillmarkError(e)) {
|
|
348
|
+
for (const d of e.diagnostics) console.error(d.severity, d.message);
|
|
349
|
+
} else {
|
|
350
|
+
throw e; // not a quillmark failure — programming error, re-throw
|
|
351
|
+
}
|
|
352
|
+
}
|
|
306
353
|
```
|
|
307
354
|
|
|
355
|
+
`QuillmarkError` is a **structural interface, not a class** — the WASM layer
|
|
356
|
+
throws a real `Error` and attaches the property, so there is no constructor to
|
|
357
|
+
`instanceof` against; narrow with `isQuillmarkError` (which also works on
|
|
358
|
+
errors from any build or WASM instance in the page).
|
|
359
|
+
|
|
308
360
|
`diagnostics` is always non-empty — length 1 for most failures, length N for
|
|
309
361
|
backend compilation errors. `message` is derived from `diagnostics`
|
|
310
362
|
(`diagnostics[0].message` for single-diagnostic errors; an aggregate
|
|
@@ -319,7 +371,7 @@ compilation failures. The same shape applies to every throw site:
|
|
|
319
371
|
variants (`InvalidFieldName`, `InvalidKindName`, `ReservedKind`,
|
|
320
372
|
`IndexOutOfRange`) appear in `diagnostics[0].message` with the
|
|
321
373
|
`[EditError::<Variant>]` prefix.
|
|
322
|
-
- `
|
|
374
|
+
- `engine.render` / `session.render` — backend compilation failures and
|
|
323
375
|
validation errors.
|
|
324
376
|
|
|
325
377
|
### Lifecycle
|
|
@@ -338,7 +390,7 @@ For environments where `using` (the [explicit resource management][erm]
|
|
|
338
390
|
proposal) hasn't landed, use an explicit `try` / `finally`:
|
|
339
391
|
|
|
340
392
|
```ts
|
|
341
|
-
const session =
|
|
393
|
+
const session = engine.open(quill, doc);
|
|
342
394
|
try {
|
|
343
395
|
for (let p = 0; p < session.pageCount; p++) {
|
|
344
396
|
session.paint(ctx, p);
|
|
@@ -356,8 +408,8 @@ try {
|
|
|
356
408
|
the legacy `~~~card-yaml` opener is still accepted but non-canonical)
|
|
357
409
|
with a `$quill` system-metadata line. Empty input surfaces a dedicated
|
|
358
410
|
"Empty markdown input cannot be parsed" message.
|
|
359
|
-
-
|
|
360
|
-
- Output schema APIs
|
|
411
|
+
- A `$quill` mismatch during `engine.render(quill, parsed)` is a thrown error, not a warning: rendering with a quill whose *name* differs (`quill::name_mismatch`) or whose *version* falls outside the selector (`quill::version_mismatch`) is rejected.
|
|
412
|
+
- Output schema APIs live on `Quill`, not the engine.
|
|
361
413
|
|
|
362
414
|
## Changelog
|
|
363
415
|
|
|
@@ -164,8 +164,9 @@ export interface QuillSchema {
|
|
|
164
164
|
|
|
165
165
|
/**
|
|
166
166
|
* Identity snapshot mirroring the `quill:` section of `Quill.yaml`.
|
|
167
|
-
* The schema lives on `Quill.schema
|
|
168
|
-
*
|
|
167
|
+
* The schema lives on `Quill.schema`; the backend's output formats are a
|
|
168
|
+
* resolved-backend capability read from the engine (`Quillmark.supportedFormats`),
|
|
169
|
+
* not part of this pure-config snapshot.
|
|
169
170
|
*/
|
|
170
171
|
export interface QuillMetadata {
|
|
171
172
|
name: string;
|
|
@@ -173,8 +174,6 @@ export interface QuillMetadata {
|
|
|
173
174
|
backend: string;
|
|
174
175
|
author: string;
|
|
175
176
|
description: string;
|
|
176
|
-
supportedFormats: OutputFormat[];
|
|
177
|
-
[key: string]: unknown;
|
|
178
177
|
}
|
|
179
178
|
|
|
180
179
|
|
|
@@ -282,7 +281,7 @@ export class Document {
|
|
|
282
281
|
* insertion order); `body` defaults to `""`. Kind validity is checked by
|
|
283
282
|
* `pushCard` / `insertCard`, not here.
|
|
284
283
|
*/
|
|
285
|
-
static makeCard(kind: string, fields
|
|
284
|
+
static makeCard(kind: string, fields?: Record<string, unknown>, body?: string): Card;
|
|
286
285
|
/**
|
|
287
286
|
* Move the card at `from` to position `to`. `from == to` is a no-op.
|
|
288
287
|
*/
|
|
@@ -445,8 +444,16 @@ export class Quill {
|
|
|
445
444
|
private constructor();
|
|
446
445
|
free(): void;
|
|
447
446
|
[Symbol.dispose](): void;
|
|
448
|
-
|
|
449
|
-
|
|
447
|
+
/**
|
|
448
|
+
* Build a quill from a file tree. Pure — no backend, no engine; the
|
|
449
|
+
* declared backend is resolved later, at render time.
|
|
450
|
+
*
|
|
451
|
+
* Accepts either a `Map<string, Uint8Array>` or a plain object
|
|
452
|
+
* (`Record<string, Uint8Array>`). Plain objects are walked via
|
|
453
|
+
* `Object.entries` at the boundary; the Rust side sees a single
|
|
454
|
+
* canonical shape.
|
|
455
|
+
*/
|
|
456
|
+
static fromTree(tree: Map<string, Uint8Array>): Quill;
|
|
450
457
|
/**
|
|
451
458
|
* Seed a starter composable `Card` of the given kind (carries `$kind`),
|
|
452
459
|
* committing its fields' `example:` values and leaving every other field
|
|
@@ -471,6 +478,19 @@ export class Quill {
|
|
|
471
478
|
* `Card` shape as the `Document.main` getter.
|
|
472
479
|
*/
|
|
473
480
|
seedMain(): Card;
|
|
481
|
+
/**
|
|
482
|
+
* Flatten this quill back into its canonical file tree — the inverse of
|
|
483
|
+
* [`fromTree`](Self::from_tree). Round-trips: `Quill.fromTree(q.toTree())`
|
|
484
|
+
* reproduces an equivalent quill.
|
|
485
|
+
*
|
|
486
|
+
* This is how a quill crosses a WASM linear-memory boundary as data: a
|
|
487
|
+
* `Quill` built in one build (e.g. the Typst-less `@quillmark/wasm/core`)
|
|
488
|
+
* cannot be passed to an engine in another (separate linear memories), so
|
|
489
|
+
* `@quillmark/wasm/runtime` re-feeds this tree to the backend build's
|
|
490
|
+
* `Quill.fromTree` on demand. Keys are `"/"`-joined relative paths,
|
|
491
|
+
* matching what `fromTree` accepts.
|
|
492
|
+
*/
|
|
493
|
+
toTree(): Map<string, Uint8Array>;
|
|
474
494
|
/**
|
|
475
495
|
* Validate `doc` against this quill's schema, returning every diagnostic
|
|
476
496
|
* (an empty array when the document is valid).
|
|
@@ -484,13 +504,17 @@ export class Quill {
|
|
|
484
504
|
*/
|
|
485
505
|
validate(doc: Document): Diagnostic[];
|
|
486
506
|
/**
|
|
487
|
-
* The
|
|
507
|
+
* The *declared* backend identifier (`config.backend`, e.g. `"typst"`).
|
|
508
|
+
* Intent, not a resolved capability — capability (`supportedFormats` /
|
|
509
|
+
* `supportsCanvas`) is read from the engine.
|
|
488
510
|
*/
|
|
489
511
|
readonly backendId: string;
|
|
490
512
|
readonly blueprint: string;
|
|
491
513
|
/**
|
|
492
|
-
* Identity snapshot of the `quill:` section of `Quill.yaml
|
|
493
|
-
* `
|
|
514
|
+
* Identity snapshot of the `quill:` section of `Quill.yaml` plus any extra
|
|
515
|
+
* `quill:` keys. Pure config — the backend's output formats are a
|
|
516
|
+
* resolved-backend capability read from the engine
|
|
517
|
+
* (`Quillmark.supportedFormats`), not part of this snapshot.
|
|
494
518
|
*/
|
|
495
519
|
readonly metadata: QuillMetadata;
|
|
496
520
|
/**
|
|
@@ -500,27 +524,38 @@ export class Quill {
|
|
|
500
524
|
* `QuillSchema` shape.
|
|
501
525
|
*/
|
|
502
526
|
readonly schema: QuillSchema;
|
|
503
|
-
/**
|
|
504
|
-
* `true` iff `RenderSession.paint` and `RenderSession.pageSize` will
|
|
505
|
-
* succeed for sessions opened by this quill. Use as a precondition
|
|
506
|
-
* probe before mounting a canvas-based preview UI.
|
|
507
|
-
*/
|
|
508
|
-
readonly supportsCanvas: boolean;
|
|
509
527
|
}
|
|
510
528
|
|
|
529
|
+
/**
|
|
530
|
+
* Render engine: a backend registry and render dispatcher. Render build only —
|
|
531
|
+
* the core build constructs and validates quills without it.
|
|
532
|
+
*/
|
|
511
533
|
export class Quillmark {
|
|
512
534
|
free(): void;
|
|
513
535
|
[Symbol.dispose](): void;
|
|
514
536
|
constructor();
|
|
515
537
|
/**
|
|
516
|
-
*
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
* `
|
|
521
|
-
*
|
|
538
|
+
* Open an iterative render session for `doc` against `quill`'s backend.
|
|
539
|
+
*/
|
|
540
|
+
open(quill: Quill, doc: Document): RenderSession;
|
|
541
|
+
/**
|
|
542
|
+
* Render `doc` against `quill` in one shot. Convenience over `open` +
|
|
543
|
+
* `RenderSession.render`: an unset `output_format` falls back to the
|
|
544
|
+
* backend's first supported format.
|
|
545
|
+
*/
|
|
546
|
+
render(quill: Quill, doc: Document, opts?: RenderOptions | null): RenderResult;
|
|
547
|
+
/**
|
|
548
|
+
* The output formats `quill`'s backend can emit. Static capability —
|
|
549
|
+
* resolves the backend but compiles nothing. Throws `UnsupportedBackend`
|
|
550
|
+
* if no registered backend matches the quill's declared backend.
|
|
551
|
+
*/
|
|
552
|
+
supportedFormats(quill: Quill): OutputFormat[];
|
|
553
|
+
/**
|
|
554
|
+
* `true` iff `quill`'s backend can paint sessions to a canvas. Asked of
|
|
555
|
+
* the real backend; `false` when the backend is unsupported or non-canvas.
|
|
556
|
+
* Use as a precondition probe before mounting a canvas-based preview UI.
|
|
522
557
|
*/
|
|
523
|
-
quill
|
|
558
|
+
supportsCanvas(quill: Quill): boolean;
|
|
524
559
|
}
|
|
525
560
|
|
|
526
561
|
/**
|
|
@@ -558,7 +593,8 @@ export class RenderSession {
|
|
|
558
593
|
readonly backendId: string;
|
|
559
594
|
readonly pageCount: number;
|
|
560
595
|
/**
|
|
561
|
-
* `true` iff `paint` and `pageSize` will succeed for this session.
|
|
596
|
+
* `true` iff `paint` and `pageSize` will succeed for this session. The
|
|
597
|
+
* backend's canvas capability, captured at open time.
|
|
562
598
|
*/
|
|
563
599
|
readonly supportsCanvas: boolean;
|
|
564
600
|
/**
|