@quillmark/wasm 0.131.0 → 0.132.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,53 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.132.0 - 2026-10-27
4
+
5
+ Upgrade path: [0.131 → 0.132](docs/migrations/0.131-to-0.132.md). A row
6
+ holding a `qm-*` element or a definition list loads as what it held, and every
7
+ Typst PDF now carries a title.
8
+
9
+ ### Quill bundles
10
+
11
+ - feat(core): **a quill reads and writes as one `.quill` bundle**, its file
12
+ tree as one zip: `Quill.yaml` at the archive root, `/` paths with no `..`,
13
+ stored or deflated entries, and a budget of 2048 entries, 32 MiB a file and
14
+ 64 MiB in all, counted off the central directory before anything inflates.
15
+ [`prose/references/quill-bundle.md`](prose/references/quill-bundle.md)
16
+ specifies the format. `Quill::from_bundle` and `Quill::to_bundle` sit beside
17
+ `from_tree`, and a refused bundle fails as `quill::bundle_invalid`,
18
+ `quill::bundle_unsupported`, `quill::bundle_path` or
19
+ `quill::bundle_too_large`. An archive listing one path as both a file and a
20
+ directory is refused.
21
+ - feat(bindings): **every surface reads and writes a bundle**: WASM
22
+ `Quill.fromBundle(bytes)` and `quill.toBundle()` in both builds, Python
23
+ `Quill.from_bundle(bytes)` and `quill.to_bundle()`. `quill_from_path` reads a
24
+ file named `*.quill` as a bundle, so `Quill.from_path` and every CLI command
25
+ taking a quill path take one; `workspace` refuses a file. `quillmark pack
26
+ <QUILL_PATH> [-o FILE]` writes one, by default `<name>@<version>.quill`.
27
+
28
+ ### Content
29
+
30
+ - feat(content)!: **a `qm-<name>` element and a definition list are no longer
31
+ content.** A `qm-*` tag other than `qm-span` and `qm-anchor` drops, its open
32
+ tag warning `parse::dropped_construct` under its name, and what it wrapped
33
+ imports as written. A definition list reads as the paragraph CommonMark
34
+ reads. A stored `element` or `description` container or `term` line loads as
35
+ what it held and saves without it, under the tag it would take anyway; the
36
+ authored lanes refuse either container. The Typst helper's `elements`
37
+ registry, `_qm-element` and `typst::unregistered_element` are gone, so a
38
+ plate calling `qm.elements.update(..)` fails to compile until the call goes.
39
+
40
+ ### Rendering
41
+
42
+ - feat(typst)!: **every Typst PDF carries a title**, in `/Info /Title` and XMP
43
+ `dc:title`: the render's new `title` option, else the plate's
44
+ `set document(title: ..)`, else the quill's `description`, trimmed.
45
+ `RenderOptions` gains `title`, the WASM and Python render options carry it,
46
+ and `quillmark render` takes `--title`.
47
+ - fix(typst): **a table cell breaks inside an email address or dotted name**,
48
+ such as `Michael.Marshall@us.af.mil`, where one wider than its column ran
49
+ into the next cell. The address still copies out of the PDF whole.
50
+
3
51
  ## v0.131.0 - 2026-10-26
4
52
 
5
53
  Upgrade path: [0.130 → 0.131](docs/migrations/0.130-to-0.131.md). A row
package/README.md CHANGED
@@ -383,7 +383,7 @@ the local date): what a `today` date field and a plate's `datetime.today()`
383
383
  render as. A session keeps the date it opened with, so a preview left open past
384
384
  midnight renders yesterday's until it is reopened.
385
385
 
386
- `opts` takes `format`, `ppi`, `pages` and `regions`, on `engine.render` and
386
+ `opts` takes `format`, `ppi`, `pages`, `regions` and `title`, on `engine.render` and
387
387
  `session.render` alike. Any other key throws rather than reading as absent,
388
388
  `today` included, so `engine.render(quill, doc, { today })` rejects instead of
389
389
  rendering the local date. The date goes last:
@@ -2153,14 +2153,14 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH RE
2153
2153
 
2154
2154
  ## Apache License 2.0
2155
2155
 
2156
- - quillmark-acroform 0.131.0 (https://github.com/borb-sh/quillmark)
2157
- - quillmark-typst 0.131.0 (https://github.com/borb-sh/quillmark)
2158
- - quillmark-cli 0.131.0 (https://github.com/borb-sh/quillmark)
2159
- - quillmark-python 0.131.0
2160
- - quillmark-content 0.131.0 (https://github.com/borb-sh/quillmark)
2161
- - quillmark-core 0.131.0 (https://github.com/borb-sh/quillmark)
2162
- - quillmark 0.131.0 (https://github.com/borb-sh/quillmark)
2163
- - quillmark-pdf 0.131.0 (https://github.com/borb-sh/quillmark)
2156
+ - quillmark-acroform 0.132.0 (https://github.com/borb-sh/quillmark)
2157
+ - quillmark-typst 0.132.0 (https://github.com/borb-sh/quillmark)
2158
+ - quillmark-cli 0.132.0 (https://github.com/borb-sh/quillmark)
2159
+ - quillmark-python 0.132.0
2160
+ - quillmark-content 0.132.0 (https://github.com/borb-sh/quillmark)
2161
+ - quillmark-core 0.132.0 (https://github.com/borb-sh/quillmark)
2162
+ - quillmark 0.132.0 (https://github.com/borb-sh/quillmark)
2163
+ - quillmark-pdf 0.132.0 (https://github.com/borb-sh/quillmark)
2164
2164
  - ciborium-io 0.2.2 (https://github.com/enarx/ciborium)
2165
2165
  - ciborium-ll 0.2.2 (https://github.com/enarx/ciborium)
2166
2166
  - ciborium 0.2.2 (https://github.com/enarx/ciborium)
@@ -6248,8 +6248,8 @@ limitations under the License.
6248
6248
 
6249
6249
  ## Apache License 2.0
6250
6250
 
6251
- - quillmark-wasm 0.131.0 (https://github.com/borb-sh/quillmark)
6252
- - quillmark-fixtures 0.131.0
6251
+ - quillmark-wasm 0.132.0 (https://github.com/borb-sh/quillmark)
6252
+ - quillmark-fixtures 0.132.0
6253
6253
  - arraydeque 0.5.1 (https://github.com/andylokandy/arraydeque)
6254
6254
  - codex 0.3.0 (https://github.com/typst/codex)
6255
6255
  - color 0.3.3 (https://github.com/linebender/color)
package/core/wasm.d.ts CHANGED
@@ -80,8 +80,7 @@ export type ContentLineKind =
80
80
  | { kind: "para" }
81
81
  | { kind: "heading"; attrs: { level: number } }
82
82
  | { kind: "code"; attrs?: { lang?: string } }
83
- | { kind: "rule" }
84
- | { kind: "term" };
83
+ | { kind: "rule" };
85
84
 
86
85
  /** An ancestor block a line nests inside, outermost first. Closed like
87
86
  * `ContentLine.kind`.
@@ -110,14 +109,7 @@ export type ContentContainer =
110
109
  attrs: { ordered: boolean; start: number; ordinal: number; checked?: boolean };
111
110
  instance?: number;
112
111
  }
113
- | { container: "quote"; instance?: number }
114
- | { container: "description"; instance?: number }
115
- | { container: "element"; attrs: ElementAttrs; instance?: number };
116
-
117
- /** A carrier element's name and attributes, one bag: `$name` is the part of
118
- * its `qm-<name>` tag after the prefix, and every other key an attribute as
119
- * written. */
120
- export type ElementAttrs = { $name: string; [attr: string]: string };
112
+ | { container: "quote"; instance?: number };
121
113
 
122
114
  /** A mark over char range `[start, end)` into `Content.text`. `type` is a
123
115
  * closed set, so `type === "link"` narrows `attrs` to `{ url: string }` with no
@@ -687,8 +679,9 @@ export class Document {
687
679
  * The newest storage version this build writes via
688
680
  * [`toStored`](Document::to_stored): a document spelling a font mark, a
689
681
  * `table` element, a merged table cell or a table head 0.130 cannot draw
690
- * carries it, every other the tag before it, which a 0.130 build reads. The tag advances only when the wire format changes, not on
691
- * every release.
682
+ * carries it, every other the tag before it, which a 0.130 build reads.
683
+ * The tag advances only when the wire format changes, not on every
684
+ * release.
692
685
  */
693
686
  static currentStorageVersion(): string;
694
687
  /**
@@ -956,6 +949,12 @@ export class Quill {
956
949
  * parse or its `$quill` is not this quill's bare name.
957
950
  */
958
951
  exampleDocument(): Document | undefined;
952
+ /**
953
+ * Read a `.quill` bundle, the zip archive holding one quill's file tree.
954
+ * Pure, as [`fromTree`](Self::from_tree) is. A bundle outside the format
955
+ * throws one `quill::bundle_*` diagnostic.
956
+ */
957
+ static fromBundle(bytes: Uint8Array): Quill;
959
958
  /**
960
959
  * Build a quill from a file tree. Pure: the declared backend is resolved
961
960
  * later, at render time. Accepts a `Map<string, Uint8Array>` or a plain
@@ -998,6 +997,11 @@ export class Quill {
998
997
  * `$kind: main` card of [`seedDocument`](Self::seed_document) alone.
999
998
  */
1000
999
  seedMain(): Card;
1000
+ /**
1001
+ * This quill's file tree as a `.quill` bundle, the bytes
1002
+ * [`fromBundle`](Self::from_bundle) reads.
1003
+ */
1004
+ toBundle(): Uint8Array;
1001
1005
  /**
1002
1006
  * Flatten this quill back into its canonical file tree, the inverse of
1003
1007
  * [`fromTree`](Self::from_tree). Keys are `"/"`-joined relative paths.
@@ -1212,6 +1216,7 @@ export interface InitOutput {
1212
1216
  readonly quill_conform: (a: number, b: number, c: number) => void;
1213
1217
  readonly quill_emptyDocument: (a: number) => number;
1214
1218
  readonly quill_exampleDocument: (a: number, b: number) => void;
1219
+ readonly quill_fromBundle: (a: number, b: number, c: number) => void;
1215
1220
  readonly quill_fromTree: (a: number, b: number) => void;
1216
1221
  readonly quill_metadata: (a: number, b: number) => void;
1217
1222
  readonly quill_parse: (a: number, b: number, c: number, d: number) => void;
@@ -1219,6 +1224,7 @@ export interface InitOutput {
1219
1224
  readonly quill_seedCard: (a: number, b: number, c: number, d: number, e: number) => void;
1220
1225
  readonly quill_seedDocument: (a: number) => number;
1221
1226
  readonly quill_seedMain: (a: number, b: number) => void;
1227
+ readonly quill_toBundle: (a: number, b: number) => void;
1222
1228
  readonly quill_toTree: (a: number) => number;
1223
1229
  readonly quill_validate: (a: number, b: number, c: number) => void;
1224
1230
  readonly quill_warnings: (a: number, b: number) => void;
package/core/wasm.js CHANGED
@@ -444,8 +444,9 @@ export class Document {
444
444
  * The newest storage version this build writes via
445
445
  * [`toStored`](Document::to_stored): a document spelling a font mark, a
446
446
  * `table` element, a merged table cell or a table head 0.130 cannot draw
447
- * carries it, every other the tag before it, which a 0.130 build reads. The tag advances only when the wire format changes, not on
448
- * every release.
447
+ * carries it, every other the tag before it, which a 0.130 build reads.
448
+ * The tag advances only when the wire format changes, not on every
449
+ * release.
449
450
  * @returns {string}
450
451
  */
451
452
  static currentStorageVersion() {
@@ -1342,6 +1343,30 @@ export class Quill {
1342
1343
  wasm.__wbindgen_add_to_stack_pointer(16);
1343
1344
  }
1344
1345
  }
1346
+ /**
1347
+ * Read a `.quill` bundle, the zip archive holding one quill's file tree.
1348
+ * Pure, as [`fromTree`](Self::from_tree) is. A bundle outside the format
1349
+ * throws one `quill::bundle_*` diagnostic.
1350
+ * @param {Uint8Array} bytes
1351
+ * @returns {Quill}
1352
+ */
1353
+ static fromBundle(bytes) {
1354
+ try {
1355
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
1356
+ const ptr0 = passArray8ToWasm0(bytes, wasm.__wbindgen_export);
1357
+ const len0 = WASM_VECTOR_LEN;
1358
+ wasm.quill_fromBundle(retptr, ptr0, len0);
1359
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
1360
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
1361
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
1362
+ if (r2) {
1363
+ throw takeObject(r1);
1364
+ }
1365
+ return Quill.__wrap(r0);
1366
+ } finally {
1367
+ wasm.__wbindgen_add_to_stack_pointer(16);
1368
+ }
1369
+ }
1345
1370
  /**
1346
1371
  * Build a quill from a file tree. Pure: the declared backend is resolved
1347
1372
  * later, at render time. Accepts a `Map<string, Uint8Array>` or a plain
@@ -1498,6 +1523,29 @@ export class Quill {
1498
1523
  wasm.__wbindgen_add_to_stack_pointer(16);
1499
1524
  }
1500
1525
  }
1526
+ /**
1527
+ * This quill's file tree as a `.quill` bundle, the bytes
1528
+ * [`fromBundle`](Self::from_bundle) reads.
1529
+ * @returns {Uint8Array}
1530
+ */
1531
+ toBundle() {
1532
+ try {
1533
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
1534
+ wasm.quill_toBundle(retptr, this.__wbg_ptr);
1535
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
1536
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
1537
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
1538
+ var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
1539
+ if (r3) {
1540
+ throw takeObject(r2);
1541
+ }
1542
+ var v1 = getArrayU8FromWasm0(r0, r1).slice();
1543
+ wasm.__wbindgen_export4(r0, r1 * 1, 1);
1544
+ return v1;
1545
+ } finally {
1546
+ wasm.__wbindgen_add_to_stack_pointer(16);
1547
+ }
1548
+ }
1501
1549
  /**
1502
1550
  * Flatten this quill back into its canonical file tree, the inverse of
1503
1551
  * [`fromTree`](Self::from_tree). Keys are `"/"`-joined relative paths.
@@ -2329,6 +2377,13 @@ function isLikeNone(x) {
2329
2377
  return x === undefined || x === null;
2330
2378
  }
2331
2379
 
2380
+ function passArray8ToWasm0(arg, malloc) {
2381
+ const ptr = malloc(arg.length * 1, 1) >>> 0;
2382
+ getUint8ArrayMemory0().set(arg, ptr / 1);
2383
+ WASM_VECTOR_LEN = arg.length;
2384
+ return ptr;
2385
+ }
2386
+
2332
2387
  function passStringToWasm0(arg, malloc, realloc) {
2333
2388
  if (realloc === undefined) {
2334
2389
  const buf = cachedTextEncoder.encode(arg);
package/core/wasm_bg.wasm CHANGED
Binary file
@@ -65,6 +65,7 @@ export const quill_blueprint: (a: number, b: number) => void;
65
65
  export const quill_conform: (a: number, b: number, c: number) => void;
66
66
  export const quill_emptyDocument: (a: number) => number;
67
67
  export const quill_exampleDocument: (a: number, b: number) => void;
68
+ export const quill_fromBundle: (a: number, b: number, c: number) => void;
68
69
  export const quill_fromTree: (a: number, b: number) => void;
69
70
  export const quill_metadata: (a: number, b: number) => void;
70
71
  export const quill_parse: (a: number, b: number, c: number, d: number) => void;
@@ -72,6 +73,7 @@ export const quill_schema: (a: number, b: number) => void;
72
73
  export const quill_seedCard: (a: number, b: number, c: number, d: number, e: number) => void;
73
74
  export const quill_seedDocument: (a: number) => number;
74
75
  export const quill_seedMain: (a: number, b: number) => void;
76
+ export const quill_toBundle: (a: number, b: number) => void;
75
77
  export const quill_toTree: (a: number) => number;
76
78
  export const quill_validate: (a: number, b: number, c: number) => void;
77
79
  export const quill_warnings: (a: number, b: number) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quillmark/wasm",
3
- "version": "0.131.0",
3
+ "version": "0.132.0",
4
4
  "description": "WebAssembly bindings for Quillmark, a schema-driven document framework",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
package/render/wasm.d.ts CHANGED
@@ -80,8 +80,7 @@ export type ContentLineKind =
80
80
  | { kind: "para" }
81
81
  | { kind: "heading"; attrs: { level: number } }
82
82
  | { kind: "code"; attrs?: { lang?: string } }
83
- | { kind: "rule" }
84
- | { kind: "term" };
83
+ | { kind: "rule" };
85
84
 
86
85
  /** An ancestor block a line nests inside, outermost first. Closed like
87
86
  * `ContentLine.kind`.
@@ -110,14 +109,7 @@ export type ContentContainer =
110
109
  attrs: { ordered: boolean; start: number; ordinal: number; checked?: boolean };
111
110
  instance?: number;
112
111
  }
113
- | { container: "quote"; instance?: number }
114
- | { container: "description"; instance?: number }
115
- | { container: "element"; attrs: ElementAttrs; instance?: number };
116
-
117
- /** A carrier element's name and attributes, one bag: `$name` is the part of
118
- * its `qm-<name>` tag after the prefix, and every other key an attribute as
119
- * written. */
120
- export type ElementAttrs = { $name: string; [attr: string]: string };
112
+ | { container: "quote"; instance?: number };
121
113
 
122
114
  /** A mark over char range `[start, end)` into `Content.text`. `type` is a
123
115
  * closed set, so `type === "link"` narrows `attrs` to `{ url: string }` with no
@@ -774,6 +766,11 @@ export interface RenderOptions {
774
766
  * document-space even when `pages` selects a subset.
775
767
  */
776
768
  regions?: boolean;
769
+ /**
770
+ * The PDF document title, over the plate's own and then the quill's
771
+ * `description`. A blank title counts as absent; ignored for PNG and SVG.
772
+ */
773
+ title?: string;
777
774
  }
778
775
 
779
776
  export interface RenderResult {
@@ -838,8 +835,9 @@ export class Document {
838
835
  * The newest storage version this build writes via
839
836
  * [`toStored`](Document::to_stored): a document spelling a font mark, a
840
837
  * `table` element, a merged table cell or a table head 0.130 cannot draw
841
- * carries it, every other the tag before it, which a 0.130 build reads. The tag advances only when the wire format changes, not on
842
- * every release.
838
+ * carries it, every other the tag before it, which a 0.130 build reads.
839
+ * The tag advances only when the wire format changes, not on every
840
+ * release.
843
841
  */
844
842
  static currentStorageVersion(): string;
845
843
  /**
@@ -1268,6 +1266,12 @@ export class Quill {
1268
1266
  * parse or its `$quill` is not this quill's bare name.
1269
1267
  */
1270
1268
  exampleDocument(): Document | undefined;
1269
+ /**
1270
+ * Read a `.quill` bundle, the zip archive holding one quill's file tree.
1271
+ * Pure, as [`fromTree`](Self::from_tree) is. A bundle outside the format
1272
+ * throws one `quill::bundle_*` diagnostic.
1273
+ */
1274
+ static fromBundle(bytes: Uint8Array): Quill;
1271
1275
  /**
1272
1276
  * Build a quill from a file tree. Pure: the declared backend is resolved
1273
1277
  * later, at render time. Accepts a `Map<string, Uint8Array>` or a plain
@@ -1310,6 +1314,11 @@ export class Quill {
1310
1314
  * `$kind: main` card of [`seedDocument`](Self::seed_document) alone.
1311
1315
  */
1312
1316
  seedMain(): Card;
1317
+ /**
1318
+ * This quill's file tree as a `.quill` bundle, the bytes
1319
+ * [`fromBundle`](Self::from_bundle) reads.
1320
+ */
1321
+ toBundle(): Uint8Array;
1313
1322
  /**
1314
1323
  * Flatten this quill back into its canonical file tree, the inverse of
1315
1324
  * [`fromTree`](Self::from_tree). Keys are `"/"`-joined relative paths.
@@ -1544,6 +1553,7 @@ export interface InitOutput {
1544
1553
  readonly quill_conform: (a: number, b: number, c: number) => void;
1545
1554
  readonly quill_emptyDocument: (a: number) => number;
1546
1555
  readonly quill_exampleDocument: (a: number, b: number) => void;
1556
+ readonly quill_fromBundle: (a: number, b: number, c: number) => void;
1547
1557
  readonly quill_fromTree: (a: number, b: number) => void;
1548
1558
  readonly quill_metadata: (a: number, b: number) => void;
1549
1559
  readonly quill_parse: (a: number, b: number, c: number, d: number) => void;
@@ -1551,6 +1561,7 @@ export interface InitOutput {
1551
1561
  readonly quill_seedCard: (a: number, b: number, c: number, d: number, e: number) => void;
1552
1562
  readonly quill_seedDocument: (a: number) => number;
1553
1563
  readonly quill_seedMain: (a: number, b: number) => void;
1564
+ readonly quill_toBundle: (a: number, b: number) => void;
1554
1565
  readonly quill_toTree: (a: number) => number;
1555
1566
  readonly quill_validate: (a: number, b: number, c: number) => void;
1556
1567
  readonly quill_warnings: (a: number, b: number) => void;
package/render/wasm.js CHANGED
@@ -444,8 +444,9 @@ export class Document {
444
444
  * The newest storage version this build writes via
445
445
  * [`toStored`](Document::to_stored): a document spelling a font mark, a
446
446
  * `table` element, a merged table cell or a table head 0.130 cannot draw
447
- * carries it, every other the tag before it, which a 0.130 build reads. The tag advances only when the wire format changes, not on
448
- * every release.
447
+ * carries it, every other the tag before it, which a 0.130 build reads.
448
+ * The tag advances only when the wire format changes, not on every
449
+ * release.
449
450
  * @returns {string}
450
451
  */
451
452
  static currentStorageVersion() {
@@ -1831,6 +1832,30 @@ export class Quill {
1831
1832
  wasm.__wbindgen_add_to_stack_pointer(16);
1832
1833
  }
1833
1834
  }
1835
+ /**
1836
+ * Read a `.quill` bundle, the zip archive holding one quill's file tree.
1837
+ * Pure, as [`fromTree`](Self::from_tree) is. A bundle outside the format
1838
+ * throws one `quill::bundle_*` diagnostic.
1839
+ * @param {Uint8Array} bytes
1840
+ * @returns {Quill}
1841
+ */
1842
+ static fromBundle(bytes) {
1843
+ try {
1844
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
1845
+ const ptr0 = passArray8ToWasm0(bytes, wasm.__wbindgen_export);
1846
+ const len0 = WASM_VECTOR_LEN;
1847
+ wasm.quill_fromBundle(retptr, ptr0, len0);
1848
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
1849
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
1850
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
1851
+ if (r2) {
1852
+ throw takeObject(r1);
1853
+ }
1854
+ return Quill.__wrap(r0);
1855
+ } finally {
1856
+ wasm.__wbindgen_add_to_stack_pointer(16);
1857
+ }
1858
+ }
1834
1859
  /**
1835
1860
  * Build a quill from a file tree. Pure: the declared backend is resolved
1836
1861
  * later, at render time. Accepts a `Map<string, Uint8Array>` or a plain
@@ -1987,6 +2012,29 @@ export class Quill {
1987
2012
  wasm.__wbindgen_add_to_stack_pointer(16);
1988
2013
  }
1989
2014
  }
2015
+ /**
2016
+ * This quill's file tree as a `.quill` bundle, the bytes
2017
+ * [`fromBundle`](Self::from_bundle) reads.
2018
+ * @returns {Uint8Array}
2019
+ */
2020
+ toBundle() {
2021
+ try {
2022
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
2023
+ wasm.quill_toBundle(retptr, this.__wbg_ptr);
2024
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
2025
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
2026
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
2027
+ var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
2028
+ if (r3) {
2029
+ throw takeObject(r2);
2030
+ }
2031
+ var v1 = getArrayU8FromWasm0(r0, r1).slice();
2032
+ wasm.__wbindgen_export4(r0, r1 * 1, 1);
2033
+ return v1;
2034
+ } finally {
2035
+ wasm.__wbindgen_add_to_stack_pointer(16);
2036
+ }
2037
+ }
1990
2038
  /**
1991
2039
  * Flatten this quill back into its canonical file tree, the inverse of
1992
2040
  * [`fromTree`](Self::from_tree). Keys are `"/"`-joined relative paths.
@@ -2899,6 +2947,13 @@ function isLikeNone(x) {
2899
2947
  return x === undefined || x === null;
2900
2948
  }
2901
2949
 
2950
+ function passArray8ToWasm0(arg, malloc) {
2951
+ const ptr = malloc(arg.length * 1, 1) >>> 0;
2952
+ getUint8ArrayMemory0().set(arg, ptr / 1);
2953
+ WASM_VECTOR_LEN = arg.length;
2954
+ return ptr;
2955
+ }
2956
+
2902
2957
  function passStringToWasm0(arg, malloc, realloc) {
2903
2958
  if (realloc === undefined) {
2904
2959
  const buf = cachedTextEncoder.encode(arg);
Binary file
@@ -85,6 +85,7 @@ export const quill_blueprint: (a: number, b: number) => void;
85
85
  export const quill_conform: (a: number, b: number, c: number) => void;
86
86
  export const quill_emptyDocument: (a: number) => number;
87
87
  export const quill_exampleDocument: (a: number, b: number) => void;
88
+ export const quill_fromBundle: (a: number, b: number, c: number) => void;
88
89
  export const quill_fromTree: (a: number, b: number) => void;
89
90
  export const quill_metadata: (a: number, b: number) => void;
90
91
  export const quill_parse: (a: number, b: number, c: number, d: number) => void;
@@ -92,6 +93,7 @@ export const quill_schema: (a: number, b: number) => void;
92
93
  export const quill_seedCard: (a: number, b: number, c: number, d: number, e: number) => void;
93
94
  export const quill_seedDocument: (a: number) => number;
94
95
  export const quill_seedMain: (a: number, b: number) => void;
96
+ export const quill_toBundle: (a: number, b: number) => void;
95
97
  export const quill_toTree: (a: number) => number;
96
98
  export const quill_validate: (a: number, b: number, c: number) => void;
97
99
  export const quill_warnings: (a: number, b: number) => void;
@@ -267,6 +267,12 @@ export interface RenderOptions {
267
267
  * consumers without a live session. Defaults to `false`.
268
268
  */
269
269
  regions?: boolean;
270
+ /**
271
+ * The PDF document title, over the plate's own `set document(title: ..)`
272
+ * and then the quill's `description`. A blank title counts as absent;
273
+ * ignored by PNG and SVG.
274
+ */
275
+ title?: string;
270
276
  }
271
277
 
272
278
  /**
@@ -331,10 +331,9 @@ function requireLocalQuill(quill, method) {
331
331
  // `runtime.test.js` § "container run boundaries" stamps a pair and re-imports
332
332
  // it, where `Content::normalize` re-mints against the Rust predicate. A tag the
333
333
  // table omits welds with nothing, so `tests/known_names_drift.rs` pins that
334
- // every container has an entry. An entry of `'*'` welds on the whole bag: an
335
- // element's attributes are open, its name among them.
334
+ // every container has an entry.
336
335
 
337
- const WELD_KEYS = { list_item: ['ordered'], quote: [], description: [], element: '*' };
336
+ const WELD_KEYS = { list_item: ['ordered'], quote: [] };
338
337
 
339
338
  /**
340
339
  * @param {import('../core/wasm.js').ContentContainer} a
@@ -347,20 +346,7 @@ function weldsWith(a, b) {
347
346
  // `hasOwn`, so a tag colliding with an `Object.prototype` member answers
348
347
  // `false` rather than reaching a function.
349
348
  if (!Object.hasOwn(WELD_KEYS, a.container)) return false;
350
- const keys = WELD_KEYS[a.container];
351
- if (keys === '*') return sameBag(a.attrs, b.attrs);
352
- return keys.every((k) => a.attrs?.[k] === b.attrs?.[k]);
353
- }
354
-
355
- /**
356
- * @param {Record<string, unknown> | undefined} a
357
- * @param {Record<string, unknown> | undefined} b
358
- * @returns {boolean}
359
- */
360
- function sameBag(a, b) {
361
- const [x, y] = [a ?? {}, b ?? {}];
362
- const keys = Object.keys(x);
363
- return keys.length === Object.keys(y).length && keys.every((k) => Object.hasOwn(y, k) && x[k] === y[k]);
349
+ return WELD_KEYS[a.container].every((k) => a.attrs?.[k] === b.attrs?.[k]);
364
350
  }
365
351
 
366
352
  /**
@@ -654,7 +640,7 @@ export class Engine {
654
640
  /**
655
641
  * @param {Quill} quill
656
642
  * @param {Document} doc
657
- * @param {object} [options] render options (`{ format, ppi, pages, regions }`)
643
+ * @param {object} [options] render options (`{ format, ppi, pages, regions, title }`)
658
644
  * @param {string} [today] the render date, `YYYY-MM-DD`
659
645
  * @returns {Promise<import('./runtime.js').RenderResult>}
660
646
  */
package/sbom.cdx.json CHANGED
@@ -2,9 +2,9 @@
2
2
  "bomFormat": "CycloneDX",
3
3
  "specVersion": "1.5",
4
4
  "version": 1,
5
- "serialNumber": "urn:uuid:7ecf8d14-2674-4091-89ee-1a7f554e9e02",
5
+ "serialNumber": "urn:uuid:f564b7e5-243a-4227-a8b7-93134c423efa",
6
6
  "metadata": {
7
- "timestamp": "2026-10-26T20:30:40.502156535Z",
7
+ "timestamp": "2026-10-27T20:03:54.928218334Z",
8
8
  "tools": [
9
9
  {
10
10
  "vendor": "CycloneDX",
@@ -14,9 +14,9 @@
14
14
  ],
15
15
  "component": {
16
16
  "type": "library",
17
- "bom-ref": "path+file:///home/runner/work/quillmark/quillmark/crates/bindings/wasm#quillmark-wasm@0.131.0",
17
+ "bom-ref": "path+file:///home/runner/work/quillmark/quillmark/crates/bindings/wasm#quillmark-wasm@0.132.0",
18
18
  "name": "quillmark-wasm",
19
- "version": "0.131.0",
19
+ "version": "0.132.0",
20
20
  "description": "WebAssembly bindings for Quillmark, a schema-driven document framework",
21
21
  "scope": "required",
22
22
  "licenses": [
@@ -24,7 +24,7 @@
24
24
  "expression": "Apache-2.0"
25
25
  }
26
26
  ],
27
- "purl": "pkg:cargo/quillmark-wasm@0.131.0?download_url=file://.",
27
+ "purl": "pkg:cargo/quillmark-wasm@0.132.0?download_url=file://.",
28
28
  "externalReferences": [
29
29
  {
30
30
  "type": "vcs",
@@ -34,10 +34,10 @@
34
34
  "components": [
35
35
  {
36
36
  "type": "library",
37
- "bom-ref": "path+file:///home/runner/work/quillmark/quillmark/crates/bindings/wasm#quillmark-wasm@0.131.0 bin-target-0",
37
+ "bom-ref": "path+file:///home/runner/work/quillmark/quillmark/crates/bindings/wasm#quillmark-wasm@0.132.0 bin-target-0",
38
38
  "name": "quillmark_wasm",
39
- "version": "0.131.0",
40
- "purl": "pkg:cargo/quillmark-wasm@0.131.0?download_url=file://.#src/lib.rs"
39
+ "version": "0.132.0",
40
+ "purl": "pkg:cargo/quillmark-wasm@0.132.0?download_url=file://.#src/lib.rs"
41
41
  }
42
42
  ]
43
43
  },
@@ -51,9 +51,9 @@
51
51
  "components": [
52
52
  {
53
53
  "type": "library",
54
- "bom-ref": "path+file:///home/runner/work/quillmark/quillmark/crates/backends/acroform#quillmark-acroform@0.131.0",
54
+ "bom-ref": "path+file:///home/runner/work/quillmark/quillmark/crates/backends/acroform#quillmark-acroform@0.132.0",
55
55
  "name": "quillmark-acroform",
56
- "version": "0.131.0",
56
+ "version": "0.132.0",
57
57
  "description": "Typst-free acroform backend for Quillmark: fills existing PDF forms via the quillmark-pdf stamping spine",
58
58
  "scope": "required",
59
59
  "licenses": [
@@ -61,7 +61,7 @@
61
61
  "expression": "Apache-2.0"
62
62
  }
63
63
  ],
64
- "purl": "pkg:cargo/quillmark-acroform@0.131.0?download_url=file://../../backends/acroform",
64
+ "purl": "pkg:cargo/quillmark-acroform@0.132.0?download_url=file://../../backends/acroform",
65
65
  "externalReferences": [
66
66
  {
67
67
  "type": "documentation",
@@ -79,9 +79,9 @@
79
79
  },
80
80
  {
81
81
  "type": "library",
82
- "bom-ref": "path+file:///home/runner/work/quillmark/quillmark/crates/backends/typst#quillmark-typst@0.131.0",
82
+ "bom-ref": "path+file:///home/runner/work/quillmark/quillmark/crates/backends/typst#quillmark-typst@0.132.0",
83
83
  "name": "quillmark-typst",
84
- "version": "0.131.0",
84
+ "version": "0.132.0",
85
85
  "description": "Typst backend for Quillmark",
86
86
  "scope": "required",
87
87
  "licenses": [
@@ -89,7 +89,7 @@
89
89
  "expression": "Apache-2.0"
90
90
  }
91
91
  ],
92
- "purl": "pkg:cargo/quillmark-typst@0.131.0?download_url=file://../../backends/typst",
92
+ "purl": "pkg:cargo/quillmark-typst@0.132.0?download_url=file://../../backends/typst",
93
93
  "externalReferences": [
94
94
  {
95
95
  "type": "documentation",
@@ -107,9 +107,9 @@
107
107
  },
108
108
  {
109
109
  "type": "library",
110
- "bom-ref": "path+file:///home/runner/work/quillmark/quillmark/crates/content#quillmark-content@0.131.0",
110
+ "bom-ref": "path+file:///home/runner/work/quillmark/quillmark/crates/content#quillmark-content@0.132.0",
111
111
  "name": "quillmark-content",
112
- "version": "0.131.0",
112
+ "version": "0.132.0",
113
113
  "description": "Content model (splice-shaped USV text with line attributes, marks, and islands), canonical serialization, edit deltas, and richtext/plaintext codecs for Quillmark",
114
114
  "scope": "required",
115
115
  "licenses": [
@@ -117,7 +117,7 @@
117
117
  "expression": "Apache-2.0"
118
118
  }
119
119
  ],
120
- "purl": "pkg:cargo/quillmark-content@0.131.0?download_url=file://../../content",
120
+ "purl": "pkg:cargo/quillmark-content@0.132.0?download_url=file://../../content",
121
121
  "externalReferences": [
122
122
  {
123
123
  "type": "website",
@@ -131,9 +131,9 @@
131
131
  },
132
132
  {
133
133
  "type": "library",
134
- "bom-ref": "path+file:///home/runner/work/quillmark/quillmark/crates/core#quillmark-core@0.131.0",
134
+ "bom-ref": "path+file:///home/runner/work/quillmark/quillmark/crates/core#quillmark-core@0.132.0",
135
135
  "name": "quillmark-core",
136
- "version": "0.131.0",
136
+ "version": "0.132.0",
137
137
  "description": "Core types and functionality for the Quillmark schema-driven document framework",
138
138
  "scope": "required",
139
139
  "licenses": [
@@ -141,7 +141,7 @@
141
141
  "expression": "Apache-2.0"
142
142
  }
143
143
  ],
144
- "purl": "pkg:cargo/quillmark-core@0.131.0?download_url=file://../../core",
144
+ "purl": "pkg:cargo/quillmark-core@0.132.0?download_url=file://../../core",
145
145
  "externalReferences": [
146
146
  {
147
147
  "type": "documentation",
@@ -159,9 +159,9 @@
159
159
  },
160
160
  {
161
161
  "type": "library",
162
- "bom-ref": "path+file:///home/runner/work/quillmark/quillmark/crates/quillmark#0.131.0",
162
+ "bom-ref": "path+file:///home/runner/work/quillmark/quillmark/crates/quillmark#0.132.0",
163
163
  "name": "quillmark",
164
- "version": "0.131.0",
164
+ "version": "0.132.0",
165
165
  "description": "A schema-driven document framework: turn Markdown into a fully typeset document with a quill",
166
166
  "scope": "required",
167
167
  "licenses": [
@@ -169,7 +169,7 @@
169
169
  "expression": "Apache-2.0"
170
170
  }
171
171
  ],
172
- "purl": "pkg:cargo/quillmark@0.131.0?download_url=file://../../quillmark",
172
+ "purl": "pkg:cargo/quillmark@0.132.0?download_url=file://../../quillmark",
173
173
  "externalReferences": [
174
174
  {
175
175
  "type": "documentation",
@@ -187,9 +187,9 @@
187
187
  },
188
188
  {
189
189
  "type": "library",
190
- "bom-ref": "path+file:///home/runner/work/quillmark/quillmark/crates/quillmark-pdf#0.131.0",
190
+ "bom-ref": "path+file:///home/runner/work/quillmark/quillmark/crates/quillmark-pdf#0.132.0",
191
191
  "name": "quillmark-pdf",
192
- "version": "0.131.0",
192
+ "version": "0.132.0",
193
193
  "description": "Typst-free AcroForm stamping spine for Quillmark: (base_pdf, &[FieldSpec]) -> stamped PDF + regions",
194
194
  "scope": "required",
195
195
  "licenses": [
@@ -197,7 +197,7 @@
197
197
  "expression": "Apache-2.0"
198
198
  }
199
199
  ],
200
- "purl": "pkg:cargo/quillmark-pdf@0.131.0?download_url=file://../../quillmark-pdf",
200
+ "purl": "pkg:cargo/quillmark-pdf@0.132.0?download_url=file://../../quillmark-pdf",
201
201
  "externalReferences": [
202
202
  {
203
203
  "type": "documentation",
@@ -10399,24 +10399,24 @@
10399
10399
  ],
10400
10400
  "dependencies": [
10401
10401
  {
10402
- "ref": "path+file:///home/runner/work/quillmark/quillmark/crates/backends/acroform#quillmark-acroform@0.131.0",
10402
+ "ref": "path+file:///home/runner/work/quillmark/quillmark/crates/backends/acroform#quillmark-acroform@0.132.0",
10403
10403
  "dependsOn": [
10404
10404
  "registry+https://github.com/rust-lang/crates.io-index#hayro@0.8.0",
10405
- "path+file:///home/runner/work/quillmark/quillmark/crates/content#quillmark-content@0.131.0",
10406
- "path+file:///home/runner/work/quillmark/quillmark/crates/core#quillmark-core@0.131.0",
10407
- "path+file:///home/runner/work/quillmark/quillmark/crates/quillmark-pdf#0.131.0",
10405
+ "path+file:///home/runner/work/quillmark/quillmark/crates/content#quillmark-content@0.132.0",
10406
+ "path+file:///home/runner/work/quillmark/quillmark/crates/core#quillmark-core@0.132.0",
10407
+ "path+file:///home/runner/work/quillmark/quillmark/crates/quillmark-pdf#0.132.0",
10408
10408
  "registry+https://github.com/rust-lang/crates.io-index#serde@1.0.229",
10409
10409
  "registry+https://github.com/rust-lang/crates.io-index#serde_json@1.0.154"
10410
10410
  ]
10411
10411
  },
10412
10412
  {
10413
- "ref": "path+file:///home/runner/work/quillmark/quillmark/crates/backends/typst#quillmark-typst@0.131.0",
10413
+ "ref": "path+file:///home/runner/work/quillmark/quillmark/crates/backends/typst#quillmark-typst@0.132.0",
10414
10414
  "dependsOn": [
10415
10415
  "registry+https://github.com/rust-lang/crates.io-index#comemo@0.5.1",
10416
10416
  "registry+https://github.com/rust-lang/crates.io-index#getrandom@0.4.3",
10417
- "path+file:///home/runner/work/quillmark/quillmark/crates/content#quillmark-content@0.131.0",
10418
- "path+file:///home/runner/work/quillmark/quillmark/crates/core#quillmark-core@0.131.0",
10419
- "path+file:///home/runner/work/quillmark/quillmark/crates/quillmark-pdf#0.131.0",
10417
+ "path+file:///home/runner/work/quillmark/quillmark/crates/content#quillmark-content@0.132.0",
10418
+ "path+file:///home/runner/work/quillmark/quillmark/crates/core#quillmark-core@0.132.0",
10419
+ "path+file:///home/runner/work/quillmark/quillmark/crates/quillmark-pdf#0.132.0",
10420
10420
  "registry+https://github.com/rust-lang/crates.io-index#serde_json@1.0.154",
10421
10421
  "registry+https://github.com/rust-lang/crates.io-index#thiserror@2.0.21",
10422
10422
  "registry+https://github.com/rust-lang/crates.io-index#toml@1.1.8+spec-1.1.0",
@@ -10428,14 +10428,14 @@
10428
10428
  ]
10429
10429
  },
10430
10430
  {
10431
- "ref": "path+file:///home/runner/work/quillmark/quillmark/crates/bindings/wasm#quillmark-wasm@0.131.0",
10431
+ "ref": "path+file:///home/runner/work/quillmark/quillmark/crates/bindings/wasm#quillmark-wasm@0.132.0",
10432
10432
  "dependsOn": [
10433
10433
  "registry+https://github.com/rust-lang/crates.io-index#console_error_panic_hook@0.1.7",
10434
10434
  "registry+https://github.com/rust-lang/crates.io-index#getrandom@0.4.3",
10435
10435
  "registry+https://github.com/rust-lang/crates.io-index#js-sys@0.3.106",
10436
- "path+file:///home/runner/work/quillmark/quillmark/crates/quillmark#0.131.0",
10437
- "path+file:///home/runner/work/quillmark/quillmark/crates/content#quillmark-content@0.131.0",
10438
- "path+file:///home/runner/work/quillmark/quillmark/crates/core#quillmark-core@0.131.0",
10436
+ "path+file:///home/runner/work/quillmark/quillmark/crates/quillmark#0.132.0",
10437
+ "path+file:///home/runner/work/quillmark/quillmark/crates/content#quillmark-content@0.132.0",
10438
+ "path+file:///home/runner/work/quillmark/quillmark/crates/core#quillmark-core@0.132.0",
10439
10439
  "registry+https://github.com/rust-lang/crates.io-index#serde@1.0.229",
10440
10440
  "registry+https://github.com/rust-lang/crates.io-index#serde-wasm-bindgen@0.6.5",
10441
10441
  "registry+https://github.com/rust-lang/crates.io-index#serde_bytes@0.11.19",
@@ -10446,7 +10446,7 @@
10446
10446
  ]
10447
10447
  },
10448
10448
  {
10449
- "ref": "path+file:///home/runner/work/quillmark/quillmark/crates/content#quillmark-content@0.131.0",
10449
+ "ref": "path+file:///home/runner/work/quillmark/quillmark/crates/content#quillmark-content@0.132.0",
10450
10450
  "dependsOn": [
10451
10451
  "registry+https://github.com/rust-lang/crates.io-index#pulldown-cmark@0.13.4",
10452
10452
  "registry+https://github.com/rust-lang/crates.io-index#serde@1.0.229",
@@ -10456,11 +10456,13 @@
10456
10456
  ]
10457
10457
  },
10458
10458
  {
10459
- "ref": "path+file:///home/runner/work/quillmark/quillmark/crates/core#quillmark-core@0.131.0",
10459
+ "ref": "path+file:///home/runner/work/quillmark/quillmark/crates/core#quillmark-core@0.132.0",
10460
10460
  "dependsOn": [
10461
+ "registry+https://github.com/rust-lang/crates.io-index#crc32fast@1.5.0",
10461
10462
  "registry+https://github.com/rust-lang/crates.io-index#glob@0.3.4",
10462
10463
  "registry+https://github.com/rust-lang/crates.io-index#indexmap@2.14.2",
10463
- "path+file:///home/runner/work/quillmark/quillmark/crates/content#quillmark-content@0.131.0",
10464
+ "registry+https://github.com/rust-lang/crates.io-index#miniz_oxide@0.8.9",
10465
+ "path+file:///home/runner/work/quillmark/quillmark/crates/content#quillmark-content@0.132.0",
10464
10466
  "registry+https://github.com/rust-lang/crates.io-index#serde@1.0.229",
10465
10467
  "registry+https://github.com/rust-lang/crates.io-index#serde-saphyr@1.3.0",
10466
10468
  "registry+https://github.com/rust-lang/crates.io-index#serde_json@1.0.154",
@@ -10471,18 +10473,18 @@
10471
10473
  ]
10472
10474
  },
10473
10475
  {
10474
- "ref": "path+file:///home/runner/work/quillmark/quillmark/crates/quillmark#0.131.0",
10476
+ "ref": "path+file:///home/runner/work/quillmark/quillmark/crates/quillmark#0.132.0",
10475
10477
  "dependsOn": [
10476
- "path+file:///home/runner/work/quillmark/quillmark/crates/backends/acroform#quillmark-acroform@0.131.0",
10477
- "path+file:///home/runner/work/quillmark/quillmark/crates/core#quillmark-core@0.131.0",
10478
- "path+file:///home/runner/work/quillmark/quillmark/crates/backends/typst#quillmark-typst@0.131.0"
10478
+ "path+file:///home/runner/work/quillmark/quillmark/crates/backends/acroform#quillmark-acroform@0.132.0",
10479
+ "path+file:///home/runner/work/quillmark/quillmark/crates/core#quillmark-core@0.132.0",
10480
+ "path+file:///home/runner/work/quillmark/quillmark/crates/backends/typst#quillmark-typst@0.132.0"
10479
10481
  ]
10480
10482
  },
10481
10483
  {
10482
- "ref": "path+file:///home/runner/work/quillmark/quillmark/crates/quillmark-pdf#0.131.0",
10484
+ "ref": "path+file:///home/runner/work/quillmark/quillmark/crates/quillmark-pdf#0.132.0",
10483
10485
  "dependsOn": [
10484
10486
  "registry+https://github.com/rust-lang/crates.io-index#pdf-writer@0.15.0",
10485
- "path+file:///home/runner/work/quillmark/quillmark/crates/core#quillmark-core@0.131.0",
10487
+ "path+file:///home/runner/work/quillmark/quillmark/crates/core#quillmark-core@0.132.0",
10486
10488
  "registry+https://github.com/rust-lang/crates.io-index#thiserror@2.0.21"
10487
10489
  ]
10488
10490
  },