@ai-react-markdown/engine 2.4.2 → 2.4.3
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/dist/index.cjs +26 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -41
- package/dist/index.d.ts +20 -41
- package/dist/index.dev.cjs +26 -21
- package/dist/index.dev.cjs.map +1 -1
- package/dist/index.dev.js +26 -21
- package/dist/index.dev.js.map +1 -1
- package/dist/index.js +26 -21
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -764,34 +764,6 @@ interface ExtractContributionsOptions {
|
|
|
764
764
|
* Defs matching these are skipped to avoid leaking sentinel rows into
|
|
765
765
|
* registry.chunkData. */
|
|
766
766
|
phantomFootnoteLabels?: Set<string>;
|
|
767
|
-
/**
|
|
768
|
-
* Caller's resolved URL transform (typically `props.urlTransform ??
|
|
769
|
-
* defaultUrlTransform`). Applied to every emitted `linkDef.url` so the
|
|
770
|
-
* registry stores already-sanitized URLs.
|
|
771
|
-
*
|
|
772
|
-
* Cross-chunk link/image references render through the registry rather
|
|
773
|
-
* than the in-tree hast (which is where react-markdown's transform pass
|
|
774
|
-
* normally enforces `urlTransform`). Without this, a chunk defining
|
|
775
|
-
* `[evil]: javascript:alert(1)` could XSS a sibling chunk that uses
|
|
776
|
-
* `[click][evil]` — the standalone path strips the protocol; the cross-
|
|
777
|
-
* chunk path would have rendered `<a href="javascript:…">`. Sanitizing at
|
|
778
|
-
* contribute time also benefits any future consumer that reads
|
|
779
|
-
* `Registry.resolveLinkDef` directly.
|
|
780
|
-
*
|
|
781
|
-
* Invocation contract mirrors react-markdown's hast-pass call site
|
|
782
|
-
* (`buildTransform` in `./markdown/transform.ts`): a synthetic
|
|
783
|
-
* `<a href={url}>` element stands in for the node argument since
|
|
784
|
-
* mdast `definition` nodes have no hast counterpart. The key is `'href'`
|
|
785
|
-
* — link defs are far more common than image defs, and protocol-allowlist
|
|
786
|
-
* transforms (including `defaultUrlTransform`) are key-agnostic anyway.
|
|
787
|
-
* A `null` return collapses to the empty string, matching how
|
|
788
|
-
* `transform.ts` would render a blocked attribute.
|
|
789
|
-
*
|
|
790
|
-
* Omitting this option preserves v1 behavior (URLs stored raw). Library
|
|
791
|
-
* callers should always supply it; the option stays optional so unit-test
|
|
792
|
-
* fixtures that don't care about URL safety can construct minimal calls.
|
|
793
|
-
*/
|
|
794
|
-
urlTransform?: UrlTransform;
|
|
795
767
|
}
|
|
796
768
|
declare function extractContributions(mdast: Root, options?: ExtractContributionsOptions): Generator<Contribution>;
|
|
797
769
|
|
|
@@ -890,18 +862,15 @@ interface Registry {
|
|
|
890
862
|
canonicalLinkFor(label: string): symbol | null;
|
|
891
863
|
globalNumber(label: string): number | null;
|
|
892
864
|
/**
|
|
893
|
-
* Resolve a cross-chunk link definition by label. The returned `url` is
|
|
894
|
-
*
|
|
895
|
-
*
|
|
896
|
-
*
|
|
897
|
-
*
|
|
865
|
+
* Resolve a cross-chunk link definition by label. The returned `url` is
|
|
866
|
+
* the RAW destination from the contributing chunk's source — the registry
|
|
867
|
+
* does not sanitize. The library's cross-chunk link/image placeholders run
|
|
868
|
+
* the full per-attribute sanitization (`sanitizeSchema.protocols` +
|
|
869
|
+
* `urlTransform`, correct key) at render time.
|
|
898
870
|
*
|
|
899
871
|
* Consumers reading `def.url` directly (custom backlink panels, analytics,
|
|
900
|
-
* dev tooling)
|
|
901
|
-
*
|
|
902
|
-
* an `href`/`src` — the contribute-time pass uses the `'href'` key and a
|
|
903
|
-
* synthetic `<a>` node, so a key-aware policy may treat the value
|
|
904
|
-
* differently when used as an `<img src>`.
|
|
872
|
+
* dev tooling) MUST run their own policy before rendering it as an
|
|
873
|
+
* `href`/`src` — a chunk can define `[evil]: javascript:alert(1)`.
|
|
905
874
|
*/
|
|
906
875
|
resolveLinkDef(label: string): LinkDef | null;
|
|
907
876
|
getRefsForLabel(label: string): number;
|
|
@@ -1692,7 +1661,11 @@ declare const sanitizeSchema: Schema;
|
|
|
1692
1661
|
* and the trailing grapheme of the source is held back until it is
|
|
1693
1662
|
* confirmed — by more text arriving or by `finish()` — so a surrogate
|
|
1694
1663
|
* half or a still-growing emoji ZWJ sequence is never revealed to the
|
|
1695
|
-
* parser mid-cluster.
|
|
1664
|
+
* parser mid-cluster. `snap()` (a replacement, or the very first `update`)
|
|
1665
|
+
* is outside this promise by design: it shows the whole replacement text
|
|
1666
|
+
* at once, trailing half-cluster included — a hold-back there would leave
|
|
1667
|
+
* a controller that never drains when nothing follows (v2.4.2 review
|
|
1668
|
+
* P3-1). Hosts that seed a stream mid-cluster get one frame of U+FFFD.
|
|
1696
1669
|
*
|
|
1697
1670
|
* @module components/smoothStream/controller
|
|
1698
1671
|
*/
|
|
@@ -1776,7 +1749,8 @@ interface SmoothStreamController {
|
|
|
1776
1749
|
* a later {@link update} resumes animation.
|
|
1777
1750
|
*/
|
|
1778
1751
|
finish(): void;
|
|
1779
|
-
/** Jumps to `source` instantly, no animation, and clears any backlog.
|
|
1752
|
+
/** Jumps to `source` instantly, no animation, and clears any backlog.
|
|
1753
|
+
* No trailing-grapheme hold-back (see the module docs). */
|
|
1780
1754
|
snap(source: string): void;
|
|
1781
1755
|
/**
|
|
1782
1756
|
* Reveals everything pending right now (skip-animation affordance). Keeps
|
|
@@ -1890,7 +1864,12 @@ interface Segment {
|
|
|
1890
1864
|
* Split content into alternating text and protected segments.
|
|
1891
1865
|
* Protected segments (isCode: true) are excluded from LaTeX processing:
|
|
1892
1866
|
* - fenced multiline code blocks: 3+ backticks or tildes at the *start of a
|
|
1893
|
-
* line* (
|
|
1867
|
+
* line* (any indentation — container-relative limits are not modelled).
|
|
1868
|
+
* Mid-line runs are never fence openers. INDENTED code blocks (4+ spaces
|
|
1869
|
+
* after a blank line, outside any container) are NOT modelled: without a
|
|
1870
|
+
* container model they cannot be told from a list item's continuation
|
|
1871
|
+
* paragraph, and protecting them would silence math in nested lists.
|
|
1872
|
+
* Known limitation — `$` inside an indented code block may be rewritten.
|
|
1894
1873
|
* - inline code spans: a run of N backticks closed by another run of exactly
|
|
1895
1874
|
* N backticks. May span newlines. Multi-backtick forms (e.g. `` `` `x` ``)
|
|
1896
1875
|
* are supported so literal backtick characters can appear inside.
|
package/dist/index.d.ts
CHANGED
|
@@ -764,34 +764,6 @@ interface ExtractContributionsOptions {
|
|
|
764
764
|
* Defs matching these are skipped to avoid leaking sentinel rows into
|
|
765
765
|
* registry.chunkData. */
|
|
766
766
|
phantomFootnoteLabels?: Set<string>;
|
|
767
|
-
/**
|
|
768
|
-
* Caller's resolved URL transform (typically `props.urlTransform ??
|
|
769
|
-
* defaultUrlTransform`). Applied to every emitted `linkDef.url` so the
|
|
770
|
-
* registry stores already-sanitized URLs.
|
|
771
|
-
*
|
|
772
|
-
* Cross-chunk link/image references render through the registry rather
|
|
773
|
-
* than the in-tree hast (which is where react-markdown's transform pass
|
|
774
|
-
* normally enforces `urlTransform`). Without this, a chunk defining
|
|
775
|
-
* `[evil]: javascript:alert(1)` could XSS a sibling chunk that uses
|
|
776
|
-
* `[click][evil]` — the standalone path strips the protocol; the cross-
|
|
777
|
-
* chunk path would have rendered `<a href="javascript:…">`. Sanitizing at
|
|
778
|
-
* contribute time also benefits any future consumer that reads
|
|
779
|
-
* `Registry.resolveLinkDef` directly.
|
|
780
|
-
*
|
|
781
|
-
* Invocation contract mirrors react-markdown's hast-pass call site
|
|
782
|
-
* (`buildTransform` in `./markdown/transform.ts`): a synthetic
|
|
783
|
-
* `<a href={url}>` element stands in for the node argument since
|
|
784
|
-
* mdast `definition` nodes have no hast counterpart. The key is `'href'`
|
|
785
|
-
* — link defs are far more common than image defs, and protocol-allowlist
|
|
786
|
-
* transforms (including `defaultUrlTransform`) are key-agnostic anyway.
|
|
787
|
-
* A `null` return collapses to the empty string, matching how
|
|
788
|
-
* `transform.ts` would render a blocked attribute.
|
|
789
|
-
*
|
|
790
|
-
* Omitting this option preserves v1 behavior (URLs stored raw). Library
|
|
791
|
-
* callers should always supply it; the option stays optional so unit-test
|
|
792
|
-
* fixtures that don't care about URL safety can construct minimal calls.
|
|
793
|
-
*/
|
|
794
|
-
urlTransform?: UrlTransform;
|
|
795
767
|
}
|
|
796
768
|
declare function extractContributions(mdast: Root, options?: ExtractContributionsOptions): Generator<Contribution>;
|
|
797
769
|
|
|
@@ -890,18 +862,15 @@ interface Registry {
|
|
|
890
862
|
canonicalLinkFor(label: string): symbol | null;
|
|
891
863
|
globalNumber(label: string): number | null;
|
|
892
864
|
/**
|
|
893
|
-
* Resolve a cross-chunk link definition by label. The returned `url` is
|
|
894
|
-
*
|
|
895
|
-
*
|
|
896
|
-
*
|
|
897
|
-
*
|
|
865
|
+
* Resolve a cross-chunk link definition by label. The returned `url` is
|
|
866
|
+
* the RAW destination from the contributing chunk's source — the registry
|
|
867
|
+
* does not sanitize. The library's cross-chunk link/image placeholders run
|
|
868
|
+
* the full per-attribute sanitization (`sanitizeSchema.protocols` +
|
|
869
|
+
* `urlTransform`, correct key) at render time.
|
|
898
870
|
*
|
|
899
871
|
* Consumers reading `def.url` directly (custom backlink panels, analytics,
|
|
900
|
-
* dev tooling)
|
|
901
|
-
*
|
|
902
|
-
* an `href`/`src` — the contribute-time pass uses the `'href'` key and a
|
|
903
|
-
* synthetic `<a>` node, so a key-aware policy may treat the value
|
|
904
|
-
* differently when used as an `<img src>`.
|
|
872
|
+
* dev tooling) MUST run their own policy before rendering it as an
|
|
873
|
+
* `href`/`src` — a chunk can define `[evil]: javascript:alert(1)`.
|
|
905
874
|
*/
|
|
906
875
|
resolveLinkDef(label: string): LinkDef | null;
|
|
907
876
|
getRefsForLabel(label: string): number;
|
|
@@ -1692,7 +1661,11 @@ declare const sanitizeSchema: Schema;
|
|
|
1692
1661
|
* and the trailing grapheme of the source is held back until it is
|
|
1693
1662
|
* confirmed — by more text arriving or by `finish()` — so a surrogate
|
|
1694
1663
|
* half or a still-growing emoji ZWJ sequence is never revealed to the
|
|
1695
|
-
* parser mid-cluster.
|
|
1664
|
+
* parser mid-cluster. `snap()` (a replacement, or the very first `update`)
|
|
1665
|
+
* is outside this promise by design: it shows the whole replacement text
|
|
1666
|
+
* at once, trailing half-cluster included — a hold-back there would leave
|
|
1667
|
+
* a controller that never drains when nothing follows (v2.4.2 review
|
|
1668
|
+
* P3-1). Hosts that seed a stream mid-cluster get one frame of U+FFFD.
|
|
1696
1669
|
*
|
|
1697
1670
|
* @module components/smoothStream/controller
|
|
1698
1671
|
*/
|
|
@@ -1776,7 +1749,8 @@ interface SmoothStreamController {
|
|
|
1776
1749
|
* a later {@link update} resumes animation.
|
|
1777
1750
|
*/
|
|
1778
1751
|
finish(): void;
|
|
1779
|
-
/** Jumps to `source` instantly, no animation, and clears any backlog.
|
|
1752
|
+
/** Jumps to `source` instantly, no animation, and clears any backlog.
|
|
1753
|
+
* No trailing-grapheme hold-back (see the module docs). */
|
|
1780
1754
|
snap(source: string): void;
|
|
1781
1755
|
/**
|
|
1782
1756
|
* Reveals everything pending right now (skip-animation affordance). Keeps
|
|
@@ -1890,7 +1864,12 @@ interface Segment {
|
|
|
1890
1864
|
* Split content into alternating text and protected segments.
|
|
1891
1865
|
* Protected segments (isCode: true) are excluded from LaTeX processing:
|
|
1892
1866
|
* - fenced multiline code blocks: 3+ backticks or tildes at the *start of a
|
|
1893
|
-
* line* (
|
|
1867
|
+
* line* (any indentation — container-relative limits are not modelled).
|
|
1868
|
+
* Mid-line runs are never fence openers. INDENTED code blocks (4+ spaces
|
|
1869
|
+
* after a blank line, outside any container) are NOT modelled: without a
|
|
1870
|
+
* container model they cannot be told from a list item's continuation
|
|
1871
|
+
* paragraph, and protecting them would silence math in nested lists.
|
|
1872
|
+
* Known limitation — `$` inside an indented code block may be rewritten.
|
|
1894
1873
|
* - inline code spans: a run of N backticks closed by another run of exactly
|
|
1895
1874
|
* N backticks. May span newlines. Multi-backtick forms (e.g. `` `` `x` ``)
|
|
1896
1875
|
* are supported so literal backtick characters can appear inside.
|
package/dist/index.dev.cjs
CHANGED
|
@@ -1149,6 +1149,8 @@ function rebaseDualWalk(node, segments, maxEnd, offsetDelta, lineDelta) {
|
|
|
1149
1149
|
for (const child of children) rebaseDualWalk(child, segments, maxEnd, offsetDelta, lineDelta);
|
|
1150
1150
|
}
|
|
1151
1151
|
}
|
|
1152
|
+
var TABLE_PART_TAG_RE = /<(?:td|th|tr|tbody|thead|tfoot|caption|col|colgroup)\b/i;
|
|
1153
|
+
var STRAY_SYNTHESIZED_END_TAG_RE = /<\/(?:br|p)\b/i;
|
|
1152
1154
|
function spliceTrees(input) {
|
|
1153
1155
|
const { prevMdast, prevHast, tailMdast, tailHast, content, boundary, injectionPrefix, injectedSegments } = input;
|
|
1154
1156
|
const injectedLen = injectionPrefix.length;
|
|
@@ -1205,6 +1207,12 @@ function spliceTrees(input) {
|
|
|
1205
1207
|
return !(start !== void 0 && start < injectedLen);
|
|
1206
1208
|
});
|
|
1207
1209
|
const tailWrapVisible = tailMdastChildren.some((child) => !isWrapInvisible(child));
|
|
1210
|
+
if (prefixMdast.some((c) => c.type === "html" && TABLE_PART_TAG_RE.test(c.value))) return null;
|
|
1211
|
+
for (const child of tailMdastChildren) {
|
|
1212
|
+
if (isWrapInvisible(child)) continue;
|
|
1213
|
+
if (child.type !== "html") break;
|
|
1214
|
+
if (STRAY_SYNTHESIZED_END_TAG_RE.test(child.value) || TABLE_PART_TAG_RE.test(child.value)) return null;
|
|
1215
|
+
}
|
|
1208
1216
|
const aligned = alignPrefixCut(prefixMdast, cutRegion, tailWrapVisible);
|
|
1209
1217
|
if (aligned === null) return null;
|
|
1210
1218
|
const hastChildren = aligned.children;
|
|
@@ -1330,6 +1338,9 @@ function alignPrefixCut(prefixMdast, cutRegion, tailWrapVisible) {
|
|
|
1330
1338
|
return null;
|
|
1331
1339
|
}
|
|
1332
1340
|
const lastIsLiteral = last !== void 0 && last.type === "text" && last.value.trim() !== "";
|
|
1341
|
+
if (lastIsLiteral && pairIdx >= 0 && visibles[pairIdx].type !== "html") {
|
|
1342
|
+
return null;
|
|
1343
|
+
}
|
|
1333
1344
|
const litOwnerEnd = pairIdx >= 0 ? visibles[pairIdx].position?.end?.offset : void 0;
|
|
1334
1345
|
const litEnd = lastIsLiteral ? last.position?.end?.offset : void 0;
|
|
1335
1346
|
if (lastIsLiteral && last.position !== void 0 && (litEnd === void 0 || litOwnerEnd === void 0)) {
|
|
@@ -1418,8 +1429,9 @@ function stripInjectedHast(tailMdast, tailHast, injectedLen, tailWrapVisible) {
|
|
|
1418
1429
|
}
|
|
1419
1430
|
function tailLeadingTextIsHoist(tailMdastChildren, tailHastChildren) {
|
|
1420
1431
|
const firstText = tailHastChildren[0];
|
|
1421
|
-
if (!firstText) return false;
|
|
1422
1432
|
const firstVisible = tailMdastChildren.find((c) => !isWrapInvisible(c));
|
|
1433
|
+
if (firstVisible?.type === "html" && STRAY_SYNTHESIZED_END_TAG_RE.test(firstVisible.value)) return null;
|
|
1434
|
+
if (!firstText) return false;
|
|
1423
1435
|
if (!isSeparatorText(firstText)) {
|
|
1424
1436
|
if (firstText.type === "text" && firstText.position === void 0 && firstVisible?.type === "html") {
|
|
1425
1437
|
if (/^\s*<\/[A-Za-z][A-Za-z0-9-]*\s*>/.test(firstVisible.value)) return true;
|
|
@@ -1860,17 +1872,8 @@ function phantomSuffixCloser(content) {
|
|
|
1860
1872
|
}
|
|
1861
1873
|
|
|
1862
1874
|
// src/components/extractContributions.ts
|
|
1863
|
-
function fakeAnchorElement(url) {
|
|
1864
|
-
return { type: "element", tagName: "a", properties: { href: url }, children: [] };
|
|
1865
|
-
}
|
|
1866
|
-
function sanitizeDefUrl(url, urlTransform) {
|
|
1867
|
-
if (!urlTransform) return url;
|
|
1868
|
-
const result = urlTransform(url, "href", fakeAnchorElement(url));
|
|
1869
|
-
return result == null ? "" : String(result);
|
|
1870
|
-
}
|
|
1871
1875
|
function* extractContributions(mdast, options = {}) {
|
|
1872
1876
|
const phantomFn = options.phantomFootnoteLabels;
|
|
1873
|
-
const urlTransform = options.urlTransform;
|
|
1874
1877
|
const out = [];
|
|
1875
1878
|
(0, import_unist_util_visit3.visit)(mdast, (n) => {
|
|
1876
1879
|
if (n.type === "footnoteReference") {
|
|
@@ -1898,7 +1901,7 @@ function* extractContributions(mdast, options = {}) {
|
|
|
1898
1901
|
out.push({
|
|
1899
1902
|
kind: "linkDef",
|
|
1900
1903
|
label: normalizeId(d.identifier),
|
|
1901
|
-
url:
|
|
1904
|
+
url: d.url,
|
|
1902
1905
|
title: d.title
|
|
1903
1906
|
});
|
|
1904
1907
|
}
|
|
@@ -3612,8 +3615,7 @@ function isProtocolAllowed(url, allowed) {
|
|
|
3612
3615
|
}
|
|
3613
3616
|
function sanitizeCrossChunkUrl(rawUrl, key, tagName, urlTransform, schema) {
|
|
3614
3617
|
rawUrl = (0, import_micromark_util_sanitize_uri2.normalizeUri)(rawUrl);
|
|
3615
|
-
const
|
|
3616
|
-
const allowed = callerProtocols === void 0 || callerProtocols === null ? sanitizeSchema.protocols?.[key] : callerProtocols[key];
|
|
3618
|
+
const allowed = Object.hasOwn(schema, "protocols") ? schema.protocols?.[key] : sanitizeSchema.protocols?.[key];
|
|
3617
3619
|
if (allowed && allowed.length > 0 && !isProtocolAllowed(rawUrl, allowed)) return null;
|
|
3618
3620
|
const transformed = urlTransform(rawUrl, key, fakeElement(tagName, key, rawUrl));
|
|
3619
3621
|
if (transformed == null) return null;
|
|
@@ -4023,15 +4025,14 @@ function lineHasBacktick(content, pos) {
|
|
|
4023
4025
|
}
|
|
4024
4026
|
return false;
|
|
4025
4027
|
}
|
|
4026
|
-
function
|
|
4028
|
+
function lineIndentBefore(content, pos) {
|
|
4027
4029
|
let i = pos - 1;
|
|
4028
|
-
let
|
|
4029
|
-
while (i >= 0 && content[i] === " ") {
|
|
4030
|
-
|
|
4031
|
-
if (spaces > 3) return false;
|
|
4030
|
+
let indent = 0;
|
|
4031
|
+
while (i >= 0 && (content[i] === " " || content[i] === " ")) {
|
|
4032
|
+
indent += content[i] === " " ? 4 : 1;
|
|
4032
4033
|
i--;
|
|
4033
4034
|
}
|
|
4034
|
-
return i < 0 || content[i] === "\n" || content[i] === "\r";
|
|
4035
|
+
return i < 0 || content[i] === "\n" || content[i] === "\r" ? indent : -1;
|
|
4035
4036
|
}
|
|
4036
4037
|
function findClosingBacktickRun(content, start, n) {
|
|
4037
4038
|
let i = start;
|
|
@@ -4052,6 +4053,7 @@ function splitByProtectedRegions(content) {
|
|
|
4052
4053
|
let multilineStart = -1;
|
|
4053
4054
|
let multilineFenceMarker = null;
|
|
4054
4055
|
let multilineFenceLength = 0;
|
|
4056
|
+
let multilineFenceIndent = 0;
|
|
4055
4057
|
function pushProtected(start, end) {
|
|
4056
4058
|
if (start > lastIndex) {
|
|
4057
4059
|
segments.push({ text: content.substring(lastIndex, start), isCode: false });
|
|
@@ -4065,7 +4067,8 @@ function splitByProtectedRegions(content) {
|
|
|
4065
4067
|
if (multilineStart !== -1) {
|
|
4066
4068
|
if (char === multilineFenceMarker) {
|
|
4067
4069
|
const runLen = getRepeatedMarkerLength(content, i, multilineFenceMarker);
|
|
4068
|
-
|
|
4070
|
+
const closerIndent = lineIndentBefore(content, i);
|
|
4071
|
+
if (runLen >= multilineFenceLength && closerIndent !== -1 && closerIndent <= multilineFenceIndent + 3 && restOfLineIsBlank(content, i + runLen)) {
|
|
4069
4072
|
pushProtected(multilineStart, i + runLen);
|
|
4070
4073
|
multilineStart = -1;
|
|
4071
4074
|
multilineFenceMarker = null;
|
|
@@ -4081,10 +4084,12 @@ function splitByProtectedRegions(content) {
|
|
|
4081
4084
|
}
|
|
4082
4085
|
if (char === "`" || char === "~") {
|
|
4083
4086
|
const runLen = getRepeatedMarkerLength(content, i, char);
|
|
4084
|
-
|
|
4087
|
+
const openerIndent = lineIndentBefore(content, i);
|
|
4088
|
+
if (runLen >= 3 && openerIndent !== -1 && !(char === "`" && lineHasBacktick(content, i + runLen))) {
|
|
4085
4089
|
multilineStart = i;
|
|
4086
4090
|
multilineFenceMarker = char;
|
|
4087
4091
|
multilineFenceLength = runLen;
|
|
4092
|
+
multilineFenceIndent = openerIndent;
|
|
4088
4093
|
i += runLen;
|
|
4089
4094
|
continue;
|
|
4090
4095
|
}
|