@ai-react-markdown/engine 2.4.3 → 2.5.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/README.md +95 -0
- package/dist/index.cjs +440 -83
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +109 -58
- package/dist/index.d.ts +109 -58
- package/dist/index.dev.cjs +440 -83
- package/dist/index.dev.cjs.map +1 -1
- package/dist/index.dev.js +440 -81
- package/dist/index.dev.js.map +1 -1
- package/dist/index.js +440 -81
- package/dist/index.js.map +1 -1
- package/package.json +12 -2
package/dist/index.d.cts
CHANGED
|
@@ -360,6 +360,16 @@ interface FreezeScanCheckpoint {
|
|
|
360
360
|
piOpen: boolean;
|
|
361
361
|
declOpen: boolean;
|
|
362
362
|
cdataOpen: boolean;
|
|
363
|
+
/** parse5 BOGUS COMMENT open inside a real html-flow run: `<!` not
|
|
364
|
+
* followed by `--` / letter / `[CDATA[`, or `</` not followed by a
|
|
365
|
+
* letter (`<!\n`, `<!-`, `</\n`, `<//`) — eaten up to the next `>`;
|
|
366
|
+
* a `</div>` inside is comment text, not a close (2026-08-19 review r2
|
|
367
|
+
* P1-3: the balance zeroed past an open div). micromark has no such
|
|
368
|
+
* construct: those bytes are just html-block content. */
|
|
369
|
+
bogusOpen: boolean;
|
|
370
|
+
/** The RAW_TEXT_ELEMENTS element currently open (its content is text to
|
|
371
|
+
* parse5): tags and comment tokens are ignored until `</name>`. */
|
|
372
|
+
rawTextOpen: string | null;
|
|
363
373
|
inFence: boolean;
|
|
364
374
|
fenceChar: string;
|
|
365
375
|
fenceLen: number;
|
|
@@ -425,7 +435,61 @@ interface FreezeScanCheckpoint {
|
|
|
425
435
|
* tagBalance but not yet confirmed by a later `>` — reverted at the next
|
|
426
436
|
* blank line (a tag cannot span one). See TRUNCATED_TAG_RE. */
|
|
427
437
|
pendingTruncatedTags: string[];
|
|
438
|
+
/** Line-truncated CLOSING tags (`</div` + EOL, no `>`) inside an html-flow
|
|
439
|
+
* run, waiting for a `>` on a later line of the same run. Unlike opens
|
|
440
|
+
* they are NOT counted up front: a close tag cannot carry attributes, so
|
|
441
|
+
* `para </style` (prose to micromark, still-open element to parse5 —
|
|
442
|
+
* RAWTEXT waits for the `>`) must not zero the balance (2026-08-19
|
|
443
|
+
* review P1 — the boundary crossed an open `<style>`). Confirmed and
|
|
444
|
+
* applied only when a later line of the run brings the `>` (parse5
|
|
445
|
+
* completes the end tag; micromark's block ends at the blank anyway);
|
|
446
|
+
* dropped unapplied at the blank (element stays counted — over-block).
|
|
447
|
+
* Paragraph-context truncated closes are never pended: a `>` at block
|
|
448
|
+
* indent on the next line is a blockquote to micromark, and the one
|
|
449
|
+
* shape that would complete the inline close (`</b\n >`, a 4+-space
|
|
450
|
+
* lazy continuation) is not modelled — the element stays counted,
|
|
451
|
+
* over-block. */
|
|
452
|
+
pendingTruncatedCloses: string[];
|
|
453
|
+
/** An html-flow line ended inside a tag (`<div`, `</div`, `<br` — open,
|
|
454
|
+
* close or void, with or without attributes): parse5's tokenizer is
|
|
455
|
+
* still in that tag, so on the following lines everything up to the
|
|
456
|
+
* FIRST `>` is attribute garbage — `</div>` there does NOT close
|
|
457
|
+
* anything (oracle review of 2.4.4: `<div>\n<div>\n</div\n</div>` froze
|
|
458
|
+
* past the still-open outer div; pre-existing, 1-char slices). While
|
|
459
|
+
* set: a line without `>` gets no tag scan at all; the line with the
|
|
460
|
+
* `>` completes the pending close (if any), then only its text after
|
|
461
|
+
* that `>` is scanned. Cleared there and at the blank line. */
|
|
462
|
+
tagAcrossLines: boolean;
|
|
463
|
+
/** Indent of the line that set `tagAcrossLines`. A following line that
|
|
464
|
+
* DE-INDENTS below it may have left the container (a list item's html
|
|
465
|
+
* block ends there; hast-util-raw resets the tokenizer at the li/ul
|
|
466
|
+
* boundary, so a `<div>` on that line is a real start tag, not garbage)
|
|
467
|
+
* — or may still be the same html block (root-level ` </div\n</div>`,
|
|
468
|
+
* still garbage). Unknowable here → poison (oracle 3rd pass). */
|
|
469
|
+
tagAcrossLinesIndent: number;
|
|
470
|
+
/** parse5's position inside that tag's attribute area at the end of the
|
|
471
|
+
* last scanned line (see TagAttrState). A quoted value left open swallows
|
|
472
|
+
* `>` and line endings; a `>` that arrives while `outside` ends the tag. */
|
|
473
|
+
tagAcrossLinesState: TagAttrState;
|
|
474
|
+
/** The html-flow run since the last blank REALLY started as a micromark
|
|
475
|
+
* html block (type 6 / type 1 / a paragraph-not-interrupting type 7) —
|
|
476
|
+
* as opposed to `htmlFlowSinceBlank`, which any `<tag` / `</tag` line
|
|
477
|
+
* start sets (over-approximation, fine for its over-blocking uses). Only
|
|
478
|
+
* in a real run are the bytes raw to parse5 across line endings; the
|
|
479
|
+
* cross-line-tag garbage model (`tagAcrossLines`, pended closes) is
|
|
480
|
+
* gated on it — in a paragraph starting `</i` the next line's `<div>` /
|
|
481
|
+
* `<!--` are REAL blocks (oracle re-check of 2.4.4: gating on
|
|
482
|
+
* htmlFlowSinceBlank swallowed them — a new under-block). Sticky to the
|
|
483
|
+
* blank; a type 6/1 start on a later line of a non-real run promotes it. */
|
|
484
|
+
htmlFlowReal: boolean;
|
|
428
485
|
}
|
|
486
|
+
/** parse5 tokenizer position inside a tag's attribute area, tracked across
|
|
487
|
+
* line endings for `tagAcrossLines` (2026-08-19 review r2 P1-2 / P2-3):
|
|
488
|
+
* `outside` = before/in an attribute name (a `"` here starts a NAME, not a
|
|
489
|
+
* value); `afterEq` = just past `=`; `unquoted` = in an unquoted value
|
|
490
|
+
* (whitespace ends it); `"` / `'` = inside a quoted value — `>` and line
|
|
491
|
+
* endings are value bytes there, only the matching quote leaves it. */
|
|
492
|
+
type TagAttrState = 'outside' | 'afterEq' | 'unquoted' | '"' | "'";
|
|
429
493
|
declare function computeFreezeBoundary(text: string, options: FreezeBoundaryOptions, resume?: FreezeScanCheckpoint | null): FreezeScanResult;
|
|
430
494
|
|
|
431
495
|
/**
|
|
@@ -649,38 +713,6 @@ interface DefLabels {
|
|
|
649
713
|
linkLabels: Set<string>;
|
|
650
714
|
}
|
|
651
715
|
declare function collectDefLabels(source: string): DefLabels;
|
|
652
|
-
/** Index just past the LAST blank line of `source`, or 0 if none.
|
|
653
|
-
* Plain non-overlapping scan: for runs of blanks ("\n\n\n") this can land
|
|
654
|
-
* a newline or two early, but the slack is whitespace-only and whitespace
|
|
655
|
-
* can never satisfy DEF_LINE_START_RE, so the decision is identical.
|
|
656
|
-
* @internal exported for tests only — the fast path is otherwise
|
|
657
|
-
* indistinguishable from a full parse whose sets came out equal. */
|
|
658
|
-
declare function lastRegionStart(source: string): number;
|
|
659
|
-
/** A line that can START a definition, matched by the FULL def signature:
|
|
660
|
-
* container prefixes (blockquote `>`, list bullets, ordered-list digits),
|
|
661
|
-
* then `[label]` with the closing bracket IMMEDIATELY followed by `:` —
|
|
662
|
-
* remark accepts a definition only with that adjacency (grammar-verified:
|
|
663
|
-
* `[x]\n: url` and `[x] : url` are paragraphs, and `[a][b]: url` is a
|
|
664
|
-
* reference because the label's first unescaped `]` isn't followed by
|
|
665
|
-
* `:`). The label alternation admits escape pairs (`\]` stays inside the
|
|
666
|
-
* label) and spans newlines (labels may soft-wrap; they cannot cross the
|
|
667
|
-
* blank line that bounds the region). Both alternatives are disjoint, so
|
|
668
|
-
* the scan is linear — no backtracking blowup on bracket-dense regions.
|
|
669
|
-
*
|
|
670
|
-
* Requiring the signature (not just a line-start `[`) is what keeps the
|
|
671
|
-
* streaming-heavy shapes — bulleted link lists `- [t](u)`, task boxes
|
|
672
|
-
* `- [x]`, reference lists `- [a][b]` — on the fast path; a bracket-only
|
|
673
|
-
* probe made every append inside a blank-line-free link list pay a full
|
|
674
|
-
* reparse (the measured Documents+smooth cliff). An INCOMPLETE def line
|
|
675
|
-
* (`[x` with `]:` still in flight) correctly stays on the fast path too:
|
|
676
|
-
* the parser sees no definition in it either, and the region re-check on
|
|
677
|
-
* the completing append flips to the full parse exactly when the answer
|
|
678
|
-
* can change. The `m` flag also matches at index 0, which is a true line
|
|
679
|
-
* start (the region begins just past a blank line or at the document
|
|
680
|
-
* start). Residual over-matching (e.g. `[x]:` inside an open code fence)
|
|
681
|
-
* is safe: it costs a redundant full parse, never a wrong result.
|
|
682
|
-
* @internal exported for tests only. */
|
|
683
|
-
declare const DEF_LINE_START_RE: RegExp;
|
|
684
716
|
interface DefLabelScanner {
|
|
685
717
|
/** Equivalent to `collectDefLabels(source)` at every call, but cheap for
|
|
686
718
|
* the streaming common case. Returns a REFERENCE-STABLE result while the
|
|
@@ -906,8 +938,18 @@ interface RegistryInternal extends Registry {
|
|
|
906
938
|
* keeps the version monotonic-by-1-per-mount which makes debugging
|
|
907
939
|
* easier). The granular `allocateSymbol` / `contributeLabels` methods
|
|
908
940
|
* remain available for tests that need to exercise each step. */
|
|
909
|
-
registerChunk(reactId: string, footnotes: Set<string>, links: Set<string
|
|
910
|
-
|
|
941
|
+
registerChunk(reactId: string, footnotes: Set<string>, links: Set<string>, documentIndex?: number): symbol;
|
|
942
|
+
/** `documentIndex` — the chunk's position in the DOCUMENT (not its mount
|
|
943
|
+
* order). Without it a chunk joins `chunkOrder` at the end, which is
|
|
944
|
+
* wrong for any list that unmounts and remounts chunks: a virtualized
|
|
945
|
+
* transcript scrolling back re-registers an earlier chunk after the ones
|
|
946
|
+
* still mounted, and footnote numbering plus "which chunk renders the
|
|
947
|
+
* aggregate footer" follow that order (2026-08-19 review r2 P2-10).
|
|
948
|
+
* Chunks that supply an index are kept sorted by it; chunks without one
|
|
949
|
+
* keep mount order after them. */
|
|
950
|
+
allocateSymbol(reactId: string, documentIndex?: number): symbol;
|
|
951
|
+
/** @internal Insert a chunk Symbol at its document position. */
|
|
952
|
+
_placeChunk(sym: symbol, documentIndex?: number): void;
|
|
911
953
|
releaseSymbol(reactId: string): void;
|
|
912
954
|
contributeLabels(symbol: symbol, footnotes: Set<string>, links: Set<string>): void;
|
|
913
955
|
contributeChunkData(symbol: symbol, data: ChunkData): void;
|
|
@@ -915,6 +957,8 @@ interface RegistryInternal extends Registry {
|
|
|
915
957
|
symbol: symbol;
|
|
916
958
|
refcount: number;
|
|
917
959
|
}>;
|
|
960
|
+
/** Symbol → the `documentIndex` its chunk supplied (see allocateSymbol). */
|
|
961
|
+
_chunkIndex: Map<symbol, number>;
|
|
918
962
|
_subscribers: Set<() => void>;
|
|
919
963
|
_notifyScheduled: boolean;
|
|
920
964
|
_notify(): void;
|
|
@@ -1019,6 +1063,12 @@ type SanitizeSchema = typeof defaultSchema;
|
|
|
1019
1063
|
* uncaught — there is no try/catch. Callers usually invoke this once at
|
|
1020
1064
|
* module load, where a thrown error surfaces as a startup-time crash and
|
|
1021
1065
|
* is the correct failure mode.
|
|
1066
|
+
* - **Widening is total.** Adding a tag to `tagNames` admits that element
|
|
1067
|
+
* with ALL of its semantics — `script`, `iframe`, `style`, `object`,
|
|
1068
|
+
* `form`, `base` re-enter the tree verbatim, and the two-gate URL story
|
|
1069
|
+
* in the README / SECURITY.md no longer describes your renderer. Prefer
|
|
1070
|
+
* allowing an attribute or a protocol over allowing an element; treat
|
|
1071
|
+
* any element you add as trusted input.
|
|
1022
1072
|
*
|
|
1023
1073
|
* @param modifier - Receives a deep clone of the library default. Mutate it
|
|
1024
1074
|
* freely; either return the (possibly different) result, or return
|
|
@@ -1413,10 +1463,16 @@ declare function isFootnoteSection(node: Element): boolean;
|
|
|
1413
1463
|
|
|
1414
1464
|
declare function normalizeId(s: string): string;
|
|
1415
1465
|
/**
|
|
1416
|
-
*
|
|
1417
|
-
*
|
|
1418
|
-
*
|
|
1419
|
-
*
|
|
1466
|
+
* The form of raw chunk SOURCE that the PASS 0.5 substring pre-check compares
|
|
1467
|
+
* registry labels against. It is exactly {@link normalizeId}: micromark's
|
|
1468
|
+
* `identifier` (what the registry keys are built from) is the label's
|
|
1469
|
+
* source bytes with backslashes KEPT (`[^a\*b]` → `a\*b`; only the `label`
|
|
1470
|
+
* field is unescaped), so the source must NOT be unescaped before matching
|
|
1471
|
+
* — an unescaping pass made every label holding an escaped punctuation
|
|
1472
|
+
* character miss the pre-check for good, and the cross-chunk reference
|
|
1473
|
+
* rendered as literal `[text][label]` (2026-08-19 review r2 P2-5; the
|
|
1474
|
+
* 2.4.5 narrowing to ASCII punctuation kept the wrong premise). Kept as a
|
|
1475
|
+
* named export for API stability.
|
|
1420
1476
|
*/
|
|
1421
1477
|
declare function normalizeForMatch(s: string): string;
|
|
1422
1478
|
|
|
@@ -1604,25 +1660,6 @@ type AttributeEntry = NonNullable<NonNullable<Schema['attributes']>[string]>[num
|
|
|
1604
1660
|
* is always tuple-form, so this branch is defensive only.
|
|
1605
1661
|
*/
|
|
1606
1662
|
declare function mergeClassNameAllowlist(existing: ReadonlyArray<AttributeEntry> | undefined, extraClassNames: readonly string[]): AttributeEntry[];
|
|
1607
|
-
/**
|
|
1608
|
-
* The full sanitize schema used by the markdown renderer: extends
|
|
1609
|
-
* `defaultSchema` to allow `<mark>`, the KaTeX math class names, and the
|
|
1610
|
-
* three custom hast tags emitted by cross-chunk coordination handlers.
|
|
1611
|
-
*
|
|
1612
|
-
* **Owns its arrays and objects.** The shallow spread of `defaultSchema`
|
|
1613
|
-
* alone would leave `attributes.a`, `attributes.img`, `protocols`,
|
|
1614
|
-
* `ancestors`, and similar nested fields aliased to `rehype-sanitize`'s
|
|
1615
|
-
* default singleton. A consumer who reasonably (but mistakenly) writes
|
|
1616
|
-
* `sanitizeSchema.protocols.href.push('myapp')` would then poison
|
|
1617
|
-
* `rehype-sanitize`'s `defaultSchema` for every other consumer in the
|
|
1618
|
-
* process — a cross-package side-effect that's near-impossible to debug.
|
|
1619
|
-
*
|
|
1620
|
-
* One `cloneDeep` at module init breaks that aliasing without measurable
|
|
1621
|
-
* cost (init-time only, single small object graph). The recommended
|
|
1622
|
-
* extension API is still {@link extendSanitizeSchema}, which clones again
|
|
1623
|
-
* per call; this layer just makes the exported singleton safe if someone
|
|
1624
|
-
* skips the helper.
|
|
1625
|
-
*/
|
|
1626
1663
|
declare const sanitizeSchema: Schema;
|
|
1627
1664
|
|
|
1628
1665
|
/**
|
|
@@ -1902,6 +1939,20 @@ declare function preprocessLaTeX(str: string): string;
|
|
|
1902
1939
|
*/
|
|
1903
1940
|
declare function createIncrementalLatexPreprocessor(options?: {
|
|
1904
1941
|
freezeThreshold?: number;
|
|
1942
|
+
/** Failure backoff (default on). Tests that rely on `freezeThreshold: 0`
|
|
1943
|
+
* to attempt a freeze on EVERY call turn it off, so 1-char chunkings keep
|
|
1944
|
+
* exercising the cut rules instead of skipping most attempts; backoff
|
|
1945
|
+
* can only freeze LESS, so passing without it implies passing with it.
|
|
1946
|
+
* @internal */
|
|
1947
|
+
backoff?: boolean;
|
|
1948
|
+
/** Test hook: called once per freeze ATTEMPT (a scan of the active
|
|
1949
|
+
* region) with the region's length and how many source bytes the
|
|
1950
|
+
* attempt froze (0 = failed), so the backoff bound and freeze progress
|
|
1951
|
+
* can be pinned. @internal */
|
|
1952
|
+
onAttempt?: (info: {
|
|
1953
|
+
activeLength: number;
|
|
1954
|
+
frozenBytes: number;
|
|
1955
|
+
}) => void;
|
|
1905
1956
|
}): (content: string) => string;
|
|
1906
1957
|
|
|
1907
1958
|
/**
|
|
@@ -1970,4 +2021,4 @@ type RemendPreprocessorOptions = Omit<RemendOptions, 'katex' | 'inlineKatex'>;
|
|
|
1970
2021
|
*/
|
|
1971
2022
|
declare function createRemendPreprocessor(options?: RemendPreprocessorOptions): AIMDContentPreprocessor;
|
|
1972
2023
|
|
|
1973
|
-
export { type AIMDContentPreprocessor, type AIMarkdownEnginePlugin, type AIMarkdownEnginePluginName, type AdvanceOptions, type AdvanceResult, type AllowElement, type ChunkData, type Contribution, type CrossChunkHandlerOptions, DEFAULT_PAYLOAD,
|
|
2024
|
+
export { type AIMDContentPreprocessor, type AIMarkdownEnginePlugin, type AIMarkdownEnginePluginName, type AdvanceOptions, type AdvanceResult, type AllowElement, type ChunkData, type Contribution, type CrossChunkHandlerOptions, DEFAULT_PAYLOAD, type DefLabelScanner, type DefLabels, type Deprecation, type EnginePluginInternals, type EnginePluginStage, type ExtractContributionsOptions, type FootnoteDef, type FreezeBoundaryOptions, type IncrementalParseState, type IncrementalStage, type LinkDef, PIPELINE_STAGES, type ParsedMarkdown, type PhantomLabels, type PipelineOptions, type PipelineStage, type RefKind, type RefRecord, type Registry, type RegistryInternal, type RehypePlugins, type RehypeRebaseHashLinksOptions, type RemarkPlugins, type RemarkRehypeOptions, type RemendPreprocessorOptions, SENTINEL_FN_CONTENT, SENTINEL_LINK_URL, SMOOTH_STREAM_PACING_PRESETS, STAGE_MEASURE_PREFIX, type SanitizeSchema, type SmoothStreamController, type SmoothStreamOptions, type SmoothStreamPacing, type SmoothStreamPacingParams, type TransformContext, type UrlAttrKey, type UrlAttrTag, type UrlTransform, advanceIncrementalParse, attributeHastChildren, buildCoreRehypePlugins, buildCoreRemarkPlugins, buildCoreRemarkRehypeOptions, buildCrossChunkHandlers, buildPhantomSuffix, buildTransform, codePointSnapshots, collectDefLabels, computeFreezeBoundary, createDefLabelScanner, createFile, createIncrementalLatexPreprocessor, createProcessor, createRegistry, createRemendPreprocessor, createSmoothStreamController, defaultEnginePlugins, defaultUrlTransform, definitionList, extendSanitizeSchema, extractContributions, extractDefBodiesFromHast, footnoteSafeId, getEnginePluginInternals, hasLoneSurrogate, highlight, isFootnoteSection, measureStage, mergeClassNameAllowlist, normalizeForMatch, normalizeId, pangu, parseStage, phantomSuffixCloser, preprocessAIMDContent, preprocessLaTeX, rehypeFooterAdorn, rehypeRebaseHashLinks, removeComments, sanitizeCrossChunkUrl, sanitizeSchema, shortenDocumentId, smartypants, sourceIdFromFootnoteLiId, splitByProtectedRegions, subscribeStageTimings, transformStage, withDefs };
|
package/dist/index.d.ts
CHANGED
|
@@ -360,6 +360,16 @@ interface FreezeScanCheckpoint {
|
|
|
360
360
|
piOpen: boolean;
|
|
361
361
|
declOpen: boolean;
|
|
362
362
|
cdataOpen: boolean;
|
|
363
|
+
/** parse5 BOGUS COMMENT open inside a real html-flow run: `<!` not
|
|
364
|
+
* followed by `--` / letter / `[CDATA[`, or `</` not followed by a
|
|
365
|
+
* letter (`<!\n`, `<!-`, `</\n`, `<//`) — eaten up to the next `>`;
|
|
366
|
+
* a `</div>` inside is comment text, not a close (2026-08-19 review r2
|
|
367
|
+
* P1-3: the balance zeroed past an open div). micromark has no such
|
|
368
|
+
* construct: those bytes are just html-block content. */
|
|
369
|
+
bogusOpen: boolean;
|
|
370
|
+
/** The RAW_TEXT_ELEMENTS element currently open (its content is text to
|
|
371
|
+
* parse5): tags and comment tokens are ignored until `</name>`. */
|
|
372
|
+
rawTextOpen: string | null;
|
|
363
373
|
inFence: boolean;
|
|
364
374
|
fenceChar: string;
|
|
365
375
|
fenceLen: number;
|
|
@@ -425,7 +435,61 @@ interface FreezeScanCheckpoint {
|
|
|
425
435
|
* tagBalance but not yet confirmed by a later `>` — reverted at the next
|
|
426
436
|
* blank line (a tag cannot span one). See TRUNCATED_TAG_RE. */
|
|
427
437
|
pendingTruncatedTags: string[];
|
|
438
|
+
/** Line-truncated CLOSING tags (`</div` + EOL, no `>`) inside an html-flow
|
|
439
|
+
* run, waiting for a `>` on a later line of the same run. Unlike opens
|
|
440
|
+
* they are NOT counted up front: a close tag cannot carry attributes, so
|
|
441
|
+
* `para </style` (prose to micromark, still-open element to parse5 —
|
|
442
|
+
* RAWTEXT waits for the `>`) must not zero the balance (2026-08-19
|
|
443
|
+
* review P1 — the boundary crossed an open `<style>`). Confirmed and
|
|
444
|
+
* applied only when a later line of the run brings the `>` (parse5
|
|
445
|
+
* completes the end tag; micromark's block ends at the blank anyway);
|
|
446
|
+
* dropped unapplied at the blank (element stays counted — over-block).
|
|
447
|
+
* Paragraph-context truncated closes are never pended: a `>` at block
|
|
448
|
+
* indent on the next line is a blockquote to micromark, and the one
|
|
449
|
+
* shape that would complete the inline close (`</b\n >`, a 4+-space
|
|
450
|
+
* lazy continuation) is not modelled — the element stays counted,
|
|
451
|
+
* over-block. */
|
|
452
|
+
pendingTruncatedCloses: string[];
|
|
453
|
+
/** An html-flow line ended inside a tag (`<div`, `</div`, `<br` — open,
|
|
454
|
+
* close or void, with or without attributes): parse5's tokenizer is
|
|
455
|
+
* still in that tag, so on the following lines everything up to the
|
|
456
|
+
* FIRST `>` is attribute garbage — `</div>` there does NOT close
|
|
457
|
+
* anything (oracle review of 2.4.4: `<div>\n<div>\n</div\n</div>` froze
|
|
458
|
+
* past the still-open outer div; pre-existing, 1-char slices). While
|
|
459
|
+
* set: a line without `>` gets no tag scan at all; the line with the
|
|
460
|
+
* `>` completes the pending close (if any), then only its text after
|
|
461
|
+
* that `>` is scanned. Cleared there and at the blank line. */
|
|
462
|
+
tagAcrossLines: boolean;
|
|
463
|
+
/** Indent of the line that set `tagAcrossLines`. A following line that
|
|
464
|
+
* DE-INDENTS below it may have left the container (a list item's html
|
|
465
|
+
* block ends there; hast-util-raw resets the tokenizer at the li/ul
|
|
466
|
+
* boundary, so a `<div>` on that line is a real start tag, not garbage)
|
|
467
|
+
* — or may still be the same html block (root-level ` </div\n</div>`,
|
|
468
|
+
* still garbage). Unknowable here → poison (oracle 3rd pass). */
|
|
469
|
+
tagAcrossLinesIndent: number;
|
|
470
|
+
/** parse5's position inside that tag's attribute area at the end of the
|
|
471
|
+
* last scanned line (see TagAttrState). A quoted value left open swallows
|
|
472
|
+
* `>` and line endings; a `>` that arrives while `outside` ends the tag. */
|
|
473
|
+
tagAcrossLinesState: TagAttrState;
|
|
474
|
+
/** The html-flow run since the last blank REALLY started as a micromark
|
|
475
|
+
* html block (type 6 / type 1 / a paragraph-not-interrupting type 7) —
|
|
476
|
+
* as opposed to `htmlFlowSinceBlank`, which any `<tag` / `</tag` line
|
|
477
|
+
* start sets (over-approximation, fine for its over-blocking uses). Only
|
|
478
|
+
* in a real run are the bytes raw to parse5 across line endings; the
|
|
479
|
+
* cross-line-tag garbage model (`tagAcrossLines`, pended closes) is
|
|
480
|
+
* gated on it — in a paragraph starting `</i` the next line's `<div>` /
|
|
481
|
+
* `<!--` are REAL blocks (oracle re-check of 2.4.4: gating on
|
|
482
|
+
* htmlFlowSinceBlank swallowed them — a new under-block). Sticky to the
|
|
483
|
+
* blank; a type 6/1 start on a later line of a non-real run promotes it. */
|
|
484
|
+
htmlFlowReal: boolean;
|
|
428
485
|
}
|
|
486
|
+
/** parse5 tokenizer position inside a tag's attribute area, tracked across
|
|
487
|
+
* line endings for `tagAcrossLines` (2026-08-19 review r2 P1-2 / P2-3):
|
|
488
|
+
* `outside` = before/in an attribute name (a `"` here starts a NAME, not a
|
|
489
|
+
* value); `afterEq` = just past `=`; `unquoted` = in an unquoted value
|
|
490
|
+
* (whitespace ends it); `"` / `'` = inside a quoted value — `>` and line
|
|
491
|
+
* endings are value bytes there, only the matching quote leaves it. */
|
|
492
|
+
type TagAttrState = 'outside' | 'afterEq' | 'unquoted' | '"' | "'";
|
|
429
493
|
declare function computeFreezeBoundary(text: string, options: FreezeBoundaryOptions, resume?: FreezeScanCheckpoint | null): FreezeScanResult;
|
|
430
494
|
|
|
431
495
|
/**
|
|
@@ -649,38 +713,6 @@ interface DefLabels {
|
|
|
649
713
|
linkLabels: Set<string>;
|
|
650
714
|
}
|
|
651
715
|
declare function collectDefLabels(source: string): DefLabels;
|
|
652
|
-
/** Index just past the LAST blank line of `source`, or 0 if none.
|
|
653
|
-
* Plain non-overlapping scan: for runs of blanks ("\n\n\n") this can land
|
|
654
|
-
* a newline or two early, but the slack is whitespace-only and whitespace
|
|
655
|
-
* can never satisfy DEF_LINE_START_RE, so the decision is identical.
|
|
656
|
-
* @internal exported for tests only — the fast path is otherwise
|
|
657
|
-
* indistinguishable from a full parse whose sets came out equal. */
|
|
658
|
-
declare function lastRegionStart(source: string): number;
|
|
659
|
-
/** A line that can START a definition, matched by the FULL def signature:
|
|
660
|
-
* container prefixes (blockquote `>`, list bullets, ordered-list digits),
|
|
661
|
-
* then `[label]` with the closing bracket IMMEDIATELY followed by `:` —
|
|
662
|
-
* remark accepts a definition only with that adjacency (grammar-verified:
|
|
663
|
-
* `[x]\n: url` and `[x] : url` are paragraphs, and `[a][b]: url` is a
|
|
664
|
-
* reference because the label's first unescaped `]` isn't followed by
|
|
665
|
-
* `:`). The label alternation admits escape pairs (`\]` stays inside the
|
|
666
|
-
* label) and spans newlines (labels may soft-wrap; they cannot cross the
|
|
667
|
-
* blank line that bounds the region). Both alternatives are disjoint, so
|
|
668
|
-
* the scan is linear — no backtracking blowup on bracket-dense regions.
|
|
669
|
-
*
|
|
670
|
-
* Requiring the signature (not just a line-start `[`) is what keeps the
|
|
671
|
-
* streaming-heavy shapes — bulleted link lists `- [t](u)`, task boxes
|
|
672
|
-
* `- [x]`, reference lists `- [a][b]` — on the fast path; a bracket-only
|
|
673
|
-
* probe made every append inside a blank-line-free link list pay a full
|
|
674
|
-
* reparse (the measured Documents+smooth cliff). An INCOMPLETE def line
|
|
675
|
-
* (`[x` with `]:` still in flight) correctly stays on the fast path too:
|
|
676
|
-
* the parser sees no definition in it either, and the region re-check on
|
|
677
|
-
* the completing append flips to the full parse exactly when the answer
|
|
678
|
-
* can change. The `m` flag also matches at index 0, which is a true line
|
|
679
|
-
* start (the region begins just past a blank line or at the document
|
|
680
|
-
* start). Residual over-matching (e.g. `[x]:` inside an open code fence)
|
|
681
|
-
* is safe: it costs a redundant full parse, never a wrong result.
|
|
682
|
-
* @internal exported for tests only. */
|
|
683
|
-
declare const DEF_LINE_START_RE: RegExp;
|
|
684
716
|
interface DefLabelScanner {
|
|
685
717
|
/** Equivalent to `collectDefLabels(source)` at every call, but cheap for
|
|
686
718
|
* the streaming common case. Returns a REFERENCE-STABLE result while the
|
|
@@ -906,8 +938,18 @@ interface RegistryInternal extends Registry {
|
|
|
906
938
|
* keeps the version monotonic-by-1-per-mount which makes debugging
|
|
907
939
|
* easier). The granular `allocateSymbol` / `contributeLabels` methods
|
|
908
940
|
* remain available for tests that need to exercise each step. */
|
|
909
|
-
registerChunk(reactId: string, footnotes: Set<string>, links: Set<string
|
|
910
|
-
|
|
941
|
+
registerChunk(reactId: string, footnotes: Set<string>, links: Set<string>, documentIndex?: number): symbol;
|
|
942
|
+
/** `documentIndex` — the chunk's position in the DOCUMENT (not its mount
|
|
943
|
+
* order). Without it a chunk joins `chunkOrder` at the end, which is
|
|
944
|
+
* wrong for any list that unmounts and remounts chunks: a virtualized
|
|
945
|
+
* transcript scrolling back re-registers an earlier chunk after the ones
|
|
946
|
+
* still mounted, and footnote numbering plus "which chunk renders the
|
|
947
|
+
* aggregate footer" follow that order (2026-08-19 review r2 P2-10).
|
|
948
|
+
* Chunks that supply an index are kept sorted by it; chunks without one
|
|
949
|
+
* keep mount order after them. */
|
|
950
|
+
allocateSymbol(reactId: string, documentIndex?: number): symbol;
|
|
951
|
+
/** @internal Insert a chunk Symbol at its document position. */
|
|
952
|
+
_placeChunk(sym: symbol, documentIndex?: number): void;
|
|
911
953
|
releaseSymbol(reactId: string): void;
|
|
912
954
|
contributeLabels(symbol: symbol, footnotes: Set<string>, links: Set<string>): void;
|
|
913
955
|
contributeChunkData(symbol: symbol, data: ChunkData): void;
|
|
@@ -915,6 +957,8 @@ interface RegistryInternal extends Registry {
|
|
|
915
957
|
symbol: symbol;
|
|
916
958
|
refcount: number;
|
|
917
959
|
}>;
|
|
960
|
+
/** Symbol → the `documentIndex` its chunk supplied (see allocateSymbol). */
|
|
961
|
+
_chunkIndex: Map<symbol, number>;
|
|
918
962
|
_subscribers: Set<() => void>;
|
|
919
963
|
_notifyScheduled: boolean;
|
|
920
964
|
_notify(): void;
|
|
@@ -1019,6 +1063,12 @@ type SanitizeSchema = typeof defaultSchema;
|
|
|
1019
1063
|
* uncaught — there is no try/catch. Callers usually invoke this once at
|
|
1020
1064
|
* module load, where a thrown error surfaces as a startup-time crash and
|
|
1021
1065
|
* is the correct failure mode.
|
|
1066
|
+
* - **Widening is total.** Adding a tag to `tagNames` admits that element
|
|
1067
|
+
* with ALL of its semantics — `script`, `iframe`, `style`, `object`,
|
|
1068
|
+
* `form`, `base` re-enter the tree verbatim, and the two-gate URL story
|
|
1069
|
+
* in the README / SECURITY.md no longer describes your renderer. Prefer
|
|
1070
|
+
* allowing an attribute or a protocol over allowing an element; treat
|
|
1071
|
+
* any element you add as trusted input.
|
|
1022
1072
|
*
|
|
1023
1073
|
* @param modifier - Receives a deep clone of the library default. Mutate it
|
|
1024
1074
|
* freely; either return the (possibly different) result, or return
|
|
@@ -1413,10 +1463,16 @@ declare function isFootnoteSection(node: Element): boolean;
|
|
|
1413
1463
|
|
|
1414
1464
|
declare function normalizeId(s: string): string;
|
|
1415
1465
|
/**
|
|
1416
|
-
*
|
|
1417
|
-
*
|
|
1418
|
-
*
|
|
1419
|
-
*
|
|
1466
|
+
* The form of raw chunk SOURCE that the PASS 0.5 substring pre-check compares
|
|
1467
|
+
* registry labels against. It is exactly {@link normalizeId}: micromark's
|
|
1468
|
+
* `identifier` (what the registry keys are built from) is the label's
|
|
1469
|
+
* source bytes with backslashes KEPT (`[^a\*b]` → `a\*b`; only the `label`
|
|
1470
|
+
* field is unescaped), so the source must NOT be unescaped before matching
|
|
1471
|
+
* — an unescaping pass made every label holding an escaped punctuation
|
|
1472
|
+
* character miss the pre-check for good, and the cross-chunk reference
|
|
1473
|
+
* rendered as literal `[text][label]` (2026-08-19 review r2 P2-5; the
|
|
1474
|
+
* 2.4.5 narrowing to ASCII punctuation kept the wrong premise). Kept as a
|
|
1475
|
+
* named export for API stability.
|
|
1420
1476
|
*/
|
|
1421
1477
|
declare function normalizeForMatch(s: string): string;
|
|
1422
1478
|
|
|
@@ -1604,25 +1660,6 @@ type AttributeEntry = NonNullable<NonNullable<Schema['attributes']>[string]>[num
|
|
|
1604
1660
|
* is always tuple-form, so this branch is defensive only.
|
|
1605
1661
|
*/
|
|
1606
1662
|
declare function mergeClassNameAllowlist(existing: ReadonlyArray<AttributeEntry> | undefined, extraClassNames: readonly string[]): AttributeEntry[];
|
|
1607
|
-
/**
|
|
1608
|
-
* The full sanitize schema used by the markdown renderer: extends
|
|
1609
|
-
* `defaultSchema` to allow `<mark>`, the KaTeX math class names, and the
|
|
1610
|
-
* three custom hast tags emitted by cross-chunk coordination handlers.
|
|
1611
|
-
*
|
|
1612
|
-
* **Owns its arrays and objects.** The shallow spread of `defaultSchema`
|
|
1613
|
-
* alone would leave `attributes.a`, `attributes.img`, `protocols`,
|
|
1614
|
-
* `ancestors`, and similar nested fields aliased to `rehype-sanitize`'s
|
|
1615
|
-
* default singleton. A consumer who reasonably (but mistakenly) writes
|
|
1616
|
-
* `sanitizeSchema.protocols.href.push('myapp')` would then poison
|
|
1617
|
-
* `rehype-sanitize`'s `defaultSchema` for every other consumer in the
|
|
1618
|
-
* process — a cross-package side-effect that's near-impossible to debug.
|
|
1619
|
-
*
|
|
1620
|
-
* One `cloneDeep` at module init breaks that aliasing without measurable
|
|
1621
|
-
* cost (init-time only, single small object graph). The recommended
|
|
1622
|
-
* extension API is still {@link extendSanitizeSchema}, which clones again
|
|
1623
|
-
* per call; this layer just makes the exported singleton safe if someone
|
|
1624
|
-
* skips the helper.
|
|
1625
|
-
*/
|
|
1626
1663
|
declare const sanitizeSchema: Schema;
|
|
1627
1664
|
|
|
1628
1665
|
/**
|
|
@@ -1902,6 +1939,20 @@ declare function preprocessLaTeX(str: string): string;
|
|
|
1902
1939
|
*/
|
|
1903
1940
|
declare function createIncrementalLatexPreprocessor(options?: {
|
|
1904
1941
|
freezeThreshold?: number;
|
|
1942
|
+
/** Failure backoff (default on). Tests that rely on `freezeThreshold: 0`
|
|
1943
|
+
* to attempt a freeze on EVERY call turn it off, so 1-char chunkings keep
|
|
1944
|
+
* exercising the cut rules instead of skipping most attempts; backoff
|
|
1945
|
+
* can only freeze LESS, so passing without it implies passing with it.
|
|
1946
|
+
* @internal */
|
|
1947
|
+
backoff?: boolean;
|
|
1948
|
+
/** Test hook: called once per freeze ATTEMPT (a scan of the active
|
|
1949
|
+
* region) with the region's length and how many source bytes the
|
|
1950
|
+
* attempt froze (0 = failed), so the backoff bound and freeze progress
|
|
1951
|
+
* can be pinned. @internal */
|
|
1952
|
+
onAttempt?: (info: {
|
|
1953
|
+
activeLength: number;
|
|
1954
|
+
frozenBytes: number;
|
|
1955
|
+
}) => void;
|
|
1905
1956
|
}): (content: string) => string;
|
|
1906
1957
|
|
|
1907
1958
|
/**
|
|
@@ -1970,4 +2021,4 @@ type RemendPreprocessorOptions = Omit<RemendOptions, 'katex' | 'inlineKatex'>;
|
|
|
1970
2021
|
*/
|
|
1971
2022
|
declare function createRemendPreprocessor(options?: RemendPreprocessorOptions): AIMDContentPreprocessor;
|
|
1972
2023
|
|
|
1973
|
-
export { type AIMDContentPreprocessor, type AIMarkdownEnginePlugin, type AIMarkdownEnginePluginName, type AdvanceOptions, type AdvanceResult, type AllowElement, type ChunkData, type Contribution, type CrossChunkHandlerOptions, DEFAULT_PAYLOAD,
|
|
2024
|
+
export { type AIMDContentPreprocessor, type AIMarkdownEnginePlugin, type AIMarkdownEnginePluginName, type AdvanceOptions, type AdvanceResult, type AllowElement, type ChunkData, type Contribution, type CrossChunkHandlerOptions, DEFAULT_PAYLOAD, type DefLabelScanner, type DefLabels, type Deprecation, type EnginePluginInternals, type EnginePluginStage, type ExtractContributionsOptions, type FootnoteDef, type FreezeBoundaryOptions, type IncrementalParseState, type IncrementalStage, type LinkDef, PIPELINE_STAGES, type ParsedMarkdown, type PhantomLabels, type PipelineOptions, type PipelineStage, type RefKind, type RefRecord, type Registry, type RegistryInternal, type RehypePlugins, type RehypeRebaseHashLinksOptions, type RemarkPlugins, type RemarkRehypeOptions, type RemendPreprocessorOptions, SENTINEL_FN_CONTENT, SENTINEL_LINK_URL, SMOOTH_STREAM_PACING_PRESETS, STAGE_MEASURE_PREFIX, type SanitizeSchema, type SmoothStreamController, type SmoothStreamOptions, type SmoothStreamPacing, type SmoothStreamPacingParams, type TransformContext, type UrlAttrKey, type UrlAttrTag, type UrlTransform, advanceIncrementalParse, attributeHastChildren, buildCoreRehypePlugins, buildCoreRemarkPlugins, buildCoreRemarkRehypeOptions, buildCrossChunkHandlers, buildPhantomSuffix, buildTransform, codePointSnapshots, collectDefLabels, computeFreezeBoundary, createDefLabelScanner, createFile, createIncrementalLatexPreprocessor, createProcessor, createRegistry, createRemendPreprocessor, createSmoothStreamController, defaultEnginePlugins, defaultUrlTransform, definitionList, extendSanitizeSchema, extractContributions, extractDefBodiesFromHast, footnoteSafeId, getEnginePluginInternals, hasLoneSurrogate, highlight, isFootnoteSection, measureStage, mergeClassNameAllowlist, normalizeForMatch, normalizeId, pangu, parseStage, phantomSuffixCloser, preprocessAIMDContent, preprocessLaTeX, rehypeFooterAdorn, rehypeRebaseHashLinks, removeComments, sanitizeCrossChunkUrl, sanitizeSchema, shortenDocumentId, smartypants, sourceIdFromFootnoteLiId, splitByProtectedRegions, subscribeStageTimings, transformStage, withDefs };
|