@markup-carve/carve-wasm 0.1.3 → 0.1.5

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.d.ts CHANGED
@@ -15,6 +15,22 @@ export interface LintWarning {
15
15
  end: number;
16
16
  }
17
17
 
18
+ export interface ProfileViolation {
19
+ /** Canonical node type that was disallowed. */
20
+ nodeType: string;
21
+ /** Machine reason: element_not_allowed | max_nesting_exceeded | link_not_allowed | image_not_allowed. */
22
+ reason: string;
23
+ /** The profile's own wording for the denial, when it carries one. */
24
+ reasonDescription: string | null;
25
+ /** The engine's prose, the same text a thrown ProfileViolationError lists. */
26
+ message: string;
27
+ }
28
+ export interface ProfileFilterResult {
29
+ /** The filtered tree, as AST JSON. */
30
+ json: string;
31
+ violations: ProfileViolation[];
32
+ }
33
+
18
34
  export interface Stamp {
19
35
  /** The spec version the document was last processed under. */
20
36
  version: string;
@@ -22,6 +38,25 @@ export interface Stamp {
22
38
  generatedBy: string | null;
23
39
  }
24
40
 
41
+ export type MigrationFidelity = "preserved" | "normalized" | "degraded" | "dropped";
42
+ export type MigrationConfidence = "exact" | "inferred" | "fallback";
43
+ export interface MigrationDiagnostic {
44
+ code: string;
45
+ message: string;
46
+ severity: "info" | "warning" | "error";
47
+ fidelity: MigrationFidelity;
48
+ confidence: MigrationConfidence;
49
+ path?: string;
50
+ }
51
+ export interface MigrationReport {
52
+ schemaVersion: 2;
53
+ sourceFormat: string;
54
+ mode?: string;
55
+ adapter?: string;
56
+ diagnostics: MigrationDiagnostic[];
57
+ }
58
+ export interface MigrationResult { value: string; report: MigrationReport; }
59
+
25
60
  export type SourceEditKind = "formatting" | "syntax-migration" | "quick-fix" | "refactor";
26
61
  export interface SourceEdit {
27
62
  /** Inclusive UTF-8 byte offset. */
@@ -41,13 +76,107 @@ export interface SourcePatch {
41
76
  unresolved: SourceSuggestion[];
42
77
  }
43
78
 
79
+ export interface StaticRendererError {
80
+ /** The renderer that failed. Only "math" is bound. */
81
+ renderer: "math";
82
+ /** True for display math. */
83
+ display: boolean;
84
+ /** The source the renderer was handed. */
85
+ source: string;
86
+ message: string;
87
+ }
88
+ export interface StaticRenderResult {
89
+ html: string;
90
+ /** Empty unless a render callback threw or returned a non-string. */
91
+ rendererErrors: StaticRendererError[];
92
+ }
93
+
94
+ export interface AccessibilityDiagnostic {
95
+ /** Stable rule id, e.g. a11y/image-alt. */
96
+ rule: string;
97
+ severity: "warning" | "error";
98
+ message: string;
99
+ /** 0-based BYTE offset into the source, or null when the node carried none. */
100
+ startOffset: number | null;
101
+ endOffset: number | null;
102
+ }
103
+
104
+ export interface SanitizeSvgOptions {
105
+ allowStyle?: boolean;
106
+ allowLinks?: boolean;
107
+ allowAnimation?: boolean;
108
+ allowExternalImages?: boolean;
109
+ }
110
+ export interface SanitizeResult {
111
+ /** Meaningful only when ok is true. */
112
+ svg: string;
113
+ /** False when the input was not a single well-formed <svg> root. */
114
+ ok: boolean;
115
+ }
116
+
117
+ export interface ParsedLocator {
118
+ label: string | null;
119
+ value: string | null;
120
+ suffixText: string | null;
121
+ }
122
+
123
+ export interface ProseMirrorResult {
124
+ /** The ProseMirror document, JSON-encoded. */
125
+ json: string;
126
+ /** Carve node type -> why its content is gone. */
127
+ dropped: Record<string, string>;
128
+ /** Carve node type -> why its node type is gone while its text survives. */
129
+ degraded: Record<string, string>;
130
+ }
131
+
44
132
 
45
133
 
134
+ /**
135
+ * Replay patch JSON onto a PART 12 tree, returning the result as AST JSON.
136
+ */
137
+ export function applyAstPatch(ast: string, patch: string): string;
138
+
139
+ /**
140
+ * Apply a security profile to an AST-JSON document (PART 12), keeping the
141
+ * filtered tree.
142
+ *
143
+ * The `profile` render option filters on the way to HTML and throws the result
144
+ * of the filtering away. This is the same pass with the tree kept, so a host
145
+ * that stores, diffs or re-renders an untrusted document does not have to
146
+ * render HTML and parse it back to get one.
147
+ *
148
+ * `violations` reports what the filter degraded or stripped, which the HTML
149
+ * path cannot: a profile whose action is `error` throws instead, so a
150
+ * resolved call under `to-text` or `strip` is the only place this is visible.
151
+ *
152
+ * Only `profileBaseHost` and `smartTypography` are read from `options`. The
153
+ * rest of the render options describe a renderer, and this is not one.
154
+ *
155
+ * The profile's `max_length` is NOT enforced here: the engine applies it to the
156
+ * source bytes before a parse, and this entry point is handed a tree.
157
+ */
158
+ export function applyProfile(json: string, profile: string, options?: object | null): ProfileFilterResult;
159
+
160
+ /**
161
+ * Replay a reversible patch, forward or inverted.
162
+ *
163
+ * The fingerprint is checked first: a tree that is not the one this patch was
164
+ * made against is refused rather than half-patched. That is a broken caller
165
+ * contract, so it throws.
166
+ */
167
+ export function applyReversibleAstPatch(ast: string, patch: string, inverse?: boolean | null): string;
168
+
46
169
  /**
47
170
  * Apply a trusted patch after its source length and fingerprint still match.
48
171
  */
49
172
  export function applySourcePatch(source: string, patch: any): string;
50
173
 
174
+ /**
175
+ * Render an AST-JSON document (PART 12) to ANSI-styled text. See
176
+ * [`ast_json_to_markdown`], including what a tree without positions costs.
177
+ */
178
+ export function astJsonToAnsi(json: string, options?: object | null): string;
179
+
51
180
  /**
52
181
  * Render an AST-JSON document (PART 12) back to canonical Carve source.
53
182
  *
@@ -69,11 +198,120 @@ export function astJsonToCarve(json: string): string;
69
198
  */
70
199
  export function astJsonToHtml(json: string, options?: object | null): string;
71
200
 
201
+ /**
202
+ * Render an AST-JSON document (PART 12) to Markdown.
203
+ *
204
+ * The direct call for a host that already holds a tree. Without it Markdown was
205
+ * reached through `astJsonToCarve` and then `toMarkdown`: a canonical write, a
206
+ * re-parse and a second render for one answer, and lossier than this, because a
207
+ * tree holding something no Carve source can spell is refused by the write
208
+ * rather than rendered.
209
+ *
210
+ * Takes the same options object as [`to_markdown_with_options`], and reads the
211
+ * same narrow part of it. The profile filter and the `before_render` hooks run,
212
+ * as they do in [`ast_json_to_html`].
213
+ *
214
+ * ORDERING FOLLOWS THE TREE. `toMarkdown` parses with positions on, because
215
+ * section 7 orders collected definitions by source position. A tree arriving as
216
+ * JSON carries whatever positions its producer put there, and one carrying none
217
+ * prints its footnote and link definitions in label order. That is the only
218
+ * order available to a tree without spans, so it is reported here rather than
219
+ * repaired.
220
+ */
221
+ export function astJsonToMarkdown(json: string, options?: object | null): string;
222
+
223
+ /**
224
+ * Render an AST-JSON document (PART 12) to plain text. See
225
+ * [`ast_json_to_markdown`], including what a tree without positions costs.
226
+ */
227
+ export function astJsonToPlainText(json: string, options?: object | null): string;
228
+
229
+ /**
230
+ * The difference between two PART 12 trees, as patch JSON.
231
+ *
232
+ * ```js
233
+ * const patch = createAstPatch(parseJson('# One\n'), parseJson('# Two\n'))
234
+ * applyAstPatch(parseJson('# One\n'), patch) // the '# Two' tree
235
+ * ```
236
+ *
237
+ * Trees and patches both cross as JSON strings, matching `parseJson` and
238
+ * `astJsonToHtml`. A patch carries node payloads, so it carries arbitrary
239
+ * document text - the reason `parseJson` chose a string in the first place.
240
+ *
241
+ * The engine's `ast_patch_to_json` and `ast_patch_from_json` are not bound
242
+ * separately. With the patch crossing as JSON they ARE the encoding of this
243
+ * pair, and a host calling them would be converting JSON it already holds.
244
+ *
245
+ * The operations are position-independent `{ op, path, value }`, so a patch
246
+ * stays meaningful against a tree that moved underneath it - unlike a source
247
+ * patch, which `createSourcePatch` fingerprints against staleness.
248
+ */
249
+ export function createAstPatch(before: string, after: string): string;
250
+
251
+ /**
252
+ * The same difference with its inverse and both fingerprints, as one JSON
253
+ * object: `{ forward, inverse, beforeFingerprint, afterFingerprint }`.
254
+ *
255
+ * This is the shape an undo step wants. THE STACK IS THE HOST'S: every entry
256
+ * point in this package is a pure function that owns nothing, so there is no
257
+ * history kept here to undo against, and a browser host already has one - a
258
+ * key handler, a toolbar, an editor's own history plugin.
259
+ *
260
+ * What the pair adds over two `createAstPatch` calls is the precondition.
261
+ * [`apply_reversible_ast_patch`] refuses a tree whose fingerprint is not the
262
+ * one the patch was made against, so an undo cannot be replayed onto a
263
+ * document that has moved on.
264
+ */
265
+ export function createReversibleAstPatch(before: string, after: string): string;
266
+
72
267
  /**
73
268
  * Build the smallest single UTF-8 byte-range replacement between two sources.
74
269
  */
75
270
  export function createSourcePatch(source: string, replacement: string, kind: string, code: string): SourcePatch;
76
271
 
272
+ /**
273
+ * Expand `{{ path }}` include directives (spec PART 9 §19) through a JS
274
+ * resolver, and hand back the expanded tree as AST JSON.
275
+ *
276
+ * The resolver MUST BE SYNCHRONOUS, which decides who can use this. A browser
277
+ * host that would resolve a path by `fetch` cannot: `fetch` is a Promise and
278
+ * wasm-bindgen cannot await across the call. A host whose files are already in
279
+ * memory - an editor with its open buffers, a bundler, a VFS, a test harness -
280
+ * resolves from that map and is exactly who this is for.
281
+ *
282
+ * ```js
283
+ * const files = new Map([['child.crv', 'Included body.\n']])
284
+ * expandIncludes('Before.\n\n{{ child.crv }}\n', {
285
+ * resolve: (path) => files.get(path) ?? null,
286
+ * })
287
+ * // { json, warnings: [], suppressedWarnings: 0, dependencies: […],
288
+ * // chargedBytes: 15, resolverErrors: [] }
289
+ * ```
290
+ *
291
+ * The resolver returns the child's source as a string, or
292
+ * `{ source, id }` when it can name the file canonically - the id is what the
293
+ * cycle guard compares, so two spellings of one file defeat it without one.
294
+ * `null` refuses the directive as `not-found`; `{ denial }` refuses it in one
295
+ * of the classes §19 names.
296
+ *
297
+ * An `async` resolver returns a Promise, which is not a string and cannot be
298
+ * awaited. That is a per-document failure reported in `resolverErrors`,
299
+ * matching what an `async` `renderers.math` gets from
300
+ * [`to_html_with_renderers`]: the directive stays literal and the caller is
301
+ * told why, rather than the value being swallowed or stringified.
302
+ *
303
+ * The BUDGETS are part of the contract, not a detail: `maxBytes` defaults to
304
+ * `max(1 MB, 8 x source bytes)`, `maxDepth` to 16, `maxResolverCalls` to 1000
305
+ * and `maxWarnings` to 100. They bound what a document of directives can make
306
+ * a host do, and lowering them is how a host serving untrusted documents keeps
307
+ * that bounded.
308
+ *
309
+ * The tree carries no positions. Expansion merges nodes from several files,
310
+ * and a span on a node that came from a child would point into a source the
311
+ * caller did not pass.
312
+ */
313
+ export function expandIncludes(source: string, options: object): IncludeExpansion;
314
+
77
315
  /**
78
316
  * Every extension name this build accepts, in registry order.
79
317
  *
@@ -100,9 +338,46 @@ export function fromBbcode(source: string): string;
100
338
  */
101
339
  export function fromDjot(source: string): string;
102
340
 
103
- export function fromHtml(source: string, mode?: string | null): any;
341
+ export function fromHtml(source: string, mode?: string | null): MigrationResult;
104
342
 
105
- export function fromMarkdown(source: string): any;
343
+ export function fromMarkdown(source: string): MigrationResult;
344
+
345
+ /**
346
+ * Convert a ProseMirror document back to canonical Carve source.
347
+ *
348
+ * The save half of the editor loop. A payload the schema map does not describe
349
+ * is refused rather than written approximately, so an editor extended with a
350
+ * node the bridge has never seen fails where it can be reported.
351
+ */
352
+ export function fromProseMirror(doc: string): string;
353
+
354
+ /**
355
+ * Import HTML straight to the tree, as AST JSON.
356
+ *
357
+ * `htmlToCarve` writes Carve SOURCE, so a host that wanted the tree had to
358
+ * re-parse what it had just written - two parses of one document to get one
359
+ * answer. This is the same importer without that round trip.
360
+ *
361
+ * ```js
362
+ * const { value, report } = htmlToAst('<p>Hello <b>world</b></p>', 'safe')
363
+ * astJsonToHtml(value)
364
+ * ```
365
+ *
366
+ * Returns the SAME `{ value, report }` shape `htmlToCarve` does, with `value`
367
+ * holding the tree instead of the source, in the same fidelity vocabulary. A
368
+ * third result shape for one importer is what that avoids.
369
+ *
370
+ * The REPORT IS NOT ALWAYS IDENTICAL, and the difference is the point. A loss
371
+ * only a WRITER takes is not reported here, because no writer ran (PART 12
372
+ * §16): a `<figure>` wrapping a table, or a table with an explicit
373
+ * head/body/foot grouping, has no Carve spelling, so `htmlToCarve` reports
374
+ * `structure-unspellable` and this does not - the tree keeps the thing that
375
+ * would have been lost.
376
+ *
377
+ * `mode` is spelled as it is there: `safe` (the default), `semantic`, and
378
+ * trusted-only `roundtrip`.
379
+ */
380
+ export function htmlToAst(source: string, mode?: string | null): MigrationResult;
106
381
 
107
382
  /**
108
383
  * Import HTML through the Rust HTML5 DOM and canonical Carve writer.
@@ -110,7 +385,16 @@ export function fromMarkdown(source: string): any;
110
385
  * Returns `{ value, report }`; `report.diagnostics` makes every lossy import
111
386
  * decision observable. `roundtrip` is only safe for Carve-produced HTML.
112
387
  */
113
- export function htmlToCarve(source: string, mode?: string | null): any;
388
+ export function htmlToCarve(source: string, mode?: string | null): MigrationResult;
389
+
390
+ /**
391
+ * The accessibility diagnostics, a second family beside `lintCarve`.
392
+ *
393
+ * Its own rule ids (`a11y/image-alt`, `a11y/heading-jump`) and its own
394
+ * severity, which `lintCarve` has no field for. Offsets are `null` when the
395
+ * node that triggered the rule carried no position.
396
+ */
397
+ export function lintAccessibility(source: string): AccessibilityDiagnostic[];
114
398
 
115
399
  /**
116
400
  * Lint a document for the degradations PART 15 describes.
@@ -125,6 +409,61 @@ export function htmlToCarve(source: string, mode?: string | null): any;
125
409
  */
126
410
  export function lintCarve(source: string): LintWarning[];
127
411
 
412
+ /**
413
+ * Lint a document with the same options object the render entry points take.
414
+ *
415
+ * `lintCarve` is the option-less form. Which degradations exist depends on the
416
+ * extensions in play, so a host that renders with a set has to lint with it.
417
+ */
418
+ export function lintCarveWithOptions(source: string, options?: object | null): LintWarning[];
419
+
420
+ /**
421
+ * Import Markdown straight to the tree, as AST JSON.
422
+ *
423
+ * `fromMarkdown` writes Carve SOURCE, so a host that wanted the tree had to
424
+ * re-parse what it had just written. This is the same importer without that
425
+ * round trip. The losses `fromMarkdown` reports are not repeated here; a host
426
+ * that needs them calls that one.
427
+ */
428
+ export function markdownToAstJson(source: string): string;
429
+
430
+ /**
431
+ * Three-way merge over PART 12 trees, with conflicts as a VALUE.
432
+ *
433
+ * ```js
434
+ * const { ok, ast, conflicts } = JSON.parse(mergeAst(base, ours, theirs))
435
+ * ```
436
+ *
437
+ * Returns `{ ok, ast, conflicts, resolverErrors }` as one JSON string. A
438
+ * conflict does NOT throw: it is a result the caller asked for, and two people
439
+ * editing one document is the ordinary case rather than a broken contract.
440
+ * `ok` is false, `ast` is null, and `conflicts` says where and why.
441
+ *
442
+ * The `{ ok, ast, conflicts }` shape and the three `reason` names -
443
+ * `both-changed`, `delete-edit`, `concurrent-sequence-edit` - are carve-js's,
444
+ * so a host merging with either engine reads one contract. The Rust engine
445
+ * carries no `deleted` flags on a conflict, so that optional carve-js field is
446
+ * absent here rather than guessed at.
447
+ *
448
+ * `options.resolve` is an optional `(conflict) => 'base' | 'ours' | 'theirs' |
449
+ * { value } | null`, answering conflicts while the merge runs; an answer of
450
+ * `null` leaves one unresolved. IT MUST BE SYNCHRONOUS. A resolver that asks a
451
+ * server, or asks the user, returns a Promise the merge cannot await - that is
452
+ * reported in `resolverErrors` and the conflict is left unresolved, the same
453
+ * treatment an `async` `renderers.math` gets.
454
+ */
455
+ export function mergeAst(base: string, ours: string, theirs: string, options?: object | null): string;
456
+
457
+ /**
458
+ * Convert BBCode and retain a conservative v2 fidelity report.
459
+ */
460
+ export function migrateBbcode(source: string): MigrationResult;
461
+
462
+ /**
463
+ * Convert Djot and retain a conservative v2 fidelity report.
464
+ */
465
+ export function migrateDjot(source: string): MigrationResult;
466
+
128
467
  /**
129
468
  * Whether a document was last processed under an older spec version than
130
469
  * `currentVersion`. An unstamped document counts as needing review.
@@ -151,13 +490,115 @@ export function needsReview(source: string, current_version: string): boolean;
151
490
  */
152
491
  export function parseJson(source: string): string;
153
492
 
493
+ /**
494
+ * Serialize the tree with the same options object as
495
+ * [`to_html_with_options`], so a host can export the tree of an untrusted
496
+ * document under the `profile` it renders that document with.
497
+ *
498
+ * `positions` is not read: every serialized tree this binding produces carries
499
+ * them, as in [`parse_json`].
500
+ */
501
+ export function parseJsonWithOptions(source: string, options?: object | null): string;
502
+
503
+ /**
504
+ * Parse the locator portion of a citation into `{ label, value, suffixText }`.
505
+ *
506
+ * A field the source did not carry is `null`. Same shape as carve-js
507
+ * `parseLocator`; pure, and never throws on bad input.
508
+ */
509
+ export function parseLocator(loc: string): ParsedLocator;
510
+
511
+ /**
512
+ * Parse a document and keep what a later [`reparse`] needs.
513
+ *
514
+ * Returns one JSON object: `{ source, document, sourceLayout, changedSource,
515
+ * reusedPreviousTree }`. `document` is the PART 12 tree, `sourceLayout` the
516
+ * byte-exact record [`parse_source_layout_json`] produces, and
517
+ * `changedSource` the byte ranges this parse covered - the whole document, on
518
+ * a first parse.
519
+ *
520
+ * The snapshot crosses as JSON rather than as a handle a host has to `free()`.
521
+ * Every other entry point here is a pure function that owns nothing, and the
522
+ * engine's own snapshot holds only the source, so there is no tree being kept
523
+ * alive in wasm memory for a handle to point at.
524
+ */
525
+ export function parseSnapshot(source: string): string;
526
+
527
+ /**
528
+ * The PART 12 §13 source-layout sidecar for a document.
529
+ *
530
+ * Separate from `parseJson`, which carries semantic positions on the nodes.
531
+ * This is the byte-exact record of the SOURCE: its line endings, whether it
532
+ * had a BOM, and a path-addressed byte span per node - what a host needs to
533
+ * write an edit back into the file it came from.
534
+ */
535
+ export function parseSourceLayoutJson(source: string): string;
536
+
154
537
  /**
155
538
  * Read a document's provenance marker: `{ version, generatedBy }`, or `null`.
156
539
  */
157
540
  export function readStamp(source: string): Stamp | null;
158
541
 
542
+ /**
543
+ * Re-parse `source` with `changes` applied.
544
+ *
545
+ * ```js
546
+ * const first = JSON.parse(parseSnapshot('# One\n'))
547
+ * const next = JSON.parse(reparse(first.source, '[{"range":[2,5],"replacement":"Two"}]'))
548
+ * ```
549
+ *
550
+ * `changes` is a JSON array of `{ range: [start, end], replacement }`.
551
+ *
552
+ * THE OFFSETS ARE UTF-8 BYTE OFFSETS, which is what `parseJson` positions and
553
+ * `createSourcePatch` ranges already mean. A browser editor counts UTF-16 code
554
+ * units, so a host holding a `selectionStart` converts before calling - an
555
+ * offset that lands inside a multi-byte character is refused rather than
556
+ * guessed at.
557
+ *
558
+ * A malformed change THROWS: overlapping ranges, an end past the source, and a
559
+ * range that splits a code point are all a broken caller contract, not a
560
+ * result the caller asked for.
561
+ *
562
+ * `reusedPreviousTree` says whether the parse reused any of the previous one.
563
+ * The pinned engine always reports `false` - it validates and applies the
564
+ * edits and then parses the whole source - so a host should read this as the
565
+ * engine's own answer rather than assume work was saved.
566
+ */
567
+ export function reparse(source: string, changes: string): string;
568
+
569
+ /**
570
+ * Sanitize an SVG document, the helper a host embedding SVG would otherwise
571
+ * reimplement.
572
+ *
573
+ * `{ svg, ok }`. `ok` false means the input was not a single well-formed
574
+ * `<svg>` root, and a caller must then show the SOURCE rather than the input:
575
+ * `svg` carries nothing to display. Every option defaults to `false`, which is
576
+ * the strict setting.
577
+ */
578
+ export function sanitizeSvg(source: string, options?: object | null): SanitizeResult;
579
+
580
+ /**
581
+ * Write a provenance marker onto already-formatted Carve.
582
+ *
583
+ * The other half of `readStamp` and `needsReview`, which could read a marker
584
+ * this package had no way to write. `generatedBy` is the engine identity a
585
+ * host wants recorded, e.g. `"my-app 1.2"`; `form` is `"line"` (default) or
586
+ * `"block"`. Same signature as carve-js `stampCarve`.
587
+ *
588
+ * The input is expected to be formatted already: this appends the marker and
589
+ * replaces one the document carries, it does not canonicalize. `toCarve` is
590
+ * the formatter.
591
+ */
592
+ export function stampCarve(formatted: string, generated_by: string, form?: string | null): string;
593
+
159
594
  export function toAnsi(source: string): string;
160
595
 
596
+ /**
597
+ * Render to ANSI text with an options object. See
598
+ * [`to_markdown_with_options`].
599
+ */
600
+ export function toAnsiWithOptions(source: string, options?: object | null): string;
601
+
161
602
  export function toAnsiWithReport(source: string, strict?: boolean | null, maximum?: number | null): any;
162
603
 
163
604
  export function toCarve(source: string): string;
@@ -167,6 +608,14 @@ export function toCarve(source: string): string;
167
608
  */
168
609
  export function toCarvePatch(source: string): SourcePatch;
169
610
 
611
+ /**
612
+ * Write canonical Carve with an options object.
613
+ *
614
+ * `profile` is the only option this target reads; see
615
+ * [`to_markdown_with_options`] for why.
616
+ */
617
+ export function toCarveWithOptions(source: string, options?: object | null): string;
618
+
170
619
  export function toCarveWithReport(source: string, strict?: boolean | null, maximum?: number | null): any;
171
620
 
172
621
  export function toHtml(source: string): string;
@@ -245,11 +694,22 @@ export function toHtmlFull(source: string, symbols?: object | null): string;
245
694
  * * `lowercaseHeadingIds` (default `false`) and `asciiHeadingIds`
246
695
  * (`"off"` (default), `"fold"`, `"strict"`) - the slug policy, for a host
247
696
  * whose anchors have to match another generator's.
697
+ * * `mentionUrl` and `tagUrl` - URL templates for `@mention` and `#tag`.
698
+ * Without them both render as inert spans, which is why a host that wants
699
+ * them linked has to say where to. The token name is percent-encoded into
700
+ * `{name}` - `{user}` works too for a mention - and the result goes through
701
+ * the same URL sanitizer as an authored link. These are the HOST's
702
+ * configuration, not the document's: the template is trusted, the name
703
+ * substituted into it is not.
248
704
  *
249
705
  * An unrecognized key is ignored: the object is configuration, and a caller
250
706
  * who mistypes one deserves the render to still work. A wrong TYPE on a key
251
707
  * that is recognized does throw, because that changes behavior silently.
252
708
  *
709
+ * `renderers` is the one recognized key this entry point refuses, because a
710
+ * render callback can fail and a bare string has nowhere to report that. Use
711
+ * [`to_html_with_renderers`].
712
+ *
253
713
  * Turning sections off changes nothing else. Ids, collision dedup, `</#id>`
254
714
  * crossrefs, implicit `[Heading][]` references and heading numbering all
255
715
  * resolve against the slug rather than the element carrying it, and the
@@ -258,6 +718,66 @@ export function toHtmlFull(source: string, symbols?: object | null): string;
258
718
  */
259
719
  export function toHtmlWithOptions(source: string, options?: object | null): string;
260
720
 
721
+ /**
722
+ * Render with a build-time math renderer, the option `mode: "static"` needs.
723
+ *
724
+ * Static output carries no client scripts, so a formula it contains has to be
725
+ * rendered while the HTML is being written. `renderers.math` is the callback
726
+ * the engine calls for each ``` ```math ``` fence, with the TeX source and a
727
+ * display flag; KaTeX's `renderToString` has that exact shape.
728
+ *
729
+ * ```js
730
+ * toHtmlWithRenderers(src, {
731
+ * mode: 'static',
732
+ * extensions: ['math-block'],
733
+ * renderers: { math: (tex, display) => katex.renderToString(tex, { displayMode: display }) },
734
+ * })
735
+ * // { html: '…', rendererErrors: [] }
736
+ * ```
737
+ *
738
+ * SECURITY: what the callback returns is inserted as **TRUSTED RAW HTML**, the
739
+ * same trust class as a `symbols` value. The difference worth stating: a symbol
740
+ * value is host configuration keyed by a NAME, while a renderer is host
741
+ * configuration that is HANDED DOCUMENT CONTENT and typically echoes some of it
742
+ * back. A host rendering documents it did not author is accepting whatever its
743
+ * renderer makes of that input, so the escaping is the renderer's job.
744
+ *
745
+ * The engine consults the renderer only under `mode: "static"`; interactive
746
+ * output keeps the `\[…\]` source for the client to typeset, and so does a
747
+ * static render with no renderer supplied.
748
+ *
749
+ * The callback must be SYNCHRONOUS. wasm-bindgen cannot await across it, so an
750
+ * `async` renderer returns a Promise the engine has no way to resolve; that is
751
+ * recorded as a failure rather than stringified into the document.
752
+ *
753
+ * `renderers.diagrams` is the same callback one level down, keyed by the
754
+ * fence's css class: `{ mermaid: (source) => html }`. A host that renders its
755
+ * diagrams beforehand passes the lookup in that one line -
756
+ * `(source) => prerendered.get(source)`. Mermaid itself cannot be passed,
757
+ * because its `render` returns a Promise from v10 on.
758
+ *
759
+ * ```js
760
+ * toHtmlWithRenderers(src, {
761
+ * mode: 'static',
762
+ * extensions: ['fenced-render'],
763
+ * renderers: { diagrams: { mermaid: (source) => prerendered.get(source) } },
764
+ * })
765
+ * ```
766
+ *
767
+ * A diagram key the document never uses renders nothing and reports nothing.
768
+ * So does a fence whose class the caller did not configure: the engine
769
+ * degrades it to an escaped source block, and this binding never sees the
770
+ * node.
771
+ *
772
+ * A callback that throws, or returns anything other than a string, does not
773
+ * abort the render: the node it was called for emits nothing and the failure
774
+ * is reported in `rendererErrors`, with `renderer` naming the css class.
775
+ * This entry point exists because [`to_html_with_options`] returns a bare
776
+ * string with nowhere to put that, and so it rejects `renderers` rather than
777
+ * dropping the failures.
778
+ */
779
+ export function toHtmlWithRenderers(source: string, options?: object | null): StaticRenderResult;
780
+
261
781
  export function toHtmlWithReport(source: string, strict?: boolean | null, maximum?: number | null): any;
262
782
 
263
783
  /**
@@ -280,10 +800,57 @@ export function toHtmlWithSymbols(source: string, symbols?: object | null): stri
280
800
 
281
801
  export function toMarkdown(source: string): string;
282
802
 
803
+ /**
804
+ * Render to Markdown with the same options object as
805
+ * [`to_html_with_options`].
806
+ *
807
+ * `profile` is why this exists. Without it a host can hold an untrusted
808
+ * document to a profile on the way to HTML and not on the way to Markdown,
809
+ * out of one package: the max-length bound, the denied constructs and the
810
+ * link policy were all unreachable here. A document the profile rejects
811
+ * throws a `ProfileViolationError` rather than resolving to an empty string.
812
+ *
813
+ * What these targets read is narrower than HTML's list: `profile` and
814
+ * `smartTypography` change the output and extensions run, while `symbols`
815
+ * (markup-carve/carve-rs#1668), `labels`, `sections`, `sourceLine`, `mode` and
816
+ * the heading-id switches are HTML-side concerns the engine's other renderers
817
+ * do not consult. `renderers` is refused for the reason
818
+ * [`to_html_with_options`] refuses it.
819
+ *
820
+ * [`to_carve_with_options`] is narrower again and reads `profile` alone: the
821
+ * engine's canonical writer is parse-only by contract, so extensions and
822
+ * `smartTypography` are inert there. They are accepted rather than refused
823
+ * because one options object is meant to serve every target.
824
+ */
825
+ export function toMarkdownWithOptions(source: string, options?: object | null): string;
826
+
283
827
  export function toMarkdownWithReport(source: string, strict?: boolean | null, maximum?: number | null): any;
284
828
 
285
829
  export function toPlainText(source: string): string;
286
830
 
831
+ /**
832
+ * Render to plain text with an options object. See
833
+ * [`to_markdown_with_options`].
834
+ */
835
+ export function toPlainTextWithOptions(source: string, options?: object | null): string;
836
+
287
837
  export function toPlainTextWithReport(source: string, strict?: boolean | null, maximum?: number | null): any;
288
838
 
839
+ /**
840
+ * Convert Carve source to the ProseMirror document shape.
841
+ *
842
+ * ProseMirror runs in a browser and nowhere else, so this is the one engine
843
+ * capability whose whole audience sits behind a WASM binding. Without it a host
844
+ * wiring a Carve editor either round-trips to a server or reimplements the node
845
+ * mapping in JS, where it drifts from the engine's.
846
+ *
847
+ * Returns `{ json, dropped, degraded }`. `json` is the ProseMirror document as
848
+ * a JSON string, the same choice `parseJson` makes and for the same reason.
849
+ * The two maps say what the ProseMirror model could not hold: `dropped` where
850
+ * the content is gone, `degraded` where the text survives without its node
851
+ * type. A silent conversion is the degradation shape `lintCarve` exists to
852
+ * avoid.
853
+ */
854
+ export function toProseMirror(source: string): ProseMirrorResult;
855
+
289
856
  export function version(): string;
package/carve_wasm.js CHANGED
@@ -5,5 +5,5 @@ import { __wbg_set_wasm } from "./carve_wasm_bg.js";
5
5
  __wbg_set_wasm(wasm);
6
6
  wasm.__wbindgen_start();
7
7
  export {
8
- applySourcePatch, astJsonToCarve, astJsonToHtml, createSourcePatch, extensions, fromBbcode, fromDjot, fromHtml, fromMarkdown, htmlToCarve, lintCarve, needsReview, parseJson, readStamp, toAnsi, toAnsiWithReport, toCarve, toCarvePatch, toCarveWithReport, toHtml, toHtmlFull, toHtmlWithOptions, toHtmlWithReport, toHtmlWithSymbols, toMarkdown, toMarkdownWithReport, toPlainText, toPlainTextWithReport, version
8
+ applyAstPatch, applyProfile, applyReversibleAstPatch, applySourcePatch, astJsonToAnsi, astJsonToCarve, astJsonToHtml, astJsonToMarkdown, astJsonToPlainText, createAstPatch, createReversibleAstPatch, createSourcePatch, expandIncludes, extensions, fromBbcode, fromDjot, fromHtml, fromMarkdown, fromProseMirror, htmlToAst, htmlToCarve, lintAccessibility, lintCarve, lintCarveWithOptions, markdownToAstJson, mergeAst, migrateBbcode, migrateDjot, needsReview, parseJson, parseJsonWithOptions, parseLocator, parseSnapshot, parseSourceLayoutJson, readStamp, reparse, sanitizeSvg, stampCarve, toAnsi, toAnsiWithOptions, toAnsiWithReport, toCarve, toCarvePatch, toCarveWithOptions, toCarveWithReport, toHtml, toHtmlFull, toHtmlWithOptions, toHtmlWithRenderers, toHtmlWithReport, toHtmlWithSymbols, toMarkdown, toMarkdownWithOptions, toMarkdownWithReport, toPlainText, toPlainTextWithOptions, toPlainTextWithReport, toProseMirror, version
9
9
  } from "./carve_wasm_bg.js";