@quillmark/wasm 0.123.1 → 0.125.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 +208 -0
- package/README.md +15 -10
- package/core/wasm.d.ts +125 -33
- package/core/wasm.js +122 -36
- package/core/wasm_bg.wasm +0 -0
- package/core/wasm_bg.wasm.d.ts +2 -0
- package/package.json +3 -2
- package/render/wasm.d.ts +162 -43
- package/render/wasm.js +154 -45
- package/render/wasm_bg.wasm +0 -0
- package/render/wasm_bg.wasm.d.ts +3 -0
- package/runtime/runtime.d.ts +79 -32
- package/runtime/runtime.js +80 -41
- package/sbom.cdx.json +12266 -0
package/runtime/runtime.js
CHANGED
|
@@ -162,11 +162,11 @@ function quillmarkError(code, message, hint) {
|
|
|
162
162
|
}
|
|
163
163
|
|
|
164
164
|
/**
|
|
165
|
-
* Throw on options that are not a plain object, or on
|
|
166
|
-
* outside `known`. The JS twin of the
|
|
167
|
-
* uncoded shape it throws: a misspelled
|
|
168
|
-
* absent, and a read reaches a key up the
|
|
169
|
-
* sees.
|
|
165
|
+
* Throw on options that are not a plain object, or on a key of them, or of a
|
|
166
|
+
* null-prototype object they inherit from, outside `known`. The JS twin of the
|
|
167
|
+
* binding's `reject_unknown_keys`, in the uncoded shape it throws: a misspelled
|
|
168
|
+
* optional key would otherwise read as absent, and a read reaches a key up the
|
|
169
|
+
* prototype chain that no own-key walk sees.
|
|
170
170
|
* @param {unknown} options
|
|
171
171
|
* @param {string[]} known
|
|
172
172
|
* @param {string} what the options' name, for the message
|
|
@@ -174,8 +174,28 @@ function quillmarkError(code, message, hint) {
|
|
|
174
174
|
*/
|
|
175
175
|
function rejectUnknownKeys(options, known, what) {
|
|
176
176
|
if (options == null) return;
|
|
177
|
-
const proto = Object.getPrototypeOf(options);
|
|
178
177
|
let message;
|
|
178
|
+
try {
|
|
179
|
+
message = unknownKeyRefusal(options, known, what);
|
|
180
|
+
} catch (e) {
|
|
181
|
+
const cause = e instanceof Error ? e.message : String(e);
|
|
182
|
+
message = `${what} must be a plain object, not one whose read throws: ${cause}`;
|
|
183
|
+
}
|
|
184
|
+
if (message === undefined) return;
|
|
185
|
+
const err = /** @type {any} */ (new Error(message));
|
|
186
|
+
err.diagnostics = [{ severity: 'error', message }];
|
|
187
|
+
throw err;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* The refusal `rejectUnknownKeys` throws, if any. A `Proxy` trap may throw.
|
|
192
|
+
* @param {unknown} options
|
|
193
|
+
* @param {string[]} known
|
|
194
|
+
* @param {string} what
|
|
195
|
+
* @returns {string | undefined}
|
|
196
|
+
*/
|
|
197
|
+
function unknownKeyRefusal(options, known, what) {
|
|
198
|
+
const proto = Object.getPrototypeOf(options);
|
|
179
199
|
if (proto !== null && Object.getPrototypeOf(proto) !== null) {
|
|
180
200
|
const passed =
|
|
181
201
|
options instanceof Map
|
|
@@ -183,15 +203,16 @@ function rejectUnknownKeys(options, known, what) {
|
|
|
183
203
|
: typeof options === 'object'
|
|
184
204
|
? 'one inheriting from another object'
|
|
185
205
|
: `a ${typeof options}`;
|
|
186
|
-
|
|
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('`, `')}\``;
|
|
206
|
+
return `${what} must be a plain object, not ${passed}`;
|
|
191
207
|
}
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
|
|
208
|
+
const keys = Object.getOwnPropertyNames(options);
|
|
209
|
+
if (proto !== null) {
|
|
210
|
+
const builtin = Object.getOwnPropertyNames(Object.prototype);
|
|
211
|
+
keys.push(...Object.getOwnPropertyNames(proto).filter((k) => !builtin.includes(k)));
|
|
212
|
+
}
|
|
213
|
+
const key = keys.find((k) => !known.includes(k));
|
|
214
|
+
if (key === undefined) return undefined;
|
|
215
|
+
return `${what} have unknown key \`${key}\`; ${what} take only \`${known.join('`, `')}\``;
|
|
195
216
|
}
|
|
196
217
|
|
|
197
218
|
// These checks deliver the ERROR, not the rejection, at the seams that cross
|
|
@@ -263,9 +284,10 @@ function requireLocalQuill(quill, method) {
|
|
|
263
284
|
// `runtime.test.js` § "container run boundaries" stamps a pair and re-imports
|
|
264
285
|
// it, where `Content::normalize` re-mints against the Rust predicate. A tag the
|
|
265
286
|
// table omits welds with nothing, so `tests/known_names_drift.rs` pins that
|
|
266
|
-
// every container has an entry.
|
|
287
|
+
// every container has an entry. An entry of `'*'` welds on the whole bag: an
|
|
288
|
+
// element's attributes are open, its name among them.
|
|
267
289
|
|
|
268
|
-
const WELD_KEYS = { list_item: ['ordered'], quote: [] };
|
|
290
|
+
const WELD_KEYS = { list_item: ['ordered'], quote: [], element: '*' };
|
|
269
291
|
|
|
270
292
|
/**
|
|
271
293
|
* @param {import('../core/wasm.js').ContentContainer} a
|
|
@@ -278,7 +300,20 @@ function weldsWith(a, b) {
|
|
|
278
300
|
// `hasOwn`, so a tag colliding with an `Object.prototype` member answers
|
|
279
301
|
// `false` rather than reaching a function.
|
|
280
302
|
if (!Object.hasOwn(WELD_KEYS, a.container)) return false;
|
|
281
|
-
|
|
303
|
+
const keys = WELD_KEYS[a.container];
|
|
304
|
+
if (keys === '*') return sameBag(a.attrs, b.attrs);
|
|
305
|
+
return keys.every((k) => a.attrs?.[k] === b.attrs?.[k]);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* @param {Record<string, unknown> | undefined} a
|
|
310
|
+
* @param {Record<string, unknown> | undefined} b
|
|
311
|
+
* @returns {boolean}
|
|
312
|
+
*/
|
|
313
|
+
function sameBag(a, b) {
|
|
314
|
+
const [x, y] = [a ?? {}, b ?? {}];
|
|
315
|
+
const keys = Object.keys(x);
|
|
316
|
+
return keys.length === Object.keys(y).length && keys.every((k) => Object.hasOwn(y, k) && x[k] === y[k]);
|
|
282
317
|
}
|
|
283
318
|
|
|
284
319
|
/**
|
|
@@ -510,16 +545,11 @@ export class Engine {
|
|
|
510
545
|
* memory and run `fn` against the backend engine. Only `render`/`open` call
|
|
511
546
|
* this, so `doc` is always present.
|
|
512
547
|
*
|
|
513
|
-
* OWNERSHIP WINDOW: both caller handles are snapshotted (`doc.toStored()
|
|
514
|
-
*
|
|
515
|
-
* await. The backend load below is a real suspension point, so reading the
|
|
548
|
+
* OWNERSHIP WINDOW: both caller handles are snapshotted (`doc.toStored()`,
|
|
549
|
+
* and `quill.toTree()` on a clone-cache miss) BEFORE the first await. The backend load below is a real suspension point, so reading the
|
|
516
550
|
* handles after it would race a caller that `free()`s them as soon as this
|
|
517
551
|
* call returns its promise ("null pointer passed to rust").
|
|
518
552
|
*
|
|
519
|
-
* `docWarnings` rides the context because the storage DTO does not carry
|
|
520
|
-
* them: `fromStored` clears the load's warnings, so the backend clone knows
|
|
521
|
-
* nothing of them and `render` splices the snapshot back in.
|
|
522
|
-
*
|
|
523
553
|
* Clone lifetimes differ by design: the `doc` clone is TRANSIENT, freed in
|
|
524
554
|
* the `finally` of every call, while the `quill` clone is CACHED and is not
|
|
525
555
|
* freed here — a `Quill` instance's contents never change after
|
|
@@ -528,13 +558,12 @@ export class Engine {
|
|
|
528
558
|
* @param {string} method the caller's name, for the rejection message
|
|
529
559
|
* @param {Quill} quill
|
|
530
560
|
* @param {Document} doc
|
|
531
|
-
* @param {(ctx: { mod: any, engine: any, quill: any, doc: any
|
|
561
|
+
* @param {(ctx: { mod: any, engine: any, quill: any, doc: any }) => any} fn
|
|
532
562
|
*/
|
|
533
563
|
async #withClones(method, quill, doc, fn) {
|
|
534
564
|
const backendId = this.#backendOf(quill, method);
|
|
535
565
|
requireLocalDoc(doc, method);
|
|
536
566
|
const docJson = doc.toStored();
|
|
537
|
-
const docWarnings = doc.warnings;
|
|
538
567
|
const quillTree = this.#quillClones.get(this.#descriptorFor(backendId).load)?.has(quill)
|
|
539
568
|
? null
|
|
540
569
|
: quill.toTree();
|
|
@@ -546,7 +575,7 @@ export class Engine {
|
|
|
546
575
|
let backendDoc = null;
|
|
547
576
|
try {
|
|
548
577
|
backendDoc = mod.Document.fromStored(docJson);
|
|
549
|
-
return fn({ mod, engine, quill: backendQuill, doc: backendDoc
|
|
578
|
+
return fn({ mod, engine, quill: backendQuill, doc: backendDoc });
|
|
550
579
|
} finally {
|
|
551
580
|
backendDoc?.free();
|
|
552
581
|
}
|
|
@@ -564,11 +593,7 @@ export class Engine {
|
|
|
564
593
|
'engine.render(quill, doc)',
|
|
565
594
|
quill,
|
|
566
595
|
doc,
|
|
567
|
-
({ engine, quill: q, doc: d
|
|
568
|
-
const result = engine.render(q, d, options ?? undefined, today);
|
|
569
|
-
result.warnings = docWarnings.concat(result.warnings);
|
|
570
|
-
return result;
|
|
571
|
-
}
|
|
596
|
+
({ engine, quill: q, doc: d }) => engine.render(q, d, options ?? undefined, today)
|
|
572
597
|
);
|
|
573
598
|
}
|
|
574
599
|
|
|
@@ -668,6 +693,13 @@ export class LiveSession {
|
|
|
668
693
|
return this.#inner.fieldBoxes(field);
|
|
669
694
|
}
|
|
670
695
|
|
|
696
|
+
/**
|
|
697
|
+
* @returns {import('./runtime.d.ts').FieldCoverage[]}
|
|
698
|
+
*/
|
|
699
|
+
coverage() {
|
|
700
|
+
return this.#inner.coverage();
|
|
701
|
+
}
|
|
702
|
+
|
|
671
703
|
/**
|
|
672
704
|
* @param {number} page
|
|
673
705
|
* @param {number} x
|
|
@@ -742,21 +774,21 @@ export class DocumentWriter {
|
|
|
742
774
|
/**
|
|
743
775
|
* @param {string} name
|
|
744
776
|
* @param {unknown} value
|
|
745
|
-
* @returns {
|
|
777
|
+
* @returns {import('../core/wasm.js').Diagnostic[]}
|
|
746
778
|
*/
|
|
747
779
|
set(name, value) {
|
|
748
780
|
return this.#doc._commitField(this.#quill, name, value);
|
|
749
781
|
}
|
|
750
782
|
/**
|
|
751
783
|
* @param {Record<string, unknown>} fields
|
|
752
|
-
* @returns {
|
|
784
|
+
* @returns {import('../core/wasm.js').Diagnostic[]}
|
|
753
785
|
*/
|
|
754
786
|
setAll(fields) {
|
|
755
787
|
return this.#doc._commitFields(this.#quill, MAIN_CARD_ADDR, fields);
|
|
756
788
|
}
|
|
757
789
|
/**
|
|
758
790
|
* @param {string} markdown
|
|
759
|
-
* @returns {import('../core/wasm.js').
|
|
791
|
+
* @returns {import('../core/wasm.js').Revised}
|
|
760
792
|
*/
|
|
761
793
|
reviseBody(markdown) {
|
|
762
794
|
return this.#doc.revise({}, markdown);
|
|
@@ -764,17 +796,24 @@ export class DocumentWriter {
|
|
|
764
796
|
/**
|
|
765
797
|
* @param {string} name
|
|
766
798
|
* @param {string} text
|
|
767
|
-
* @returns {import('../core/wasm.js').
|
|
799
|
+
* @returns {import('../core/wasm.js').Revised}
|
|
768
800
|
*/
|
|
769
801
|
reviseField(name, text) {
|
|
770
802
|
return this.#doc._reviseField(this.#quill, name, text);
|
|
771
803
|
}
|
|
804
|
+
/**
|
|
805
|
+
* @param {string} markdown
|
|
806
|
+
* @returns {import('../core/wasm.js').DocumentRevised}
|
|
807
|
+
*/
|
|
808
|
+
reviseDocument(markdown) {
|
|
809
|
+
return this.#doc._reviseDocument(this.#quill, markdown);
|
|
810
|
+
}
|
|
772
811
|
/**
|
|
773
812
|
* @param {string} kind
|
|
774
813
|
* @param {Record<string, unknown>} [fields]
|
|
775
814
|
* @param {string} [body]
|
|
776
815
|
* @param {number} [at] insertion index; appends when omitted
|
|
777
|
-
* @returns {
|
|
816
|
+
* @returns {import('../core/wasm.js').Diagnostic[]}
|
|
778
817
|
*/
|
|
779
818
|
addCard(kind, fields, body, at) {
|
|
780
819
|
return this.#doc._addCard(this.#quill, kind, fields, body, at);
|
|
@@ -823,21 +862,21 @@ export class CardWriter {
|
|
|
823
862
|
/**
|
|
824
863
|
* @param {string} name
|
|
825
864
|
* @param {unknown} value
|
|
826
|
-
* @returns {
|
|
865
|
+
* @returns {import('../core/wasm.js').Diagnostic[]}
|
|
827
866
|
*/
|
|
828
867
|
set(name, value) {
|
|
829
868
|
return this.#doc._commitField(this.#quill, { card: this.#index, field: name }, value);
|
|
830
869
|
}
|
|
831
870
|
/**
|
|
832
871
|
* @param {Record<string, unknown>} fields
|
|
833
|
-
* @returns {
|
|
872
|
+
* @returns {import('../core/wasm.js').Diagnostic[]}
|
|
834
873
|
*/
|
|
835
874
|
setAll(fields) {
|
|
836
875
|
return this.#doc._commitFields(this.#quill, { card: this.#index }, fields);
|
|
837
876
|
}
|
|
838
877
|
/**
|
|
839
878
|
* @param {string} markdown
|
|
840
|
-
* @returns {import('../core/wasm.js').
|
|
879
|
+
* @returns {import('../core/wasm.js').Revised}
|
|
841
880
|
*/
|
|
842
881
|
reviseBody(markdown) {
|
|
843
882
|
return this.#doc.revise({ card: this.#index }, markdown);
|
|
@@ -845,7 +884,7 @@ export class CardWriter {
|
|
|
845
884
|
/**
|
|
846
885
|
* @param {string} name
|
|
847
886
|
* @param {string} text
|
|
848
|
-
* @returns {import('../core/wasm.js').
|
|
887
|
+
* @returns {import('../core/wasm.js').Revised}
|
|
849
888
|
*/
|
|
850
889
|
reviseField(name, text) {
|
|
851
890
|
return this.#doc._reviseField(this.#quill, { card: this.#index, field: name }, text);
|