@markup-carve/carve-wasm 0.1.5 → 0.1.6

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/carve_wasm_bg.js CHANGED
@@ -1,3 +1,72 @@
1
+ /**
2
+ * A parser snapshot retained between editor updates. Call `free()` when done.
3
+ */
4
+ export class ParserSession {
5
+ __destroy_into_raw() {
6
+ const ptr = this.__wbg_ptr;
7
+ this.__wbg_ptr = 0;
8
+ ParserSessionFinalization.unregister(this);
9
+ return ptr;
10
+ }
11
+ free() {
12
+ const ptr = this.__destroy_into_raw();
13
+ wasm.__wbg_parsersession_free(ptr, 0);
14
+ }
15
+ /**
16
+ * Apply byte edits; a rejected edit leaves the session unchanged.
17
+ * @param {string} changes
18
+ * @returns {string}
19
+ */
20
+ edit(changes) {
21
+ let deferred3_0;
22
+ let deferred3_1;
23
+ try {
24
+ const ptr0 = passStringToWasm0(changes, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
25
+ const len0 = WASM_VECTOR_LEN;
26
+ const ret = wasm.parsersession_edit(this.__wbg_ptr, ptr0, len0);
27
+ var ptr2 = ret[0];
28
+ var len2 = ret[1];
29
+ if (ret[3]) {
30
+ ptr2 = 0; len2 = 0;
31
+ throw takeFromExternrefTable0(ret[2]);
32
+ }
33
+ deferred3_0 = ptr2;
34
+ deferred3_1 = len2;
35
+ return getStringFromWasm0(ptr2, len2);
36
+ } finally {
37
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
38
+ }
39
+ }
40
+ /**
41
+ * @param {string} source
42
+ */
43
+ constructor(source) {
44
+ const ptr0 = passStringToWasm0(source, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
45
+ const len0 = WASM_VECTOR_LEN;
46
+ const ret = wasm.parsersession_new(ptr0, len0);
47
+ this.__wbg_ptr = ret >>> 0;
48
+ ParserSessionFinalization.register(this, this.__wbg_ptr, this);
49
+ return this;
50
+ }
51
+ /**
52
+ * The current result, with byte ranges and parser-work counters.
53
+ * @returns {string}
54
+ */
55
+ snapshot() {
56
+ let deferred1_0;
57
+ let deferred1_1;
58
+ try {
59
+ const ret = wasm.parsersession_snapshot(this.__wbg_ptr);
60
+ deferred1_0 = ret[0];
61
+ deferred1_1 = ret[1];
62
+ return getStringFromWasm0(ret[0], ret[1]);
63
+ } finally {
64
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
65
+ }
66
+ }
67
+ }
68
+ if (Symbol.dispose) ParserSession.prototype[Symbol.dispose] = ParserSession.prototype.free;
69
+
1
70
  /**
2
71
  * Replay patch JSON onto a PART 12 tree, returning the result as AST JSON.
3
72
  * @param {string} ast
@@ -99,7 +168,7 @@ export function applyReversibleAstPatch(ast, patch, inverse) {
99
168
  /**
100
169
  * Apply a trusted patch after its source length and fingerprint still match.
101
170
  * @param {string} source
102
- * @param {any} patch
171
+ * @param {SourcePatch} patch
103
172
  * @returns {string}
104
173
  */
105
174
  export function applySourcePatch(source, patch) {
@@ -127,7 +196,7 @@ export function applySourcePatch(source, patch) {
127
196
  * Render an AST-JSON document (PART 12) to ANSI-styled text. See
128
197
  * [`ast_json_to_markdown`], including what a tree without positions costs.
129
198
  * @param {string} json
130
- * @param {object | null} [options]
199
+ * @param {RenderOptions | null} options
131
200
  * @returns {string}
132
201
  */
133
202
  export function astJsonToAnsi(json, options) {
@@ -191,7 +260,7 @@ export function astJsonToCarve(json) {
191
260
  * Takes the same options object as [`to_html_with_options`], so an edited tree
192
261
  * renders under the profile, labels and switches the host already configured.
193
262
  * @param {string} json
194
- * @param {object | null} [options]
263
+ * @param {RenderOptions | null} options
195
264
  * @returns {string}
196
265
  */
197
266
  export function astJsonToHtml(json, options) {
@@ -235,7 +304,7 @@ export function astJsonToHtml(json, options) {
235
304
  * order available to a tree without spans, so it is reported here rather than
236
305
  * repaired.
237
306
  * @param {string} json
238
- * @param {object | null} [options]
307
+ * @param {RenderOptions | null} options
239
308
  * @returns {string}
240
309
  */
241
310
  export function astJsonToMarkdown(json, options) {
@@ -263,7 +332,7 @@ export function astJsonToMarkdown(json, options) {
263
332
  * Render an AST-JSON document (PART 12) to plain text. See
264
333
  * [`ast_json_to_markdown`], including what a tree without positions costs.
265
334
  * @param {string} json
266
- * @param {object | null} [options]
335
+ * @param {RenderOptions | null} options
267
336
  * @returns {string}
268
337
  */
269
338
  export function astJsonToPlainText(json, options) {
@@ -438,7 +507,7 @@ export function createSourcePatch(source, replacement, kind, code) {
438
507
  * and a span on a node that came from a child would point into a source the
439
508
  * caller did not pass.
440
509
  * @param {string} source
441
- * @param {object} options
510
+ * @param {IncludeOptions} options
442
511
  * @returns {IncludeExpansion}
443
512
  */
444
513
  export function expandIncludes(source, options) {
@@ -666,8 +735,9 @@ export function lintAccessibility(source) {
666
735
  *
667
736
  * Returns an array of `{ line, column, rule, message, start, end }`. The rule
668
737
  * ids are shared with carve-js and carve-php, so the same trigger reports the
669
- * same id everywhere. Offsets are BYTE offsets into the source, matching the
670
- * engine.
738
+ * same id everywhere. Offsets count UTF-16 CODE UNITS, so they index the
739
+ * JavaScript string the caller holds; the engine answers in bytes and this
740
+ * wrapper converts (#164).
671
741
  *
672
742
  * Built as JS objects rather than a JSON string: a message carries arbitrary
673
743
  * document text, and hand-rolled JSON escaping is where that goes wrong.
@@ -690,8 +760,8 @@ export function lintCarve(source) {
690
760
  * `lintCarve` is the option-less form. Which degradations exist depends on the
691
761
  * extensions in play, so a host that renders with a set has to lint with it.
692
762
  * @param {string} source
693
- * @param {object | null} [options]
694
- * @returns {LintWarning[]}
763
+ * @param {RenderOptions | null} options
764
+ * @returns {any}
695
765
  */
696
766
  export function lintCarveWithOptions(source, options) {
697
767
  const ptr0 = passStringToWasm0(source, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
@@ -872,7 +942,7 @@ export function parseJson(source) {
872
942
  * `positions` is not read: every serialized tree this binding produces carries
873
943
  * them, as in [`parse_json`].
874
944
  * @param {string} source
875
- * @param {object | null} [options]
945
+ * @param {RenderOptions | null} options
876
946
  * @returns {string}
877
947
  */
878
948
  export function parseJsonWithOptions(source, options) {
@@ -995,8 +1065,8 @@ export function readStamp(source) {
995
1065
  *
996
1066
  * `changes` is a JSON array of `{ range: [start, end], replacement }`.
997
1067
  *
998
- * THE OFFSETS ARE UTF-8 BYTE OFFSETS, which is what `parseJson` positions and
999
- * `createSourcePatch` ranges already mean. A browser editor counts UTF-16 code
1068
+ * THE OFFSETS ARE UTF-8 BYTE OFFSETS, matching `createSourcePatch` ranges.
1069
+ * `parseJson` positions count Unicode codepoints instead. A browser editor counts UTF-16 code
1000
1070
  * units, so a host holding a `selectionStart` converts before calling - an
1001
1071
  * offset that lands inside a multi-byte character is refused rather than
1002
1072
  * guessed at.
@@ -1006,9 +1076,9 @@ export function readStamp(source) {
1006
1076
  * result the caller asked for.
1007
1077
  *
1008
1078
  * `reusedPreviousTree` says whether the parse reused any of the previous one.
1009
- * The pinned engine always reports `false` - it validates and applies the
1010
- * edits and then parses the whole source - so a host should read this as the
1011
- * engine's own answer rather than assume work was saved.
1079
+ * The engine can reuse unchanged plain paragraphs. Other syntax falls back
1080
+ * to a full parse. This function rebuilds the initial snapshot from source;
1081
+ * use a parser session to retain it across edits.
1012
1082
  * @param {string} source
1013
1083
  * @param {string} changes
1014
1084
  * @returns {string}
@@ -1122,7 +1192,7 @@ export function toAnsi(source) {
1122
1192
  * Render to ANSI text with an options object. See
1123
1193
  * [`to_markdown_with_options`].
1124
1194
  * @param {string} source
1125
- * @param {object | null} [options]
1195
+ * @param {RenderOptions | null} options
1126
1196
  * @returns {string}
1127
1197
  */
1128
1198
  export function toAnsiWithOptions(source, options) {
@@ -1148,14 +1218,14 @@ export function toAnsiWithOptions(source, options) {
1148
1218
 
1149
1219
  /**
1150
1220
  * @param {string} source
1151
- * @param {boolean | null} [strict]
1152
- * @param {number | null} [maximum]
1221
+ * @param {boolean | null} strict
1222
+ * @param {number | null} maximum
1153
1223
  * @returns {any}
1154
1224
  */
1155
1225
  export function toAnsiWithReport(source, strict, maximum) {
1156
1226
  const ptr0 = passStringToWasm0(source, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1157
1227
  const len0 = WASM_VECTOR_LEN;
1158
- const ret = wasm.toAnsiWithReport(ptr0, len0, isLikeNone(strict) ? 0xFFFFFF : strict ? 1 : 0, isLikeNone(maximum) ? 0x100000001 : (maximum) >>> 0);
1228
+ const ret = wasm.toAnsiWithReport(ptr0, len0, isLikeNone(strict) ? 0 : addToExternrefTable0(strict), isLikeNone(maximum) ? 0 : addToExternrefTable0(maximum));
1159
1229
  if (ret[2]) {
1160
1230
  throw takeFromExternrefTable0(ret[1]);
1161
1231
  }
@@ -1202,7 +1272,7 @@ export function toCarvePatch(source) {
1202
1272
  * `profile` is the only option this target reads; see
1203
1273
  * [`to_markdown_with_options`] for why.
1204
1274
  * @param {string} source
1205
- * @param {object | null} [options]
1275
+ * @param {RenderOptions | null} options
1206
1276
  * @returns {string}
1207
1277
  */
1208
1278
  export function toCarveWithOptions(source, options) {
@@ -1228,14 +1298,14 @@ export function toCarveWithOptions(source, options) {
1228
1298
 
1229
1299
  /**
1230
1300
  * @param {string} source
1231
- * @param {boolean | null} [strict]
1232
- * @param {number | null} [maximum]
1301
+ * @param {boolean | null} strict
1302
+ * @param {number | null} maximum
1233
1303
  * @returns {any}
1234
1304
  */
1235
1305
  export function toCarveWithReport(source, strict, maximum) {
1236
1306
  const ptr0 = passStringToWasm0(source, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1237
1307
  const len0 = WASM_VECTOR_LEN;
1238
- const ret = wasm.toCarveWithReport(ptr0, len0, isLikeNone(strict) ? 0xFFFFFF : strict ? 1 : 0, isLikeNone(maximum) ? 0x100000001 : (maximum) >>> 0);
1308
+ const ret = wasm.toCarveWithReport(ptr0, len0, isLikeNone(strict) ? 0 : addToExternrefTable0(strict), isLikeNone(maximum) ? 0 : addToExternrefTable0(maximum));
1239
1309
  if (ret[2]) {
1240
1310
  throw takeFromExternrefTable0(ret[1]);
1241
1311
  }
@@ -1379,7 +1449,7 @@ export function toHtmlFull(source, symbols) {
1379
1449
  * endnotes `<section role="doc-endnotes">` is a separate construct that is
1380
1450
  * still emitted.
1381
1451
  * @param {string} source
1382
- * @param {object | null} [options]
1452
+ * @param {RenderOptions | null} options
1383
1453
  * @returns {string}
1384
1454
  */
1385
1455
  export function toHtmlWithOptions(source, options) {
@@ -1461,8 +1531,8 @@ export function toHtmlWithOptions(source, options) {
1461
1531
  * string with nowhere to put that, and so it rejects `renderers` rather than
1462
1532
  * dropping the failures.
1463
1533
  * @param {string} source
1464
- * @param {object | null} [options]
1465
- * @returns {StaticRenderResult}
1534
+ * @param {StaticRenderOptions | null} options
1535
+ * @returns {any}
1466
1536
  */
1467
1537
  export function toHtmlWithRenderers(source, options) {
1468
1538
  const ptr0 = passStringToWasm0(source, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
@@ -1476,14 +1546,14 @@ export function toHtmlWithRenderers(source, options) {
1476
1546
 
1477
1547
  /**
1478
1548
  * @param {string} source
1479
- * @param {boolean | null} [strict]
1480
- * @param {number | null} [maximum]
1549
+ * @param {boolean | null} strict
1550
+ * @param {number | null} maximum
1481
1551
  * @returns {any}
1482
1552
  */
1483
1553
  export function toHtmlWithReport(source, strict, maximum) {
1484
1554
  const ptr0 = passStringToWasm0(source, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1485
1555
  const len0 = WASM_VECTOR_LEN;
1486
- const ret = wasm.toHtmlWithReport(ptr0, len0, isLikeNone(strict) ? 0xFFFFFF : strict ? 1 : 0, isLikeNone(maximum) ? 0x100000001 : (maximum) >>> 0);
1556
+ const ret = wasm.toHtmlWithReport(ptr0, len0, isLikeNone(strict) ? 0 : addToExternrefTable0(strict), isLikeNone(maximum) ? 0 : addToExternrefTable0(maximum));
1487
1557
  if (ret[2]) {
1488
1558
  throw takeFromExternrefTable0(ret[1]);
1489
1559
  }
@@ -1571,7 +1641,7 @@ export function toMarkdown(source) {
1571
1641
  * `smartTypography` are inert there. They are accepted rather than refused
1572
1642
  * because one options object is meant to serve every target.
1573
1643
  * @param {string} source
1574
- * @param {object | null} [options]
1644
+ * @param {RenderOptions | null} options
1575
1645
  * @returns {string}
1576
1646
  */
1577
1647
  export function toMarkdownWithOptions(source, options) {
@@ -1597,14 +1667,14 @@ export function toMarkdownWithOptions(source, options) {
1597
1667
 
1598
1668
  /**
1599
1669
  * @param {string} source
1600
- * @param {boolean | null} [strict]
1601
- * @param {number | null} [maximum]
1670
+ * @param {boolean | null} strict
1671
+ * @param {number | null} maximum
1602
1672
  * @returns {any}
1603
1673
  */
1604
1674
  export function toMarkdownWithReport(source, strict, maximum) {
1605
1675
  const ptr0 = passStringToWasm0(source, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1606
1676
  const len0 = WASM_VECTOR_LEN;
1607
- const ret = wasm.toMarkdownWithReport(ptr0, len0, isLikeNone(strict) ? 0xFFFFFF : strict ? 1 : 0, isLikeNone(maximum) ? 0x100000001 : (maximum) >>> 0);
1677
+ const ret = wasm.toMarkdownWithReport(ptr0, len0, isLikeNone(strict) ? 0 : addToExternrefTable0(strict), isLikeNone(maximum) ? 0 : addToExternrefTable0(maximum));
1608
1678
  if (ret[2]) {
1609
1679
  throw takeFromExternrefTable0(ret[1]);
1610
1680
  }
@@ -1634,7 +1704,7 @@ export function toPlainText(source) {
1634
1704
  * Render to plain text with an options object. See
1635
1705
  * [`to_markdown_with_options`].
1636
1706
  * @param {string} source
1637
- * @param {object | null} [options]
1707
+ * @param {RenderOptions | null} options
1638
1708
  * @returns {string}
1639
1709
  */
1640
1710
  export function toPlainTextWithOptions(source, options) {
@@ -1660,14 +1730,14 @@ export function toPlainTextWithOptions(source, options) {
1660
1730
 
1661
1731
  /**
1662
1732
  * @param {string} source
1663
- * @param {boolean | null} [strict]
1664
- * @param {number | null} [maximum]
1733
+ * @param {boolean | null} strict
1734
+ * @param {number | null} maximum
1665
1735
  * @returns {any}
1666
1736
  */
1667
1737
  export function toPlainTextWithReport(source, strict, maximum) {
1668
1738
  const ptr0 = passStringToWasm0(source, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1669
1739
  const len0 = WASM_VECTOR_LEN;
1670
- const ret = wasm.toPlainTextWithReport(ptr0, len0, isLikeNone(strict) ? 0xFFFFFF : strict ? 1 : 0, isLikeNone(maximum) ? 0x100000001 : (maximum) >>> 0);
1740
+ const ret = wasm.toPlainTextWithReport(ptr0, len0, isLikeNone(strict) ? 0 : addToExternrefTable0(strict), isLikeNone(maximum) ? 0 : addToExternrefTable0(maximum));
1671
1741
  if (ret[2]) {
1672
1742
  throw takeFromExternrefTable0(ret[1]);
1673
1743
  }
@@ -2023,6 +2093,10 @@ export function __wbindgen_init_externref_table() {
2023
2093
  table.set(offset + 2, true);
2024
2094
  table.set(offset + 3, false);
2025
2095
  }
2096
+ const ParserSessionFinalization = (typeof FinalizationRegistry === 'undefined')
2097
+ ? { register: () => {}, unregister: () => {} }
2098
+ : new FinalizationRegistry(ptr => wasm.__wbg_parsersession_free(ptr >>> 0, 1));
2099
+
2026
2100
  function addToExternrefTable0(obj) {
2027
2101
  const idx = wasm.__externref_table_alloc();
2028
2102
  wasm.__wbindgen_externrefs.set(idx, obj);
Binary file
@@ -0,0 +1,89 @@
1
+ # Package compatibility
2
+
3
+ The release tarball contains these entry points:
4
+
5
+ | Import | Initialization | Intended host |
6
+ | --- | --- | --- |
7
+ | `@markup-carve/carve-wasm` | Automatic | Node or a browser bundler with native WASM imports |
8
+ | `@markup-carve/carve-wasm/node` | Automatic | Node ESM and CommonJS |
9
+ | `@markup-carve/carve-wasm/web` | `await init()` | Browser modules and module workers |
10
+ | `@markup-carve/carve-wasm/render` | `await init()` | Browser hosts that only render HTML |
11
+ | `@markup-carve/carve-wasm/offsets` | None | UTF-16, UTF-8 and codepoint boundary conversion |
12
+
13
+ The root export selects the Node entry through the `node` condition. Browser
14
+ bundlers select the bundler entry. A bundler that enables Node conditions for a
15
+ browser build should use `/web` explicitly.
16
+
17
+ ## Browser modules
18
+
19
+ Resolve the package through a bundler or serve the package directory, retaining
20
+ its hierarchy. The full entry points share the package-root WASM file. Initialization is asynchronous; rendering after it is
21
+ synchronous.
22
+
23
+ ```js
24
+ import init, { toHtmlWithOptions } from '@markup-carve/carve-wasm/web'
25
+ await init()
26
+ const html = toHtmlWithOptions(source, { rawHtml: false, profile: 'comment' })
27
+ ```
28
+
29
+ The rendering-only entry uses the same pattern. It has no parser JSON,
30
+ importers, reports, includes or editor APIs. Both entries export a default
31
+ initializer that can take the WASM module or URL when the default relative URL
32
+ is unsuitable. Serve `.wasm` as `application/wasm` for streaming compilation.
33
+
34
+ CI installs the npm tarball and tests Vite 8.3.2 production bundles in
35
+ Chromium, Firefox and WebKit through Playwright 1.61.1. Vite's build target is
36
+ `esnext` because these entries use top-level await. Earlier Vite releases may
37
+ need a WASM plugin for the root bundler entry; they are outside this tested
38
+ matrix. This matrix does not establish a minimum browser version.
39
+
40
+ ## Node and TypeScript
41
+
42
+ Node 22 is tested with both `import` and `require`. The Node build loads its
43
+ package-root WASM file synchronously, so copying only its JavaScript file fails.
44
+
45
+ TypeScript 5.9.3 is tested with `strict: true`, `skipLibCheck: false` and
46
+ `NodeNext` module resolution against the installed tarball. wasm-bindgen emits
47
+ `Symbol.dispose` declarations for `ParserSession`; include `ESNext.Disposable`
48
+ in `compilerOptions.lib` when the rest of the project targets ES2022. Explicit
49
+ `session.free()` remains supported.
50
+
51
+ ## Editors and workers
52
+
53
+ Edit ranges use UTF-8 byte offsets. Browser selection ranges use UTF-16 code
54
+ units; AST positions use Unicode codepoints. Convert against the source the
55
+ edit applies to, before sending it to a worker. See `/offsets` and the
56
+ [incremental API reference](reference.md#re-parsing-while-someone-types).
57
+
58
+ [carve-worker.mjs](../examples/carve-worker.mjs) initializes `/web` once and
59
+ retains one `ParserSession`. Messages carry `id` and `action`: `open` takes
60
+ `source`, `edit` takes `changes`, `render` takes `source`, and `close` frees the
61
+ session. Replies contain `value` or `error`. The consumer suite tests this
62
+ protocol in each browser. Create it with a bundler-resolved module worker:
63
+
64
+ ```js
65
+ const worker = new Worker(new URL('./carve-worker.mjs', import.meta.url), {
66
+ type: 'module',
67
+ })
68
+ ```
69
+
70
+ Copy the example into the application beside this call. Free retained sessions
71
+ when documents close, and terminate workers when the host closes them.
72
+
73
+ ## Fidelity and resource limits
74
+
75
+ HTML import projects through a DOM and cannot retain all Carve source
76
+ constructs. Its `roundtrip` mode is for trusted Carve-produced HTML. The corpus
77
+ ledger records output differences, while the stability gate requires a second
78
+ import to settle. Inspect conversion reports before accepting imported source.
79
+ Markdown, Djot and BBCode migration reports still mark fidelity as unverified.
80
+
81
+ ProseMirror reports dropped nodes, degraded nodes and canonical source changes.
82
+ A nonempty report requires a host decision before replacing the original
83
+ source. Preserve the original source when an editor cannot represent it.
84
+
85
+ The engine limits nesting to 200 levels. CI checks that depth in browsers and
86
+ measures the Node stack needed by serialization separately. Larger documents
87
+ still consume synchronous CPU time; move work into a worker when it would block
88
+ an editor. `scripts/benchmark.mjs` measures the shipped package, but its elapsed
89
+ times are machine-dependent and are not latency guarantees.