@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.
@@ -1,33 +1,38 @@
1
- // @quillmark/wasm/runtime canonical consumer API.
1
+ // @quillmark/wasm/runtime: canonical consumer API.
2
2
  //
3
3
  // `Quill`/`Document` are re-exported verbatim from the core build (their full
4
4
  // surface, no drift). Render-side types (`RenderResult`, `RenderOptions`,
5
5
  // `Artifact`, `OutputFormat`, `PageSize`, `PaintOptions`, `PaintResult`) are
6
- // defined HERE as the canonical, backend-neutral render contract NOT sourced
6
+ // defined HERE as the canonical, backend-neutral render contract: NOT sourced
7
7
  // from any one private backend build. A type-level drift guard
8
8
  // (`runtime.types.test-d.ts`, via `npm run typecheck`) asserts they stay
9
9
  // mutually assignable with the Typst backend's generated declarations. `Engine`
10
10
  // is the render dispatcher that hides the cross-WASM-memory seam.
11
11
 
12
12
  // CANONICAL INVARIANT: the root re-exports the core build's `Quill`/`Document`
13
- // verbatim they are the SAME classes, never wrappers. There is exactly one
13
+ // verbatim; they are the SAME classes, never wrappers. There is exactly one
14
14
  // public entry point, so this is a structural fact. Replacing the re-export
15
15
  // with a wrapper is a breaking design change, not a refactor. See runtime.js.
16
+ //
17
+ // ONE COPY PER PROCESS: two copies of this package are two WASM linear memories
18
+ // and two `Quill`/`Document` classes. Every method taking a handle refuses one
19
+ // belonging to another copy, with a `QuillmarkError` naming `npm ls
20
+ // @quillmark/wasm`. Errors are the exception: `isQuillmarkError` is structural.
16
21
  export { Quill, Document, init } from '../core/wasm.js';
17
22
  // The document-free content codec, re-exported from the core build.
18
23
  export { importMarkdown, exportMarkdown, rebase, mapPos } from '../core/wasm.js';
19
- // The document-model path parser/serializer route on `Diagnostic.path`
24
+ // The document-model path parser/serializer: route on `Diagnostic.path`
20
25
  // segments instead of regexing the string.
21
26
  export { parseDocPath, formatDocPath } from '../core/wasm.js';
22
27
 
23
28
  import type { CardAddr } from '../core/wasm.js';
24
29
 
25
30
  /**
26
- * The main card's address the default target of the card-scoped verbs
31
+ * The main card's address: the default target of the card-scoped verbs
27
32
  * (`storeFields` / `storeExt` / `commitFields` / …). A named, {@link CardAddr}-typed
28
33
  * alias for the empty address `{}`, so a main-card write names its target:
29
34
  * `doc.storeFields(MAIN_CARD_ADDR, fields)`. It IS `{}` (frozen at runtime), a
30
- * pure alias `{}` and `undefined` stay equally valid. A card selector only,
35
+ * pure alias: `{}` and `undefined` stay equally valid. A card selector only,
31
36
  * never a field address.
32
37
  */
33
38
  export declare const MAIN_CARD_ADDR: CardAddr;
@@ -49,17 +54,24 @@ export type {
49
54
  QuillMetadata
50
55
  } from '../core/wasm.js';
51
56
 
52
- // Content edit vocabulary the op-grained content model `Document`'s methods
57
+ // Content edit vocabulary: the op-grained content model `Document`'s methods
53
58
  // speak (`applyChange(addr, bundle)`, `install(addr, rt)`, `revise(…) => Delta`).
54
59
  // Declared in the core build; re-exported here so the single public entry point
55
- // names every type its own re-exported surface already references `Card.body`
60
+ // names every type its own re-exported surface already references: `Card.body`
56
61
  // is a `Content`, `PayloadItem.nestedFills` a `PathStep[][]`, `CardInput.body` a
57
- // `Content | string` rather than forcing consumers to derive them structurally
62
+ // `Content | string`: rather than forcing consumers to derive them structurally
58
63
  // off the `Document` handle. The content write path (a ProseMirror↔content codec)
59
64
  // must name all of them; they are its correctness core, not edge types.
65
+ // `ContentLineKind` is the shared half of `ContentLine` and `setKind`, so lifting
66
+ // a line's kind whole (destructure off `containers`/`continues`, spread the rest
67
+ // into the op) is the version-proof spelling of building a `setKind`. Naming it
68
+ // is what makes that spelling type-check without a cast. The alternative, an
69
+ // arm-by-arm switch, means guessing at the open arm's shape and re-editing on
70
+ // every arm added.
60
71
  export type {
61
72
  Content,
62
73
  ContentLine,
74
+ ContentLineKind,
63
75
  ContentContainer,
64
76
  ContentMark,
65
77
  ContentIsland,
@@ -78,7 +90,7 @@ export type {
78
90
  DocPathSeg
79
91
  } from '../core/wasm.js';
80
92
 
81
- // The resolved-value view the return shape of `quill.resolve(doc)`. Value
93
+ // The resolved-value view: the return shape of `quill.resolve(doc)`. Value
82
94
  // + source rung per declared field (the body is a `body` sibling on its card,
83
95
  // never a row in `fields`); diagnostics stay `quill.validate`, guidance stays
84
96
  // `quill.schema`.
@@ -96,14 +108,14 @@ export type {
96
108
  // ── Error contract ──────────────────────────────────────────────────────────
97
109
 
98
110
  /**
99
- * The error every fallible method in this package throws parse
111
+ * The error every fallible method in this package throws: parse
100
112
  * (`Document.fromMarkdown`), document mutation, validation
101
113
  * (`Quill.fromTree`, `quill.validate`), and rendering (`engine.render`,
102
114
  * `engine.open`, `session.render`).
103
115
  *
104
116
  * This is a STRUCTURAL interface, not a class: the WASM layer throws a real
105
117
  * `Error` and attaches `diagnostics` to it, so there is no constructor to
106
- * `instanceof` against narrow with {@link isQuillmarkError}. `diagnostics`
118
+ * `instanceof` against, narrow with {@link isQuillmarkError}. `diagnostics`
107
119
  * is always non-empty; `message` is the first diagnostic's message (or an
108
120
  * `"N error(s): …"` aggregate for multi-diagnostic failures), so iterate
109
121
  * `diagnostics` for per-error detail. The shape is identical to
@@ -115,20 +127,22 @@ export interface QuillmarkError extends Error {
115
127
 
116
128
  /**
117
129
  * Narrow an unknown caught value to {@link QuillmarkError}. Structural
118
- * (`Error` carrying a `diagnostics` array), so it works on errors from any
119
- * build or WASM instance in the page consistent with the package's
120
- * duck-typed handling of handles.
130
+ * (`Error` carrying a `diagnostics` array), so it narrows errors from any build
131
+ * or WASM instance in the page. Handles are the opposite: a `Quill` or
132
+ * `Document` from a second copy of this package is rejected wherever it is
133
+ * passed, since two copies are two linear memories. An error is data, not a
134
+ * handle, so nothing is gained by refusing one that crossed.
121
135
  */
122
136
  export declare function isQuillmarkError(e: unknown): e is QuillmarkError;
123
137
 
124
138
  // ── Open-set discriminant guards ────────────────────────────────────────────
125
139
  // `ContentIsland.type`, `ContentMark.type`, `ContentLine.kind`, and
126
- // `ContentContainer.container` are open sets each union has a residual
140
+ // `ContentContainer.container` are open sets: each union has a residual
127
141
  // `{ …: string; … }` arm, so a bare discriminant check never narrows the payload
128
142
  // (TS keeps the residual arm live, since a `string` can equal the literal).
129
143
  // These guards are the checked narrowing path for the pinned arms; an
130
144
  // unrecognized discriminant fails every guard and keeps its opaque payload. Only
131
- // the payload-carrying arms get a guard the bare marks
145
+ // the payload-carrying arms get a guard: the bare marks
132
146
  // (`strong`/`emph`/`underline`/`strike`/`code`), the payload-free lines
133
147
  // (`para`/`island`/`rule`), and `quote` narrow to nothing.
134
148
 
@@ -181,6 +195,39 @@ export declare function isListItemContainer(
181
195
  ordinal: number;
182
196
  };
183
197
 
198
+ // ── Open-set membership guards ──────────────────────────────────────────────
199
+ // The guards above answer "is this arm X", one pinned arm at a time. These four
200
+ // answer "is this a value this build knows?": the question a read-modify-write
201
+ // consumer must ask, since lowering an edit restates every line's kind and
202
+ // containers, and a construct the consumer cannot hold is gone on write-back
203
+ // unless it is carried inertly. Without a predicate a consumer enumerates the
204
+ // built-in names itself and re-couples to a closed set, going wrong at the first
205
+ // release that adds one.
206
+ //
207
+ // They classify unknown TAGS, not unknown payloads on known tags: a future
208
+ // `kind: "footnote"` carrying a sibling `ref` loses `ref` at any consumer that
209
+ // predates it, with or without these.
210
+
211
+ /** True when this build does not know `line.kind`: the open arm, carrying opaque `attrs`. */
212
+ export declare function isUnknownLine(
213
+ line: ContentLine
214
+ ): line is ContentLine & { kind: string; attrs: unknown };
215
+
216
+ /** True when this build does not know `container.container`. See {@link isUnknownLine}. */
217
+ export declare function isUnknownContainer(
218
+ container: ContentContainer
219
+ ): container is ContentContainer & { container: string; attrs: unknown };
220
+
221
+ /** True when this build does not know `mark.type`. See {@link isUnknownLine}. */
222
+ export declare function isUnknownMark(
223
+ mark: ContentMark
224
+ ): mark is ContentMark & { type: string; attrs: unknown };
225
+
226
+ /** True when this build does not know `island.type` (its payload rides `props`, not `attrs`). */
227
+ export declare function isUnknownIsland(
228
+ island: ContentIsland
229
+ ): island is ContentIsland & { type: string; props: unknown };
230
+
184
231
  // ── Canonical render-side types ─────────────────────────────────────────────
185
232
  // These are the BACKEND-NEUTRAL render contract of the plural-backend API. They
186
233
  // are defined HERE (not re-exported from one private backend) because no single
@@ -209,21 +256,21 @@ export interface RenderOptions {
209
256
  /**
210
257
  * Populate {@link RenderResult.regions} with the schema-field geometry
211
258
  * sidecar (the same entries {@link LiveSession.regions} serves), for
212
- * consumers without a live session e.g. overlays over a one-shot SVG
259
+ * consumers without a live session; e.g. overlays over a one-shot SVG
213
260
  * export. Defaults to `false`: exports pay no introspection cost.
214
261
  */
215
262
  regions?: boolean;
216
263
  }
217
264
 
218
265
  /**
219
- * How precisely a {@link ContentHit.pos} resolved the marker a caret UI reads
266
+ * How precisely a {@link ContentHit.pos} resolved: the marker a caret UI reads
220
267
  * to decide whether to trust the offset. Never sub-cluster: `'cluster'` is the
221
268
  * finest, `'segment'` the floor it degrades to on origin-less ink.
222
269
  *
223
- * - `'cluster'` `pos` is the first content char of the cluster under the point
270
+ * - `'cluster'`: `pos` is the first content char of the cluster under the point
224
271
  * (an escaped/CJK/shaping cluster floors to its first char). Place the caret
225
272
  * at `pos` directly.
226
- * - `'segment'` the point hit origin-less ink (list markers, numbering, a
273
+ * - `'segment'`: the point hit origin-less ink (list markers, numbering, a
227
274
  * multi-line code fence's interior), so `pos` degraded to the containing
228
275
  * segment's start. Treat `pos` as the selected segment, not a caret.
229
276
  */
@@ -232,7 +279,7 @@ export type HitGranularity = 'cluster' | 'segment';
232
279
  /** A click resolved to a field and USV offset into its Content. */
233
280
  export interface ContentHit {
234
281
  /**
235
- * The field's canonical `DocPath` address (`parseDocPath`-routable) the same
282
+ * The field's canonical `DocPath` address (`parseDocPath`-routable): the same
236
283
  * address {@link LiveSession.fieldAt} returns for that point.
237
284
  */
238
285
  field: string;
@@ -247,28 +294,28 @@ export interface ContentHit {
247
294
  /**
248
295
  * A rendered field region: the canonical `DocPath` field address (`field`) plus
249
296
  * its geometry (`rect`) on the page. Emitted by backends that place schema fields
250
- * (`pdfform` AcroForm widgets; Typst form-fields and span-tracked content
297
+ * (`pdfform` AcroForm widgets; Typst form-fields and span-tracked content:
251
298
  * richtext bodies, `richtext[]` elements, card content fields, direct scalar
252
- * references). Only fields with a schema address produce a region a
299
+ * references). Only fields with a schema address produce a region: a
253
300
  * backend-only widget produces none, and the backend widget name never
254
301
  * appears.
255
302
  *
256
303
  * Use it to scroll to / highlight the focused field's rect; for the click
257
304
  * direction use {@link LiveSession.fieldAt}, which resolves a point on *any*
258
- * placement, not just the first one surfaced here. Geometry only
305
+ * placement, not just the first one surfaced here. Geometry only:
259
306
  * `LiveSession.paint` already bakes every value into the raster (see
260
307
  * {@link LiveSession}), so a region is never a compositing input.
261
308
  *
262
309
  * COORDINATE TRANSFORM. `rect` is in PDF points with a **bottom-left** origin.
263
310
  *
264
311
  * For an **HTML/CSS overlay** on a `width:100%` canvas, position hotspots as
265
- * percentages of the page they track the displayed size across DPI and pane
312
+ * percentages of the page; they track the displayed size across DPI and pane
266
313
  * resize for free, and only the Y axis flips:
267
314
  *
268
315
  * ```js
269
316
  * const [x0, y0, x1, y1] = region.rect; // PDF pt, bottom-left origin
270
317
  * const left = (x0 / pageWidthPt) * 100; // % of page (from PageSize.widthPt)
271
- * const top = (1 - y1 / pageHeightPt) * 100; // % flip Y (from PageSize.heightPt)
318
+ * const top = (1 - y1 / pageHeightPt) * 100; // %: flip Y (from PageSize.heightPt)
272
319
  * const width = ((x1 - x0) / pageWidthPt) * 100;
273
320
  * const height = ((y1 - y0) / pageHeightPt) * 100;
274
321
  * ```
@@ -294,7 +341,7 @@ export interface FieldRegion {
294
341
  /** `[x0, y0, x1, y1]` in PDF points (1/72″), bottom-left origin. */
295
342
  rect: [number, number, number, number];
296
343
  /**
297
- * The content slice this box covers USV `[start, end)` into the field's
344
+ * The content slice this box covers: USV `[start, end)` into the field's
298
345
  * `Content` for content ink (one segment), absent for a scalar reference
299
346
  * site or widget. Consumers key segment highlights on it;
300
347
  * {@link LiveSession.fieldBoxes} unions same-page segments for the
@@ -310,7 +357,7 @@ export interface RenderResult {
310
357
  outputFormat: OutputFormat;
311
358
  renderTimeMs: number;
312
359
  /**
313
- * Schema-field geometry sidecar populated only when
360
+ * Schema-field geometry sidecar: populated only when
314
361
  * {@link RenderOptions.regions} requested it; empty otherwise. The same
315
362
  * entries {@link LiveSession.regions} serves, for consumers without a live
316
363
  * session. Page indices are document-space even under a `pages` subset
@@ -354,7 +401,7 @@ export interface PaintResult {
354
401
  */
355
402
  clamped: boolean;
356
403
  /**
357
- * The `densityScale` actually applied equal to the requested value unless
404
+ * The `densityScale` actually applied: equal to the requested value unless
358
405
  * `clamped`, then reduced proportionally. `layoutScale × effectiveDensityScale`
359
406
  * is the scale the backing store was rasterized at.
360
407
  */
@@ -377,7 +424,7 @@ export interface ChangeSet {
377
424
  * imported backend build module; `formats`/`canvas` are the REQUIRED static
378
425
  * capability manifest. That manifest is what makes
379
426
  * `Engine.supportedFormats`/`Engine.supportsCanvas` always FREE: they answer
380
- * from it directly no backend binary is loaded and no quill is cloned into
427
+ * from it directly, no backend binary is loaded and no quill is cloned into
381
428
  * backend memory. A malformed descriptor throws at `new Engine(...)`.
382
429
  */
383
430
  export interface BackendDescriptor {
@@ -390,7 +437,7 @@ export interface EngineOptions {
390
437
  /**
391
438
  * Extra or overriding backend descriptors, merged over the built-ins. Keys are
392
439
  * backend ids (as declared by `Quill.yaml`'s `backend:` and reported by
393
- * `Quill.backendId`). Each value is a `BackendDescriptor` `formats`/`canvas`
440
+ * `Quill.backendId`). Each value is a `BackendDescriptor`: `formats`/`canvas`
394
441
  * are required, so capability probes are ALWAYS free (no binary load, no quill
395
442
  * clone). Malformed entries throw at construction. The default registry maps
396
443
  * `"typst"` to the bundled Typst build.
@@ -430,12 +477,12 @@ export declare class Engine {
430
477
  supportedFormats(quill: Quill): Promise<OutputFormat[]>;
431
478
 
432
479
  /**
433
- * Whether `quill`'s BACKEND can paint sessions to a canvas a pre-session
480
+ * Whether `quill`'s BACKEND can paint sessions to a canvas: a pre-session
434
481
  * ESTIMATE, not a fact about any particular compile. Same always-free probe
435
482
  * as `supportedFormats`: answered from the descriptor's required `canvas`
436
483
  * manifest, no binary load and no quill clone. Both the Typst and pdfform
437
484
  * backends report `true` here unconditionally; each paints a complete page
438
- * raster (see {@link LiveSession.paint}) but a specific compile can still
485
+ * raster (see {@link LiveSession.paint}), but a specific compile can still
439
486
  * refuse to paint (e.g. a 0-page document), so this can answer `true` while
440
487
  * the resulting {@link LiveSession.supportsCanvas} answers `false`. Gate
441
488
  * mounting a canvas UI on this; gate the actual `paint` call on the session's
@@ -448,7 +495,7 @@ export declare class Engine {
448
495
  * Iterative render session over a compiled snapshot. `free()` when done.
449
496
  *
450
497
  * CANVAS PAINT IS COMPLETE. {@link LiveSession.paint} writes a complete page
451
- * raster every piece of page content is already visible in the painted
498
+ * raster: every piece of page content is already visible in the painted
452
499
  * pixels, with NO compositing required by the caller. Both backends that
453
500
  * support canvas satisfy this: Typst rasterizes its laid-out page natively;
454
501
  * pdfform pre-flattens bound field values into the page content and rasterizes
@@ -462,7 +509,7 @@ export declare class LiveSession {
462
509
  readonly pageCount: number;
463
510
  readonly backendId: string;
464
511
  /**
465
- * `true` iff `paint`/`pageSize` will succeed for THIS compile the
512
+ * `true` iff `paint`/`pageSize` will succeed for THIS compile: the
466
513
  * authoritative answer, derived from the session's canvas seam, so it can
467
514
  * never disagree with what `paint` actually does. This can be `false` even
468
515
  * when {@link Engine.supportsCanvas} answered `true` for the same `quill`
@@ -473,7 +520,7 @@ export declare class LiveSession {
473
520
  readonly supportsCanvas: boolean;
474
521
  readonly warnings: Diagnostic[];
475
522
  /**
476
- * Recompile the session against `doc` the edit verb of a live preview.
523
+ * Recompile the session against `doc`: the edit verb of a live preview.
477
524
  * Transactional: on throw every read (`render`, `paint`, `pageSize`,
478
525
  * `regions`) keeps serving the last-good compile, and the session recovers
479
526
  * on the next successful `apply`. On success reads serve the new compile;
@@ -493,30 +540,30 @@ export declare class LiveSession {
493
540
  * (so a highlight covers continuation pages); a scalar referenced at
494
541
  * several plate sites surfaces each site; tracked content plus a
495
542
  * `field:`-bound widget yields both, widget ordered first. Group by
496
- * `field` every entry routes to that field. Later placements of one
543
+ * `field`: every entry routes to that field. Later placements of one
497
544
  * content value are not enumerated; {@link fieldAt} still resolves
498
545
  * clicks on them.
499
546
  */
500
547
  regions(): FieldRegion[];
501
548
  /**
502
549
  * The whole-field highlight boxes for `field` (a canonical `DocPath` address,
503
- * as {@link regions} keys) one union rect per page, over the field's
550
+ * as {@link regions} keys): one union rect per page, over the field's
504
551
  * `span`-bearing content segments (the "highlight the focused field"
505
552
  * quantity). Owns the union {@link regions} leaves derived
506
553
  * (span-filter + per-page union), keeping `regions()` the low-level disjoint
507
- * truth, so a consumer stops reimplementing it. **Content only** a field
554
+ * truth, so a consumer stops reimplementing it. **Content only**: a field
508
555
  * placed solely as a scalar reference or a bound widget carries no `span`
509
556
  * and returns `[]`; its box is a single {@link regions} rect. Reflects the
510
557
  * current compile, like `regions()`.
511
558
  */
512
559
  fieldBoxes(field: string): FieldRegion[];
513
560
  /**
514
- * The schema field whose content is under a point on `page` the forward
561
+ * The schema field whose content is under a point on `page`, the forward
515
562
  * (click → field) direction: hit-test a click against the compiled
516
563
  * document and get back the canonical `DocPath` field address
517
564
  * (`parseDocPath`-routable) to focus in the editor, or `undefined` off any
518
565
  * field's ink. `x`/`y` are PDF points with a **bottom-left** origin, the
519
- * same space as {@link FieldRegion.rect} from a canvas click, invert the
566
+ * same space as {@link FieldRegion.rect}, from a canvas click, invert the
520
567
  * overlay transform documented there:
521
568
  * `x = clickPx.x / renderScale`,
522
569
  * `y = pageHeightPt - clickPx.y / renderScale`. Unlike {@link regions},
@@ -529,7 +576,7 @@ export declare class LiveSession {
529
576
  */
530
577
  positionAt(page: number, x: number, y: number): ContentHit | undefined;
531
578
  /**
532
- * Content position → caret rect reverse of {@link positionAt}. `field` is a
579
+ * Content position → caret rect: reverse of {@link positionAt}. `field` is a
533
580
  * canonical `DocPath` address (`parseDocPath`-routable), as {@link regions} keys.
534
581
  */
535
582
  locate(field: string, pos: number): FieldRegion | undefined;
@@ -538,18 +585,18 @@ export declare class LiveSession {
538
585
  /**
539
586
  * Paint `page` into a 2D canvas context, sizing the backing store itself
540
587
  * (it owns `canvas.width`/`height`; the caller owns `canvas.style.*`). The
541
- * painted raster is COMPLETE all page content visible, no caller-side
588
+ * painted raster is COMPLETE: all page content visible, no caller-side
542
589
  * compositing (Typst rasterizes natively; pdfform rasterizes its
543
590
  * pre-flattened page). Effective rasterization scale is
544
591
  * `layoutScale × densityScale`, clamped so neither backing dimension exceeds
545
- * 16384 px {@link PaintResult.clamped} reports the clamp and
592
+ * 16384 px: {@link PaintResult.clamped} reports the clamp and
546
593
  * {@link PaintResult.effectiveDensityScale} the density actually applied.
547
594
  *
548
595
  * The write is a whole-backing-store `putImageData`, which bypasses the 2D
549
596
  * context transform, `globalAlpha`, and clip: the painter owns the entire
550
597
  * canvas, so give each visible page its own `` element. You cannot
551
598
  * paint two pages into one canvas, paint into a sub-rect, or apply a context
552
- * transform through this call the raster is complete precisely so you never
599
+ * transform through this call: the raster is complete precisely so you never
553
600
  * need to. Keep the per-page canvases alive while their pages stay near the
554
601
  * viewport: each `paint` re-rasterizes from scratch, so reusing (pooling) a
555
602
  * canvas across pages on scroll re-runs a full render, whereas an idle canvas
@@ -563,7 +610,7 @@ export declare class LiveSession {
563
610
  free(): void;
564
611
  }
565
612
 
566
- // ── Typed writer the schema-bound front door ───────────────────────────────
613
+ // ── Typed writer: the schema-bound front door ───────────────────────────────
567
614
 
568
615
  // `quill.writer(doc)` is patched onto the re-exported `Quill` prototype (the
569
616
  // class is re-exported verbatim, so the method is declared by merging into the
@@ -571,20 +618,20 @@ export declare class LiveSession {
571
618
  declare module '../core/wasm.js' {
572
619
  interface Quill {
573
620
  /**
574
- * Bind this quill's schema to `doc` for typed writes the documented
621
+ * Bind this quill's schema to `doc` for typed writes: the documented
575
622
  * front door, mirroring core's `quill.writer(&mut doc)`. The schema grants
576
623
  * the typing, so the quill is the factory. The returned writer holds both
577
624
  * handles by reference and owns neither (nothing to `free()`); it is
578
- * ephemeral by convention bind, write, discard.
625
+ * ephemeral by convention: bind, write, discard.
579
626
  */
580
627
  writer(doc: Document): DocumentWriter;
581
628
  /**
582
- * Bind this quill's schema to `doc` for interpreted reads the read twin of
629
+ * Bind this quill's schema to `doc` for interpreted reads: the read twin of
583
630
  * {@link Quill.writer}, mirroring core's `quill.reader(&doc)`. Each field is
584
631
  * read by its declared type (a richtext field to markdown, every other type
585
632
  * verbatim) with schema authority, so a name the schema does not declare
586
633
  * throws rather than reading back `undefined`. Holds both handles by
587
- * reference and owns neither (nothing to `free()`); ephemeral by convention
634
+ * reference and owns neither (nothing to `free()`); ephemeral by convention:
588
635
  * bind, read, discard.
589
636
  */
590
637
  reader(doc: Document): DocumentReader;
@@ -592,22 +639,22 @@ declare module '../core/wasm.js' {
592
639
  }
593
640
 
594
641
  /**
595
- * A `Document` bound to its `Quill` for typed writes the schema-bound writer,
642
+ * A `Document` bound to its `Quill` for typed writes: the schema-bound writer,
596
643
  * constructed via {@link Quill.writer}. Speaks names, values, and markdown. Bare
597
644
  * `set` / `setAll` / `setBody` / `reviseField` / `addCard` / `card(i).set`
598
645
  * instead of threading the `quill` handle through the underscored ABI. Holds both
599
- * handles by reference and owns neither nothing to `free()`.
646
+ * handles by reference and owns neither: nothing to `free()`.
600
647
  *
601
648
  * Typed commit is the default whenever a quill is in hand: it resolves each
602
649
  * field's schema type and strict-commits it, throwing `UnknownField` for a name
603
- * the schema does not declare on the typed path an undeclared name is a typo,
650
+ * the schema does not declare, on the typed path an undeclared name is a typo,
604
651
  * not a fallback. The raw `Document.storeField` / `storeFields` verbs remain the
605
652
  * deliberate quill-free primitive (standalone data, storage/migration infra, or
606
653
  * holding not-yet-conforming in-progress input).
607
654
  */
608
655
  export declare class DocumentWriter {
609
656
  constructor(quill: Quill, doc: Document);
610
- /** The bound document the instance passed in, mutated in place. */
657
+ /** The bound document: the instance passed in, mutated in place. */
611
658
  readonly document: Document;
612
659
  /**
613
660
  * Typed-commit one main-card field (strict coerce, mismatch throws now).
@@ -615,19 +662,19 @@ export declare class DocumentWriter {
615
662
  */
616
663
  set(name: string, value: unknown): void;
617
664
  /**
618
- * Typed-commit several main-card fields atomically nothing is applied on
665
+ * Typed-commit several main-card fields atomically: nothing is applied on
619
666
  * error (throws a {@link QuillmarkError} carrying one diagnostic per
620
667
  * offending field, including an `UnknownField` for each undeclared name).
621
668
  */
622
669
  setAll(fields: Record<string, unknown>): void;
623
670
  /**
624
671
  * Set the main body from markdown (edit semantics: anchors rebase), discarding
625
- * the delta the receipt-free body write. Use `doc.revise({}, md)` for the
672
+ * the delta, the receipt-free body write. Use `doc.revise({}, md)` for the
626
673
  * `Delta` receipt.
627
674
  */
628
675
  setBody(markdown: string): void;
629
676
  /**
630
- * Revise the richtext main-card field `name` from markdown typed *and*
677
+ * Revise the richtext main-card field `name` from markdown: typed *and*
631
678
  * anchor-preserving. Surviving anchors rebase, then the diffed result is
632
679
  * schema-conformed (`richtext(inline)` rejects a multi-block result). Throws
633
680
  * `UnknownField` for a name the schema does not declare. Returns the `Delta`.
@@ -635,7 +682,7 @@ export declare class DocumentWriter {
635
682
  reviseField(name: string, markdown: string): Delta;
636
683
  /**
637
684
  * Build a composable card of `kind`, typed-commit `fields` onto it, set its
638
- * body from optional markdown, and place it the fused `makeCard` + typed
685
+ * body from optional markdown, and place it: the fused `makeCard` + typed
639
686
  * commit + insertion. `at` picks the position: omitted appends, a number
640
687
  * inserts at that index, so a positioned typed insert is one atomic call
641
688
  * rather than `addCard` + `moveCard`. Transactional: a rejected field (throws
@@ -647,9 +694,10 @@ export declare class DocumentWriter {
647
694
  removeCard(index: number): Card | undefined;
648
695
  /**
649
696
  * A {@link CardWriter} for the composable card at `index`. Index validity is
650
- * checked lazily at commit time, so this never throws. The cursor is
651
- * ephemeral a `removeCard`/`addCard` between binding and writing silently
652
- * retargets it; for durable addressing stamp `$id` and re-resolve at write.
697
+ * checked lazily at commit time, so an out-of-range index does not throw here.
698
+ * The cursor is ephemeral: a `removeCard`/`addCard` between binding and writing
699
+ * silently retargets it; for durable addressing stamp `$id` and re-resolve at
700
+ * write.
653
701
  */
654
702
  card(index: number): CardWriter;
655
703
  }
@@ -666,7 +714,7 @@ export declare class CardWriter {
666
714
  readonly index: number;
667
715
  /**
668
716
  * The bound card's `$kind` (empty string when it carries none), read through
669
- * the document mirrors core `CardWriter::kind()`. Throws `IndexOutOfRange`
717
+ * the document: mirrors core `CardWriter::kind()`. Throws `IndexOutOfRange`
670
718
  * if the bound index is out of range.
671
719
  */
672
720
  readonly kind: string;
@@ -675,7 +723,7 @@ export declare class CardWriter {
675
723
  /** Set this card's body from markdown (edit semantics), discarding the delta. */
676
724
  setBody(markdown: string): void;
677
725
  /**
678
- * Revise the richtext field `name` on this card from markdown typed *and*
726
+ * Revise the richtext field `name` on this card from markdown: typed *and*
679
727
  * anchor-preserving; the card twin of {@link DocumentWriter.reviseField}.
680
728
  * Throws `UnknownField` for an undeclared name and `IndexOutOfRange` if the
681
729
  * bound index is out of range. Returns the `Delta`.
@@ -684,12 +732,12 @@ export declare class CardWriter {
684
732
  }
685
733
 
686
734
  /**
687
- * A `Document` bound to its `Quill` for interpreted reads the schema-plane read
735
+ * A `Document` bound to its `Quill` for interpreted reads: the schema-plane read
688
736
  * surface, constructed via {@link Quill.reader} and the read twin of
689
737
  * {@link DocumentWriter}. One `get` reads each field by its declared type: a
690
738
  * richtext field to its markdown projection, a plaintext field to its literal
691
739
  * text, every other type its canonical value verbatim. Holds both handles by
692
- * reference and owns neither nothing to `free()`.
740
+ * reference and owns neither: nothing to `free()`.
693
741
  *
694
742
  * The schema authority is the point: unlike the quill-free transport `Document.getStored`,
695
743
  * a name the schema does not declare throws `UnknownField` (a typo) rather than
@@ -700,7 +748,7 @@ export declare class CardWriter {
700
748
  */
701
749
  export declare class DocumentReader {
702
750
  constructor(quill: Quill, doc: Document);
703
- /** The bound document the instance passed in. */
751
+ /** The bound document: the instance passed in. */
704
752
  readonly document: Document;
705
753
  /**
706
754
  * Read the value at `addr`, interpreted by its declared type: a richtext field
@@ -711,12 +759,13 @@ export declare class DocumentReader {
711
759
  * `IndexOutOfRange` for a bad `addr.card`.
712
760
  */
713
761
  get(addr: Addr | string): unknown;
714
- /** The main body's markdown the quill-free body read. Equals `get({})`. */
762
+ /** The main body's markdown: the quill-free body read. Equals `get({})`. */
715
763
  getBody(): string;
716
764
  /**
717
765
  * A {@link CardReader} for the composable card at `index`. Index validity is
718
- * checked lazily at read time, so this never throws. The cursor is ephemeral —
719
- * a `removeCard`/`addCard` between binding and reading silently retargets it.
766
+ * checked lazily at read time, so an out-of-range index does not throw here.
767
+ * The cursor is ephemeral: a `removeCard`/`addCard` between binding and reading
768
+ * silently retargets it.
720
769
  */
721
770
  card(index: number): CardReader;
722
771
  }
@@ -742,6 +791,6 @@ export declare class CardReader {
742
791
  * `IndexOutOfRange` for a bad index.
743
792
  */
744
793
  get(name: string): unknown;
745
- /** This card's body markdown the card twin of {@link DocumentReader.getBody}. */
794
+ /** This card's body markdown: the card twin of {@link DocumentReader.getBody}. */
746
795
  getBody(): string;
747
796
  }