@quillmark/wasm 0.119.0 → 0.121.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,80 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.121.0 - 2026-09-30
4
+
5
+ Upgrade path: [0.120 → 0.121](docs/migrations/0.120-to-0.121.md).
6
+
7
+ ### Matrix presence
8
+
9
+ - feat(core,typst,wasm)!: **a matrix member is held by being present in the
10
+ document**: a mapping is held whatever it carries, `{}` included, and a bare
11
+ scalar is the tick. A mapping naming no `held` flips from unticked to ticked,
12
+ with nothing reporting it. `held` is never stored: a member mapping storing
13
+ it fails validation as `validation::held_stored`, and the render with it, and
14
+ a `Quill.yaml` `seed:` or `default:` storing it fails to load as
15
+ `quill::seed_held_stored` / `quill::default_held_stored`. A `held: null` is
16
+ absent. The strict write rests a held member with no answers as `true`, and
17
+ the blueprint's `# e.g.` line drops `held: true`. (#2023)
18
+
19
+ ### Matrix plate
20
+
21
+ - feat(core,typst,acroform)!: **a matrix reaches the plate as the members it
22
+ holds**, each its columns keyed by id: no member carries `held` or a roster
23
+ `title`, and an unheld member is absent, so a plate reading `m.held` or
24
+ `m.title` fails to compile. `roster(dict, key)` in the Typst helper prints the
25
+ whole vocabulary as `(id, title, held, value, path)` rows, and the dictionary
26
+ declaring a matrix carries `$path` for it. A member's tick is its own address,
27
+ `<field>.<member>`: a claim on `<field>.<member>.held` fails the compile, an
28
+ acroform binding on it fails to load as `acroform::dangling_binding`, and a
29
+ bare tick the boolean coercion refuses is `validation::type_mismatch` at the
30
+ member's path. `resolve()` reports the members a matrix holds. A matrix takes
31
+ a `default:` and `type: matrix?`. The transform schema carries the roster as
32
+ `quillmark:roster` `[id, title]` pairs, and Rust `QUILLMARK_ORDER_KEY` is
33
+ `QUILLMARK_ROSTER_KEY`; `FieldSchema::members` is `FieldSchema::member`,
34
+ beside `added_item`, and `namespace_props` answers `None` for a matrix.
35
+ (#2023)
36
+
37
+ ### Open matrix
38
+
39
+ - feat(core,typst,wasm): **`open: true` on a matrix admits items a document
40
+ adds**, each keyed by a snake_case id and carrying a `title`, taking the
41
+ roster's columns. The plate and `roster` carry them after the held roster
42
+ members, sorted by id, and an added item's `title` is a cell with an address.
43
+ Any other key outside the roster is `validation::enum_violation`, which gains
44
+ an `open` arg. The transform schema declares the added item as
45
+ `additionalProperties`, `schema()` emits `open: true` (WASM
46
+ `QuillFieldSchema.open`), and an acroform quill declaring one fails to load as
47
+ `quill::open_matrix_unsupported`. `FieldType::Matrix` carries `open: bool`.
48
+ (#2023)
49
+
50
+ ### Release
51
+
52
+ - ci(release): **crate publishing retries past a crates.io index backlog**,
53
+ excluding the crates crates.io already holds at the release version, so a
54
+ re-run resumes a partial upload. (#2029)
55
+
56
+
57
+ ## v0.120.0 - 2026-09-30
58
+
59
+ Upgrade path: [0.119 → 0.120](docs/migrations/0.119-to-0.120.md).
60
+
61
+ ### `Engine.load`
62
+
63
+ - feat(wasm): **`engine.load(quill)` loads and instantiates a quill's backend
64
+ build without a document**, cloning no quill. It is the memoized load
65
+ `render` and `open` await, so a host can start the render build's fetch once
66
+ the quill resolves and mount its editor on core meanwhile. Awaiting it before
67
+ `open` makes the session's first compile read the current document. A failed
68
+ load rejects, `runtime::backend_load_failed` for the built-ins, and the next
69
+ call retries. (#2027)
70
+
71
+ ### `quill::table_column_not_leaf`
72
+
73
+ - refactor(core)!: **a `ui.layout: table` column that is not a leaf fails to
74
+ load as `quill::table_column_not_leaf`**, where it was
75
+ `quill::table_column_not_flat`. Its trigger and message are unchanged.
76
+ (#2021)
77
+
3
78
  ## v0.119.0 - 2026-09-30
4
79
 
5
80
  ### `ui.layout: flat`
package/README.md CHANGED
@@ -119,8 +119,8 @@ A load failure surfaces as `runtime::init_failed`, whose hint names that line.
119
119
  Create the render dispatcher. Routes each quill to its backend by
120
120
  `quill.backendId`, lazily loads that backend binary, and renders: cloning the
121
121
  quill/document into the backend's memory and freeing the clones internally.
122
- `render`, `open`, and `supportedFormats` are **async** (the first call may load
123
- a backend). Pass `{ backends }` to register or override backend descriptors.
122
+ `render`, `open`, `load`, and `supportedFormats` are **async** (the first call
123
+ may load a backend). Pass `{ backends }` to register or override backend descriptors.
124
124
  Each entry is a descriptor (`{ [backendId]: { load, formats } }`) where `load`
125
125
  is the lazy thunk returning the backend module and `formats` is the
126
126
  **required** static capability manifest. A malformed descriptor throws at
@@ -131,6 +131,21 @@ is the lazy thunk returning the backend module and `formats` is the
131
131
  manifest: never loading the multi-MB backend binary and never cloning the
132
132
  quill. Use it as a non-failing pre-render probe.
133
133
 
134
+ **An editor does not wait on the render build.** `open` reads the document
135
+ before it awaits the backend load, so a session opened while the build loads
136
+ compiles the document as it stood at the call. Mount the editor on core, start
137
+ the load, and open once it lands:
138
+
139
+ ```js
140
+ void engine.load(quill); // start the fetch as soon as the quill resolves
141
+ mountEditor(quill, doc); // core alone
142
+ await engine.load(quill); // memoized: the same load
143
+ const session = await engine.open(quill, doc); // one compile, current document
144
+ ```
145
+
146
+ `load` reads only `quill.backendId` and clones nothing. A failed load rejects
147
+ with `runtime::backend_load_failed`, and the next call retries.
148
+
134
149
  ### The two doors: `Document.fromMarkdown` vs `quill.parse` / `quill.conform`
135
150
 
136
151
  `Document.fromMarkdown` is the quill-free **transport door** (migrations, `$ext`
@@ -451,7 +466,7 @@ try {
451
466
 
452
467
  **Delivery follows the function, not the failure.** A synchronous method throws;
453
468
  a promise-returning one rejects. The promise-returning surface is `init` and the
454
- three `Engine` verbs (`render`, `open`, `supportedFormats`), so a programming
469
+ four `Engine` verbs (`render`, `open`, `load`, `supportedFormats`), so a programming
455
470
  error reached through one of them (a foreign handle, an unregistered backend)
456
471
  rejects like any other failure. Nothing here both returns
457
472
  a promise and throws, so a `.catch` on a promise-returning call is a whole
package/core/wasm.d.ts CHANGED
@@ -383,7 +383,7 @@ export interface QuillFieldUi {
383
383
  /** The control the field asks for, where the shape admits more than one.
384
384
  * `"table"` is valid only on an `array` whose `items` is an `object`.
385
385
  * Every column is a leaf, a contract refused at load as
386
- * `quill::table_column_not_flat`. `"flat"` is valid only on an `object`
386
+ * `quill::table_column_not_leaf`. `"flat"` is valid only on an `object`
387
387
  * that is not an array's element: its properties stand at the depth of the
388
388
  * field list around it, with no frame of their own. Either is a
389
389
  * request: a consumer that cannot draws its own choice for the type. */
@@ -439,9 +439,16 @@ export interface QuillFieldSchema {
439
439
  variants?: Record<string, Record<string, QuillFieldSchema>>;
440
440
  /** The roster of a `type: "matrix"` field, required there and valid
441
441
  * nowhere else: member id to display title, key order the display order.
442
- * Each member is an object of `held` plus the field's `properties`
443
- * (the columns), addressed as `<field>.<member id>.held`. */
442
+ * A member is held by being present in the document, as a mapping of the
443
+ * field's `properties` (the columns) or a bare `true`; unticking removes
444
+ * it. Its own address `<field>.<member id>` is the tick, and each column
445
+ * addresses one step further down. */
444
446
  members?: Record<string, string>;
447
+ /** `true` on a `type: "matrix"` field admitting items a document adds
448
+ * beside the roster: each keyed by a snake_case id and carrying a
449
+ * `title` string beside the columns, held by being present. Valid only
450
+ * on a matrix. */
451
+ open?: boolean;
445
452
  ui?: QuillFieldUi;
446
453
  properties?: Record<string, QuillFieldSchema>;
447
454
  items?: QuillFieldSchema;
package/core/wasm_bg.wasm CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quillmark/wasm",
3
- "version": "0.119.0",
3
+ "version": "0.121.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
@@ -394,7 +394,7 @@ export interface QuillFieldUi {
394
394
  /** The control the field asks for, where the shape admits more than one.
395
395
  * `"table"` is valid only on an `array` whose `items` is an `object`.
396
396
  * Every column is a leaf, a contract refused at load as
397
- * `quill::table_column_not_flat`. `"flat"` is valid only on an `object`
397
+ * `quill::table_column_not_leaf`. `"flat"` is valid only on an `object`
398
398
  * that is not an array's element: its properties stand at the depth of the
399
399
  * field list around it, with no frame of their own. Either is a
400
400
  * request: a consumer that cannot draws its own choice for the type. */
@@ -450,9 +450,16 @@ export interface QuillFieldSchema {
450
450
  variants?: Record<string, Record<string, QuillFieldSchema>>;
451
451
  /** The roster of a `type: "matrix"` field, required there and valid
452
452
  * nowhere else: member id to display title, key order the display order.
453
- * Each member is an object of `held` plus the field's `properties`
454
- * (the columns), addressed as `<field>.<member id>.held`. */
453
+ * A member is held by being present in the document, as a mapping of the
454
+ * field's `properties` (the columns) or a bare `true`; unticking removes
455
+ * it. Its own address `<field>.<member id>` is the tick, and each column
456
+ * addresses one step further down. */
455
457
  members?: Record<string, string>;
458
+ /** `true` on a `type: "matrix"` field admitting items a document adds
459
+ * beside the roster: each keyed by a snake_case id and carrying a
460
+ * `title` string beside the columns, held by being present. Valid only
461
+ * on a matrix. */
462
+ open?: boolean;
456
463
  ui?: QuillFieldUi;
457
464
  properties?: Record<string, QuillFieldSchema>;
458
465
  items?: QuillFieldSchema;
Binary file
@@ -423,6 +423,19 @@ export declare class Engine {
423
423
  */
424
424
  open(quill: Quill, doc: Document, today?: string): Promise<LiveSession>;
425
425
 
426
+ /**
427
+ * Load and instantiate `quill`'s backend build, reading no document and
428
+ * cloning no quill. It is the memoized load `render` and `open` await, so a
429
+ * host can start the fetch before it has a document to open. Only
430
+ * `quill.backendId` is read, before the first await. A failed load rejects
431
+ * (`runtime::backend_load_failed` for the built-ins) and the next call
432
+ * retries.
433
+ *
434
+ * `open` snapshots its document before awaiting this load: await `load`
435
+ * first, and the session's first compile is of the current document.
436
+ */
437
+ load(quill: Quill): Promise<void>;
438
+
426
439
  /**
427
440
  * Output formats `quill`'s backend can emit. An always-free pre-render probe:
428
441
  * it answers from the descriptor's `formats` manifest without loading the
@@ -553,6 +553,14 @@ export class Engine {
553
553
  );
554
554
  }
555
555
 
556
+ /**
557
+ * @param {Quill} quill
558
+ * @returns {Promise<void>}
559
+ */
560
+ async load(quill) {
561
+ await this.#resolveBackend(this.#backendOf(quill, 'engine.load(quill)'));
562
+ }
563
+
556
564
  /**
557
565
  * @param {Quill} quill
558
566
  * @returns {Promise<import('./runtime.js').OutputFormat[]>}