@quillmark/wasm 0.94.0 → 0.96.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.
@@ -58,11 +58,27 @@
58
58
  // re-export keeps the identity: the exported `Quill` IS the core class.
59
59
  import { Quill, Document, init } from '../core/wasm.js';
60
60
  export { Quill, Document, init };
61
- // The document-free corpus codec — re-exported verbatim from the core build so
61
+ // The document-free content codec — re-exported verbatim from the core build so
62
62
  // the runtime subpath exposes `exportMarkdown(body)` (the on-demand markdown
63
- // projection that replaces the eager `bodyMarkdown`), `importMarkdown`, and the
64
- // position-mapping pair (`rebase`, `mapPos`).
63
+ // projection), `importMarkdown`, and the position-mapping pair (`rebase`,
64
+ // `mapPos`).
65
65
  export { importMarkdown, exportMarkdown, rebase, mapPos } from '../core/wasm.js';
66
+ // The document-model path parser/serializer: `parseDocPath(str) => DocPathSeg[]`
67
+ // and its inverse `formatDocPath`, so a consumer routes on `Diagnostic.path`
68
+ // segments instead of reverse-engineering the grammar.
69
+ export { parseDocPath, formatDocPath } from '../core/wasm.js';
70
+
71
+ // ── The main-card address ───────────────────────────────────────────────────
72
+ /**
73
+ * The main card's address — the default target of the card-scoped verbs
74
+ * (`storeFields` / `storeExt` / `commitFields` / …). A named, `CardAddr`-typed
75
+ * alias for the empty address `{}`, so a main-card write names its target:
76
+ * `doc.storeFields(MAIN_CARD_ADDR, fields)`. It IS `{}` (frozen), a pure alias —
77
+ * `{}` and `undefined` stay equally valid. Card axis only: a card selector,
78
+ * never a field address.
79
+ * @type {import('../core/wasm.js').CardAddr}
80
+ */
81
+ export const MAIN_CARD_ADDR = Object.freeze({});
66
82
 
67
83
  /**
68
84
  * Narrow an unknown caught value to a `QuillmarkError` — the error every
@@ -479,7 +495,7 @@ export class LiveSession {
479
495
  * @param {number} page
480
496
  * @param {number} x
481
497
  * @param {number} y
482
- * @returns {import('./runtime.d.ts').CorpusHit | undefined}
498
+ * @returns {import('./runtime.d.ts').ContentHit | undefined}
483
499
  */
484
500
  positionAt(page, x, y) {
485
501
  return this.#inner.positionAt(page, x, y);
@@ -531,7 +547,7 @@ export class LiveSession {
531
547
  // typed-committed (coerced to canonical form, mismatch throws now), and a name
532
548
  // the schema does not declare throws `UnknownField` rather than falling to the
533
549
  // opaque store — on the typed path an undeclared name is a typo. Opaque storage
534
- // stays available through the raw `Document.setField` / `setCardField` verbs.
550
+ // stays available through the raw addressed `Document.storeField` verb.
535
551
 
536
552
  /**
537
553
  * A {@link Document} bound to its {@link Quill} for typed writes — the JS twin
@@ -556,54 +572,68 @@ export class DocumentWriter {
556
572
  }
557
573
  /**
558
574
  * Typed-commit one main-card field (strict coerce, mismatch throws now).
559
- * Throws `UnknownField` for a name the schema does not declare. See
560
- * `Document.commitField`.
575
+ * Throws `UnknownField` for a name the schema does not declare.
561
576
  * @param {string} name
562
577
  * @param {unknown} value
563
578
  * @returns {void}
564
579
  */
565
580
  set(name, value) {
566
- return this.#doc.commitField(this.#quill, name, value);
581
+ return this.#doc._commitField(this.#quill, name, value);
567
582
  }
568
583
  /**
569
584
  * Typed-commit several main-card fields atomically — nothing is applied on
570
585
  * error (throws a per-field diagnostic bundle, including an `UnknownField`
571
- * for each undeclared name). See `Document.commitFields`.
586
+ * for each undeclared name).
572
587
  * @param {Record<string, unknown>} fields
573
588
  * @returns {void}
574
589
  */
575
590
  setAll(fields) {
576
- return this.#doc.commitFields(this.#quill, fields);
591
+ return this.#doc._commitFields(this.#quill, MAIN_CARD_ADDR, fields);
577
592
  }
578
593
  /**
579
594
  * Set the main body from markdown (edit semantics: surviving anchors rebase),
580
595
  * discarding the text delta — the receipt-free body write. Call
581
- * `doc.revise({}, md)` for the {@link Delta} receipt (the corpus-lane
582
- * spelling). Markdown in, no corpus or receipt in sight.
596
+ * `doc.revise({}, md)` for the {@link Delta} receipt.
583
597
  * @param {string} markdown
584
598
  * @returns {void}
585
599
  */
586
600
  setBody(markdown) {
587
601
  this.#doc.revise({}, markdown);
588
602
  }
603
+ /**
604
+ * Revise the richtext main-card field `name` from markdown — typed *and*
605
+ * anchor-preserving. Surviving anchors rebase, then the diffed result is
606
+ * schema-conformed (`richtext(inline)` rejects a multi-block result). Throws
607
+ * `UnknownField` for a name the schema does not declare. Returns the text
608
+ * {@link Delta}.
609
+ * @param {string} name
610
+ * @param {string} markdown
611
+ * @returns {import('../core/wasm.js').Delta}
612
+ */
613
+ reviseField(name, markdown) {
614
+ return this.#doc._reviseField(this.#quill, name, markdown);
615
+ }
589
616
  /**
590
617
  * Build a composable card of `kind`, typed-commit `fields` onto it, set its
591
- * body from optional markdown, and append it — the fused `makeCard` + typed
592
- * commit + `pushCard`. Transactional: the card is committed in full before it
593
- * joins the document, so a rejected field (throws a per-field diagnostic
594
- * bundle, `UnknownField` per undeclared name) or an invalid kind/body leaves
595
- * the document untouched. See `Document.addCard`.
618
+ * body from optional markdown, and place it — the fused `makeCard` + typed
619
+ * commit + insertion. `at` picks the position: omitted appends, a number
620
+ * inserts at that index (`0..=cardCount`), so a positioned typed insert is one
621
+ * atomic call rather than `addCard` + `moveCard`. Transactional: the card is
622
+ * committed in full before it joins the document, so a rejected field (throws
623
+ * a per-field diagnostic bundle, `UnknownField` per undeclared name) or an
624
+ * invalid kind/body/position leaves the document untouched.
596
625
  * @param {string} kind
597
626
  * @param {Record<string, unknown>} [fields]
598
627
  * @param {string} [body]
628
+ * @param {number} [at] insertion index; appends when omitted
599
629
  * @returns {void}
600
630
  */
601
- addCard(kind, fields, body) {
602
- return this.#doc.addCard(this.#quill, kind, fields, body);
631
+ addCard(kind, fields, body, at) {
632
+ return this.#doc._addCard(this.#quill, kind, fields, body, at);
603
633
  }
604
634
  /**
605
635
  * Remove the composable card at `index`, returning it (or `undefined` if the
606
- * index is out of range) — the tier-1 spelling of `Document.removeCard`.
636
+ * index is out of range) — the writer spelling of `Document.removeCard`.
607
637
  * @param {number} index
608
638
  * @returns {import('../core/wasm.js').Card | undefined}
609
639
  */
@@ -651,25 +681,34 @@ export class CardWriter {
651
681
  return this.#index;
652
682
  }
653
683
  /**
654
- * Typed-commit one field on this card, per `Document.commitCardField`.
655
- * Throws `UnknownField` for an undeclared name and `IndexOutOfRange` if the
656
- * bound index is out of range.
684
+ * The bound card's `$kind` (empty string when it carries none), read through
685
+ * the document mirrors core `CardWriter::kind()`. Ephemeral like the cursor
686
+ * itself: throws `IndexOutOfRange` if the bound index is out of range.
687
+ * @returns {string}
688
+ */
689
+ get kind() {
690
+ return this.#doc.card(this.#index).kind;
691
+ }
692
+ /**
693
+ * Typed-commit one field on this card, addressed at `{ card, field }`. Throws
694
+ * `UnknownField` for an undeclared name and `IndexOutOfRange` if the bound
695
+ * index is out of range.
657
696
  * @param {string} name
658
697
  * @param {unknown} value
659
698
  * @returns {void}
660
699
  */
661
700
  set(name, value) {
662
- return this.#doc.commitCardField(this.#quill, this.#index, name, value);
701
+ return this.#doc._commitField(this.#quill, { card: this.#index, field: name }, value);
663
702
  }
664
703
  /**
665
- * Typed-commit several fields on this card atomically, per
666
- * `Document.commitCardFields`. Throws a per-field diagnostic bundle on error
667
- * and `IndexOutOfRange` if the bound index is out of range.
704
+ * Typed-commit several fields on this card atomically, addressed at
705
+ * `{ card }`. Throws a per-field diagnostic bundle on error and
706
+ * `IndexOutOfRange` if the bound index is out of range.
668
707
  * @param {Record<string, unknown>} fields
669
708
  * @returns {void}
670
709
  */
671
710
  setAll(fields) {
672
- return this.#doc.commitCardFields(this.#quill, this.#index, fields);
711
+ return this.#doc._commitFields(this.#quill, { card: this.#index }, fields);
673
712
  }
674
713
  /**
675
714
  * Set this card's body from markdown (edit semantics), discarding the delta —
@@ -680,10 +719,22 @@ export class CardWriter {
680
719
  setBody(markdown) {
681
720
  this.#doc.revise({ card: this.#index }, markdown);
682
721
  }
722
+ /**
723
+ * Revise the richtext field `name` on this card from markdown — typed *and*
724
+ * anchor-preserving; the card twin of {@link DocumentWriter.reviseField}.
725
+ * Throws `UnknownField` for an undeclared name and `IndexOutOfRange` if the
726
+ * bound index is out of range. Returns the text {@link Delta}.
727
+ * @param {string} name
728
+ * @param {string} markdown
729
+ * @returns {import('../core/wasm.js').Delta}
730
+ */
731
+ reviseField(name, markdown) {
732
+ return this.#doc._reviseField(this.#quill, { card: this.#index, field: name }, markdown);
733
+ }
683
734
  }
684
735
 
685
736
  // ── `quill.writer(doc)` — the typed front door ──────────────────────────────
686
- // The tier-1 default: bind the quill's schema to a document and issue bare
737
+ // The schema-bound writer: bind the quill's schema to a document and issue bare
687
738
  // typed writes. Mirrors core's `quill.writer(&mut doc)` — the schema grants the
688
739
  // typing, so the quill (not the document) is the factory. Patched onto the
689
740
  // re-exported `Quill` prototype rather than wrapped: `Quill === CoreQuill`
@@ -701,3 +752,137 @@ export class CardWriter {
701
752
  Quill.prototype.writer = function writer(doc) {
702
753
  return new DocumentWriter(this, doc);
703
754
  };
755
+
756
+ // ── Typed-reader sugar: the schema-plane read surface ──────────────────────────
757
+ // The read twin of the writer above. The transport `Document.get` is schema-free
758
+ // — a `Document` cannot say which fields are richtext, so an unknown field name
759
+ // reads back `undefined` rather than as the typo it is. Binding the quill's
760
+ // schema (`_readerGet` takes the handle, like the `commit*` verbs) lets one `get`
761
+ // interpret by declared type: a richtext field to markdown, a plaintext field to
762
+ // its literal text, every other type verbatim, and an unknown name throws
763
+ // `UnknownField`. A field's markdown lives here, not on the body-only
764
+ // `getMarkdown`. Like the writer classes these hold the caller's handles by
765
+ // reference, own no WASM object, and have nothing to `free()`.
766
+
767
+ /**
768
+ * A {@link Document} bound to its {@link Quill} for typed reads — the JS twin of
769
+ * Rust's `quill.reader(&doc)` and the read counterpart of {@link DocumentWriter}.
770
+ * Reads target the main card; use {@link card} for a composable card. Holds both
771
+ * handles by reference and owns neither, so there is nothing to `free()`.
772
+ */
773
+ export class DocumentReader {
774
+ #quill;
775
+ #doc;
776
+ /**
777
+ * @param {Quill} quill the schema source for interpreted reads
778
+ * @param {Document} doc the document to read, held by reference (not owned)
779
+ */
780
+ constructor(quill, doc) {
781
+ this.#quill = quill;
782
+ this.#doc = doc;
783
+ }
784
+ /** The bound document — the same instance passed in. */
785
+ get document() {
786
+ return this.#doc;
787
+ }
788
+ /**
789
+ * Read the value at `addr`, interpreted by its declared type: a richtext field
790
+ * to markdown, every other type verbatim. A bare string is `Addr` shorthand
791
+ * for `{ field }`; an absent `addr.field` reads the body markdown. `undefined`
792
+ * for an absent field; throws `UnknownField` for a name the schema does not
793
+ * declare, `FieldRichtextDecode` for a richtext field holding an undecodable
794
+ * value, and `IndexOutOfRange` for a bad `addr.card`.
795
+ * @param {import('../core/wasm.js').Addr | string} addr
796
+ * @returns {unknown}
797
+ */
798
+ get(addr) {
799
+ return this.#doc._readerGet(this.#quill, addr);
800
+ }
801
+ /**
802
+ * The main body's markdown — the quill-free body read (a body's type is a
803
+ * format fact, not a schema fact). Equivalent to `get({})`.
804
+ * @returns {string}
805
+ */
806
+ getBody() {
807
+ return this.#doc._readerGet(this.#quill, {});
808
+ }
809
+ /**
810
+ * A {@link CardReader} bound to the composable card at `index`. Index validity
811
+ * is checked lazily by the underlying read (it throws `IndexOutOfRange` at read
812
+ * time), so constructing one never throws. Ephemeral like the writer cursor —
813
+ * it holds `index`, not the card, so a `removeCard`/`addCard` between binding
814
+ * and reading silently retargets it.
815
+ * @param {number} index
816
+ * @returns {CardReader}
817
+ */
818
+ card(index) {
819
+ return new CardReader(this.#quill, this.#doc, index);
820
+ }
821
+ }
822
+
823
+ /**
824
+ * A single composable card bound to its {@link Quill} for typed reads, from
825
+ * {@link DocumentReader.card}. Same `get` / `getBody` verbs as
826
+ * {@link DocumentReader}, reading the card at its bound index.
827
+ */
828
+ export class CardReader {
829
+ #quill;
830
+ #doc;
831
+ #index;
832
+ /**
833
+ * @param {Quill} quill the schema source
834
+ * @param {Document} doc the document to read, held by reference (not owned)
835
+ * @param {number} index the composable card's index
836
+ */
837
+ constructor(quill, doc, index) {
838
+ this.#quill = quill;
839
+ this.#doc = doc;
840
+ this.#index = index;
841
+ }
842
+ /** The bound card index. */
843
+ get index() {
844
+ return this.#index;
845
+ }
846
+ /**
847
+ * The bound card's `$kind` (empty string when it carries none), read through
848
+ * the document. Throws `IndexOutOfRange` if the bound index is out of range.
849
+ * @returns {string}
850
+ */
851
+ get kind() {
852
+ return this.#doc.card(this.#index).kind;
853
+ }
854
+ /**
855
+ * Read the field `name` on this card, interpreted by its declared type,
856
+ * addressed at `{ card, field }`. `undefined` when absent; throws
857
+ * `UnknownField` for an undeclared name and `IndexOutOfRange` for a bad index.
858
+ * @param {string} name
859
+ * @returns {unknown}
860
+ */
861
+ get(name) {
862
+ return this.#doc._readerGet(this.#quill, { card: this.#index, field: name });
863
+ }
864
+ /**
865
+ * This card's body markdown — the card twin of {@link DocumentReader.getBody}.
866
+ * @returns {string}
867
+ */
868
+ getBody() {
869
+ return this.#doc._readerGet(this.#quill, { card: this.#index });
870
+ }
871
+ }
872
+
873
+ // ── `quill.reader(doc)` — the schema-plane read front door ─────────────────────
874
+ // The read twin of `quill.writer(doc)`, patched onto the same re-exported `Quill`
875
+ // prototype (the `Quill === CoreQuill` identity invariant holds — this only adds
876
+ // a method constructing the pure-JS reader, which owns no WASM handle).
877
+ /**
878
+ * A {@link DocumentReader} binding this quill's schema to `doc` for interpreted
879
+ * reads — the read front door, mirroring core's `quill.reader(&doc)`. The returned
880
+ * reader holds both handles by reference and owns neither, so there is nothing to
881
+ * `free()`. Ephemeral by convention: bind, read, discard.
882
+ * @this {Quill}
883
+ * @param {Document} doc the document to read, held by reference (not owned)
884
+ * @returns {DocumentReader}
885
+ */
886
+ Quill.prototype.reader = function reader(doc) {
887
+ return new DocumentReader(this, doc);
888
+ };