@quillmark/wasm 0.122.0 → 0.123.1

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,121 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.123.1 - 2026-10-06
4
+
5
+ Upgrade path: [0.123.0 → 0.123.1](docs/migrations/0.123.0-to-0.123.1.md).
6
+
7
+ ### Table cells
8
+
9
+ - feat(content)!: **a table cell carries a line break**, one `\n` in its
10
+ `text`, spelled `<br>` inside the pipe cell (`| line one<br>line two |`, any
11
+ case, with attributes or a closing `/`) and typeset as `#linebreak()`. A
12
+ mark spans the break as it spans a prose hard break, and its edge moves off
13
+ it. `to_markdown` writes a cell's `\n` as `<br>`, and a `\n` in a cell
14
+ written through the JSON lanes is a break, where normalization made it a
15
+ space. `TableCell.text` is unchanged in shape. (#2071)
16
+ - feat(content)!: **an inline `<br>` is a hard break in a paragraph and a
17
+ space in a heading**, where it rendered nothing, so a `richtext(inline)`
18
+ value holding one now has two lines and fails as `validation::not_inline`
19
+ (`edit::field_not_inline` on a strict write; a quill `default:` fails to
20
+ load), and nothing else reports the change. A `<br>` with no text before it
21
+ on its line, or alone on a line, still renders nothing; `\<br>` and a `<br>`
22
+ in backticks stay literal. A `<br>` in an image's alt is a space, where it
23
+ was dropped. (#2071)
24
+
25
+
26
+ ## v0.123.0 - 2026-10-06
27
+
28
+ Upgrade path: [0.122 → 0.123](docs/migrations/0.122-to-0.123.md).
29
+
30
+ ### Boolean coercion
31
+
32
+ - fix(core)!: **a number under a `boolean` field renders by whether it is
33
+ non-zero**, a matrix member's bare tick included, so a float of magnitude at
34
+ most `2.220446049250313e-16`, such as `1e-17`, renders `true` where it
35
+ rendered `false`, and nothing reports the change. `0` and `-0.0` render
36
+ `false`, and every integer reads as before. (#2053)
37
+
38
+ ### Open matrix
39
+
40
+ - fix(core)!: **an open matrix's added item whose `title` is `""` or
41
+ whitespace alone fails as `validation::enum_violation`** at its key, carrying
42
+ the `open` hint, and the render with it, where it printed a held row with
43
+ nothing beside the tick. Such an item in a `default:` fails to load as
44
+ `quill::default_not_in_enum`, and in a card kind's `seed:` as
45
+ `quill::seed_enum_violation`. (#2068)
46
+
47
+ ### Comment placement
48
+
49
+ - fix(core)!: **a comment's text drops the whitespace ending its line**, read
50
+ from markdown, a stored row or a `CardWire` alike, so `to_markdown` writes
51
+ `# note` for `# note ` and its emission reads back to the same document. A
52
+ stored row holding such a comment rewrites once when saved again, and
53
+ nothing reports the change. (#2064)
54
+ - fix(core)!: **a comment keeps the slot the YAML gives it** under a tagged
55
+ empty value (`k: !!str`, `k: !`), inside an alias key's value, and around or
56
+ inside a merge (`<<`), where `to_markdown` dropped or moved it, and nothing
57
+ reports the change. A comment at a lesser column below a tagged or anchored
58
+ empty value belongs to the collection around it. A top-level alias key keeps
59
+ its place in the field order, where its field moved to the block's end, and
60
+ a `parse::unsupported_yaml_tag` inside its value names the key's text. A
61
+ sequence item emptied by its merges emits as `- {}` with its comment after
62
+ it. (#2064)
63
+ - fix(core): **`to_markdown` indexes a field's comments once**, so emitting a
64
+ commented container costs its entries plus its comments, not their product;
65
+ the emitted markdown is byte-for-byte the same. (#2064)
66
+
67
+ ### Base PDF reading
68
+
69
+ - fix(pdf,acroform)!: **a `form.pdf` whose page `/Annots` hold a widget
70
+ annotation fails to open as `pdf::existing_acroform`**, naming the first
71
+ page holding one, whatever its catalog `/AcroForm` holds, where a base whose
72
+ `/AcroForm` was deleted or nulled stamped the fresh widgets beside its own.
73
+ An annotation whose `/Subtype` references `/Widget` is a widget. (#2064)
74
+ - fix(pdf)!: **a trailer, catalog or page-tree node naming a key twice or
75
+ with no value, or holding a token where a key belongs, fails as
76
+ `pdf::parse`** (`pdf::stamp_parse` for the catalog under `stamp`), and an
77
+ `/Info` object as `pdf::write`, where the stamp rewrote one entry of two or
78
+ appended a key that took the next token as its value. A trailer's direct
79
+ `/Info` dictionary of such a shape stamps a fresh `/Info` without its
80
+ entries. (#2064)
81
+ - fix(pdf): **`%`, `{` and `}` end a token and NUL is white-space**, so
82
+ `/AcroForm null%stripped` reads as `null` and stamps. A reference to a
83
+ `null` object or to no object reads as absent, so `/AcroForm 7 0 R` over
84
+ `7 0 obj null endobj` stamps where it failed as `pdf::existing_acroform`.
85
+ (#2064)
86
+
87
+ ### WASM options
88
+
89
+ - fix(wasm)!: **an options object, `Addr` or `CardInput` must be a plain
90
+ object**, one whose prototype is `null` or `Object.prototype` of any realm:
91
+ a class instance, `Object.create(defaults)` and a `Map` throw, where 0.122
92
+ read a class instance's and an inherited key and none of a `Map`'s entries.
93
+ A key the verb does not read throws when it is non-enumerable, such as the
94
+ `__ob__` Vue 2 defines, or holds `undefined`, and so does a `new Engine`
95
+ argument other than an object, `null` or `undefined`. Spread into a literal:
96
+ `{ ...defaults, ...options }`. (#2064)
97
+
98
+ ### Typst plate path
99
+
100
+ - fix(typst,cli): **a `plate_file` led by `./` names the file at the quill
101
+ root**, so `plate_file: ./plate.typ` loads where it failed as
102
+ `typst::plate_missing`, and `quillmark validate` accepts it where it refused
103
+ it as `cli::plate_file_escapes_quill`. A leading `/` or a `..` step still
104
+ misses, with a hint naming the spelling from the quill root. (#2064)
105
+ - fix(typst): the rooted-path hint on a `typst::file_not_found` states what the
106
+ quill root holds, true of a bare path and a rooted one alike. (#2064)
107
+
108
+ ### Parse hints
109
+
110
+ - fix(core): **an unquoted `.inf`, `.nan` or `1e999` hints its quoted
111
+ spelling**, `s: ".inf"`, and the message drops serde-saphyr's option name;
112
+ the parse still fails as `parse::yaml_error_with_location`. (#2064)
113
+ - fix(docs): card-yaml's "Quote these" table lists the number spellings a
114
+ `string` field takes as a number: an `_` between digits, a `0x`, `0o` or
115
+ `0b` prefix, an exponent, and the non-finite spellings that fail the parse.
116
+ (#2064)
117
+
118
+
3
119
  ## v0.122.0 - 2026-10-05
4
120
 
5
121
  Upgrade path: [0.121 → 0.122](docs/migrations/0.121-to-0.122.md).
package/README.md CHANGED
@@ -503,9 +503,12 @@ same shape applies to every throw site:
503
503
  - `engine.render` / `session.render`: backend compilation failures and
504
504
  validation errors.
505
505
  - An object argument carrying a key its verb does not read: the render
506
- options, `new Engine` options, an `Addr`, a `CardInput`. The diagnostic
507
- names the key and carries no `code`: it is a call site to fix, not a
508
- condition to route on.
506
+ options, `new Engine` options, an `Addr`, a `CardInput`. Every own string
507
+ key counts, a non-enumerable one and one holding `undefined` included. The
508
+ argument must be a plain object, its prototype `null` or `Object.prototype`
509
+ of any realm, so a `Map`, a class instance or `Object.create({ … })` throws.
510
+ The diagnostic names the key or what was passed, and carries no `code`: it
511
+ is a call site to fix, not a condition to route on.
509
512
  - `engine.render(quill, parsed)` against a quill whose *name* differs
510
513
  (`quill::name_mismatch`) or whose *version* falls outside the document's
511
514
  selector (`quill::version_mismatch`): a throw, never a warning.
package/core/wasm.d.ts CHANGED
@@ -127,7 +127,7 @@ export type ContentMarkKind =
127
127
 
128
128
  /** A cell in a `TableProps`. `marks` rides the prose `ContentMark` shape, but
129
129
  * each mark's `start`/`end` are USV offsets into this cell's `text`, not into
130
- * `Content.text`. */
130
+ * `Content.text`. A `\n` in `text` is a line break. */
131
131
  export interface TableCell {
132
132
  text: string;
133
133
  marks: ContentMark[];
@@ -446,8 +446,8 @@ export interface QuillFieldSchema {
446
446
  members?: Record<string, string>;
447
447
  /** `true` on a `type: "matrix"` field admitting items a document adds
448
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. */
449
+ * `title` string, not blank, beside the columns, held by being present.
450
+ * Valid only on a matrix. */
451
451
  open?: boolean;
452
452
  ui?: QuillFieldUi;
453
453
  properties?: Record<string, QuillFieldSchema>;
package/core/wasm.js CHANGED
@@ -1918,6 +1918,14 @@ function __wbg_get_imports() {
1918
1918
  const ret = getObject(arg0).getMonth();
1919
1919
  return ret;
1920
1920
  },
1921
+ __wbg_getOwnPropertyNames_f8299644de14134c: function(arg0) {
1922
+ const ret = Object.getOwnPropertyNames(getObject(arg0));
1923
+ return addHeapObject(ret);
1924
+ },
1925
+ __wbg_getPrototypeOf_4e7d85b5bf38d546: function() { return handleError(function (arg0) {
1926
+ const ret = Reflect.getPrototypeOf(getObject(arg0));
1927
+ return addHeapObject(ret);
1928
+ }, arguments); },
1921
1929
  __wbg_get_658f6698067d9515: function() { return handleError(function (arg0, arg1) {
1922
1930
  const ret = Reflect.get(getObject(arg0), getObject(arg1));
1923
1931
  return addHeapObject(ret);
@@ -1976,10 +1984,6 @@ function __wbg_get_imports() {
1976
1984
  const ret = Symbol.iterator;
1977
1985
  return addHeapObject(ret);
1978
1986
  },
1979
- __wbg_keys_440be172f17c0265: function(arg0) {
1980
- const ret = Object.keys(getObject(arg0));
1981
- return addHeapObject(ret);
1982
- },
1983
1987
  __wbg_length_7f3c00c40364105e: function(arg0) {
1984
1988
  const ret = getObject(arg0).length;
1985
1989
  return ret;
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.122.0",
3
+ "version": "0.123.1",
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
@@ -127,7 +127,7 @@ export type ContentMarkKind =
127
127
 
128
128
  /** A cell in a `TableProps`. `marks` rides the prose `ContentMark` shape, but
129
129
  * each mark's `start`/`end` are USV offsets into this cell's `text`, not into
130
- * `Content.text`. */
130
+ * `Content.text`. A `\n` in `text` is a line break. */
131
131
  export interface TableCell {
132
132
  text: string;
133
133
  marks: ContentMark[];
@@ -457,8 +457,8 @@ export interface QuillFieldSchema {
457
457
  members?: Record<string, string>;
458
458
  /** `true` on a `type: "matrix"` field admitting items a document adds
459
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. */
460
+ * `title` string, not blank, beside the columns, held by being present.
461
+ * Valid only on a matrix. */
462
462
  open?: boolean;
463
463
  ui?: QuillFieldUi;
464
464
  properties?: Record<string, QuillFieldSchema>;
package/render/wasm.js CHANGED
@@ -2352,6 +2352,14 @@ function __wbg_get_imports() {
2352
2352
  const ret = getObject(arg0).getMonth();
2353
2353
  return ret;
2354
2354
  },
2355
+ __wbg_getOwnPropertyNames_f8299644de14134c: function(arg0) {
2356
+ const ret = Object.getOwnPropertyNames(getObject(arg0));
2357
+ return addHeapObject(ret);
2358
+ },
2359
+ __wbg_getPrototypeOf_4e7d85b5bf38d546: function() { return handleError(function (arg0) {
2360
+ const ret = Reflect.getPrototypeOf(getObject(arg0));
2361
+ return addHeapObject(ret);
2362
+ }, arguments); },
2355
2363
  __wbg_get_658f6698067d9515: function() { return handleError(function (arg0, arg1) {
2356
2364
  const ret = Reflect.get(getObject(arg0), getObject(arg1));
2357
2365
  return addHeapObject(ret);
@@ -2430,10 +2438,6 @@ function __wbg_get_imports() {
2430
2438
  const ret = Symbol.iterator;
2431
2439
  return addHeapObject(ret);
2432
2440
  },
2433
- __wbg_keys_440be172f17c0265: function(arg0) {
2434
- const ret = Object.keys(getObject(arg0));
2435
- return addHeapObject(ret);
2436
- },
2437
2441
  __wbg_length_7f3c00c40364105e: function(arg0) {
2438
2442
  const ret = getObject(arg0).length;
2439
2443
  return ret;
Binary file
@@ -239,7 +239,8 @@ export interface Artifact {
239
239
  }
240
240
 
241
241
  /**
242
- * Options for one render. Any other key throws, `today` included: the render
242
+ * Options for one render, as a plain object. Any other key throws, `today`
243
+ * included: the render
243
244
  * date is an argument of {@link Engine.render} and {@link Engine.open}, not an
244
245
  * option.
245
246
  */
@@ -378,7 +379,7 @@ export interface BackendDescriptor {
378
379
  formats: OutputFormat[];
379
380
  }
380
381
 
381
- /** Options for `new Engine(...)`. A key other than `backends` throws. */
382
+ /** Options for `new Engine(...)`, as a plain object. A key other than `backends` throws. */
382
383
  export interface EngineOptions {
383
384
  /**
384
385
  * Extra or overriding backend descriptors, merged over the built-ins. Keys are
@@ -162,22 +162,36 @@ function quillmarkError(code, message, hint) {
162
162
  }
163
163
 
164
164
  /**
165
- * Throw on an own key of an options object outside `known`. The JS twin of the
166
- * binding's `reject_unknown_keys`, in the uncoded shape it throws: a misspelled
167
- * optional key would otherwise read as absent.
165
+ * Throw on options that are not a plain object, or on an own key of them
166
+ * outside `known`. The JS twin of the binding's `reject_unknown_keys`, in the
167
+ * uncoded shape it throws: a misspelled optional key would otherwise read as
168
+ * absent, and a read reaches a key up the prototype chain that no own-key walk
169
+ * sees.
168
170
  * @param {unknown} options
169
171
  * @param {string[]} known
170
172
  * @param {string} what the options' name, for the message
171
173
  * @returns {void}
172
174
  */
173
175
  function rejectUnknownKeys(options, known, what) {
174
- for (const key of Object.keys(options ?? {})) {
175
- if (known.includes(key)) continue;
176
- const message = `${what} have unknown key \`${key}\`; ${what} take only \`${known.join('`, `')}\``;
177
- const err = /** @type {any} */ (new Error(message));
178
- err.diagnostics = [{ severity: 'error', message }];
179
- throw err;
176
+ if (options == null) return;
177
+ const proto = Object.getPrototypeOf(options);
178
+ let message;
179
+ if (proto !== null && Object.getPrototypeOf(proto) !== null) {
180
+ const passed =
181
+ options instanceof Map
182
+ ? 'a `Map`'
183
+ : typeof options === 'object'
184
+ ? 'one inheriting from another object'
185
+ : `a ${typeof options}`;
186
+ message = `${what} must be a plain object, not ${passed}`;
187
+ } else {
188
+ const key = Object.getOwnPropertyNames(options).find((k) => !known.includes(k));
189
+ if (key === undefined) return;
190
+ message = `${what} have unknown key \`${key}\`; ${what} take only \`${known.join('`, `')}\``;
180
191
  }
192
+ const err = /** @type {any} */ (new Error(message));
193
+ err.diagnostics = [{ severity: 'error', message }];
194
+ throw err;
181
195
  }
182
196
 
183
197
  // These checks deliver the ERROR, not the rejection, at the seams that cross