@wdprlib/parser 5.2.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 +2211 -1182
- package/dist/index.d.cts +15 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +2211 -1182
- 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/module/listpages/resolution/items.ts +2 -2
- package/src/parser/rules/block/module/listpages/resolution/pager.ts +43 -0
- package/src/parser/rules/block/module/listpages/resolution/wrapper.ts +6 -1
- package/src/parser/rules/block/module/listpages/resolve.ts +1 -1
- package/src/parser/rules/block/module/listpages/types/external-data.ts +13 -0
- package/src/parser/rules/block/module/listpages/url-resolution/params.ts +5 -4
- package/src/parser/rules/block/module/resolution/data-maps.ts +75 -3
- package/src/parser/rules/block/module/resolution/resolve-async.ts +12 -3
- 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/pipeline/process.ts +8 -1
- 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")
|
|
@@ -1525,7 +2794,9 @@ function parseInlineUntil(ctx, endType) {
|
|
|
1525
2794
|
nodes.pop();
|
|
1526
2795
|
}
|
|
1527
2796
|
}
|
|
1528
|
-
|
|
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
|
+
}
|
|
1529
2800
|
consumed += result.consumed;
|
|
1530
2801
|
pos += result.consumed;
|
|
1531
2802
|
matched = true;
|
|
@@ -1550,138 +2821,10 @@ var FORMATTING_CLOSE_TOKENS = new Set([
|
|
|
1550
2821
|
"MONO_CLOSE",
|
|
1551
2822
|
"COLOR_MARKER"
|
|
1552
2823
|
]);
|
|
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;
|
|
1635
|
-
}
|
|
1636
|
-
if (token5.type === "WHITESPACE") {
|
|
1637
|
-
pos++;
|
|
1638
|
-
consumed++;
|
|
1639
|
-
continue;
|
|
1640
|
-
}
|
|
1641
|
-
if (!isAttributeNameToken(token5)) {
|
|
1642
|
-
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
|
-
}
|
|
1663
|
-
attrs[name] = valueResult.value;
|
|
1664
|
-
pos++;
|
|
1665
|
-
consumed++;
|
|
1666
|
-
}
|
|
1667
|
-
return { attrs, consumed };
|
|
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 });
|
|
1680
|
-
}
|
|
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 {
|
|
@@ -3012,80 +4136,95 @@ var definitionListRule = {
|
|
|
3012
4136
|
consumed: result.consumed
|
|
3013
4137
|
};
|
|
3014
4138
|
}
|
|
3015
|
-
};
|
|
3016
|
-
|
|
3017
|
-
// packages/parser/src/parser/
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
4139
|
+
};
|
|
4140
|
+
|
|
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);
|
|
4148
|
+
}
|
|
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);
|
|
4163
|
+
for (let i = 0;i < elements.length; i++) {
|
|
4164
|
+
if (!isUnparsedDivParagraph(elements[i]))
|
|
4165
|
+
continue;
|
|
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 = [];
|
|
3025
4173
|
for (let i = 0;i < elements.length; i++) {
|
|
3026
|
-
const
|
|
3027
|
-
if (!
|
|
4174
|
+
const el = elements[i];
|
|
4175
|
+
if (!el)
|
|
3028
4176
|
continue;
|
|
3029
|
-
if (
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
if (result.length > 0) {
|
|
3034
|
-
const spanContent = [...result];
|
|
3035
|
-
result.length = 0;
|
|
3036
|
-
result.push({
|
|
3037
|
-
element: "container",
|
|
3038
|
-
data: {
|
|
3039
|
-
type: "span",
|
|
3040
|
-
attributes: {},
|
|
3041
|
-
elements: spanContent
|
|
3042
|
-
}
|
|
3043
|
-
});
|
|
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: [
|
|
@@ -3398,135 +4544,22 @@ function parseDivOpen(ctx) {
|
|
|
3398
4544
|
pos++;
|
|
3399
4545
|
consumed++;
|
|
3400
4546
|
}
|
|
3401
|
-
return {
|
|
3402
|
-
blockName: nameResult.name,
|
|
3403
|
-
paragraphStrip: nameResult.name === "div_",
|
|
3404
|
-
attributes: attrResult.attrs,
|
|
3405
|
-
bodyStart: pos,
|
|
3406
|
-
consumed,
|
|
3407
|
-
hasRequiredNewline
|
|
3408
|
-
};
|
|
3409
|
-
}
|
|
3410
|
-
function isDivBlockName(name) {
|
|
3411
|
-
return name === "div" || name === "div_";
|
|
3412
|
-
}
|
|
3413
|
-
|
|
3414
|
-
// packages/parser/src/parser/rules/block/div/index.ts
|
|
3415
|
-
var divRule = {
|
|
3416
|
-
name: "div",
|
|
3417
|
-
startTokens: ["BLOCK_OPEN"],
|
|
3418
|
-
requiresLineStart: false,
|
|
3419
|
-
parse(ctx) {
|
|
3420
|
-
const openToken = currentToken(ctx);
|
|
3421
|
-
if (openToken.type !== "BLOCK_OPEN") {
|
|
3422
|
-
return { success: false };
|
|
3423
|
-
}
|
|
3424
|
-
const openResult = parseDivOpen(ctx);
|
|
3425
|
-
if (!openResult) {
|
|
3426
|
-
return { success: false };
|
|
3427
|
-
}
|
|
3428
|
-
if (!openResult.hasRequiredNewline) {
|
|
3429
|
-
return consumeFailedDiv(ctx);
|
|
3430
|
-
}
|
|
3431
|
-
if (ctx.scope.divClosesBudget === 0) {
|
|
3432
|
-
return { success: false };
|
|
3433
|
-
}
|
|
3434
|
-
const openPosition = openToken.position;
|
|
3435
|
-
let pos = openResult.bodyStart;
|
|
3436
|
-
let consumed = openResult.consumed;
|
|
3437
|
-
const bodyResult = parseDivBody(ctx, pos, openResult.paragraphStrip);
|
|
3438
|
-
consumed += bodyResult.consumed;
|
|
3439
|
-
pos += bodyResult.consumed;
|
|
3440
|
-
if (ctx.tokens[pos]?.type !== "BLOCK_END_OPEN") {
|
|
3441
|
-
ctx.diagnostics.push({
|
|
3442
|
-
severity: "warning",
|
|
3443
|
-
code: "unclosed-block",
|
|
3444
|
-
message: `Missing closing tag [[/div]] for [[${openResult.blockName}]]`,
|
|
3445
|
-
position: openPosition
|
|
3446
|
-
});
|
|
3447
|
-
}
|
|
3448
|
-
if (ctx.tokens[pos]?.type === "BLOCK_END_OPEN") {
|
|
3449
|
-
const closeResult = consumeDivClose(ctx, pos);
|
|
3450
|
-
pos = closeResult.pos;
|
|
3451
|
-
consumed += closeResult.consumed;
|
|
3452
|
-
}
|
|
3453
|
-
return {
|
|
3454
|
-
success: true,
|
|
3455
|
-
elements: [
|
|
3456
|
-
{
|
|
3457
|
-
element: "container",
|
|
3458
|
-
data: {
|
|
3459
|
-
type: "div",
|
|
3460
|
-
attributes: openResult.attributes,
|
|
3461
|
-
elements: bodyResult.elements
|
|
3462
|
-
}
|
|
3463
|
-
}
|
|
3464
|
-
],
|
|
3465
|
-
consumed
|
|
3466
|
-
};
|
|
3467
|
-
}
|
|
3468
|
-
};
|
|
3469
|
-
|
|
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 };
|
|
4547
|
+
return {
|
|
4548
|
+
blockName: nameResult.name,
|
|
4549
|
+
paragraphStrip: nameResult.name === "div_",
|
|
4550
|
+
attributes: attrResult.attrs,
|
|
4551
|
+
bodyStart: pos,
|
|
4552
|
+
consumed,
|
|
4553
|
+
hasRequiredNewline
|
|
4554
|
+
};
|
|
3516
4555
|
}
|
|
3517
|
-
function
|
|
3518
|
-
|
|
3519
|
-
let consumed = 1 + closeNameConsumed;
|
|
3520
|
-
if (ctx.tokens[pos]?.type === "BLOCK_CLOSE") {
|
|
3521
|
-
pos++;
|
|
3522
|
-
consumed++;
|
|
3523
|
-
}
|
|
3524
|
-
return consumed;
|
|
4556
|
+
function isDivBlockName(name) {
|
|
4557
|
+
return name === "div" || name === "div_";
|
|
3525
4558
|
}
|
|
3526
4559
|
|
|
3527
|
-
// packages/parser/src/parser/rules/block/
|
|
3528
|
-
var
|
|
3529
|
-
name: "
|
|
4560
|
+
// packages/parser/src/parser/rules/block/div/index.ts
|
|
4561
|
+
var divRule = {
|
|
4562
|
+
name: "div",
|
|
3530
4563
|
startTokens: ["BLOCK_OPEN"],
|
|
3531
4564
|
requiresLineStart: false,
|
|
3532
4565
|
parse(ctx) {
|
|
@@ -3534,56 +4567,49 @@ var codeBlockRule = {
|
|
|
3534
4567
|
if (openToken.type !== "BLOCK_OPEN") {
|
|
3535
4568
|
return { success: false };
|
|
3536
4569
|
}
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
const nameResult = parseBlockName(ctx, pos);
|
|
3540
|
-
if (!nameResult || nameResult.name !== "code") {
|
|
4570
|
+
const openResult = parseDivOpen(ctx);
|
|
4571
|
+
if (!openResult) {
|
|
3541
4572
|
return { success: false };
|
|
3542
4573
|
}
|
|
3543
|
-
|
|
3544
|
-
|
|
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++;
|
|
4574
|
+
if (!openResult.hasRequiredNewline) {
|
|
4575
|
+
return consumeFailedDiv(ctx);
|
|
3557
4576
|
}
|
|
3558
|
-
if (ctx.
|
|
3559
|
-
|
|
3560
|
-
consumed++;
|
|
4577
|
+
if (ctx.scope.divClosesBudget === 0) {
|
|
4578
|
+
return { success: false };
|
|
3561
4579
|
}
|
|
3562
|
-
const
|
|
3563
|
-
let
|
|
3564
|
-
consumed
|
|
3565
|
-
pos
|
|
3566
|
-
|
|
4580
|
+
const openPosition = openToken.position;
|
|
4581
|
+
let pos = openResult.bodyStart;
|
|
4582
|
+
let consumed = openResult.consumed;
|
|
4583
|
+
const bodyResult = parseDivBody(ctx, pos, openResult.paragraphStrip);
|
|
4584
|
+
consumed += bodyResult.consumed;
|
|
4585
|
+
pos += bodyResult.consumed;
|
|
4586
|
+
if (ctx.tokens[pos]?.type !== "BLOCK_END_OPEN") {
|
|
3567
4587
|
ctx.diagnostics.push({
|
|
3568
4588
|
severity: "warning",
|
|
3569
4589
|
code: "unclosed-block",
|
|
3570
|
-
message:
|
|
3571
|
-
position:
|
|
4590
|
+
message: `Missing closing tag [[/div]] for [[${openResult.blockName}]]`,
|
|
4591
|
+
position: openPosition
|
|
3572
4592
|
});
|
|
3573
4593
|
}
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
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;
|
|
4594
|
+
if (ctx.tokens[pos]?.type === "BLOCK_END_OPEN") {
|
|
4595
|
+
const closeResult = consumeDivClose(ctx, pos);
|
|
4596
|
+
pos = closeResult.pos;
|
|
4597
|
+
consumed += closeResult.consumed;
|
|
3585
4598
|
}
|
|
3586
|
-
return {
|
|
4599
|
+
return {
|
|
4600
|
+
success: true,
|
|
4601
|
+
elements: [
|
|
4602
|
+
{
|
|
4603
|
+
element: "container",
|
|
4604
|
+
data: {
|
|
4605
|
+
type: "div",
|
|
4606
|
+
attributes: openResult.attributes,
|
|
4607
|
+
elements: bodyResult.elements
|
|
4608
|
+
}
|
|
4609
|
+
}
|
|
4610
|
+
],
|
|
4611
|
+
consumed
|
|
4612
|
+
};
|
|
3587
4613
|
}
|
|
3588
4614
|
};
|
|
3589
4615
|
|
|
@@ -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;
|
|
@@ -6253,9 +7282,9 @@ function renderListPagesItems(module2, data, compiledTemplate, parse) {
|
|
|
6253
7282
|
continue;
|
|
6254
7283
|
const ctx = {
|
|
6255
7284
|
page,
|
|
6256
|
-
index: i + 1,
|
|
7285
|
+
index: (data.pagination?.offset ?? 0) + i + 1,
|
|
6257
7286
|
total: data.totalCount,
|
|
6258
|
-
limit: module2.limit,
|
|
7287
|
+
limit: data.pagination ? data.pagination.limit : module2.limit,
|
|
6259
7288
|
site: data.site
|
|
6260
7289
|
};
|
|
6261
7290
|
const itemAst = getModuleParseAst(parse(compiledTemplate(ctx)));
|
|
@@ -6275,9 +7304,46 @@ function renderListPagesItems(module2, data, compiledTemplate, parse) {
|
|
|
6275
7304
|
return items;
|
|
6276
7305
|
}
|
|
6277
7306
|
|
|
7307
|
+
// packages/parser/src/parser/rules/block/module/listpages/resolution/pager.ts
|
|
7308
|
+
function createListPagesPager(data) {
|
|
7309
|
+
const pagination = data.pagination;
|
|
7310
|
+
if (!pagination || pagination.totalPages <= 1)
|
|
7311
|
+
return [];
|
|
7312
|
+
const { currentPage, totalPages, urlPath, parameter } = pagination;
|
|
7313
|
+
const pages = new Set([1, totalPages]);
|
|
7314
|
+
for (let page = Math.max(1, currentPage - 2);page <= Math.min(totalPages, currentPage + 2); page++) {
|
|
7315
|
+
pages.add(page);
|
|
7316
|
+
}
|
|
7317
|
+
return [
|
|
7318
|
+
{
|
|
7319
|
+
element: "pager",
|
|
7320
|
+
data: {
|
|
7321
|
+
currentPage,
|
|
7322
|
+
totalPages,
|
|
7323
|
+
pages: [...pages].sort((a, b) => a - b).map((page) => ({
|
|
7324
|
+
page,
|
|
7325
|
+
href: pageUrl(urlPath, parameter, page)
|
|
7326
|
+
}))
|
|
7327
|
+
}
|
|
7328
|
+
}
|
|
7329
|
+
];
|
|
7330
|
+
}
|
|
7331
|
+
function pageUrl(urlPath, parameter, page) {
|
|
7332
|
+
const suffixStart = urlPath.search(/[?#]/);
|
|
7333
|
+
const path = suffixStart === -1 ? urlPath : urlPath.slice(0, suffixStart);
|
|
7334
|
+
const suffix = suffixStart === -1 ? "" : urlPath.slice(suffixStart);
|
|
7335
|
+
const parts = path.split("/");
|
|
7336
|
+
const result = parts.slice(0, 2);
|
|
7337
|
+
for (let index = 2;index < parts.length; index += 2) {
|
|
7338
|
+
if (parts[index] !== parameter)
|
|
7339
|
+
result.push(...parts.slice(index, index + 2));
|
|
7340
|
+
}
|
|
7341
|
+
return `${result.join("/").replace(/\/$/, "")}/${parameter}/${page}${suffix}`;
|
|
7342
|
+
}
|
|
7343
|
+
|
|
6278
7344
|
// packages/parser/src/parser/rules/block/module/listpages/resolution/wrapper.ts
|
|
6279
|
-
function wrapListPagesResult(module2, items, parse) {
|
|
6280
|
-
if (items.length === 0) {
|
|
7345
|
+
function wrapListPagesResult(module2, items, parse, data) {
|
|
7346
|
+
if (items.length === 0 && (!data || data.pages.length === 0)) {
|
|
6281
7347
|
return [];
|
|
6282
7348
|
}
|
|
6283
7349
|
const result = [];
|
|
@@ -6290,6 +7356,8 @@ function wrapListPagesResult(module2, items, parse) {
|
|
|
6290
7356
|
const appendAst = getModuleParseAst(parse(module2["append-line"]));
|
|
6291
7357
|
result.push(...appendAst.elements);
|
|
6292
7358
|
}
|
|
7359
|
+
if (data)
|
|
7360
|
+
result.push(...createListPagesPager(data));
|
|
6293
7361
|
if (module2.wrapper) {
|
|
6294
7362
|
return [
|
|
6295
7363
|
{
|
|
@@ -6311,7 +7379,7 @@ function isListPagesModule2(module2) {
|
|
|
6311
7379
|
}
|
|
6312
7380
|
function resolveListPages(module2, data, compiledTemplate, parse) {
|
|
6313
7381
|
const items = renderListPagesItems(module2, data, compiledTemplate, parse);
|
|
6314
|
-
return wrapListPagesResult(module2, items, parse);
|
|
7382
|
+
return wrapListPagesResult(module2, items, parse, data);
|
|
6315
7383
|
}
|
|
6316
7384
|
// packages/parser/src/parser/rules/block/module/listpages/types/external-data.ts
|
|
6317
7385
|
function definePageData(input) {
|
|
@@ -6408,10 +7476,10 @@ var URL_RESOLVABLE_FIELDS = [
|
|
|
6408
7476
|
];
|
|
6409
7477
|
|
|
6410
7478
|
// packages/parser/src/parser/rules/block/module/listpages/url-resolution/params.ts
|
|
6411
|
-
function parseUrlParams(url) {
|
|
7479
|
+
function parseUrlParams(url, hasPageName = false) {
|
|
6412
7480
|
const params = new Map;
|
|
6413
|
-
const parts = url.split("/").filter(Boolean);
|
|
6414
|
-
const pairStart = isUrlParameter(parts[0]) ? 0 : 1;
|
|
7481
|
+
const parts = url.split(/[?#]/, 1)[0].split("/").filter(Boolean);
|
|
7482
|
+
const pairStart = !hasPageName && isUrlParameter(parts[0]) ? 0 : 1;
|
|
6415
7483
|
for (let i = pairStart;i < parts.length - 1; i += 2) {
|
|
6416
7484
|
const key = parts[i];
|
|
6417
7485
|
const value = parts[i + 1];
|
|
@@ -6814,7 +7882,7 @@ function resolveIfTags(data, pageTags) {
|
|
|
6814
7882
|
// packages/parser/src/parser/preprocess/utils/raw-regions.ts
|
|
6815
7883
|
var BASE_PLACEHOLDER_OPEN = "";
|
|
6816
7884
|
var BASE_PLACEHOLDER_CLOSE = "";
|
|
6817
|
-
var RAW_BLOCK_OPEN_PATTERN = /\[\[
|
|
7885
|
+
var RAW_BLOCK_OPEN_PATTERN = /\[\[html\b[^\]]*\]\]/iy;
|
|
6818
7886
|
function makeUniqueSentinels(source) {
|
|
6819
7887
|
let openRun = 0;
|
|
6820
7888
|
let closeRun = 0;
|
|
@@ -6833,10 +7901,21 @@ function makeUniqueSentinels(source) {
|
|
|
6833
7901
|
}
|
|
6834
7902
|
function maskRawRegions(source, sentinels) {
|
|
6835
7903
|
const placeholders = [];
|
|
7904
|
+
let tokens;
|
|
7905
|
+
const getTokens = () => tokens ??= tokenize(source);
|
|
6836
7906
|
let masked = "";
|
|
6837
7907
|
let i = 0;
|
|
6838
7908
|
while (i < source.length) {
|
|
6839
|
-
|
|
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);
|
|
6840
7919
|
if (rawBlock) {
|
|
6841
7920
|
masked += rawBlock.placeholder;
|
|
6842
7921
|
i = rawBlock.end;
|
|
@@ -6857,16 +7936,25 @@ function restorePlaceholders(source, placeholders, sentinels) {
|
|
|
6857
7936
|
const pattern = new RegExp(`${escapeRegex(sentinels.open)}(\\d+)${escapeRegex(sentinels.close)}`, "g");
|
|
6858
7937
|
return source.replace(pattern, (_, idx) => placeholders[Number(idx)] ?? "");
|
|
6859
7938
|
}
|
|
6860
|
-
function tryMaskRawBlock(source, pos, placeholders, sentinels) {
|
|
7939
|
+
function tryMaskRawBlock(source, pos, placeholders, sentinels, getTokens) {
|
|
6861
7940
|
if (source[pos] !== "[" || source[pos + 1] !== "[")
|
|
6862
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
|
+
}
|
|
6863
7952
|
RAW_BLOCK_OPEN_PATTERN.lastIndex = pos;
|
|
6864
7953
|
const openMatch = RAW_BLOCK_OPEN_PATTERN.exec(source);
|
|
6865
7954
|
if (!openMatch)
|
|
6866
7955
|
return null;
|
|
6867
|
-
const name = openMatch[1].toLowerCase();
|
|
6868
7956
|
const openLen = openMatch[0].length;
|
|
6869
|
-
const closePattern =
|
|
7957
|
+
const closePattern = /\[\[\/\s*html\s*\]\]/gi;
|
|
6870
7958
|
closePattern.lastIndex = pos + openLen;
|
|
6871
7959
|
const closeMatch = closePattern.exec(source);
|
|
6872
7960
|
if (closeMatch) {
|
|
@@ -6876,12 +7964,19 @@ function tryMaskRawBlock(source, pos, placeholders, sentinels) {
|
|
|
6876
7964
|
end
|
|
6877
7965
|
};
|
|
6878
7966
|
}
|
|
6879
|
-
|
|
6880
|
-
|
|
6881
|
-
|
|
6882
|
-
|
|
6883
|
-
|
|
6884
|
-
|
|
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;
|
|
6885
7980
|
}
|
|
6886
7981
|
function tryMaskRawInline(source, pos, placeholders, sentinels) {
|
|
6887
7982
|
if (source[pos] === "@" && source[pos + 1] === "<") {
|
|
@@ -6893,17 +7988,22 @@ function tryMaskRawInline(source, pos, placeholders, sentinels) {
|
|
|
6893
7988
|
return null;
|
|
6894
7989
|
}
|
|
6895
7990
|
function tryMaskSingleLineRaw(source, pos, openerLength, close, placeholders, sentinels) {
|
|
6896
|
-
const
|
|
6897
|
-
|
|
6898
|
-
`, pos + openerLength);
|
|
6899
|
-
if (closePos === -1 || newline !== -1 && newline < closePos)
|
|
7991
|
+
const end = singleLineRawEnd(source, pos, openerLength, close);
|
|
7992
|
+
if (end === pos)
|
|
6900
7993
|
return null;
|
|
6901
|
-
const end = closePos + close.length;
|
|
6902
7994
|
return {
|
|
6903
7995
|
placeholder: pushPlaceholder(placeholders, source.slice(pos, end), sentinels),
|
|
6904
7996
|
end
|
|
6905
7997
|
};
|
|
6906
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
|
+
}
|
|
6907
8007
|
function pushPlaceholder(placeholders, text, sentinels) {
|
|
6908
8008
|
const idx = placeholders.length;
|
|
6909
8009
|
placeholders.push(text);
|
|
@@ -7509,18 +8609,66 @@ function resolveListUsers(_module, data, compiledTemplate, parse) {
|
|
|
7509
8609
|
return itemAst.elements;
|
|
7510
8610
|
}
|
|
7511
8611
|
// packages/parser/src/parser/rules/block/module/resolution/data-maps.ts
|
|
7512
|
-
async function buildListPagesDataMap(dataProvider, requirements, urlPath) {
|
|
8612
|
+
async function buildListPagesDataMap(dataProvider, requirements, urlPath, paginationState = { nextUnprefixed: 1 }) {
|
|
7513
8613
|
const dataMap = new Map;
|
|
7514
|
-
const urlParams = parseUrlParams(urlPath ?? "");
|
|
8614
|
+
const urlParams = parseUrlParams(urlPath ?? "", true);
|
|
7515
8615
|
for (const req of requirements) {
|
|
7516
8616
|
const normalizedQuery = resolveAndNormalizeQuery(req, urlParams);
|
|
7517
|
-
|
|
8617
|
+
if (!urlPath || !urlPath.startsWith("/") || urlPath.startsWith("//")) {
|
|
8618
|
+
const data2 = await dataProvider.fetchListPages?.(normalizedQuery, req);
|
|
8619
|
+
if (data2)
|
|
8620
|
+
dataMap.set(req.id, data2);
|
|
8621
|
+
continue;
|
|
8622
|
+
}
|
|
8623
|
+
const ordinal = req.urlAttrPrefix ? 0 : paginationState.nextUnprefixed++;
|
|
8624
|
+
const parameter = req.urlAttrPrefix ? `${encodeURIComponent(req.urlAttrPrefix)}_p` : ordinal === 1 ? "p" : `p${ordinal}`;
|
|
8625
|
+
const perPage = Math.min(250, positiveInteger(normalizedQuery.perPage, 20));
|
|
8626
|
+
const baseOffset = positiveInteger(normalizedQuery.offset, 0);
|
|
8627
|
+
const limit = normalizedQuery.limit !== undefined && normalizedQuery.limit >= 0 ? Math.floor(normalizedQuery.limit) : undefined;
|
|
8628
|
+
const rawPage = urlParams.get(parameter) ?? "1";
|
|
8629
|
+
let currentPage = /^\d+$/.test(rawPage) ? positiveInteger(Number(rawPage), 1) : 1;
|
|
8630
|
+
currentPage = Math.min(currentPage, Math.floor((Number.MAX_SAFE_INTEGER - baseOffset) / perPage) + 1);
|
|
8631
|
+
if (limit !== undefined)
|
|
8632
|
+
currentPage = Math.min(currentPage, Math.max(1, Math.ceil(limit / perPage)));
|
|
8633
|
+
const fetchPage = () => {
|
|
8634
|
+
const relativeOffset = (currentPage - 1) * perPage;
|
|
8635
|
+
return dataProvider.fetchListPages?.({
|
|
8636
|
+
...normalizedQuery,
|
|
8637
|
+
offset: baseOffset + relativeOffset,
|
|
8638
|
+
limit: Math.min(perPage, limit === undefined ? perPage : Math.max(0, limit - relativeOffset)),
|
|
8639
|
+
perPage
|
|
8640
|
+
}, req);
|
|
8641
|
+
};
|
|
8642
|
+
let data = await fetchPage();
|
|
7518
8643
|
if (data) {
|
|
7519
|
-
|
|
8644
|
+
const count = Math.min(Math.max(0, data.totalCount - baseOffset), limit ?? Infinity);
|
|
8645
|
+
const totalPages = Math.ceil(count / perPage);
|
|
8646
|
+
const lastPage = Math.max(1, totalPages);
|
|
8647
|
+
if (currentPage > lastPage) {
|
|
8648
|
+
currentPage = lastPage;
|
|
8649
|
+
data = await fetchPage();
|
|
8650
|
+
}
|
|
8651
|
+
if (data)
|
|
8652
|
+
dataMap.set(req.id, {
|
|
8653
|
+
...data,
|
|
8654
|
+
pages: data.pages.slice(0, Math.min(perPage, Math.max(0, count - (currentPage - 1) * perPage))),
|
|
8655
|
+
pagination: {
|
|
8656
|
+
currentPage,
|
|
8657
|
+
perPage,
|
|
8658
|
+
totalPages,
|
|
8659
|
+
offset: baseOffset + (currentPage - 1) * perPage,
|
|
8660
|
+
limit,
|
|
8661
|
+
urlPath,
|
|
8662
|
+
parameter
|
|
8663
|
+
}
|
|
8664
|
+
});
|
|
7520
8665
|
}
|
|
7521
8666
|
}
|
|
7522
8667
|
return dataMap;
|
|
7523
8668
|
}
|
|
8669
|
+
function positiveInteger(value, fallback) {
|
|
8670
|
+
return value !== undefined && Number.isSafeInteger(value) && value > 0 ? value : fallback;
|
|
8671
|
+
}
|
|
7524
8672
|
async function buildListUsersDataMap(dataProvider, requirements) {
|
|
7525
8673
|
const dataMap = new Map;
|
|
7526
8674
|
for (const req of requirements) {
|
|
@@ -9022,167 +10170,32 @@ function parseVariables(tokens) {
|
|
|
9022
10170
|
for (const token5 of tokens) {
|
|
9023
10171
|
if (token5 === "|") {
|
|
9024
10172
|
assignVariable(vars, current2);
|
|
9025
|
-
current2 = "";
|
|
9026
|
-
} else {
|
|
9027
|
-
current2 += token5;
|
|
9028
|
-
}
|
|
9029
|
-
}
|
|
9030
|
-
assignVariable(vars, current2);
|
|
9031
|
-
return vars;
|
|
9032
|
-
}
|
|
9033
|
-
function assignVariable(vars, source) {
|
|
9034
|
-
if (!source.trim()) {
|
|
9035
|
-
return;
|
|
9036
|
-
}
|
|
9037
|
-
const eqIndex = source.indexOf("=");
|
|
9038
|
-
if (eqIndex === -1) {
|
|
9039
|
-
return;
|
|
9040
|
-
}
|
|
9041
|
-
const key = source.slice(0, eqIndex).trim();
|
|
9042
|
-
if (!key) {
|
|
9043
|
-
return;
|
|
9044
|
-
}
|
|
9045
|
-
vars[key] = source.slice(eqIndex + 1).trim();
|
|
9046
|
-
}
|
|
9047
|
-
|
|
9048
|
-
// packages/parser/src/parser/rules/block/include/index.ts
|
|
9049
|
-
var includeRule = {
|
|
9050
|
-
name: "include",
|
|
9051
|
-
startTokens: ["BLOCK_OPEN"],
|
|
9052
|
-
requiresLineStart: false,
|
|
9053
|
-
parse(ctx) {
|
|
9054
|
-
const openToken = currentToken(ctx);
|
|
9055
|
-
if (openToken.type !== "BLOCK_OPEN") {
|
|
9056
|
-
return { success: false };
|
|
9057
|
-
}
|
|
9058
|
-
let pos = ctx.pos + 1;
|
|
9059
|
-
let consumed = 1;
|
|
9060
|
-
const nameResult = parseBlockName(ctx, pos);
|
|
9061
|
-
if (!nameResult || nameResult.name.toLowerCase() !== "include") {
|
|
9062
|
-
return { success: false };
|
|
9063
|
-
}
|
|
9064
|
-
if (!ctx.settings.enablePageSyntax) {
|
|
9065
|
-
return { success: false };
|
|
9066
|
-
}
|
|
9067
|
-
pos += nameResult.consumed;
|
|
9068
|
-
consumed += nameResult.consumed;
|
|
9069
|
-
while (ctx.tokens[pos]?.type === "WHITESPACE") {
|
|
9070
|
-
pos++;
|
|
9071
|
-
consumed++;
|
|
9072
|
-
}
|
|
9073
|
-
const args = collectIncludeArguments(ctx, pos);
|
|
9074
|
-
pos += args.consumed;
|
|
9075
|
-
consumed += args.consumed;
|
|
9076
|
-
if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
|
|
9077
|
-
return { success: false };
|
|
9078
|
-
}
|
|
9079
|
-
pos++;
|
|
9080
|
-
consumed++;
|
|
9081
|
-
const directiveEnd = pos;
|
|
9082
|
-
if (ctx.tokens[pos]?.type === "NEWLINE") {
|
|
9083
|
-
pos++;
|
|
9084
|
-
consumed++;
|
|
9085
|
-
}
|
|
9086
|
-
if (!args.target) {
|
|
9087
|
-
return { success: false };
|
|
9088
|
-
}
|
|
9089
|
-
const location = parsePageRef(args.target);
|
|
9090
|
-
if (ctx.deferInclude?.(location)) {
|
|
9091
|
-
const source = ctx.tokens.slice(ctx.pos, directiveEnd).map((token5) => token5.value).join("");
|
|
9092
|
-
const elements = [];
|
|
9093
|
-
const lines = source.split(`
|
|
9094
|
-
`);
|
|
9095
|
-
for (let index = 0;index < lines.length; index++) {
|
|
9096
|
-
if (index > 0)
|
|
9097
|
-
elements.push(import_ast5.lineBreak());
|
|
9098
|
-
if (lines[index] !== "")
|
|
9099
|
-
elements.push(import_ast5.text(lines[index]));
|
|
9100
|
-
}
|
|
9101
|
-
return { success: true, elements: [import_ast5.paragraph(elements)], consumed };
|
|
9102
|
-
}
|
|
9103
|
-
return {
|
|
9104
|
-
success: true,
|
|
9105
|
-
elements: [
|
|
9106
|
-
{
|
|
9107
|
-
element: "include",
|
|
9108
|
-
data: {
|
|
9109
|
-
"paragraph-safe": false,
|
|
9110
|
-
variables: parseVariables(args.argumentTokens),
|
|
9111
|
-
location,
|
|
9112
|
-
elements: []
|
|
9113
|
-
}
|
|
9114
|
-
}
|
|
9115
|
-
],
|
|
9116
|
-
consumed
|
|
9117
|
-
};
|
|
9118
|
-
}
|
|
9119
|
-
};
|
|
9120
|
-
|
|
9121
|
-
// packages/parser/src/parser/rules/block/math/content.ts
|
|
9122
|
-
function collectMathContent(ctx, startPos) {
|
|
9123
|
-
let latexSource = "";
|
|
9124
|
-
let pos = startPos;
|
|
9125
|
-
let consumed = 0;
|
|
9126
|
-
let foundClose = false;
|
|
9127
|
-
while (pos < ctx.tokens.length) {
|
|
9128
|
-
const token5 = ctx.tokens[pos];
|
|
9129
|
-
if (!token5)
|
|
9130
|
-
break;
|
|
9131
|
-
if (token5.type === "BLOCK_END_OPEN") {
|
|
9132
|
-
const closeNameResult = parseBlockName(ctx, pos + 1);
|
|
9133
|
-
if (closeNameResult?.name === "math") {
|
|
9134
|
-
foundClose = true;
|
|
9135
|
-
break;
|
|
9136
|
-
}
|
|
9137
|
-
}
|
|
9138
|
-
latexSource += token5.type === "BACKSLASH_BREAK" ? "\\\n" : token5.value;
|
|
9139
|
-
pos++;
|
|
9140
|
-
consumed++;
|
|
9141
|
-
}
|
|
9142
|
-
return { latexSource, consumed, foundClose };
|
|
9143
|
-
}
|
|
9144
|
-
function consumeMathClose(ctx, startPos) {
|
|
9145
|
-
let pos = startPos + 1;
|
|
9146
|
-
let consumed = 1;
|
|
9147
|
-
const closeNameResult = parseBlockName(ctx, pos);
|
|
9148
|
-
if (closeNameResult) {
|
|
9149
|
-
pos += closeNameResult.consumed;
|
|
9150
|
-
consumed += closeNameResult.consumed;
|
|
9151
|
-
}
|
|
9152
|
-
if (ctx.tokens[pos]?.type === "BLOCK_CLOSE") {
|
|
9153
|
-
pos++;
|
|
9154
|
-
consumed++;
|
|
9155
|
-
}
|
|
9156
|
-
if (ctx.tokens[pos]?.type === "NEWLINE") {
|
|
9157
|
-
consumed++;
|
|
10173
|
+
current2 = "";
|
|
10174
|
+
} else {
|
|
10175
|
+
current2 += token5;
|
|
10176
|
+
}
|
|
9158
10177
|
}
|
|
9159
|
-
|
|
10178
|
+
assignVariable(vars, current2);
|
|
10179
|
+
return vars;
|
|
9160
10180
|
}
|
|
9161
|
-
|
|
9162
|
-
|
|
9163
|
-
|
|
9164
|
-
let pos = startPos;
|
|
9165
|
-
let consumed = 0;
|
|
9166
|
-
let name = "";
|
|
9167
|
-
const first = ctx.tokens[pos];
|
|
9168
|
-
if (first?.type !== "IDENTIFIER" && first?.type !== "TEXT") {
|
|
9169
|
-
return { name: null, consumed: 0 };
|
|
10181
|
+
function assignVariable(vars, source) {
|
|
10182
|
+
if (!source.trim()) {
|
|
10183
|
+
return;
|
|
9170
10184
|
}
|
|
9171
|
-
|
|
9172
|
-
|
|
9173
|
-
|
|
9174
|
-
|
|
9175
|
-
|
|
9176
|
-
|
|
9177
|
-
|
|
9178
|
-
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;
|
|
9179
10192
|
}
|
|
9180
|
-
|
|
10193
|
+
vars[key] = source.slice(eqIndex + 1).trim();
|
|
9181
10194
|
}
|
|
9182
10195
|
|
|
9183
|
-
// packages/parser/src/parser/rules/block/
|
|
9184
|
-
var
|
|
9185
|
-
name: "
|
|
10196
|
+
// packages/parser/src/parser/rules/block/include/index.ts
|
|
10197
|
+
var includeRule = {
|
|
10198
|
+
name: "include",
|
|
9186
10199
|
startTokens: ["BLOCK_OPEN"],
|
|
9187
10200
|
requiresLineStart: false,
|
|
9188
10201
|
parse(ctx) {
|
|
@@ -9193,7 +10206,10 @@ var mathBlockRule = {
|
|
|
9193
10206
|
let pos = ctx.pos + 1;
|
|
9194
10207
|
let consumed = 1;
|
|
9195
10208
|
const nameResult = parseBlockName(ctx, pos);
|
|
9196
|
-
if (!nameResult || nameResult.name !== "
|
|
10209
|
+
if (!nameResult || nameResult.name.toLowerCase() !== "include") {
|
|
10210
|
+
return { success: false };
|
|
10211
|
+
}
|
|
10212
|
+
if (!ctx.settings.enablePageSyntax) {
|
|
9197
10213
|
return { success: false };
|
|
9198
10214
|
}
|
|
9199
10215
|
pos += nameResult.consumed;
|
|
@@ -9202,49 +10218,46 @@ var mathBlockRule = {
|
|
|
9202
10218
|
pos++;
|
|
9203
10219
|
consumed++;
|
|
9204
10220
|
}
|
|
9205
|
-
const
|
|
9206
|
-
pos +=
|
|
9207
|
-
consumed +=
|
|
9208
|
-
while (ctx.tokens[pos]?.type === "WHITESPACE") {
|
|
9209
|
-
pos++;
|
|
9210
|
-
consumed++;
|
|
9211
|
-
}
|
|
10221
|
+
const args = collectIncludeArguments(ctx, pos);
|
|
10222
|
+
pos += args.consumed;
|
|
10223
|
+
consumed += args.consumed;
|
|
9212
10224
|
if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
|
|
9213
10225
|
return { success: false };
|
|
9214
10226
|
}
|
|
9215
10227
|
pos++;
|
|
9216
10228
|
consumed++;
|
|
10229
|
+
const directiveEnd = pos;
|
|
9217
10230
|
if (ctx.tokens[pos]?.type === "NEWLINE") {
|
|
9218
10231
|
pos++;
|
|
9219
10232
|
consumed++;
|
|
9220
10233
|
}
|
|
9221
|
-
|
|
9222
|
-
const latexSource = contentResult.latexSource.trim();
|
|
9223
|
-
consumed += contentResult.consumed;
|
|
9224
|
-
pos += contentResult.consumed;
|
|
9225
|
-
if (!contentResult.foundClose) {
|
|
9226
|
-
ctx.diagnostics.push({
|
|
9227
|
-
severity: "warning",
|
|
9228
|
-
code: "unclosed-block",
|
|
9229
|
-
message: "Missing closing tag [[/math]] for [[math]]",
|
|
9230
|
-
position: openToken.position
|
|
9231
|
-
});
|
|
9232
|
-
} else {
|
|
9233
|
-
const closeConsumed = consumeMathClose(ctx, pos);
|
|
9234
|
-
pos += closeConsumed;
|
|
9235
|
-
consumed += closeConsumed;
|
|
9236
|
-
}
|
|
9237
|
-
if (!latexSource) {
|
|
10234
|
+
if (!args.target) {
|
|
9238
10235
|
return { success: false };
|
|
9239
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
|
+
}
|
|
9240
10251
|
return {
|
|
9241
10252
|
success: true,
|
|
9242
10253
|
elements: [
|
|
9243
10254
|
{
|
|
9244
|
-
element: "
|
|
10255
|
+
element: "include",
|
|
9245
10256
|
data: {
|
|
9246
|
-
|
|
9247
|
-
|
|
10257
|
+
"paragraph-safe": false,
|
|
10258
|
+
variables: parseVariables(args.argumentTokens),
|
|
10259
|
+
location,
|
|
10260
|
+
elements: []
|
|
9248
10261
|
}
|
|
9249
10262
|
}
|
|
9250
10263
|
],
|
|
@@ -10114,7 +11127,8 @@ function parseBibliographyContent(ctx, startPos) {
|
|
|
10114
11127
|
const inlineCtx = { ...ctx, pos };
|
|
10115
11128
|
const result = parseInlineUntil(inlineCtx, "NEWLINE");
|
|
10116
11129
|
if (result.elements.length > 0) {
|
|
10117
|
-
|
|
11130
|
+
for (const element of result.elements)
|
|
11131
|
+
content.push(element);
|
|
10118
11132
|
pos += result.consumed;
|
|
10119
11133
|
consumed += result.consumed;
|
|
10120
11134
|
} else {
|
|
@@ -10543,6 +11557,7 @@ var blockRules = [
|
|
|
10543
11557
|
iftagsRule,
|
|
10544
11558
|
bibliographyRule,
|
|
10545
11559
|
galleryRule,
|
|
11560
|
+
noteRule,
|
|
10546
11561
|
divRule
|
|
10547
11562
|
];
|
|
10548
11563
|
// packages/parser/src/parser/rules/inline/formatting/close.ts
|
|
@@ -10555,6 +11570,11 @@ function findFormattingClose(ctx, start, marker) {
|
|
|
10555
11570
|
return null;
|
|
10556
11571
|
if (!table && token5.type === "NEWLINE" && getParagraphNewlineBoundary(ctx, pos, true).shouldBreak)
|
|
10557
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
|
+
}
|
|
10558
11578
|
if (token5.type === marker && !table?.suppressedClosers.has(pos))
|
|
10559
11579
|
return pos;
|
|
10560
11580
|
const protectedEnd = protectedInlineRegionEnd(ctx.tokens, pos, end);
|
|
@@ -10600,253 +11620,93 @@ function parseDelimitedContainer(ctx, closeToken, type, options = {}) {
|
|
|
10600
11620
|
consumed
|
|
10601
11621
|
};
|
|
10602
11622
|
}
|
|
10603
|
-
return {
|
|
10604
|
-
success: true,
|
|
10605
|
-
elements: [createInlineContainer(type, result.elements)],
|
|
10606
|
-
consumed
|
|
10607
|
-
};
|
|
10608
|
-
}
|
|
10609
|
-
|
|
10610
|
-
// packages/parser/src/parser/rules/inline/bold.ts
|
|
10611
|
-
var boldRule = {
|
|
10612
|
-
name: "bold",
|
|
10613
|
-
startTokens: ["BOLD_MARKER"],
|
|
10614
|
-
parse(ctx) {
|
|
10615
|
-
return parseDelimitedContainer(ctx, "BOLD_MARKER", "bold", { discardEmpty: true });
|
|
10616
|
-
}
|
|
10617
|
-
};
|
|
10618
|
-
|
|
10619
|
-
// packages/parser/src/parser/rules/inline/italic.ts
|
|
10620
|
-
var italicRule = {
|
|
10621
|
-
name: "italic",
|
|
10622
|
-
startTokens: ["ITALIC_MARKER"],
|
|
10623
|
-
parse(ctx) {
|
|
10624
|
-
return parseDelimitedContainer(ctx, "ITALIC_MARKER", "italics");
|
|
10625
|
-
}
|
|
10626
|
-
};
|
|
10627
|
-
|
|
10628
|
-
// packages/parser/src/parser/rules/inline/underline/index.ts
|
|
10629
|
-
var underlineRule = {
|
|
10630
|
-
name: "underline",
|
|
10631
|
-
startTokens: ["UNDERLINE_MARKER"],
|
|
10632
|
-
parse(ctx) {
|
|
10633
|
-
return parseDelimitedContainer(ctx, "UNDERLINE_MARKER", "underline", { discardEmpty: true });
|
|
10634
|
-
}
|
|
10635
|
-
};
|
|
10636
|
-
|
|
10637
|
-
// packages/parser/src/parser/rules/inline/strikethrough/parse.ts
|
|
10638
|
-
function parseStrikethroughContent(ctx) {
|
|
10639
|
-
return parseDelimitedContainer(ctx, "STRIKE_MARKER", "strikethrough");
|
|
10640
|
-
}
|
|
10641
|
-
|
|
10642
|
-
// packages/parser/src/parser/rules/inline/strikethrough/syntax.ts
|
|
10643
|
-
function hasValidStrikethroughClose(ctx) {
|
|
10644
|
-
const close = findFormattingClose(ctx, ctx.pos + 1, "STRIKE_MARKER");
|
|
10645
|
-
return close !== null && close > ctx.pos + 1 && ctx.tokens[close - 1]?.type !== "WHITESPACE";
|
|
10646
|
-
}
|
|
10647
|
-
|
|
10648
|
-
// packages/parser/src/parser/rules/inline/strikethrough/index.ts
|
|
10649
|
-
var strikethroughRule = {
|
|
10650
|
-
name: "strikethrough",
|
|
10651
|
-
startTokens: ["STRIKE_MARKER"],
|
|
10652
|
-
parse(ctx) {
|
|
10653
|
-
if (!hasValidStrikethroughClose(ctx)) {
|
|
10654
|
-
return {
|
|
10655
|
-
success: true,
|
|
10656
|
-
elements: [{ element: "text", data: "—" }],
|
|
10657
|
-
consumed: 1
|
|
10658
|
-
};
|
|
10659
|
-
}
|
|
10660
|
-
return parseStrikethroughContent(ctx);
|
|
10661
|
-
}
|
|
10662
|
-
};
|
|
10663
|
-
|
|
10664
|
-
// packages/parser/src/parser/rules/inline/superscript.ts
|
|
10665
|
-
var superscriptRule = {
|
|
10666
|
-
name: "superscript",
|
|
10667
|
-
startTokens: ["SUPER_MARKER"],
|
|
10668
|
-
parse(ctx) {
|
|
10669
|
-
return parseDelimitedContainer(ctx, "SUPER_MARKER", "superscript", {
|
|
10670
|
-
discardEmpty: true
|
|
10671
|
-
});
|
|
10672
|
-
}
|
|
10673
|
-
};
|
|
10674
|
-
|
|
10675
|
-
// packages/parser/src/parser/rules/inline/subscript.ts
|
|
10676
|
-
var subscriptRule = {
|
|
10677
|
-
name: "subscript",
|
|
10678
|
-
startTokens: ["SUB_MARKER"],
|
|
10679
|
-
parse(ctx) {
|
|
10680
|
-
return parseDelimitedContainer(ctx, "SUB_MARKER", "subscript", { discardEmpty: true });
|
|
10681
|
-
}
|
|
10682
|
-
};
|
|
10683
|
-
|
|
10684
|
-
// packages/parser/src/parser/rules/inline/monospace.ts
|
|
10685
|
-
var monospaceRule = {
|
|
10686
|
-
name: "monospace",
|
|
10687
|
-
startTokens: ["MONO_MARKER"],
|
|
10688
|
-
parse(ctx) {
|
|
10689
|
-
return parseDelimitedContainer(ctx, "MONO_CLOSE", "monospace");
|
|
10690
|
-
}
|
|
10691
|
-
};
|
|
10692
|
-
|
|
10693
|
-
// packages/parser/src/parser/rules/inline/link-triple/fallback.ts
|
|
10694
|
-
function literalOpenLink(value) {
|
|
10695
|
-
return {
|
|
10696
|
-
success: true,
|
|
10697
|
-
elements: [{ element: "text", data: value }],
|
|
10698
|
-
consumed: 1
|
|
10699
|
-
};
|
|
10700
|
-
}
|
|
10701
|
-
|
|
10702
|
-
// packages/parser/src/parser/rules/inline/link-triple/label.ts
|
|
10703
|
-
function buildTripleLinkLabel(args) {
|
|
10704
|
-
return {
|
|
10705
|
-
text: getTripleLinkDisplayText(args)
|
|
10706
|
-
};
|
|
10707
|
-
}
|
|
10708
|
-
function getTripleLinkDisplayText(args) {
|
|
10709
|
-
const trimmedLabel = args.labelText.trim();
|
|
10710
|
-
if (args.foundPipe) {
|
|
10711
|
-
return trimmedLabel || args.finalTarget;
|
|
10712
|
-
}
|
|
10713
|
-
const colonIdx = args.originalTarget.indexOf(":");
|
|
10714
|
-
if (colonIdx !== -1 && !args.originalTarget.startsWith("http") && !args.originalTarget.startsWith("*")) {
|
|
10715
|
-
return args.originalTarget.slice(colonIdx + 1).trim();
|
|
10716
|
-
}
|
|
10717
|
-
return args.originalTarget;
|
|
10718
|
-
}
|
|
10719
|
-
|
|
10720
|
-
// packages/parser/src/parser/rules/inline/link-triple/syntax.ts
|
|
10721
|
-
function hasClosingLinkMarker(ctx, startPos) {
|
|
10722
|
-
let pos = startPos;
|
|
10723
|
-
while (pos < ctx.tokens.length) {
|
|
10724
|
-
const token5 = ctx.tokens[pos];
|
|
10725
|
-
if (!token5 || token5.type === "EOF") {
|
|
10726
|
-
return false;
|
|
10727
|
-
}
|
|
10728
|
-
if (token5.type === "LINK_CLOSE") {
|
|
10729
|
-
return true;
|
|
10730
|
-
}
|
|
10731
|
-
if (token5.type === "NEWLINE") {
|
|
10732
|
-
const next = ctx.tokens[pos + 1];
|
|
10733
|
-
if (next?.type === "NEWLINE" || next?.type === "LINK_CLOSE") {
|
|
10734
|
-
return false;
|
|
10735
|
-
}
|
|
10736
|
-
}
|
|
10737
|
-
pos++;
|
|
10738
|
-
}
|
|
10739
|
-
return false;
|
|
10740
|
-
}
|
|
10741
|
-
function collectTripleLinkParts(ctx, startPos) {
|
|
10742
|
-
let target = "";
|
|
10743
|
-
let labelText = "";
|
|
10744
|
-
let foundPipe = false;
|
|
10745
|
-
let consumed = 1;
|
|
10746
|
-
let pos = startPos;
|
|
10747
|
-
while (pos < ctx.tokens.length) {
|
|
10748
|
-
const token5 = ctx.tokens[pos];
|
|
10749
|
-
if (!token5 || token5.type === "LINK_CLOSE" || token5.type === "EOF") {
|
|
10750
|
-
break;
|
|
10751
|
-
}
|
|
10752
|
-
if (token5.type === "NEWLINE") {
|
|
10753
|
-
if (foundPipe) {
|
|
10754
|
-
labelText += " ";
|
|
10755
|
-
} else {
|
|
10756
|
-
target += " ";
|
|
10757
|
-
}
|
|
10758
|
-
consumed++;
|
|
10759
|
-
pos++;
|
|
10760
|
-
continue;
|
|
10761
|
-
}
|
|
10762
|
-
if (token5.type === "PIPE" && !foundPipe) {
|
|
10763
|
-
foundPipe = true;
|
|
10764
|
-
} else if (foundPipe) {
|
|
10765
|
-
labelText += token5.value;
|
|
10766
|
-
} else {
|
|
10767
|
-
target += token5.value;
|
|
10768
|
-
}
|
|
10769
|
-
consumed++;
|
|
10770
|
-
pos++;
|
|
10771
|
-
}
|
|
10772
|
-
if (ctx.tokens[pos]?.type === "LINK_CLOSE") {
|
|
10773
|
-
consumed++;
|
|
10774
|
-
}
|
|
10775
|
-
return { target, labelText, foundPipe, consumed };
|
|
11623
|
+
return {
|
|
11624
|
+
success: true,
|
|
11625
|
+
elements: [createInlineContainer(type, result.elements)],
|
|
11626
|
+
consumed
|
|
11627
|
+
};
|
|
10776
11628
|
}
|
|
10777
11629
|
|
|
10778
|
-
// packages/parser/src/parser/rules/inline/
|
|
10779
|
-
var
|
|
10780
|
-
|
|
10781
|
-
|
|
10782
|
-
|
|
10783
|
-
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 });
|
|
10784
11636
|
}
|
|
10785
|
-
|
|
10786
|
-
return INTERWIKI_PREFIXES.has(prefix);
|
|
10787
|
-
}
|
|
11637
|
+
};
|
|
10788
11638
|
|
|
10789
|
-
// packages/parser/src/parser/rules/inline/
|
|
10790
|
-
|
|
10791
|
-
|
|
10792
|
-
|
|
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");
|
|
10793
11645
|
}
|
|
10794
|
-
|
|
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");
|
|
10795
11660
|
}
|
|
10796
|
-
|
|
10797
|
-
|
|
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";
|
|
10798
11666
|
}
|
|
10799
|
-
|
|
10800
|
-
|
|
10801
|
-
|
|
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);
|
|
10802
11681
|
}
|
|
10803
|
-
|
|
10804
|
-
|
|
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
|
+
});
|
|
10805
11692
|
}
|
|
10806
|
-
|
|
10807
|
-
|
|
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 });
|
|
10808
11701
|
}
|
|
10809
|
-
|
|
10810
|
-
}
|
|
11702
|
+
};
|
|
10811
11703
|
|
|
10812
|
-
// packages/parser/src/parser/rules/inline/
|
|
10813
|
-
var
|
|
10814
|
-
name: "
|
|
10815
|
-
startTokens: ["
|
|
11704
|
+
// packages/parser/src/parser/rules/inline/monospace.ts
|
|
11705
|
+
var monospaceRule = {
|
|
11706
|
+
name: "monospace",
|
|
11707
|
+
startTokens: ["MONO_MARKER"],
|
|
10816
11708
|
parse(ctx) {
|
|
10817
|
-
|
|
10818
|
-
if (!hasClosingLinkMarker(ctx, ctx.pos + 1)) {
|
|
10819
|
-
return literalOpenLink(startToken.value);
|
|
10820
|
-
}
|
|
10821
|
-
const parts = collectTripleLinkParts(ctx, ctx.pos + 1);
|
|
10822
|
-
const trimmedTarget = parts.target.trim();
|
|
10823
|
-
if (isInvalidTripleLinkTarget(trimmedTarget, parts.foundPipe)) {
|
|
10824
|
-
return literalOpenLink(startToken.value);
|
|
10825
|
-
}
|
|
10826
|
-
const normalized = normalizeTripleLinkTarget(trimmedTarget);
|
|
10827
|
-
const { linkType, link } = determineLinkTypeAndLocation(normalized.target);
|
|
10828
|
-
const label = buildTripleLinkLabel({
|
|
10829
|
-
foundPipe: parts.foundPipe,
|
|
10830
|
-
labelText: parts.labelText,
|
|
10831
|
-
finalTarget: normalized.target,
|
|
10832
|
-
originalTarget: trimmedTarget
|
|
10833
|
-
});
|
|
10834
|
-
return {
|
|
10835
|
-
success: true,
|
|
10836
|
-
elements: [
|
|
10837
|
-
{
|
|
10838
|
-
element: "link",
|
|
10839
|
-
data: {
|
|
10840
|
-
type: linkType,
|
|
10841
|
-
link,
|
|
10842
|
-
extra: null,
|
|
10843
|
-
label,
|
|
10844
|
-
target: normalized.hasStar && linkType === "direct" ? "new-tab" : null
|
|
10845
|
-
}
|
|
10846
|
-
}
|
|
10847
|
-
],
|
|
10848
|
-
consumed: parts.consumed
|
|
10849
|
-
};
|
|
11709
|
+
return parseDelimitedContainer(ctx, "MONO_CLOSE", "monospace");
|
|
10850
11710
|
}
|
|
10851
11711
|
};
|
|
10852
11712
|
|
|
@@ -10857,7 +11717,7 @@ function normalizeAnchor(anchor) {
|
|
|
10857
11717
|
|
|
10858
11718
|
// packages/parser/src/parser/rules/inline/link-bracket/direct-url.ts
|
|
10859
11719
|
function isDirectBracketUrl(url) {
|
|
10860
|
-
return url !== "" && (url.startsWith("/") || url
|
|
11720
|
+
return url !== "" && (url.startsWith("/") || startsWithUrlScheme(url, 0));
|
|
10861
11721
|
}
|
|
10862
11722
|
|
|
10863
11723
|
// packages/parser/src/parser/rules/inline/link-bracket/parts.ts
|
|
@@ -10866,35 +11726,24 @@ function collectBracketLinkParts(ctx, startPos) {
|
|
|
10866
11726
|
return null;
|
|
10867
11727
|
}
|
|
10868
11728
|
let pos = startPos;
|
|
10869
|
-
|
|
10870
|
-
|
|
10871
|
-
while (pos <
|
|
10872
|
-
const token5 = ctx.tokens[pos];
|
|
10873
|
-
if (!token5 || token5.type === "WHITESPACE" || token5.type === "BRACKET_CLOSE" || token5.type === "NEWLINE" || token5.type === "EOF") {
|
|
10874
|
-
break;
|
|
10875
|
-
}
|
|
10876
|
-
first += token5.value;
|
|
10877
|
-
pos++;
|
|
10878
|
-
consumed++;
|
|
10879
|
-
}
|
|
10880
|
-
while (ctx.tokens[pos]?.type === "WHITESPACE") {
|
|
10881
|
-
pos++;
|
|
10882
|
-
consumed++;
|
|
10883
|
-
}
|
|
10884
|
-
let label = "";
|
|
10885
|
-
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) {
|
|
10886
11732
|
const token5 = ctx.tokens[pos];
|
|
10887
|
-
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")
|
|
10888
11734
|
break;
|
|
10889
|
-
|
|
10890
|
-
label += token5.value;
|
|
11735
|
+
values.push(token5.value);
|
|
10891
11736
|
pos++;
|
|
10892
|
-
consumed++;
|
|
10893
11737
|
}
|
|
10894
|
-
if (ctx.tokens[pos]?.type !== "BRACKET_CLOSE")
|
|
11738
|
+
if (pos >= end || ctx.tokens[pos]?.type !== "BRACKET_CLOSE")
|
|
10895
11739
|
return null;
|
|
10896
|
-
|
|
10897
|
-
|
|
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
|
+
};
|
|
10898
11747
|
}
|
|
10899
11748
|
|
|
10900
11749
|
// packages/parser/src/parser/rules/inline/link-bracket/prefix.ts
|
|
@@ -10905,6 +11754,14 @@ function parseBracketLinkPrefix(ctx, startPos) {
|
|
|
10905
11754
|
return { target: null, bodyStart: startPos, consumed: 0 };
|
|
10906
11755
|
}
|
|
10907
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
|
+
|
|
10908
11765
|
// packages/parser/src/parser/rules/inline/link-bracket/parsed.ts
|
|
10909
11766
|
function parseSingleBracketLink(ctx) {
|
|
10910
11767
|
const prefix = parseBracketLinkPrefix(ctx, ctx.pos + 1);
|
|
@@ -10913,17 +11770,20 @@ function parseSingleBracketLink(ctx) {
|
|
|
10913
11770
|
return null;
|
|
10914
11771
|
}
|
|
10915
11772
|
const link = parts.first.trim();
|
|
10916
|
-
|
|
11773
|
+
const email = isBracketEmail(link);
|
|
11774
|
+
const wikiPage = wikipediaPage(link);
|
|
11775
|
+
if (!email && wikiPage === null && !isDirectBracketUrl(link)) {
|
|
10917
11776
|
return null;
|
|
10918
11777
|
}
|
|
10919
|
-
const labelText = parts.label.trim();
|
|
11778
|
+
const labelText = parts.label.trim() || wikiPage;
|
|
10920
11779
|
if (!labelText) {
|
|
10921
11780
|
return null;
|
|
10922
11781
|
}
|
|
10923
11782
|
return {
|
|
10924
|
-
link,
|
|
11783
|
+
link: email ? `mailto:${link}` : link,
|
|
11784
|
+
interwiki: wikiPage !== null,
|
|
10925
11785
|
labelText,
|
|
10926
|
-
target: prefix.target,
|
|
11786
|
+
target: wikiPage !== null ? "new-tab" : prefix.target,
|
|
10927
11787
|
consumed: 1 + prefix.consumed + parts.consumed
|
|
10928
11788
|
};
|
|
10929
11789
|
}
|
|
@@ -10976,7 +11836,7 @@ var linkSingleRule = {
|
|
|
10976
11836
|
{
|
|
10977
11837
|
element: "link",
|
|
10978
11838
|
data: {
|
|
10979
|
-
type: "direct",
|
|
11839
|
+
type: parsed.interwiki ? "interwiki" : "direct",
|
|
10980
11840
|
link: parsed.link,
|
|
10981
11841
|
extra: null,
|
|
10982
11842
|
label: linkLabel,
|
|
@@ -11045,6 +11905,134 @@ var linkStarRule = {
|
|
|
11045
11905
|
}
|
|
11046
11906
|
};
|
|
11047
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
|
+
|
|
11048
12036
|
// packages/parser/src/parser/rules/inline/color/syntax.ts
|
|
11049
12037
|
function parseColorContent(ctx) {
|
|
11050
12038
|
const close = findFormattingClose(ctx, ctx.pos + 1, "COLOR_MARKER");
|
|
@@ -11131,7 +12119,7 @@ var newlineLineBreakRule = {
|
|
|
11131
12119
|
}
|
|
11132
12120
|
return {
|
|
11133
12121
|
success: true,
|
|
11134
|
-
elements: [
|
|
12122
|
+
elements: [createAutomaticLineBreak(currentTok)],
|
|
11135
12123
|
consumed: 1
|
|
11136
12124
|
};
|
|
11137
12125
|
}
|
|
@@ -11154,6 +12142,9 @@ function isValidBlockStartAfterNewline(ctx, tokenPos) {
|
|
|
11154
12142
|
if (!isBlockStartToken(token5?.type) || !token5?.lineStart) {
|
|
11155
12143
|
return false;
|
|
11156
12144
|
}
|
|
12145
|
+
if (token5.type === "LIST_BULLET" || token5.type === "LIST_NUMBER") {
|
|
12146
|
+
return ctx.tokens[tokenPos + 1]?.type === "WHITESPACE";
|
|
12147
|
+
}
|
|
11157
12148
|
if (token5.type !== "HEADING_MARKER") {
|
|
11158
12149
|
return true;
|
|
11159
12150
|
}
|
|
@@ -11411,6 +12402,9 @@ var htmlInlineRule = {
|
|
|
11411
12402
|
}
|
|
11412
12403
|
};
|
|
11413
12404
|
|
|
12405
|
+
// packages/parser/src/parser/rules/inline/raw/angle.ts
|
|
12406
|
+
var import_entities = require("entities");
|
|
12407
|
+
|
|
11414
12408
|
// packages/parser/src/parser/rules/inline/raw/result.ts
|
|
11415
12409
|
function rawElement(value, consumed) {
|
|
11416
12410
|
return {
|
|
@@ -11458,7 +12452,7 @@ function parseAngleRaw(ctx) {
|
|
|
11458
12452
|
if (ctx.tokens[pos]?.type === "RAW_BLOCK_CLOSE") {
|
|
11459
12453
|
consumed++;
|
|
11460
12454
|
}
|
|
11461
|
-
return rawElement(value, consumed);
|
|
12455
|
+
return rawElement(import_entities.decodeHTML(value), consumed);
|
|
11462
12456
|
}
|
|
11463
12457
|
|
|
11464
12458
|
// packages/parser/src/parser/rules/inline/raw/double-at.ts
|
|
@@ -11681,7 +12675,7 @@ function consumeSpanNewline(ctx, pos, paragraphStrip, afterBlankLine, children,
|
|
|
11681
12675
|
return { consumed: consumed2, afterBlankLine: paragraphStrip };
|
|
11682
12676
|
}
|
|
11683
12677
|
const targetChildren = paragraphStrip && afterBlankLine ? escapedChildren : children;
|
|
11684
|
-
targetChildren.push(
|
|
12678
|
+
targetChildren.push(createAutomaticLineBreak(ctx.tokens[pos]));
|
|
11685
12679
|
let consumed = 1;
|
|
11686
12680
|
let nextPos = pos + 1;
|
|
11687
12681
|
while (ctx.tokens[nextPos]?.type === "WHITESPACE" && ctx.tokens[nextPos]?.lineStart) {
|
|
@@ -11769,7 +12763,9 @@ function parseOneSpanChild(ctx, pos, targetChildren) {
|
|
|
11769
12763
|
for (const rule of getCandidateInlineRules(inlineRules, token5.type)) {
|
|
11770
12764
|
const result = rule.parse(inlineCtx);
|
|
11771
12765
|
if (result.success) {
|
|
11772
|
-
targetChildren
|
|
12766
|
+
stripAutomaticLineBreak(targetChildren, result.stripLeadingLineBreak);
|
|
12767
|
+
for (const element of result.elements)
|
|
12768
|
+
targetChildren.push(element);
|
|
11773
12769
|
return { consumed: result.consumed };
|
|
11774
12770
|
}
|
|
11775
12771
|
}
|
|
@@ -11837,6 +12833,48 @@ var closeSpanRule = {
|
|
|
11837
12833
|
}
|
|
11838
12834
|
};
|
|
11839
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
|
+
|
|
11840
12878
|
// packages/parser/src/parser/rules/inline/size/content.ts
|
|
11841
12879
|
function parseSizeContent(ctx, startPos) {
|
|
11842
12880
|
const children = [];
|
|
@@ -11858,7 +12896,8 @@ function parseSizeContent(ctx, startPos) {
|
|
|
11858
12896
|
const inlineCtx = { ...ctx, pos };
|
|
11859
12897
|
const inlineResult = parseInlineUntil(inlineCtx, "BLOCK_END_OPEN");
|
|
11860
12898
|
if (inlineResult.elements.length > 0) {
|
|
11861
|
-
|
|
12899
|
+
for (const element of inlineResult.elements)
|
|
12900
|
+
children.push(element);
|
|
11862
12901
|
pos += inlineResult.consumed;
|
|
11863
12902
|
consumed += inlineResult.consumed;
|
|
11864
12903
|
} else {
|
|
@@ -11887,6 +12926,16 @@ function tryConsumeSizeClose(ctx, pos) {
|
|
|
11887
12926
|
|
|
11888
12927
|
// packages/parser/src/parser/rules/inline/size/value.ts
|
|
11889
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
|
+
];
|
|
11890
12939
|
function parseSizeValue(ctx, startPos) {
|
|
11891
12940
|
let pos = startPos;
|
|
11892
12941
|
let consumed = 0;
|
|
@@ -11911,6 +12960,8 @@ function parseSizeValue(ctx, startPos) {
|
|
|
11911
12960
|
return isValidSizeValue(size) ? { size, consumed } : null;
|
|
11912
12961
|
}
|
|
11913
12962
|
function isValidSizeValue(size) {
|
|
12963
|
+
if (VALID_SIZE_KEYWORDS.includes(size))
|
|
12964
|
+
return true;
|
|
11914
12965
|
const unitPattern = VALID_SIZE_UNITS.join("|");
|
|
11915
12966
|
return new RegExp(`^(\\d+(?:\\.\\d+)?)(${unitPattern})$`, "i").test(size);
|
|
11916
12967
|
}
|
|
@@ -11982,19 +13033,6 @@ var sizeRule = {
|
|
|
11982
13033
|
}
|
|
11983
13034
|
};
|
|
11984
13035
|
|
|
11985
|
-
// packages/parser/src/parser/rules/inline/footnote/child.ts
|
|
11986
|
-
function parseFootnoteChild(ctx, pos) {
|
|
11987
|
-
const token5 = ctx.tokens[pos];
|
|
11988
|
-
if (!token5) {
|
|
11989
|
-
return { elements: [], consumed: 0 };
|
|
11990
|
-
}
|
|
11991
|
-
const inlineResult = parseInlineUntil({ ...ctx, pos }, "BLOCK_END_OPEN");
|
|
11992
|
-
if (inlineResult.elements.length > 0) {
|
|
11993
|
-
return { elements: inlineResult.elements, consumed: inlineResult.consumed };
|
|
11994
|
-
}
|
|
11995
|
-
return { elements: [{ element: "text", data: token5.value }], consumed: 1 };
|
|
11996
|
-
}
|
|
11997
|
-
|
|
11998
13036
|
// packages/parser/src/parser/rules/inline/footnote/close.ts
|
|
11999
13037
|
function tryConsumeFootnoteClose(ctx, pos) {
|
|
12000
13038
|
if (ctx.tokens[pos]?.type !== "BLOCK_END_OPEN") {
|
|
@@ -12016,96 +13054,73 @@ function tryConsumeFootnoteClose(ctx, pos) {
|
|
|
12016
13054
|
return { consumed };
|
|
12017
13055
|
}
|
|
12018
13056
|
|
|
12019
|
-
// packages/parser/src/parser/rules/inline/
|
|
12020
|
-
function
|
|
12021
|
-
let
|
|
12022
|
-
let consumed =
|
|
12023
|
-
|
|
12024
|
-
|
|
12025
|
-
consumed++;
|
|
12026
|
-
}
|
|
12027
|
-
if (ctx.tokens[nextPos]?.type !== "NEWLINE") {
|
|
12028
|
-
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;
|
|
12029
13063
|
}
|
|
12030
|
-
|
|
12031
|
-
|
|
13064
|
+
pos++;
|
|
13065
|
+
consumed++;
|
|
13066
|
+
while (ctx.tokens[pos]?.type === "WHITESPACE") {
|
|
13067
|
+
pos++;
|
|
12032
13068
|
consumed++;
|
|
12033
13069
|
}
|
|
12034
|
-
|
|
12035
|
-
}
|
|
12036
|
-
|
|
12037
|
-
// packages/parser/src/parser/rules/inline/footnote/content.ts
|
|
12038
|
-
function parseFootnoteContent(ctx, startPos) {
|
|
12039
|
-
const paragraphs = [[]];
|
|
12040
|
-
let currentParagraph = 0;
|
|
12041
|
-
let pos = startPos;
|
|
12042
|
-
let consumed = 0;
|
|
13070
|
+
let latexSource = "";
|
|
12043
13071
|
while (pos < ctx.tokens.length) {
|
|
12044
13072
|
const token5 = ctx.tokens[pos];
|
|
12045
|
-
if (!token5 || token5.type === "
|
|
12046
|
-
|
|
12047
|
-
}
|
|
12048
|
-
const closeResult = tryConsumeFootnoteClose(ctx, pos);
|
|
12049
|
-
if (closeResult) {
|
|
12050
|
-
return {
|
|
12051
|
-
paragraphs,
|
|
12052
|
-
consumed: consumed + closeResult.consumed,
|
|
12053
|
-
foundClose: true
|
|
12054
|
-
};
|
|
13073
|
+
if (!token5 || token5.type === "NEWLINE") {
|
|
13074
|
+
return null;
|
|
12055
13075
|
}
|
|
12056
|
-
if (token5.type === "
|
|
12057
|
-
|
|
12058
|
-
pos += newlineResult.consumed;
|
|
12059
|
-
consumed += newlineResult.consumed;
|
|
12060
|
-
if (newlineResult.paragraphBreak) {
|
|
12061
|
-
currentParagraph++;
|
|
12062
|
-
paragraphs[currentParagraph] = [];
|
|
12063
|
-
} else {
|
|
12064
|
-
paragraphs[currentParagraph].push({ element: "line-break" });
|
|
12065
|
-
}
|
|
12066
|
-
continue;
|
|
13076
|
+
if (token5.type === "TEXT" && token5.value === "$" && ctx.tokens[pos + 1]?.type === "BLOCK_CLOSE") {
|
|
13077
|
+
break;
|
|
12067
13078
|
}
|
|
12068
|
-
|
|
12069
|
-
|
|
12070
|
-
|
|
12071
|
-
|
|
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;
|
|
12072
13090
|
}
|
|
12073
|
-
return {
|
|
13091
|
+
return {
|
|
13092
|
+
latexSource: latexSource.trim(),
|
|
13093
|
+
consumed: consumed + 1
|
|
13094
|
+
};
|
|
12074
13095
|
}
|
|
12075
13096
|
|
|
12076
|
-
// packages/parser/src/parser/rules/inline/
|
|
12077
|
-
|
|
12078
|
-
|
|
12079
|
-
|
|
12080
|
-
|
|
12081
|
-
|
|
12082
|
-
|
|
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 };
|
|
12083
13105
|
}
|
|
12084
|
-
|
|
12085
|
-
|
|
12086
|
-
|
|
12087
|
-
children.push({
|
|
12088
|
-
element: "container",
|
|
12089
|
-
data: {
|
|
12090
|
-
type: "paragraph",
|
|
12091
|
-
attributes: {},
|
|
12092
|
-
elements: para
|
|
12093
|
-
}
|
|
12094
|
-
});
|
|
13106
|
+
const parsed = parseInlineMathSource(ctx, ctx.pos + 1);
|
|
13107
|
+
if (!parsed) {
|
|
13108
|
+
return { success: false };
|
|
12095
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
|
+
};
|
|
12096
13122
|
}
|
|
12097
|
-
|
|
12098
|
-
}
|
|
12099
|
-
function trimLineBreaks(elements) {
|
|
12100
|
-
const result = [...elements];
|
|
12101
|
-
while (result.length > 0 && result[0]?.element === "line-break") {
|
|
12102
|
-
result.shift();
|
|
12103
|
-
}
|
|
12104
|
-
while (result.length > 0 && result[result.length - 1]?.element === "line-break") {
|
|
12105
|
-
result.pop();
|
|
12106
|
-
}
|
|
12107
|
-
return result;
|
|
12108
|
-
}
|
|
13123
|
+
};
|
|
12109
13124
|
|
|
12110
13125
|
// packages/parser/src/parser/rules/inline/footnote/open.ts
|
|
12111
13126
|
function parseFootnoteOpen(ctx) {
|
|
@@ -12132,6 +13147,91 @@ function parseFootnoteOpen(ctx) {
|
|
|
12132
13147
|
return { bodyStart: pos, consumed };
|
|
12133
13148
|
}
|
|
12134
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
|
+
|
|
12135
13235
|
// packages/parser/src/parser/rules/inline/footnote/index.ts
|
|
12136
13236
|
var footnoteRule = {
|
|
12137
13237
|
name: "footnote",
|
|
@@ -12147,7 +13247,7 @@ var footnoteRule = {
|
|
|
12147
13247
|
}
|
|
12148
13248
|
const contentResult = parseFootnoteContent(ctx, openResult.bodyStart);
|
|
12149
13249
|
const consumed = openResult.consumed + contentResult.consumed;
|
|
12150
|
-
const children = buildFootnoteChildren(contentResult.
|
|
13250
|
+
const children = buildFootnoteChildren(contentResult.elements, contentResult.leadingParagraphBreak);
|
|
12151
13251
|
if (!contentResult.foundClose) {
|
|
12152
13252
|
ctx.diagnostics.push({
|
|
12153
13253
|
severity: "warning",
|
|
@@ -12507,11 +13607,15 @@ function parseAnchorChild(ctx, pos) {
|
|
|
12507
13607
|
if (!token5) {
|
|
12508
13608
|
return { elements: [], consumed: 0 };
|
|
12509
13609
|
}
|
|
12510
|
-
const inlineCtx = {
|
|
13610
|
+
const inlineCtx = {
|
|
13611
|
+
...ctx,
|
|
13612
|
+
pos,
|
|
13613
|
+
scope: { ...ctx.scope, suppressEmailLinks: true }
|
|
13614
|
+
};
|
|
12511
13615
|
for (const rule of getCandidateInlineRules(inlineRules, token5.type)) {
|
|
12512
13616
|
const result = rule.parse(inlineCtx);
|
|
12513
13617
|
if (result.success) {
|
|
12514
|
-
return
|
|
13618
|
+
return result;
|
|
12515
13619
|
}
|
|
12516
13620
|
}
|
|
12517
13621
|
return { elements: [{ element: "text", data: token5.value }], consumed: 1 };
|
|
@@ -12571,7 +13675,7 @@ function consumeAnchorNewline(ctx, pos, paragraphStrip, children) {
|
|
|
12571
13675
|
let consumed = 1;
|
|
12572
13676
|
let nextPos = pos + 1;
|
|
12573
13677
|
if (!paragraphStrip) {
|
|
12574
|
-
children.push(
|
|
13678
|
+
children.push(createAutomaticLineBreak(ctx.tokens[pos]));
|
|
12575
13679
|
while (ctx.tokens[nextPos]?.type === "WHITESPACE" && ctx.tokens[nextPos]?.lineStart) {
|
|
12576
13680
|
nextPos++;
|
|
12577
13681
|
consumed++;
|
|
@@ -12624,7 +13728,9 @@ function parseAnchorContent(ctx, startPos, paragraphStrip) {
|
|
|
12624
13728
|
continue;
|
|
12625
13729
|
}
|
|
12626
13730
|
const child = parseAnchorChild(ctx, pos);
|
|
12627
|
-
children
|
|
13731
|
+
stripAutomaticLineBreak(children, child.stripLeadingLineBreak);
|
|
13732
|
+
for (const element of child.elements)
|
|
13733
|
+
children.push(element);
|
|
12628
13734
|
pos += child.consumed;
|
|
12629
13735
|
consumed += child.consumed;
|
|
12630
13736
|
}
|
|
@@ -12698,75 +13804,8 @@ var anchorRule = {
|
|
|
12698
13804
|
}
|
|
12699
13805
|
}
|
|
12700
13806
|
],
|
|
12701
|
-
consumed
|
|
12702
|
-
|
|
12703
|
-
}
|
|
12704
|
-
};
|
|
12705
|
-
|
|
12706
|
-
// packages/parser/src/parser/rules/inline/math-inline/syntax.ts
|
|
12707
|
-
function parseInlineMathSource(ctx, startPos) {
|
|
12708
|
-
let pos = startPos;
|
|
12709
|
-
let consumed = 0;
|
|
12710
|
-
if (ctx.tokens[pos]?.type !== "TEXT" || ctx.tokens[pos]?.value !== "$") {
|
|
12711
|
-
return null;
|
|
12712
|
-
}
|
|
12713
|
-
pos++;
|
|
12714
|
-
consumed++;
|
|
12715
|
-
while (ctx.tokens[pos]?.type === "WHITESPACE") {
|
|
12716
|
-
pos++;
|
|
12717
|
-
consumed++;
|
|
12718
|
-
}
|
|
12719
|
-
let latexSource = "";
|
|
12720
|
-
while (pos < ctx.tokens.length) {
|
|
12721
|
-
const token5 = ctx.tokens[pos];
|
|
12722
|
-
if (!token5 || token5.type === "NEWLINE") {
|
|
12723
|
-
return null;
|
|
12724
|
-
}
|
|
12725
|
-
if (token5.type === "TEXT" && token5.value === "$" && ctx.tokens[pos + 1]?.type === "BLOCK_CLOSE") {
|
|
12726
|
-
break;
|
|
12727
|
-
}
|
|
12728
|
-
latexSource += token5.value;
|
|
12729
|
-
pos++;
|
|
12730
|
-
consumed++;
|
|
12731
|
-
}
|
|
12732
|
-
if (ctx.tokens[pos]?.type !== "TEXT" || ctx.tokens[pos]?.value !== "$") {
|
|
12733
|
-
return null;
|
|
12734
|
-
}
|
|
12735
|
-
pos++;
|
|
12736
|
-
consumed++;
|
|
12737
|
-
if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
|
|
12738
|
-
return null;
|
|
12739
|
-
}
|
|
12740
|
-
return {
|
|
12741
|
-
latexSource: latexSource.trim(),
|
|
12742
|
-
consumed: consumed + 1
|
|
12743
|
-
};
|
|
12744
|
-
}
|
|
12745
|
-
|
|
12746
|
-
// packages/parser/src/parser/rules/inline/math-inline/index.ts
|
|
12747
|
-
var mathInlineRule = {
|
|
12748
|
-
name: "math-inline",
|
|
12749
|
-
startTokens: ["BLOCK_OPEN"],
|
|
12750
|
-
parse(ctx) {
|
|
12751
|
-
const openToken = currentToken(ctx);
|
|
12752
|
-
if (openToken.type !== "BLOCK_OPEN") {
|
|
12753
|
-
return { success: false };
|
|
12754
|
-
}
|
|
12755
|
-
const parsed = parseInlineMathSource(ctx, ctx.pos + 1);
|
|
12756
|
-
if (!parsed) {
|
|
12757
|
-
return { success: false };
|
|
12758
|
-
}
|
|
12759
|
-
return {
|
|
12760
|
-
success: true,
|
|
12761
|
-
elements: [
|
|
12762
|
-
{
|
|
12763
|
-
element: "math-inline",
|
|
12764
|
-
data: {
|
|
12765
|
-
"latex-source": parsed.latexSource
|
|
12766
|
-
}
|
|
12767
|
-
}
|
|
12768
|
-
],
|
|
12769
|
-
consumed: 1 + parsed.consumed
|
|
13807
|
+
consumed,
|
|
13808
|
+
stripLeadingLineBreak: openResult.paragraphStrip ? precedingSingleNewline(ctx) : undefined
|
|
12770
13809
|
};
|
|
12771
13810
|
}
|
|
12772
13811
|
};
|
|
@@ -12877,7 +13916,9 @@ function parseInlineBranch(ctx, startPos) {
|
|
|
12877
13916
|
}
|
|
12878
13917
|
const result = rule.parse(inlineCtx);
|
|
12879
13918
|
if (result.success) {
|
|
12880
|
-
elements
|
|
13919
|
+
stripAutomaticLineBreak(elements, result.stripLeadingLineBreak);
|
|
13920
|
+
for (const element of result.elements)
|
|
13921
|
+
elements.push(element);
|
|
12881
13922
|
consumed += result.consumed;
|
|
12882
13923
|
pos += result.consumed;
|
|
12883
13924
|
matched = true;
|
|
@@ -13200,6 +14241,7 @@ var textRule = {
|
|
|
13200
14241
|
|
|
13201
14242
|
// packages/parser/src/parser/rules/inline/index.ts
|
|
13202
14243
|
var inlineRules = [
|
|
14244
|
+
emailRule,
|
|
13203
14245
|
boldRule,
|
|
13204
14246
|
italicRule,
|
|
13205
14247
|
underlineRule,
|
|
@@ -13211,6 +14253,7 @@ var inlineRules = [
|
|
|
13211
14253
|
linkSingleRule,
|
|
13212
14254
|
linkAnchorRule,
|
|
13213
14255
|
linkStarRule,
|
|
14256
|
+
autolinkRule,
|
|
13214
14257
|
colorRule,
|
|
13215
14258
|
backslashLineBreakRule,
|
|
13216
14259
|
underscoreLineBreakRule,
|
|
@@ -13220,6 +14263,9 @@ var inlineRules = [
|
|
|
13220
14263
|
rawRule,
|
|
13221
14264
|
imageRule,
|
|
13222
14265
|
embedBlockRule,
|
|
14266
|
+
buttonRule,
|
|
14267
|
+
socialRule,
|
|
14268
|
+
dateRule,
|
|
13223
14269
|
sizeRule,
|
|
13224
14270
|
footnoteRule,
|
|
13225
14271
|
spanRule,
|
|
@@ -13475,6 +14521,8 @@ function mergeSpanStripParagraphs(children) {
|
|
|
13475
14521
|
i++;
|
|
13476
14522
|
continue;
|
|
13477
14523
|
}
|
|
14524
|
+
const firstMeaningful = paraData.elements.find((child) => child.element !== "line-break" && !isWhitespaceText(child));
|
|
14525
|
+
const keepParagraph = firstMeaningful && !isSpanStripMarker(firstMeaningful);
|
|
13478
14526
|
const mergedChildren = [...paraData.elements];
|
|
13479
14527
|
i++;
|
|
13480
14528
|
while (i < expandedChildren.length) {
|
|
@@ -13487,7 +14535,8 @@ function mergeSpanStripParagraphs(children) {
|
|
|
13487
14535
|
break;
|
|
13488
14536
|
}
|
|
13489
14537
|
const hasSpanStrip = hasParagraphStripSpan(nextPara);
|
|
13490
|
-
|
|
14538
|
+
for (const element of nextParaData.elements)
|
|
14539
|
+
mergedChildren.push(element);
|
|
13491
14540
|
i++;
|
|
13492
14541
|
if (!hasSpanStrip) {
|
|
13493
14542
|
const peekNext = expandedChildren[i];
|
|
@@ -13498,7 +14547,7 @@ function mergeSpanStripParagraphs(children) {
|
|
|
13498
14547
|
}
|
|
13499
14548
|
const escapedSpans = extractEscapedSpans(mergedChildren);
|
|
13500
14549
|
removeLineBreaksAroundSpanStrip(mergedChildren);
|
|
13501
|
-
if (escapedSpans.length > 0) {
|
|
14550
|
+
if (escapedSpans.length > 0 || keepParagraph) {
|
|
13502
14551
|
if (mergedChildren.length > 0) {
|
|
13503
14552
|
result.push(paragraphElement(mergedChildren));
|
|
13504
14553
|
}
|
|
@@ -13719,50 +14768,6 @@ function cleanInternalFlags(elements) {
|
|
|
13719
14768
|
}
|
|
13720
14769
|
return removeEmptySpansAndAdjacentWhitespace(cleaned ?? elements);
|
|
13721
14770
|
}
|
|
13722
|
-
// packages/parser/src/parser/postprocess/divAdjacentParagraph.ts
|
|
13723
|
-
function isParagraphContainer2(el) {
|
|
13724
|
-
if (!el || el.element !== "container")
|
|
13725
|
-
return false;
|
|
13726
|
-
return el.data.type === "paragraph";
|
|
13727
|
-
}
|
|
13728
|
-
function isDivContainer(el) {
|
|
13729
|
-
if (!el || el.element !== "container")
|
|
13730
|
-
return false;
|
|
13731
|
-
return el.data.type === "div";
|
|
13732
|
-
}
|
|
13733
|
-
function suppressAtLevel(elements) {
|
|
13734
|
-
if (elements.length <= 1)
|
|
13735
|
-
return elements;
|
|
13736
|
-
const unwrap = Array.from({ length: elements.length }, () => false);
|
|
13737
|
-
for (let i = 0;i < elements.length; i++) {
|
|
13738
|
-
if (!isParagraphContainer2(elements[i]))
|
|
13739
|
-
continue;
|
|
13740
|
-
const prevIsDiv = i > 0 && isDivContainer(elements[i - 1]);
|
|
13741
|
-
const nextIsDiv = i < elements.length - 1 && isDivContainer(elements[i + 1]);
|
|
13742
|
-
if (prevIsDiv || nextIsDiv) {
|
|
13743
|
-
unwrap[i] = true;
|
|
13744
|
-
}
|
|
13745
|
-
}
|
|
13746
|
-
const result = [];
|
|
13747
|
-
for (let i = 0;i < elements.length; i++) {
|
|
13748
|
-
const el = elements[i];
|
|
13749
|
-
if (!el)
|
|
13750
|
-
continue;
|
|
13751
|
-
if (unwrap[i] && el.element === "container") {
|
|
13752
|
-
const inner = el.data.elements;
|
|
13753
|
-
if (i > 0 && isDivContainer(elements[i - 1])) {
|
|
13754
|
-
result.push({ element: "line-break" });
|
|
13755
|
-
}
|
|
13756
|
-
result.push(...inner);
|
|
13757
|
-
} else {
|
|
13758
|
-
result.push(el);
|
|
13759
|
-
}
|
|
13760
|
-
}
|
|
13761
|
-
return result;
|
|
13762
|
-
}
|
|
13763
|
-
function suppressDivAdjacentParagraphs(elements) {
|
|
13764
|
-
return suppressAtLevel(elements);
|
|
13765
|
-
}
|
|
13766
14771
|
// packages/parser/src/parser/parse/footnotes.ts
|
|
13767
14772
|
function containsFootnoteBlock(elements) {
|
|
13768
14773
|
let found = false;
|
|
@@ -14040,7 +15045,9 @@ function substitute(text2) {
|
|
|
14040
15045
|
result = result.replace(WHITESPACE_ONLY_LINE, "");
|
|
14041
15046
|
}
|
|
14042
15047
|
if (result.indexOf("\\\n") !== -1) {
|
|
14043
|
-
|
|
15048
|
+
const sentinels = makeUniqueSentinels(result);
|
|
15049
|
+
const { masked, placeholders } = maskRawRegions(result, sentinels);
|
|
15050
|
+
result = restorePlaceholders(masked.replace(CONCAT_LINES, String.fromCharCode(57344)), placeholders, sentinels);
|
|
14044
15051
|
}
|
|
14045
15052
|
if (result.indexOf("\t") !== -1) {
|
|
14046
15053
|
result = result.replace(TABS, " ");
|
|
@@ -14107,14 +15114,26 @@ function replaceDelimitedTypography(text2, opener, closer, leftQuote, rightQuote
|
|
|
14107
15114
|
let searchFrom = 0;
|
|
14108
15115
|
let result = "";
|
|
14109
15116
|
let lastCopied = 0;
|
|
15117
|
+
let closeIndex = -1;
|
|
15118
|
+
let newlineIndex = -1;
|
|
14110
15119
|
while (searchFrom < text2.length) {
|
|
14111
15120
|
const openIndex = text2.indexOf(opener, searchFrom);
|
|
14112
15121
|
if (openIndex === -1)
|
|
14113
15122
|
break;
|
|
14114
15123
|
const contentStart = openIndex + opener.length;
|
|
14115
|
-
|
|
15124
|
+
if (closeIndex < contentStart)
|
|
15125
|
+
closeIndex = text2.indexOf(closer, contentStart);
|
|
14116
15126
|
if (closeIndex === -1)
|
|
14117
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
|
+
}
|
|
14118
15137
|
result += text2.slice(lastCopied, openIndex);
|
|
14119
15138
|
result += leftQuote;
|
|
14120
15139
|
result += text2.slice(contentStart, closeIndex);
|
|
@@ -14125,7 +15144,12 @@ function replaceDelimitedTypography(text2, opener, closer, leftQuote, rightQuote
|
|
|
14125
15144
|
return lastCopied === 0 ? text2 : result + text2.slice(lastCopied);
|
|
14126
15145
|
}
|
|
14127
15146
|
function substitute2(text2) {
|
|
14128
|
-
|
|
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;
|
|
14129
15153
|
if (result.includes("``") && result.includes("''")) {
|
|
14130
15154
|
result = replaceDelimitedTypography(result, "``", "''", LEFT_DOUBLE_QUOTE, RIGHT_DOUBLE_QUOTE);
|
|
14131
15155
|
}
|
|
@@ -14141,7 +15165,7 @@ function substitute2(text2) {
|
|
|
14141
15165
|
if (result.includes(". . .")) {
|
|
14142
15166
|
result = replaceExactEllipsisPattern(result, ". . .");
|
|
14143
15167
|
}
|
|
14144
|
-
return result;
|
|
15168
|
+
return restorePlaceholders(result, placeholders, sentinels);
|
|
14145
15169
|
}
|
|
14146
15170
|
|
|
14147
15171
|
// packages/parser/src/parser/preprocess/index.ts
|
|
@@ -14388,7 +15412,7 @@ async function resolveModulesWithAsyncParse(ast, dataProvider, options) {
|
|
|
14388
15412
|
registry.register(ast);
|
|
14389
15413
|
const parse2 = async (source) => registry.register(await options.parse(source));
|
|
14390
15414
|
const [listPagesData, listUsersData, tagCloudData] = await Promise.all([
|
|
14391
|
-
buildListPagesDataMap(dataProvider, options.requirements.listPages ?? [], options.urlPath),
|
|
15415
|
+
buildListPagesDataMap(dataProvider, options.requirements.listPages ?? [], options.urlPath, options.paginationState),
|
|
14392
15416
|
buildListUsersDataMap(dataProvider, options.requirements.listUsers ?? []),
|
|
14393
15417
|
buildTagCloudDataMap(dataProvider, options.requirements.tagCloud ?? [])
|
|
14394
15418
|
]);
|
|
@@ -14476,9 +15500,9 @@ async function resolveListPagesAsync(module2, data, template, parse2) {
|
|
|
14476
15500
|
continue;
|
|
14477
15501
|
const variableContext = {
|
|
14478
15502
|
page,
|
|
14479
|
-
index: i + 1,
|
|
15503
|
+
index: (data.pagination?.offset ?? 0) + i + 1,
|
|
14480
15504
|
total: data.totalCount,
|
|
14481
|
-
limit: module2.limit,
|
|
15505
|
+
limit: data.pagination ? data.pagination.limit : module2.limit,
|
|
14482
15506
|
site: data.site
|
|
14483
15507
|
};
|
|
14484
15508
|
const parsed = await parse2(template(variableContext));
|
|
@@ -14498,6 +15522,7 @@ async function resolveListPagesAsync(module2, data, template, parse2) {
|
|
|
14498
15522
|
if (module2["append-line"] && !module2.separate) {
|
|
14499
15523
|
result.push(...(await parse2(module2["append-line"])).elements);
|
|
14500
15524
|
}
|
|
15525
|
+
result.push(...createListPagesPager(data));
|
|
14501
15526
|
return module2.wrapper ? [
|
|
14502
15527
|
{
|
|
14503
15528
|
element: "container",
|
|
@@ -14598,6 +15623,9 @@ async function processWikitext(source, options) {
|
|
|
14598
15623
|
const dataProvider = createModuleDataProvider(options, callbackContext);
|
|
14599
15624
|
const parseFragment = parseSource2;
|
|
14600
15625
|
let ast = initial.ast;
|
|
15626
|
+
const paginationState = { nextUnprefixed: 1 };
|
|
15627
|
+
const requestedPath = options.page.urlPath;
|
|
15628
|
+
const urlPath = !requestedPath || /^\/(?:[?#]|$)/.test(requestedPath) ? `/${options.page.fullName}${requestedPath?.slice(1) ?? ""}` : requestedPath;
|
|
14601
15629
|
for (let pass = 0;pass < DEFAULT_MODULE_MAX_PASSES; pass++) {
|
|
14602
15630
|
const extraction = extractDataRequirements(ast);
|
|
14603
15631
|
if (pass > 0 && !hasResolvableRequirements(extraction.requirements, options.dataProvider)) {
|
|
@@ -14608,7 +15636,8 @@ async function processWikitext(source, options) {
|
|
|
14608
15636
|
compiledListPagesTemplates: extraction.compiledListPagesTemplates,
|
|
14609
15637
|
compiledListUsersTemplates: extraction.compiledListUsersTemplates,
|
|
14610
15638
|
requirements: extraction.requirements,
|
|
14611
|
-
urlPath
|
|
15639
|
+
urlPath,
|
|
15640
|
+
paginationState,
|
|
14612
15641
|
pageTags: options.page.tags
|
|
14613
15642
|
});
|
|
14614
15643
|
ast = resolved.ast;
|