@quillmark/wasm 0.113.0 → 0.114.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,130 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.114.0 - 2026-09-18
4
+
5
+ ### Schema, validation and the resolved view
6
+
7
+ - feat(core): **`type: matrix`: a closed vocabulary someone ticks.** A card kind
8
+ gave add and remove, the wrong verbs for a roster the page prints in full, and
9
+ an `array<{member: enum, detail}>` hid every unpicked option, let the same
10
+ member in twice, and left the plate owning a second copy of the vocabulary to
11
+ print the unheld boxes. A `matrix` declares `members:` — ordered blocks of
12
+ `id: Title`, groups optional — and `properties:` as the columns, and the
13
+ loader expands them into an `object` whose properties are the member ids, each
14
+ carrying a synthesized `held: {type: boolean, default: false}` beside the
15
+ columns. Coercion, validation, blank-fill and addressing are the typed
16
+ dictionary's, reached through the new `FieldSchema::namespace_props`, so
17
+ `qualifications.flight_cc.held` regions on Typst and binds a checkbox on
18
+ acroform without a new address grammar. Four behaviors are the type's own.
19
+ **Key presence is the tick**: `cyber_200: true` normalizes to the member
20
+ object as the bare `classification: CUI` normalizes to `{value: CUI}`, and a
21
+ mapping naming no `held` is held, so a document stays sparse. **The roster
22
+ reaches the wire**: every member present in declaration order carrying its own
23
+ `title` and `group`, so a plate prints the vocabulary without holding a second
24
+ copy of it. **The wire carries the live world only**: an unheld member's
25
+ columns render at their blanks whatever the document retains, the closed shape
26
+ variants already hold, so tick, type, untick, retick keeps the answer in the
27
+ file and stops rendering it. **Obligation is gated on the tick**: a column with
28
+ no `default:` reads "required when held", the variant rule one level down,
29
+ while the matrix itself obliges nothing, takes no `default:` or `example:`
30
+ (`quill::{default,example}_on_namespace`, the existing namespace rule) and
31
+ seeds empty. `held`, `title` and `group` are reserved as column names
32
+ (`quill::matrix_reserved_column`); a member id is a snake_case identifier
33
+ (`quill::invalid_matrix_member`), unique across the roster
34
+ (`quill::duplicate_matrix_member`), and one outside it is refused as an
35
+ out-of-domain enum member is. The blueprint spells the roster in the existing
36
+ format slot, `# matrix<flight_cc | dodin_ops | …>`, over a `{}` cell, so no
37
+ third annotation form is minted and a model sees the whole vocabulary without
38
+ twenty-seven lines to delete. Closes #1831.
39
+ - feat(core): **the transform schema carries a declared key order, and the Typst
40
+ codegen honours it.** `Codegen::emit_value` sorts dict keys so a reorder-only
41
+ `update` rebuilds byte-identical `lib.typ` and comemo reuses the whole compile.
42
+ A matrix is the one node that cannot pay it: printing the vocabulary as the
43
+ schema groups it is the type's purpose, and sorted keys hand the plate
44
+ `cyber_200` before `sq_cc_candidate`. A container node whose *schema* fixes an
45
+ order now says so with `quillmark:order`, and the emitter reads it. The order
46
+ is a property of the schema rather than of the data, so equal data still
47
+ produces byte-equal source and nothing about the reuse changes; a node
48
+ carrying no such key sorts as before.
49
+ - feat(core): **`max:` on an array, and `validation::cardinality`.** A form with
50
+ thirty-seven ruled lines silently swallowed a thirty-eighth row, and the limit
51
+ lived in `description:` prose that no consumer reads. `max:` is a non-negative
52
+ integer on an `array`, refused elsewhere, and a `default:`/`example:` longer
53
+ than it fails the load (`quill::{default,example}_over_max`) rather than
54
+ seeding a document that warns on arrival. `Quill::validate` reports
55
+ `validation::cardinality` at the field's own path with `{max, actual}`, at
56
+ every depth — an array in a typed dictionary, a matrix member, a live variant
57
+ world or another array's elements is capped by its own declaration — and never
58
+ gates render: fatal ≡ won't-render is an invariant of the diagnostic model, and
59
+ the plate keeps its own rule for the surplus. The count is the render floor's,
60
+ so a bare scalar coerced to a one-element array is counted as one. `min:` is
61
+ not taken: obligation is `default:`'s absence, so `min: 1` is `required:` under
62
+ another name. Closes #1826.
63
+ - feat(core): **the blueprint carries a cap as `# up to <N>`.** The author most
64
+ likely to exceed a limit is the MCP flow that reads the spec once and then
65
+ writes, and it reads the blueprint: `schema()` is consulted before that author
66
+ writes, and the `validate` warning arrives after the overflowing document
67
+ exists. The line rides the own-line leading slot directly under the field's
68
+ description, the form `# composable (0..N)` already takes for a card kind's
69
+ cardinality, so the `<type>[<format>]` inline grammar is untouched. It reaches
70
+ a field and an `object` property, the two positions that slot exists at.
71
+ - feat(core): **`ui.layout: table` asks an editor for the grid a typed table
72
+ wants.** A row of four short cells drew as a stack of collapsed rows that open
73
+ one at a time — the right control for a row of long prose, the wrong one here —
74
+ and `UiFieldSchema` is `deny_unknown_fields`, so the shape had no way to ask.
75
+ `layout: table` is valid on an `array` whose `items` is an `object` and refused
76
+ with `quill::invalid_ui` anywhere else, and `schema()` echoes it verbatim. A
77
+ request, not a contract: the plate, `validate` and the blueprint are all
78
+ deliberately inert on it, and a consumer that cannot draw the control falls
79
+ back to its own choice for the type. `items.ui.title` is documented beside it
80
+ as the collapsed row's summary template, which needed no loader change.
81
+ Closes #1825.
82
+ - feat(core): **a card kind declaring `body.enabled: false` warns.** A card is a
83
+ part someone writes; a repeated record someone fills in is a row, an
84
+ `array<object>` on the card that owns it. Four card kinds across three airmark
85
+ quills were rows in card costume, each bodiless with a plate reassembling them
86
+ from the stream by position. `quill::bodiless_card_kind` says so at
87
+ `Severity::Warning`, hinting at the row shape. A warning and not a load error,
88
+ because the loader sees the proxy and not the fact: whether a kind interleaves
89
+ among kinds of other sorts is a property of documents and the plate, nothing in
90
+ `Quill.yaml` states it, and a bodiless positional kind — a page break, a rule,
91
+ an inserted signature block — is a card. `main` keeps the key unwarned: a form
92
+ has no root prose. Closes #1824.
93
+
94
+ ### The binding surface
95
+
96
+ - feat(wasm): **`formatDiagnostic` renders a diagnostic as the CLI does.**
97
+ `Document.formatDiagnostic` left the binding in 0.113 among the five owner
98
+ calls a host can make itself, and it was the one of the five that left a
99
+ surface behind: Python keeps the rendering on `PyDiagnostic.__str__`, which is
100
+ `fmt_pretty`, and the CLI prints through the same call, so WASM alone lost the
101
+ engine's English. A consumer wording its own still selects by `code` + `args`.
102
+
103
+ ### Docs and tests
104
+
105
+ - docs(core): **`ERROR.md` § "Error Presentation" names the two lanes apart.** A
106
+ consumer surfacing the engine's wording calls the one printer; a consumer
107
+ wording its own selects by `code` + `args` and owns the layout with the
108
+ sentence.
109
+ - docs(acroform): **the worked example gains the richtext field the fixture
110
+ does.** `sample_form` is what the backend guide points at for a hand-authored
111
+ `form.pdf` + `form.json`, so its excerpts state what that fixture declares.
112
+ - test(core): **one fixture walk, one scalar-fidelity home, one card-order
113
+ test.** Closes #1676.
114
+ - test(core): **one loader, one coercion table, one quill header.** Closes #1677.
115
+ - test(pdf,typst): **one base-PDF builder, one home per invariant.** Closes
116
+ #1681, closes #1680.
117
+ - ci: **the release dispatches the docs deploy it no longer triggers.**
118
+ `docs.yml` deploys Pages on `release: published`, and moving `gh release
119
+ create` onto `GITHUB_TOKEN` stopped that event starting a run, so the site sat
120
+ eleven releases behind at v0.102.0. `workflow_dispatch` is the one event exempt
121
+ from that rule, which `release-prepare.yml` already leans on for `ci.yml`, so
122
+ the release dispatches `docs.yml` at the tag it just pushed — the site is built
123
+ from the released bytes, and a prerelease is skipped as the event path skipped
124
+ it.
125
+ - build(deps): **lopdf 0.44.0 → 0.45.0**, and **taiki-e/install-action 2.87.8 →
126
+ 2.87.12** in the actions group.
127
+
3
128
  ## v0.113.0 - 2026-09-16
4
129
 
5
130
  Upgrade path: [0.112 → 0.113](docs/migrations/0.112-to-0.113.md).
package/core/wasm.d.ts CHANGED
@@ -397,6 +397,11 @@ export interface QuillFieldUi {
397
397
  /** Label for an `enum`'s blank option. Absent, the consumer supplies a
398
398
  * conventional label of its own. */
399
399
  blank_title?: string;
400
+ /** The control the field asks for, where the shape admits more than one.
401
+ * A request, not a contract: a consumer that cannot draw it falls back to
402
+ * its own choice for the type. `"table"` is valid only on an `array`
403
+ * whose `items` is an `object`. */
404
+ layout?: "table";
400
405
  }
401
406
 
402
407
  /** One entry in a card's `ui.groups` registry: a display-label override for the
@@ -448,7 +453,7 @@ export interface QuillCardBody {
448
453
  * gates render: an absent field blank-fills.
449
454
  */
450
455
  export interface QuillFieldSchema {
451
- type: "string" | "number" | "integer" | "boolean" | "array" | "object" | "date" | "datetime" | "richtext" | "plaintext" | "enum";
456
+ type: "string" | "number" | "integer" | "boolean" | "array" | "object" | "date" | "datetime" | "richtext" | "plaintext" | "enum" | "matrix";
452
457
  description?: string;
453
458
  default?: unknown;
454
459
  example?: unknown;
@@ -460,14 +465,30 @@ export interface QuillFieldSchema {
460
465
  * member. Declaring it makes the field rest as a container,
461
466
  * `{value: <member>, …that member's fields}`, rather than a bare string. */
462
467
  variants?: Record<string, Record<string, QuillFieldSchema>>;
468
+ /** The roster of a `type: "matrix"` field, required there and valid
469
+ * nowhere else: the closed vocabulary a document ticks, in display order.
470
+ * Each member is an object of `held` plus the field's `properties`
471
+ * (the columns), addressed as `<field>.<member id>.held`. */
472
+ members?: QuillMatrixGroup[];
463
473
  ui?: QuillFieldUi;
464
474
  properties?: Record<string, QuillFieldSchema>;
465
475
  items?: QuillFieldSchema;
476
+ /** The element count past which an `array` overflows the page it is laid
477
+ * out on. Valid only on an `array`. Never gates render: a document over
478
+ * the cap warns `validation::cardinality` and renders. */
479
+ max?: number;
466
480
  /** `true` on a `richtext` or `plaintext` field declared `inline`: the
467
481
  * single-paragraph, container-free, island-free constraint. */
468
482
  inline?: boolean;
469
483
  }
470
484
 
485
+ /** One block of a `type: "matrix"` roster: an optional display heading and the
486
+ * members under it, member id to display title. Key order is display order. */
487
+ export interface QuillMatrixGroup {
488
+ group?: string;
489
+ values: Record<string, string>;
490
+ }
491
+
471
492
  /** Schema entry for the main card or a named card kind. */
472
493
  export interface QuillCardSchema {
473
494
  description?: string;
@@ -923,6 +944,19 @@ export class Quill {
923
944
  */
924
945
  export function exportMarkdown(rt: Content): string;
925
946
 
947
+ /**
948
+ * Render a diagnostic as the CLI and Python's `str(diagnostic)` render it:
949
+ * the severity tag and the message, the code parenthesised after them, then
950
+ * location, path and hint each on an indented line of its own. The engine
951
+ * owns the one printer, so a consumer surfacing diagnostics reads it here
952
+ * rather than keeping a copy of the layout that drifts from the CLI's.
953
+ *
954
+ * Takes the `Diagnostic` shape every read hands back. Throws on a value that
955
+ * is not one — a missing `severity` or `message`, or a `severity` outside the
956
+ * two-value ladder.
957
+ */
958
+ export function formatDiagnostic(diagnostic: Diagnostic): string;
959
+
926
960
  /**
927
961
  * Serialize structured [`DocPathSeg`] segments back to the canonical path
928
962
  * string: the inverse of `parseDocPath`. Throws on a segment array the
@@ -1043,6 +1077,7 @@ export interface InitOutput {
1043
1077
  readonly document_toStored: (a: number, b: number) => void;
1044
1078
  readonly document_warnings: (a: number, b: number) => void;
1045
1079
  readonly exportMarkdown: (a: number, b: number) => void;
1080
+ readonly formatDiagnostic: (a: number, b: number) => void;
1046
1081
  readonly formatDocPath: (a: number, b: number) => void;
1047
1082
  readonly importMarkdown: (a: number, b: number, c: number) => void;
1048
1083
  readonly mapMarks: (a: number, b: number, c: number) => void;
package/core/wasm.js CHANGED
@@ -1546,6 +1546,44 @@ export function exportMarkdown(rt) {
1546
1546
  }
1547
1547
  }
1548
1548
 
1549
+ /**
1550
+ * Render a diagnostic as the CLI and Python's `str(diagnostic)` render it:
1551
+ * the severity tag and the message, the code parenthesised after them, then
1552
+ * location, path and hint each on an indented line of its own. The engine
1553
+ * owns the one printer, so a consumer surfacing diagnostics reads it here
1554
+ * rather than keeping a copy of the layout that drifts from the CLI's.
1555
+ *
1556
+ * Takes the `Diagnostic` shape every read hands back. Throws on a value that
1557
+ * is not one — a missing `severity` or `message`, or a `severity` outside the
1558
+ * two-value ladder.
1559
+ * @param {Diagnostic} diagnostic
1560
+ * @returns {string}
1561
+ */
1562
+ export function formatDiagnostic(diagnostic) {
1563
+ let deferred2_0;
1564
+ let deferred2_1;
1565
+ try {
1566
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
1567
+ wasm.formatDiagnostic(retptr, addHeapObject(diagnostic));
1568
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
1569
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
1570
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
1571
+ var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
1572
+ var ptr1 = r0;
1573
+ var len1 = r1;
1574
+ if (r3) {
1575
+ ptr1 = 0; len1 = 0;
1576
+ throw takeObject(r2);
1577
+ }
1578
+ deferred2_0 = ptr1;
1579
+ deferred2_1 = len1;
1580
+ return getStringFromWasm0(ptr1, len1);
1581
+ } finally {
1582
+ wasm.__wbindgen_add_to_stack_pointer(16);
1583
+ wasm.__wbindgen_export4(deferred2_0, deferred2_1, 1);
1584
+ }
1585
+ }
1586
+
1549
1587
  /**
1550
1588
  * Serialize structured [`DocPathSeg`] segments back to the canonical path
1551
1589
  * string: the inverse of `parseDocPath`. Throws on a segment array the
package/core/wasm_bg.wasm CHANGED
Binary file
@@ -52,6 +52,7 @@ export const document_toMarkdown: (a: number, b: number) => void;
52
52
  export const document_toStored: (a: number, b: number) => void;
53
53
  export const document_warnings: (a: number, b: number) => void;
54
54
  export const exportMarkdown: (a: number, b: number) => void;
55
+ export const formatDiagnostic: (a: number, b: number) => void;
55
56
  export const formatDocPath: (a: number, b: number) => void;
56
57
  export const importMarkdown: (a: number, b: number, c: number) => void;
57
58
  export const mapMarks: (a: number, b: number, c: number) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quillmark/wasm",
3
- "version": "0.113.0",
3
+ "version": "0.114.0",
4
4
  "description": "WebAssembly bindings for Quillmark, a schema-driven document engine",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
package/render/wasm.d.ts CHANGED
@@ -452,6 +452,11 @@ export interface QuillFieldUi {
452
452
  /** Label for an `enum`'s blank option. Absent, the consumer supplies a
453
453
  * conventional label of its own. */
454
454
  blank_title?: string;
455
+ /** The control the field asks for, where the shape admits more than one.
456
+ * A request, not a contract: a consumer that cannot draw it falls back to
457
+ * its own choice for the type. `"table"` is valid only on an `array`
458
+ * whose `items` is an `object`. */
459
+ layout?: "table";
455
460
  }
456
461
 
457
462
  /** One entry in a card's `ui.groups` registry: a display-label override for the
@@ -503,7 +508,7 @@ export interface QuillCardBody {
503
508
  * gates render: an absent field blank-fills.
504
509
  */
505
510
  export interface QuillFieldSchema {
506
- type: "string" | "number" | "integer" | "boolean" | "array" | "object" | "date" | "datetime" | "richtext" | "plaintext" | "enum";
511
+ type: "string" | "number" | "integer" | "boolean" | "array" | "object" | "date" | "datetime" | "richtext" | "plaintext" | "enum" | "matrix";
507
512
  description?: string;
508
513
  default?: unknown;
509
514
  example?: unknown;
@@ -515,14 +520,30 @@ export interface QuillFieldSchema {
515
520
  * member. Declaring it makes the field rest as a container,
516
521
  * `{value: <member>, …that member's fields}`, rather than a bare string. */
517
522
  variants?: Record<string, Record<string, QuillFieldSchema>>;
523
+ /** The roster of a `type: "matrix"` field, required there and valid
524
+ * nowhere else: the closed vocabulary a document ticks, in display order.
525
+ * Each member is an object of `held` plus the field's `properties`
526
+ * (the columns), addressed as `<field>.<member id>.held`. */
527
+ members?: QuillMatrixGroup[];
518
528
  ui?: QuillFieldUi;
519
529
  properties?: Record<string, QuillFieldSchema>;
520
530
  items?: QuillFieldSchema;
531
+ /** The element count past which an `array` overflows the page it is laid
532
+ * out on. Valid only on an `array`. Never gates render: a document over
533
+ * the cap warns `validation::cardinality` and renders. */
534
+ max?: number;
521
535
  /** `true` on a `richtext` or `plaintext` field declared `inline`: the
522
536
  * single-paragraph, container-free, island-free constraint. */
523
537
  inline?: boolean;
524
538
  }
525
539
 
540
+ /** One block of a `type: "matrix"` roster: an optional display heading and the
541
+ * members under it, member id to display title. Key order is display order. */
542
+ export interface QuillMatrixGroup {
543
+ group?: string;
544
+ values: Record<string, string>;
545
+ }
546
+
526
547
  /** Schema entry for the main card or a named card kind. */
527
548
  export interface QuillCardSchema {
528
549
  description?: string;
@@ -1225,6 +1246,19 @@ export class Quillmark {
1225
1246
  */
1226
1247
  export function exportMarkdown(rt: Content): string;
1227
1248
 
1249
+ /**
1250
+ * Render a diagnostic as the CLI and Python's `str(diagnostic)` render it:
1251
+ * the severity tag and the message, the code parenthesised after them, then
1252
+ * location, path and hint each on an indented line of its own. The engine
1253
+ * owns the one printer, so a consumer surfacing diagnostics reads it here
1254
+ * rather than keeping a copy of the layout that drifts from the CLI's.
1255
+ *
1256
+ * Takes the `Diagnostic` shape every read hands back. Throws on a value that
1257
+ * is not one — a missing `severity` or `message`, or a `severity` outside the
1258
+ * two-value ladder.
1259
+ */
1260
+ export function formatDiagnostic(diagnostic: Diagnostic): string;
1261
+
1228
1262
  /**
1229
1263
  * Serialize structured [`DocPathSeg`] segments back to the canonical path
1230
1264
  * string: the inverse of `parseDocPath`. Throws on a segment array the
@@ -1347,6 +1381,7 @@ export interface InitOutput {
1347
1381
  readonly document_toStored: (a: number, b: number) => void;
1348
1382
  readonly document_warnings: (a: number, b: number) => void;
1349
1383
  readonly exportMarkdown: (a: number, b: number) => void;
1384
+ readonly formatDiagnostic: (a: number, b: number) => void;
1350
1385
  readonly formatDocPath: (a: number, b: number) => void;
1351
1386
  readonly importMarkdown: (a: number, b: number, c: number) => void;
1352
1387
  readonly livesession_backendId: (a: number, b: number) => void;
package/render/wasm.js CHANGED
@@ -1965,6 +1965,44 @@ export function exportMarkdown(rt) {
1965
1965
  }
1966
1966
  }
1967
1967
 
1968
+ /**
1969
+ * Render a diagnostic as the CLI and Python's `str(diagnostic)` render it:
1970
+ * the severity tag and the message, the code parenthesised after them, then
1971
+ * location, path and hint each on an indented line of its own. The engine
1972
+ * owns the one printer, so a consumer surfacing diagnostics reads it here
1973
+ * rather than keeping a copy of the layout that drifts from the CLI's.
1974
+ *
1975
+ * Takes the `Diagnostic` shape every read hands back. Throws on a value that
1976
+ * is not one — a missing `severity` or `message`, or a `severity` outside the
1977
+ * two-value ladder.
1978
+ * @param {Diagnostic} diagnostic
1979
+ * @returns {string}
1980
+ */
1981
+ export function formatDiagnostic(diagnostic) {
1982
+ let deferred2_0;
1983
+ let deferred2_1;
1984
+ try {
1985
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
1986
+ wasm.formatDiagnostic(retptr, addHeapObject(diagnostic));
1987
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
1988
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
1989
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
1990
+ var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
1991
+ var ptr1 = r0;
1992
+ var len1 = r1;
1993
+ if (r3) {
1994
+ ptr1 = 0; len1 = 0;
1995
+ throw takeObject(r2);
1996
+ }
1997
+ deferred2_0 = ptr1;
1998
+ deferred2_1 = len1;
1999
+ return getStringFromWasm0(ptr1, len1);
2000
+ } finally {
2001
+ wasm.__wbindgen_add_to_stack_pointer(16);
2002
+ wasm.__wbindgen_export4(deferred2_0, deferred2_1, 1);
2003
+ }
2004
+ }
2005
+
1968
2006
  /**
1969
2007
  * Serialize structured [`DocPathSeg`] segments back to the canonical path
1970
2008
  * string: the inverse of `parseDocPath`. Throws on a segment array the
Binary file
@@ -54,6 +54,7 @@ export const document_toMarkdown: (a: number, b: number) => void;
54
54
  export const document_toStored: (a: number, b: number) => void;
55
55
  export const document_warnings: (a: number, b: number) => void;
56
56
  export const exportMarkdown: (a: number, b: number) => void;
57
+ export const formatDiagnostic: (a: number, b: number) => void;
57
58
  export const formatDocPath: (a: number, b: number) => void;
58
59
  export const importMarkdown: (a: number, b: number, c: number) => void;
59
60
  export const livesession_backendId: (a: number, b: number) => void;
@@ -22,7 +22,8 @@ import type {
22
22
  mapPos,
23
23
  mapMarks,
24
24
  parseDocPath,
25
- formatDocPath
25
+ formatDocPath,
26
+ formatDiagnostic
26
27
  } from '../core/wasm.js';
27
28
 
28
29
  /**
@@ -42,6 +43,7 @@ export interface CoreSurface {
42
43
  mapMarks: typeof mapMarks;
43
44
  parseDocPath: typeof parseDocPath;
44
45
  formatDocPath: typeof formatDocPath;
46
+ formatDiagnostic: typeof formatDiagnostic;
45
47
  }
46
48
 
47
49
  /**
@@ -106,6 +108,7 @@ export type {
106
108
  QuillFieldUi,
107
109
  QuillCardUi,
108
110
  QuillGroupUi,
111
+ QuillMatrixGroup,
109
112
  QuillMetadata
110
113
  } from '../core/wasm.js';
111
114
 
@@ -20,7 +20,7 @@ import initCore, { Quill, Document } from '../core/wasm.js';
20
20
  // Resolution-time, so `node:fs` never enters a browser graph.
21
21
  import { toModuleSource } from '#quillmark-env';
22
22
  import { importMarkdown, exportMarkdown, rebase, mapPos, mapMarks } from '../core/wasm.js';
23
- import { parseDocPath, formatDocPath } from '../core/wasm.js';
23
+ import { parseDocPath, formatDocPath, formatDiagnostic } from '../core/wasm.js';
24
24
 
25
25
  // A `--target web` build exports its classes synchronously but carries no wasm
26
26
  // instance until something instantiates it. This module owns that for core,
@@ -50,7 +50,8 @@ const CORE_SURFACE = Object.freeze({
50
50
  mapPos,
51
51
  mapMarks,
52
52
  parseDocPath,
53
- formatDocPath
53
+ formatDocPath,
54
+ formatDiagnostic
54
55
  });
55
56
 
56
57
  /** The in-flight or settled core instantiation, resolving to `CORE_SURFACE`.