@wdprlib/parser 5.3.0 → 5.4.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/dist/index.cjs +2074 -1137
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2074 -1137
- package/package.json +3 -2
- package/src/build-info.generated.ts +2 -2
- package/src/lexer/lexer.ts +34 -5
- package/src/lexer/quoted-string.ts +4 -4
- package/src/lexer/syntax-actions.ts +6 -1
- package/src/lexer/text-actions.ts +15 -1
- package/src/lexer/url-schemes.ts +78 -0
- package/src/parser/constants.ts +4 -0
- package/src/parser/parse/block.ts +1 -1
- package/src/parser/postprocess/divAdjacentParagraph.ts +23 -21
- package/src/parser/postprocess/spanStrip/merge.ts +8 -2
- package/src/parser/preprocess/typography.ts +25 -3
- package/src/parser/preprocess/utils/raw-regions.ts +59 -14
- package/src/parser/preprocess/whitespace/index.ts +8 -1
- package/src/parser/rules/block/bibliography/entry-content.ts +1 -1
- package/src/parser/rules/block/block-list/bare-content.ts +3 -1
- package/src/parser/rules/block/block-list/bare-paragraph.ts +7 -2
- package/src/parser/rules/block/block-list/item-content.ts +7 -3
- package/src/parser/rules/block/block-list/li-content.ts +8 -3
- package/src/parser/rules/block/block-list/li-item.ts +1 -1
- package/src/parser/rules/block/blockquote/build.ts +1 -1
- package/src/parser/rules/block/code/boundary.ts +76 -0
- package/src/parser/rules/block/code/content.ts +11 -40
- package/src/parser/rules/block/code/index.ts +8 -31
- package/src/parser/rules/block/code/open.ts +46 -0
- package/src/parser/rules/block/definition-list/item-key.ts +1 -1
- package/src/parser/rules/block/definition-list/item-value.ts +1 -1
- package/src/parser/rules/block/div/failed.ts +2 -0
- package/src/parser/rules/block/index.ts +3 -0
- package/src/parser/rules/block/list/line.ts +6 -3
- package/src/parser/rules/block/math/boundary.ts +104 -0
- package/src/parser/rules/block/math/index.ts +17 -57
- package/src/parser/rules/block/note/boundary.ts +88 -0
- package/src/parser/rules/block/note/index.ts +37 -0
- package/src/parser/rules/block/paragraph/index.ts +12 -4
- package/src/parser/rules/block/paragraph/normalize.ts +6 -1
- package/src/parser/rules/block/parsing/block-item.ts +1 -1
- package/src/parser/rules/block/parsing/content.ts +1 -1
- package/src/parser/rules/block/parsing/inline-content.ts +6 -3
- package/src/parser/rules/block/table/pipe/cell.ts +3 -1
- package/src/parser/rules/block/table-block/cell-content/index.ts +1 -1
- package/src/parser/rules/block/table-block/cell-content/segments.ts +5 -2
- package/src/parser/rules/block/table-block/cell-newline.ts +2 -1
- package/src/parser/rules/contracts/rule.ts +4 -2
- package/src/parser/rules/contracts/scope.ts +2 -0
- package/src/parser/rules/inline/anchor/child.ts +8 -2
- package/src/parser/rules/inline/anchor/content.ts +3 -1
- package/src/parser/rules/inline/anchor/index.ts +4 -1
- package/src/parser/rules/inline/anchor/newline.ts +2 -1
- package/src/parser/rules/inline/autolink.ts +153 -0
- package/src/parser/rules/inline/button/attributes.ts +17 -0
- package/src/parser/rules/inline/button/index.ts +17 -0
- package/src/parser/rules/inline/button/syntax.ts +56 -0
- package/src/parser/rules/inline/date/index.ts +17 -0
- package/src/parser/rules/inline/date/syntax.ts +46 -0
- package/src/parser/rules/inline/email/candidates.ts +134 -0
- package/src/parser/rules/inline/email/index.ts +36 -0
- package/src/parser/rules/inline/email/scan.ts +76 -0
- package/src/parser/rules/inline/expr/branch.ts +3 -1
- package/src/parser/rules/inline/footnote/boundary.ts +56 -0
- package/src/parser/rules/inline/footnote/content.ts +29 -41
- package/src/parser/rules/inline/footnote/elements.ts +9 -34
- package/src/parser/rules/inline/footnote/index.ts +4 -1
- package/src/parser/rules/inline/formatting/close.ts +12 -0
- package/src/parser/rules/inline/index.ts +14 -0
- package/src/parser/rules/inline/line-break/newline.ts +8 -1
- package/src/parser/rules/inline/link-bracket/direct-url.ts +11 -3
- package/src/parser/rules/inline/link-bracket/parsed.ts +9 -4
- package/src/parser/rules/inline/link-bracket/parts.ts +14 -36
- package/src/parser/rules/inline/link-bracket/special-target.ts +9 -0
- package/src/parser/rules/inline/link-single.ts +9 -7
- package/src/parser/rules/inline/link-triple/index.ts +1 -0
- package/src/parser/rules/inline/link-triple/label.ts +7 -1
- package/src/parser/rules/inline/parsing/automatic-line-break.ts +35 -0
- package/src/parser/rules/inline/parsing/block-boundary.ts +2 -0
- package/src/parser/rules/inline/parsing/block-start-predicates.ts +10 -0
- package/src/parser/rules/inline/parsing/inline-content.ts +36 -6
- package/src/parser/rules/inline/parsing/plain-text.ts +7 -2
- package/src/parser/rules/inline/parsing/preserved-line-break.ts +13 -0
- package/src/parser/rules/inline/parsing/raw-tag.ts +19 -0
- package/src/parser/rules/inline/raw/angle.ts +2 -1
- package/src/parser/rules/inline/raw/end.ts +21 -1
- package/src/parser/rules/inline/size/content.ts +1 -1
- package/src/parser/rules/inline/size/value.ts +11 -0
- package/src/parser/rules/inline/social/index.ts +17 -0
- package/src/parser/rules/inline/social/syntax.ts +40 -0
- package/src/parser/rules/inline/span/content.ts +3 -1
- package/src/parser/rules/inline/span/newline.ts +2 -1
- package/src/parser/rules/opaque-probe.ts +58 -0
- package/src/parser/rules/block/math/content.ts +0 -54
- package/src/parser/rules/block/math/name.ts +0 -35
- package/src/parser/rules/inline/footnote/child.ts +0 -22
- package/src/parser/rules/inline/footnote/newline.ts +0 -27
package/dist/index.cjs
CHANGED
|
@@ -82,8 +82,8 @@ module.exports = __toCommonJS(exports_src);
|
|
|
82
82
|
|
|
83
83
|
// packages/parser/src/build-info.generated.ts
|
|
84
84
|
var buildInfo = Object.freeze({
|
|
85
|
-
version: "5.
|
|
86
|
-
sha: "
|
|
85
|
+
version: "5.4.0",
|
|
86
|
+
sha: "5e221ddeccc585e64dd1a2eb49b14817c3c1be5d",
|
|
87
87
|
dirty: false
|
|
88
88
|
});
|
|
89
89
|
|
|
@@ -272,13 +272,13 @@ function isValidAnchorNameChar(code) {
|
|
|
272
272
|
}
|
|
273
273
|
|
|
274
274
|
// packages/parser/src/lexer/quoted-string.ts
|
|
275
|
-
function scanQuotedString(state) {
|
|
275
|
+
function scanQuotedString(state, end = state.source.length) {
|
|
276
276
|
let quoted = advance(state);
|
|
277
|
-
while (
|
|
277
|
+
while (state.pos < end && current(state) !== '"' && current(state) !== `
|
|
278
278
|
`) {
|
|
279
279
|
quoted += advance(state);
|
|
280
280
|
}
|
|
281
|
-
if (current(state) === '"') {
|
|
281
|
+
if (state.pos < end && current(state) === '"') {
|
|
282
282
|
quoted += advance(state);
|
|
283
283
|
}
|
|
284
284
|
return quoted;
|
|
@@ -363,6 +363,26 @@ function isCompactPlainTextBoundary(code) {
|
|
|
363
363
|
}
|
|
364
364
|
}
|
|
365
365
|
|
|
366
|
+
// packages/parser/src/lexer/url-schemes.ts
|
|
367
|
+
var URL_SCHEME_NAMES = new Set([
|
|
368
|
+
"http",
|
|
369
|
+
"https",
|
|
370
|
+
"ftp",
|
|
371
|
+
"gopher",
|
|
372
|
+
"news",
|
|
373
|
+
"mailto",
|
|
374
|
+
"mms"
|
|
375
|
+
]);
|
|
376
|
+
var TRAILING_URL_SCHEME = /(?:^|[^A-Za-z0-9])(https?|ftp|gopher|news|mailto|mms)$/;
|
|
377
|
+
var URL_SCHEME_PREFIX = /^(?:(?:https?|ftp|gopher|news|mms):\/\/|mailto:)/;
|
|
378
|
+
var URL_PATTERN = /^(?:(?:https?|ftp|gopher|news|mms):\/\/|mailto:)(?:[^ \\/"']*\/)*[^ \t\n\\/"']*[A-Za-z%0-9/?=&~_]/;
|
|
379
|
+
function startsWithUrlScheme(src, pos) {
|
|
380
|
+
return URL_SCHEME_PREFIX.test(src.slice(pos, pos + 10));
|
|
381
|
+
}
|
|
382
|
+
function startsWithUrl(src, pos) {
|
|
383
|
+
return URL_PATTERN.test(src.slice(pos, pos + 2048));
|
|
384
|
+
}
|
|
385
|
+
|
|
366
386
|
// packages/parser/src/lexer/syntax-actions.ts
|
|
367
387
|
function scanSimpleSyntaxToken(src, pos, isLineStart) {
|
|
368
388
|
switch (src[pos]) {
|
|
@@ -399,7 +419,7 @@ function scanSimpleSyntaxToken(src, pos, isLineStart) {
|
|
|
399
419
|
}
|
|
400
420
|
}
|
|
401
421
|
function scanStarToken(src, pos, isLineStart) {
|
|
402
|
-
if (src[pos + 1] === "*") {
|
|
422
|
+
if (src[pos + 1] === "*" && !startsWithUrl(src, pos + 2)) {
|
|
403
423
|
return token("BOLD_MARKER", "**");
|
|
404
424
|
}
|
|
405
425
|
return isLineStart ? token("LIST_BULLET", "*") : token("STAR", "*");
|
|
@@ -585,7 +605,13 @@ function scanTextToken(src, pos) {
|
|
|
585
605
|
return token3("TEXT", char);
|
|
586
606
|
}
|
|
587
607
|
function scanCompactTextToken(src, pos) {
|
|
588
|
-
|
|
608
|
+
let end = findCompactPlainTextRunEnd(src, pos);
|
|
609
|
+
if (end > pos && src[end] === ":") {
|
|
610
|
+
const match = TRAILING_URL_SCHEME.exec(src.slice(pos, end));
|
|
611
|
+
if (match) {
|
|
612
|
+
end -= match[1].length;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
589
615
|
return end > pos ? runToken3(src, pos, end, "TEXT") : null;
|
|
590
616
|
}
|
|
591
617
|
function token3(type, value) {
|
|
@@ -631,6 +657,8 @@ class Lexer {
|
|
|
631
657
|
splitBlockClosePositions = new Set;
|
|
632
658
|
lastNonWhitespaceType = null;
|
|
633
659
|
blockOpenerDepth = 0;
|
|
660
|
+
rawTagBounds = null;
|
|
661
|
+
rawClosesExhausted = false;
|
|
634
662
|
constructor(source, options = {}) {
|
|
635
663
|
this.options = {
|
|
636
664
|
trackPositions: options.trackPositions ?? true,
|
|
@@ -651,8 +679,8 @@ class Lexer {
|
|
|
651
679
|
current() {
|
|
652
680
|
return current(this.state);
|
|
653
681
|
}
|
|
654
|
-
findInvalidAnchorNameEnd() {
|
|
655
|
-
return findInvalidAnchorNameEnd(
|
|
682
|
+
findInvalidAnchorNameEnd(source) {
|
|
683
|
+
return findInvalidAnchorNameEnd(source, this.state.pos);
|
|
656
684
|
}
|
|
657
685
|
advance(n = 1) {
|
|
658
686
|
return advance(this.state, n);
|
|
@@ -664,6 +692,18 @@ class Lexer {
|
|
|
664
692
|
this.state.tokens.push(createLexerToken(this.state, type, value, this.options.trackPositions));
|
|
665
693
|
this.lastNonWhitespaceType = updateLastNonWhitespaceType(this.lastNonWhitespaceType, type);
|
|
666
694
|
this.blockOpenerDepth = nextBlockOpenerDepth(this.blockOpenerDepth, type);
|
|
695
|
+
if (this.rawTagBounds === null && !this.rawClosesExhausted && (value.toLowerCase() === "button" || value.toLowerCase() === "social") && this.state.tokens.at(-2)?.type === "BLOCK_OPEN" && /\s/.test(this.current())) {
|
|
696
|
+
const close = this.state.source.indexOf("]]", this.state.pos);
|
|
697
|
+
if (close < 0) {
|
|
698
|
+
this.rawClosesExhausted = true;
|
|
699
|
+
} else {
|
|
700
|
+
this.rawTagBounds = {
|
|
701
|
+
source: this.state.source.slice(0, close),
|
|
702
|
+
close,
|
|
703
|
+
outerDepth: this.blockOpenerDepth - 1
|
|
704
|
+
};
|
|
705
|
+
}
|
|
706
|
+
}
|
|
667
707
|
}
|
|
668
708
|
emitTokenAction(action) {
|
|
669
709
|
advanceByToken(this.state, action.type, action.length, action.value);
|
|
@@ -681,7 +721,14 @@ class Lexer {
|
|
|
681
721
|
scanToken() {
|
|
682
722
|
const char = this.current();
|
|
683
723
|
const isLineStart = isSyntaxLineStart(this.state);
|
|
684
|
-
const
|
|
724
|
+
const bounds = this.rawTagBounds;
|
|
725
|
+
const src = bounds?.source ?? this.state.source;
|
|
726
|
+
if (bounds && this.state.pos === bounds.close) {
|
|
727
|
+
this.emitTokenAction({ type: "BLOCK_CLOSE", value: "]]", length: 2 });
|
|
728
|
+
this.blockOpenerDepth = bounds.outerDepth;
|
|
729
|
+
this.rawTagBounds = null;
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
685
732
|
const spacingAction = scanSpacingToken(src, this.state.pos);
|
|
686
733
|
if (spacingAction) {
|
|
687
734
|
this.emitTokenAction(limitBlockquotePrefixSpace(spacingAction, this.state.tokens.at(-1)));
|
|
@@ -694,7 +741,7 @@ class Lexer {
|
|
|
694
741
|
lineStart: isLineStart,
|
|
695
742
|
physicalLineStart: this.state.lineStart,
|
|
696
743
|
splitBlockClose: this.splitBlockClosePositions.has(this.state.pos),
|
|
697
|
-
findInvalidAnchorNameEnd: () => this.findInvalidAnchorNameEnd()
|
|
744
|
+
findInvalidAnchorNameEnd: () => this.findInvalidAnchorNameEnd(src)
|
|
698
745
|
});
|
|
699
746
|
if (punctuation.handled) {
|
|
700
747
|
if (punctuation.clearSplitBlockCloseAt !== undefined) {
|
|
@@ -709,7 +756,7 @@ class Lexer {
|
|
|
709
756
|
if (char === '"') {
|
|
710
757
|
const lastNonWs = this.lastNonWhitespaceTokenType();
|
|
711
758
|
if (this.blockOpenerDepth > 0 && lastNonWs === "EQUALS") {
|
|
712
|
-
this.addToken("QUOTED_STRING", scanQuotedString(this.state));
|
|
759
|
+
this.addToken("QUOTED_STRING", scanQuotedString(this.state, src.length));
|
|
713
760
|
return;
|
|
714
761
|
}
|
|
715
762
|
this.advance();
|
|
@@ -897,7 +944,7 @@ function parseBlockItem(ctx) {
|
|
|
897
944
|
}
|
|
898
945
|
}
|
|
899
946
|
const fallback = ctx.blockFallbackRule.parse(ctx);
|
|
900
|
-
if (fallback.success
|
|
947
|
+
if (fallback.success) {
|
|
901
948
|
return { elements: fallback.elements, consumed: fallback.consumed };
|
|
902
949
|
}
|
|
903
950
|
return { elements: [], consumed: 1 };
|
|
@@ -945,7 +992,8 @@ function parseBlocksUntil(ctx, closeCondition, options) {
|
|
|
945
992
|
blockCtx.pos = pos;
|
|
946
993
|
blockCtx.scope = blockScope;
|
|
947
994
|
const result = parseBlockItem(blockCtx);
|
|
948
|
-
|
|
995
|
+
for (const element of result.elements)
|
|
996
|
+
elements.push(element);
|
|
949
997
|
consumed += result.consumed;
|
|
950
998
|
pos += result.consumed;
|
|
951
999
|
}
|
|
@@ -972,6 +1020,42 @@ function getExcludedBlockRules(blockRules, excluded) {
|
|
|
972
1020
|
byExcluded.set(excluded, filtered);
|
|
973
1021
|
return filtered;
|
|
974
1022
|
}
|
|
1023
|
+
// packages/parser/src/parser/rules/inline/parsing/automatic-line-break.ts
|
|
1024
|
+
var origins = new WeakMap;
|
|
1025
|
+
function createAutomaticLineBreak(token5) {
|
|
1026
|
+
const element = { element: "line-break" };
|
|
1027
|
+
origins.set(element, token5);
|
|
1028
|
+
return element;
|
|
1029
|
+
}
|
|
1030
|
+
function precedingSingleNewline(ctx) {
|
|
1031
|
+
let pos = ctx.pos - 1;
|
|
1032
|
+
while (ctx.tokens[pos]?.type === "WHITESPACE")
|
|
1033
|
+
pos--;
|
|
1034
|
+
const newline = ctx.tokens[pos];
|
|
1035
|
+
if (newline?.type !== "NEWLINE")
|
|
1036
|
+
return;
|
|
1037
|
+
pos--;
|
|
1038
|
+
while (ctx.tokens[pos]?.type === "WHITESPACE")
|
|
1039
|
+
pos--;
|
|
1040
|
+
if (ctx.tokens[pos]?.type === "NEWLINE")
|
|
1041
|
+
return;
|
|
1042
|
+
return newline;
|
|
1043
|
+
}
|
|
1044
|
+
function stripAutomaticLineBreak(elements, token5) {
|
|
1045
|
+
if (!token5)
|
|
1046
|
+
return;
|
|
1047
|
+
let index = elements.length - 1;
|
|
1048
|
+
while (index >= 0) {
|
|
1049
|
+
const element2 = elements[index];
|
|
1050
|
+
if (element2?.element !== "text" || !/^[ \t]*$/.test(element2.data))
|
|
1051
|
+
break;
|
|
1052
|
+
index--;
|
|
1053
|
+
}
|
|
1054
|
+
const element = elements[index];
|
|
1055
|
+
if (element && origins.get(element) === token5)
|
|
1056
|
+
elements.length = index;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
975
1059
|
// packages/parser/src/parser/rules/inline/parsing/rules.ts
|
|
976
1060
|
function canApplyInlineRule(rule, token5) {
|
|
977
1061
|
if (rule.startTokens.length === 0) {
|
|
@@ -994,18 +1078,479 @@ function getCandidateInlineRules(inlineRules, tokenType) {
|
|
|
994
1078
|
byType.set(tokenType, candidates);
|
|
995
1079
|
return candidates;
|
|
996
1080
|
}
|
|
1081
|
+
// packages/parser/src/parser/rules/inline/parsing/raw-tag.ts
|
|
1082
|
+
var unclosedRanges = new WeakMap;
|
|
1083
|
+
function findRawTagClose(tokens, start, end) {
|
|
1084
|
+
const unclosed = unclosedRanges.get(tokens);
|
|
1085
|
+
if (unclosed && start >= unclosed.start && end <= unclosed.end)
|
|
1086
|
+
return null;
|
|
1087
|
+
for (let close = start;close < end; close++) {
|
|
1088
|
+
if (tokens[close]?.type === "BLOCK_CLOSE")
|
|
1089
|
+
return close;
|
|
1090
|
+
if (!tokens[close] || tokens[close]?.type === "EOF")
|
|
1091
|
+
break;
|
|
1092
|
+
}
|
|
1093
|
+
unclosedRanges.set(tokens, { start, end });
|
|
1094
|
+
return null;
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
// packages/parser/src/parser/rules/inline/button/attributes.ts
|
|
1098
|
+
function parseButtonAttributes(source) {
|
|
1099
|
+
const sections = source.trim().split('="');
|
|
1100
|
+
const attrs = {};
|
|
1101
|
+
let key = sections[0].trim();
|
|
1102
|
+
for (const section of sections.slice(1)) {
|
|
1103
|
+
const quote = section.lastIndexOf('"');
|
|
1104
|
+
if (quote < 0)
|
|
1105
|
+
continue;
|
|
1106
|
+
if (key === "text" || key === "class" || key === "style") {
|
|
1107
|
+
attrs[key] = section.slice(0, quote).replace(/\\([\s\S]|$)/g, (_match, char) => char === "0" ? "\x00" : char);
|
|
1108
|
+
}
|
|
1109
|
+
key = section.slice(quote + 1).trim();
|
|
1110
|
+
}
|
|
1111
|
+
return attrs;
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
// packages/parser/src/parser/rules/inline/button/syntax.ts
|
|
1115
|
+
function parseButtonSyntax(ctx, start, end) {
|
|
1116
|
+
const tokens = ctx.tokens;
|
|
1117
|
+
if (tokens[start]?.type !== "BLOCK_OPEN" || tokens[start + 1]?.value.toLowerCase() !== "button")
|
|
1118
|
+
return null;
|
|
1119
|
+
let pos = start + 2;
|
|
1120
|
+
const skipSpace = () => {
|
|
1121
|
+
const before = pos;
|
|
1122
|
+
while (pos < end && /^\s+$/.test(tokens[pos]?.value ?? ""))
|
|
1123
|
+
pos++;
|
|
1124
|
+
return pos > before;
|
|
1125
|
+
};
|
|
1126
|
+
if (!skipSpace())
|
|
1127
|
+
return null;
|
|
1128
|
+
let action = "";
|
|
1129
|
+
while (pos < end && tokens[pos]?.type !== "BLOCK_CLOSE" && !/^\s+$/.test(tokens[pos]?.value ?? "")) {
|
|
1130
|
+
const part = tokens[pos]?.value ?? "";
|
|
1131
|
+
if (!/^[a-z0-9_-]+$/i.test(part))
|
|
1132
|
+
return null;
|
|
1133
|
+
action += part;
|
|
1134
|
+
pos++;
|
|
1135
|
+
}
|
|
1136
|
+
if (!action)
|
|
1137
|
+
return null;
|
|
1138
|
+
action = action.replaceAll("_", "-");
|
|
1139
|
+
skipSpace();
|
|
1140
|
+
const close = findRawTagClose(tokens, pos, end);
|
|
1141
|
+
if (close === null)
|
|
1142
|
+
return null;
|
|
1143
|
+
const attrs = parseButtonAttributes(tokens.slice(pos, close).map((token5) => token5.value).join(""));
|
|
1144
|
+
const value = (key) => attrs[key] && attrs[key] !== "0" ? attrs[key] : null;
|
|
1145
|
+
const attributes = {};
|
|
1146
|
+
for (const name of ["class", "style"]) {
|
|
1147
|
+
const attr = value(name);
|
|
1148
|
+
if (attr !== null)
|
|
1149
|
+
attributes[name] = attr;
|
|
1150
|
+
}
|
|
1151
|
+
return { data: { action, text: value("text"), attributes }, end: close + 1 };
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
// packages/parser/src/parser/rules/inline/social/syntax.ts
|
|
1155
|
+
var invalidBodies = new WeakMap;
|
|
1156
|
+
function parseSocialSyntax(ctx, start, end) {
|
|
1157
|
+
const tokens = ctx.tokens;
|
|
1158
|
+
if (tokens[start]?.type !== "BLOCK_OPEN" || tokens[start + 1]?.value.toLowerCase() !== "social")
|
|
1159
|
+
return null;
|
|
1160
|
+
const bodyStart = start + 2;
|
|
1161
|
+
if (tokens[bodyStart]?.type !== "BLOCK_CLOSE" && !/^\s+$/.test(tokens[bodyStart]?.value ?? ""))
|
|
1162
|
+
return null;
|
|
1163
|
+
const invalid = invalidBodies.get(tokens);
|
|
1164
|
+
if (invalid && bodyStart >= invalid.start && bodyStart <= invalid.bracket)
|
|
1165
|
+
return null;
|
|
1166
|
+
const close = findRawTagClose(tokens, bodyStart, end);
|
|
1167
|
+
if (close === null)
|
|
1168
|
+
return null;
|
|
1169
|
+
for (let pos = bodyStart;pos < close; pos++) {
|
|
1170
|
+
if (tokens[pos].value.includes("]")) {
|
|
1171
|
+
invalidBodies.set(tokens, { start: bodyStart, bracket: pos });
|
|
1172
|
+
return null;
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
const body = tokens.slice(bodyStart, close).map((token5) => token5.value).join("");
|
|
1176
|
+
const sites = body.trim() ? body.split(",").map((site) => site.trim().toLowerCase()).filter(Boolean) : null;
|
|
1177
|
+
return { data: { sites }, end: close + 1 };
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
// packages/parser/src/parser/rules/block/parsing/attributes/names.ts
|
|
1181
|
+
function consumeAttributeName(ctx, startPos, startConsumed, startName, options) {
|
|
1182
|
+
if (startName === "_" && isAttributeWordToken(ctx.tokens[startPos])) {
|
|
1183
|
+
startName += ctx.tokens[startPos]?.value ?? "";
|
|
1184
|
+
startPos++;
|
|
1185
|
+
startConsumed++;
|
|
1186
|
+
}
|
|
1187
|
+
return options.strikeHyphens ? consumeRawNameSuffix(ctx, startPos, startConsumed, startName, options.hyphenatedNames) : consumeSafeNameSuffix(ctx, startPos, startConsumed, startName);
|
|
1188
|
+
}
|
|
1189
|
+
function isAttributeNameToken(token5) {
|
|
1190
|
+
return isAttributeWordToken(token5) || token5?.type === "UNDERSCORE";
|
|
1191
|
+
}
|
|
1192
|
+
function consumeSafeNameSuffix(ctx, startPos, startConsumed, startName) {
|
|
1193
|
+
let name = startName;
|
|
1194
|
+
let pos = startPos;
|
|
1195
|
+
let consumed = startConsumed;
|
|
1196
|
+
while (isAttributeNameSeparator(ctx.tokens[pos]) && isAttributeWordToken(ctx.tokens[pos + 1])) {
|
|
1197
|
+
name += ctx.tokens[pos]?.value ?? "";
|
|
1198
|
+
pos++;
|
|
1199
|
+
consumed++;
|
|
1200
|
+
name += ctx.tokens[pos]?.value ?? "";
|
|
1201
|
+
pos++;
|
|
1202
|
+
consumed++;
|
|
1203
|
+
}
|
|
1204
|
+
return { name, pos, consumed };
|
|
1205
|
+
}
|
|
1206
|
+
function consumeRawNameSuffix(ctx, startPos, startConsumed, startName, hyphenatedNames) {
|
|
1207
|
+
let name = startName;
|
|
1208
|
+
let pos = startPos;
|
|
1209
|
+
let consumed = startConsumed;
|
|
1210
|
+
while (isAttributeNameSeparator(ctx.tokens[pos])) {
|
|
1211
|
+
while (isAttributeNameSeparator(ctx.tokens[pos])) {
|
|
1212
|
+
if (hyphenatedNames || ctx.tokens[pos]?.type === "UNDERSCORE") {
|
|
1213
|
+
name += ctx.tokens[pos]?.value ?? "-";
|
|
1214
|
+
}
|
|
1215
|
+
pos++;
|
|
1216
|
+
consumed++;
|
|
1217
|
+
}
|
|
1218
|
+
if (!isAttributeWordToken(ctx.tokens[pos])) {
|
|
1219
|
+
break;
|
|
1220
|
+
}
|
|
1221
|
+
if (hyphenatedNames || name.endsWith("_")) {
|
|
1222
|
+
name += ctx.tokens[pos]?.value ?? "";
|
|
1223
|
+
}
|
|
1224
|
+
pos++;
|
|
1225
|
+
consumed++;
|
|
1226
|
+
}
|
|
1227
|
+
return { name, pos, consumed };
|
|
1228
|
+
}
|
|
1229
|
+
function isAttributeWordToken(token5) {
|
|
1230
|
+
return token5?.type === "TEXT" || token5?.type === "IDENTIFIER";
|
|
1231
|
+
}
|
|
1232
|
+
function isAttributeNameSeparator(token5) {
|
|
1233
|
+
return token5?.type === "TEXT" && token5.value === "-" || token5?.type === "STRIKE_MARKER" || token5?.type === "UNDERSCORE";
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
// packages/parser/src/parser/rules/block/parsing/attributes/values.ts
|
|
1237
|
+
function consumeAttributeValue(token5) {
|
|
1238
|
+
if (!token5) {
|
|
1239
|
+
return null;
|
|
1240
|
+
}
|
|
1241
|
+
if (token5.type === "QUOTED_STRING") {
|
|
1242
|
+
return { value: stripQuotes(token5.value) };
|
|
1243
|
+
}
|
|
1244
|
+
if (isAttributeNameToken(token5)) {
|
|
1245
|
+
return { value: token5.value };
|
|
1246
|
+
}
|
|
1247
|
+
return null;
|
|
1248
|
+
}
|
|
1249
|
+
function stripQuotes(value) {
|
|
1250
|
+
return value.startsWith('"') && value.endsWith('"') ? value.slice(1, -1) : value;
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
// packages/parser/src/parser/rules/block/parsing/attributes/scanner.ts
|
|
1254
|
+
function scanAttributes(ctx, startPos, options) {
|
|
1255
|
+
const attrs = {};
|
|
1256
|
+
let pos = startPos;
|
|
1257
|
+
let consumed = 0;
|
|
1258
|
+
while (pos < ctx.tokens.length) {
|
|
1259
|
+
const token5 = ctx.tokens[pos];
|
|
1260
|
+
if (!token5 || isAttributeTerminator(token5)) {
|
|
1261
|
+
break;
|
|
1262
|
+
}
|
|
1263
|
+
if (token5.type === "WHITESPACE") {
|
|
1264
|
+
pos++;
|
|
1265
|
+
consumed++;
|
|
1266
|
+
continue;
|
|
1267
|
+
}
|
|
1268
|
+
if (!isAttributeNameToken(token5)) {
|
|
1269
|
+
pos++;
|
|
1270
|
+
consumed++;
|
|
1271
|
+
continue;
|
|
1272
|
+
}
|
|
1273
|
+
let name = token5.value;
|
|
1274
|
+
pos++;
|
|
1275
|
+
consumed++;
|
|
1276
|
+
const nameResult = consumeAttributeName(ctx, pos, consumed, name, options);
|
|
1277
|
+
pos = nameResult.pos;
|
|
1278
|
+
consumed = nameResult.consumed;
|
|
1279
|
+
name = nameResult.name.toLowerCase();
|
|
1280
|
+
if (ctx.tokens[pos]?.type !== "EQUALS") {
|
|
1281
|
+
attrs[name] = "true";
|
|
1282
|
+
continue;
|
|
1283
|
+
}
|
|
1284
|
+
pos++;
|
|
1285
|
+
consumed++;
|
|
1286
|
+
const valueResult = consumeAttributeValue(ctx.tokens[pos]);
|
|
1287
|
+
if (!valueResult) {
|
|
1288
|
+
continue;
|
|
1289
|
+
}
|
|
1290
|
+
attrs[name] = valueResult.value;
|
|
1291
|
+
pos++;
|
|
1292
|
+
consumed++;
|
|
1293
|
+
}
|
|
1294
|
+
return { attrs, consumed };
|
|
1295
|
+
}
|
|
1296
|
+
function isAttributeTerminator(token5) {
|
|
1297
|
+
return token5.type === "BLOCK_CLOSE" || token5.type === "NEWLINE" || token5.type === "EOF";
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
// packages/parser/src/parser/rules/block/parsing/attributes/index.ts
|
|
1301
|
+
function parseAttributes(ctx, startPos) {
|
|
1302
|
+
const result = scanAttributes(ctx, startPos, { hyphenatedNames: true, strikeHyphens: false });
|
|
1303
|
+
return { attrs: filterUnsafeAttributes(result.attrs), consumed: result.consumed };
|
|
1304
|
+
}
|
|
1305
|
+
function parseAttributesRaw(ctx, startPos, hyphenatedNames = true) {
|
|
1306
|
+
return scanAttributes(ctx, startPos, { hyphenatedNames, strikeHyphens: true });
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
// packages/parser/src/parser/rules/inline/date/syntax.ts
|
|
1310
|
+
function parseDateSyntax(ctx, start, end) {
|
|
1311
|
+
const tokens = ctx.tokens;
|
|
1312
|
+
if (tokens[start]?.type !== "BLOCK_OPEN" || tokens[start + 1]?.value !== "date")
|
|
1313
|
+
return null;
|
|
1314
|
+
let pos = start + 2;
|
|
1315
|
+
const skipSpace = () => {
|
|
1316
|
+
const before = pos;
|
|
1317
|
+
while (pos < end && /^(?:\s+)$/.test(tokens[pos]?.value ?? ""))
|
|
1318
|
+
pos++;
|
|
1319
|
+
return pos > before;
|
|
1320
|
+
};
|
|
1321
|
+
if (!skipSpace())
|
|
1322
|
+
return null;
|
|
1323
|
+
const value = tokens[pos]?.value ?? "";
|
|
1324
|
+
if (pos >= end || !/^\d+$/.test(value))
|
|
1325
|
+
return null;
|
|
1326
|
+
const timestamp = Number(value);
|
|
1327
|
+
if (!Number.isSafeInteger(timestamp) || timestamp > 8640000000000)
|
|
1328
|
+
return null;
|
|
1329
|
+
pos++;
|
|
1330
|
+
const separator = skipSpace();
|
|
1331
|
+
if (tokens[pos]?.type !== "BLOCK_CLOSE" && !separator)
|
|
1332
|
+
return null;
|
|
1333
|
+
let close = pos;
|
|
1334
|
+
for (;close < end; close++) {
|
|
1335
|
+
const token5 = tokens[close];
|
|
1336
|
+
if (!token5 || token5.type === "EOF" || token5.type === "BLOCK_OPEN" || /[\r\n]/.test(token5.value))
|
|
1337
|
+
return null;
|
|
1338
|
+
if (token5.type === "BLOCK_CLOSE")
|
|
1339
|
+
break;
|
|
1340
|
+
}
|
|
1341
|
+
if (close >= end)
|
|
1342
|
+
return null;
|
|
1343
|
+
const attributes = parseAttributesRaw(ctx, pos).attrs;
|
|
1344
|
+
const format = attributes.format || null;
|
|
1345
|
+
return {
|
|
1346
|
+
data: {
|
|
1347
|
+
value: { timestamp, timezone: "UTC" },
|
|
1348
|
+
format,
|
|
1349
|
+
hover: format?.split("|").slice(1).includes("agohover") ?? false
|
|
1350
|
+
},
|
|
1351
|
+
end: close + 1
|
|
1352
|
+
};
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
// packages/parser/src/parser/rules/inline/email/scan.ts
|
|
1356
|
+
function isDomainChar(code) {
|
|
1357
|
+
return code >= 48 && code <= 57 || code >= 65 && code <= 90 || code >= 97 && code <= 122 || code === 45;
|
|
1358
|
+
}
|
|
1359
|
+
function isLocalChar(code) {
|
|
1360
|
+
return isDomainChar(code) || code === 95;
|
|
1361
|
+
}
|
|
1362
|
+
function scanEmail(source, start, commentEnd) {
|
|
1363
|
+
const comments = [];
|
|
1364
|
+
let pos = start;
|
|
1365
|
+
const skipComments = () => {
|
|
1366
|
+
let end2 = commentEnd(pos);
|
|
1367
|
+
while (end2 > pos) {
|
|
1368
|
+
comments.push({ start: pos, end: end2 });
|
|
1369
|
+
pos = end2;
|
|
1370
|
+
end2 = commentEnd(pos);
|
|
1371
|
+
}
|
|
1372
|
+
};
|
|
1373
|
+
let localPart = false;
|
|
1374
|
+
while (pos < source.length) {
|
|
1375
|
+
skipComments();
|
|
1376
|
+
if (isLocalChar(source.charCodeAt(pos))) {
|
|
1377
|
+
localPart = true;
|
|
1378
|
+
pos++;
|
|
1379
|
+
} else if (source[pos] === "." && localPart) {
|
|
1380
|
+
localPart = false;
|
|
1381
|
+
pos++;
|
|
1382
|
+
} else
|
|
1383
|
+
break;
|
|
1384
|
+
}
|
|
1385
|
+
const localEnd = pos;
|
|
1386
|
+
if (!localPart || source[pos] !== "@")
|
|
1387
|
+
return { localEnd, comments };
|
|
1388
|
+
pos++;
|
|
1389
|
+
let domainPart = false;
|
|
1390
|
+
let dots = 0;
|
|
1391
|
+
let end = -1;
|
|
1392
|
+
while (pos < source.length) {
|
|
1393
|
+
skipComments();
|
|
1394
|
+
if (isDomainChar(source.charCodeAt(pos))) {
|
|
1395
|
+
domainPart = true;
|
|
1396
|
+
pos++;
|
|
1397
|
+
if (dots > 0)
|
|
1398
|
+
end = pos;
|
|
1399
|
+
} else if (source[pos] === "." && domainPart) {
|
|
1400
|
+
domainPart = false;
|
|
1401
|
+
dots++;
|
|
1402
|
+
pos++;
|
|
1403
|
+
} else
|
|
1404
|
+
break;
|
|
1405
|
+
}
|
|
1406
|
+
if (end === -1)
|
|
1407
|
+
return { localEnd, comments };
|
|
1408
|
+
const parts = [];
|
|
1409
|
+
let copied = start;
|
|
1410
|
+
for (const comment of comments) {
|
|
1411
|
+
if (comment.start >= end)
|
|
1412
|
+
break;
|
|
1413
|
+
parts.push(source.slice(copied, comment.start));
|
|
1414
|
+
copied = comment.end;
|
|
1415
|
+
}
|
|
1416
|
+
parts.push(source.slice(copied, end));
|
|
1417
|
+
return { end, address: parts.join(""), localEnd, comments };
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
// packages/parser/src/parser/rules/inline/email/candidates.ts
|
|
1421
|
+
var caches = new WeakMap;
|
|
1422
|
+
var EMAIL_START_TOKENS = [
|
|
1423
|
+
"TEXT",
|
|
1424
|
+
"IDENTIFIER",
|
|
1425
|
+
"UNDERSCORE",
|
|
1426
|
+
"UNDERLINE_MARKER",
|
|
1427
|
+
"STRIKE_MARKER"
|
|
1428
|
+
];
|
|
1429
|
+
function getCache(tokens) {
|
|
1430
|
+
let cache = caches.get(tokens);
|
|
1431
|
+
if (cache)
|
|
1432
|
+
return cache;
|
|
1433
|
+
const offsets = [0];
|
|
1434
|
+
const values = [];
|
|
1435
|
+
for (const token5 of tokens) {
|
|
1436
|
+
values.push(token5.value);
|
|
1437
|
+
offsets.push(offsets.at(-1) + token5.value.length);
|
|
1438
|
+
}
|
|
1439
|
+
cache = {
|
|
1440
|
+
source: values.join(""),
|
|
1441
|
+
offsets,
|
|
1442
|
+
candidates: new Map,
|
|
1443
|
+
commentEnds: new Map,
|
|
1444
|
+
unclosedComment: Infinity
|
|
1445
|
+
};
|
|
1446
|
+
caches.set(tokens, cache);
|
|
1447
|
+
return cache;
|
|
1448
|
+
}
|
|
1449
|
+
function commentEnd(cache, pos) {
|
|
1450
|
+
const opener = cache.source[pos] === `
|
|
1451
|
+
` ? pos + 1 : pos;
|
|
1452
|
+
if (!cache.source.startsWith("[!--", opener))
|
|
1453
|
+
return pos;
|
|
1454
|
+
const cached = cache.commentEnds.get(pos);
|
|
1455
|
+
if (cached !== undefined)
|
|
1456
|
+
return cached;
|
|
1457
|
+
const close = opener >= cache.unclosedComment ? -1 : cache.source.indexOf("--]", opener + 4);
|
|
1458
|
+
if (close === -1)
|
|
1459
|
+
cache.unclosedComment = Math.min(cache.unclosedComment, opener);
|
|
1460
|
+
const end = close === -1 ? pos : close + 3;
|
|
1461
|
+
cache.commentEnds.set(pos, end);
|
|
1462
|
+
return end;
|
|
1463
|
+
}
|
|
1464
|
+
function getEmailCandidate(tokens, index) {
|
|
1465
|
+
const token5 = tokens[index];
|
|
1466
|
+
if (!token5 || !EMAIL_START_TOKENS.includes(token5.type))
|
|
1467
|
+
return null;
|
|
1468
|
+
const cache = getCache(tokens);
|
|
1469
|
+
if (cache.candidates.has(index))
|
|
1470
|
+
return cache.candidates.get(index);
|
|
1471
|
+
const value = tokens[index]?.value ?? "";
|
|
1472
|
+
let suffix = value.length;
|
|
1473
|
+
while (suffix > 0 && (isLocalChar(value.charCodeAt(suffix - 1)) || value[suffix - 1] === "."))
|
|
1474
|
+
suffix--;
|
|
1475
|
+
const doubled = value.lastIndexOf("..");
|
|
1476
|
+
if (doubled >= suffix)
|
|
1477
|
+
suffix = doubled + 2;
|
|
1478
|
+
while (value[suffix] === ".")
|
|
1479
|
+
suffix++;
|
|
1480
|
+
if (suffix >= value.length || !isLocalChar(value.charCodeAt(suffix))) {
|
|
1481
|
+
cache.candidates.set(index, null);
|
|
1482
|
+
return null;
|
|
1483
|
+
}
|
|
1484
|
+
const start = cache.offsets[index] + suffix;
|
|
1485
|
+
const scanned = scanEmail(cache.source, start, (pos) => commentEnd(cache, pos));
|
|
1486
|
+
if (scanned.end === undefined) {
|
|
1487
|
+
cache.candidates.set(index, null);
|
|
1488
|
+
let comment = 0;
|
|
1489
|
+
for (let i = index + 1;i < tokens.length && cache.offsets[i + 1] <= scanned.localEnd; i++) {
|
|
1490
|
+
const offset = cache.offsets[i];
|
|
1491
|
+
while (scanned.comments[comment] && scanned.comments[comment].end <= offset)
|
|
1492
|
+
comment++;
|
|
1493
|
+
const region = scanned.comments[comment];
|
|
1494
|
+
if (!region || offset < region.start)
|
|
1495
|
+
cache.candidates.set(i, null);
|
|
1496
|
+
}
|
|
1497
|
+
return null;
|
|
1498
|
+
}
|
|
1499
|
+
let endToken = index;
|
|
1500
|
+
while (cache.offsets[endToken + 1] < scanned.end)
|
|
1501
|
+
endToken++;
|
|
1502
|
+
const candidate = { start, end: scanned.end, endToken, address: scanned.address };
|
|
1503
|
+
cache.candidates.set(index, candidate);
|
|
1504
|
+
return candidate;
|
|
1505
|
+
}
|
|
1506
|
+
function getEmailGroup(tokens, index, limit) {
|
|
1507
|
+
const first = getEmailCandidate(tokens, index);
|
|
1508
|
+
if (!first || first.endToken >= limit)
|
|
1509
|
+
return null;
|
|
1510
|
+
const candidates = [first];
|
|
1511
|
+
let last = first;
|
|
1512
|
+
while (last.endToken > index) {
|
|
1513
|
+
const next = getEmailCandidate(tokens, last.endToken);
|
|
1514
|
+
if (!next || next.start < last.end || next.endToken >= limit)
|
|
1515
|
+
break;
|
|
1516
|
+
candidates.push(next);
|
|
1517
|
+
last = next;
|
|
1518
|
+
}
|
|
1519
|
+
const cache = getCache(tokens);
|
|
1520
|
+
return {
|
|
1521
|
+
candidates,
|
|
1522
|
+
source: cache.source,
|
|
1523
|
+
start: cache.offsets[index],
|
|
1524
|
+
end: cache.offsets[last.endToken + 1],
|
|
1525
|
+
endToken: last.endToken + 1
|
|
1526
|
+
};
|
|
1527
|
+
}
|
|
1528
|
+
function emailRegionEnd(tokens, index, limit) {
|
|
1529
|
+
return getEmailGroup(tokens, index, limit)?.endToken ?? index;
|
|
1530
|
+
}
|
|
1531
|
+
|
|
997
1532
|
// packages/parser/src/parser/rules/inline/raw/end.ts
|
|
1533
|
+
var unclosedAngleRanges = new WeakMap;
|
|
998
1534
|
function rawRegionEnd(tokens, start, end) {
|
|
999
1535
|
const type = tokens[start]?.type;
|
|
1000
1536
|
const close = type === "RAW_OPEN" ? "RAW_OPEN" : type === "RAW_BLOCK_OPEN" ? "RAW_BLOCK_CLOSE" : null;
|
|
1001
1537
|
if (!close)
|
|
1002
1538
|
return start;
|
|
1539
|
+
const cached = type === "RAW_BLOCK_OPEN" ? unclosedAngleRanges.get(tokens) : undefined;
|
|
1540
|
+
if (cached && start >= cached.start && start < cached.end && (cached.lineEnd || end <= cached.end)) {
|
|
1541
|
+
return start;
|
|
1542
|
+
}
|
|
1003
1543
|
for (let pos = start + 1;pos < end; pos++) {
|
|
1004
|
-
if (tokens[pos]?.type === "NEWLINE" || tokens[pos]?.type === "EOF")
|
|
1005
|
-
|
|
1544
|
+
if (tokens[pos]?.type === "NEWLINE" || tokens[pos]?.type === "EOF") {
|
|
1545
|
+
if (type === "RAW_BLOCK_OPEN")
|
|
1546
|
+
unclosedAngleRanges.set(tokens, { start, end: pos, lineEnd: true });
|
|
1547
|
+
return start;
|
|
1548
|
+
}
|
|
1006
1549
|
if (tokens[pos]?.type === close)
|
|
1007
1550
|
return pos + 1;
|
|
1008
1551
|
}
|
|
1552
|
+
if (type === "RAW_BLOCK_OPEN")
|
|
1553
|
+
unclosedAngleRanges.set(tokens, { start, end, lineEnd: false });
|
|
1009
1554
|
return start;
|
|
1010
1555
|
}
|
|
1011
1556
|
function protectedInlineRegionEnd(tokens, start, end) {
|
|
@@ -1024,7 +1569,7 @@ var MIN_INLINE_TEXT_RUN_LENGTH = 32;
|
|
|
1024
1569
|
var MIN_INLINE_TEXT_RUN_DOCUMENT_TOKENS = 1e5;
|
|
1025
1570
|
function collectLongPlainTextRun(ctx, startPos, endType) {
|
|
1026
1571
|
const firstToken = ctx.tokens[startPos];
|
|
1027
|
-
if (firstToken?.type === "TEXT" && firstToken.value.length >= MIN_INLINE_TEXT_RUN_LENGTH && firstToken.value !== "(") {
|
|
1572
|
+
if (!getEmailCandidate(ctx.tokens, startPos) && firstToken?.type === "TEXT" && firstToken.value.length >= MIN_INLINE_TEXT_RUN_LENGTH && firstToken.value !== "(") {
|
|
1028
1573
|
return { value: firstToken.value, consumed: 1 };
|
|
1029
1574
|
}
|
|
1030
1575
|
let pos = startPos;
|
|
@@ -1046,10 +1591,10 @@ function collectLongPlainTextRun(ctx, startPos, endType) {
|
|
|
1046
1591
|
}
|
|
1047
1592
|
function isPlainTextRunToken(ctx, pos) {
|
|
1048
1593
|
const token5 = ctx.tokens[pos];
|
|
1049
|
-
if (!token5)
|
|
1594
|
+
if (!token5 || getEmailCandidate(ctx.tokens, pos))
|
|
1050
1595
|
return false;
|
|
1051
1596
|
if (token5.type === "IDENTIFIER") {
|
|
1052
|
-
return
|
|
1597
|
+
return !(URL_SCHEME_NAMES.has(token5.value) && ctx.tokens[pos + 1]?.type === "COLON");
|
|
1053
1598
|
}
|
|
1054
1599
|
if (token5.type === "WHITESPACE") {
|
|
1055
1600
|
const next = ctx.tokens[pos + 1];
|
|
@@ -1198,6 +1743,10 @@ var BLOCK_START_TOKENS = [
|
|
|
1198
1743
|
"HEADING_MARKER",
|
|
1199
1744
|
"HR_MARKER",
|
|
1200
1745
|
"TABLE_MARKER",
|
|
1746
|
+
"TABLE_HEADER",
|
|
1747
|
+
"TABLE_LEFT",
|
|
1748
|
+
"TABLE_CENTER",
|
|
1749
|
+
"TABLE_RIGHT",
|
|
1201
1750
|
"COLON",
|
|
1202
1751
|
"BLOCK_OPEN",
|
|
1203
1752
|
"BLOCK_END_OPEN",
|
|
@@ -1275,14 +1824,727 @@ var INDENT_ACCEPTING_BLOCK_NAMES = new Set([
|
|
|
1275
1824
|
"tabs"
|
|
1276
1825
|
]);
|
|
1277
1826
|
|
|
1278
|
-
// packages/parser/src/parser/rules/
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1827
|
+
// packages/parser/src/parser/rules/block/code/open.ts
|
|
1828
|
+
var attributeRanges = new WeakMap;
|
|
1829
|
+
function findAttributesEnd(tokens, start) {
|
|
1830
|
+
const cached = attributeRanges.get(tokens);
|
|
1831
|
+
if (cached && start >= cached.start && start <= cached.end)
|
|
1832
|
+
return cached.end;
|
|
1833
|
+
let end = start;
|
|
1834
|
+
while (end < tokens.length) {
|
|
1835
|
+
const type = tokens[end]?.type;
|
|
1836
|
+
if (type === "BLOCK_CLOSE" || type === "NEWLINE" || type === "EOF")
|
|
1837
|
+
break;
|
|
1838
|
+
end++;
|
|
1839
|
+
}
|
|
1840
|
+
attributeRanges.set(tokens, { start, end });
|
|
1841
|
+
return end;
|
|
1842
|
+
}
|
|
1843
|
+
function findCodeOpen(tokens, start) {
|
|
1844
|
+
const name = tokens[start + 1];
|
|
1845
|
+
if (tokens[start]?.type !== "BLOCK_OPEN" || name?.type !== "IDENTIFIER" && name?.type !== "TEXT" || name.value.toLowerCase() !== "code" || tokens[start + 2]?.type === "UNDERSCORE")
|
|
1846
|
+
return null;
|
|
1847
|
+
const attributesEnd = findAttributesEnd(tokens, start + 2);
|
|
1848
|
+
const repaired = tokens[attributesEnd]?.type !== "BLOCK_CLOSE";
|
|
1849
|
+
const last = tokens[attributesEnd - 1];
|
|
1850
|
+
if (repaired && (last?.type !== "QUOTED_STRING" || !last.value.includes("]]")))
|
|
1851
|
+
return null;
|
|
1852
|
+
let bodyStart = attributesEnd + (repaired ? 0 : 1);
|
|
1853
|
+
if (tokens[bodyStart]?.type === "NEWLINE")
|
|
1854
|
+
bodyStart++;
|
|
1855
|
+
return {
|
|
1856
|
+
attributesEnd,
|
|
1857
|
+
bodyStart,
|
|
1858
|
+
repaired,
|
|
1859
|
+
closingSwallowed: repaired && last.value.includes("[[/code]]")
|
|
1860
|
+
};
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
// packages/parser/src/parser/rules/block/code/boundary.ts
|
|
1864
|
+
var caches2 = new WeakMap;
|
|
1865
|
+
function codeCloseEnd(tokens, start) {
|
|
1866
|
+
if (tokens[start]?.type !== "BLOCK_END_OPEN" || tokens[start + 1]?.value.toLowerCase() !== "code")
|
|
1867
|
+
return start;
|
|
1868
|
+
let end = start + 2;
|
|
1869
|
+
while (tokens[end]?.type === "WHITESPACE")
|
|
1870
|
+
end++;
|
|
1871
|
+
return tokens[end]?.type === "BLOCK_CLOSE" ? end + 1 : start;
|
|
1872
|
+
}
|
|
1873
|
+
function nestedCodeBodyStart(tokens, start) {
|
|
1874
|
+
if (tokens[start]?.type !== "BLOCK_OPEN" || tokens[start + 1]?.value.toLowerCase() !== "code")
|
|
1875
|
+
return start;
|
|
1876
|
+
for (let pos = start + 2;pos < tokens.length; pos++) {
|
|
1877
|
+
const type = tokens[pos]?.type;
|
|
1878
|
+
if (type === "NEWLINE" || type === "EOF" || type === "BLOCK_OPEN")
|
|
1879
|
+
return start;
|
|
1880
|
+
if (type === "BLOCK_CLOSE") {
|
|
1881
|
+
const open = findCodeOpen(tokens, start);
|
|
1882
|
+
return open && !open.repaired ? open.bodyStart : start;
|
|
1883
|
+
}
|
|
1884
|
+
}
|
|
1885
|
+
return start;
|
|
1886
|
+
}
|
|
1887
|
+
function findCodeBodyBounds(tokens, start) {
|
|
1888
|
+
let cache = caches2.get(tokens);
|
|
1889
|
+
if (!cache) {
|
|
1890
|
+
cache = new Map;
|
|
1891
|
+
caches2.set(tokens, cache);
|
|
1892
|
+
}
|
|
1893
|
+
const cached = cache.get(start);
|
|
1894
|
+
if (cached)
|
|
1895
|
+
return cached;
|
|
1896
|
+
const stack = [start];
|
|
1897
|
+
let pos = start;
|
|
1898
|
+
while (pos < tokens.length && tokens[pos]?.type !== "EOF") {
|
|
1899
|
+
const rawEnd = rawRegionEnd(tokens, pos, tokens.length);
|
|
1900
|
+
if (rawEnd > pos) {
|
|
1901
|
+
pos = rawEnd;
|
|
1902
|
+
continue;
|
|
1903
|
+
}
|
|
1904
|
+
const end = codeCloseEnd(tokens, pos);
|
|
1905
|
+
if (end > pos) {
|
|
1906
|
+
const result2 = { closeStart: pos, end, foundClose: true };
|
|
1907
|
+
cache.set(stack.pop(), result2);
|
|
1908
|
+
if (stack.length === 0)
|
|
1909
|
+
return result2;
|
|
1910
|
+
pos = end;
|
|
1911
|
+
continue;
|
|
1912
|
+
}
|
|
1913
|
+
const bodyStart = nestedCodeBodyStart(tokens, pos);
|
|
1914
|
+
if (bodyStart > pos) {
|
|
1915
|
+
const child = cache.get(bodyStart);
|
|
1916
|
+
if (child) {
|
|
1917
|
+
pos = child.end;
|
|
1918
|
+
if (!child.foundClose)
|
|
1919
|
+
break;
|
|
1920
|
+
} else {
|
|
1921
|
+
stack.push(bodyStart);
|
|
1922
|
+
pos = bodyStart;
|
|
1923
|
+
}
|
|
1924
|
+
continue;
|
|
1925
|
+
}
|
|
1926
|
+
pos++;
|
|
1927
|
+
}
|
|
1928
|
+
const result = { closeStart: pos, end: pos, foundClose: false };
|
|
1929
|
+
for (const bodyStart of stack)
|
|
1930
|
+
cache.set(bodyStart, result);
|
|
1931
|
+
return result;
|
|
1932
|
+
}
|
|
1933
|
+
|
|
1934
|
+
// packages/parser/src/parser/rules/block/math/boundary.ts
|
|
1935
|
+
var nameRanges = new WeakMap;
|
|
1936
|
+
var bodyCaches = new WeakMap;
|
|
1937
|
+
function findNameEnd(tokens, start) {
|
|
1938
|
+
const cached = nameRanges.get(tokens);
|
|
1939
|
+
if (cached && start >= cached.start && start <= cached.end)
|
|
1940
|
+
return cached.end;
|
|
1941
|
+
let end = start;
|
|
1942
|
+
while (end < tokens.length) {
|
|
1943
|
+
const type = tokens[end]?.type;
|
|
1944
|
+
if (type === "BLOCK_CLOSE" || type === "WHITESPACE" || type === "NEWLINE" || type === "EOF")
|
|
1945
|
+
break;
|
|
1946
|
+
end++;
|
|
1947
|
+
}
|
|
1948
|
+
nameRanges.set(tokens, { start, end });
|
|
1949
|
+
return end;
|
|
1950
|
+
}
|
|
1951
|
+
function findMathOpen(tokens, start) {
|
|
1952
|
+
const name = tokens[start + 1];
|
|
1953
|
+
if (tokens[start]?.type !== "BLOCK_OPEN" || name?.type !== "IDENTIFIER" && name?.type !== "TEXT" || name.value.toLowerCase() !== "math" || tokens[start + 2]?.type === "UNDERSCORE")
|
|
1954
|
+
return null;
|
|
1955
|
+
let pos = start + 2;
|
|
1956
|
+
while (tokens[pos]?.type === "WHITESPACE")
|
|
1957
|
+
pos++;
|
|
1958
|
+
const nameStart = pos;
|
|
1959
|
+
if (tokens[pos]?.type === "IDENTIFIER" || tokens[pos]?.type === "TEXT") {
|
|
1960
|
+
pos = findNameEnd(tokens, pos);
|
|
1961
|
+
}
|
|
1962
|
+
const nameEnd = pos;
|
|
1963
|
+
while (tokens[pos]?.type === "WHITESPACE")
|
|
1964
|
+
pos++;
|
|
1965
|
+
if (tokens[pos]?.type !== "BLOCK_CLOSE")
|
|
1966
|
+
return null;
|
|
1967
|
+
pos++;
|
|
1968
|
+
if (tokens[pos]?.type === "NEWLINE")
|
|
1969
|
+
pos++;
|
|
1970
|
+
return { nameStart, nameEnd, bodyStart: pos };
|
|
1971
|
+
}
|
|
1972
|
+
function mathCloseEnd(tokens, start) {
|
|
1973
|
+
if (tokens[start]?.type !== "BLOCK_END_OPEN" || tokens[start + 1]?.value.toLowerCase() !== "math" || tokens[start + 2]?.type !== "BLOCK_CLOSE")
|
|
1974
|
+
return start;
|
|
1975
|
+
const end = start + 3;
|
|
1976
|
+
return tokens[end]?.type === "NEWLINE" ? end + 1 : end;
|
|
1977
|
+
}
|
|
1978
|
+
function findMathBodyBounds(tokens, start) {
|
|
1979
|
+
let cache = bodyCaches.get(tokens);
|
|
1980
|
+
if (!cache) {
|
|
1981
|
+
cache = new Map;
|
|
1982
|
+
bodyCaches.set(tokens, cache);
|
|
1983
|
+
}
|
|
1984
|
+
const visited = [];
|
|
1985
|
+
let result = {
|
|
1986
|
+
closeStart: tokens.length,
|
|
1987
|
+
end: tokens.length,
|
|
1988
|
+
foundClose: false,
|
|
1989
|
+
hasContent: false
|
|
1990
|
+
};
|
|
1991
|
+
for (let pos = start;pos < tokens.length; pos++) {
|
|
1992
|
+
const cached = cache.get(pos);
|
|
1993
|
+
if (cached) {
|
|
1994
|
+
result = cached;
|
|
1995
|
+
break;
|
|
1996
|
+
}
|
|
1997
|
+
const end = mathCloseEnd(tokens, pos);
|
|
1998
|
+
if (end > pos) {
|
|
1999
|
+
result = { closeStart: pos, end, foundClose: true, hasContent: false };
|
|
2000
|
+
cache.set(pos, result);
|
|
2001
|
+
break;
|
|
2002
|
+
}
|
|
2003
|
+
visited.push(pos);
|
|
2004
|
+
}
|
|
2005
|
+
for (let i = visited.length - 1;i >= 0; i--) {
|
|
2006
|
+
const pos = visited[i];
|
|
2007
|
+
const token5 = tokens[pos];
|
|
2008
|
+
if (!result.hasContent && (token5.type === "BACKSLASH_BREAK" || token5.value.trim() !== "")) {
|
|
2009
|
+
result = { ...result, hasContent: true };
|
|
2010
|
+
}
|
|
2011
|
+
cache.set(pos, result);
|
|
2012
|
+
}
|
|
2013
|
+
return result;
|
|
2014
|
+
}
|
|
2015
|
+
|
|
2016
|
+
// packages/parser/src/parser/rules/opaque-probe.ts
|
|
2017
|
+
function createOpaqueProbe(ctx) {
|
|
2018
|
+
return {
|
|
2019
|
+
...ctx,
|
|
2020
|
+
diagnostics: [],
|
|
2021
|
+
footnotes: [],
|
|
2022
|
+
tocEntries: [],
|
|
2023
|
+
codeBlocks: [],
|
|
2024
|
+
htmlBlocks: [],
|
|
2025
|
+
bibcites: [],
|
|
2026
|
+
scope: {
|
|
2027
|
+
...ctx.scope,
|
|
2028
|
+
inlineEnd: undefined,
|
|
2029
|
+
tableFormatting: undefined,
|
|
2030
|
+
blockCloseCondition: () => true
|
|
2031
|
+
}
|
|
2032
|
+
};
|
|
2033
|
+
}
|
|
2034
|
+
function opaqueRuleEnd(probe, pos, rules, requireClosed = false) {
|
|
2035
|
+
const token5 = probe.tokens[pos];
|
|
2036
|
+
if (!token5)
|
|
2037
|
+
return pos;
|
|
2038
|
+
probe.pos = pos;
|
|
2039
|
+
for (const rule of rules) {
|
|
2040
|
+
if (!rule.startTokens.includes(token5.type))
|
|
2041
|
+
continue;
|
|
2042
|
+
if (rule.name === "code") {
|
|
2043
|
+
const open = findCodeOpen(probe.tokens, pos);
|
|
2044
|
+
if (!open)
|
|
2045
|
+
continue;
|
|
2046
|
+
if (open.closingSwallowed) {
|
|
2047
|
+
if (!requireClosed)
|
|
2048
|
+
return open.bodyStart;
|
|
2049
|
+
continue;
|
|
2050
|
+
}
|
|
2051
|
+
const bounds = findCodeBodyBounds(probe.tokens, open.bodyStart);
|
|
2052
|
+
if (!requireClosed || bounds.foundClose)
|
|
2053
|
+
return bounds.end;
|
|
2054
|
+
continue;
|
|
2055
|
+
}
|
|
2056
|
+
if (rule.name === "math") {
|
|
2057
|
+
const open = findMathOpen(probe.tokens, pos);
|
|
2058
|
+
if (!open)
|
|
2059
|
+
continue;
|
|
2060
|
+
const bounds = findMathBodyBounds(probe.tokens, open.bodyStart);
|
|
2061
|
+
if (bounds.hasContent && (!requireClosed || bounds.foundClose))
|
|
2062
|
+
return bounds.end;
|
|
2063
|
+
continue;
|
|
2064
|
+
}
|
|
2065
|
+
const result = rule.parse(probe);
|
|
2066
|
+
if (result.success)
|
|
2067
|
+
return pos + result.consumed;
|
|
2068
|
+
}
|
|
2069
|
+
return pos;
|
|
2070
|
+
}
|
|
2071
|
+
|
|
2072
|
+
// packages/parser/src/parser/rules/tokens.ts
|
|
2073
|
+
function currentToken(ctx) {
|
|
2074
|
+
return ctx.tokens[ctx.pos] ?? eofToken();
|
|
2075
|
+
}
|
|
2076
|
+
function eofToken() {
|
|
2077
|
+
return {
|
|
2078
|
+
type: "EOF",
|
|
2079
|
+
value: "",
|
|
2080
|
+
position: { start: { line: 0, column: 0, offset: 0 }, end: { line: 0, column: 0, offset: 0 } },
|
|
2081
|
+
lineStart: false
|
|
2082
|
+
};
|
|
2083
|
+
}
|
|
2084
|
+
function hasClosingMarkerBeforeNewline(ctx, markerType, markerValue) {
|
|
2085
|
+
let pos = ctx.pos;
|
|
2086
|
+
while (pos < (ctx.scope.inlineEnd ?? ctx.tokens.length)) {
|
|
2087
|
+
const token5 = ctx.tokens[pos];
|
|
2088
|
+
if (!token5 || token5.type === "NEWLINE" || token5.type === "EOF") {
|
|
2089
|
+
return false;
|
|
2090
|
+
}
|
|
2091
|
+
if (token5.type === markerType) {
|
|
2092
|
+
if (markerValue === undefined || token5.value === markerValue) {
|
|
2093
|
+
return true;
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
2096
|
+
pos++;
|
|
2097
|
+
}
|
|
2098
|
+
return false;
|
|
2099
|
+
}
|
|
2100
|
+
// packages/parser/src/parser/rules/block/code/attributes.ts
|
|
2101
|
+
function repairSwallowedCodeClose(ctx, pos, attrs) {
|
|
2102
|
+
const prevToken = ctx.tokens[pos - 1];
|
|
2103
|
+
if (prevToken?.type !== "QUOTED_STRING" || !prevToken.value.includes("]]")) {
|
|
2104
|
+
return null;
|
|
2105
|
+
}
|
|
2106
|
+
const rawValue = prevToken.value;
|
|
2107
|
+
const bracketIdx = rawValue.indexOf("]]");
|
|
2108
|
+
const truncatedValue = rawValue.startsWith('"') ? rawValue.slice(1, bracketIdx) : rawValue.slice(0, bracketIdx);
|
|
2109
|
+
for (const key of Object.keys(attrs)) {
|
|
2110
|
+
const stored = attrs[key];
|
|
2111
|
+
if (stored === rawValue || stored === rawValue.slice(1, -1) || stored === rawValue.slice(1)) {
|
|
2112
|
+
attrs[key] = truncatedValue;
|
|
2113
|
+
break;
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2116
|
+
return {
|
|
2117
|
+
closingSwallowed: rawValue.includes("[[/code]]")
|
|
2118
|
+
};
|
|
2119
|
+
}
|
|
2120
|
+
|
|
2121
|
+
// packages/parser/src/parser/rules/block/paragraph/span-markers.ts
|
|
2122
|
+
function processCloseSpanMarkers(elements) {
|
|
2123
|
+
let result = null;
|
|
2124
|
+
for (let i = 0;i < elements.length; i++) {
|
|
2125
|
+
const elem = elements[i];
|
|
2126
|
+
if (!elem)
|
|
2127
|
+
continue;
|
|
2128
|
+
if (isCloseSpanMarker(elem)) {
|
|
2129
|
+
if (result === null) {
|
|
2130
|
+
result = elements.slice(0, i);
|
|
2131
|
+
}
|
|
2132
|
+
if (result.length > 0) {
|
|
2133
|
+
const spanContent = [...result];
|
|
2134
|
+
result.length = 0;
|
|
2135
|
+
result.push({
|
|
2136
|
+
element: "container",
|
|
2137
|
+
data: {
|
|
2138
|
+
type: "span",
|
|
2139
|
+
attributes: {},
|
|
2140
|
+
elements: spanContent
|
|
2141
|
+
}
|
|
2142
|
+
});
|
|
2143
|
+
}
|
|
2144
|
+
} else {
|
|
2145
|
+
result?.push(elem);
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
return result ?? elements;
|
|
2149
|
+
}
|
|
2150
|
+
function isCloseSpanMarker(elem) {
|
|
2151
|
+
return elem.element === "container" && elem.data && typeof elem.data === "object" && "type" in elem.data && elem.data.type === "span" && "attributes" in elem.data && typeof elem.data.attributes === "object" && elem.data.attributes !== null && "_closeSpan" in elem.data.attributes;
|
|
2152
|
+
}
|
|
2153
|
+
|
|
2154
|
+
// packages/parser/src/parser/rules/inline/parsing/preserved-line-break.ts
|
|
2155
|
+
function createPreservedTrailingLineBreak() {
|
|
2156
|
+
const lineBreak = { element: "line-break" };
|
|
2157
|
+
lineBreak._preservedTrailingBreak = true;
|
|
2158
|
+
return lineBreak;
|
|
2159
|
+
}
|
|
2160
|
+
function createPreservedLeadingLineBreak() {
|
|
2161
|
+
const lineBreak = { element: "line-break", _preservedLeadingBreak: true };
|
|
2162
|
+
return lineBreak;
|
|
2163
|
+
}
|
|
2164
|
+
function isPreservedLeadingLineBreak(element) {
|
|
2165
|
+
return element?.element === "line-break" && element._preservedLeadingBreak === true;
|
|
2166
|
+
}
|
|
2167
|
+
|
|
2168
|
+
// packages/parser/src/parser/rules/block/paragraph/normalize.ts
|
|
2169
|
+
function normalizeParagraphElements(source) {
|
|
2170
|
+
let elements = processCloseSpanMarkers(source);
|
|
2171
|
+
removeTrailingLineBreaks(elements);
|
|
2172
|
+
removeTrailingWhitespaceText(elements);
|
|
2173
|
+
elements = removeLeadingLineBreaks(elements);
|
|
2174
|
+
return elements;
|
|
2175
|
+
}
|
|
2176
|
+
function removeTrailingLineBreaks(elements) {
|
|
2177
|
+
while (elements.length > 0 && elements[elements.length - 1]?.element === "line-break") {
|
|
2178
|
+
const lastEl = elements[elements.length - 1];
|
|
2179
|
+
if (lastEl._preservedTrailingBreak) {
|
|
2180
|
+
delete lastEl._preservedTrailingBreak;
|
|
2181
|
+
break;
|
|
2182
|
+
}
|
|
2183
|
+
elements.pop();
|
|
2184
|
+
}
|
|
2185
|
+
}
|
|
2186
|
+
function removeTrailingWhitespaceText(elements) {
|
|
2187
|
+
while (elements.length > 0) {
|
|
2188
|
+
const last = elements[elements.length - 1];
|
|
2189
|
+
if (last?.element === "text" && "data" in last && typeof last.data === "string" && last.data.trim() === "") {
|
|
2190
|
+
elements.pop();
|
|
2191
|
+
} else {
|
|
2192
|
+
break;
|
|
2193
|
+
}
|
|
2194
|
+
}
|
|
2195
|
+
}
|
|
2196
|
+
function removeLeadingLineBreaks(elements) {
|
|
2197
|
+
let first = 0;
|
|
2198
|
+
while (first < elements.length && elements[first]?.element === "line-break" && !isPreservedLeadingLineBreak(elements[first])) {
|
|
2199
|
+
first++;
|
|
2200
|
+
}
|
|
2201
|
+
return first > 0 ? elements.slice(first) : elements;
|
|
2202
|
+
}
|
|
2203
|
+
|
|
2204
|
+
// packages/parser/src/parser/rules/block/code/content.ts
|
|
2205
|
+
function collectCodeContent(ctx, startPos, closingSwallowed) {
|
|
2206
|
+
if (closingSwallowed)
|
|
2207
|
+
return { contents: "", consumed: 0, foundClose: true };
|
|
2208
|
+
const bounds = findCodeBodyBounds(ctx.tokens, startPos);
|
|
2209
|
+
return {
|
|
2210
|
+
contents: ctx.tokens.slice(startPos, bounds.closeStart).map((token5) => token5.value).join(""),
|
|
2211
|
+
consumed: bounds.end - startPos,
|
|
2212
|
+
foundClose: bounds.foundClose
|
|
2213
|
+
};
|
|
2214
|
+
}
|
|
2215
|
+
|
|
2216
|
+
// packages/parser/src/parser/rules/block/code/index.ts
|
|
2217
|
+
var codeBlockRule = {
|
|
2218
|
+
name: "code",
|
|
2219
|
+
startTokens: ["BLOCK_OPEN"],
|
|
2220
|
+
requiresLineStart: false,
|
|
2221
|
+
parse(ctx) {
|
|
2222
|
+
const openToken = currentToken(ctx);
|
|
2223
|
+
if (openToken.type !== "BLOCK_OPEN") {
|
|
2224
|
+
return { success: false };
|
|
2225
|
+
}
|
|
2226
|
+
const open = findCodeOpen(ctx.tokens, ctx.pos);
|
|
2227
|
+
if (!open)
|
|
2228
|
+
return { success: false };
|
|
2229
|
+
const attrResult = parseAttributesRaw(ctx, ctx.pos + 2);
|
|
2230
|
+
if (open.repaired)
|
|
2231
|
+
repairSwallowedCodeClose(ctx, open.attributesEnd, attrResult.attrs);
|
|
2232
|
+
let pos = open.bodyStart;
|
|
2233
|
+
let consumed = pos - ctx.pos;
|
|
2234
|
+
const contentResult = collectCodeContent(ctx, pos, open.closingSwallowed);
|
|
2235
|
+
let codeContent = contentResult.contents.replace(/\n$/, "");
|
|
2236
|
+
consumed += contentResult.consumed;
|
|
2237
|
+
pos += contentResult.consumed;
|
|
2238
|
+
if (!contentResult.foundClose) {
|
|
2239
|
+
ctx.diagnostics.push({
|
|
2240
|
+
severity: "warning",
|
|
2241
|
+
code: "unclosed-block",
|
|
2242
|
+
message: "Missing closing tag [[/code]] for [[code]]",
|
|
2243
|
+
position: openToken.position
|
|
2244
|
+
});
|
|
2245
|
+
}
|
|
2246
|
+
const codeBlockData = {
|
|
2247
|
+
contents: codeContent,
|
|
2248
|
+
language: attrResult.attrs.type ?? null,
|
|
2249
|
+
name: attrResult.attrs.name ?? null
|
|
2250
|
+
};
|
|
2251
|
+
ctx.codeBlocks.push(codeBlockData);
|
|
2252
|
+
const elements = [{ element: "code", data: codeBlockData }];
|
|
2253
|
+
if (ctx.tokens[pos]?.type === "NEWLINE" && !getParagraphNewlineBoundary(ctx, pos, false).shouldBreak && !ctx.scope.blockCloseCondition?.({ ...ctx, pos: pos + 1 })) {
|
|
2254
|
+
const after = parseInlineUntil({ ...ctx, pos: pos + 1 }, "PARAGRAPH_BREAK");
|
|
2255
|
+
elements.push({ element: "line-break" }, ...normalizeParagraphElements(after.elements));
|
|
2256
|
+
consumed += 1 + after.consumed;
|
|
2257
|
+
}
|
|
2258
|
+
return { success: true, elements, consumed };
|
|
2259
|
+
}
|
|
2260
|
+
};
|
|
2261
|
+
|
|
2262
|
+
// packages/parser/src/parser/rules/block/math/index.ts
|
|
2263
|
+
var mathBlockRule = {
|
|
2264
|
+
name: "math",
|
|
2265
|
+
startTokens: ["BLOCK_OPEN"],
|
|
2266
|
+
requiresLineStart: false,
|
|
2267
|
+
parse(ctx) {
|
|
2268
|
+
const openToken = currentToken(ctx);
|
|
2269
|
+
const open = findMathOpen(ctx.tokens, ctx.pos);
|
|
2270
|
+
if (!open)
|
|
2271
|
+
return { success: false };
|
|
2272
|
+
const bounds = findMathBodyBounds(ctx.tokens, open.bodyStart);
|
|
2273
|
+
if (!bounds.foundClose) {
|
|
2274
|
+
ctx.diagnostics.push({
|
|
2275
|
+
severity: "warning",
|
|
2276
|
+
code: "unclosed-block",
|
|
2277
|
+
message: "Missing closing tag [[/math]] for [[math]]",
|
|
2278
|
+
position: openToken.position
|
|
2279
|
+
});
|
|
2280
|
+
}
|
|
2281
|
+
if (!bounds.hasContent) {
|
|
2282
|
+
return { success: false };
|
|
2283
|
+
}
|
|
2284
|
+
const latexSource = ctx.tokens.slice(open.bodyStart, bounds.closeStart).map((token5) => token5.type === "BACKSLASH_BREAK" ? "\\\n" : token5.value).join("").trim();
|
|
2285
|
+
const name = ctx.tokens.slice(open.nameStart, open.nameEnd).map((token5) => token5.value).join("");
|
|
2286
|
+
return {
|
|
2287
|
+
success: true,
|
|
2288
|
+
elements: [
|
|
2289
|
+
{
|
|
2290
|
+
element: "math",
|
|
2291
|
+
data: {
|
|
2292
|
+
name: name || null,
|
|
2293
|
+
"latex-source": latexSource
|
|
2294
|
+
}
|
|
2295
|
+
}
|
|
2296
|
+
],
|
|
2297
|
+
consumed: bounds.end - ctx.pos
|
|
2298
|
+
};
|
|
2299
|
+
}
|
|
2300
|
+
};
|
|
2301
|
+
|
|
2302
|
+
// packages/parser/src/parser/rules/inline/link-triple/fallback.ts
|
|
2303
|
+
function literalOpenLink(value) {
|
|
2304
|
+
return {
|
|
2305
|
+
success: true,
|
|
2306
|
+
elements: [{ element: "text", data: value }],
|
|
2307
|
+
consumed: 1
|
|
2308
|
+
};
|
|
2309
|
+
}
|
|
2310
|
+
|
|
2311
|
+
// packages/parser/src/parser/rules/inline/link-triple/label.ts
|
|
2312
|
+
function buildTripleLinkLabel(args) {
|
|
2313
|
+
if (args.isPage && args.foundPipe && !args.labelText.trim())
|
|
2314
|
+
return "page";
|
|
2315
|
+
return {
|
|
2316
|
+
text: getTripleLinkDisplayText({
|
|
2317
|
+
...args,
|
|
2318
|
+
originalTarget: args.isPage && !args.foundPipe ? args.originalTarget.split("#")[0] : args.originalTarget
|
|
2319
|
+
})
|
|
2320
|
+
};
|
|
2321
|
+
}
|
|
2322
|
+
function getTripleLinkDisplayText(args) {
|
|
2323
|
+
const trimmedLabel = args.labelText.trim();
|
|
2324
|
+
if (args.foundPipe) {
|
|
2325
|
+
return trimmedLabel || args.finalTarget;
|
|
2326
|
+
}
|
|
2327
|
+
const colonIdx = args.originalTarget.indexOf(":");
|
|
2328
|
+
if (colonIdx !== -1 && !args.originalTarget.startsWith("http") && !args.originalTarget.startsWith("*")) {
|
|
2329
|
+
return args.originalTarget.slice(colonIdx + 1).trim();
|
|
2330
|
+
}
|
|
2331
|
+
return args.originalTarget;
|
|
2332
|
+
}
|
|
2333
|
+
|
|
2334
|
+
// packages/parser/src/parser/rules/inline/link-triple/syntax.ts
|
|
2335
|
+
function hasClosingLinkMarker(ctx, startPos) {
|
|
2336
|
+
let pos = startPos;
|
|
2337
|
+
while (pos < ctx.tokens.length) {
|
|
2338
|
+
const token5 = ctx.tokens[pos];
|
|
2339
|
+
if (!token5 || token5.type === "EOF") {
|
|
2340
|
+
return false;
|
|
2341
|
+
}
|
|
2342
|
+
if (token5.type === "LINK_CLOSE") {
|
|
2343
|
+
return true;
|
|
2344
|
+
}
|
|
2345
|
+
if (token5.type === "NEWLINE") {
|
|
2346
|
+
const next = ctx.tokens[pos + 1];
|
|
2347
|
+
if (next?.type === "NEWLINE" || next?.type === "LINK_CLOSE") {
|
|
2348
|
+
return false;
|
|
2349
|
+
}
|
|
2350
|
+
}
|
|
2351
|
+
pos++;
|
|
2352
|
+
}
|
|
2353
|
+
return false;
|
|
2354
|
+
}
|
|
2355
|
+
function collectTripleLinkParts(ctx, startPos) {
|
|
2356
|
+
let target = "";
|
|
2357
|
+
let labelText = "";
|
|
2358
|
+
let foundPipe = false;
|
|
2359
|
+
let consumed = 1;
|
|
2360
|
+
let pos = startPos;
|
|
2361
|
+
while (pos < ctx.tokens.length) {
|
|
2362
|
+
const token5 = ctx.tokens[pos];
|
|
2363
|
+
if (!token5 || token5.type === "LINK_CLOSE" || token5.type === "EOF") {
|
|
2364
|
+
break;
|
|
2365
|
+
}
|
|
2366
|
+
if (token5.type === "NEWLINE") {
|
|
2367
|
+
if (foundPipe) {
|
|
2368
|
+
labelText += " ";
|
|
2369
|
+
} else {
|
|
2370
|
+
target += " ";
|
|
2371
|
+
}
|
|
2372
|
+
consumed++;
|
|
2373
|
+
pos++;
|
|
2374
|
+
continue;
|
|
2375
|
+
}
|
|
2376
|
+
if (token5.type === "PIPE" && !foundPipe) {
|
|
2377
|
+
foundPipe = true;
|
|
2378
|
+
} else if (foundPipe) {
|
|
2379
|
+
labelText += token5.value;
|
|
2380
|
+
} else {
|
|
2381
|
+
target += token5.value;
|
|
2382
|
+
}
|
|
2383
|
+
consumed++;
|
|
2384
|
+
pos++;
|
|
2385
|
+
}
|
|
2386
|
+
if (ctx.tokens[pos]?.type === "LINK_CLOSE") {
|
|
2387
|
+
consumed++;
|
|
2388
|
+
}
|
|
2389
|
+
return { target, labelText, foundPipe, consumed };
|
|
2390
|
+
}
|
|
2391
|
+
|
|
2392
|
+
// packages/parser/src/parser/rules/inline/link-triple/interwiki.ts
|
|
2393
|
+
var INTERWIKI_PREFIXES = new Set(["wikipedia", "google", "dictionary", "wikidot"]);
|
|
2394
|
+
function isInterwikiTarget(target) {
|
|
2395
|
+
const colonIdx = target.indexOf(":");
|
|
2396
|
+
if (colonIdx <= 0 || target.includes("/")) {
|
|
2397
|
+
return false;
|
|
2398
|
+
}
|
|
2399
|
+
const prefix = target.slice(0, colonIdx).toLowerCase();
|
|
2400
|
+
return INTERWIKI_PREFIXES.has(prefix);
|
|
2401
|
+
}
|
|
2402
|
+
|
|
2403
|
+
// packages/parser/src/parser/rules/inline/link-triple/target.ts
|
|
2404
|
+
function normalizeTripleLinkTarget(trimmedTarget) {
|
|
2405
|
+
if (trimmedTarget.startsWith("*")) {
|
|
2406
|
+
return { target: trimmedTarget.slice(1), hasStar: true };
|
|
2407
|
+
}
|
|
2408
|
+
return { target: trimmedTarget, hasStar: false };
|
|
2409
|
+
}
|
|
2410
|
+
function isInvalidTripleLinkTarget(trimmedTarget, foundPipe) {
|
|
2411
|
+
return trimmedTarget === "" && foundPipe || /#{2,}/.test(trimmedTarget);
|
|
2412
|
+
}
|
|
2413
|
+
function determineLinkTypeAndLocation(target) {
|
|
2414
|
+
if (target.startsWith("#")) {
|
|
2415
|
+
return { linkType: "anchor", link: target };
|
|
2416
|
+
}
|
|
2417
|
+
if (target.startsWith("http://") || target.startsWith("https://")) {
|
|
2418
|
+
return { linkType: "direct", link: target };
|
|
2419
|
+
}
|
|
2420
|
+
if (isInterwikiTarget(target)) {
|
|
2421
|
+
return { linkType: "interwiki", link: target };
|
|
2422
|
+
}
|
|
2423
|
+
return { linkType: "page", link: { site: null, page: target } };
|
|
2424
|
+
}
|
|
2425
|
+
|
|
2426
|
+
// packages/parser/src/parser/rules/inline/link-triple/index.ts
|
|
2427
|
+
var linkTripleRule = {
|
|
2428
|
+
name: "linkTriple",
|
|
2429
|
+
startTokens: ["LINK_OPEN"],
|
|
2430
|
+
parse(ctx) {
|
|
2431
|
+
const startToken = currentToken(ctx);
|
|
2432
|
+
if (!hasClosingLinkMarker(ctx, ctx.pos + 1)) {
|
|
2433
|
+
return literalOpenLink(startToken.value);
|
|
2434
|
+
}
|
|
2435
|
+
const parts = collectTripleLinkParts(ctx, ctx.pos + 1);
|
|
2436
|
+
const trimmedTarget = parts.target.trim();
|
|
2437
|
+
if (isInvalidTripleLinkTarget(trimmedTarget, parts.foundPipe)) {
|
|
2438
|
+
return literalOpenLink(startToken.value);
|
|
2439
|
+
}
|
|
2440
|
+
const normalized = normalizeTripleLinkTarget(trimmedTarget);
|
|
2441
|
+
const { linkType, link } = determineLinkTypeAndLocation(normalized.target);
|
|
2442
|
+
const label = buildTripleLinkLabel({
|
|
2443
|
+
isPage: linkType === "page",
|
|
2444
|
+
foundPipe: parts.foundPipe,
|
|
2445
|
+
labelText: parts.labelText,
|
|
2446
|
+
finalTarget: normalized.target,
|
|
2447
|
+
originalTarget: trimmedTarget
|
|
2448
|
+
});
|
|
2449
|
+
return {
|
|
2450
|
+
success: true,
|
|
2451
|
+
elements: [
|
|
2452
|
+
{
|
|
2453
|
+
element: "link",
|
|
2454
|
+
data: {
|
|
2455
|
+
type: linkType,
|
|
2456
|
+
link,
|
|
2457
|
+
extra: null,
|
|
2458
|
+
label,
|
|
2459
|
+
target: normalized.hasStar && linkType === "direct" ? "new-tab" : null
|
|
2460
|
+
}
|
|
2461
|
+
}
|
|
2462
|
+
],
|
|
2463
|
+
consumed: parts.consumed
|
|
2464
|
+
};
|
|
2465
|
+
}
|
|
2466
|
+
};
|
|
2467
|
+
|
|
2468
|
+
// packages/parser/src/parser/rules/block/note/boundary.ts
|
|
2469
|
+
var opaqueRules = [codeBlockRule, mathBlockRule, linkTripleRule];
|
|
2470
|
+
var boundsCache = new WeakMap;
|
|
2471
|
+
var closeCache = new WeakMap;
|
|
2472
|
+
function tagEnd(tokens, pos, name, close = false) {
|
|
2473
|
+
return tokens[pos]?.type === (close ? "BLOCK_END_OPEN" : "BLOCK_OPEN") && tokens[pos + 1]?.value.toLowerCase() === name && tokens[pos + 2]?.type === "BLOCK_CLOSE" ? pos + 3 : pos;
|
|
2474
|
+
}
|
|
2475
|
+
function findClose(probe, start, name) {
|
|
2476
|
+
let byName = closeCache.get(probe.tokens);
|
|
2477
|
+
if (!byName) {
|
|
2478
|
+
byName = new Map;
|
|
2479
|
+
closeCache.set(probe.tokens, byName);
|
|
2480
|
+
}
|
|
2481
|
+
let cache = byName.get(name);
|
|
2482
|
+
if (!cache) {
|
|
2483
|
+
cache = new Map;
|
|
2484
|
+
byName.set(name, cache);
|
|
2485
|
+
}
|
|
2486
|
+
if (cache.has(start))
|
|
2487
|
+
return cache.get(start);
|
|
2488
|
+
const visited = [];
|
|
2489
|
+
let result = -1;
|
|
2490
|
+
for (let pos = start;pos < probe.tokens.length; pos++) {
|
|
2491
|
+
if (cache.has(pos)) {
|
|
2492
|
+
result = cache.get(pos);
|
|
2493
|
+
break;
|
|
2494
|
+
}
|
|
2495
|
+
visited.push(pos);
|
|
2496
|
+
const protectedEnd = protectedInlineRegionEnd(probe.tokens, pos, probe.tokens.length);
|
|
2497
|
+
if (protectedEnd > pos) {
|
|
2498
|
+
pos = protectedEnd - 1;
|
|
2499
|
+
continue;
|
|
2500
|
+
}
|
|
2501
|
+
if (tagEnd(probe.tokens, pos, name, true) > pos) {
|
|
2502
|
+
result = pos;
|
|
2503
|
+
break;
|
|
2504
|
+
}
|
|
2505
|
+
const opaqueEnd = opaqueRuleEnd(probe, pos, opaqueRules, true);
|
|
2506
|
+
if (opaqueEnd > pos) {
|
|
2507
|
+
pos = opaqueEnd - 1;
|
|
2508
|
+
continue;
|
|
2509
|
+
}
|
|
2510
|
+
if (name === "note") {
|
|
2511
|
+
const footnoteStart = tagEnd(probe.tokens, pos, "footnote");
|
|
2512
|
+
if (footnoteStart > pos) {
|
|
2513
|
+
const end = findClose(probe, footnoteStart, "footnote");
|
|
2514
|
+
if (end >= 0)
|
|
2515
|
+
pos = end + 2;
|
|
2516
|
+
}
|
|
2517
|
+
}
|
|
2518
|
+
}
|
|
2519
|
+
for (const pos of visited)
|
|
2520
|
+
cache.set(pos, result);
|
|
2521
|
+
return result;
|
|
2522
|
+
}
|
|
2523
|
+
function findNoteBounds(ctx, start = ctx.pos) {
|
|
2524
|
+
const openEnd = tagEnd(ctx.tokens, start, "note");
|
|
2525
|
+
if (openEnd === start || ctx.tokens[openEnd]?.type !== "NEWLINE")
|
|
2526
|
+
return null;
|
|
2527
|
+
let cache = boundsCache.get(ctx.tokens);
|
|
2528
|
+
if (!cache) {
|
|
2529
|
+
cache = new Map;
|
|
2530
|
+
boundsCache.set(ctx.tokens, cache);
|
|
2531
|
+
}
|
|
2532
|
+
if (cache.has(start))
|
|
2533
|
+
return cache.get(start);
|
|
2534
|
+
const close = findClose(createOpaqueProbe(ctx), openEnd + 1, "note");
|
|
2535
|
+
const result = close < 0 ? null : { bodyStart: openEnd + 1, close, end: close + 3 };
|
|
2536
|
+
cache.set(start, result);
|
|
2537
|
+
return result;
|
|
2538
|
+
}
|
|
2539
|
+
|
|
2540
|
+
// packages/parser/src/parser/rules/inline/parsing/block-boundary.ts
|
|
2541
|
+
function isExcludedBlockToken(ctx, tokenPos) {
|
|
2542
|
+
const excluded = ctx.scope.excludedBlockNames;
|
|
2543
|
+
if (!excluded?.size)
|
|
2544
|
+
return false;
|
|
2545
|
+
const token5 = ctx.tokens[tokenPos];
|
|
2546
|
+
if (token5?.type !== "BLOCK_OPEN" && token5?.type !== "BLOCK_END_OPEN")
|
|
2547
|
+
return false;
|
|
1286
2548
|
const nameResult = parseBlockName(ctx, tokenPos + 1);
|
|
1287
2549
|
return nameResult !== null && excluded.has(nameResult.name);
|
|
1288
2550
|
}
|
|
@@ -1297,6 +2559,8 @@ function isUnknownBlockToken(ctx, tokenPos) {
|
|
|
1297
2559
|
}
|
|
1298
2560
|
return true;
|
|
1299
2561
|
}
|
|
2562
|
+
if (nameResult.name === "note")
|
|
2563
|
+
return findNoteBounds(ctx, tokenPos) === null;
|
|
1300
2564
|
return !KNOWN_BLOCK_NAMES.has(nameResult.name);
|
|
1301
2565
|
}
|
|
1302
2566
|
function isIndentAcceptingBlock(ctx, tokenPos) {
|
|
@@ -1320,7 +2584,13 @@ function isParagraphBreakingBlockStart(ctx, newlinePos, lookAhead) {
|
|
|
1320
2584
|
if (!nextMeaningfulToken.lineStart && !isIndentedBlockOpener) {
|
|
1321
2585
|
return false;
|
|
1322
2586
|
}
|
|
1323
|
-
return !parseImageOpen({ ...ctx, pos: nextPos }) && !isOrphanCloseSpan(ctx, nextPos) && !isAnchorName(ctx, nextPos) && !isInvalidBlockOpen(ctx, nextPos) && !isInvalidHeading(ctx, nextPos) && !isExcludedBlockStart(ctx, nextPos) && !isUnknownBlockStart(ctx, nextPos);
|
|
2587
|
+
return !parseImageOpen({ ...ctx, pos: nextPos }) && !isOrphanCloseSpan(ctx, nextPos) && !isAnchorName(ctx, nextPos) && !isInvalidBlockOpen(ctx, nextPos) && !isInvalidHeading(ctx, nextPos) && !isInvalidListMarker(ctx, nextPos) && !isExcludedBlockStart(ctx, nextPos) && !isUnknownBlockStart(ctx, nextPos);
|
|
2588
|
+
}
|
|
2589
|
+
function isInvalidListMarker(ctx, markerPos) {
|
|
2590
|
+
const marker = ctx.tokens[markerPos];
|
|
2591
|
+
if (marker?.type !== "LIST_BULLET" && marker?.type !== "LIST_NUMBER")
|
|
2592
|
+
return false;
|
|
2593
|
+
return ctx.tokens[markerPos + 1]?.type !== "WHITESPACE";
|
|
1324
2594
|
}
|
|
1325
2595
|
function isOrphanCloseSpan(ctx, blockEndOpenPos) {
|
|
1326
2596
|
const token5 = ctx.tokens[blockEndOpenPos];
|
|
@@ -1406,13 +2676,6 @@ function skipWhitespaceAfterNewline(ctx, newlinePos) {
|
|
|
1406
2676
|
return lookAhead;
|
|
1407
2677
|
}
|
|
1408
2678
|
|
|
1409
|
-
// packages/parser/src/parser/rules/inline/parsing/preserved-line-break.ts
|
|
1410
|
-
function createPreservedTrailingLineBreak() {
|
|
1411
|
-
const lineBreak = { element: "line-break" };
|
|
1412
|
-
lineBreak._preservedTrailingBreak = true;
|
|
1413
|
-
return lineBreak;
|
|
1414
|
-
}
|
|
1415
|
-
|
|
1416
2679
|
// packages/parser/src/parser/rules/inline/parsing/simple-token.ts
|
|
1417
2680
|
function parseSimpleInlineToken(token5, nextToken) {
|
|
1418
2681
|
if (token5.type === "TEXT" && token5.value !== "(") {
|
|
@@ -1429,12 +2692,13 @@ function parseInlineUntil(ctx, endType) {
|
|
|
1429
2692
|
const nodes = [];
|
|
1430
2693
|
let consumed = 0;
|
|
1431
2694
|
let pos = ctx.pos;
|
|
2695
|
+
let consumedEmptyRaw = false;
|
|
1432
2696
|
const paragraphMode = endType === "PARAGRAPH_BREAK";
|
|
1433
2697
|
const multiline = paragraphMode || FORMATTING_CLOSE_TOKENS.has(endType);
|
|
1434
2698
|
let inlineEnd = ctx.scope.inlineEnd ?? ctx.tokens.length;
|
|
1435
2699
|
if (!multiline) {
|
|
1436
2700
|
for (let end = ctx.pos;end < inlineEnd; end++) {
|
|
1437
|
-
const protectedEnd = protectedInlineRegionEnd(ctx.tokens, end, inlineEnd);
|
|
2701
|
+
const protectedEnd = Math.max(parseButtonSyntax(ctx, end, inlineEnd)?.end ?? end, parseSocialSyntax(ctx, end, inlineEnd)?.end ?? end, parseDateSyntax(ctx, end, inlineEnd)?.end ?? end, emailRegionEnd(ctx.tokens, end, inlineEnd), protectedInlineRegionEnd(ctx.tokens, end, inlineEnd));
|
|
1438
2702
|
if (protectedEnd > end) {
|
|
1439
2703
|
end = protectedEnd - 1;
|
|
1440
2704
|
continue;
|
|
@@ -1483,10 +2747,11 @@ function parseInlineUntil(ctx, endType) {
|
|
|
1483
2747
|
consumed++;
|
|
1484
2748
|
continue;
|
|
1485
2749
|
}
|
|
1486
|
-
|
|
2750
|
+
const hasEmail = emailRegionEnd(ctx.tokens, pos, inlineEnd) > pos;
|
|
2751
|
+
if (token5.type === endType && !hasEmail) {
|
|
1487
2752
|
break;
|
|
1488
2753
|
}
|
|
1489
|
-
if (canCollectLongPlainTextRuns) {
|
|
2754
|
+
if (canCollectLongPlainTextRuns && !hasEmail) {
|
|
1490
2755
|
const plainTextRun = collectLongPlainTextRun(ctx, pos, endType);
|
|
1491
2756
|
if (plainTextRun) {
|
|
1492
2757
|
nodes.push({ element: "text", data: plainTextRun.value });
|
|
@@ -1496,7 +2761,7 @@ function parseInlineUntil(ctx, endType) {
|
|
|
1496
2761
|
}
|
|
1497
2762
|
}
|
|
1498
2763
|
const simpleToken = parseSimpleInlineToken(token5, ctx.tokens[pos + 1]);
|
|
1499
|
-
if (simpleToken) {
|
|
2764
|
+
if (simpleToken && !hasEmail) {
|
|
1500
2765
|
nodes.push(simpleToken.element);
|
|
1501
2766
|
consumed += simpleToken.consumed;
|
|
1502
2767
|
pos += simpleToken.consumed;
|
|
@@ -1507,6 +2772,10 @@ function parseInlineUntil(ctx, endType) {
|
|
|
1507
2772
|
for (const rule of getCandidateInlineRules(inlineRules, token5.type)) {
|
|
1508
2773
|
const result = rule.parse(inlineCtx);
|
|
1509
2774
|
if (result.success) {
|
|
2775
|
+
stripAutomaticLineBreak(nodes, result.stripLeadingLineBreak);
|
|
2776
|
+
if (rule.name === "raw" && result.elements.length === 0 && nodes.length === 0) {
|
|
2777
|
+
consumedEmptyRaw = true;
|
|
2778
|
+
}
|
|
1510
2779
|
if (rule.name === "comment") {
|
|
1511
2780
|
let after = pos + result.consumed;
|
|
1512
2781
|
while (ctx.tokens[after]?.type === "WHITESPACE")
|
|
@@ -1523,165 +2792,39 @@ function parseInlineUntil(ctx, endType) {
|
|
|
1523
2792
|
}
|
|
1524
2793
|
if (nodes.at(-1)?.element === "line-break")
|
|
1525
2794
|
nodes.pop();
|
|
1526
|
-
}
|
|
1527
|
-
}
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
nodes.push({ element: "text", data: token5.value });
|
|
1537
|
-
consumed++;
|
|
1538
|
-
pos++;
|
|
1539
|
-
}
|
|
1540
|
-
}
|
|
1541
|
-
return { elements: nodes, consumed };
|
|
1542
|
-
}
|
|
1543
|
-
var FORMATTING_CLOSE_TOKENS = new Set([
|
|
1544
|
-
"BOLD_MARKER",
|
|
1545
|
-
"ITALIC_MARKER",
|
|
1546
|
-
"UNDERLINE_MARKER",
|
|
1547
|
-
"STRIKE_MARKER",
|
|
1548
|
-
"SUPER_MARKER",
|
|
1549
|
-
"SUB_MARKER",
|
|
1550
|
-
"MONO_CLOSE",
|
|
1551
|
-
"COLOR_MARKER"
|
|
1552
|
-
]);
|
|
1553
|
-
// packages/parser/src/parser/rules/block/parsing/attributes/names.ts
|
|
1554
|
-
function consumeAttributeName(ctx, startPos, startConsumed, startName, options) {
|
|
1555
|
-
if (startName === "_" && isAttributeWordToken(ctx.tokens[startPos])) {
|
|
1556
|
-
startName += ctx.tokens[startPos]?.value ?? "";
|
|
1557
|
-
startPos++;
|
|
1558
|
-
startConsumed++;
|
|
1559
|
-
}
|
|
1560
|
-
return options.strikeHyphens ? consumeRawNameSuffix(ctx, startPos, startConsumed, startName, options.hyphenatedNames) : consumeSafeNameSuffix(ctx, startPos, startConsumed, startName);
|
|
1561
|
-
}
|
|
1562
|
-
function isAttributeNameToken(token5) {
|
|
1563
|
-
return isAttributeWordToken(token5) || token5?.type === "UNDERSCORE";
|
|
1564
|
-
}
|
|
1565
|
-
function consumeSafeNameSuffix(ctx, startPos, startConsumed, startName) {
|
|
1566
|
-
let name = startName;
|
|
1567
|
-
let pos = startPos;
|
|
1568
|
-
let consumed = startConsumed;
|
|
1569
|
-
while (isAttributeNameSeparator(ctx.tokens[pos]) && isAttributeWordToken(ctx.tokens[pos + 1])) {
|
|
1570
|
-
name += ctx.tokens[pos]?.value ?? "";
|
|
1571
|
-
pos++;
|
|
1572
|
-
consumed++;
|
|
1573
|
-
name += ctx.tokens[pos]?.value ?? "";
|
|
1574
|
-
pos++;
|
|
1575
|
-
consumed++;
|
|
1576
|
-
}
|
|
1577
|
-
return { name, pos, consumed };
|
|
1578
|
-
}
|
|
1579
|
-
function consumeRawNameSuffix(ctx, startPos, startConsumed, startName, hyphenatedNames) {
|
|
1580
|
-
let name = startName;
|
|
1581
|
-
let pos = startPos;
|
|
1582
|
-
let consumed = startConsumed;
|
|
1583
|
-
while (isAttributeNameSeparator(ctx.tokens[pos])) {
|
|
1584
|
-
while (isAttributeNameSeparator(ctx.tokens[pos])) {
|
|
1585
|
-
if (hyphenatedNames || ctx.tokens[pos]?.type === "UNDERSCORE") {
|
|
1586
|
-
name += ctx.tokens[pos]?.value ?? "-";
|
|
1587
|
-
}
|
|
1588
|
-
pos++;
|
|
1589
|
-
consumed++;
|
|
1590
|
-
}
|
|
1591
|
-
if (!isAttributeWordToken(ctx.tokens[pos])) {
|
|
1592
|
-
break;
|
|
1593
|
-
}
|
|
1594
|
-
if (hyphenatedNames || name.endsWith("_")) {
|
|
1595
|
-
name += ctx.tokens[pos]?.value ?? "";
|
|
1596
|
-
}
|
|
1597
|
-
pos++;
|
|
1598
|
-
consumed++;
|
|
1599
|
-
}
|
|
1600
|
-
return { name, pos, consumed };
|
|
1601
|
-
}
|
|
1602
|
-
function isAttributeWordToken(token5) {
|
|
1603
|
-
return token5?.type === "TEXT" || token5?.type === "IDENTIFIER";
|
|
1604
|
-
}
|
|
1605
|
-
function isAttributeNameSeparator(token5) {
|
|
1606
|
-
return token5?.type === "TEXT" && token5.value === "-" || token5?.type === "STRIKE_MARKER" || token5?.type === "UNDERSCORE";
|
|
1607
|
-
}
|
|
1608
|
-
|
|
1609
|
-
// packages/parser/src/parser/rules/block/parsing/attributes/values.ts
|
|
1610
|
-
function consumeAttributeValue(token5) {
|
|
1611
|
-
if (!token5) {
|
|
1612
|
-
return null;
|
|
1613
|
-
}
|
|
1614
|
-
if (token5.type === "QUOTED_STRING") {
|
|
1615
|
-
return { value: stripQuotes(token5.value) };
|
|
1616
|
-
}
|
|
1617
|
-
if (isAttributeNameToken(token5)) {
|
|
1618
|
-
return { value: token5.value };
|
|
1619
|
-
}
|
|
1620
|
-
return null;
|
|
1621
|
-
}
|
|
1622
|
-
function stripQuotes(value) {
|
|
1623
|
-
return value.startsWith('"') && value.endsWith('"') ? value.slice(1, -1) : value;
|
|
1624
|
-
}
|
|
1625
|
-
|
|
1626
|
-
// packages/parser/src/parser/rules/block/parsing/attributes/scanner.ts
|
|
1627
|
-
function scanAttributes(ctx, startPos, options) {
|
|
1628
|
-
const attrs = {};
|
|
1629
|
-
let pos = startPos;
|
|
1630
|
-
let consumed = 0;
|
|
1631
|
-
while (pos < ctx.tokens.length) {
|
|
1632
|
-
const token5 = ctx.tokens[pos];
|
|
1633
|
-
if (!token5 || isAttributeTerminator(token5)) {
|
|
1634
|
-
break;
|
|
2795
|
+
}
|
|
2796
|
+
}
|
|
2797
|
+
for (const element of result.elements) {
|
|
2798
|
+
nodes.push(paragraphMode && consumedEmptyRaw && nodes.length === 0 && token5.type === "NEWLINE" && element.element === "line-break" ? createPreservedLeadingLineBreak() : element);
|
|
2799
|
+
}
|
|
2800
|
+
consumed += result.consumed;
|
|
2801
|
+
pos += result.consumed;
|
|
2802
|
+
matched = true;
|
|
2803
|
+
break;
|
|
2804
|
+
}
|
|
1635
2805
|
}
|
|
1636
|
-
if (
|
|
1637
|
-
|
|
2806
|
+
if (!matched) {
|
|
2807
|
+
nodes.push({ element: "text", data: token5.value });
|
|
1638
2808
|
consumed++;
|
|
1639
|
-
continue;
|
|
1640
|
-
}
|
|
1641
|
-
if (!isAttributeNameToken(token5)) {
|
|
1642
2809
|
pos++;
|
|
1643
|
-
consumed++;
|
|
1644
|
-
continue;
|
|
1645
|
-
}
|
|
1646
|
-
let name = token5.value;
|
|
1647
|
-
pos++;
|
|
1648
|
-
consumed++;
|
|
1649
|
-
const nameResult = consumeAttributeName(ctx, pos, consumed, name, options);
|
|
1650
|
-
pos = nameResult.pos;
|
|
1651
|
-
consumed = nameResult.consumed;
|
|
1652
|
-
name = nameResult.name.toLowerCase();
|
|
1653
|
-
if (ctx.tokens[pos]?.type !== "EQUALS") {
|
|
1654
|
-
attrs[name] = "true";
|
|
1655
|
-
continue;
|
|
1656
|
-
}
|
|
1657
|
-
pos++;
|
|
1658
|
-
consumed++;
|
|
1659
|
-
const valueResult = consumeAttributeValue(ctx.tokens[pos]);
|
|
1660
|
-
if (!valueResult) {
|
|
1661
|
-
continue;
|
|
1662
2810
|
}
|
|
1663
|
-
attrs[name] = valueResult.value;
|
|
1664
|
-
pos++;
|
|
1665
|
-
consumed++;
|
|
1666
2811
|
}
|
|
1667
|
-
return {
|
|
1668
|
-
}
|
|
1669
|
-
function isAttributeTerminator(token5) {
|
|
1670
|
-
return token5.type === "BLOCK_CLOSE" || token5.type === "NEWLINE" || token5.type === "EOF";
|
|
1671
|
-
}
|
|
1672
|
-
|
|
1673
|
-
// packages/parser/src/parser/rules/block/parsing/attributes/index.ts
|
|
1674
|
-
function parseAttributes(ctx, startPos) {
|
|
1675
|
-
const result = scanAttributes(ctx, startPos, { hyphenatedNames: true, strikeHyphens: false });
|
|
1676
|
-
return { attrs: filterUnsafeAttributes(result.attrs), consumed: result.consumed };
|
|
1677
|
-
}
|
|
1678
|
-
function parseAttributesRaw(ctx, startPos, hyphenatedNames = true) {
|
|
1679
|
-
return scanAttributes(ctx, startPos, { hyphenatedNames, strikeHyphens: true });
|
|
2812
|
+
return { elements: nodes, consumed };
|
|
1680
2813
|
}
|
|
2814
|
+
var FORMATTING_CLOSE_TOKENS = new Set([
|
|
2815
|
+
"BOLD_MARKER",
|
|
2816
|
+
"ITALIC_MARKER",
|
|
2817
|
+
"UNDERLINE_MARKER",
|
|
2818
|
+
"STRIKE_MARKER",
|
|
2819
|
+
"SUPER_MARKER",
|
|
2820
|
+
"SUB_MARKER",
|
|
2821
|
+
"MONO_CLOSE",
|
|
2822
|
+
"COLOR_MARKER"
|
|
2823
|
+
]);
|
|
1681
2824
|
// packages/parser/src/parser/parse/block.ts
|
|
1682
|
-
function parseNextBlock(ctx, skipWhitespace2,
|
|
2825
|
+
function parseNextBlock(ctx, skipWhitespace2, isAtEnd3) {
|
|
1683
2826
|
skipWhitespace2();
|
|
1684
|
-
if (
|
|
2827
|
+
if (isAtEnd3()) {
|
|
1685
2828
|
return [];
|
|
1686
2829
|
}
|
|
1687
2830
|
const token5 = ctx.tokens[ctx.pos];
|
|
@@ -1700,7 +2843,7 @@ function parseNextBlock(ctx, skipWhitespace2, isAtEnd2) {
|
|
|
1700
2843
|
}
|
|
1701
2844
|
}
|
|
1702
2845
|
const result = ctx.blockFallbackRule.parse(ctx);
|
|
1703
|
-
if (result.success
|
|
2846
|
+
if (result.success) {
|
|
1704
2847
|
ctx.pos += result.consumed;
|
|
1705
2848
|
return result.elements;
|
|
1706
2849
|
}
|
|
@@ -1710,35 +2853,6 @@ function parseNextBlock(ctx, skipWhitespace2, isAtEnd2) {
|
|
|
1710
2853
|
|
|
1711
2854
|
// packages/parser/src/parser/parse/context.ts
|
|
1712
2855
|
var import_ast6 = require("@wdprlib/ast");
|
|
1713
|
-
|
|
1714
|
-
// packages/parser/src/parser/rules/tokens.ts
|
|
1715
|
-
function currentToken(ctx) {
|
|
1716
|
-
return ctx.tokens[ctx.pos] ?? eofToken();
|
|
1717
|
-
}
|
|
1718
|
-
function eofToken() {
|
|
1719
|
-
return {
|
|
1720
|
-
type: "EOF",
|
|
1721
|
-
value: "",
|
|
1722
|
-
position: { start: { line: 0, column: 0, offset: 0 }, end: { line: 0, column: 0, offset: 0 } },
|
|
1723
|
-
lineStart: false
|
|
1724
|
-
};
|
|
1725
|
-
}
|
|
1726
|
-
function hasClosingMarkerBeforeNewline(ctx, markerType, markerValue) {
|
|
1727
|
-
let pos = ctx.pos;
|
|
1728
|
-
while (pos < (ctx.scope.inlineEnd ?? ctx.tokens.length)) {
|
|
1729
|
-
const token5 = ctx.tokens[pos];
|
|
1730
|
-
if (!token5 || token5.type === "NEWLINE" || token5.type === "EOF") {
|
|
1731
|
-
return false;
|
|
1732
|
-
}
|
|
1733
|
-
if (token5.type === markerType) {
|
|
1734
|
-
if (markerValue === undefined || token5.value === markerValue) {
|
|
1735
|
-
return true;
|
|
1736
|
-
}
|
|
1737
|
-
}
|
|
1738
|
-
pos++;
|
|
1739
|
-
}
|
|
1740
|
-
return false;
|
|
1741
|
-
}
|
|
1742
2856
|
// packages/parser/src/parser/rules/block/heading/open.ts
|
|
1743
2857
|
function parseHeadingOpen(ctx) {
|
|
1744
2858
|
const marker = ctx.tokens[ctx.pos];
|
|
@@ -1984,10 +3098,11 @@ function parseNativeListLine(ctx, startPos) {
|
|
|
1984
3098
|
const ltype = markerToken.type === "LIST_BULLET" ? "bullet" : "numbered";
|
|
1985
3099
|
pos++;
|
|
1986
3100
|
consumed++;
|
|
1987
|
-
if (ctx.tokens[pos]?.type
|
|
1988
|
-
|
|
1989
|
-
consumed++;
|
|
3101
|
+
if (ctx.tokens[pos]?.type !== "WHITESPACE") {
|
|
3102
|
+
return { kind: "stop" };
|
|
1990
3103
|
}
|
|
3104
|
+
pos++;
|
|
3105
|
+
consumed++;
|
|
1991
3106
|
const inlineCtx = { ...ctx, pos };
|
|
1992
3107
|
const inlineResult = parseInlineUntil(inlineCtx, "NEWLINE");
|
|
1993
3108
|
consumed += inlineResult.consumed;
|
|
@@ -2097,9 +3212,9 @@ function appendBareParagraphElements(state, elements) {
|
|
|
2097
3212
|
function appendBareParagraphText(state, text) {
|
|
2098
3213
|
state.current.push({ element: "text", data: text });
|
|
2099
3214
|
}
|
|
2100
|
-
function appendBareParagraphLineBreakIfNeeded(state) {
|
|
3215
|
+
function appendBareParagraphLineBreakIfNeeded(state, token5) {
|
|
2101
3216
|
if (state.current.length > 0) {
|
|
2102
|
-
state.current.push(
|
|
3217
|
+
state.current.push(createAutomaticLineBreak(token5));
|
|
2103
3218
|
}
|
|
2104
3219
|
}
|
|
2105
3220
|
function flushBareParagraph(state) {
|
|
@@ -2204,7 +3319,7 @@ function parseBareListContent(ctx, startPos, listType) {
|
|
|
2204
3319
|
if (consecutiveNewlines >= 2) {
|
|
2205
3320
|
flushBareParagraph(paragraphState);
|
|
2206
3321
|
} else {
|
|
2207
|
-
appendBareParagraphLineBreakIfNeeded(paragraphState);
|
|
3322
|
+
appendBareParagraphLineBreakIfNeeded(paragraphState, token5);
|
|
2208
3323
|
}
|
|
2209
3324
|
continue;
|
|
2210
3325
|
}
|
|
@@ -2216,6 +3331,7 @@ function parseBareListContent(ctx, startPos, listType) {
|
|
|
2216
3331
|
for (const rule of getCandidateInlineRules(ctx.inlineRules, token5.type)) {
|
|
2217
3332
|
const result = rule.parse(inlineCtx);
|
|
2218
3333
|
if (result.success) {
|
|
3334
|
+
stripAutomaticLineBreak(paragraphState.current, result.stripLeadingLineBreak);
|
|
2219
3335
|
appendBareParagraphElements(paragraphState, result.elements);
|
|
2220
3336
|
consumed += result.consumed;
|
|
2221
3337
|
pos += result.consumed;
|
|
@@ -2254,7 +3370,7 @@ function parseListItemBlockContent(ctx, pos, token5) {
|
|
|
2254
3370
|
for (const rule of getCandidateBlockRules(filteredBlockRules, token5)) {
|
|
2255
3371
|
const result = rule.parse(blockCtx);
|
|
2256
3372
|
if (result.success) {
|
|
2257
|
-
return { matched: true,
|
|
3373
|
+
return { matched: true, ...result };
|
|
2258
3374
|
}
|
|
2259
3375
|
}
|
|
2260
3376
|
return { matched: false, elements: [], consumed: 0 };
|
|
@@ -2273,7 +3389,7 @@ function parseListItemInlineContent(ctx, pos, tokenType) {
|
|
|
2273
3389
|
for (const rule of getCandidateInlineRules(ctx.inlineRules, tokenType)) {
|
|
2274
3390
|
const result = rule.parse(inlineCtx);
|
|
2275
3391
|
if (result.success) {
|
|
2276
|
-
return { matched: true,
|
|
3392
|
+
return { matched: true, ...result };
|
|
2277
3393
|
}
|
|
2278
3394
|
}
|
|
2279
3395
|
return { matched: false, elements: [], consumed: 0 };
|
|
@@ -2315,7 +3431,9 @@ function collectPostLiTrailingContent(ctx, startPos, listType) {
|
|
|
2315
3431
|
}
|
|
2316
3432
|
const inlineResult = parseListItemInlineContent(ctx, pos, token5.type);
|
|
2317
3433
|
if (inlineResult.matched) {
|
|
2318
|
-
elements
|
|
3434
|
+
stripAutomaticLineBreak(elements, inlineResult.stripLeadingLineBreak);
|
|
3435
|
+
for (const element of inlineResult.elements)
|
|
3436
|
+
elements.push(element);
|
|
2319
3437
|
consumed += inlineResult.consumed;
|
|
2320
3438
|
pos += inlineResult.consumed;
|
|
2321
3439
|
continue;
|
|
@@ -2360,7 +3478,7 @@ function collectLiItemContent(ctx, startPos, listType, parseNestedList) {
|
|
|
2360
3478
|
if (token5.type === "NEWLINE") {
|
|
2361
3479
|
const newlineResult = consumeLiItemNewlines(ctx, pos, elements.length > 0);
|
|
2362
3480
|
if (newlineResult.addLineBreak) {
|
|
2363
|
-
elements.push(
|
|
3481
|
+
elements.push(createAutomaticLineBreak(token5));
|
|
2364
3482
|
}
|
|
2365
3483
|
pos += newlineResult.consumed;
|
|
2366
3484
|
consumed += newlineResult.consumed;
|
|
@@ -2368,14 +3486,17 @@ function collectLiItemContent(ctx, startPos, listType, parseNestedList) {
|
|
|
2368
3486
|
}
|
|
2369
3487
|
const blockResult = parseListItemBlockContent(ctx, pos, token5);
|
|
2370
3488
|
if (blockResult.matched) {
|
|
2371
|
-
|
|
3489
|
+
for (const element of blockResult.elements)
|
|
3490
|
+
elements.push(element);
|
|
2372
3491
|
consumed += blockResult.consumed;
|
|
2373
3492
|
pos += blockResult.consumed;
|
|
2374
3493
|
continue;
|
|
2375
3494
|
}
|
|
2376
3495
|
const inlineResult = parseListItemInlineContent(ctx, pos, token5.type);
|
|
2377
3496
|
if (inlineResult.matched) {
|
|
2378
|
-
elements
|
|
3497
|
+
stripAutomaticLineBreak(elements, inlineResult.stripLeadingLineBreak);
|
|
3498
|
+
for (const element of inlineResult.elements)
|
|
3499
|
+
elements.push(element);
|
|
2379
3500
|
consumed += inlineResult.consumed;
|
|
2380
3501
|
pos += inlineResult.consumed;
|
|
2381
3502
|
continue;
|
|
@@ -2446,7 +3567,8 @@ function parseLiItem(ctx, startPos, listType, parseNestedList) {
|
|
|
2446
3567
|
consumed += closeConsumed;
|
|
2447
3568
|
pos += closeConsumed;
|
|
2448
3569
|
const trailingResult = collectPostLiTrailingContent(ctx, pos, listType);
|
|
2449
|
-
|
|
3570
|
+
for (const element of trailingResult.elements)
|
|
3571
|
+
contentElements.push(element);
|
|
2450
3572
|
consumed += trailingResult.consumed;
|
|
2451
3573
|
}
|
|
2452
3574
|
return {
|
|
@@ -2706,7 +3828,7 @@ function sliceLineTokens(ctx, lines) {
|
|
|
2706
3828
|
for (const { start, end } of lines) {
|
|
2707
3829
|
for (let pos = start;pos < end; pos++) {
|
|
2708
3830
|
const token5 = ctx.tokens[pos];
|
|
2709
|
-
if (token5) {
|
|
3831
|
+
if (token5 && token5.type !== "BACKSLASH_BREAK") {
|
|
2710
3832
|
tokens.push(token5);
|
|
2711
3833
|
}
|
|
2712
3834
|
}
|
|
@@ -2876,7 +3998,8 @@ function parseDefinitionItemKey(ctx, startPos) {
|
|
|
2876
3998
|
const inlineCtx = { ...ctx, pos };
|
|
2877
3999
|
const result = parseInlineUntil(inlineCtx, "COLON");
|
|
2878
4000
|
if (result.elements.length > 0) {
|
|
2879
|
-
|
|
4001
|
+
for (const element of result.elements)
|
|
4002
|
+
key.push(element);
|
|
2880
4003
|
for (let i = 0;i < result.consumed; i++) {
|
|
2881
4004
|
const t = ctx.tokens[pos + i];
|
|
2882
4005
|
if (t)
|
|
@@ -2932,7 +4055,8 @@ function parseDefinitionItemValue(ctx, startPos) {
|
|
|
2932
4055
|
const inlineCtx = { ...ctx, pos };
|
|
2933
4056
|
const result = parseInlineUntil(inlineCtx, "NEWLINE");
|
|
2934
4057
|
if (result.elements.length > 0) {
|
|
2935
|
-
|
|
4058
|
+
for (const element of result.elements)
|
|
4059
|
+
value.push(element);
|
|
2936
4060
|
pos += result.consumed;
|
|
2937
4061
|
consumed += result.consumed;
|
|
2938
4062
|
} else {
|
|
@@ -3014,78 +4138,93 @@ var definitionListRule = {
|
|
|
3014
4138
|
}
|
|
3015
4139
|
};
|
|
3016
4140
|
|
|
3017
|
-
// packages/parser/src/parser/
|
|
3018
|
-
|
|
3019
|
-
|
|
4141
|
+
// packages/parser/src/parser/postprocess/divAdjacentParagraph.ts
|
|
4142
|
+
var unparsedDivStarts = new WeakSet;
|
|
4143
|
+
function markUnparsedDivStart(elements) {
|
|
4144
|
+
const first = elements[0];
|
|
4145
|
+
const text = first?.element === "container" && first.data.type === "paragraph" ? first.data.elements[0] : first;
|
|
4146
|
+
if (text?.element === "text")
|
|
4147
|
+
unparsedDivStarts.add(text);
|
|
3020
4148
|
}
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
4149
|
+
function isUnparsedDivParagraph(el) {
|
|
4150
|
+
if (!el || el.element !== "container")
|
|
4151
|
+
return false;
|
|
4152
|
+
return el.data.type === "paragraph" && el.data.elements.some((child) => unparsedDivStarts.has(child));
|
|
4153
|
+
}
|
|
4154
|
+
function isDivContainer(el) {
|
|
4155
|
+
if (!el || el.element !== "container")
|
|
4156
|
+
return false;
|
|
4157
|
+
return el.data.type === "div";
|
|
4158
|
+
}
|
|
4159
|
+
function suppressAtLevel(elements) {
|
|
4160
|
+
if (elements.length <= 1)
|
|
4161
|
+
return elements;
|
|
4162
|
+
const unwrap = Array.from({ length: elements.length }, () => false);
|
|
3025
4163
|
for (let i = 0;i < elements.length; i++) {
|
|
3026
|
-
|
|
3027
|
-
if (!elem)
|
|
4164
|
+
if (!isUnparsedDivParagraph(elements[i]))
|
|
3028
4165
|
continue;
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
});
|
|
4166
|
+
const prevIsDiv = i > 0 && isDivContainer(elements[i - 1]);
|
|
4167
|
+
const nextIsDiv = i < elements.length - 1 && isDivContainer(elements[i + 1]);
|
|
4168
|
+
if (prevIsDiv || nextIsDiv) {
|
|
4169
|
+
unwrap[i] = true;
|
|
4170
|
+
}
|
|
4171
|
+
}
|
|
4172
|
+
const result = [];
|
|
4173
|
+
for (let i = 0;i < elements.length; i++) {
|
|
4174
|
+
const el = elements[i];
|
|
4175
|
+
if (!el)
|
|
4176
|
+
continue;
|
|
4177
|
+
if (unwrap[i] && el.element === "container") {
|
|
4178
|
+
const inner = el.data.elements;
|
|
4179
|
+
if (i > 0 && isDivContainer(elements[i - 1])) {
|
|
4180
|
+
result.push({ element: "line-break" });
|
|
3044
4181
|
}
|
|
4182
|
+
result.push(...inner);
|
|
3045
4183
|
} else {
|
|
3046
|
-
result
|
|
4184
|
+
result.push(el);
|
|
3047
4185
|
}
|
|
3048
4186
|
}
|
|
3049
|
-
return result
|
|
4187
|
+
return result;
|
|
3050
4188
|
}
|
|
3051
|
-
function
|
|
3052
|
-
return
|
|
4189
|
+
function suppressDivAdjacentParagraphs(elements) {
|
|
4190
|
+
return suppressAtLevel(elements);
|
|
3053
4191
|
}
|
|
3054
4192
|
|
|
3055
|
-
// packages/parser/src/parser/rules/block/
|
|
3056
|
-
function
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
return
|
|
4193
|
+
// packages/parser/src/parser/rules/block/div/close.ts
|
|
4194
|
+
function isDivClose(ctx) {
|
|
4195
|
+
const token5 = ctx.tokens[ctx.pos];
|
|
4196
|
+
if (token5?.type !== "BLOCK_END_OPEN")
|
|
4197
|
+
return false;
|
|
4198
|
+
const closeNameResult = parseBlockName(ctx, ctx.pos + 1);
|
|
4199
|
+
return closeNameResult?.name === "div";
|
|
3062
4200
|
}
|
|
3063
|
-
function
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
break;
|
|
3069
|
-
}
|
|
3070
|
-
elements.pop();
|
|
4201
|
+
function consumeDivClose(ctx, startPos) {
|
|
4202
|
+
let pos = startPos;
|
|
4203
|
+
let consumed = 0;
|
|
4204
|
+
if (ctx.tokens[pos]?.type !== "BLOCK_END_OPEN") {
|
|
4205
|
+
return { pos, consumed };
|
|
3071
4206
|
}
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
} else {
|
|
3079
|
-
break;
|
|
3080
|
-
}
|
|
4207
|
+
pos++;
|
|
4208
|
+
consumed++;
|
|
4209
|
+
const closeNameResult = parseBlockName(ctx, pos);
|
|
4210
|
+
if (closeNameResult) {
|
|
4211
|
+
pos += closeNameResult.consumed;
|
|
4212
|
+
consumed += closeNameResult.consumed;
|
|
3081
4213
|
}
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
while (first < elements.length && elements[first]?.element === "line-break") {
|
|
3086
|
-
first++;
|
|
4214
|
+
if (ctx.tokens[pos]?.type === "BLOCK_CLOSE") {
|
|
4215
|
+
pos++;
|
|
4216
|
+
consumed++;
|
|
3087
4217
|
}
|
|
3088
|
-
|
|
4218
|
+
if (ctx.tokens[pos]?.type === "NEWLINE") {
|
|
4219
|
+
pos++;
|
|
4220
|
+
consumed++;
|
|
4221
|
+
}
|
|
4222
|
+
return { pos, consumed };
|
|
4223
|
+
}
|
|
4224
|
+
|
|
4225
|
+
// packages/parser/src/parser/rules/block/paragraph/content.ts
|
|
4226
|
+
function parseInlineContent(ctx) {
|
|
4227
|
+
return parseInlineUntil(ctx, "PARAGRAPH_BREAK");
|
|
3089
4228
|
}
|
|
3090
4229
|
|
|
3091
4230
|
// packages/parser/src/parser/rules/block/paragraph/index.ts
|
|
@@ -3095,25 +4234,30 @@ var paragraphRule = {
|
|
|
3095
4234
|
requiresLineStart: false,
|
|
3096
4235
|
parse(ctx) {
|
|
3097
4236
|
const result = parseInlineContent(ctx);
|
|
3098
|
-
if (result.
|
|
4237
|
+
if (result.consumed === 0) {
|
|
3099
4238
|
return { success: false };
|
|
3100
4239
|
}
|
|
3101
4240
|
const elements = normalizeParagraphElements(result.elements);
|
|
3102
4241
|
if (elements.length === 0) {
|
|
3103
|
-
return { success:
|
|
4242
|
+
return { success: true, elements: [], consumed: result.consumed };
|
|
3104
4243
|
}
|
|
3105
4244
|
const nextPos = ctx.pos + result.consumed;
|
|
3106
4245
|
const nextToken = ctx.tokens[nextPos];
|
|
3107
4246
|
if (nextToken?.type === "COLON" && nextToken.lineStart) {
|
|
4247
|
+
if (isPreservedLeadingLineBreak(elements[0]))
|
|
4248
|
+
elements[0] = { element: "line-break" };
|
|
3108
4249
|
return {
|
|
3109
4250
|
success: true,
|
|
3110
4251
|
elements: [...elements, { element: "line-break" }],
|
|
3111
4252
|
consumed: result.consumed
|
|
3112
4253
|
};
|
|
3113
4254
|
}
|
|
4255
|
+
const wrapped = wrapParagraphElements(elements);
|
|
4256
|
+
if (isDivClose(ctx))
|
|
4257
|
+
markUnparsedDivStart(wrapped);
|
|
3114
4258
|
return {
|
|
3115
4259
|
success: true,
|
|
3116
|
-
elements:
|
|
4260
|
+
elements: wrapped,
|
|
3117
4261
|
consumed: result.consumed
|
|
3118
4262
|
};
|
|
3119
4263
|
}
|
|
@@ -3124,7 +4268,7 @@ function wrapParagraphElements(elements) {
|
|
|
3124
4268
|
let bare = false;
|
|
3125
4269
|
const flush = (trimBreaks = false) => {
|
|
3126
4270
|
const content = trimBreaks ? normalizeParagraphElements(group) : group;
|
|
3127
|
-
while (content[0]?.element === "line-break")
|
|
4271
|
+
while (content[0]?.element === "line-break" && !isPreservedLeadingLineBreak(content[0]))
|
|
3128
4272
|
content.shift();
|
|
3129
4273
|
while (content.length) {
|
|
3130
4274
|
const last = content.at(-1);
|
|
@@ -3136,6 +4280,8 @@ function wrapParagraphElements(elements) {
|
|
|
3136
4280
|
content.shift();
|
|
3137
4281
|
if (content[0]?.element === "text")
|
|
3138
4282
|
content[0] = { element: "text", data: content[0].data.trimStart() };
|
|
4283
|
+
if (isPreservedLeadingLineBreak(content[0]))
|
|
4284
|
+
content[0] = { element: "line-break" };
|
|
3139
4285
|
if (content.length)
|
|
3140
4286
|
output.push(...bare || content.some((el) => el.element === "image") ? content : [
|
|
3141
4287
|
{
|
|
@@ -3157,37 +4303,36 @@ function wrapParagraphElements(elements) {
|
|
|
3157
4303
|
return output;
|
|
3158
4304
|
}
|
|
3159
4305
|
|
|
3160
|
-
// packages/parser/src/parser/rules/block/
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
4306
|
+
// packages/parser/src/parser/rules/block/note/index.ts
|
|
4307
|
+
var excludedBlockNames = new Set(["note"]);
|
|
4308
|
+
var noteRule = {
|
|
4309
|
+
name: "note",
|
|
4310
|
+
startTokens: ["BLOCK_OPEN"],
|
|
4311
|
+
requiresLineStart: false,
|
|
4312
|
+
parse(ctx) {
|
|
4313
|
+
const bounds = findNoteBounds(ctx);
|
|
4314
|
+
if (!bounds)
|
|
4315
|
+
return { success: false };
|
|
4316
|
+
const body = parseBlocksUntil({
|
|
4317
|
+
...ctx,
|
|
4318
|
+
tokens: ctx.tokens.slice(bounds.bodyStart, bounds.close),
|
|
4319
|
+
pos: 0,
|
|
4320
|
+
scope: {
|
|
4321
|
+
...ctx.scope,
|
|
4322
|
+
inlineEnd: undefined,
|
|
4323
|
+
tableFormatting: undefined,
|
|
4324
|
+
blockCloseCondition: undefined
|
|
4325
|
+
}
|
|
4326
|
+
}, () => false, { excludedBlockNames });
|
|
4327
|
+
return {
|
|
4328
|
+
success: true,
|
|
4329
|
+
consumed: bounds.end - ctx.pos,
|
|
4330
|
+
elements: [
|
|
4331
|
+
{ element: "container", data: { type: "note", attributes: {}, elements: body.elements } }
|
|
4332
|
+
]
|
|
4333
|
+
};
|
|
3188
4334
|
}
|
|
3189
|
-
|
|
3190
|
-
}
|
|
4335
|
+
};
|
|
3191
4336
|
|
|
3192
4337
|
// packages/parser/src/parser/rules/block/div/nesting.ts
|
|
3193
4338
|
var divCloseCountCache = new WeakMap;
|
|
@@ -3356,6 +4501,7 @@ function consumeFailedDiv(ctx) {
|
|
|
3356
4501
|
pos++;
|
|
3357
4502
|
consumed++;
|
|
3358
4503
|
}
|
|
4504
|
+
markUnparsedDivStart(elements);
|
|
3359
4505
|
return {
|
|
3360
4506
|
success: true,
|
|
3361
4507
|
elements: [
|
|
@@ -3467,126 +4613,6 @@ var divRule = {
|
|
|
3467
4613
|
}
|
|
3468
4614
|
};
|
|
3469
4615
|
|
|
3470
|
-
// packages/parser/src/parser/rules/block/code/attributes.ts
|
|
3471
|
-
function repairSwallowedCodeClose(ctx, pos, attrs) {
|
|
3472
|
-
const prevToken = ctx.tokens[pos - 1];
|
|
3473
|
-
if (prevToken?.type !== "QUOTED_STRING" || !prevToken.value.includes("]]")) {
|
|
3474
|
-
return null;
|
|
3475
|
-
}
|
|
3476
|
-
const rawValue = prevToken.value;
|
|
3477
|
-
const bracketIdx = rawValue.indexOf("]]");
|
|
3478
|
-
const truncatedValue = rawValue.startsWith('"') ? rawValue.slice(1, bracketIdx) : rawValue.slice(0, bracketIdx);
|
|
3479
|
-
for (const key of Object.keys(attrs)) {
|
|
3480
|
-
const stored = attrs[key];
|
|
3481
|
-
if (stored === rawValue || stored === rawValue.slice(1, -1) || stored === rawValue.slice(1)) {
|
|
3482
|
-
attrs[key] = truncatedValue;
|
|
3483
|
-
break;
|
|
3484
|
-
}
|
|
3485
|
-
}
|
|
3486
|
-
return {
|
|
3487
|
-
closingSwallowed: rawValue.includes("[[/code]]")
|
|
3488
|
-
};
|
|
3489
|
-
}
|
|
3490
|
-
|
|
3491
|
-
// packages/parser/src/parser/rules/block/code/content.ts
|
|
3492
|
-
function collectCodeContent(ctx, startPos, closingSwallowed) {
|
|
3493
|
-
const contentParts = [];
|
|
3494
|
-
let pos = startPos;
|
|
3495
|
-
let consumed = 0;
|
|
3496
|
-
let foundClose = closingSwallowed;
|
|
3497
|
-
while (!closingSwallowed && pos < ctx.tokens.length) {
|
|
3498
|
-
const token5 = ctx.tokens[pos];
|
|
3499
|
-
if (!token5 || token5.type === "EOF") {
|
|
3500
|
-
break;
|
|
3501
|
-
}
|
|
3502
|
-
if (token5.type === "BLOCK_END_OPEN") {
|
|
3503
|
-
const closeNameResult = parseBlockName(ctx, pos + 1);
|
|
3504
|
-
if (closeNameResult?.name === "code") {
|
|
3505
|
-
foundClose = true;
|
|
3506
|
-
const closeConsumed = consumeCodeClose(ctx, pos, closeNameResult.consumed);
|
|
3507
|
-
consumed += closeConsumed;
|
|
3508
|
-
break;
|
|
3509
|
-
}
|
|
3510
|
-
}
|
|
3511
|
-
contentParts.push(token5.value);
|
|
3512
|
-
pos++;
|
|
3513
|
-
consumed++;
|
|
3514
|
-
}
|
|
3515
|
-
return { contents: contentParts.join(""), consumed, foundClose };
|
|
3516
|
-
}
|
|
3517
|
-
function consumeCodeClose(ctx, startPos, closeNameConsumed) {
|
|
3518
|
-
let pos = startPos + 1 + closeNameConsumed;
|
|
3519
|
-
let consumed = 1 + closeNameConsumed;
|
|
3520
|
-
if (ctx.tokens[pos]?.type === "BLOCK_CLOSE") {
|
|
3521
|
-
pos++;
|
|
3522
|
-
consumed++;
|
|
3523
|
-
}
|
|
3524
|
-
return consumed;
|
|
3525
|
-
}
|
|
3526
|
-
|
|
3527
|
-
// packages/parser/src/parser/rules/block/code/index.ts
|
|
3528
|
-
var codeBlockRule = {
|
|
3529
|
-
name: "code",
|
|
3530
|
-
startTokens: ["BLOCK_OPEN"],
|
|
3531
|
-
requiresLineStart: false,
|
|
3532
|
-
parse(ctx) {
|
|
3533
|
-
const openToken = currentToken(ctx);
|
|
3534
|
-
if (openToken.type !== "BLOCK_OPEN") {
|
|
3535
|
-
return { success: false };
|
|
3536
|
-
}
|
|
3537
|
-
let pos = ctx.pos + 1;
|
|
3538
|
-
let consumed = 1;
|
|
3539
|
-
const nameResult = parseBlockName(ctx, pos);
|
|
3540
|
-
if (!nameResult || nameResult.name !== "code") {
|
|
3541
|
-
return { success: false };
|
|
3542
|
-
}
|
|
3543
|
-
pos += nameResult.consumed;
|
|
3544
|
-
consumed += nameResult.consumed;
|
|
3545
|
-
const attrResult = parseAttributesRaw(ctx, pos);
|
|
3546
|
-
pos += attrResult.consumed;
|
|
3547
|
-
consumed += attrResult.consumed;
|
|
3548
|
-
let closingSwallowed = false;
|
|
3549
|
-
if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
|
|
3550
|
-
const repaired = repairSwallowedCodeClose(ctx, pos, attrResult.attrs);
|
|
3551
|
-
if (!repaired)
|
|
3552
|
-
return { success: false };
|
|
3553
|
-
closingSwallowed = repaired.closingSwallowed;
|
|
3554
|
-
} else {
|
|
3555
|
-
pos++;
|
|
3556
|
-
consumed++;
|
|
3557
|
-
}
|
|
3558
|
-
if (ctx.tokens[pos]?.type === "NEWLINE") {
|
|
3559
|
-
pos++;
|
|
3560
|
-
consumed++;
|
|
3561
|
-
}
|
|
3562
|
-
const contentResult = collectCodeContent(ctx, pos, closingSwallowed);
|
|
3563
|
-
let codeContent = contentResult.contents.replace(/\n$/, "");
|
|
3564
|
-
consumed += contentResult.consumed;
|
|
3565
|
-
pos += contentResult.consumed;
|
|
3566
|
-
if (!contentResult.foundClose) {
|
|
3567
|
-
ctx.diagnostics.push({
|
|
3568
|
-
severity: "warning",
|
|
3569
|
-
code: "unclosed-block",
|
|
3570
|
-
message: "Missing closing tag [[/code]] for [[code]]",
|
|
3571
|
-
position: openToken.position
|
|
3572
|
-
});
|
|
3573
|
-
}
|
|
3574
|
-
const codeBlockData = {
|
|
3575
|
-
contents: codeContent,
|
|
3576
|
-
language: attrResult.attrs.type ?? null,
|
|
3577
|
-
name: attrResult.attrs.name ?? null
|
|
3578
|
-
};
|
|
3579
|
-
ctx.codeBlocks.push(codeBlockData);
|
|
3580
|
-
const elements = [{ element: "code", data: codeBlockData }];
|
|
3581
|
-
if (ctx.tokens[pos]?.type === "NEWLINE" && !getParagraphNewlineBoundary(ctx, pos, false).shouldBreak && !ctx.scope.blockCloseCondition?.({ ...ctx, pos: pos + 1 })) {
|
|
3582
|
-
const after = parseInlineUntil({ ...ctx, pos: pos + 1 }, "PARAGRAPH_BREAK");
|
|
3583
|
-
elements.push({ element: "line-break" }, ...normalizeParagraphElements(after.elements));
|
|
3584
|
-
consumed += 1 + after.consumed;
|
|
3585
|
-
}
|
|
3586
|
-
return { success: true, elements, consumed };
|
|
3587
|
-
}
|
|
3588
|
-
};
|
|
3589
|
-
|
|
3590
4616
|
// packages/parser/src/parser/rules/block/collapsible/attributes.ts
|
|
3591
4617
|
function parseMultilineAttributes(ctx, startPos) {
|
|
3592
4618
|
const attrs = {};
|
|
@@ -4015,7 +5041,9 @@ function parseTableCell(ctx, startPos, cellStart) {
|
|
|
4015
5041
|
for (const rule of getCandidateInlineRules(inlineRules, token5.type)) {
|
|
4016
5042
|
const result = rule.parse(inlineCtx);
|
|
4017
5043
|
if (result.success) {
|
|
4018
|
-
children
|
|
5044
|
+
stripAutomaticLineBreak(children, result.stripLeadingLineBreak);
|
|
5045
|
+
for (const element of result.elements)
|
|
5046
|
+
children.push(element);
|
|
4019
5047
|
consumed += result.consumed;
|
|
4020
5048
|
pos += result.consumed;
|
|
4021
5049
|
matched = true;
|
|
@@ -4282,7 +5310,8 @@ function createCellContentAccumulator() {
|
|
|
4282
5310
|
addInline(element) {
|
|
4283
5311
|
currentSegment.push(element);
|
|
4284
5312
|
},
|
|
4285
|
-
addInlineElements(nextElements) {
|
|
5313
|
+
addInlineElements(nextElements, stripLeadingLineBreak) {
|
|
5314
|
+
stripAutomaticLineBreak(currentSegment, stripLeadingLineBreak);
|
|
4286
5315
|
currentSegment.push(...nextElements);
|
|
4287
5316
|
},
|
|
4288
5317
|
addBlockElements(blockElements) {
|
|
@@ -4382,7 +5411,7 @@ function consumeCellContentNewline(ctx, startPos, content) {
|
|
|
4382
5411
|
return { consumed };
|
|
4383
5412
|
}
|
|
4384
5413
|
if (!content.isEmpty()) {
|
|
4385
|
-
content.addInline(
|
|
5414
|
+
content.addInline(createAutomaticLineBreak(ctx.tokens[startPos]));
|
|
4386
5415
|
}
|
|
4387
5416
|
return { consumed };
|
|
4388
5417
|
}
|
|
@@ -4433,7 +5462,7 @@ function parseCellContent(ctx, closeCondition) {
|
|
|
4433
5462
|
for (const rule of getCandidateInlineRules(ctx.inlineRules, token5.type)) {
|
|
4434
5463
|
const result = rule.parse(inlineCtx);
|
|
4435
5464
|
if (result.success) {
|
|
4436
|
-
content.addInlineElements(result.elements);
|
|
5465
|
+
content.addInlineElements(result.elements, result.stripLeadingLineBreak);
|
|
4437
5466
|
consumed += result.consumed;
|
|
4438
5467
|
pos += result.consumed;
|
|
4439
5468
|
matched = true;
|
|
@@ -6853,7 +7882,7 @@ function resolveIfTags(data, pageTags) {
|
|
|
6853
7882
|
// packages/parser/src/parser/preprocess/utils/raw-regions.ts
|
|
6854
7883
|
var BASE_PLACEHOLDER_OPEN = "";
|
|
6855
7884
|
var BASE_PLACEHOLDER_CLOSE = "";
|
|
6856
|
-
var RAW_BLOCK_OPEN_PATTERN = /\[\[
|
|
7885
|
+
var RAW_BLOCK_OPEN_PATTERN = /\[\[html\b[^\]]*\]\]/iy;
|
|
6857
7886
|
function makeUniqueSentinels(source) {
|
|
6858
7887
|
let openRun = 0;
|
|
6859
7888
|
let closeRun = 0;
|
|
@@ -6872,10 +7901,21 @@ function makeUniqueSentinels(source) {
|
|
|
6872
7901
|
}
|
|
6873
7902
|
function maskRawRegions(source, sentinels) {
|
|
6874
7903
|
const placeholders = [];
|
|
7904
|
+
let tokens;
|
|
7905
|
+
const getTokens = () => tokens ??= tokenize(source);
|
|
6875
7906
|
let masked = "";
|
|
6876
7907
|
let i = 0;
|
|
6877
7908
|
while (i < source.length) {
|
|
6878
|
-
|
|
7909
|
+
if (source.startsWith("[!--", i)) {
|
|
7910
|
+
const close = source.indexOf("--]", i + 4);
|
|
7911
|
+
if (close !== -1) {
|
|
7912
|
+
const end = close + 3;
|
|
7913
|
+
masked += source.slice(i, end);
|
|
7914
|
+
i = end;
|
|
7915
|
+
continue;
|
|
7916
|
+
}
|
|
7917
|
+
}
|
|
7918
|
+
const rawBlock = tryMaskRawBlock(source, i, placeholders, sentinels, getTokens);
|
|
6879
7919
|
if (rawBlock) {
|
|
6880
7920
|
masked += rawBlock.placeholder;
|
|
6881
7921
|
i = rawBlock.end;
|
|
@@ -6896,16 +7936,25 @@ function restorePlaceholders(source, placeholders, sentinels) {
|
|
|
6896
7936
|
const pattern = new RegExp(`${escapeRegex(sentinels.open)}(\\d+)${escapeRegex(sentinels.close)}`, "g");
|
|
6897
7937
|
return source.replace(pattern, (_, idx) => placeholders[Number(idx)] ?? "");
|
|
6898
7938
|
}
|
|
6899
|
-
function tryMaskRawBlock(source, pos, placeholders, sentinels) {
|
|
7939
|
+
function tryMaskRawBlock(source, pos, placeholders, sentinels, getTokens) {
|
|
6900
7940
|
if (source[pos] !== "[" || source[pos + 1] !== "[")
|
|
6901
7941
|
return null;
|
|
7942
|
+
if (source.slice(pos, pos + 6).toLowerCase() === "[[code") {
|
|
7943
|
+
const tokens = getTokens();
|
|
7944
|
+
const start = tokenAtOffset(tokens, pos);
|
|
7945
|
+
const open = findCodeOpen(tokens, start);
|
|
7946
|
+
if (!open)
|
|
7947
|
+
return null;
|
|
7948
|
+
const bounds = open.closingSwallowed ? null : findCodeBodyBounds(tokens, open.bodyStart);
|
|
7949
|
+
const end = open.closingSwallowed ? tokens[open.attributesEnd - 1].position.end.offset : bounds.foundClose ? tokens[bounds.end - 1].position.end.offset : source.length;
|
|
7950
|
+
return { placeholder: pushPlaceholder(placeholders, source.slice(pos, end), sentinels), end };
|
|
7951
|
+
}
|
|
6902
7952
|
RAW_BLOCK_OPEN_PATTERN.lastIndex = pos;
|
|
6903
7953
|
const openMatch = RAW_BLOCK_OPEN_PATTERN.exec(source);
|
|
6904
7954
|
if (!openMatch)
|
|
6905
7955
|
return null;
|
|
6906
|
-
const name = openMatch[1].toLowerCase();
|
|
6907
7956
|
const openLen = openMatch[0].length;
|
|
6908
|
-
const closePattern =
|
|
7957
|
+
const closePattern = /\[\[\/\s*html\s*\]\]/gi;
|
|
6909
7958
|
closePattern.lastIndex = pos + openLen;
|
|
6910
7959
|
const closeMatch = closePattern.exec(source);
|
|
6911
7960
|
if (closeMatch) {
|
|
@@ -6915,12 +7964,19 @@ function tryMaskRawBlock(source, pos, placeholders, sentinels) {
|
|
|
6915
7964
|
end
|
|
6916
7965
|
};
|
|
6917
7966
|
}
|
|
6918
|
-
|
|
6919
|
-
|
|
6920
|
-
|
|
6921
|
-
|
|
6922
|
-
|
|
6923
|
-
|
|
7967
|
+
return null;
|
|
7968
|
+
}
|
|
7969
|
+
function tokenAtOffset(tokens, offset) {
|
|
7970
|
+
let low = 0;
|
|
7971
|
+
let high = tokens.length;
|
|
7972
|
+
while (low < high) {
|
|
7973
|
+
const middle = Math.floor((low + high) / 2);
|
|
7974
|
+
if (tokens[middle].position.start.offset < offset)
|
|
7975
|
+
low = middle + 1;
|
|
7976
|
+
else
|
|
7977
|
+
high = middle;
|
|
7978
|
+
}
|
|
7979
|
+
return tokens[low]?.position.start.offset === offset ? low : tokens.length;
|
|
6924
7980
|
}
|
|
6925
7981
|
function tryMaskRawInline(source, pos, placeholders, sentinels) {
|
|
6926
7982
|
if (source[pos] === "@" && source[pos + 1] === "<") {
|
|
@@ -6932,17 +7988,22 @@ function tryMaskRawInline(source, pos, placeholders, sentinels) {
|
|
|
6932
7988
|
return null;
|
|
6933
7989
|
}
|
|
6934
7990
|
function tryMaskSingleLineRaw(source, pos, openerLength, close, placeholders, sentinels) {
|
|
6935
|
-
const
|
|
6936
|
-
|
|
6937
|
-
`, pos + openerLength);
|
|
6938
|
-
if (closePos === -1 || newline !== -1 && newline < closePos)
|
|
7991
|
+
const end = singleLineRawEnd(source, pos, openerLength, close);
|
|
7992
|
+
if (end === pos)
|
|
6939
7993
|
return null;
|
|
6940
|
-
const end = closePos + close.length;
|
|
6941
7994
|
return {
|
|
6942
7995
|
placeholder: pushPlaceholder(placeholders, source.slice(pos, end), sentinels),
|
|
6943
7996
|
end
|
|
6944
7997
|
};
|
|
6945
7998
|
}
|
|
7999
|
+
function singleLineRawEnd(source, pos, openerLength, close) {
|
|
8000
|
+
const closePos = source.indexOf(close, pos + openerLength);
|
|
8001
|
+
const newline = source.indexOf(`
|
|
8002
|
+
`, pos + openerLength);
|
|
8003
|
+
if (closePos === -1 || newline !== -1 && newline < closePos)
|
|
8004
|
+
return pos;
|
|
8005
|
+
return closePos + close.length;
|
|
8006
|
+
}
|
|
6946
8007
|
function pushPlaceholder(placeholders, text, sentinels) {
|
|
6947
8008
|
const idx = placeholders.length;
|
|
6948
8009
|
placeholders.push(text);
|
|
@@ -9109,167 +10170,32 @@ function parseVariables(tokens) {
|
|
|
9109
10170
|
for (const token5 of tokens) {
|
|
9110
10171
|
if (token5 === "|") {
|
|
9111
10172
|
assignVariable(vars, current2);
|
|
9112
|
-
current2 = "";
|
|
9113
|
-
} else {
|
|
9114
|
-
current2 += token5;
|
|
9115
|
-
}
|
|
9116
|
-
}
|
|
9117
|
-
assignVariable(vars, current2);
|
|
9118
|
-
return vars;
|
|
9119
|
-
}
|
|
9120
|
-
function assignVariable(vars, source) {
|
|
9121
|
-
if (!source.trim()) {
|
|
9122
|
-
return;
|
|
9123
|
-
}
|
|
9124
|
-
const eqIndex = source.indexOf("=");
|
|
9125
|
-
if (eqIndex === -1) {
|
|
9126
|
-
return;
|
|
9127
|
-
}
|
|
9128
|
-
const key = source.slice(0, eqIndex).trim();
|
|
9129
|
-
if (!key) {
|
|
9130
|
-
return;
|
|
9131
|
-
}
|
|
9132
|
-
vars[key] = source.slice(eqIndex + 1).trim();
|
|
9133
|
-
}
|
|
9134
|
-
|
|
9135
|
-
// packages/parser/src/parser/rules/block/include/index.ts
|
|
9136
|
-
var includeRule = {
|
|
9137
|
-
name: "include",
|
|
9138
|
-
startTokens: ["BLOCK_OPEN"],
|
|
9139
|
-
requiresLineStart: false,
|
|
9140
|
-
parse(ctx) {
|
|
9141
|
-
const openToken = currentToken(ctx);
|
|
9142
|
-
if (openToken.type !== "BLOCK_OPEN") {
|
|
9143
|
-
return { success: false };
|
|
9144
|
-
}
|
|
9145
|
-
let pos = ctx.pos + 1;
|
|
9146
|
-
let consumed = 1;
|
|
9147
|
-
const nameResult = parseBlockName(ctx, pos);
|
|
9148
|
-
if (!nameResult || nameResult.name.toLowerCase() !== "include") {
|
|
9149
|
-
return { success: false };
|
|
9150
|
-
}
|
|
9151
|
-
if (!ctx.settings.enablePageSyntax) {
|
|
9152
|
-
return { success: false };
|
|
9153
|
-
}
|
|
9154
|
-
pos += nameResult.consumed;
|
|
9155
|
-
consumed += nameResult.consumed;
|
|
9156
|
-
while (ctx.tokens[pos]?.type === "WHITESPACE") {
|
|
9157
|
-
pos++;
|
|
9158
|
-
consumed++;
|
|
9159
|
-
}
|
|
9160
|
-
const args = collectIncludeArguments(ctx, pos);
|
|
9161
|
-
pos += args.consumed;
|
|
9162
|
-
consumed += args.consumed;
|
|
9163
|
-
if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
|
|
9164
|
-
return { success: false };
|
|
9165
|
-
}
|
|
9166
|
-
pos++;
|
|
9167
|
-
consumed++;
|
|
9168
|
-
const directiveEnd = pos;
|
|
9169
|
-
if (ctx.tokens[pos]?.type === "NEWLINE") {
|
|
9170
|
-
pos++;
|
|
9171
|
-
consumed++;
|
|
9172
|
-
}
|
|
9173
|
-
if (!args.target) {
|
|
9174
|
-
return { success: false };
|
|
9175
|
-
}
|
|
9176
|
-
const location = parsePageRef(args.target);
|
|
9177
|
-
if (ctx.deferInclude?.(location)) {
|
|
9178
|
-
const source = ctx.tokens.slice(ctx.pos, directiveEnd).map((token5) => token5.value).join("");
|
|
9179
|
-
const elements = [];
|
|
9180
|
-
const lines = source.split(`
|
|
9181
|
-
`);
|
|
9182
|
-
for (let index = 0;index < lines.length; index++) {
|
|
9183
|
-
if (index > 0)
|
|
9184
|
-
elements.push(import_ast5.lineBreak());
|
|
9185
|
-
if (lines[index] !== "")
|
|
9186
|
-
elements.push(import_ast5.text(lines[index]));
|
|
9187
|
-
}
|
|
9188
|
-
return { success: true, elements: [import_ast5.paragraph(elements)], consumed };
|
|
9189
|
-
}
|
|
9190
|
-
return {
|
|
9191
|
-
success: true,
|
|
9192
|
-
elements: [
|
|
9193
|
-
{
|
|
9194
|
-
element: "include",
|
|
9195
|
-
data: {
|
|
9196
|
-
"paragraph-safe": false,
|
|
9197
|
-
variables: parseVariables(args.argumentTokens),
|
|
9198
|
-
location,
|
|
9199
|
-
elements: []
|
|
9200
|
-
}
|
|
9201
|
-
}
|
|
9202
|
-
],
|
|
9203
|
-
consumed
|
|
9204
|
-
};
|
|
9205
|
-
}
|
|
9206
|
-
};
|
|
9207
|
-
|
|
9208
|
-
// packages/parser/src/parser/rules/block/math/content.ts
|
|
9209
|
-
function collectMathContent(ctx, startPos) {
|
|
9210
|
-
let latexSource = "";
|
|
9211
|
-
let pos = startPos;
|
|
9212
|
-
let consumed = 0;
|
|
9213
|
-
let foundClose = false;
|
|
9214
|
-
while (pos < ctx.tokens.length) {
|
|
9215
|
-
const token5 = ctx.tokens[pos];
|
|
9216
|
-
if (!token5)
|
|
9217
|
-
break;
|
|
9218
|
-
if (token5.type === "BLOCK_END_OPEN") {
|
|
9219
|
-
const closeNameResult = parseBlockName(ctx, pos + 1);
|
|
9220
|
-
if (closeNameResult?.name === "math") {
|
|
9221
|
-
foundClose = true;
|
|
9222
|
-
break;
|
|
9223
|
-
}
|
|
9224
|
-
}
|
|
9225
|
-
latexSource += token5.type === "BACKSLASH_BREAK" ? "\\\n" : token5.value;
|
|
9226
|
-
pos++;
|
|
9227
|
-
consumed++;
|
|
9228
|
-
}
|
|
9229
|
-
return { latexSource, consumed, foundClose };
|
|
9230
|
-
}
|
|
9231
|
-
function consumeMathClose(ctx, startPos) {
|
|
9232
|
-
let pos = startPos + 1;
|
|
9233
|
-
let consumed = 1;
|
|
9234
|
-
const closeNameResult = parseBlockName(ctx, pos);
|
|
9235
|
-
if (closeNameResult) {
|
|
9236
|
-
pos += closeNameResult.consumed;
|
|
9237
|
-
consumed += closeNameResult.consumed;
|
|
9238
|
-
}
|
|
9239
|
-
if (ctx.tokens[pos]?.type === "BLOCK_CLOSE") {
|
|
9240
|
-
pos++;
|
|
9241
|
-
consumed++;
|
|
9242
|
-
}
|
|
9243
|
-
if (ctx.tokens[pos]?.type === "NEWLINE") {
|
|
9244
|
-
consumed++;
|
|
10173
|
+
current2 = "";
|
|
10174
|
+
} else {
|
|
10175
|
+
current2 += token5;
|
|
10176
|
+
}
|
|
9245
10177
|
}
|
|
9246
|
-
|
|
10178
|
+
assignVariable(vars, current2);
|
|
10179
|
+
return vars;
|
|
9247
10180
|
}
|
|
9248
|
-
|
|
9249
|
-
|
|
9250
|
-
|
|
9251
|
-
let pos = startPos;
|
|
9252
|
-
let consumed = 0;
|
|
9253
|
-
let name = "";
|
|
9254
|
-
const first = ctx.tokens[pos];
|
|
9255
|
-
if (first?.type !== "IDENTIFIER" && first?.type !== "TEXT") {
|
|
9256
|
-
return { name: null, consumed: 0 };
|
|
10181
|
+
function assignVariable(vars, source) {
|
|
10182
|
+
if (!source.trim()) {
|
|
10183
|
+
return;
|
|
9257
10184
|
}
|
|
9258
|
-
|
|
9259
|
-
|
|
9260
|
-
|
|
9261
|
-
|
|
9262
|
-
|
|
9263
|
-
|
|
9264
|
-
|
|
9265
|
-
consumed++;
|
|
10185
|
+
const eqIndex = source.indexOf("=");
|
|
10186
|
+
if (eqIndex === -1) {
|
|
10187
|
+
return;
|
|
10188
|
+
}
|
|
10189
|
+
const key = source.slice(0, eqIndex).trim();
|
|
10190
|
+
if (!key) {
|
|
10191
|
+
return;
|
|
9266
10192
|
}
|
|
9267
|
-
|
|
10193
|
+
vars[key] = source.slice(eqIndex + 1).trim();
|
|
9268
10194
|
}
|
|
9269
10195
|
|
|
9270
|
-
// packages/parser/src/parser/rules/block/
|
|
9271
|
-
var
|
|
9272
|
-
name: "
|
|
10196
|
+
// packages/parser/src/parser/rules/block/include/index.ts
|
|
10197
|
+
var includeRule = {
|
|
10198
|
+
name: "include",
|
|
9273
10199
|
startTokens: ["BLOCK_OPEN"],
|
|
9274
10200
|
requiresLineStart: false,
|
|
9275
10201
|
parse(ctx) {
|
|
@@ -9280,7 +10206,10 @@ var mathBlockRule = {
|
|
|
9280
10206
|
let pos = ctx.pos + 1;
|
|
9281
10207
|
let consumed = 1;
|
|
9282
10208
|
const nameResult = parseBlockName(ctx, pos);
|
|
9283
|
-
if (!nameResult || nameResult.name !== "
|
|
10209
|
+
if (!nameResult || nameResult.name.toLowerCase() !== "include") {
|
|
10210
|
+
return { success: false };
|
|
10211
|
+
}
|
|
10212
|
+
if (!ctx.settings.enablePageSyntax) {
|
|
9284
10213
|
return { success: false };
|
|
9285
10214
|
}
|
|
9286
10215
|
pos += nameResult.consumed;
|
|
@@ -9289,49 +10218,46 @@ var mathBlockRule = {
|
|
|
9289
10218
|
pos++;
|
|
9290
10219
|
consumed++;
|
|
9291
10220
|
}
|
|
9292
|
-
const
|
|
9293
|
-
pos +=
|
|
9294
|
-
consumed +=
|
|
9295
|
-
while (ctx.tokens[pos]?.type === "WHITESPACE") {
|
|
9296
|
-
pos++;
|
|
9297
|
-
consumed++;
|
|
9298
|
-
}
|
|
10221
|
+
const args = collectIncludeArguments(ctx, pos);
|
|
10222
|
+
pos += args.consumed;
|
|
10223
|
+
consumed += args.consumed;
|
|
9299
10224
|
if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
|
|
9300
10225
|
return { success: false };
|
|
9301
10226
|
}
|
|
9302
10227
|
pos++;
|
|
9303
10228
|
consumed++;
|
|
10229
|
+
const directiveEnd = pos;
|
|
9304
10230
|
if (ctx.tokens[pos]?.type === "NEWLINE") {
|
|
9305
10231
|
pos++;
|
|
9306
10232
|
consumed++;
|
|
9307
10233
|
}
|
|
9308
|
-
|
|
9309
|
-
const latexSource = contentResult.latexSource.trim();
|
|
9310
|
-
consumed += contentResult.consumed;
|
|
9311
|
-
pos += contentResult.consumed;
|
|
9312
|
-
if (!contentResult.foundClose) {
|
|
9313
|
-
ctx.diagnostics.push({
|
|
9314
|
-
severity: "warning",
|
|
9315
|
-
code: "unclosed-block",
|
|
9316
|
-
message: "Missing closing tag [[/math]] for [[math]]",
|
|
9317
|
-
position: openToken.position
|
|
9318
|
-
});
|
|
9319
|
-
} else {
|
|
9320
|
-
const closeConsumed = consumeMathClose(ctx, pos);
|
|
9321
|
-
pos += closeConsumed;
|
|
9322
|
-
consumed += closeConsumed;
|
|
9323
|
-
}
|
|
9324
|
-
if (!latexSource) {
|
|
10234
|
+
if (!args.target) {
|
|
9325
10235
|
return { success: false };
|
|
9326
10236
|
}
|
|
10237
|
+
const location = parsePageRef(args.target);
|
|
10238
|
+
if (ctx.deferInclude?.(location)) {
|
|
10239
|
+
const source = ctx.tokens.slice(ctx.pos, directiveEnd).map((token5) => token5.value).join("");
|
|
10240
|
+
const elements = [];
|
|
10241
|
+
const lines = source.split(`
|
|
10242
|
+
`);
|
|
10243
|
+
for (let index = 0;index < lines.length; index++) {
|
|
10244
|
+
if (index > 0)
|
|
10245
|
+
elements.push(import_ast5.lineBreak());
|
|
10246
|
+
if (lines[index] !== "")
|
|
10247
|
+
elements.push(import_ast5.text(lines[index]));
|
|
10248
|
+
}
|
|
10249
|
+
return { success: true, elements: [import_ast5.paragraph(elements)], consumed };
|
|
10250
|
+
}
|
|
9327
10251
|
return {
|
|
9328
10252
|
success: true,
|
|
9329
10253
|
elements: [
|
|
9330
10254
|
{
|
|
9331
|
-
element: "
|
|
10255
|
+
element: "include",
|
|
9332
10256
|
data: {
|
|
9333
|
-
|
|
9334
|
-
|
|
10257
|
+
"paragraph-safe": false,
|
|
10258
|
+
variables: parseVariables(args.argumentTokens),
|
|
10259
|
+
location,
|
|
10260
|
+
elements: []
|
|
9335
10261
|
}
|
|
9336
10262
|
}
|
|
9337
10263
|
],
|
|
@@ -10201,7 +11127,8 @@ function parseBibliographyContent(ctx, startPos) {
|
|
|
10201
11127
|
const inlineCtx = { ...ctx, pos };
|
|
10202
11128
|
const result = parseInlineUntil(inlineCtx, "NEWLINE");
|
|
10203
11129
|
if (result.elements.length > 0) {
|
|
10204
|
-
|
|
11130
|
+
for (const element of result.elements)
|
|
11131
|
+
content.push(element);
|
|
10205
11132
|
pos += result.consumed;
|
|
10206
11133
|
consumed += result.consumed;
|
|
10207
11134
|
} else {
|
|
@@ -10630,6 +11557,7 @@ var blockRules = [
|
|
|
10630
11557
|
iftagsRule,
|
|
10631
11558
|
bibliographyRule,
|
|
10632
11559
|
galleryRule,
|
|
11560
|
+
noteRule,
|
|
10633
11561
|
divRule
|
|
10634
11562
|
];
|
|
10635
11563
|
// packages/parser/src/parser/rules/inline/formatting/close.ts
|
|
@@ -10642,6 +11570,11 @@ function findFormattingClose(ctx, start, marker) {
|
|
|
10642
11570
|
return null;
|
|
10643
11571
|
if (!table && token5.type === "NEWLINE" && getParagraphNewlineBoundary(ctx, pos, true).shouldBreak)
|
|
10644
11572
|
return null;
|
|
11573
|
+
const inlineRegionEnd = Math.max(emailRegionEnd(ctx.tokens, pos, end), parseButtonSyntax(ctx, pos, end)?.end ?? pos, parseSocialSyntax(ctx, pos, end)?.end ?? pos);
|
|
11574
|
+
if (inlineRegionEnd > pos) {
|
|
11575
|
+
pos = inlineRegionEnd - 1;
|
|
11576
|
+
continue;
|
|
11577
|
+
}
|
|
10645
11578
|
if (token5.type === marker && !table?.suppressedClosers.has(pos))
|
|
10646
11579
|
return pos;
|
|
10647
11580
|
const protectedEnd = protectedInlineRegionEnd(ctx.tokens, pos, end);
|
|
@@ -10687,253 +11620,93 @@ function parseDelimitedContainer(ctx, closeToken, type, options = {}) {
|
|
|
10687
11620
|
consumed
|
|
10688
11621
|
};
|
|
10689
11622
|
}
|
|
10690
|
-
return {
|
|
10691
|
-
success: true,
|
|
10692
|
-
elements: [createInlineContainer(type, result.elements)],
|
|
10693
|
-
consumed
|
|
10694
|
-
};
|
|
10695
|
-
}
|
|
10696
|
-
|
|
10697
|
-
// packages/parser/src/parser/rules/inline/bold.ts
|
|
10698
|
-
var boldRule = {
|
|
10699
|
-
name: "bold",
|
|
10700
|
-
startTokens: ["BOLD_MARKER"],
|
|
10701
|
-
parse(ctx) {
|
|
10702
|
-
return parseDelimitedContainer(ctx, "BOLD_MARKER", "bold", { discardEmpty: true });
|
|
10703
|
-
}
|
|
10704
|
-
};
|
|
10705
|
-
|
|
10706
|
-
// packages/parser/src/parser/rules/inline/italic.ts
|
|
10707
|
-
var italicRule = {
|
|
10708
|
-
name: "italic",
|
|
10709
|
-
startTokens: ["ITALIC_MARKER"],
|
|
10710
|
-
parse(ctx) {
|
|
10711
|
-
return parseDelimitedContainer(ctx, "ITALIC_MARKER", "italics");
|
|
10712
|
-
}
|
|
10713
|
-
};
|
|
10714
|
-
|
|
10715
|
-
// packages/parser/src/parser/rules/inline/underline/index.ts
|
|
10716
|
-
var underlineRule = {
|
|
10717
|
-
name: "underline",
|
|
10718
|
-
startTokens: ["UNDERLINE_MARKER"],
|
|
10719
|
-
parse(ctx) {
|
|
10720
|
-
return parseDelimitedContainer(ctx, "UNDERLINE_MARKER", "underline", { discardEmpty: true });
|
|
10721
|
-
}
|
|
10722
|
-
};
|
|
10723
|
-
|
|
10724
|
-
// packages/parser/src/parser/rules/inline/strikethrough/parse.ts
|
|
10725
|
-
function parseStrikethroughContent(ctx) {
|
|
10726
|
-
return parseDelimitedContainer(ctx, "STRIKE_MARKER", "strikethrough");
|
|
10727
|
-
}
|
|
10728
|
-
|
|
10729
|
-
// packages/parser/src/parser/rules/inline/strikethrough/syntax.ts
|
|
10730
|
-
function hasValidStrikethroughClose(ctx) {
|
|
10731
|
-
const close = findFormattingClose(ctx, ctx.pos + 1, "STRIKE_MARKER");
|
|
10732
|
-
return close !== null && close > ctx.pos + 1 && ctx.tokens[close - 1]?.type !== "WHITESPACE";
|
|
10733
|
-
}
|
|
10734
|
-
|
|
10735
|
-
// packages/parser/src/parser/rules/inline/strikethrough/index.ts
|
|
10736
|
-
var strikethroughRule = {
|
|
10737
|
-
name: "strikethrough",
|
|
10738
|
-
startTokens: ["STRIKE_MARKER"],
|
|
10739
|
-
parse(ctx) {
|
|
10740
|
-
if (!hasValidStrikethroughClose(ctx)) {
|
|
10741
|
-
return {
|
|
10742
|
-
success: true,
|
|
10743
|
-
elements: [{ element: "text", data: "—" }],
|
|
10744
|
-
consumed: 1
|
|
10745
|
-
};
|
|
10746
|
-
}
|
|
10747
|
-
return parseStrikethroughContent(ctx);
|
|
10748
|
-
}
|
|
10749
|
-
};
|
|
10750
|
-
|
|
10751
|
-
// packages/parser/src/parser/rules/inline/superscript.ts
|
|
10752
|
-
var superscriptRule = {
|
|
10753
|
-
name: "superscript",
|
|
10754
|
-
startTokens: ["SUPER_MARKER"],
|
|
10755
|
-
parse(ctx) {
|
|
10756
|
-
return parseDelimitedContainer(ctx, "SUPER_MARKER", "superscript", {
|
|
10757
|
-
discardEmpty: true
|
|
10758
|
-
});
|
|
10759
|
-
}
|
|
10760
|
-
};
|
|
10761
|
-
|
|
10762
|
-
// packages/parser/src/parser/rules/inline/subscript.ts
|
|
10763
|
-
var subscriptRule = {
|
|
10764
|
-
name: "subscript",
|
|
10765
|
-
startTokens: ["SUB_MARKER"],
|
|
10766
|
-
parse(ctx) {
|
|
10767
|
-
return parseDelimitedContainer(ctx, "SUB_MARKER", "subscript", { discardEmpty: true });
|
|
10768
|
-
}
|
|
10769
|
-
};
|
|
10770
|
-
|
|
10771
|
-
// packages/parser/src/parser/rules/inline/monospace.ts
|
|
10772
|
-
var monospaceRule = {
|
|
10773
|
-
name: "monospace",
|
|
10774
|
-
startTokens: ["MONO_MARKER"],
|
|
10775
|
-
parse(ctx) {
|
|
10776
|
-
return parseDelimitedContainer(ctx, "MONO_CLOSE", "monospace");
|
|
10777
|
-
}
|
|
10778
|
-
};
|
|
10779
|
-
|
|
10780
|
-
// packages/parser/src/parser/rules/inline/link-triple/fallback.ts
|
|
10781
|
-
function literalOpenLink(value) {
|
|
10782
|
-
return {
|
|
10783
|
-
success: true,
|
|
10784
|
-
elements: [{ element: "text", data: value }],
|
|
10785
|
-
consumed: 1
|
|
10786
|
-
};
|
|
10787
|
-
}
|
|
10788
|
-
|
|
10789
|
-
// packages/parser/src/parser/rules/inline/link-triple/label.ts
|
|
10790
|
-
function buildTripleLinkLabel(args) {
|
|
10791
|
-
return {
|
|
10792
|
-
text: getTripleLinkDisplayText(args)
|
|
10793
|
-
};
|
|
10794
|
-
}
|
|
10795
|
-
function getTripleLinkDisplayText(args) {
|
|
10796
|
-
const trimmedLabel = args.labelText.trim();
|
|
10797
|
-
if (args.foundPipe) {
|
|
10798
|
-
return trimmedLabel || args.finalTarget;
|
|
10799
|
-
}
|
|
10800
|
-
const colonIdx = args.originalTarget.indexOf(":");
|
|
10801
|
-
if (colonIdx !== -1 && !args.originalTarget.startsWith("http") && !args.originalTarget.startsWith("*")) {
|
|
10802
|
-
return args.originalTarget.slice(colonIdx + 1).trim();
|
|
10803
|
-
}
|
|
10804
|
-
return args.originalTarget;
|
|
10805
|
-
}
|
|
10806
|
-
|
|
10807
|
-
// packages/parser/src/parser/rules/inline/link-triple/syntax.ts
|
|
10808
|
-
function hasClosingLinkMarker(ctx, startPos) {
|
|
10809
|
-
let pos = startPos;
|
|
10810
|
-
while (pos < ctx.tokens.length) {
|
|
10811
|
-
const token5 = ctx.tokens[pos];
|
|
10812
|
-
if (!token5 || token5.type === "EOF") {
|
|
10813
|
-
return false;
|
|
10814
|
-
}
|
|
10815
|
-
if (token5.type === "LINK_CLOSE") {
|
|
10816
|
-
return true;
|
|
10817
|
-
}
|
|
10818
|
-
if (token5.type === "NEWLINE") {
|
|
10819
|
-
const next = ctx.tokens[pos + 1];
|
|
10820
|
-
if (next?.type === "NEWLINE" || next?.type === "LINK_CLOSE") {
|
|
10821
|
-
return false;
|
|
10822
|
-
}
|
|
10823
|
-
}
|
|
10824
|
-
pos++;
|
|
10825
|
-
}
|
|
10826
|
-
return false;
|
|
10827
|
-
}
|
|
10828
|
-
function collectTripleLinkParts(ctx, startPos) {
|
|
10829
|
-
let target = "";
|
|
10830
|
-
let labelText = "";
|
|
10831
|
-
let foundPipe = false;
|
|
10832
|
-
let consumed = 1;
|
|
10833
|
-
let pos = startPos;
|
|
10834
|
-
while (pos < ctx.tokens.length) {
|
|
10835
|
-
const token5 = ctx.tokens[pos];
|
|
10836
|
-
if (!token5 || token5.type === "LINK_CLOSE" || token5.type === "EOF") {
|
|
10837
|
-
break;
|
|
10838
|
-
}
|
|
10839
|
-
if (token5.type === "NEWLINE") {
|
|
10840
|
-
if (foundPipe) {
|
|
10841
|
-
labelText += " ";
|
|
10842
|
-
} else {
|
|
10843
|
-
target += " ";
|
|
10844
|
-
}
|
|
10845
|
-
consumed++;
|
|
10846
|
-
pos++;
|
|
10847
|
-
continue;
|
|
10848
|
-
}
|
|
10849
|
-
if (token5.type === "PIPE" && !foundPipe) {
|
|
10850
|
-
foundPipe = true;
|
|
10851
|
-
} else if (foundPipe) {
|
|
10852
|
-
labelText += token5.value;
|
|
10853
|
-
} else {
|
|
10854
|
-
target += token5.value;
|
|
10855
|
-
}
|
|
10856
|
-
consumed++;
|
|
10857
|
-
pos++;
|
|
10858
|
-
}
|
|
10859
|
-
if (ctx.tokens[pos]?.type === "LINK_CLOSE") {
|
|
10860
|
-
consumed++;
|
|
10861
|
-
}
|
|
10862
|
-
return { target, labelText, foundPipe, consumed };
|
|
11623
|
+
return {
|
|
11624
|
+
success: true,
|
|
11625
|
+
elements: [createInlineContainer(type, result.elements)],
|
|
11626
|
+
consumed
|
|
11627
|
+
};
|
|
10863
11628
|
}
|
|
10864
11629
|
|
|
10865
|
-
// packages/parser/src/parser/rules/inline/
|
|
10866
|
-
var
|
|
10867
|
-
|
|
10868
|
-
|
|
10869
|
-
|
|
10870
|
-
return
|
|
11630
|
+
// packages/parser/src/parser/rules/inline/bold.ts
|
|
11631
|
+
var boldRule = {
|
|
11632
|
+
name: "bold",
|
|
11633
|
+
startTokens: ["BOLD_MARKER"],
|
|
11634
|
+
parse(ctx) {
|
|
11635
|
+
return parseDelimitedContainer(ctx, "BOLD_MARKER", "bold", { discardEmpty: true });
|
|
10871
11636
|
}
|
|
10872
|
-
|
|
10873
|
-
return INTERWIKI_PREFIXES.has(prefix);
|
|
10874
|
-
}
|
|
11637
|
+
};
|
|
10875
11638
|
|
|
10876
|
-
// packages/parser/src/parser/rules/inline/
|
|
10877
|
-
|
|
10878
|
-
|
|
10879
|
-
|
|
11639
|
+
// packages/parser/src/parser/rules/inline/italic.ts
|
|
11640
|
+
var italicRule = {
|
|
11641
|
+
name: "italic",
|
|
11642
|
+
startTokens: ["ITALIC_MARKER"],
|
|
11643
|
+
parse(ctx) {
|
|
11644
|
+
return parseDelimitedContainer(ctx, "ITALIC_MARKER", "italics");
|
|
10880
11645
|
}
|
|
10881
|
-
|
|
11646
|
+
};
|
|
11647
|
+
|
|
11648
|
+
// packages/parser/src/parser/rules/inline/underline/index.ts
|
|
11649
|
+
var underlineRule = {
|
|
11650
|
+
name: "underline",
|
|
11651
|
+
startTokens: ["UNDERLINE_MARKER"],
|
|
11652
|
+
parse(ctx) {
|
|
11653
|
+
return parseDelimitedContainer(ctx, "UNDERLINE_MARKER", "underline", { discardEmpty: true });
|
|
11654
|
+
}
|
|
11655
|
+
};
|
|
11656
|
+
|
|
11657
|
+
// packages/parser/src/parser/rules/inline/strikethrough/parse.ts
|
|
11658
|
+
function parseStrikethroughContent(ctx) {
|
|
11659
|
+
return parseDelimitedContainer(ctx, "STRIKE_MARKER", "strikethrough");
|
|
10882
11660
|
}
|
|
10883
|
-
|
|
10884
|
-
|
|
11661
|
+
|
|
11662
|
+
// packages/parser/src/parser/rules/inline/strikethrough/syntax.ts
|
|
11663
|
+
function hasValidStrikethroughClose(ctx) {
|
|
11664
|
+
const close = findFormattingClose(ctx, ctx.pos + 1, "STRIKE_MARKER");
|
|
11665
|
+
return close !== null && close > ctx.pos + 1 && ctx.tokens[close - 1]?.type !== "WHITESPACE";
|
|
10885
11666
|
}
|
|
10886
|
-
|
|
10887
|
-
|
|
10888
|
-
|
|
11667
|
+
|
|
11668
|
+
// packages/parser/src/parser/rules/inline/strikethrough/index.ts
|
|
11669
|
+
var strikethroughRule = {
|
|
11670
|
+
name: "strikethrough",
|
|
11671
|
+
startTokens: ["STRIKE_MARKER"],
|
|
11672
|
+
parse(ctx) {
|
|
11673
|
+
if (!hasValidStrikethroughClose(ctx)) {
|
|
11674
|
+
return {
|
|
11675
|
+
success: true,
|
|
11676
|
+
elements: [{ element: "text", data: "—" }],
|
|
11677
|
+
consumed: 1
|
|
11678
|
+
};
|
|
11679
|
+
}
|
|
11680
|
+
return parseStrikethroughContent(ctx);
|
|
10889
11681
|
}
|
|
10890
|
-
|
|
10891
|
-
|
|
11682
|
+
};
|
|
11683
|
+
|
|
11684
|
+
// packages/parser/src/parser/rules/inline/superscript.ts
|
|
11685
|
+
var superscriptRule = {
|
|
11686
|
+
name: "superscript",
|
|
11687
|
+
startTokens: ["SUPER_MARKER"],
|
|
11688
|
+
parse(ctx) {
|
|
11689
|
+
return parseDelimitedContainer(ctx, "SUPER_MARKER", "superscript", {
|
|
11690
|
+
discardEmpty: true
|
|
11691
|
+
});
|
|
10892
11692
|
}
|
|
10893
|
-
|
|
10894
|
-
|
|
11693
|
+
};
|
|
11694
|
+
|
|
11695
|
+
// packages/parser/src/parser/rules/inline/subscript.ts
|
|
11696
|
+
var subscriptRule = {
|
|
11697
|
+
name: "subscript",
|
|
11698
|
+
startTokens: ["SUB_MARKER"],
|
|
11699
|
+
parse(ctx) {
|
|
11700
|
+
return parseDelimitedContainer(ctx, "SUB_MARKER", "subscript", { discardEmpty: true });
|
|
10895
11701
|
}
|
|
10896
|
-
|
|
10897
|
-
}
|
|
11702
|
+
};
|
|
10898
11703
|
|
|
10899
|
-
// packages/parser/src/parser/rules/inline/
|
|
10900
|
-
var
|
|
10901
|
-
name: "
|
|
10902
|
-
startTokens: ["
|
|
11704
|
+
// packages/parser/src/parser/rules/inline/monospace.ts
|
|
11705
|
+
var monospaceRule = {
|
|
11706
|
+
name: "monospace",
|
|
11707
|
+
startTokens: ["MONO_MARKER"],
|
|
10903
11708
|
parse(ctx) {
|
|
10904
|
-
|
|
10905
|
-
if (!hasClosingLinkMarker(ctx, ctx.pos + 1)) {
|
|
10906
|
-
return literalOpenLink(startToken.value);
|
|
10907
|
-
}
|
|
10908
|
-
const parts = collectTripleLinkParts(ctx, ctx.pos + 1);
|
|
10909
|
-
const trimmedTarget = parts.target.trim();
|
|
10910
|
-
if (isInvalidTripleLinkTarget(trimmedTarget, parts.foundPipe)) {
|
|
10911
|
-
return literalOpenLink(startToken.value);
|
|
10912
|
-
}
|
|
10913
|
-
const normalized = normalizeTripleLinkTarget(trimmedTarget);
|
|
10914
|
-
const { linkType, link } = determineLinkTypeAndLocation(normalized.target);
|
|
10915
|
-
const label = buildTripleLinkLabel({
|
|
10916
|
-
foundPipe: parts.foundPipe,
|
|
10917
|
-
labelText: parts.labelText,
|
|
10918
|
-
finalTarget: normalized.target,
|
|
10919
|
-
originalTarget: trimmedTarget
|
|
10920
|
-
});
|
|
10921
|
-
return {
|
|
10922
|
-
success: true,
|
|
10923
|
-
elements: [
|
|
10924
|
-
{
|
|
10925
|
-
element: "link",
|
|
10926
|
-
data: {
|
|
10927
|
-
type: linkType,
|
|
10928
|
-
link,
|
|
10929
|
-
extra: null,
|
|
10930
|
-
label,
|
|
10931
|
-
target: normalized.hasStar && linkType === "direct" ? "new-tab" : null
|
|
10932
|
-
}
|
|
10933
|
-
}
|
|
10934
|
-
],
|
|
10935
|
-
consumed: parts.consumed
|
|
10936
|
-
};
|
|
11709
|
+
return parseDelimitedContainer(ctx, "MONO_CLOSE", "monospace");
|
|
10937
11710
|
}
|
|
10938
11711
|
};
|
|
10939
11712
|
|
|
@@ -10944,7 +11717,7 @@ function normalizeAnchor(anchor) {
|
|
|
10944
11717
|
|
|
10945
11718
|
// packages/parser/src/parser/rules/inline/link-bracket/direct-url.ts
|
|
10946
11719
|
function isDirectBracketUrl(url) {
|
|
10947
|
-
return url !== "" && (url.startsWith("/") || url
|
|
11720
|
+
return url !== "" && (url.startsWith("/") || startsWithUrlScheme(url, 0));
|
|
10948
11721
|
}
|
|
10949
11722
|
|
|
10950
11723
|
// packages/parser/src/parser/rules/inline/link-bracket/parts.ts
|
|
@@ -10953,35 +11726,24 @@ function collectBracketLinkParts(ctx, startPos) {
|
|
|
10953
11726
|
return null;
|
|
10954
11727
|
}
|
|
10955
11728
|
let pos = startPos;
|
|
10956
|
-
|
|
10957
|
-
|
|
10958
|
-
while (pos <
|
|
10959
|
-
const token5 = ctx.tokens[pos];
|
|
10960
|
-
if (!token5 || token5.type === "WHITESPACE" || token5.type === "BRACKET_CLOSE" || token5.type === "NEWLINE" || token5.type === "EOF") {
|
|
10961
|
-
break;
|
|
10962
|
-
}
|
|
10963
|
-
first += token5.value;
|
|
10964
|
-
pos++;
|
|
10965
|
-
consumed++;
|
|
10966
|
-
}
|
|
10967
|
-
while (ctx.tokens[pos]?.type === "WHITESPACE") {
|
|
10968
|
-
pos++;
|
|
10969
|
-
consumed++;
|
|
10970
|
-
}
|
|
10971
|
-
let label = "";
|
|
10972
|
-
while (pos < ctx.tokens.length) {
|
|
11729
|
+
const end = Math.min(ctx.scope.inlineEnd ?? ctx.tokens.length, ctx.tokens.length);
|
|
11730
|
+
const values = [];
|
|
11731
|
+
while (pos < end) {
|
|
10973
11732
|
const token5 = ctx.tokens[pos];
|
|
10974
|
-
if (!token5 || token5.type === "BRACKET_CLOSE" || token5.type === "NEWLINE" || token5.type === "EOF")
|
|
11733
|
+
if (!token5 || token5.type === "BRACKET_CLOSE" || token5.type === "NEWLINE" || token5.type === "EOF")
|
|
10975
11734
|
break;
|
|
10976
|
-
|
|
10977
|
-
label += token5.value;
|
|
11735
|
+
values.push(token5.value);
|
|
10978
11736
|
pos++;
|
|
10979
|
-
consumed++;
|
|
10980
11737
|
}
|
|
10981
|
-
if (ctx.tokens[pos]?.type !== "BRACKET_CLOSE")
|
|
11738
|
+
if (pos >= end || ctx.tokens[pos]?.type !== "BRACKET_CLOSE")
|
|
10982
11739
|
return null;
|
|
10983
|
-
|
|
10984
|
-
|
|
11740
|
+
const content = values.join("");
|
|
11741
|
+
const separator = content.search(/[ \t]/);
|
|
11742
|
+
return {
|
|
11743
|
+
first: separator === -1 ? content : content.slice(0, separator),
|
|
11744
|
+
label: separator === -1 ? "" : content.slice(separator).trimStart(),
|
|
11745
|
+
consumed: pos - startPos + 1
|
|
11746
|
+
};
|
|
10985
11747
|
}
|
|
10986
11748
|
|
|
10987
11749
|
// packages/parser/src/parser/rules/inline/link-bracket/prefix.ts
|
|
@@ -10992,6 +11754,14 @@ function parseBracketLinkPrefix(ctx, startPos) {
|
|
|
10992
11754
|
return { target: null, bodyStart: startPos, consumed: 0 };
|
|
10993
11755
|
}
|
|
10994
11756
|
|
|
11757
|
+
// packages/parser/src/parser/rules/inline/link-bracket/special-target.ts
|
|
11758
|
+
function isBracketEmail(target) {
|
|
11759
|
+
return /^[_a-z0-9-]+(?:\.[_a-z0-9-]+)*@[a-z0-9-]+(?:\.[a-z0-9-]+)+$/i.test(target);
|
|
11760
|
+
}
|
|
11761
|
+
function wikipediaPage(target) {
|
|
11762
|
+
return /^wikipedia:((?!:)[A-Za-z0-9_/=&~#.:;+-]+)$/.exec(target)?.[1] ?? null;
|
|
11763
|
+
}
|
|
11764
|
+
|
|
10995
11765
|
// packages/parser/src/parser/rules/inline/link-bracket/parsed.ts
|
|
10996
11766
|
function parseSingleBracketLink(ctx) {
|
|
10997
11767
|
const prefix = parseBracketLinkPrefix(ctx, ctx.pos + 1);
|
|
@@ -11000,17 +11770,20 @@ function parseSingleBracketLink(ctx) {
|
|
|
11000
11770
|
return null;
|
|
11001
11771
|
}
|
|
11002
11772
|
const link = parts.first.trim();
|
|
11003
|
-
|
|
11773
|
+
const email = isBracketEmail(link);
|
|
11774
|
+
const wikiPage = wikipediaPage(link);
|
|
11775
|
+
if (!email && wikiPage === null && !isDirectBracketUrl(link)) {
|
|
11004
11776
|
return null;
|
|
11005
11777
|
}
|
|
11006
|
-
const labelText = parts.label.trim();
|
|
11778
|
+
const labelText = parts.label.trim() || wikiPage;
|
|
11007
11779
|
if (!labelText) {
|
|
11008
11780
|
return null;
|
|
11009
11781
|
}
|
|
11010
11782
|
return {
|
|
11011
|
-
link,
|
|
11783
|
+
link: email ? `mailto:${link}` : link,
|
|
11784
|
+
interwiki: wikiPage !== null,
|
|
11012
11785
|
labelText,
|
|
11013
|
-
target: prefix.target,
|
|
11786
|
+
target: wikiPage !== null ? "new-tab" : prefix.target,
|
|
11014
11787
|
consumed: 1 + prefix.consumed + parts.consumed
|
|
11015
11788
|
};
|
|
11016
11789
|
}
|
|
@@ -11063,7 +11836,7 @@ var linkSingleRule = {
|
|
|
11063
11836
|
{
|
|
11064
11837
|
element: "link",
|
|
11065
11838
|
data: {
|
|
11066
|
-
type: "direct",
|
|
11839
|
+
type: parsed.interwiki ? "interwiki" : "direct",
|
|
11067
11840
|
link: parsed.link,
|
|
11068
11841
|
extra: null,
|
|
11069
11842
|
label: linkLabel,
|
|
@@ -11132,6 +11905,134 @@ var linkStarRule = {
|
|
|
11132
11905
|
}
|
|
11133
11906
|
};
|
|
11134
11907
|
|
|
11908
|
+
// packages/parser/src/parser/rules/inline/autolink.ts
|
|
11909
|
+
var URL_BOUNDARY_TOKENS = new Set([
|
|
11910
|
+
"WHITESPACE",
|
|
11911
|
+
"NEWLINE",
|
|
11912
|
+
"EOF",
|
|
11913
|
+
"BLOCK_OPEN",
|
|
11914
|
+
"BLOCK_END_OPEN",
|
|
11915
|
+
"BLOCK_CLOSE",
|
|
11916
|
+
"LINK_OPEN",
|
|
11917
|
+
"LINK_CLOSE",
|
|
11918
|
+
"COMMENT_OPEN",
|
|
11919
|
+
"BACKSLASH_BREAK"
|
|
11920
|
+
]);
|
|
11921
|
+
var autolinkRule = {
|
|
11922
|
+
name: "autolink",
|
|
11923
|
+
startTokens: ["IDENTIFIER", "STAR", "LIST_BULLET"],
|
|
11924
|
+
parse(ctx) {
|
|
11925
|
+
let pos = ctx.pos;
|
|
11926
|
+
let target = null;
|
|
11927
|
+
const first = ctx.tokens[pos];
|
|
11928
|
+
if (!first) {
|
|
11929
|
+
return { success: false };
|
|
11930
|
+
}
|
|
11931
|
+
if (first.type === "STAR" || first.type === "LIST_BULLET") {
|
|
11932
|
+
if (first.value !== "*") {
|
|
11933
|
+
return { success: false };
|
|
11934
|
+
}
|
|
11935
|
+
target = "new-tab";
|
|
11936
|
+
pos++;
|
|
11937
|
+
}
|
|
11938
|
+
const scheme = ctx.tokens[pos];
|
|
11939
|
+
if (scheme?.type !== "IDENTIFIER" || !URL_SCHEME_NAMES.has(scheme.value)) {
|
|
11940
|
+
return { success: false };
|
|
11941
|
+
}
|
|
11942
|
+
if (ctx.tokens[pos + 1]?.type !== "COLON") {
|
|
11943
|
+
return { success: false };
|
|
11944
|
+
}
|
|
11945
|
+
const prev = ctx.tokens[ctx.pos - 1];
|
|
11946
|
+
if (prev && !first.lineStart) {
|
|
11947
|
+
const lastChar = prev.value[prev.value.length - 1] ?? "";
|
|
11948
|
+
if (/[A-Za-z]/.test(lastChar)) {
|
|
11949
|
+
return { success: false };
|
|
11950
|
+
}
|
|
11951
|
+
}
|
|
11952
|
+
const values = [];
|
|
11953
|
+
let end = pos;
|
|
11954
|
+
const inlineEnd = ctx.scope.inlineEnd ?? ctx.tokens.length;
|
|
11955
|
+
while (end < inlineEnd) {
|
|
11956
|
+
const token5 = ctx.tokens[end];
|
|
11957
|
+
if (!token5 || URL_BOUNDARY_TOKENS.has(token5.type)) {
|
|
11958
|
+
break;
|
|
11959
|
+
}
|
|
11960
|
+
if (token5.type === "RAW_OPEN" || token5.type === "RAW_BLOCK_OPEN") {
|
|
11961
|
+
if (rawRegionEnd(ctx.tokens, end, inlineEnd) > end)
|
|
11962
|
+
break;
|
|
11963
|
+
}
|
|
11964
|
+
values.push(token5.value);
|
|
11965
|
+
end++;
|
|
11966
|
+
if (/[ \t\n\\"']/.test(token5.value))
|
|
11967
|
+
break;
|
|
11968
|
+
}
|
|
11969
|
+
const candidate = values.join("");
|
|
11970
|
+
const match = URL_PATTERN.exec(candidate);
|
|
11971
|
+
if (!match) {
|
|
11972
|
+
return { success: false };
|
|
11973
|
+
}
|
|
11974
|
+
const url = match[0];
|
|
11975
|
+
let length = 0;
|
|
11976
|
+
let count = 0;
|
|
11977
|
+
while (length < url.length) {
|
|
11978
|
+
length += values[count]?.length ?? 0;
|
|
11979
|
+
count++;
|
|
11980
|
+
}
|
|
11981
|
+
const rest = candidate.slice(url.length, length);
|
|
11982
|
+
const elements = [
|
|
11983
|
+
{
|
|
11984
|
+
element: "link",
|
|
11985
|
+
data: {
|
|
11986
|
+
type: "direct",
|
|
11987
|
+
link: url,
|
|
11988
|
+
extra: null,
|
|
11989
|
+
label: { text: url },
|
|
11990
|
+
target
|
|
11991
|
+
}
|
|
11992
|
+
}
|
|
11993
|
+
];
|
|
11994
|
+
if (rest !== "") {
|
|
11995
|
+
elements.push({ element: "text", data: rest });
|
|
11996
|
+
}
|
|
11997
|
+
return {
|
|
11998
|
+
success: true,
|
|
11999
|
+
elements,
|
|
12000
|
+
consumed: pos - ctx.pos + count
|
|
12001
|
+
};
|
|
12002
|
+
}
|
|
12003
|
+
};
|
|
12004
|
+
|
|
12005
|
+
// packages/parser/src/parser/rules/inline/email/index.ts
|
|
12006
|
+
var emailRule = {
|
|
12007
|
+
name: "email",
|
|
12008
|
+
startTokens: EMAIL_START_TOKENS,
|
|
12009
|
+
parse(ctx) {
|
|
12010
|
+
const group = getEmailGroup(ctx.tokens, ctx.pos, ctx.scope.inlineEnd ?? ctx.tokens.length);
|
|
12011
|
+
if (!group)
|
|
12012
|
+
return { success: false };
|
|
12013
|
+
const elements = [];
|
|
12014
|
+
let copied = group.start;
|
|
12015
|
+
for (const candidate of group.candidates) {
|
|
12016
|
+
if (copied < candidate.start)
|
|
12017
|
+
elements.push({ element: "text", data: group.source.slice(copied, candidate.start) });
|
|
12018
|
+
elements.push(ctx.scope.suppressEmailLinks ? { element: "text", data: candidate.address } : {
|
|
12019
|
+
element: "link",
|
|
12020
|
+
data: {
|
|
12021
|
+
type: "direct",
|
|
12022
|
+
link: `mailto:${candidate.address}`,
|
|
12023
|
+
label: { text: candidate.address },
|
|
12024
|
+
target: null,
|
|
12025
|
+
extra: null
|
|
12026
|
+
}
|
|
12027
|
+
});
|
|
12028
|
+
copied = candidate.end;
|
|
12029
|
+
}
|
|
12030
|
+
if (copied < group.end)
|
|
12031
|
+
elements.push({ element: "text", data: group.source.slice(copied, group.end) });
|
|
12032
|
+
return { success: true, elements, consumed: group.endToken - ctx.pos };
|
|
12033
|
+
}
|
|
12034
|
+
};
|
|
12035
|
+
|
|
11135
12036
|
// packages/parser/src/parser/rules/inline/color/syntax.ts
|
|
11136
12037
|
function parseColorContent(ctx) {
|
|
11137
12038
|
const close = findFormattingClose(ctx, ctx.pos + 1, "COLOR_MARKER");
|
|
@@ -11218,7 +12119,7 @@ var newlineLineBreakRule = {
|
|
|
11218
12119
|
}
|
|
11219
12120
|
return {
|
|
11220
12121
|
success: true,
|
|
11221
|
-
elements: [
|
|
12122
|
+
elements: [createAutomaticLineBreak(currentTok)],
|
|
11222
12123
|
consumed: 1
|
|
11223
12124
|
};
|
|
11224
12125
|
}
|
|
@@ -11241,6 +12142,9 @@ function isValidBlockStartAfterNewline(ctx, tokenPos) {
|
|
|
11241
12142
|
if (!isBlockStartToken(token5?.type) || !token5?.lineStart) {
|
|
11242
12143
|
return false;
|
|
11243
12144
|
}
|
|
12145
|
+
if (token5.type === "LIST_BULLET" || token5.type === "LIST_NUMBER") {
|
|
12146
|
+
return ctx.tokens[tokenPos + 1]?.type === "WHITESPACE";
|
|
12147
|
+
}
|
|
11244
12148
|
if (token5.type !== "HEADING_MARKER") {
|
|
11245
12149
|
return true;
|
|
11246
12150
|
}
|
|
@@ -11498,6 +12402,9 @@ var htmlInlineRule = {
|
|
|
11498
12402
|
}
|
|
11499
12403
|
};
|
|
11500
12404
|
|
|
12405
|
+
// packages/parser/src/parser/rules/inline/raw/angle.ts
|
|
12406
|
+
var import_entities = require("entities");
|
|
12407
|
+
|
|
11501
12408
|
// packages/parser/src/parser/rules/inline/raw/result.ts
|
|
11502
12409
|
function rawElement(value, consumed) {
|
|
11503
12410
|
return {
|
|
@@ -11545,7 +12452,7 @@ function parseAngleRaw(ctx) {
|
|
|
11545
12452
|
if (ctx.tokens[pos]?.type === "RAW_BLOCK_CLOSE") {
|
|
11546
12453
|
consumed++;
|
|
11547
12454
|
}
|
|
11548
|
-
return rawElement(value, consumed);
|
|
12455
|
+
return rawElement(import_entities.decodeHTML(value), consumed);
|
|
11549
12456
|
}
|
|
11550
12457
|
|
|
11551
12458
|
// packages/parser/src/parser/rules/inline/raw/double-at.ts
|
|
@@ -11768,7 +12675,7 @@ function consumeSpanNewline(ctx, pos, paragraphStrip, afterBlankLine, children,
|
|
|
11768
12675
|
return { consumed: consumed2, afterBlankLine: paragraphStrip };
|
|
11769
12676
|
}
|
|
11770
12677
|
const targetChildren = paragraphStrip && afterBlankLine ? escapedChildren : children;
|
|
11771
|
-
targetChildren.push(
|
|
12678
|
+
targetChildren.push(createAutomaticLineBreak(ctx.tokens[pos]));
|
|
11772
12679
|
let consumed = 1;
|
|
11773
12680
|
let nextPos = pos + 1;
|
|
11774
12681
|
while (ctx.tokens[nextPos]?.type === "WHITESPACE" && ctx.tokens[nextPos]?.lineStart) {
|
|
@@ -11856,7 +12763,9 @@ function parseOneSpanChild(ctx, pos, targetChildren) {
|
|
|
11856
12763
|
for (const rule of getCandidateInlineRules(inlineRules, token5.type)) {
|
|
11857
12764
|
const result = rule.parse(inlineCtx);
|
|
11858
12765
|
if (result.success) {
|
|
11859
|
-
targetChildren
|
|
12766
|
+
stripAutomaticLineBreak(targetChildren, result.stripLeadingLineBreak);
|
|
12767
|
+
for (const element of result.elements)
|
|
12768
|
+
targetChildren.push(element);
|
|
11860
12769
|
return { consumed: result.consumed };
|
|
11861
12770
|
}
|
|
11862
12771
|
}
|
|
@@ -11924,6 +12833,48 @@ var closeSpanRule = {
|
|
|
11924
12833
|
}
|
|
11925
12834
|
};
|
|
11926
12835
|
|
|
12836
|
+
// packages/parser/src/parser/rules/inline/button/index.ts
|
|
12837
|
+
var buttonRule = {
|
|
12838
|
+
name: "button",
|
|
12839
|
+
startTokens: ["BLOCK_OPEN"],
|
|
12840
|
+
parse(ctx) {
|
|
12841
|
+
const result = parseButtonSyntax(ctx, ctx.pos, ctx.scope.inlineEnd ?? ctx.tokens.length);
|
|
12842
|
+
return result ? {
|
|
12843
|
+
success: true,
|
|
12844
|
+
consumed: result.end - ctx.pos,
|
|
12845
|
+
elements: [{ element: "button", data: result.data }]
|
|
12846
|
+
} : { success: false };
|
|
12847
|
+
}
|
|
12848
|
+
};
|
|
12849
|
+
|
|
12850
|
+
// packages/parser/src/parser/rules/inline/social/index.ts
|
|
12851
|
+
var socialRule = {
|
|
12852
|
+
name: "social",
|
|
12853
|
+
startTokens: ["BLOCK_OPEN"],
|
|
12854
|
+
parse(ctx) {
|
|
12855
|
+
const result = parseSocialSyntax(ctx, ctx.pos, ctx.scope.inlineEnd ?? ctx.tokens.length);
|
|
12856
|
+
return result ? {
|
|
12857
|
+
success: true,
|
|
12858
|
+
consumed: result.end - ctx.pos,
|
|
12859
|
+
elements: [{ element: "social", data: result.data }]
|
|
12860
|
+
} : { success: false };
|
|
12861
|
+
}
|
|
12862
|
+
};
|
|
12863
|
+
|
|
12864
|
+
// packages/parser/src/parser/rules/inline/date/index.ts
|
|
12865
|
+
var dateRule = {
|
|
12866
|
+
name: "date",
|
|
12867
|
+
startTokens: ["BLOCK_OPEN"],
|
|
12868
|
+
parse(ctx) {
|
|
12869
|
+
const parsed = parseDateSyntax(ctx, ctx.pos, ctx.scope.inlineEnd ?? ctx.tokens.length);
|
|
12870
|
+
return parsed ? {
|
|
12871
|
+
success: true,
|
|
12872
|
+
consumed: parsed.end - ctx.pos,
|
|
12873
|
+
elements: [{ element: "date", data: parsed.data }]
|
|
12874
|
+
} : { success: false };
|
|
12875
|
+
}
|
|
12876
|
+
};
|
|
12877
|
+
|
|
11927
12878
|
// packages/parser/src/parser/rules/inline/size/content.ts
|
|
11928
12879
|
function parseSizeContent(ctx, startPos) {
|
|
11929
12880
|
const children = [];
|
|
@@ -11945,7 +12896,8 @@ function parseSizeContent(ctx, startPos) {
|
|
|
11945
12896
|
const inlineCtx = { ...ctx, pos };
|
|
11946
12897
|
const inlineResult = parseInlineUntil(inlineCtx, "BLOCK_END_OPEN");
|
|
11947
12898
|
if (inlineResult.elements.length > 0) {
|
|
11948
|
-
|
|
12899
|
+
for (const element of inlineResult.elements)
|
|
12900
|
+
children.push(element);
|
|
11949
12901
|
pos += inlineResult.consumed;
|
|
11950
12902
|
consumed += inlineResult.consumed;
|
|
11951
12903
|
} else {
|
|
@@ -11974,6 +12926,16 @@ function tryConsumeSizeClose(ctx, pos) {
|
|
|
11974
12926
|
|
|
11975
12927
|
// packages/parser/src/parser/rules/inline/size/value.ts
|
|
11976
12928
|
var VALID_SIZE_UNITS = ["px", "em", "rem", "ex", "%", "cm", "mm", "in", "pc"];
|
|
12929
|
+
var VALID_SIZE_KEYWORDS = [
|
|
12930
|
+
"smaller",
|
|
12931
|
+
"larger",
|
|
12932
|
+
"xx-small",
|
|
12933
|
+
"x-small",
|
|
12934
|
+
"small",
|
|
12935
|
+
"large",
|
|
12936
|
+
"x-large",
|
|
12937
|
+
"xx-large"
|
|
12938
|
+
];
|
|
11977
12939
|
function parseSizeValue(ctx, startPos) {
|
|
11978
12940
|
let pos = startPos;
|
|
11979
12941
|
let consumed = 0;
|
|
@@ -11998,6 +12960,8 @@ function parseSizeValue(ctx, startPos) {
|
|
|
11998
12960
|
return isValidSizeValue(size) ? { size, consumed } : null;
|
|
11999
12961
|
}
|
|
12000
12962
|
function isValidSizeValue(size) {
|
|
12963
|
+
if (VALID_SIZE_KEYWORDS.includes(size))
|
|
12964
|
+
return true;
|
|
12001
12965
|
const unitPattern = VALID_SIZE_UNITS.join("|");
|
|
12002
12966
|
return new RegExp(`^(\\d+(?:\\.\\d+)?)(${unitPattern})$`, "i").test(size);
|
|
12003
12967
|
}
|
|
@@ -12069,19 +13033,6 @@ var sizeRule = {
|
|
|
12069
13033
|
}
|
|
12070
13034
|
};
|
|
12071
13035
|
|
|
12072
|
-
// packages/parser/src/parser/rules/inline/footnote/child.ts
|
|
12073
|
-
function parseFootnoteChild(ctx, pos) {
|
|
12074
|
-
const token5 = ctx.tokens[pos];
|
|
12075
|
-
if (!token5) {
|
|
12076
|
-
return { elements: [], consumed: 0 };
|
|
12077
|
-
}
|
|
12078
|
-
const inlineResult = parseInlineUntil({ ...ctx, pos }, "BLOCK_END_OPEN");
|
|
12079
|
-
if (inlineResult.elements.length > 0) {
|
|
12080
|
-
return { elements: inlineResult.elements, consumed: inlineResult.consumed };
|
|
12081
|
-
}
|
|
12082
|
-
return { elements: [{ element: "text", data: token5.value }], consumed: 1 };
|
|
12083
|
-
}
|
|
12084
|
-
|
|
12085
13036
|
// packages/parser/src/parser/rules/inline/footnote/close.ts
|
|
12086
13037
|
function tryConsumeFootnoteClose(ctx, pos) {
|
|
12087
13038
|
if (ctx.tokens[pos]?.type !== "BLOCK_END_OPEN") {
|
|
@@ -12103,96 +13054,73 @@ function tryConsumeFootnoteClose(ctx, pos) {
|
|
|
12103
13054
|
return { consumed };
|
|
12104
13055
|
}
|
|
12105
13056
|
|
|
12106
|
-
// packages/parser/src/parser/rules/inline/
|
|
12107
|
-
function
|
|
12108
|
-
let
|
|
12109
|
-
let consumed =
|
|
12110
|
-
|
|
12111
|
-
|
|
12112
|
-
consumed++;
|
|
12113
|
-
}
|
|
12114
|
-
if (ctx.tokens[nextPos]?.type !== "NEWLINE") {
|
|
12115
|
-
return { consumed, paragraphBreak: false };
|
|
13057
|
+
// packages/parser/src/parser/rules/inline/math-inline/syntax.ts
|
|
13058
|
+
function parseInlineMathSource(ctx, startPos) {
|
|
13059
|
+
let pos = startPos;
|
|
13060
|
+
let consumed = 0;
|
|
13061
|
+
if (ctx.tokens[pos]?.type !== "TEXT" || ctx.tokens[pos]?.value !== "$") {
|
|
13062
|
+
return null;
|
|
12116
13063
|
}
|
|
12117
|
-
|
|
12118
|
-
|
|
13064
|
+
pos++;
|
|
13065
|
+
consumed++;
|
|
13066
|
+
while (ctx.tokens[pos]?.type === "WHITESPACE") {
|
|
13067
|
+
pos++;
|
|
12119
13068
|
consumed++;
|
|
12120
13069
|
}
|
|
12121
|
-
|
|
12122
|
-
}
|
|
12123
|
-
|
|
12124
|
-
// packages/parser/src/parser/rules/inline/footnote/content.ts
|
|
12125
|
-
function parseFootnoteContent(ctx, startPos) {
|
|
12126
|
-
const paragraphs = [[]];
|
|
12127
|
-
let currentParagraph = 0;
|
|
12128
|
-
let pos = startPos;
|
|
12129
|
-
let consumed = 0;
|
|
13070
|
+
let latexSource = "";
|
|
12130
13071
|
while (pos < ctx.tokens.length) {
|
|
12131
13072
|
const token5 = ctx.tokens[pos];
|
|
12132
|
-
if (!token5 || token5.type === "
|
|
12133
|
-
|
|
12134
|
-
}
|
|
12135
|
-
const closeResult = tryConsumeFootnoteClose(ctx, pos);
|
|
12136
|
-
if (closeResult) {
|
|
12137
|
-
return {
|
|
12138
|
-
paragraphs,
|
|
12139
|
-
consumed: consumed + closeResult.consumed,
|
|
12140
|
-
foundClose: true
|
|
12141
|
-
};
|
|
13073
|
+
if (!token5 || token5.type === "NEWLINE") {
|
|
13074
|
+
return null;
|
|
12142
13075
|
}
|
|
12143
|
-
if (token5.type === "
|
|
12144
|
-
|
|
12145
|
-
pos += newlineResult.consumed;
|
|
12146
|
-
consumed += newlineResult.consumed;
|
|
12147
|
-
if (newlineResult.paragraphBreak) {
|
|
12148
|
-
currentParagraph++;
|
|
12149
|
-
paragraphs[currentParagraph] = [];
|
|
12150
|
-
} else {
|
|
12151
|
-
paragraphs[currentParagraph].push({ element: "line-break" });
|
|
12152
|
-
}
|
|
12153
|
-
continue;
|
|
13076
|
+
if (token5.type === "TEXT" && token5.value === "$" && ctx.tokens[pos + 1]?.type === "BLOCK_CLOSE") {
|
|
13077
|
+
break;
|
|
12154
13078
|
}
|
|
12155
|
-
|
|
12156
|
-
|
|
12157
|
-
|
|
12158
|
-
|
|
13079
|
+
latexSource += token5.value;
|
|
13080
|
+
pos++;
|
|
13081
|
+
consumed++;
|
|
13082
|
+
}
|
|
13083
|
+
if (ctx.tokens[pos]?.type !== "TEXT" || ctx.tokens[pos]?.value !== "$") {
|
|
13084
|
+
return null;
|
|
13085
|
+
}
|
|
13086
|
+
pos++;
|
|
13087
|
+
consumed++;
|
|
13088
|
+
if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
|
|
13089
|
+
return null;
|
|
12159
13090
|
}
|
|
12160
|
-
return {
|
|
13091
|
+
return {
|
|
13092
|
+
latexSource: latexSource.trim(),
|
|
13093
|
+
consumed: consumed + 1
|
|
13094
|
+
};
|
|
12161
13095
|
}
|
|
12162
13096
|
|
|
12163
|
-
// packages/parser/src/parser/rules/inline/
|
|
12164
|
-
|
|
12165
|
-
|
|
12166
|
-
|
|
12167
|
-
|
|
12168
|
-
|
|
12169
|
-
|
|
13097
|
+
// packages/parser/src/parser/rules/inline/math-inline/index.ts
|
|
13098
|
+
var mathInlineRule = {
|
|
13099
|
+
name: "math-inline",
|
|
13100
|
+
startTokens: ["BLOCK_OPEN"],
|
|
13101
|
+
parse(ctx) {
|
|
13102
|
+
const openToken = currentToken(ctx);
|
|
13103
|
+
if (openToken.type !== "BLOCK_OPEN") {
|
|
13104
|
+
return { success: false };
|
|
12170
13105
|
}
|
|
12171
|
-
|
|
12172
|
-
|
|
12173
|
-
|
|
12174
|
-
children.push({
|
|
12175
|
-
element: "container",
|
|
12176
|
-
data: {
|
|
12177
|
-
type: "paragraph",
|
|
12178
|
-
attributes: {},
|
|
12179
|
-
elements: para
|
|
12180
|
-
}
|
|
12181
|
-
});
|
|
13106
|
+
const parsed = parseInlineMathSource(ctx, ctx.pos + 1);
|
|
13107
|
+
if (!parsed) {
|
|
13108
|
+
return { success: false };
|
|
12182
13109
|
}
|
|
13110
|
+
return {
|
|
13111
|
+
success: true,
|
|
13112
|
+
elements: [
|
|
13113
|
+
{
|
|
13114
|
+
element: "math-inline",
|
|
13115
|
+
data: {
|
|
13116
|
+
"latex-source": parsed.latexSource
|
|
13117
|
+
}
|
|
13118
|
+
}
|
|
13119
|
+
],
|
|
13120
|
+
consumed: 1 + parsed.consumed
|
|
13121
|
+
};
|
|
12183
13122
|
}
|
|
12184
|
-
|
|
12185
|
-
}
|
|
12186
|
-
function trimLineBreaks(elements) {
|
|
12187
|
-
const result = [...elements];
|
|
12188
|
-
while (result.length > 0 && result[0]?.element === "line-break") {
|
|
12189
|
-
result.shift();
|
|
12190
|
-
}
|
|
12191
|
-
while (result.length > 0 && result[result.length - 1]?.element === "line-break") {
|
|
12192
|
-
result.pop();
|
|
12193
|
-
}
|
|
12194
|
-
return result;
|
|
12195
|
-
}
|
|
13123
|
+
};
|
|
12196
13124
|
|
|
12197
13125
|
// packages/parser/src/parser/rules/inline/footnote/open.ts
|
|
12198
13126
|
function parseFootnoteOpen(ctx) {
|
|
@@ -12219,6 +13147,91 @@ function parseFootnoteOpen(ctx) {
|
|
|
12219
13147
|
return { bodyStart: pos, consumed };
|
|
12220
13148
|
}
|
|
12221
13149
|
|
|
13150
|
+
// packages/parser/src/parser/rules/inline/footnote/boundary.ts
|
|
13151
|
+
var opaqueRules2 = [
|
|
13152
|
+
codeBlockRule,
|
|
13153
|
+
htmlBlockRule,
|
|
13154
|
+
mathBlockRule,
|
|
13155
|
+
mathInlineRule,
|
|
13156
|
+
linkTripleRule,
|
|
13157
|
+
linkSingleRule,
|
|
13158
|
+
linkStarRule,
|
|
13159
|
+
linkAnchorRule
|
|
13160
|
+
];
|
|
13161
|
+
function findFootnoteEnd(ctx, start) {
|
|
13162
|
+
const probe = createOpaqueProbe(ctx);
|
|
13163
|
+
let depth = 0;
|
|
13164
|
+
for (let pos = start;pos < ctx.tokens.length; pos++) {
|
|
13165
|
+
if (ctx.tokens[pos]?.type === "EOF")
|
|
13166
|
+
return pos;
|
|
13167
|
+
const protectedEnd = protectedInlineRegionEnd(ctx.tokens, pos, ctx.tokens.length);
|
|
13168
|
+
if (protectedEnd > pos) {
|
|
13169
|
+
pos = protectedEnd - 1;
|
|
13170
|
+
continue;
|
|
13171
|
+
}
|
|
13172
|
+
probe.pos = pos;
|
|
13173
|
+
const close = tryConsumeFootnoteClose(probe, pos);
|
|
13174
|
+
if (close) {
|
|
13175
|
+
if (depth === 0)
|
|
13176
|
+
return pos;
|
|
13177
|
+
depth--;
|
|
13178
|
+
pos += close.consumed - 1;
|
|
13179
|
+
continue;
|
|
13180
|
+
}
|
|
13181
|
+
const open = parseFootnoteOpen(probe);
|
|
13182
|
+
if (open) {
|
|
13183
|
+
depth++;
|
|
13184
|
+
pos += open.consumed - 1;
|
|
13185
|
+
continue;
|
|
13186
|
+
}
|
|
13187
|
+
const opaqueEnd = opaqueRuleEnd(probe, pos, opaqueRules2);
|
|
13188
|
+
if (opaqueEnd > pos)
|
|
13189
|
+
pos = opaqueEnd - 1;
|
|
13190
|
+
}
|
|
13191
|
+
return ctx.tokens.length;
|
|
13192
|
+
}
|
|
13193
|
+
|
|
13194
|
+
// packages/parser/src/parser/rules/inline/footnote/content.ts
|
|
13195
|
+
function parseFootnoteContent(ctx, startPos) {
|
|
13196
|
+
const end = findFootnoteEnd(ctx, startPos);
|
|
13197
|
+
let leadingNewlines = 0;
|
|
13198
|
+
for (let pos = startPos;pos < end; pos++) {
|
|
13199
|
+
const type = ctx.tokens[pos]?.type;
|
|
13200
|
+
if (type === "NEWLINE")
|
|
13201
|
+
leadingNewlines++;
|
|
13202
|
+
else if (type !== "WHITESPACE")
|
|
13203
|
+
break;
|
|
13204
|
+
}
|
|
13205
|
+
const bodyCtx = {
|
|
13206
|
+
...ctx,
|
|
13207
|
+
tokens: ctx.tokens.slice(startPos, end),
|
|
13208
|
+
pos: 0,
|
|
13209
|
+
scope: {
|
|
13210
|
+
...ctx.scope,
|
|
13211
|
+
inlineEnd: undefined,
|
|
13212
|
+
tableFormatting: undefined,
|
|
13213
|
+
blockCloseCondition: undefined
|
|
13214
|
+
}
|
|
13215
|
+
};
|
|
13216
|
+
const result = parseBlocksUntil(bodyCtx, () => false);
|
|
13217
|
+
const close = tryConsumeFootnoteClose(ctx, end);
|
|
13218
|
+
return {
|
|
13219
|
+
elements: result.elements,
|
|
13220
|
+
consumed: end - startPos + (close?.consumed ?? 0),
|
|
13221
|
+
foundClose: close !== null,
|
|
13222
|
+
leadingParagraphBreak: leadingNewlines >= 2
|
|
13223
|
+
};
|
|
13224
|
+
}
|
|
13225
|
+
|
|
13226
|
+
// packages/parser/src/parser/rules/inline/footnote/elements.ts
|
|
13227
|
+
function buildFootnoteChildren(elements, leadingParagraphBreak) {
|
|
13228
|
+
const first = elements[0];
|
|
13229
|
+
if (!leadingParagraphBreak && first?.element === "container" && first.data.type === "paragraph") {
|
|
13230
|
+
return [...first.data.elements, ...elements.slice(1)];
|
|
13231
|
+
}
|
|
13232
|
+
return elements;
|
|
13233
|
+
}
|
|
13234
|
+
|
|
12222
13235
|
// packages/parser/src/parser/rules/inline/footnote/index.ts
|
|
12223
13236
|
var footnoteRule = {
|
|
12224
13237
|
name: "footnote",
|
|
@@ -12234,7 +13247,7 @@ var footnoteRule = {
|
|
|
12234
13247
|
}
|
|
12235
13248
|
const contentResult = parseFootnoteContent(ctx, openResult.bodyStart);
|
|
12236
13249
|
const consumed = openResult.consumed + contentResult.consumed;
|
|
12237
|
-
const children = buildFootnoteChildren(contentResult.
|
|
13250
|
+
const children = buildFootnoteChildren(contentResult.elements, contentResult.leadingParagraphBreak);
|
|
12238
13251
|
if (!contentResult.foundClose) {
|
|
12239
13252
|
ctx.diagnostics.push({
|
|
12240
13253
|
severity: "warning",
|
|
@@ -12594,11 +13607,15 @@ function parseAnchorChild(ctx, pos) {
|
|
|
12594
13607
|
if (!token5) {
|
|
12595
13608
|
return { elements: [], consumed: 0 };
|
|
12596
13609
|
}
|
|
12597
|
-
const inlineCtx = {
|
|
13610
|
+
const inlineCtx = {
|
|
13611
|
+
...ctx,
|
|
13612
|
+
pos,
|
|
13613
|
+
scope: { ...ctx.scope, suppressEmailLinks: true }
|
|
13614
|
+
};
|
|
12598
13615
|
for (const rule of getCandidateInlineRules(inlineRules, token5.type)) {
|
|
12599
13616
|
const result = rule.parse(inlineCtx);
|
|
12600
13617
|
if (result.success) {
|
|
12601
|
-
return
|
|
13618
|
+
return result;
|
|
12602
13619
|
}
|
|
12603
13620
|
}
|
|
12604
13621
|
return { elements: [{ element: "text", data: token5.value }], consumed: 1 };
|
|
@@ -12658,7 +13675,7 @@ function consumeAnchorNewline(ctx, pos, paragraphStrip, children) {
|
|
|
12658
13675
|
let consumed = 1;
|
|
12659
13676
|
let nextPos = pos + 1;
|
|
12660
13677
|
if (!paragraphStrip) {
|
|
12661
|
-
children.push(
|
|
13678
|
+
children.push(createAutomaticLineBreak(ctx.tokens[pos]));
|
|
12662
13679
|
while (ctx.tokens[nextPos]?.type === "WHITESPACE" && ctx.tokens[nextPos]?.lineStart) {
|
|
12663
13680
|
nextPos++;
|
|
12664
13681
|
consumed++;
|
|
@@ -12711,7 +13728,9 @@ function parseAnchorContent(ctx, startPos, paragraphStrip) {
|
|
|
12711
13728
|
continue;
|
|
12712
13729
|
}
|
|
12713
13730
|
const child = parseAnchorChild(ctx, pos);
|
|
12714
|
-
children
|
|
13731
|
+
stripAutomaticLineBreak(children, child.stripLeadingLineBreak);
|
|
13732
|
+
for (const element of child.elements)
|
|
13733
|
+
children.push(element);
|
|
12715
13734
|
pos += child.consumed;
|
|
12716
13735
|
consumed += child.consumed;
|
|
12717
13736
|
}
|
|
@@ -12785,75 +13804,8 @@ var anchorRule = {
|
|
|
12785
13804
|
}
|
|
12786
13805
|
}
|
|
12787
13806
|
],
|
|
12788
|
-
consumed
|
|
12789
|
-
|
|
12790
|
-
}
|
|
12791
|
-
};
|
|
12792
|
-
|
|
12793
|
-
// packages/parser/src/parser/rules/inline/math-inline/syntax.ts
|
|
12794
|
-
function parseInlineMathSource(ctx, startPos) {
|
|
12795
|
-
let pos = startPos;
|
|
12796
|
-
let consumed = 0;
|
|
12797
|
-
if (ctx.tokens[pos]?.type !== "TEXT" || ctx.tokens[pos]?.value !== "$") {
|
|
12798
|
-
return null;
|
|
12799
|
-
}
|
|
12800
|
-
pos++;
|
|
12801
|
-
consumed++;
|
|
12802
|
-
while (ctx.tokens[pos]?.type === "WHITESPACE") {
|
|
12803
|
-
pos++;
|
|
12804
|
-
consumed++;
|
|
12805
|
-
}
|
|
12806
|
-
let latexSource = "";
|
|
12807
|
-
while (pos < ctx.tokens.length) {
|
|
12808
|
-
const token5 = ctx.tokens[pos];
|
|
12809
|
-
if (!token5 || token5.type === "NEWLINE") {
|
|
12810
|
-
return null;
|
|
12811
|
-
}
|
|
12812
|
-
if (token5.type === "TEXT" && token5.value === "$" && ctx.tokens[pos + 1]?.type === "BLOCK_CLOSE") {
|
|
12813
|
-
break;
|
|
12814
|
-
}
|
|
12815
|
-
latexSource += token5.value;
|
|
12816
|
-
pos++;
|
|
12817
|
-
consumed++;
|
|
12818
|
-
}
|
|
12819
|
-
if (ctx.tokens[pos]?.type !== "TEXT" || ctx.tokens[pos]?.value !== "$") {
|
|
12820
|
-
return null;
|
|
12821
|
-
}
|
|
12822
|
-
pos++;
|
|
12823
|
-
consumed++;
|
|
12824
|
-
if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
|
|
12825
|
-
return null;
|
|
12826
|
-
}
|
|
12827
|
-
return {
|
|
12828
|
-
latexSource: latexSource.trim(),
|
|
12829
|
-
consumed: consumed + 1
|
|
12830
|
-
};
|
|
12831
|
-
}
|
|
12832
|
-
|
|
12833
|
-
// packages/parser/src/parser/rules/inline/math-inline/index.ts
|
|
12834
|
-
var mathInlineRule = {
|
|
12835
|
-
name: "math-inline",
|
|
12836
|
-
startTokens: ["BLOCK_OPEN"],
|
|
12837
|
-
parse(ctx) {
|
|
12838
|
-
const openToken = currentToken(ctx);
|
|
12839
|
-
if (openToken.type !== "BLOCK_OPEN") {
|
|
12840
|
-
return { success: false };
|
|
12841
|
-
}
|
|
12842
|
-
const parsed = parseInlineMathSource(ctx, ctx.pos + 1);
|
|
12843
|
-
if (!parsed) {
|
|
12844
|
-
return { success: false };
|
|
12845
|
-
}
|
|
12846
|
-
return {
|
|
12847
|
-
success: true,
|
|
12848
|
-
elements: [
|
|
12849
|
-
{
|
|
12850
|
-
element: "math-inline",
|
|
12851
|
-
data: {
|
|
12852
|
-
"latex-source": parsed.latexSource
|
|
12853
|
-
}
|
|
12854
|
-
}
|
|
12855
|
-
],
|
|
12856
|
-
consumed: 1 + parsed.consumed
|
|
13807
|
+
consumed,
|
|
13808
|
+
stripLeadingLineBreak: openResult.paragraphStrip ? precedingSingleNewline(ctx) : undefined
|
|
12857
13809
|
};
|
|
12858
13810
|
}
|
|
12859
13811
|
};
|
|
@@ -12964,7 +13916,9 @@ function parseInlineBranch(ctx, startPos) {
|
|
|
12964
13916
|
}
|
|
12965
13917
|
const result = rule.parse(inlineCtx);
|
|
12966
13918
|
if (result.success) {
|
|
12967
|
-
elements
|
|
13919
|
+
stripAutomaticLineBreak(elements, result.stripLeadingLineBreak);
|
|
13920
|
+
for (const element of result.elements)
|
|
13921
|
+
elements.push(element);
|
|
12968
13922
|
consumed += result.consumed;
|
|
12969
13923
|
pos += result.consumed;
|
|
12970
13924
|
matched = true;
|
|
@@ -13287,6 +14241,7 @@ var textRule = {
|
|
|
13287
14241
|
|
|
13288
14242
|
// packages/parser/src/parser/rules/inline/index.ts
|
|
13289
14243
|
var inlineRules = [
|
|
14244
|
+
emailRule,
|
|
13290
14245
|
boldRule,
|
|
13291
14246
|
italicRule,
|
|
13292
14247
|
underlineRule,
|
|
@@ -13298,6 +14253,7 @@ var inlineRules = [
|
|
|
13298
14253
|
linkSingleRule,
|
|
13299
14254
|
linkAnchorRule,
|
|
13300
14255
|
linkStarRule,
|
|
14256
|
+
autolinkRule,
|
|
13301
14257
|
colorRule,
|
|
13302
14258
|
backslashLineBreakRule,
|
|
13303
14259
|
underscoreLineBreakRule,
|
|
@@ -13307,6 +14263,9 @@ var inlineRules = [
|
|
|
13307
14263
|
rawRule,
|
|
13308
14264
|
imageRule,
|
|
13309
14265
|
embedBlockRule,
|
|
14266
|
+
buttonRule,
|
|
14267
|
+
socialRule,
|
|
14268
|
+
dateRule,
|
|
13310
14269
|
sizeRule,
|
|
13311
14270
|
footnoteRule,
|
|
13312
14271
|
spanRule,
|
|
@@ -13562,6 +14521,8 @@ function mergeSpanStripParagraphs(children) {
|
|
|
13562
14521
|
i++;
|
|
13563
14522
|
continue;
|
|
13564
14523
|
}
|
|
14524
|
+
const firstMeaningful = paraData.elements.find((child) => child.element !== "line-break" && !isWhitespaceText(child));
|
|
14525
|
+
const keepParagraph = firstMeaningful && !isSpanStripMarker(firstMeaningful);
|
|
13565
14526
|
const mergedChildren = [...paraData.elements];
|
|
13566
14527
|
i++;
|
|
13567
14528
|
while (i < expandedChildren.length) {
|
|
@@ -13574,7 +14535,8 @@ function mergeSpanStripParagraphs(children) {
|
|
|
13574
14535
|
break;
|
|
13575
14536
|
}
|
|
13576
14537
|
const hasSpanStrip = hasParagraphStripSpan(nextPara);
|
|
13577
|
-
|
|
14538
|
+
for (const element of nextParaData.elements)
|
|
14539
|
+
mergedChildren.push(element);
|
|
13578
14540
|
i++;
|
|
13579
14541
|
if (!hasSpanStrip) {
|
|
13580
14542
|
const peekNext = expandedChildren[i];
|
|
@@ -13585,7 +14547,7 @@ function mergeSpanStripParagraphs(children) {
|
|
|
13585
14547
|
}
|
|
13586
14548
|
const escapedSpans = extractEscapedSpans(mergedChildren);
|
|
13587
14549
|
removeLineBreaksAroundSpanStrip(mergedChildren);
|
|
13588
|
-
if (escapedSpans.length > 0) {
|
|
14550
|
+
if (escapedSpans.length > 0 || keepParagraph) {
|
|
13589
14551
|
if (mergedChildren.length > 0) {
|
|
13590
14552
|
result.push(paragraphElement(mergedChildren));
|
|
13591
14553
|
}
|
|
@@ -13806,50 +14768,6 @@ function cleanInternalFlags(elements) {
|
|
|
13806
14768
|
}
|
|
13807
14769
|
return removeEmptySpansAndAdjacentWhitespace(cleaned ?? elements);
|
|
13808
14770
|
}
|
|
13809
|
-
// packages/parser/src/parser/postprocess/divAdjacentParagraph.ts
|
|
13810
|
-
function isParagraphContainer2(el) {
|
|
13811
|
-
if (!el || el.element !== "container")
|
|
13812
|
-
return false;
|
|
13813
|
-
return el.data.type === "paragraph";
|
|
13814
|
-
}
|
|
13815
|
-
function isDivContainer(el) {
|
|
13816
|
-
if (!el || el.element !== "container")
|
|
13817
|
-
return false;
|
|
13818
|
-
return el.data.type === "div";
|
|
13819
|
-
}
|
|
13820
|
-
function suppressAtLevel(elements) {
|
|
13821
|
-
if (elements.length <= 1)
|
|
13822
|
-
return elements;
|
|
13823
|
-
const unwrap = Array.from({ length: elements.length }, () => false);
|
|
13824
|
-
for (let i = 0;i < elements.length; i++) {
|
|
13825
|
-
if (!isParagraphContainer2(elements[i]))
|
|
13826
|
-
continue;
|
|
13827
|
-
const prevIsDiv = i > 0 && isDivContainer(elements[i - 1]);
|
|
13828
|
-
const nextIsDiv = i < elements.length - 1 && isDivContainer(elements[i + 1]);
|
|
13829
|
-
if (prevIsDiv || nextIsDiv) {
|
|
13830
|
-
unwrap[i] = true;
|
|
13831
|
-
}
|
|
13832
|
-
}
|
|
13833
|
-
const result = [];
|
|
13834
|
-
for (let i = 0;i < elements.length; i++) {
|
|
13835
|
-
const el = elements[i];
|
|
13836
|
-
if (!el)
|
|
13837
|
-
continue;
|
|
13838
|
-
if (unwrap[i] && el.element === "container") {
|
|
13839
|
-
const inner = el.data.elements;
|
|
13840
|
-
if (i > 0 && isDivContainer(elements[i - 1])) {
|
|
13841
|
-
result.push({ element: "line-break" });
|
|
13842
|
-
}
|
|
13843
|
-
result.push(...inner);
|
|
13844
|
-
} else {
|
|
13845
|
-
result.push(el);
|
|
13846
|
-
}
|
|
13847
|
-
}
|
|
13848
|
-
return result;
|
|
13849
|
-
}
|
|
13850
|
-
function suppressDivAdjacentParagraphs(elements) {
|
|
13851
|
-
return suppressAtLevel(elements);
|
|
13852
|
-
}
|
|
13853
14771
|
// packages/parser/src/parser/parse/footnotes.ts
|
|
13854
14772
|
function containsFootnoteBlock(elements) {
|
|
13855
14773
|
let found = false;
|
|
@@ -14127,7 +15045,9 @@ function substitute(text2) {
|
|
|
14127
15045
|
result = result.replace(WHITESPACE_ONLY_LINE, "");
|
|
14128
15046
|
}
|
|
14129
15047
|
if (result.indexOf("\\\n") !== -1) {
|
|
14130
|
-
|
|
15048
|
+
const sentinels = makeUniqueSentinels(result);
|
|
15049
|
+
const { masked, placeholders } = maskRawRegions(result, sentinels);
|
|
15050
|
+
result = restorePlaceholders(masked.replace(CONCAT_LINES, String.fromCharCode(57344)), placeholders, sentinels);
|
|
14131
15051
|
}
|
|
14132
15052
|
if (result.indexOf("\t") !== -1) {
|
|
14133
15053
|
result = result.replace(TABS, " ");
|
|
@@ -14194,14 +15114,26 @@ function replaceDelimitedTypography(text2, opener, closer, leftQuote, rightQuote
|
|
|
14194
15114
|
let searchFrom = 0;
|
|
14195
15115
|
let result = "";
|
|
14196
15116
|
let lastCopied = 0;
|
|
15117
|
+
let closeIndex = -1;
|
|
15118
|
+
let newlineIndex = -1;
|
|
14197
15119
|
while (searchFrom < text2.length) {
|
|
14198
15120
|
const openIndex = text2.indexOf(opener, searchFrom);
|
|
14199
15121
|
if (openIndex === -1)
|
|
14200
15122
|
break;
|
|
14201
15123
|
const contentStart = openIndex + opener.length;
|
|
14202
|
-
|
|
15124
|
+
if (closeIndex < contentStart)
|
|
15125
|
+
closeIndex = text2.indexOf(closer, contentStart);
|
|
14203
15126
|
if (closeIndex === -1)
|
|
14204
15127
|
break;
|
|
15128
|
+
if (newlineIndex < contentStart) {
|
|
15129
|
+
const nextNewline = text2.indexOf(`
|
|
15130
|
+
`, contentStart);
|
|
15131
|
+
newlineIndex = nextNewline === -1 ? text2.length : nextNewline;
|
|
15132
|
+
}
|
|
15133
|
+
if (newlineIndex < closeIndex) {
|
|
15134
|
+
searchFrom = newlineIndex + 1;
|
|
15135
|
+
continue;
|
|
15136
|
+
}
|
|
14205
15137
|
result += text2.slice(lastCopied, openIndex);
|
|
14206
15138
|
result += leftQuote;
|
|
14207
15139
|
result += text2.slice(contentStart, closeIndex);
|
|
@@ -14212,7 +15144,12 @@ function replaceDelimitedTypography(text2, opener, closer, leftQuote, rightQuote
|
|
|
14212
15144
|
return lastCopied === 0 ? text2 : result + text2.slice(lastCopied);
|
|
14213
15145
|
}
|
|
14214
15146
|
function substitute2(text2) {
|
|
14215
|
-
|
|
15147
|
+
if (!text2.includes("`") && !text2.includes(",,") && !text2.includes("...") && !text2.includes(". . .")) {
|
|
15148
|
+
return text2;
|
|
15149
|
+
}
|
|
15150
|
+
const sentinels = makeUniqueSentinels(text2);
|
|
15151
|
+
const { masked, placeholders } = maskRawRegions(text2, sentinels);
|
|
15152
|
+
let result = masked;
|
|
14216
15153
|
if (result.includes("``") && result.includes("''")) {
|
|
14217
15154
|
result = replaceDelimitedTypography(result, "``", "''", LEFT_DOUBLE_QUOTE, RIGHT_DOUBLE_QUOTE);
|
|
14218
15155
|
}
|
|
@@ -14228,7 +15165,7 @@ function substitute2(text2) {
|
|
|
14228
15165
|
if (result.includes(". . .")) {
|
|
14229
15166
|
result = replaceExactEllipsisPattern(result, ". . .");
|
|
14230
15167
|
}
|
|
14231
|
-
return result;
|
|
15168
|
+
return restorePlaceholders(result, placeholders, sentinels);
|
|
14232
15169
|
}
|
|
14233
15170
|
|
|
14234
15171
|
// packages/parser/src/parser/preprocess/index.ts
|