@quillmark/wasm 0.98.0 → 0.99.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.
@@ -44,7 +44,7 @@ export interface Card {
44
44
  seed?: Record<string, unknown>;
45
45
  payloadItems: PayloadItem[];
46
46
  /**
47
- * The card body as canonical `Content` the source-of-truth content model.
47
+ * The card body as canonical `Content`: the source-of-truth content model.
48
48
  * Always this content shape on read, never a markdown string. For the markdown
49
49
  * projection call the codec `exportMarkdown(card.body)`. Write a body back
50
50
  * with `doc.install(addr, rt)` / `doc.revise(addr, md)`, or via `CardInput.body`.
@@ -53,10 +53,10 @@ export interface Card {
53
53
  }
54
54
 
55
55
  /**
56
- * A card written *into* a document the input twin of `Card`, accepted by
56
+ * A card written *into* a document: the input twin of `Card`, accepted by
57
57
  * `Document.insertCard`. Like `Card` but `body` also
58
58
  * takes a markdown `string` (imported to the content, so a markdown / LLM writer
59
- * needn't build the `Content` shape), and every field but `kind` is optional
59
+ * needn't build the `Content` shape), and every field but `kind` is optional:
60
60
  * an absent field defaults (no payload items, an empty body). Write one inline
61
61
  * (`{ kind, body }`) or build it with `Document.makeCard`.
62
62
  */
@@ -71,7 +71,7 @@ export interface CardInput {
71
71
  }
72
72
 
73
73
  /**
74
- * Canonical richtext content the content model for a card body (and richtext
74
+ * Canonical richtext content: the content model for a card body (and richtext
75
75
  * fields). One text sequence over a single coordinate space (Unicode scalar
76
76
  * values): `text` plus line attributes, anchored `marks`, and embedded
77
77
  * `islands`. Every edit is a splice; markdown is a projection, not the model.
@@ -95,7 +95,7 @@ export type ContentLine = {
95
95
  continues?: boolean;
96
96
  } & ContentLineKind;
97
97
 
98
- /** A line's block role, declared once for `ContentLine` and the `setKind` op
98
+ /** A line's block role, declared once for `ContentLine` and the `setKind` op:
99
99
  * a new role is one edit here, as for `ContentContainer`. */
100
100
  export type ContentLineKind =
101
101
  | { kind: "para" }
@@ -115,7 +115,7 @@ export type ContentContainer =
115
115
 
116
116
  /** A mark over char range `[start, end)` into `Content.text`. The open `type`
117
117
  * arm blocks discriminant narrowing (as on `ContentIsland`), so read a
118
- * payload-carrying arm behind its guard `isLinkMark` (`url`) / `isAnchorMark`
118
+ * payload-carrying arm behind its guard: `isLinkMark` (`url`) / `isAnchorMark`
119
119
  * (`id`), from `@quillmark/wasm/runtime`; the bare arms carry no payload. An
120
120
  * `anchor`'s `id` is a caller-supplied, opaque handle, unique per `Content` and
121
121
  * invariant while the mark lives (positions rebase, the id never does); it has no
@@ -128,7 +128,7 @@ export type ContentMark = { start: number; end: number } & (
128
128
  | { type: string; attrs: unknown }
129
129
  );
130
130
 
131
- /** A cell in a `TableProps` its plain `text` plus the `marks` over it. `marks`
131
+ /** A cell in a `TableProps`: its plain `text` plus the `marks` over it. `marks`
132
132
  * rides the same wire shape as prose `ContentMark`, but each mark's `start`/`end`
133
133
  * are USV offsets into this cell's `text` (`0..text.length`), not into
134
134
  * `Content.text`. */
@@ -156,12 +156,16 @@ export interface ImageProps {
156
156
  * open set: the engine pins `props` as `TableProps` for `table` and `ImageProps`
157
157
  * for `image`; an island of any other type round-trips with opaque `props`. Like
158
158
  * `ContentMark`, the open `type` arm means a discriminant check does not itself
159
- * narrow `props` read `props` as the matching shape behind the `isTableIsland` /
159
+ * narrow `props`: read `props` as the matching shape behind the `isTableIsland` /
160
160
  * `isImageIsland` guards (from `@quillmark/wasm/runtime`), which narrow it. */
161
+ /** How faithfully the markdown projection can carry an island. Open like an
162
+ * island `type`: a class this build does not know round-trips verbatim, and
163
+ * reads as `unrepresentable`. */
164
+ export type ContentLossClass = "lossless" | "degraded" | "unrepresentable" | (string & {});
165
+
161
166
  export type ContentIsland = {
162
167
  id: string;
163
- /** How faithfully the markdown projection can carry this island. */
164
- loss: "lossless" | "degraded" | "unrepresentable";
168
+ loss: ContentLossClass;
165
169
  } & (
166
170
  | { type: "table"; props: TableProps }
167
171
  | { type: "image"; props: ImageProps }
@@ -169,14 +173,14 @@ export type ContentIsland = {
169
173
  );
170
174
 
171
175
  /**
172
- * A write address one navigation concept for the whole `Document` surface. An
176
+ * A write address: one navigation concept for the whole `Document` surface. An
173
177
  * absent `field` targets the card body; an absent `card` targets the main card.
174
178
  * `{}` is the main-card body; `{ card: 2 }` the body of the composable card at
175
179
  * index 2; `{ field: "intro" }` the main card's `intro` field; `{ card: 2,
176
180
  * field: "intro" }` a card field.
177
181
  *
178
182
  * On the `Addr`-taking verbs a **bare string** is shorthand for `{ field: name }`
179
- * `doc.storeField("qty", 3)`, `doc.revise("intro", md)` the one coercion
183
+ * (`doc.storeField("qty", 3)`, `doc.revise("intro", md)`) the one coercion
180
184
  * rule. A bare number is *not* an addr (`{ card: 2 }` is the self-documenting
181
185
  * spelling), so no third navigation idiom re-fragments the surface.
182
186
  */
@@ -186,7 +190,7 @@ export interface Addr {
186
190
  }
187
191
 
188
192
  /**
189
- * A card-only address the axis the card-scoped verbs (`storeFields`,
193
+ * A card-only address: the axis the card-scoped verbs (`storeFields`,
190
194
  * `storeExt`, `getExt`, `commitFields`, …) take. An absent `card` targets the
191
195
  * main card. A present `field` throws: a card address takes only `card`, and a
192
196
  * would-be nested write is a bug the error names rather than silently ignores.
@@ -197,7 +201,7 @@ export interface CardAddr {
197
201
 
198
202
  /**
199
203
  * A text-splice change set over the USV content (CodeMirror `ChangeSet`
200
- * semantics) plain, structured-clone-able data. Returned by `revise` and by
204
+ * semantics): plain, structured-clone-able data. Returned by `revise` and by
201
205
  * the `rebase` codec; map a stored position through it with `mapPos`.
202
206
  */
203
207
  export interface Delta {
@@ -211,7 +215,7 @@ export type Assoc = "before" | "after";
211
215
  * A mark edit in final-text coordinates (post-delta, post-line-op). `add` /
212
216
  * `remove` carry the `ContentMark` vocabulary (`{ type, … }`); `removeAnchor`
213
217
  * drops one identity anchor by id. An `add` of an `anchor` requires a non-empty
214
- * `id` not already live in the field a collision or the empty id throws
218
+ * `id` not already live in the field: a collision or the empty id throws
215
219
  * (ids are caller-supplied and unique per `Content`; DOCUMENT_STORAGE
216
220
  * § Anchor-id identity).
217
221
  */
@@ -227,7 +231,7 @@ export type MarkOp =
227
231
  /**
228
232
  * A line/block edit. `split`/`join` splice `\n`; `setKind`/`setContainers`/
229
233
  * `setContinues` touch metadata. `setContinues` sets/clears a line's within-block
230
- * hard-break flag (`ContentLine.continues`) the op-grained way to lower a
234
+ * hard-break flag (`ContentLine.continues`): the op-grained way to lower a
231
235
  * Shift+Enter hard break or a new code-fence interior line; `continues: true` on
232
236
  * line 0 is rejected (nothing precedes it to continue).
233
237
  */
@@ -253,7 +257,7 @@ export interface ChangeBundle {
253
257
 
254
258
  /**
255
259
  * One segment of a parsed `Diagnostic.path` (see `parseDocPath`). The head
256
- * carries the document-model root `main` (only before `body`), a `card`
260
+ * carries the document-model root: `main` (only before `body`), a `card`
257
261
  * (`kind: null` is the unknown-kind `cards[i]` form), or a `field`; the tail is
258
262
  * `field` / `index` / a terminal `body`.
259
263
  */
@@ -268,7 +272,7 @@ export type DocPathSeg =
268
272
 
269
273
  /**
270
274
  * Page dimensions in points (1 pt = 1/72 inch). Typst measures in Typst
271
- * points; pdfform measures in PDF points the same unit.
275
+ * points; pdfform measures in PDF points: the same unit.
272
276
  *
273
277
  * Report-only: the painter sizes the canvas itself based on
274
278
  * `PaintOptions`. `pageSize` is exposed for callers that need page
@@ -284,16 +288,16 @@ export interface PageSize {
284
288
  * Inputs to `LiveSession.paint`. Both fields are optional and default
285
289
  * to `1`.
286
290
  *
287
- * - `layoutScale` layout-space pixels per point (Typst point / PDF
288
- * point the same 1/72″ unit). For on-screen
291
+ * - `layoutScale` (layout-space pixels per point (Typst point / PDF
292
+ * point) the same 1/72″ unit). For on-screen
289
293
  * canvases this is CSS pixels per pt; the page's layout-pixel size is
290
294
  * `widthPt * layoutScale × heightPt * layoutScale`. The painter
291
295
  * surfaces these dimensions as `layoutWidth` / `layoutHeight` so
292
296
  * consumers can drive `canvas.style.*` (or any layout system).
293
- * - `densityScale` backing-store density multiplier. Fold
297
+ * - `densityScale`: backing-store density multiplier. Fold
294
298
  * `window.devicePixelRatio`, in-app zoom, and `visualViewport.scale`
295
299
  * (pinch-zoom) into a single value here. Defaults to `1`, which
296
- * produces a non-retina backing store pass `window.devicePixelRatio`
300
+ * produces a non-retina backing store: pass `window.devicePixelRatio`
297
301
  * for crisp output on high-DPI displays.
298
302
  *
299
303
  * The effective rasterization scale is `layoutScale * densityScale`.
@@ -309,22 +313,22 @@ export interface PaintOptions {
309
313
  /**
310
314
  * Returned by `LiveSession.paint`.
311
315
  *
312
- * - `layoutWidth` / `layoutHeight` layout-pixel dimensions of the
316
+ * - `layoutWidth` / `layoutHeight`: layout-pixel dimensions of the
313
317
  * canvas's display box. For on-screen canvases this is CSS pixels:
314
318
  * set `canvas.style.width = layoutWidth + "px"` and
315
319
  * `canvas.style.height = layoutHeight + "px"` (or feed these into
316
320
  * your layout system). Independent of `densityScale`.
317
- * - `pixelWidth` / `pixelHeight` integer backing-store pixel
321
+ * - `pixelWidth` / `pixelHeight`: integer backing-store pixel
318
322
  * dimensions the painter wrote to `canvas.width` / `canvas.height`.
319
323
  * Equal to `round(layoutWidth * densityScale)` ×
320
324
  * `round(layoutHeight * densityScale)` *unless* the requested backing
321
325
  * exceeded the painter's safe maximum (16384 px per side), in which
322
326
  * case `densityScale` was clamped to fit.
323
- * - `clamped` `true` when that 16384-px clamp fired, so the page is
327
+ * - `clamped`: `true` when that 16384-px clamp fired, so the page is
324
328
  * painted at fewer device pixels than requested and renders soft at the
325
329
  * same `canvas.style` size. Reads the clamp off the return value instead
326
330
  * of the `pixelWidth < round(layoutWidth * densityScale)` derivation.
327
- * - `effectiveDensityScale` the `densityScale` actually applied: the
331
+ * - `effectiveDensityScale`, the `densityScale` actually applied: the
328
332
  * requested value unless `clamped`, then reduced proportionally.
329
333
  * `layoutScale * effectiveDensityScale` is the scale the backing store
330
334
  * was rasterized at.
@@ -333,11 +337,11 @@ export interface PaintOptions {
333
337
  * write to them. The painter does **not** touch `canvas.style.*`;
334
338
  * consumers own layout. The write is a whole-backing-store `putImageData`,
335
339
  * which bypasses the 2D context transform, `globalAlpha`, and clip: give
336
- * each visible page its own `` you cannot composite two pages, a
340
+ * each visible page its own `<canvas>`; you cannot composite two pages, a
337
341
  * sub-rect, or a context transform through `paint`.
338
342
  *
339
343
  * For `OffscreenCanvasRenderingContext2D` (Worker rasterization, no
340
- * DOM), `layoutWidth` / `layoutHeight` are informational there's no
344
+ * DOM), `layoutWidth` / `layoutHeight` are informational: there's no
341
345
  * CSS layout box to apply them to.
342
346
  */
343
347
  export interface PaintResult {
@@ -356,7 +360,7 @@ export type FieldSource = "authored" | "default" | "zero";
356
360
 
357
361
  /**
358
362
  * One resolved row: its `name`, the value the render projection would use, and
359
- * the `FieldSource` rung it came from. Rows are an ordered array declaration
363
+ * the `FieldSource` rung it came from. Rows are an ordered array: declaration
360
364
  * order is structural, not object-key order. The card body is a `body` sibling
361
365
  * on its card, never a row in `fields`. Diagnostics stay `Quill.validate`'s;
362
366
  * schema guidance (`example:`, labels) reads from `Quill.schema`.
@@ -368,7 +372,7 @@ export interface ResolvedField {
368
372
  }
369
373
 
370
374
  /**
371
- * The main card's resolved rows in declaration order, plus its body row
375
+ * The main card's resolved rows in declaration order, plus its body row:
372
376
  * `null` when the main enables no body.
373
377
  */
374
378
  export interface ResolvedMain {
@@ -379,7 +383,7 @@ export interface ResolvedMain {
379
383
  /**
380
384
  * One composable card's resolved rows in declaration order, with its authored
381
385
  * `kind` (`null` for an unknown-kind card), its document-array `index`, and its
382
- * body row `null` when the kind enables no body.
386
+ * body row: `null` when the kind enables no body.
383
387
  */
384
388
  export interface ResolvedCard {
385
389
  kind: string | null;
@@ -390,7 +394,7 @@ export interface ResolvedCard {
390
394
 
391
395
  /**
392
396
  * The resolved-value view (`Quill.resolve`): the main card and every
393
- * composable card. Value and provenance only completeness and errors stay
397
+ * composable card. Value and provenance only: completeness and errors stay
394
398
  * `Quill.validate`.
395
399
  */
396
400
  export interface Resolved {
@@ -411,7 +415,7 @@ export interface QuillFieldUi {
411
415
  }
412
416
 
413
417
  /** One entry in a card's `ui.groups` registry: a display-label override for the
414
- * group id (the map key). An empty object carries no override the consumer
418
+ * group id (the map key). An empty object carries no override: the consumer
415
419
  * derives the label from the id (`memo_for` → "Memo For"), as it does a field
416
420
  * label from its key. */
417
421
  export interface QuillGroupUi {
@@ -423,7 +427,7 @@ export interface QuillCardUi {
423
427
  title?: string;
424
428
  /** The card's group registry: the ordered table of contents naming every
425
429
  * group a field's `ui.group` may reference. The map key is the group id, and
426
- * key order is declaration order the display-order contract, the same one
430
+ * key order is declaration order: the display-order contract, the same one
427
431
  * `fields` key order carries. Absent when the card declares no groups (or
428
432
  * uses the deprecated implicit-group form). */
429
433
  groups?: Record<string, QuillGroupUi>;
@@ -461,7 +465,7 @@ export interface QuillFieldSchema {
461
465
  properties?: Record<string, QuillFieldSchema>;
462
466
  items?: QuillFieldSchema;
463
467
  /** Present (and `true`) on a `richtext` or `plaintext` field declared
464
- * `inline` the single-paragraph, container-free, island-free constraint.
468
+ * `inline`: the single-paragraph, container-free, island-free constraint.
465
469
  * Core serializes `inline: true` into the schema JSON; absent otherwise. */
466
470
  inline?: boolean;
467
471
  }
@@ -502,67 +506,205 @@ export interface QuillMetadata {
502
506
  }
503
507
 
504
508
 
505
- export interface Artifact {
506
- format: OutputFormat;
507
- bytes: Uint8Array;
508
- mimeType: string;
509
- }
510
-
511
- export interface ChangeSet {
512
- pageCount: number;
513
- dirtyPages: number[];
509
+ /**
510
+ * A rendered field region: the quill schema field address plus its geometry on
511
+ * the page. Emitted for schema-bound fields: span-tracked content (richtext
512
+ * bodies, `richtext[]` elements, card content fields, direct scalar
513
+ * references) and form-field widgets (pdfform AcroForm, Typst `form-field`).
514
+ * Consumers use it to scroll to / highlight the focused field; for the
515
+ * reverse click direction use `LiveSession.fieldAt`, which answers over any
516
+ * placement. Geometry only: the raster is already complete, so a region is
517
+ * never a compositing input.
518
+ *
519
+ * `field` is **not** unique: content fields surface one region **per segment**
520
+ * (paragraph, heading, whole code fence) and per page each touches, a scalar
521
+ * referenced at several plate sites surfaces each site, and tracked content
522
+ * plus a `field:`-bound widget yields both. Group by `field`: every entry
523
+ * routes to that field. The whole-field highlight is the **union of a page\'s
524
+ * `span`-bearing segment rects**, so inter-paragraph whitespace stays
525
+ * uncovered; `LiveSession.fieldBoxes(field)` owns that union so
526
+ * consumers need not derive it. Later placements of one content value are not
527
+ * enumerated; `fieldAt` / `positionAt` still resolve clicks on them.
528
+ */
529
+ export interface FieldRegion {
530
+ /**
531
+ * Canonical `DocPath` field address (e.g. `\"signature_block\"`,
532
+ * `\"cards.indorsement[1].from\"`, `\"main.body\"`): the same grammar
533
+ * `parseDocPath` reads and `Diagnostic.path` carries. The session resolves
534
+ * the backend\'s plate-space per-kind ordinal to this absolute-index form,
535
+ * so one parser routes every address. Feed it back to `fieldBoxes` /
536
+ * `locate`; hit-test the click direction with `fieldAt` / `positionAt`.
537
+ */
538
+ field: string;
539
+ /**
540
+ * 0-based page index.
541
+ */
542
+ page: number;
543
+ /**
544
+ * `[x0, y0, x1, y1]` in PDF points (1/72″), bottom-left origin.
545
+ */
546
+ rect: [number, number, number, number];
547
+ /**
548
+ * The content slice this box covers: USV `[start, end)` into the field\'s
549
+ * `Content` for content ink (one segment), `undefined` for a scalar
550
+ * reference site or widget. Consumers key segment highlights on it;
551
+ * `fieldBoxes(field)` unions same-page segments for the whole-field box.
552
+ */
553
+ span?: [number, number];
514
554
  }
515
555
 
556
+ /**
557
+ * A resolved point → content position: the field a click landed in and the USV
558
+ * offset into its `Content`. The `LiveSession.positionAt` result, paired with
559
+ * `locate` (content position → caret rect). `pos` is cluster-exact and degrades
560
+ * to the containing segment\'s start on origin-less ink; `granularity` reports
561
+ * which happened so a caret UI need not guess.
562
+ */
516
563
  export interface ContentHit {
564
+ /**
565
+ * Canonical `DocPath` field address (same grammar as `FieldRegion.field`).
566
+ */
517
567
  field: string;
568
+ /**
569
+ * USV offset into the field\'s `Content`.
570
+ */
518
571
  pos: number;
572
+ /**
573
+ * Whether `pos` is cluster-exact or floored to the segment start
574
+ * (`HitGranularity`). `undefined` when the backend does not report it.
575
+ * Additive-optional.
576
+ */
519
577
  granularity?: HitGranularity;
520
578
  }
521
579
 
580
+ /**
581
+ * Diagnostic message (error or warning)
582
+ */
522
583
  export interface Diagnostic {
523
584
  severity: Severity;
524
585
  code?: string;
525
586
  message: string;
526
587
  location?: Location;
588
+ /**
589
+ * Document-model path anchor (e.g. `\"cards.indorsement[0].signature_block\"`).
590
+ *
591
+ * Set on schema validation diagnostics; `undefined` otherwise. See the
592
+ * Rust `quillmark_core::error` module docs for the path grammar.
593
+ */
527
594
  path?: string;
528
595
  hint?: string;
529
596
  sourceChain?: string[];
530
597
  }
531
598
 
532
- export interface FieldRegion {
533
- field: string;
534
- page: number;
535
- rect: [number, number, number, number];
536
- span?: [number, number];
537
- }
538
-
539
- export interface Location {
540
- file: string;
541
- line: number;
542
- column: number;
543
- }
599
+ /**
600
+ * How precisely a `ContentHit.pos` resolved: the marker a caret UI reads to
601
+ * decide whether to trust the offset. Never sub-cluster: `cluster` is the
602
+ * finest this API offers, `segment` the floor it degrades to on origin-less
603
+ * ink.
604
+ */
605
+ export type HitGranularity = "cluster" | "segment";
544
606
 
607
+ /**
608
+ * Options for rendering.
609
+ */
545
610
  export interface RenderOptions {
546
611
  format?: OutputFormat;
612
+ /**
613
+ * Pixels per inch for raster output formats (PNG).
614
+ * Ignored for vector/document formats (PDF, SVG).
615
+ * Defaults to 144.0 (2x at 72pt/inch) when omitted.
616
+ */
547
617
  ppi?: number;
618
+ /**
619
+ * Optional 0-based page indices to render (e.g., `[0, 2]` for the
620
+ * first and third pages). `undefined` renders all pages. Any index
621
+ * `>= pageCount` throws with the `typst::page_index_out_of_bounds`
622
+ * code: read `LiveSession.pageCount` first if validation is needed.
623
+ * **Not supported for PDF output**: passing `pages` with
624
+ * `format: \"pdf\"` throws with the
625
+ * `typst::pdf_page_selection_not_supported` code.
626
+ */
548
627
  pages?: number[];
628
+ /**
629
+ * Override for the PDF `/Info` `/Producer` metadata string. Omit to use
630
+ * the default (`Quillmark <version>`). Applies to PDF output only.
631
+ */
549
632
  producer?: string;
633
+ /**
634
+ * Populate `RenderResult.regions` with the schema-field geometry sidecar
635
+ * (the same entries `LiveSession.regions()` serves), for consumers
636
+ * without a live session; e.g. overlays over a one-shot SVG export.
637
+ * Defaults to `false`: exports pay no introspection cost. The sidecar
638
+ * always describes the whole document: page indices are document-space
639
+ * even when `pages` selects a subset.
640
+ */
550
641
  regions?: boolean;
551
642
  }
552
643
 
644
+ /**
645
+ * Output formats supported by backends.
646
+ *
647
+ * Gated behind the engine surface (`typst` or `pdfform`) so tsify omits
648
+ * its `.d.ts` interface from the core bundle (`pkg/core/wasm.d.ts`), which
649
+ * has no rendering surface.
650
+ */
651
+ export type OutputFormat = "pdf" | "svg" | "png";
652
+
653
+ /**
654
+ * Rendered artifact (PDF, SVG, etc.).
655
+ */
656
+ export interface Artifact {
657
+ format: OutputFormat;
658
+ /**
659
+ * Serialized via `serde_bytes` so `serde_wasm_bindgen` emits a real
660
+ * `Uint8Array` at the boundary instead of a `number[]`. Without this
661
+ * annotation, the declared `Uint8Array` type would silently lie.
662
+ */
663
+ bytes: Uint8Array;
664
+ mimeType: string;
665
+ }
666
+
667
+ /**
668
+ * Result of a render operation.
669
+ */
553
670
  export interface RenderResult {
554
671
  artifacts: Artifact[];
555
672
  warnings: Diagnostic[];
556
673
  outputFormat: OutputFormat;
557
674
  renderTimeMs: number;
675
+ /**
676
+ * Schema-field geometry sidecar: populated only when
677
+ * `RenderOptions.regions` requested it; empty otherwise. The same entries
678
+ * `LiveSession.regions()` serves, for consumers without a live session.
679
+ * Page indices are document-space even under a `pages` subset render.
680
+ */
558
681
  regions: FieldRegion[];
559
682
  }
560
683
 
561
- export type HitGranularity = "cluster" | "segment";
684
+ /**
685
+ * Severity levels for diagnostics
686
+ */
687
+ export type Severity = "error" | "warning";
562
688
 
563
- export type OutputFormat = "pdf" | "svg" | "png";
689
+ /**
690
+ * Source location for errors and warnings
691
+ */
692
+ export interface Location {
693
+ file: string;
694
+ line: number;
695
+ column: number;
696
+ }
564
697
 
565
- export type Severity = "error" | "warning";
698
+ /**
699
+ * What a committed `LiveSession.apply` changed. `dirtyPages` lists the pages
700
+ * whose rendered content differs from the previous compile, including pages
701
+ * the edit added; removed pages are implied by `pageCount`. A preview
702
+ * repaints `dirty ∩ visible` and nothing else.
703
+ */
704
+ export interface ChangeSet {
705
+ pageCount: number;
706
+ dirtyPages: number[];
707
+ }
566
708
 
567
709
 
568
710
  /**
@@ -573,7 +715,7 @@ export class Document {
573
715
  [Symbol.dispose](): void;
574
716
  /**
575
717
  * **Apply** a committed content edit `bundle` (`{ delta?, lineOps?, markOps? }`)
576
- * at `addr` the editor splice: text delta first, then line ops, then mark
718
+ * at `addr`, the editor splice: text delta first, then line ops, then mark
577
719
  * ops (mark ranges in final-text coordinates), each all-or-nothing. An absent
578
720
  * `addr.field` targets the body, an absent `addr.card` the main card.
579
721
  *
@@ -590,7 +732,7 @@ export class Document {
590
732
  */
591
733
  static blueprintInstruction(quill_name: string): string;
592
734
  /**
593
- * A single composable card by index the whole `Card`, the card-indexed
735
+ * A single composable card by index: the whole `Card`, the card-indexed
594
736
  * twin of the [`main`](Self::main) getter, so reading one card need not
595
737
  * materialize every card via [`cards`](Self::cards). An out-of-range
596
738
  * `index` throws `edit::index_out_of_range`, matching the card write
@@ -645,54 +787,54 @@ export class Document {
645
787
  static fromMarkdown(markdown: string): Document;
646
788
  /**
647
789
  * The whole `$ext` map at `addr` (a card address, absent `card` = main), or
648
- * `undefined` when the card carries none. The fine-grained `$ext` read
790
+ * `undefined` when the card carries none. The fine-grained `$ext` read:
649
791
  * your own state without serializing the whole card. Throws on a present
650
792
  * `field` (a card address takes only `card`) or an out-of-range card.
651
793
  */
652
794
  getExt(addr?: CardAddr): Record<string, unknown> | undefined;
653
795
  /**
654
796
  * The value stored under `$ext[ns]` at `addr` (a card address, absent `card`
655
- * = main), or `undefined`. The namespace-scoped `$ext` read your own slot
797
+ * = main), or `undefined`. The namespace-scoped `$ext` read: your own slot
656
798
  * without a whole-card serialize, and non-destructive (unlike
657
799
  * `removeExtNamespace`). Throws on a present `field` or an out-of-range card.
658
800
  */
659
801
  getExtNamespace(addr: CardAddr, ns: string): unknown;
660
802
  /**
661
- * The **body** markdown projection the main body, or a composable card's
662
- * body (`{ card }`) the on-demand, lossy export (content-only marks do not
803
+ * The **body** markdown projection (the main body, or a composable card's
804
+ * body (`{ card }`)) the on-demand, lossy export (content-only marks do not
663
805
  * survive markdown). A body's type is a format fact, not a schema fact, so
664
806
  * this read stays quill-free; a body is never absent.
665
807
  *
666
808
  * `addr` is an optional **card address** (`{ card }`, absent = main). A
667
- * present `field` throws a field's markdown is read through the
809
+ * present `field` throws: a field's markdown is read through the
668
810
  * schema-plane `quill.reader(doc).get(field)`, which interprets by declared
669
- * type (#978). An out-of-range `addr.card` throws.
811
+ * type. An out-of-range `addr.card` throws.
670
812
  */
671
813
  getMarkdown(addr?: CardAddr): string;
672
814
  /**
673
- * Read the **verbatim stored value** at `addr` the raw payload value of a
815
+ * Read the **verbatim stored value** at `addr`: the raw payload value of a
674
816
  * field (a content object for a richtext field, a scalar/array/object
675
817
  * otherwise), or the **body content** when `addr.field` is absent. A bare
676
818
  * string is `Addr` shorthand for `{ field }`. Reads are total over the field
677
819
  * axis: an absent field is `undefined`; only an out-of-range `addr.card`
678
820
  * throws `edit::index_out_of_range`. Needs no schema, so it lives on
679
- * `Document` the read echo of the verbatim `store*` write, distinct from
821
+ * `Document`: the read echo of the verbatim `store*` write, distinct from
680
822
  * the interpreted schema-plane [`reader.get`](Self::reader_get). For the
681
823
  * markdown projection use [`getMarkdown`](Self::get_markdown) (body) or
682
824
  * `reader.get` (a field's declared type).
683
825
  */
684
826
  getStored(addr: Addr | string): unknown;
685
827
  /**
686
- * Insert a card the single insertion verb: `at` absent appends, a number
828
+ * Insert a card, the single insertion verb: `at` absent appends, a number
687
829
  * inserts at that index (must be in `0..=cards.length`). Accepts a
688
- * `CardInput` a card read back (`cards` / `removeCard` / `quill.seedCard`),
830
+ * `CardInput`: a card read back (`cards` / `removeCard` / `quill.seedCard`),
689
831
  * a [`makeCard`](Document::make_card) result, or a bare `{ kind, body }`
690
832
  * (every returned `Card` is a valid `CardInput`). Throws if `card.kind` is
691
833
  * not a valid kind name, or if `at` is out of range.
692
834
  */
693
835
  insertCard(card: CardInput, at?: number): void;
694
836
  /**
695
- * **Install** a richtext value at `addr` **value semantics**, content only.
837
+ * **Install** a richtext value at `addr`: **value semantics**, content only.
696
838
  * Stores exactly `rt` (a canonical `Content` content object); the identity
697
839
  * anchors of any previous value are gone. An absent `addr.field` targets the
698
840
  * body, an absent `addr.card` the main card. For "here's new markdown," use
@@ -706,25 +848,25 @@ export class Document {
706
848
  install(addr: Addr | string, rt: Content): void;
707
849
  /**
708
850
  * Whether the field at `addr` is marked `!must_fill`. A bare string is `Addr`
709
- * shorthand for `{ field }`. `false` for an absent field (truthful it isn't
851
+ * shorthand for `{ field }`. `false` for an absent field (truthful: it isn't
710
852
  * marked) and for a body address (a body is never a fill). Only an
711
853
  * out-of-range `addr.card` throws.
712
854
  */
713
855
  isFill(addr: Addr | string): boolean;
714
856
  /**
715
857
  * Replace this document's contents **in place** from a versioned storage
716
- * DTO string the mutating twin of the static
858
+ * DTO string: the mutating twin of the static
717
859
  * [`fromJson`](Document::from_json) constructor. Parse-time `warnings` are
718
860
  * cleared. Throws (leaving the document unchanged) on an invalid DTO.
719
861
  *
720
862
  * The cross-WASM-memory `Document` bridge: mutate a document on a
721
863
  * backend-memory clone, then write the mutated state back into the caller's
722
- * canonical document with this the one way to update a live handle across
864
+ * canonical document with this, the one way to update a live handle across
723
865
  * the linear-memory seam without the caller re-binding its variable.
724
866
  */
725
867
  loadJson(json: string): void;
726
868
  /**
727
- * Build a fresh `Card` from a kind and a flat field map the ergonomic
869
+ * Build a fresh `Card` from a kind and a flat field map: the ergonomic
728
870
  * constructor for `insertCard`. `fields` is an optional
729
871
  * `Record<string, unknown>` (each entry becomes a card field, in
730
872
  * insertion order); `body` defaults to `""`.
@@ -734,8 +876,8 @@ export class Document {
734
876
  * here.
735
877
  *
736
878
  * Checks only what a detached card can decide alone: field-name grammar
737
- * and value depth. Kind validity is positional `main` is right for the
738
- * root, reserved for a composable card so `insertCard` is its gate, and
879
+ * and value depth. Kind validity is positional (`main` is right for the
880
+ * root, reserved for a composable card) so `insertCard` is its gate, and
739
881
  * any kind string is accepted here.
740
882
  */
741
883
  static makeCard(kind: string, fields?: Record<string, unknown>, body?: string): Card;
@@ -744,7 +886,7 @@ export class Document {
744
886
  */
745
887
  moveCard(from: number, to: number): void;
746
888
  /**
747
- * `new Document(quillRef)` a blank document: a main card carrying only
889
+ * `new Document(quillRef)`, a blank document: a main card carrying only
748
890
  * `$quill`, an empty body, and no composable cards. The programmatic
749
891
  * blank canvas: absent fields resolve at render time (`default`, else
750
892
  * type-empty zero), so nothing the caller did not set reaches the
@@ -755,7 +897,7 @@ export class Document {
755
897
  /**
756
898
  * The canonical `$quill` reference grammar as author-facing text. Core is
757
899
  * the single source of truth: drive schema `describe` and validation
758
- * messages from this instead of re-stating the rule it matches the
900
+ * messages from this instead of re-stating the rule; it matches the
759
901
  * `hint` on `parse::invalid_quill_reference`. Cache it; the value never
760
902
  * changes.
761
903
  */
@@ -763,7 +905,7 @@ export class Document {
763
905
  removeCard(index: number): Card | undefined;
764
906
  /**
765
907
  * Remove the `$ext` map on the card `addr` targets *entirely*, returning the
766
- * previous map or `undefined` a blunt escape hatch that discards every
908
+ * previous map or `undefined`: a blunt escape hatch that discards every
767
909
  * namespace at once (prefer `removeExtNamespace`). `addr` is a card address
768
910
  * (absent = main). Throws on a present `field` or an out-of-range card.
769
911
  */
@@ -789,7 +931,7 @@ export class Document {
789
931
  */
790
932
  removeSeedNamespace(card_kind: string): any;
791
933
  /**
792
- * **Revise** the richtext value at `addr` from a markdown string **edit
934
+ * **Revise** the richtext value at `addr` from a markdown string: **edit
793
935
  * semantics**, the default write path, returning the text `Delta`. Imports
794
936
  * the markdown, diffs it against the current value, rebases surviving
795
937
  * identity anchors, and returns the change an editor bridge maps its own
@@ -802,7 +944,7 @@ export class Document {
802
944
  revise(addr: Addr | string, markdown: string): Delta;
803
945
  /**
804
946
  * Read the `schema` version tag from a raw storage DTO string without a
805
- * full parse, or `undefined`. Returns unknown future versions as-is
947
+ * full parse, or `undefined`. Returns unknown future versions as-is:
806
948
  * useful to distinguish "build too old" from "payload corrupt" when
807
949
  * `fromJson` throws.
808
950
  */
@@ -811,7 +953,7 @@ export class Document {
811
953
  * The main card's `$seed` overlay object for `kind` (the `$seed[kind]`
812
954
  * entry), or `undefined` when absent. The cheap read that feeds
813
955
  * `quill.seedCard(kind, overlay)` without serializing the whole main card
814
- * via [`main`](Self::main) to fish out one key and it keeps `seedCard`
956
+ * via [`main`](Self::main) to fish out one key, and it keeps `seedCard`
815
957
  * pure: the quill still never reads the document.
816
958
  */
817
959
  seedOverlay(kind: string): Record<string, unknown> | undefined;
@@ -829,41 +971,41 @@ export class Document {
829
971
  * Replace the opaque `$ext` map on the card `addr` targets (a card address,
830
972
  * absent `card` = main). `value` must be a plain object. `$ext` carries
831
973
  * out-of-band consumer state and never reaches the rendered output; pass
832
- * `{}` for an explicit empty `$ext`. Quill-free and verbatim an opaque
974
+ * `{}` for an explicit empty `$ext`. Quill-free and verbatim: an opaque
833
975
  * `store` verb. Throws on a present `field` or an out-of-range card.
834
976
  */
835
977
  storeExt(addr: CardAddr, value: any): void;
836
978
  /**
837
979
  * Merge `value` into `$ext[ns]` on the card `addr` targets, preserving
838
- * sibling namespaces the recommended `$ext` write. `addr` is a card
839
- * address (absent = main). Quill-free and verbatim an opaque `store` verb.
980
+ * sibling namespaces: the recommended `$ext` write. `addr` is a card
981
+ * address (absent = main). Quill-free and verbatim: an opaque `store` verb.
840
982
  * Throws on a present `field` or an out-of-range card.
841
983
  */
842
984
  storeExtNamespace(addr: CardAddr, ns: string, value: any): void;
843
985
  /**
844
- * Store a field verbatim at `addr` the opaque store (**store** = verbatim,
986
+ * Store a field verbatim at `addr`: the opaque store (**store** = verbatim,
845
987
  * coercion deferred to render; the typed write is
846
988
  * [`commitField`](Document::commit_field)). A bare string is `Addr`
847
989
  * shorthand for `{ field }`, so `doc.storeField("qty", 3)` reads as written;
848
990
  * `{ card: 2, field: "qty" }` targets a composable card. Clears any
849
- * `!must_fill` marker. A body address (no `field`) throws a body is never
991
+ * `!must_fill` marker. A body address (no `field`) throws: a body is never
850
992
  * opaque; write it with `revise` / `install` / `writer.setBody`. Throws on
851
993
  * an out-of-range card or a malformed name.
852
994
  */
853
995
  storeField(addr: Addr | string, value: any): void;
854
996
  /**
855
- * Store several fields verbatim and atomically on the card `addr` targets
997
+ * Store several fields verbatim and atomically on the card `addr` targets:
856
998
  * the opaque store's batch. `addr` is a **card address** (`{ card }`, absent
857
999
  * = main); a present `field` throws. The batch verb takes the address first
858
1000
  * and is never shape-overloaded, because `card` is a legal field name:
859
1001
  * `storeFields({}, fields)` is the main card, `storeFields({ card: 2 },
860
- * fields)` a composable one never ambiguous with "set field `card`".
1002
+ * fields)` a composable one, never ambiguous with "set field `card`".
861
1003
  * Nothing is applied on error; the thrown error's `diagnostics` carry one
862
1004
  * entry per offending field. Throws on an out-of-range card.
863
1005
  */
864
1006
  storeFields(addr: CardAddr, fields: Record<string, unknown>): void;
865
1007
  /**
866
- * Store a field verbatim at `addr` and mark it `!must_fill` the opaque
1008
+ * Store a field verbatim at `addr` and mark it `!must_fill`: the opaque
867
1009
  * store's fill variant, card-capable (a bare string or `{ field }` for main,
868
1010
  * `{ card, field }` for a composable card). A body address throws. Same
869
1011
  * validation as [`storeField`](Document::store_field).
@@ -871,9 +1013,9 @@ export class Document {
871
1013
  storeFill(addr: Addr | string, value: any): void;
872
1014
  /**
873
1015
  * Merge a card-kind's seed `overlay` into the **main** card's `$seed` map
874
- * under `cardKind`, preserving sibling kinds `$seed` lives on the main
1016
+ * under `cardKind`, preserving sibling kinds: `$seed` lives on the main
875
1017
  * card by model, so this takes no address. Sets the starting values new
876
- * cards of that kind spawn with. Quill-free and verbatim an opaque `store`
1018
+ * cards of that kind spawn with. Quill-free and verbatim: an opaque `store`
877
1019
  * verb. Throws if `overlay` cannot be serialized or nests too deep.
878
1020
  */
879
1021
  storeSeedNamespace(card_kind: string, overlay: any): void;
@@ -881,7 +1023,7 @@ export class Document {
881
1023
  * Serialize this document to a versioned storage DTO string.
882
1024
  *
883
1025
  * Prefer this over `toMarkdown` for persistence across restarts or crate
884
- * upgrades the wire format is frozen per `schema` version. Parse-time
1026
+ * upgrades: the wire format is frozen per `schema` version. Parse-time
885
1027
  * `warnings` are excluded from the DTO.
886
1028
  *
887
1029
  * Output is **byte-deterministic** within a `schema` version: equal
@@ -895,7 +1037,7 @@ export class Document {
895
1037
  toMarkdown(): string;
896
1038
  /**
897
1039
  * Like [`fromJson`](Document::from_json) but returns `undefined` instead
898
- * of throwing when `json` is not a valid storage DTO use to
1040
+ * of throwing when `json` is not a valid storage DTO: use to
899
1041
  * discriminate format without exceptions as control flow.
900
1042
  * `undefined` means "not a storage DTO"; `fromMarkdown` still throws on
901
1043
  * genuinely malformed markdown.
@@ -908,7 +1050,7 @@ export class Document {
908
1050
  readonly cards: Card[];
909
1051
  /**
910
1052
  * The document's main (entry) card. Allocates and serializes on each
911
- * call cache locally if read in a hot loop.
1053
+ * call: cache locally if read in a hot loop.
912
1054
  */
913
1055
  readonly main: Card;
914
1056
  readonly quillRef: string;
@@ -920,7 +1062,7 @@ export class Document {
920
1062
  * `fieldAt`, `positionAt`, `locate`) serve the current compile. `apply(doc)`
921
1063
  * recompiles a whole document in place, transactionally (on throw every read
922
1064
  * keeps serving the last-good compile). Geometry reads reflect the current
923
- * compile; anchoring a caret across edits is the editor's job re-read
1065
+ * compile; anchoring a caret across edits is the editor's job: re-read
924
1066
  * geometry after each committed `apply`.
925
1067
  *
926
1068
  * **Empty documents.** A zero-page document yields a valid session
@@ -933,7 +1075,7 @@ export class LiveSession {
933
1075
  free(): void;
934
1076
  [Symbol.dispose](): void;
935
1077
  /**
936
- * Recompile the session against `doc` the edit verb of a live preview.
1078
+ * Recompile the session against `doc`: the edit verb of a live preview.
937
1079
  * The document is compiled through the same schema pipeline as `open`
938
1080
  * (same quill), then applied transactionally: on throw every read
939
1081
  * (`render`, `paint`, `pageSize`, `regions`, `fieldAt`) keeps serving the last-good
@@ -942,11 +1084,11 @@ export class LiveSession {
942
1084
  */
943
1085
  apply(doc: Document): ChangeSet;
944
1086
  /**
945
- * The schema field whose content is under a point on `page` the
1087
+ * The schema field whose content is under a point on `page`, the
946
1088
  * forward (click → field) direction: hit-test a click against the
947
1089
  * compiled document and get back the `DocPath` field address to focus in
948
1090
  * the editor, or `undefined` off any field's ink. `x`/`y` are PDF points
949
- * with a **bottom-left** origin, the same space as `FieldRegion.rect` —
1091
+ * with a **bottom-left** origin, the same space as `FieldRegion.rect`,
950
1092
  * from a canvas click, invert the overlay transform documented on
951
1093
  * `FieldRegion`: `x = clickPx.x / renderScale`,
952
1094
  * `y = pageHeightPt - clickPx.y / renderScale`. Unlike `regions()`,
@@ -954,19 +1096,19 @@ export class LiveSession {
954
1096
  */
955
1097
  fieldAt(page: number, x: number, y: number): string | undefined;
956
1098
  /**
957
- * The whole-field highlight boxes for `field` one union rect per page,
1099
+ * The whole-field highlight boxes for `field`: one union rect per page,
958
1100
  * over the field's `span`-bearing content segments. The convenience that
959
1101
  * owns the union `regions()` leaves derived: it keeps `regions()` the
960
- * low-level disjoint truth (#829) and folds the span-filter + per-page
1102
+ * low-level disjoint truth and folds the span-filter + per-page
961
1103
  * union here, so a "highlight the focused field" consumer stops
962
- * reimplementing it. **Content only** a field placed solely as a scalar
1104
+ * reimplementing it. **Content only**: a field placed solely as a scalar
963
1105
  * reference or a bound widget carries no `span` and returns `[]`; its box
964
1106
  * is a single `regions()` rect. Reflects the current compile, like
965
1107
  * `regions()`.
966
1108
  */
967
1109
  fieldBoxes(field: string): FieldRegion[];
968
1110
  /**
969
- * A content position → **caret rect** the reverse of `positionAt`: given
1111
+ * A content position → **caret rect**, the reverse of `positionAt`: given
970
1112
  * a field and a USV offset into its `Content`, return the box (in the
971
1113
  * same bottom-left PDF-point space as `FieldRegion.rect`) to draw a caret
972
1114
  * at, its `span` collapsed to `[pos, pos]`; `undefined` when the field
@@ -983,12 +1125,12 @@ export class LiveSession {
983
1125
  * `OffscreenCanvasRenderingContext2D`. The painter owns
984
1126
  * `canvas.width`/`height` (no `clearRect` needed); consumers own
985
1127
  * `canvas.style.*`. If `layoutScale * densityScale` exceeds 16384 px
986
- * per side, `densityScale` is clamped `PaintResult.clamped` reports it and
1128
+ * per side, `densityScale` is clamped: `PaintResult.clamped` reports it and
987
1129
  * `PaintResult.effectiveDensityScale` carries the density actually applied.
988
1130
  *
989
1131
  * `put_image_data` writes the whole backing store, bypassing the 2D
990
1132
  * context's transform, `globalAlpha`, and clip: the painter owns the entire
991
- * canvas, so each visible page needs its own `` you cannot composite
1133
+ * canvas, so each visible page needs its own `<canvas>`; you cannot composite
992
1134
  * two pages, a sub-rect, or a context transform through this call.
993
1135
  *
994
1136
  * Throws if the backend has no canvas painter, `page` is out of range,
@@ -996,18 +1138,18 @@ export class LiveSession {
996
1138
  */
997
1139
  paint(ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D, page: number, opts: PaintOptions | undefined): PaintResult;
998
1140
  /**
999
- * A point → **content position** the fine-grained click direction:
1141
+ * A point → **content position**, the fine-grained click direction:
1000
1142
  * hit-test a point and get back the field *and* a USV offset into its
1001
1143
  * `Content` (for placing a caret or mapping a selection into the content
1002
1144
  * model), or `undefined` off all content ink. `x`/`y` are PDF points,
1003
- * bottom-left origin the same space as `fieldAt`. The offset is
1145
+ * bottom-left origin: the same space as `fieldAt`. The offset is
1004
1146
  * cluster-exact and degrades to the containing segment's start on
1005
1147
  * origin-less ink (list markers, a code fence's interior). See
1006
1148
  * `ContentHit`.
1007
1149
  */
1008
1150
  positionAt(page: number, x: number, y: number): ContentHit | undefined;
1009
1151
  /**
1010
- * Schema-field geometry for this compiled session each content field's
1152
+ * Schema-field geometry for this compiled session: each content field's
1011
1153
  * **first placement** (one region per page it touches) plus widget and
1012
1154
  * scalar-reference-site regions, keyed on the canonical `DocPath` address
1013
1155
  * (`parseDocPath`-routable; the session resolves the backend's plate-space
@@ -1027,12 +1169,12 @@ export class LiveSession {
1027
1169
  /**
1028
1170
  * `true` iff `paint` and `pageSize` will succeed for this session. Derived
1029
1171
  * from the session's canvas seam, so it reflects exactly what `paint` will
1030
- * do no separately captured flag.
1172
+ * do: no separately captured flag.
1031
1173
  */
1032
1174
  readonly supportsCanvas: boolean;
1033
1175
  /**
1034
1176
  * Non-fatal diagnostics of the session's **current compile** (e.g. Typst
1035
- * font fallback) set at open and refreshed by each committed `apply`;
1177
+ * font fallback): set at open and refreshed by each committed `apply`;
1036
1178
  * a failed apply keeps the last-good compile's warnings. Also appended
1037
1179
  * to `RenderResult.warnings` on each `render()` call.
1038
1180
  */
@@ -1044,7 +1186,7 @@ export class Quill {
1044
1186
  free(): void;
1045
1187
  [Symbol.dispose](): void;
1046
1188
  /**
1047
- * Build a quill from a file tree. Pure no backend, no engine; the
1189
+ * Build a quill from a file tree. Pure: no backend, no engine; the
1048
1190
  * declared backend is resolved later, at render time.
1049
1191
  *
1050
1192
  * Accepts either a `Map<string, Uint8Array>` or a plain object
@@ -1054,11 +1196,11 @@ export class Quill {
1054
1196
  */
1055
1197
  static fromTree(tree: Map<string, Uint8Array>): Quill;
1056
1198
  /**
1057
- * The resolved-value view of `doc` against this quill's schema for every
1199
+ * The resolved-value view of `doc` against this quill's schema: for every
1058
1200
  * declared field the value the render projection would use and the
1059
1201
  * `FieldSource` rung it came from (`"authored" | "default" | "zero"`), in
1060
1202
  * one call. The card body is a `body` sibling on its card (row `name`
1061
- * `"body"`), never a row in `fields` `null` when the kind enables no body.
1203
+ * `"body"`), never a row in `fields`: `null` when the kind enables no body.
1062
1204
  *
1063
1205
  * Value and provenance only: completeness and errors stay `validate`'s
1064
1206
  * (a consumer merges it with its own diagnostic producers regardless), and
@@ -1075,11 +1217,11 @@ export class Quill {
1075
1217
  * Pass `document.seedOverlay(cardKind)` as `overlay` so a card added to a
1076
1218
  * template-derived document inherits its curated starting values; omit it
1077
1219
  * (or pass `undefined` / `null`) for the bare schema seed. `overlay` is a
1078
- * plain object this reads the document, it does not mutate it.
1220
+ * plain object: this reads the document, it does not mutate it.
1079
1221
  */
1080
1222
  seedCard(card_kind: string, overlay: Record<string, unknown> | undefined): Card | undefined;
1081
1223
  /**
1082
- * Seed a starter `Document` from the schema the main card plus one
1224
+ * Seed a starter `Document` from the schema, the main card plus one
1083
1225
  * instance of each composable card kind, each committing its fields'
1084
1226
  * `example:` values and leaving every other field absent (interpolated at
1085
1227
  * render: `default:`, else type-empty zero). Illustration-first: a field
@@ -1088,14 +1230,14 @@ export class Quill {
1088
1230
  */
1089
1231
  seedDocument(): Document;
1090
1232
  /**
1091
- * Seed a starter main `Card` (carries `$quill`) from the schema the
1233
+ * Seed a starter main `Card` (carries `$quill`) from the schema: the
1092
1234
  * `$kind: main` card of [`seedDocument`](Self::seed_document) in
1093
1235
  * isolation, committing each field's `example:` value. Returns the same
1094
1236
  * `Card` shape as the `Document.main` getter.
1095
1237
  */
1096
1238
  seedMain(): Card;
1097
1239
  /**
1098
- * Flatten this quill back into its canonical file tree the inverse of
1240
+ * Flatten this quill back into its canonical file tree: the inverse of
1099
1241
  * [`fromTree`](Self::from_tree). Round-trips: `Quill.fromTree(q.toTree())`
1100
1242
  * reproduces an equivalent quill.
1101
1243
  *
@@ -1111,8 +1253,8 @@ export class Quill {
1111
1253
  * Validate `doc` against this quill's schema, returning every diagnostic
1112
1254
  * (an empty array when the document is valid).
1113
1255
  *
1114
- * Forwards the canonical `validation::*` diagnostics same `code`,
1115
- * `path`, and `hint` the engine emits including the non-fatal
1256
+ * Forwards the canonical `validation::*` diagnostics (same `code`,
1257
+ * `path`, and `hint` the engine emits) including the non-fatal
1116
1258
  * `validation::must_fill` warning for each `!must_fill` marker left in
1117
1259
  * the document. Field values, defaults, and order are not part of this
1118
1260
  * surface: read them from the `Document` payload and `Quill.schema`
@@ -1121,14 +1263,14 @@ export class Quill {
1121
1263
  validate(doc: Document): Diagnostic[];
1122
1264
  /**
1123
1265
  * The *declared* backend identifier (`config.backend`, e.g. `"typst"`).
1124
- * Intent, not a resolved capability capability (`supportedFormats` /
1266
+ * Intent, not a resolved capability: capability (`supportedFormats` /
1125
1267
  * `supportsCanvas`) is read from the engine.
1126
1268
  */
1127
1269
  readonly backendId: string;
1128
1270
  readonly blueprint: string;
1129
1271
  /**
1130
1272
  * Identity snapshot of the `quill:` section of `Quill.yaml` plus any extra
1131
- * `quill:` keys. Pure config the backend's output formats are a
1273
+ * `quill:` keys. Pure config: the backend's output formats are a
1132
1274
  * resolved-backend capability read from the engine
1133
1275
  * (`Quillmark.supportedFormats`), not part of this snapshot.
1134
1276
  */
@@ -1136,15 +1278,15 @@ export class Quill {
1136
1278
  /**
1137
1279
  * Document schema for the quill: the user-fillable fields plus their
1138
1280
  * `ui` hints (title / group / compact / multiline). The single
1139
- * field-metadata surface drives form editors and LLM/MCP consumers
1140
- * alike. Key order in `fields`/`properties` is declaration order the
1281
+ * field-metadata surface: drives form editors and LLM/MCP consumers
1282
+ * alike. Key order in `fields`/`properties` is declaration order: the
1141
1283
  * ordering contract. Returns the `QuillSchema` shape.
1142
1284
  */
1143
1285
  readonly schema: QuillSchema;
1144
1286
  }
1145
1287
 
1146
1288
  /**
1147
- * Render engine: a backend registry and render dispatcher. Render build only
1289
+ * Render engine: a backend registry and render dispatcher. Render build only:
1148
1290
  * the core build constructs and validates quills without it.
1149
1291
  */
1150
1292
  export class Quillmark {
@@ -1162,7 +1304,7 @@ export class Quillmark {
1162
1304
  */
1163
1305
  render(quill: Quill, doc: Document, opts?: RenderOptions | null): RenderResult;
1164
1306
  /**
1165
- * The output formats `quill`'s backend can emit. Static capability
1307
+ * The output formats `quill`'s backend can emit. Static capability:
1166
1308
  * resolves the backend but compiles nothing. Throws `engine::backend_not_found`
1167
1309
  * if no registered backend matches the quill's declared backend.
1168
1310
  */
@@ -1178,7 +1320,7 @@ export class Quillmark {
1178
1320
  }
1179
1321
 
1180
1322
  /**
1181
- * Export a canonical `Content` content to its markdown projection the pure
1323
+ * Export a canonical `Content` content to its markdown projection: the pure
1182
1324
  * on-demand codec behind `exportMarkdown(card.body)`. Throws if `rt` is not a
1183
1325
  * canonical content.
1184
1326
  */
@@ -1186,7 +1328,7 @@ export function exportMarkdown(rt: Content): string;
1186
1328
 
1187
1329
  /**
1188
1330
  * Serialize structured [`DocPathSeg`] segments back to the canonical path
1189
- * string the inverse of `parseDocPath`, for a consumer that builds a path
1331
+ * string: the inverse of `parseDocPath`, for a consumer that builds a path
1190
1332
  * rather than reads one. Throws on a segment array the deserializer rejects,
1191
1333
  * and on an empty segment array (symmetric with `parseDocPath("")`, which
1192
1334
  * throws "empty path").
@@ -1194,7 +1336,7 @@ export function exportMarkdown(rt: Content): string;
1194
1336
  export function formatDocPath(segs: DocPathSeg[]): string;
1195
1337
 
1196
1338
  /**
1197
- * Import a markdown string to a canonical `Content` content the pure,
1339
+ * Import a markdown string to a canonical `Content` content: the pure,
1198
1340
  * document-free codec. Pair with `install(addr, importMarkdown(md))` to spell
1199
1341
  * the cold (anchor-losing) write at the call site; prefer `revise` for edit
1200
1342
  * semantics. Throws on an over-nested input.
@@ -1207,8 +1349,8 @@ export function importMarkdown(markdown: string): Content;
1207
1349
  export function init(): void;
1208
1350
 
1209
1351
  /**
1210
- * Map a base content position a USV index into `Content.text`, not a UTF-16
1211
- * offset through a `delta` to its new USV position: the pure position-mapping
1352
+ * Map a base content position (a USV index into `Content.text`, not a UTF-16
1353
+ * offset) through a `delta` to its new USV position: the pure position-mapping
1212
1354
  * codec an editor bridge composes to hold a caret stable across a `revise`.
1213
1355
  * `assoc` decides the side of a same-position insertion (`"after"` moves past
1214
1356
  * it). Throws on a malformed `delta`.
@@ -1218,14 +1360,14 @@ export function mapPos(delta: Delta, pos: number, assoc: Assoc): number;
1218
1360
  /**
1219
1361
  * Parse a canonical document-model `Diagnostic.path`
1220
1362
  * (`cards.<kind>[<i>].<field>`, `main.body`, `recipients[0].name`) into its
1221
- * structured [`DocPathSeg`] segments the exported inverse of the engine's
1363
+ * structured [`DocPathSeg`] segments: the exported inverse of the engine's
1222
1364
  * one path serializer, so a consumer routes on segments instead of regexing
1223
1365
  * the string. Throws on a malformed path.
1224
1366
  */
1225
1367
  export function parseDocPath(path: string): DocPathSeg[];
1226
1368
 
1227
1369
  /**
1228
- * Rebase `markdown` onto a `base` content the pure, document-free twin of
1370
+ * Rebase `markdown` onto a `base` content, the pure, document-free twin of
1229
1371
  * `revise`: cold-import + `diff_import`, returning the new `content` and the
1230
1372
  * text `delta` (its offsets USV indices into `Content.text`, surviving anchors
1231
1373
  * rebased). Use it to compute a revise without a document in hand; `revise(addr,