@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.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// packages/parser/src/build-info.generated.ts
|
|
2
2
|
var buildInfo = Object.freeze({
|
|
3
|
-
version: "5.
|
|
4
|
-
sha: "
|
|
3
|
+
version: "5.4.0",
|
|
4
|
+
sha: "5e221ddeccc585e64dd1a2eb49b14817c3c1be5d",
|
|
5
5
|
dirty: false
|
|
6
6
|
});
|
|
7
7
|
|
|
@@ -205,13 +205,13 @@ function isValidAnchorNameChar(code) {
|
|
|
205
205
|
}
|
|
206
206
|
|
|
207
207
|
// packages/parser/src/lexer/quoted-string.ts
|
|
208
|
-
function scanQuotedString(state) {
|
|
208
|
+
function scanQuotedString(state, end = state.source.length) {
|
|
209
209
|
let quoted = advance(state);
|
|
210
|
-
while (
|
|
210
|
+
while (state.pos < end && current(state) !== '"' && current(state) !== `
|
|
211
211
|
`) {
|
|
212
212
|
quoted += advance(state);
|
|
213
213
|
}
|
|
214
|
-
if (current(state) === '"') {
|
|
214
|
+
if (state.pos < end && current(state) === '"') {
|
|
215
215
|
quoted += advance(state);
|
|
216
216
|
}
|
|
217
217
|
return quoted;
|
|
@@ -296,6 +296,26 @@ function isCompactPlainTextBoundary(code) {
|
|
|
296
296
|
}
|
|
297
297
|
}
|
|
298
298
|
|
|
299
|
+
// packages/parser/src/lexer/url-schemes.ts
|
|
300
|
+
var URL_SCHEME_NAMES = new Set([
|
|
301
|
+
"http",
|
|
302
|
+
"https",
|
|
303
|
+
"ftp",
|
|
304
|
+
"gopher",
|
|
305
|
+
"news",
|
|
306
|
+
"mailto",
|
|
307
|
+
"mms"
|
|
308
|
+
]);
|
|
309
|
+
var TRAILING_URL_SCHEME = /(?:^|[^A-Za-z0-9])(https?|ftp|gopher|news|mailto|mms)$/;
|
|
310
|
+
var URL_SCHEME_PREFIX = /^(?:(?:https?|ftp|gopher|news|mms):\/\/|mailto:)/;
|
|
311
|
+
var URL_PATTERN = /^(?:(?:https?|ftp|gopher|news|mms):\/\/|mailto:)(?:[^ \\/"']*\/)*[^ \t\n\\/"']*[A-Za-z%0-9/?=&~_]/;
|
|
312
|
+
function startsWithUrlScheme(src, pos) {
|
|
313
|
+
return URL_SCHEME_PREFIX.test(src.slice(pos, pos + 10));
|
|
314
|
+
}
|
|
315
|
+
function startsWithUrl(src, pos) {
|
|
316
|
+
return URL_PATTERN.test(src.slice(pos, pos + 2048));
|
|
317
|
+
}
|
|
318
|
+
|
|
299
319
|
// packages/parser/src/lexer/syntax-actions.ts
|
|
300
320
|
function scanSimpleSyntaxToken(src, pos, isLineStart) {
|
|
301
321
|
switch (src[pos]) {
|
|
@@ -332,7 +352,7 @@ function scanSimpleSyntaxToken(src, pos, isLineStart) {
|
|
|
332
352
|
}
|
|
333
353
|
}
|
|
334
354
|
function scanStarToken(src, pos, isLineStart) {
|
|
335
|
-
if (src[pos + 1] === "*") {
|
|
355
|
+
if (src[pos + 1] === "*" && !startsWithUrl(src, pos + 2)) {
|
|
336
356
|
return token("BOLD_MARKER", "**");
|
|
337
357
|
}
|
|
338
358
|
return isLineStart ? token("LIST_BULLET", "*") : token("STAR", "*");
|
|
@@ -518,7 +538,13 @@ function scanTextToken(src, pos) {
|
|
|
518
538
|
return token3("TEXT", char);
|
|
519
539
|
}
|
|
520
540
|
function scanCompactTextToken(src, pos) {
|
|
521
|
-
|
|
541
|
+
let end = findCompactPlainTextRunEnd(src, pos);
|
|
542
|
+
if (end > pos && src[end] === ":") {
|
|
543
|
+
const match = TRAILING_URL_SCHEME.exec(src.slice(pos, end));
|
|
544
|
+
if (match) {
|
|
545
|
+
end -= match[1].length;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
522
548
|
return end > pos ? runToken3(src, pos, end, "TEXT") : null;
|
|
523
549
|
}
|
|
524
550
|
function token3(type, value) {
|
|
@@ -564,6 +590,8 @@ class Lexer {
|
|
|
564
590
|
splitBlockClosePositions = new Set;
|
|
565
591
|
lastNonWhitespaceType = null;
|
|
566
592
|
blockOpenerDepth = 0;
|
|
593
|
+
rawTagBounds = null;
|
|
594
|
+
rawClosesExhausted = false;
|
|
567
595
|
constructor(source, options = {}) {
|
|
568
596
|
this.options = {
|
|
569
597
|
trackPositions: options.trackPositions ?? true,
|
|
@@ -584,8 +612,8 @@ class Lexer {
|
|
|
584
612
|
current() {
|
|
585
613
|
return current(this.state);
|
|
586
614
|
}
|
|
587
|
-
findInvalidAnchorNameEnd() {
|
|
588
|
-
return findInvalidAnchorNameEnd(
|
|
615
|
+
findInvalidAnchorNameEnd(source) {
|
|
616
|
+
return findInvalidAnchorNameEnd(source, this.state.pos);
|
|
589
617
|
}
|
|
590
618
|
advance(n = 1) {
|
|
591
619
|
return advance(this.state, n);
|
|
@@ -597,6 +625,18 @@ class Lexer {
|
|
|
597
625
|
this.state.tokens.push(createLexerToken(this.state, type, value, this.options.trackPositions));
|
|
598
626
|
this.lastNonWhitespaceType = updateLastNonWhitespaceType(this.lastNonWhitespaceType, type);
|
|
599
627
|
this.blockOpenerDepth = nextBlockOpenerDepth(this.blockOpenerDepth, type);
|
|
628
|
+
if (this.rawTagBounds === null && !this.rawClosesExhausted && (value.toLowerCase() === "button" || value.toLowerCase() === "social") && this.state.tokens.at(-2)?.type === "BLOCK_OPEN" && /\s/.test(this.current())) {
|
|
629
|
+
const close = this.state.source.indexOf("]]", this.state.pos);
|
|
630
|
+
if (close < 0) {
|
|
631
|
+
this.rawClosesExhausted = true;
|
|
632
|
+
} else {
|
|
633
|
+
this.rawTagBounds = {
|
|
634
|
+
source: this.state.source.slice(0, close),
|
|
635
|
+
close,
|
|
636
|
+
outerDepth: this.blockOpenerDepth - 1
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
}
|
|
600
640
|
}
|
|
601
641
|
emitTokenAction(action) {
|
|
602
642
|
advanceByToken(this.state, action.type, action.length, action.value);
|
|
@@ -614,7 +654,14 @@ class Lexer {
|
|
|
614
654
|
scanToken() {
|
|
615
655
|
const char = this.current();
|
|
616
656
|
const isLineStart = isSyntaxLineStart(this.state);
|
|
617
|
-
const
|
|
657
|
+
const bounds = this.rawTagBounds;
|
|
658
|
+
const src = bounds?.source ?? this.state.source;
|
|
659
|
+
if (bounds && this.state.pos === bounds.close) {
|
|
660
|
+
this.emitTokenAction({ type: "BLOCK_CLOSE", value: "]]", length: 2 });
|
|
661
|
+
this.blockOpenerDepth = bounds.outerDepth;
|
|
662
|
+
this.rawTagBounds = null;
|
|
663
|
+
return;
|
|
664
|
+
}
|
|
618
665
|
const spacingAction = scanSpacingToken(src, this.state.pos);
|
|
619
666
|
if (spacingAction) {
|
|
620
667
|
this.emitTokenAction(limitBlockquotePrefixSpace(spacingAction, this.state.tokens.at(-1)));
|
|
@@ -627,7 +674,7 @@ class Lexer {
|
|
|
627
674
|
lineStart: isLineStart,
|
|
628
675
|
physicalLineStart: this.state.lineStart,
|
|
629
676
|
splitBlockClose: this.splitBlockClosePositions.has(this.state.pos),
|
|
630
|
-
findInvalidAnchorNameEnd: () => this.findInvalidAnchorNameEnd()
|
|
677
|
+
findInvalidAnchorNameEnd: () => this.findInvalidAnchorNameEnd(src)
|
|
631
678
|
});
|
|
632
679
|
if (punctuation.handled) {
|
|
633
680
|
if (punctuation.clearSplitBlockCloseAt !== undefined) {
|
|
@@ -642,7 +689,7 @@ class Lexer {
|
|
|
642
689
|
if (char === '"') {
|
|
643
690
|
const lastNonWs = this.lastNonWhitespaceTokenType();
|
|
644
691
|
if (this.blockOpenerDepth > 0 && lastNonWs === "EQUALS") {
|
|
645
|
-
this.addToken("QUOTED_STRING", scanQuotedString(this.state));
|
|
692
|
+
this.addToken("QUOTED_STRING", scanQuotedString(this.state, src.length));
|
|
646
693
|
return;
|
|
647
694
|
}
|
|
648
695
|
this.advance();
|
|
@@ -830,7 +877,7 @@ function parseBlockItem(ctx) {
|
|
|
830
877
|
}
|
|
831
878
|
}
|
|
832
879
|
const fallback = ctx.blockFallbackRule.parse(ctx);
|
|
833
|
-
if (fallback.success
|
|
880
|
+
if (fallback.success) {
|
|
834
881
|
return { elements: fallback.elements, consumed: fallback.consumed };
|
|
835
882
|
}
|
|
836
883
|
return { elements: [], consumed: 1 };
|
|
@@ -878,7 +925,8 @@ function parseBlocksUntil(ctx, closeCondition, options) {
|
|
|
878
925
|
blockCtx.pos = pos;
|
|
879
926
|
blockCtx.scope = blockScope;
|
|
880
927
|
const result = parseBlockItem(blockCtx);
|
|
881
|
-
|
|
928
|
+
for (const element of result.elements)
|
|
929
|
+
elements.push(element);
|
|
882
930
|
consumed += result.consumed;
|
|
883
931
|
pos += result.consumed;
|
|
884
932
|
}
|
|
@@ -905,6 +953,42 @@ function getExcludedBlockRules(blockRules, excluded) {
|
|
|
905
953
|
byExcluded.set(excluded, filtered);
|
|
906
954
|
return filtered;
|
|
907
955
|
}
|
|
956
|
+
// packages/parser/src/parser/rules/inline/parsing/automatic-line-break.ts
|
|
957
|
+
var origins = new WeakMap;
|
|
958
|
+
function createAutomaticLineBreak(token5) {
|
|
959
|
+
const element = { element: "line-break" };
|
|
960
|
+
origins.set(element, token5);
|
|
961
|
+
return element;
|
|
962
|
+
}
|
|
963
|
+
function precedingSingleNewline(ctx) {
|
|
964
|
+
let pos = ctx.pos - 1;
|
|
965
|
+
while (ctx.tokens[pos]?.type === "WHITESPACE")
|
|
966
|
+
pos--;
|
|
967
|
+
const newline = ctx.tokens[pos];
|
|
968
|
+
if (newline?.type !== "NEWLINE")
|
|
969
|
+
return;
|
|
970
|
+
pos--;
|
|
971
|
+
while (ctx.tokens[pos]?.type === "WHITESPACE")
|
|
972
|
+
pos--;
|
|
973
|
+
if (ctx.tokens[pos]?.type === "NEWLINE")
|
|
974
|
+
return;
|
|
975
|
+
return newline;
|
|
976
|
+
}
|
|
977
|
+
function stripAutomaticLineBreak(elements, token5) {
|
|
978
|
+
if (!token5)
|
|
979
|
+
return;
|
|
980
|
+
let index = elements.length - 1;
|
|
981
|
+
while (index >= 0) {
|
|
982
|
+
const element2 = elements[index];
|
|
983
|
+
if (element2?.element !== "text" || !/^[ \t]*$/.test(element2.data))
|
|
984
|
+
break;
|
|
985
|
+
index--;
|
|
986
|
+
}
|
|
987
|
+
const element = elements[index];
|
|
988
|
+
if (element && origins.get(element) === token5)
|
|
989
|
+
elements.length = index;
|
|
990
|
+
}
|
|
991
|
+
|
|
908
992
|
// packages/parser/src/parser/rules/inline/parsing/rules.ts
|
|
909
993
|
function canApplyInlineRule(rule, token5) {
|
|
910
994
|
if (rule.startTokens.length === 0) {
|
|
@@ -927,18 +1011,479 @@ function getCandidateInlineRules(inlineRules, tokenType) {
|
|
|
927
1011
|
byType.set(tokenType, candidates);
|
|
928
1012
|
return candidates;
|
|
929
1013
|
}
|
|
1014
|
+
// packages/parser/src/parser/rules/inline/parsing/raw-tag.ts
|
|
1015
|
+
var unclosedRanges = new WeakMap;
|
|
1016
|
+
function findRawTagClose(tokens, start, end) {
|
|
1017
|
+
const unclosed = unclosedRanges.get(tokens);
|
|
1018
|
+
if (unclosed && start >= unclosed.start && end <= unclosed.end)
|
|
1019
|
+
return null;
|
|
1020
|
+
for (let close = start;close < end; close++) {
|
|
1021
|
+
if (tokens[close]?.type === "BLOCK_CLOSE")
|
|
1022
|
+
return close;
|
|
1023
|
+
if (!tokens[close] || tokens[close]?.type === "EOF")
|
|
1024
|
+
break;
|
|
1025
|
+
}
|
|
1026
|
+
unclosedRanges.set(tokens, { start, end });
|
|
1027
|
+
return null;
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
// packages/parser/src/parser/rules/inline/button/attributes.ts
|
|
1031
|
+
function parseButtonAttributes(source) {
|
|
1032
|
+
const sections = source.trim().split('="');
|
|
1033
|
+
const attrs = {};
|
|
1034
|
+
let key = sections[0].trim();
|
|
1035
|
+
for (const section of sections.slice(1)) {
|
|
1036
|
+
const quote = section.lastIndexOf('"');
|
|
1037
|
+
if (quote < 0)
|
|
1038
|
+
continue;
|
|
1039
|
+
if (key === "text" || key === "class" || key === "style") {
|
|
1040
|
+
attrs[key] = section.slice(0, quote).replace(/\\([\s\S]|$)/g, (_match, char) => char === "0" ? "\x00" : char);
|
|
1041
|
+
}
|
|
1042
|
+
key = section.slice(quote + 1).trim();
|
|
1043
|
+
}
|
|
1044
|
+
return attrs;
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
// packages/parser/src/parser/rules/inline/button/syntax.ts
|
|
1048
|
+
function parseButtonSyntax(ctx, start, end) {
|
|
1049
|
+
const tokens = ctx.tokens;
|
|
1050
|
+
if (tokens[start]?.type !== "BLOCK_OPEN" || tokens[start + 1]?.value.toLowerCase() !== "button")
|
|
1051
|
+
return null;
|
|
1052
|
+
let pos = start + 2;
|
|
1053
|
+
const skipSpace = () => {
|
|
1054
|
+
const before = pos;
|
|
1055
|
+
while (pos < end && /^\s+$/.test(tokens[pos]?.value ?? ""))
|
|
1056
|
+
pos++;
|
|
1057
|
+
return pos > before;
|
|
1058
|
+
};
|
|
1059
|
+
if (!skipSpace())
|
|
1060
|
+
return null;
|
|
1061
|
+
let action = "";
|
|
1062
|
+
while (pos < end && tokens[pos]?.type !== "BLOCK_CLOSE" && !/^\s+$/.test(tokens[pos]?.value ?? "")) {
|
|
1063
|
+
const part = tokens[pos]?.value ?? "";
|
|
1064
|
+
if (!/^[a-z0-9_-]+$/i.test(part))
|
|
1065
|
+
return null;
|
|
1066
|
+
action += part;
|
|
1067
|
+
pos++;
|
|
1068
|
+
}
|
|
1069
|
+
if (!action)
|
|
1070
|
+
return null;
|
|
1071
|
+
action = action.replaceAll("_", "-");
|
|
1072
|
+
skipSpace();
|
|
1073
|
+
const close = findRawTagClose(tokens, pos, end);
|
|
1074
|
+
if (close === null)
|
|
1075
|
+
return null;
|
|
1076
|
+
const attrs = parseButtonAttributes(tokens.slice(pos, close).map((token5) => token5.value).join(""));
|
|
1077
|
+
const value = (key) => attrs[key] && attrs[key] !== "0" ? attrs[key] : null;
|
|
1078
|
+
const attributes = {};
|
|
1079
|
+
for (const name of ["class", "style"]) {
|
|
1080
|
+
const attr = value(name);
|
|
1081
|
+
if (attr !== null)
|
|
1082
|
+
attributes[name] = attr;
|
|
1083
|
+
}
|
|
1084
|
+
return { data: { action, text: value("text"), attributes }, end: close + 1 };
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
// packages/parser/src/parser/rules/inline/social/syntax.ts
|
|
1088
|
+
var invalidBodies = new WeakMap;
|
|
1089
|
+
function parseSocialSyntax(ctx, start, end) {
|
|
1090
|
+
const tokens = ctx.tokens;
|
|
1091
|
+
if (tokens[start]?.type !== "BLOCK_OPEN" || tokens[start + 1]?.value.toLowerCase() !== "social")
|
|
1092
|
+
return null;
|
|
1093
|
+
const bodyStart = start + 2;
|
|
1094
|
+
if (tokens[bodyStart]?.type !== "BLOCK_CLOSE" && !/^\s+$/.test(tokens[bodyStart]?.value ?? ""))
|
|
1095
|
+
return null;
|
|
1096
|
+
const invalid = invalidBodies.get(tokens);
|
|
1097
|
+
if (invalid && bodyStart >= invalid.start && bodyStart <= invalid.bracket)
|
|
1098
|
+
return null;
|
|
1099
|
+
const close = findRawTagClose(tokens, bodyStart, end);
|
|
1100
|
+
if (close === null)
|
|
1101
|
+
return null;
|
|
1102
|
+
for (let pos = bodyStart;pos < close; pos++) {
|
|
1103
|
+
if (tokens[pos].value.includes("]")) {
|
|
1104
|
+
invalidBodies.set(tokens, { start: bodyStart, bracket: pos });
|
|
1105
|
+
return null;
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
const body = tokens.slice(bodyStart, close).map((token5) => token5.value).join("");
|
|
1109
|
+
const sites = body.trim() ? body.split(",").map((site) => site.trim().toLowerCase()).filter(Boolean) : null;
|
|
1110
|
+
return { data: { sites }, end: close + 1 };
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
// packages/parser/src/parser/rules/block/parsing/attributes/names.ts
|
|
1114
|
+
function consumeAttributeName(ctx, startPos, startConsumed, startName, options) {
|
|
1115
|
+
if (startName === "_" && isAttributeWordToken(ctx.tokens[startPos])) {
|
|
1116
|
+
startName += ctx.tokens[startPos]?.value ?? "";
|
|
1117
|
+
startPos++;
|
|
1118
|
+
startConsumed++;
|
|
1119
|
+
}
|
|
1120
|
+
return options.strikeHyphens ? consumeRawNameSuffix(ctx, startPos, startConsumed, startName, options.hyphenatedNames) : consumeSafeNameSuffix(ctx, startPos, startConsumed, startName);
|
|
1121
|
+
}
|
|
1122
|
+
function isAttributeNameToken(token5) {
|
|
1123
|
+
return isAttributeWordToken(token5) || token5?.type === "UNDERSCORE";
|
|
1124
|
+
}
|
|
1125
|
+
function consumeSafeNameSuffix(ctx, startPos, startConsumed, startName) {
|
|
1126
|
+
let name = startName;
|
|
1127
|
+
let pos = startPos;
|
|
1128
|
+
let consumed = startConsumed;
|
|
1129
|
+
while (isAttributeNameSeparator(ctx.tokens[pos]) && isAttributeWordToken(ctx.tokens[pos + 1])) {
|
|
1130
|
+
name += ctx.tokens[pos]?.value ?? "";
|
|
1131
|
+
pos++;
|
|
1132
|
+
consumed++;
|
|
1133
|
+
name += ctx.tokens[pos]?.value ?? "";
|
|
1134
|
+
pos++;
|
|
1135
|
+
consumed++;
|
|
1136
|
+
}
|
|
1137
|
+
return { name, pos, consumed };
|
|
1138
|
+
}
|
|
1139
|
+
function consumeRawNameSuffix(ctx, startPos, startConsumed, startName, hyphenatedNames) {
|
|
1140
|
+
let name = startName;
|
|
1141
|
+
let pos = startPos;
|
|
1142
|
+
let consumed = startConsumed;
|
|
1143
|
+
while (isAttributeNameSeparator(ctx.tokens[pos])) {
|
|
1144
|
+
while (isAttributeNameSeparator(ctx.tokens[pos])) {
|
|
1145
|
+
if (hyphenatedNames || ctx.tokens[pos]?.type === "UNDERSCORE") {
|
|
1146
|
+
name += ctx.tokens[pos]?.value ?? "-";
|
|
1147
|
+
}
|
|
1148
|
+
pos++;
|
|
1149
|
+
consumed++;
|
|
1150
|
+
}
|
|
1151
|
+
if (!isAttributeWordToken(ctx.tokens[pos])) {
|
|
1152
|
+
break;
|
|
1153
|
+
}
|
|
1154
|
+
if (hyphenatedNames || name.endsWith("_")) {
|
|
1155
|
+
name += ctx.tokens[pos]?.value ?? "";
|
|
1156
|
+
}
|
|
1157
|
+
pos++;
|
|
1158
|
+
consumed++;
|
|
1159
|
+
}
|
|
1160
|
+
return { name, pos, consumed };
|
|
1161
|
+
}
|
|
1162
|
+
function isAttributeWordToken(token5) {
|
|
1163
|
+
return token5?.type === "TEXT" || token5?.type === "IDENTIFIER";
|
|
1164
|
+
}
|
|
1165
|
+
function isAttributeNameSeparator(token5) {
|
|
1166
|
+
return token5?.type === "TEXT" && token5.value === "-" || token5?.type === "STRIKE_MARKER" || token5?.type === "UNDERSCORE";
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
// packages/parser/src/parser/rules/block/parsing/attributes/values.ts
|
|
1170
|
+
function consumeAttributeValue(token5) {
|
|
1171
|
+
if (!token5) {
|
|
1172
|
+
return null;
|
|
1173
|
+
}
|
|
1174
|
+
if (token5.type === "QUOTED_STRING") {
|
|
1175
|
+
return { value: stripQuotes(token5.value) };
|
|
1176
|
+
}
|
|
1177
|
+
if (isAttributeNameToken(token5)) {
|
|
1178
|
+
return { value: token5.value };
|
|
1179
|
+
}
|
|
1180
|
+
return null;
|
|
1181
|
+
}
|
|
1182
|
+
function stripQuotes(value) {
|
|
1183
|
+
return value.startsWith('"') && value.endsWith('"') ? value.slice(1, -1) : value;
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
// packages/parser/src/parser/rules/block/parsing/attributes/scanner.ts
|
|
1187
|
+
function scanAttributes(ctx, startPos, options) {
|
|
1188
|
+
const attrs = {};
|
|
1189
|
+
let pos = startPos;
|
|
1190
|
+
let consumed = 0;
|
|
1191
|
+
while (pos < ctx.tokens.length) {
|
|
1192
|
+
const token5 = ctx.tokens[pos];
|
|
1193
|
+
if (!token5 || isAttributeTerminator(token5)) {
|
|
1194
|
+
break;
|
|
1195
|
+
}
|
|
1196
|
+
if (token5.type === "WHITESPACE") {
|
|
1197
|
+
pos++;
|
|
1198
|
+
consumed++;
|
|
1199
|
+
continue;
|
|
1200
|
+
}
|
|
1201
|
+
if (!isAttributeNameToken(token5)) {
|
|
1202
|
+
pos++;
|
|
1203
|
+
consumed++;
|
|
1204
|
+
continue;
|
|
1205
|
+
}
|
|
1206
|
+
let name = token5.value;
|
|
1207
|
+
pos++;
|
|
1208
|
+
consumed++;
|
|
1209
|
+
const nameResult = consumeAttributeName(ctx, pos, consumed, name, options);
|
|
1210
|
+
pos = nameResult.pos;
|
|
1211
|
+
consumed = nameResult.consumed;
|
|
1212
|
+
name = nameResult.name.toLowerCase();
|
|
1213
|
+
if (ctx.tokens[pos]?.type !== "EQUALS") {
|
|
1214
|
+
attrs[name] = "true";
|
|
1215
|
+
continue;
|
|
1216
|
+
}
|
|
1217
|
+
pos++;
|
|
1218
|
+
consumed++;
|
|
1219
|
+
const valueResult = consumeAttributeValue(ctx.tokens[pos]);
|
|
1220
|
+
if (!valueResult) {
|
|
1221
|
+
continue;
|
|
1222
|
+
}
|
|
1223
|
+
attrs[name] = valueResult.value;
|
|
1224
|
+
pos++;
|
|
1225
|
+
consumed++;
|
|
1226
|
+
}
|
|
1227
|
+
return { attrs, consumed };
|
|
1228
|
+
}
|
|
1229
|
+
function isAttributeTerminator(token5) {
|
|
1230
|
+
return token5.type === "BLOCK_CLOSE" || token5.type === "NEWLINE" || token5.type === "EOF";
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
// packages/parser/src/parser/rules/block/parsing/attributes/index.ts
|
|
1234
|
+
function parseAttributes(ctx, startPos) {
|
|
1235
|
+
const result = scanAttributes(ctx, startPos, { hyphenatedNames: true, strikeHyphens: false });
|
|
1236
|
+
return { attrs: filterUnsafeAttributes(result.attrs), consumed: result.consumed };
|
|
1237
|
+
}
|
|
1238
|
+
function parseAttributesRaw(ctx, startPos, hyphenatedNames = true) {
|
|
1239
|
+
return scanAttributes(ctx, startPos, { hyphenatedNames, strikeHyphens: true });
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
// packages/parser/src/parser/rules/inline/date/syntax.ts
|
|
1243
|
+
function parseDateSyntax(ctx, start, end) {
|
|
1244
|
+
const tokens = ctx.tokens;
|
|
1245
|
+
if (tokens[start]?.type !== "BLOCK_OPEN" || tokens[start + 1]?.value !== "date")
|
|
1246
|
+
return null;
|
|
1247
|
+
let pos = start + 2;
|
|
1248
|
+
const skipSpace = () => {
|
|
1249
|
+
const before = pos;
|
|
1250
|
+
while (pos < end && /^(?:\s+)$/.test(tokens[pos]?.value ?? ""))
|
|
1251
|
+
pos++;
|
|
1252
|
+
return pos > before;
|
|
1253
|
+
};
|
|
1254
|
+
if (!skipSpace())
|
|
1255
|
+
return null;
|
|
1256
|
+
const value = tokens[pos]?.value ?? "";
|
|
1257
|
+
if (pos >= end || !/^\d+$/.test(value))
|
|
1258
|
+
return null;
|
|
1259
|
+
const timestamp = Number(value);
|
|
1260
|
+
if (!Number.isSafeInteger(timestamp) || timestamp > 8640000000000)
|
|
1261
|
+
return null;
|
|
1262
|
+
pos++;
|
|
1263
|
+
const separator = skipSpace();
|
|
1264
|
+
if (tokens[pos]?.type !== "BLOCK_CLOSE" && !separator)
|
|
1265
|
+
return null;
|
|
1266
|
+
let close = pos;
|
|
1267
|
+
for (;close < end; close++) {
|
|
1268
|
+
const token5 = tokens[close];
|
|
1269
|
+
if (!token5 || token5.type === "EOF" || token5.type === "BLOCK_OPEN" || /[\r\n]/.test(token5.value))
|
|
1270
|
+
return null;
|
|
1271
|
+
if (token5.type === "BLOCK_CLOSE")
|
|
1272
|
+
break;
|
|
1273
|
+
}
|
|
1274
|
+
if (close >= end)
|
|
1275
|
+
return null;
|
|
1276
|
+
const attributes = parseAttributesRaw(ctx, pos).attrs;
|
|
1277
|
+
const format = attributes.format || null;
|
|
1278
|
+
return {
|
|
1279
|
+
data: {
|
|
1280
|
+
value: { timestamp, timezone: "UTC" },
|
|
1281
|
+
format,
|
|
1282
|
+
hover: format?.split("|").slice(1).includes("agohover") ?? false
|
|
1283
|
+
},
|
|
1284
|
+
end: close + 1
|
|
1285
|
+
};
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
// packages/parser/src/parser/rules/inline/email/scan.ts
|
|
1289
|
+
function isDomainChar(code) {
|
|
1290
|
+
return code >= 48 && code <= 57 || code >= 65 && code <= 90 || code >= 97 && code <= 122 || code === 45;
|
|
1291
|
+
}
|
|
1292
|
+
function isLocalChar(code) {
|
|
1293
|
+
return isDomainChar(code) || code === 95;
|
|
1294
|
+
}
|
|
1295
|
+
function scanEmail(source, start, commentEnd) {
|
|
1296
|
+
const comments = [];
|
|
1297
|
+
let pos = start;
|
|
1298
|
+
const skipComments = () => {
|
|
1299
|
+
let end2 = commentEnd(pos);
|
|
1300
|
+
while (end2 > pos) {
|
|
1301
|
+
comments.push({ start: pos, end: end2 });
|
|
1302
|
+
pos = end2;
|
|
1303
|
+
end2 = commentEnd(pos);
|
|
1304
|
+
}
|
|
1305
|
+
};
|
|
1306
|
+
let localPart = false;
|
|
1307
|
+
while (pos < source.length) {
|
|
1308
|
+
skipComments();
|
|
1309
|
+
if (isLocalChar(source.charCodeAt(pos))) {
|
|
1310
|
+
localPart = true;
|
|
1311
|
+
pos++;
|
|
1312
|
+
} else if (source[pos] === "." && localPart) {
|
|
1313
|
+
localPart = false;
|
|
1314
|
+
pos++;
|
|
1315
|
+
} else
|
|
1316
|
+
break;
|
|
1317
|
+
}
|
|
1318
|
+
const localEnd = pos;
|
|
1319
|
+
if (!localPart || source[pos] !== "@")
|
|
1320
|
+
return { localEnd, comments };
|
|
1321
|
+
pos++;
|
|
1322
|
+
let domainPart = false;
|
|
1323
|
+
let dots = 0;
|
|
1324
|
+
let end = -1;
|
|
1325
|
+
while (pos < source.length) {
|
|
1326
|
+
skipComments();
|
|
1327
|
+
if (isDomainChar(source.charCodeAt(pos))) {
|
|
1328
|
+
domainPart = true;
|
|
1329
|
+
pos++;
|
|
1330
|
+
if (dots > 0)
|
|
1331
|
+
end = pos;
|
|
1332
|
+
} else if (source[pos] === "." && domainPart) {
|
|
1333
|
+
domainPart = false;
|
|
1334
|
+
dots++;
|
|
1335
|
+
pos++;
|
|
1336
|
+
} else
|
|
1337
|
+
break;
|
|
1338
|
+
}
|
|
1339
|
+
if (end === -1)
|
|
1340
|
+
return { localEnd, comments };
|
|
1341
|
+
const parts = [];
|
|
1342
|
+
let copied = start;
|
|
1343
|
+
for (const comment of comments) {
|
|
1344
|
+
if (comment.start >= end)
|
|
1345
|
+
break;
|
|
1346
|
+
parts.push(source.slice(copied, comment.start));
|
|
1347
|
+
copied = comment.end;
|
|
1348
|
+
}
|
|
1349
|
+
parts.push(source.slice(copied, end));
|
|
1350
|
+
return { end, address: parts.join(""), localEnd, comments };
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
// packages/parser/src/parser/rules/inline/email/candidates.ts
|
|
1354
|
+
var caches = new WeakMap;
|
|
1355
|
+
var EMAIL_START_TOKENS = [
|
|
1356
|
+
"TEXT",
|
|
1357
|
+
"IDENTIFIER",
|
|
1358
|
+
"UNDERSCORE",
|
|
1359
|
+
"UNDERLINE_MARKER",
|
|
1360
|
+
"STRIKE_MARKER"
|
|
1361
|
+
];
|
|
1362
|
+
function getCache(tokens) {
|
|
1363
|
+
let cache = caches.get(tokens);
|
|
1364
|
+
if (cache)
|
|
1365
|
+
return cache;
|
|
1366
|
+
const offsets = [0];
|
|
1367
|
+
const values = [];
|
|
1368
|
+
for (const token5 of tokens) {
|
|
1369
|
+
values.push(token5.value);
|
|
1370
|
+
offsets.push(offsets.at(-1) + token5.value.length);
|
|
1371
|
+
}
|
|
1372
|
+
cache = {
|
|
1373
|
+
source: values.join(""),
|
|
1374
|
+
offsets,
|
|
1375
|
+
candidates: new Map,
|
|
1376
|
+
commentEnds: new Map,
|
|
1377
|
+
unclosedComment: Infinity
|
|
1378
|
+
};
|
|
1379
|
+
caches.set(tokens, cache);
|
|
1380
|
+
return cache;
|
|
1381
|
+
}
|
|
1382
|
+
function commentEnd(cache, pos) {
|
|
1383
|
+
const opener = cache.source[pos] === `
|
|
1384
|
+
` ? pos + 1 : pos;
|
|
1385
|
+
if (!cache.source.startsWith("[!--", opener))
|
|
1386
|
+
return pos;
|
|
1387
|
+
const cached = cache.commentEnds.get(pos);
|
|
1388
|
+
if (cached !== undefined)
|
|
1389
|
+
return cached;
|
|
1390
|
+
const close = opener >= cache.unclosedComment ? -1 : cache.source.indexOf("--]", opener + 4);
|
|
1391
|
+
if (close === -1)
|
|
1392
|
+
cache.unclosedComment = Math.min(cache.unclosedComment, opener);
|
|
1393
|
+
const end = close === -1 ? pos : close + 3;
|
|
1394
|
+
cache.commentEnds.set(pos, end);
|
|
1395
|
+
return end;
|
|
1396
|
+
}
|
|
1397
|
+
function getEmailCandidate(tokens, index) {
|
|
1398
|
+
const token5 = tokens[index];
|
|
1399
|
+
if (!token5 || !EMAIL_START_TOKENS.includes(token5.type))
|
|
1400
|
+
return null;
|
|
1401
|
+
const cache = getCache(tokens);
|
|
1402
|
+
if (cache.candidates.has(index))
|
|
1403
|
+
return cache.candidates.get(index);
|
|
1404
|
+
const value = tokens[index]?.value ?? "";
|
|
1405
|
+
let suffix = value.length;
|
|
1406
|
+
while (suffix > 0 && (isLocalChar(value.charCodeAt(suffix - 1)) || value[suffix - 1] === "."))
|
|
1407
|
+
suffix--;
|
|
1408
|
+
const doubled = value.lastIndexOf("..");
|
|
1409
|
+
if (doubled >= suffix)
|
|
1410
|
+
suffix = doubled + 2;
|
|
1411
|
+
while (value[suffix] === ".")
|
|
1412
|
+
suffix++;
|
|
1413
|
+
if (suffix >= value.length || !isLocalChar(value.charCodeAt(suffix))) {
|
|
1414
|
+
cache.candidates.set(index, null);
|
|
1415
|
+
return null;
|
|
1416
|
+
}
|
|
1417
|
+
const start = cache.offsets[index] + suffix;
|
|
1418
|
+
const scanned = scanEmail(cache.source, start, (pos) => commentEnd(cache, pos));
|
|
1419
|
+
if (scanned.end === undefined) {
|
|
1420
|
+
cache.candidates.set(index, null);
|
|
1421
|
+
let comment = 0;
|
|
1422
|
+
for (let i = index + 1;i < tokens.length && cache.offsets[i + 1] <= scanned.localEnd; i++) {
|
|
1423
|
+
const offset = cache.offsets[i];
|
|
1424
|
+
while (scanned.comments[comment] && scanned.comments[comment].end <= offset)
|
|
1425
|
+
comment++;
|
|
1426
|
+
const region = scanned.comments[comment];
|
|
1427
|
+
if (!region || offset < region.start)
|
|
1428
|
+
cache.candidates.set(i, null);
|
|
1429
|
+
}
|
|
1430
|
+
return null;
|
|
1431
|
+
}
|
|
1432
|
+
let endToken = index;
|
|
1433
|
+
while (cache.offsets[endToken + 1] < scanned.end)
|
|
1434
|
+
endToken++;
|
|
1435
|
+
const candidate = { start, end: scanned.end, endToken, address: scanned.address };
|
|
1436
|
+
cache.candidates.set(index, candidate);
|
|
1437
|
+
return candidate;
|
|
1438
|
+
}
|
|
1439
|
+
function getEmailGroup(tokens, index, limit) {
|
|
1440
|
+
const first = getEmailCandidate(tokens, index);
|
|
1441
|
+
if (!first || first.endToken >= limit)
|
|
1442
|
+
return null;
|
|
1443
|
+
const candidates = [first];
|
|
1444
|
+
let last = first;
|
|
1445
|
+
while (last.endToken > index) {
|
|
1446
|
+
const next = getEmailCandidate(tokens, last.endToken);
|
|
1447
|
+
if (!next || next.start < last.end || next.endToken >= limit)
|
|
1448
|
+
break;
|
|
1449
|
+
candidates.push(next);
|
|
1450
|
+
last = next;
|
|
1451
|
+
}
|
|
1452
|
+
const cache = getCache(tokens);
|
|
1453
|
+
return {
|
|
1454
|
+
candidates,
|
|
1455
|
+
source: cache.source,
|
|
1456
|
+
start: cache.offsets[index],
|
|
1457
|
+
end: cache.offsets[last.endToken + 1],
|
|
1458
|
+
endToken: last.endToken + 1
|
|
1459
|
+
};
|
|
1460
|
+
}
|
|
1461
|
+
function emailRegionEnd(tokens, index, limit) {
|
|
1462
|
+
return getEmailGroup(tokens, index, limit)?.endToken ?? index;
|
|
1463
|
+
}
|
|
1464
|
+
|
|
930
1465
|
// packages/parser/src/parser/rules/inline/raw/end.ts
|
|
1466
|
+
var unclosedAngleRanges = new WeakMap;
|
|
931
1467
|
function rawRegionEnd(tokens, start, end) {
|
|
932
1468
|
const type = tokens[start]?.type;
|
|
933
1469
|
const close = type === "RAW_OPEN" ? "RAW_OPEN" : type === "RAW_BLOCK_OPEN" ? "RAW_BLOCK_CLOSE" : null;
|
|
934
1470
|
if (!close)
|
|
935
1471
|
return start;
|
|
1472
|
+
const cached = type === "RAW_BLOCK_OPEN" ? unclosedAngleRanges.get(tokens) : undefined;
|
|
1473
|
+
if (cached && start >= cached.start && start < cached.end && (cached.lineEnd || end <= cached.end)) {
|
|
1474
|
+
return start;
|
|
1475
|
+
}
|
|
936
1476
|
for (let pos = start + 1;pos < end; pos++) {
|
|
937
|
-
if (tokens[pos]?.type === "NEWLINE" || tokens[pos]?.type === "EOF")
|
|
938
|
-
|
|
1477
|
+
if (tokens[pos]?.type === "NEWLINE" || tokens[pos]?.type === "EOF") {
|
|
1478
|
+
if (type === "RAW_BLOCK_OPEN")
|
|
1479
|
+
unclosedAngleRanges.set(tokens, { start, end: pos, lineEnd: true });
|
|
1480
|
+
return start;
|
|
1481
|
+
}
|
|
939
1482
|
if (tokens[pos]?.type === close)
|
|
940
1483
|
return pos + 1;
|
|
941
1484
|
}
|
|
1485
|
+
if (type === "RAW_BLOCK_OPEN")
|
|
1486
|
+
unclosedAngleRanges.set(tokens, { start, end, lineEnd: false });
|
|
942
1487
|
return start;
|
|
943
1488
|
}
|
|
944
1489
|
function protectedInlineRegionEnd(tokens, start, end) {
|
|
@@ -957,7 +1502,7 @@ var MIN_INLINE_TEXT_RUN_LENGTH = 32;
|
|
|
957
1502
|
var MIN_INLINE_TEXT_RUN_DOCUMENT_TOKENS = 1e5;
|
|
958
1503
|
function collectLongPlainTextRun(ctx, startPos, endType) {
|
|
959
1504
|
const firstToken = ctx.tokens[startPos];
|
|
960
|
-
if (firstToken?.type === "TEXT" && firstToken.value.length >= MIN_INLINE_TEXT_RUN_LENGTH && firstToken.value !== "(") {
|
|
1505
|
+
if (!getEmailCandidate(ctx.tokens, startPos) && firstToken?.type === "TEXT" && firstToken.value.length >= MIN_INLINE_TEXT_RUN_LENGTH && firstToken.value !== "(") {
|
|
961
1506
|
return { value: firstToken.value, consumed: 1 };
|
|
962
1507
|
}
|
|
963
1508
|
let pos = startPos;
|
|
@@ -979,10 +1524,10 @@ function collectLongPlainTextRun(ctx, startPos, endType) {
|
|
|
979
1524
|
}
|
|
980
1525
|
function isPlainTextRunToken(ctx, pos) {
|
|
981
1526
|
const token5 = ctx.tokens[pos];
|
|
982
|
-
if (!token5)
|
|
1527
|
+
if (!token5 || getEmailCandidate(ctx.tokens, pos))
|
|
983
1528
|
return false;
|
|
984
1529
|
if (token5.type === "IDENTIFIER") {
|
|
985
|
-
return
|
|
1530
|
+
return !(URL_SCHEME_NAMES.has(token5.value) && ctx.tokens[pos + 1]?.type === "COLON");
|
|
986
1531
|
}
|
|
987
1532
|
if (token5.type === "WHITESPACE") {
|
|
988
1533
|
const next = ctx.tokens[pos + 1];
|
|
@@ -1131,6 +1676,10 @@ var BLOCK_START_TOKENS = [
|
|
|
1131
1676
|
"HEADING_MARKER",
|
|
1132
1677
|
"HR_MARKER",
|
|
1133
1678
|
"TABLE_MARKER",
|
|
1679
|
+
"TABLE_HEADER",
|
|
1680
|
+
"TABLE_LEFT",
|
|
1681
|
+
"TABLE_CENTER",
|
|
1682
|
+
"TABLE_RIGHT",
|
|
1134
1683
|
"COLON",
|
|
1135
1684
|
"BLOCK_OPEN",
|
|
1136
1685
|
"BLOCK_END_OPEN",
|
|
@@ -1208,14 +1757,727 @@ var INDENT_ACCEPTING_BLOCK_NAMES = new Set([
|
|
|
1208
1757
|
"tabs"
|
|
1209
1758
|
]);
|
|
1210
1759
|
|
|
1211
|
-
// packages/parser/src/parser/rules/
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1760
|
+
// packages/parser/src/parser/rules/block/code/open.ts
|
|
1761
|
+
var attributeRanges = new WeakMap;
|
|
1762
|
+
function findAttributesEnd(tokens, start) {
|
|
1763
|
+
const cached = attributeRanges.get(tokens);
|
|
1764
|
+
if (cached && start >= cached.start && start <= cached.end)
|
|
1765
|
+
return cached.end;
|
|
1766
|
+
let end = start;
|
|
1767
|
+
while (end < tokens.length) {
|
|
1768
|
+
const type = tokens[end]?.type;
|
|
1769
|
+
if (type === "BLOCK_CLOSE" || type === "NEWLINE" || type === "EOF")
|
|
1770
|
+
break;
|
|
1771
|
+
end++;
|
|
1772
|
+
}
|
|
1773
|
+
attributeRanges.set(tokens, { start, end });
|
|
1774
|
+
return end;
|
|
1775
|
+
}
|
|
1776
|
+
function findCodeOpen(tokens, start) {
|
|
1777
|
+
const name = tokens[start + 1];
|
|
1778
|
+
if (tokens[start]?.type !== "BLOCK_OPEN" || name?.type !== "IDENTIFIER" && name?.type !== "TEXT" || name.value.toLowerCase() !== "code" || tokens[start + 2]?.type === "UNDERSCORE")
|
|
1779
|
+
return null;
|
|
1780
|
+
const attributesEnd = findAttributesEnd(tokens, start + 2);
|
|
1781
|
+
const repaired = tokens[attributesEnd]?.type !== "BLOCK_CLOSE";
|
|
1782
|
+
const last = tokens[attributesEnd - 1];
|
|
1783
|
+
if (repaired && (last?.type !== "QUOTED_STRING" || !last.value.includes("]]")))
|
|
1784
|
+
return null;
|
|
1785
|
+
let bodyStart = attributesEnd + (repaired ? 0 : 1);
|
|
1786
|
+
if (tokens[bodyStart]?.type === "NEWLINE")
|
|
1787
|
+
bodyStart++;
|
|
1788
|
+
return {
|
|
1789
|
+
attributesEnd,
|
|
1790
|
+
bodyStart,
|
|
1791
|
+
repaired,
|
|
1792
|
+
closingSwallowed: repaired && last.value.includes("[[/code]]")
|
|
1793
|
+
};
|
|
1794
|
+
}
|
|
1795
|
+
|
|
1796
|
+
// packages/parser/src/parser/rules/block/code/boundary.ts
|
|
1797
|
+
var caches2 = new WeakMap;
|
|
1798
|
+
function codeCloseEnd(tokens, start) {
|
|
1799
|
+
if (tokens[start]?.type !== "BLOCK_END_OPEN" || tokens[start + 1]?.value.toLowerCase() !== "code")
|
|
1800
|
+
return start;
|
|
1801
|
+
let end = start + 2;
|
|
1802
|
+
while (tokens[end]?.type === "WHITESPACE")
|
|
1803
|
+
end++;
|
|
1804
|
+
return tokens[end]?.type === "BLOCK_CLOSE" ? end + 1 : start;
|
|
1805
|
+
}
|
|
1806
|
+
function nestedCodeBodyStart(tokens, start) {
|
|
1807
|
+
if (tokens[start]?.type !== "BLOCK_OPEN" || tokens[start + 1]?.value.toLowerCase() !== "code")
|
|
1808
|
+
return start;
|
|
1809
|
+
for (let pos = start + 2;pos < tokens.length; pos++) {
|
|
1810
|
+
const type = tokens[pos]?.type;
|
|
1811
|
+
if (type === "NEWLINE" || type === "EOF" || type === "BLOCK_OPEN")
|
|
1812
|
+
return start;
|
|
1813
|
+
if (type === "BLOCK_CLOSE") {
|
|
1814
|
+
const open = findCodeOpen(tokens, start);
|
|
1815
|
+
return open && !open.repaired ? open.bodyStart : start;
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
return start;
|
|
1819
|
+
}
|
|
1820
|
+
function findCodeBodyBounds(tokens, start) {
|
|
1821
|
+
let cache = caches2.get(tokens);
|
|
1822
|
+
if (!cache) {
|
|
1823
|
+
cache = new Map;
|
|
1824
|
+
caches2.set(tokens, cache);
|
|
1825
|
+
}
|
|
1826
|
+
const cached = cache.get(start);
|
|
1827
|
+
if (cached)
|
|
1828
|
+
return cached;
|
|
1829
|
+
const stack = [start];
|
|
1830
|
+
let pos = start;
|
|
1831
|
+
while (pos < tokens.length && tokens[pos]?.type !== "EOF") {
|
|
1832
|
+
const rawEnd = rawRegionEnd(tokens, pos, tokens.length);
|
|
1833
|
+
if (rawEnd > pos) {
|
|
1834
|
+
pos = rawEnd;
|
|
1835
|
+
continue;
|
|
1836
|
+
}
|
|
1837
|
+
const end = codeCloseEnd(tokens, pos);
|
|
1838
|
+
if (end > pos) {
|
|
1839
|
+
const result2 = { closeStart: pos, end, foundClose: true };
|
|
1840
|
+
cache.set(stack.pop(), result2);
|
|
1841
|
+
if (stack.length === 0)
|
|
1842
|
+
return result2;
|
|
1843
|
+
pos = end;
|
|
1844
|
+
continue;
|
|
1845
|
+
}
|
|
1846
|
+
const bodyStart = nestedCodeBodyStart(tokens, pos);
|
|
1847
|
+
if (bodyStart > pos) {
|
|
1848
|
+
const child = cache.get(bodyStart);
|
|
1849
|
+
if (child) {
|
|
1850
|
+
pos = child.end;
|
|
1851
|
+
if (!child.foundClose)
|
|
1852
|
+
break;
|
|
1853
|
+
} else {
|
|
1854
|
+
stack.push(bodyStart);
|
|
1855
|
+
pos = bodyStart;
|
|
1856
|
+
}
|
|
1857
|
+
continue;
|
|
1858
|
+
}
|
|
1859
|
+
pos++;
|
|
1860
|
+
}
|
|
1861
|
+
const result = { closeStart: pos, end: pos, foundClose: false };
|
|
1862
|
+
for (const bodyStart of stack)
|
|
1863
|
+
cache.set(bodyStart, result);
|
|
1864
|
+
return result;
|
|
1865
|
+
}
|
|
1866
|
+
|
|
1867
|
+
// packages/parser/src/parser/rules/block/math/boundary.ts
|
|
1868
|
+
var nameRanges = new WeakMap;
|
|
1869
|
+
var bodyCaches = new WeakMap;
|
|
1870
|
+
function findNameEnd(tokens, start) {
|
|
1871
|
+
const cached = nameRanges.get(tokens);
|
|
1872
|
+
if (cached && start >= cached.start && start <= cached.end)
|
|
1873
|
+
return cached.end;
|
|
1874
|
+
let end = start;
|
|
1875
|
+
while (end < tokens.length) {
|
|
1876
|
+
const type = tokens[end]?.type;
|
|
1877
|
+
if (type === "BLOCK_CLOSE" || type === "WHITESPACE" || type === "NEWLINE" || type === "EOF")
|
|
1878
|
+
break;
|
|
1879
|
+
end++;
|
|
1880
|
+
}
|
|
1881
|
+
nameRanges.set(tokens, { start, end });
|
|
1882
|
+
return end;
|
|
1883
|
+
}
|
|
1884
|
+
function findMathOpen(tokens, start) {
|
|
1885
|
+
const name = tokens[start + 1];
|
|
1886
|
+
if (tokens[start]?.type !== "BLOCK_OPEN" || name?.type !== "IDENTIFIER" && name?.type !== "TEXT" || name.value.toLowerCase() !== "math" || tokens[start + 2]?.type === "UNDERSCORE")
|
|
1887
|
+
return null;
|
|
1888
|
+
let pos = start + 2;
|
|
1889
|
+
while (tokens[pos]?.type === "WHITESPACE")
|
|
1890
|
+
pos++;
|
|
1891
|
+
const nameStart = pos;
|
|
1892
|
+
if (tokens[pos]?.type === "IDENTIFIER" || tokens[pos]?.type === "TEXT") {
|
|
1893
|
+
pos = findNameEnd(tokens, pos);
|
|
1894
|
+
}
|
|
1895
|
+
const nameEnd = pos;
|
|
1896
|
+
while (tokens[pos]?.type === "WHITESPACE")
|
|
1897
|
+
pos++;
|
|
1898
|
+
if (tokens[pos]?.type !== "BLOCK_CLOSE")
|
|
1899
|
+
return null;
|
|
1900
|
+
pos++;
|
|
1901
|
+
if (tokens[pos]?.type === "NEWLINE")
|
|
1902
|
+
pos++;
|
|
1903
|
+
return { nameStart, nameEnd, bodyStart: pos };
|
|
1904
|
+
}
|
|
1905
|
+
function mathCloseEnd(tokens, start) {
|
|
1906
|
+
if (tokens[start]?.type !== "BLOCK_END_OPEN" || tokens[start + 1]?.value.toLowerCase() !== "math" || tokens[start + 2]?.type !== "BLOCK_CLOSE")
|
|
1907
|
+
return start;
|
|
1908
|
+
const end = start + 3;
|
|
1909
|
+
return tokens[end]?.type === "NEWLINE" ? end + 1 : end;
|
|
1910
|
+
}
|
|
1911
|
+
function findMathBodyBounds(tokens, start) {
|
|
1912
|
+
let cache = bodyCaches.get(tokens);
|
|
1913
|
+
if (!cache) {
|
|
1914
|
+
cache = new Map;
|
|
1915
|
+
bodyCaches.set(tokens, cache);
|
|
1916
|
+
}
|
|
1917
|
+
const visited = [];
|
|
1918
|
+
let result = {
|
|
1919
|
+
closeStart: tokens.length,
|
|
1920
|
+
end: tokens.length,
|
|
1921
|
+
foundClose: false,
|
|
1922
|
+
hasContent: false
|
|
1923
|
+
};
|
|
1924
|
+
for (let pos = start;pos < tokens.length; pos++) {
|
|
1925
|
+
const cached = cache.get(pos);
|
|
1926
|
+
if (cached) {
|
|
1927
|
+
result = cached;
|
|
1928
|
+
break;
|
|
1929
|
+
}
|
|
1930
|
+
const end = mathCloseEnd(tokens, pos);
|
|
1931
|
+
if (end > pos) {
|
|
1932
|
+
result = { closeStart: pos, end, foundClose: true, hasContent: false };
|
|
1933
|
+
cache.set(pos, result);
|
|
1934
|
+
break;
|
|
1935
|
+
}
|
|
1936
|
+
visited.push(pos);
|
|
1937
|
+
}
|
|
1938
|
+
for (let i = visited.length - 1;i >= 0; i--) {
|
|
1939
|
+
const pos = visited[i];
|
|
1940
|
+
const token5 = tokens[pos];
|
|
1941
|
+
if (!result.hasContent && (token5.type === "BACKSLASH_BREAK" || token5.value.trim() !== "")) {
|
|
1942
|
+
result = { ...result, hasContent: true };
|
|
1943
|
+
}
|
|
1944
|
+
cache.set(pos, result);
|
|
1945
|
+
}
|
|
1946
|
+
return result;
|
|
1947
|
+
}
|
|
1948
|
+
|
|
1949
|
+
// packages/parser/src/parser/rules/opaque-probe.ts
|
|
1950
|
+
function createOpaqueProbe(ctx) {
|
|
1951
|
+
return {
|
|
1952
|
+
...ctx,
|
|
1953
|
+
diagnostics: [],
|
|
1954
|
+
footnotes: [],
|
|
1955
|
+
tocEntries: [],
|
|
1956
|
+
codeBlocks: [],
|
|
1957
|
+
htmlBlocks: [],
|
|
1958
|
+
bibcites: [],
|
|
1959
|
+
scope: {
|
|
1960
|
+
...ctx.scope,
|
|
1961
|
+
inlineEnd: undefined,
|
|
1962
|
+
tableFormatting: undefined,
|
|
1963
|
+
blockCloseCondition: () => true
|
|
1964
|
+
}
|
|
1965
|
+
};
|
|
1966
|
+
}
|
|
1967
|
+
function opaqueRuleEnd(probe, pos, rules, requireClosed = false) {
|
|
1968
|
+
const token5 = probe.tokens[pos];
|
|
1969
|
+
if (!token5)
|
|
1970
|
+
return pos;
|
|
1971
|
+
probe.pos = pos;
|
|
1972
|
+
for (const rule of rules) {
|
|
1973
|
+
if (!rule.startTokens.includes(token5.type))
|
|
1974
|
+
continue;
|
|
1975
|
+
if (rule.name === "code") {
|
|
1976
|
+
const open = findCodeOpen(probe.tokens, pos);
|
|
1977
|
+
if (!open)
|
|
1978
|
+
continue;
|
|
1979
|
+
if (open.closingSwallowed) {
|
|
1980
|
+
if (!requireClosed)
|
|
1981
|
+
return open.bodyStart;
|
|
1982
|
+
continue;
|
|
1983
|
+
}
|
|
1984
|
+
const bounds = findCodeBodyBounds(probe.tokens, open.bodyStart);
|
|
1985
|
+
if (!requireClosed || bounds.foundClose)
|
|
1986
|
+
return bounds.end;
|
|
1987
|
+
continue;
|
|
1988
|
+
}
|
|
1989
|
+
if (rule.name === "math") {
|
|
1990
|
+
const open = findMathOpen(probe.tokens, pos);
|
|
1991
|
+
if (!open)
|
|
1992
|
+
continue;
|
|
1993
|
+
const bounds = findMathBodyBounds(probe.tokens, open.bodyStart);
|
|
1994
|
+
if (bounds.hasContent && (!requireClosed || bounds.foundClose))
|
|
1995
|
+
return bounds.end;
|
|
1996
|
+
continue;
|
|
1997
|
+
}
|
|
1998
|
+
const result = rule.parse(probe);
|
|
1999
|
+
if (result.success)
|
|
2000
|
+
return pos + result.consumed;
|
|
2001
|
+
}
|
|
2002
|
+
return pos;
|
|
2003
|
+
}
|
|
2004
|
+
|
|
2005
|
+
// packages/parser/src/parser/rules/tokens.ts
|
|
2006
|
+
function currentToken(ctx) {
|
|
2007
|
+
return ctx.tokens[ctx.pos] ?? eofToken();
|
|
2008
|
+
}
|
|
2009
|
+
function eofToken() {
|
|
2010
|
+
return {
|
|
2011
|
+
type: "EOF",
|
|
2012
|
+
value: "",
|
|
2013
|
+
position: { start: { line: 0, column: 0, offset: 0 }, end: { line: 0, column: 0, offset: 0 } },
|
|
2014
|
+
lineStart: false
|
|
2015
|
+
};
|
|
2016
|
+
}
|
|
2017
|
+
function hasClosingMarkerBeforeNewline(ctx, markerType, markerValue) {
|
|
2018
|
+
let pos = ctx.pos;
|
|
2019
|
+
while (pos < (ctx.scope.inlineEnd ?? ctx.tokens.length)) {
|
|
2020
|
+
const token5 = ctx.tokens[pos];
|
|
2021
|
+
if (!token5 || token5.type === "NEWLINE" || token5.type === "EOF") {
|
|
2022
|
+
return false;
|
|
2023
|
+
}
|
|
2024
|
+
if (token5.type === markerType) {
|
|
2025
|
+
if (markerValue === undefined || token5.value === markerValue) {
|
|
2026
|
+
return true;
|
|
2027
|
+
}
|
|
2028
|
+
}
|
|
2029
|
+
pos++;
|
|
2030
|
+
}
|
|
2031
|
+
return false;
|
|
2032
|
+
}
|
|
2033
|
+
// packages/parser/src/parser/rules/block/code/attributes.ts
|
|
2034
|
+
function repairSwallowedCodeClose(ctx, pos, attrs) {
|
|
2035
|
+
const prevToken = ctx.tokens[pos - 1];
|
|
2036
|
+
if (prevToken?.type !== "QUOTED_STRING" || !prevToken.value.includes("]]")) {
|
|
2037
|
+
return null;
|
|
2038
|
+
}
|
|
2039
|
+
const rawValue = prevToken.value;
|
|
2040
|
+
const bracketIdx = rawValue.indexOf("]]");
|
|
2041
|
+
const truncatedValue = rawValue.startsWith('"') ? rawValue.slice(1, bracketIdx) : rawValue.slice(0, bracketIdx);
|
|
2042
|
+
for (const key of Object.keys(attrs)) {
|
|
2043
|
+
const stored = attrs[key];
|
|
2044
|
+
if (stored === rawValue || stored === rawValue.slice(1, -1) || stored === rawValue.slice(1)) {
|
|
2045
|
+
attrs[key] = truncatedValue;
|
|
2046
|
+
break;
|
|
2047
|
+
}
|
|
2048
|
+
}
|
|
2049
|
+
return {
|
|
2050
|
+
closingSwallowed: rawValue.includes("[[/code]]")
|
|
2051
|
+
};
|
|
2052
|
+
}
|
|
2053
|
+
|
|
2054
|
+
// packages/parser/src/parser/rules/block/paragraph/span-markers.ts
|
|
2055
|
+
function processCloseSpanMarkers(elements) {
|
|
2056
|
+
let result = null;
|
|
2057
|
+
for (let i = 0;i < elements.length; i++) {
|
|
2058
|
+
const elem = elements[i];
|
|
2059
|
+
if (!elem)
|
|
2060
|
+
continue;
|
|
2061
|
+
if (isCloseSpanMarker(elem)) {
|
|
2062
|
+
if (result === null) {
|
|
2063
|
+
result = elements.slice(0, i);
|
|
2064
|
+
}
|
|
2065
|
+
if (result.length > 0) {
|
|
2066
|
+
const spanContent = [...result];
|
|
2067
|
+
result.length = 0;
|
|
2068
|
+
result.push({
|
|
2069
|
+
element: "container",
|
|
2070
|
+
data: {
|
|
2071
|
+
type: "span",
|
|
2072
|
+
attributes: {},
|
|
2073
|
+
elements: spanContent
|
|
2074
|
+
}
|
|
2075
|
+
});
|
|
2076
|
+
}
|
|
2077
|
+
} else {
|
|
2078
|
+
result?.push(elem);
|
|
2079
|
+
}
|
|
2080
|
+
}
|
|
2081
|
+
return result ?? elements;
|
|
2082
|
+
}
|
|
2083
|
+
function isCloseSpanMarker(elem) {
|
|
2084
|
+
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;
|
|
2085
|
+
}
|
|
2086
|
+
|
|
2087
|
+
// packages/parser/src/parser/rules/inline/parsing/preserved-line-break.ts
|
|
2088
|
+
function createPreservedTrailingLineBreak() {
|
|
2089
|
+
const lineBreak = { element: "line-break" };
|
|
2090
|
+
lineBreak._preservedTrailingBreak = true;
|
|
2091
|
+
return lineBreak;
|
|
2092
|
+
}
|
|
2093
|
+
function createPreservedLeadingLineBreak() {
|
|
2094
|
+
const lineBreak = { element: "line-break", _preservedLeadingBreak: true };
|
|
2095
|
+
return lineBreak;
|
|
2096
|
+
}
|
|
2097
|
+
function isPreservedLeadingLineBreak(element) {
|
|
2098
|
+
return element?.element === "line-break" && element._preservedLeadingBreak === true;
|
|
2099
|
+
}
|
|
2100
|
+
|
|
2101
|
+
// packages/parser/src/parser/rules/block/paragraph/normalize.ts
|
|
2102
|
+
function normalizeParagraphElements(source) {
|
|
2103
|
+
let elements = processCloseSpanMarkers(source);
|
|
2104
|
+
removeTrailingLineBreaks(elements);
|
|
2105
|
+
removeTrailingWhitespaceText(elements);
|
|
2106
|
+
elements = removeLeadingLineBreaks(elements);
|
|
2107
|
+
return elements;
|
|
2108
|
+
}
|
|
2109
|
+
function removeTrailingLineBreaks(elements) {
|
|
2110
|
+
while (elements.length > 0 && elements[elements.length - 1]?.element === "line-break") {
|
|
2111
|
+
const lastEl = elements[elements.length - 1];
|
|
2112
|
+
if (lastEl._preservedTrailingBreak) {
|
|
2113
|
+
delete lastEl._preservedTrailingBreak;
|
|
2114
|
+
break;
|
|
2115
|
+
}
|
|
2116
|
+
elements.pop();
|
|
2117
|
+
}
|
|
2118
|
+
}
|
|
2119
|
+
function removeTrailingWhitespaceText(elements) {
|
|
2120
|
+
while (elements.length > 0) {
|
|
2121
|
+
const last = elements[elements.length - 1];
|
|
2122
|
+
if (last?.element === "text" && "data" in last && typeof last.data === "string" && last.data.trim() === "") {
|
|
2123
|
+
elements.pop();
|
|
2124
|
+
} else {
|
|
2125
|
+
break;
|
|
2126
|
+
}
|
|
2127
|
+
}
|
|
2128
|
+
}
|
|
2129
|
+
function removeLeadingLineBreaks(elements) {
|
|
2130
|
+
let first = 0;
|
|
2131
|
+
while (first < elements.length && elements[first]?.element === "line-break" && !isPreservedLeadingLineBreak(elements[first])) {
|
|
2132
|
+
first++;
|
|
2133
|
+
}
|
|
2134
|
+
return first > 0 ? elements.slice(first) : elements;
|
|
2135
|
+
}
|
|
2136
|
+
|
|
2137
|
+
// packages/parser/src/parser/rules/block/code/content.ts
|
|
2138
|
+
function collectCodeContent(ctx, startPos, closingSwallowed) {
|
|
2139
|
+
if (closingSwallowed)
|
|
2140
|
+
return { contents: "", consumed: 0, foundClose: true };
|
|
2141
|
+
const bounds = findCodeBodyBounds(ctx.tokens, startPos);
|
|
2142
|
+
return {
|
|
2143
|
+
contents: ctx.tokens.slice(startPos, bounds.closeStart).map((token5) => token5.value).join(""),
|
|
2144
|
+
consumed: bounds.end - startPos,
|
|
2145
|
+
foundClose: bounds.foundClose
|
|
2146
|
+
};
|
|
2147
|
+
}
|
|
2148
|
+
|
|
2149
|
+
// packages/parser/src/parser/rules/block/code/index.ts
|
|
2150
|
+
var codeBlockRule = {
|
|
2151
|
+
name: "code",
|
|
2152
|
+
startTokens: ["BLOCK_OPEN"],
|
|
2153
|
+
requiresLineStart: false,
|
|
2154
|
+
parse(ctx) {
|
|
2155
|
+
const openToken = currentToken(ctx);
|
|
2156
|
+
if (openToken.type !== "BLOCK_OPEN") {
|
|
2157
|
+
return { success: false };
|
|
2158
|
+
}
|
|
2159
|
+
const open = findCodeOpen(ctx.tokens, ctx.pos);
|
|
2160
|
+
if (!open)
|
|
2161
|
+
return { success: false };
|
|
2162
|
+
const attrResult = parseAttributesRaw(ctx, ctx.pos + 2);
|
|
2163
|
+
if (open.repaired)
|
|
2164
|
+
repairSwallowedCodeClose(ctx, open.attributesEnd, attrResult.attrs);
|
|
2165
|
+
let pos = open.bodyStart;
|
|
2166
|
+
let consumed = pos - ctx.pos;
|
|
2167
|
+
const contentResult = collectCodeContent(ctx, pos, open.closingSwallowed);
|
|
2168
|
+
let codeContent = contentResult.contents.replace(/\n$/, "");
|
|
2169
|
+
consumed += contentResult.consumed;
|
|
2170
|
+
pos += contentResult.consumed;
|
|
2171
|
+
if (!contentResult.foundClose) {
|
|
2172
|
+
ctx.diagnostics.push({
|
|
2173
|
+
severity: "warning",
|
|
2174
|
+
code: "unclosed-block",
|
|
2175
|
+
message: "Missing closing tag [[/code]] for [[code]]",
|
|
2176
|
+
position: openToken.position
|
|
2177
|
+
});
|
|
2178
|
+
}
|
|
2179
|
+
const codeBlockData = {
|
|
2180
|
+
contents: codeContent,
|
|
2181
|
+
language: attrResult.attrs.type ?? null,
|
|
2182
|
+
name: attrResult.attrs.name ?? null
|
|
2183
|
+
};
|
|
2184
|
+
ctx.codeBlocks.push(codeBlockData);
|
|
2185
|
+
const elements = [{ element: "code", data: codeBlockData }];
|
|
2186
|
+
if (ctx.tokens[pos]?.type === "NEWLINE" && !getParagraphNewlineBoundary(ctx, pos, false).shouldBreak && !ctx.scope.blockCloseCondition?.({ ...ctx, pos: pos + 1 })) {
|
|
2187
|
+
const after = parseInlineUntil({ ...ctx, pos: pos + 1 }, "PARAGRAPH_BREAK");
|
|
2188
|
+
elements.push({ element: "line-break" }, ...normalizeParagraphElements(after.elements));
|
|
2189
|
+
consumed += 1 + after.consumed;
|
|
2190
|
+
}
|
|
2191
|
+
return { success: true, elements, consumed };
|
|
2192
|
+
}
|
|
2193
|
+
};
|
|
2194
|
+
|
|
2195
|
+
// packages/parser/src/parser/rules/block/math/index.ts
|
|
2196
|
+
var mathBlockRule = {
|
|
2197
|
+
name: "math",
|
|
2198
|
+
startTokens: ["BLOCK_OPEN"],
|
|
2199
|
+
requiresLineStart: false,
|
|
2200
|
+
parse(ctx) {
|
|
2201
|
+
const openToken = currentToken(ctx);
|
|
2202
|
+
const open = findMathOpen(ctx.tokens, ctx.pos);
|
|
2203
|
+
if (!open)
|
|
2204
|
+
return { success: false };
|
|
2205
|
+
const bounds = findMathBodyBounds(ctx.tokens, open.bodyStart);
|
|
2206
|
+
if (!bounds.foundClose) {
|
|
2207
|
+
ctx.diagnostics.push({
|
|
2208
|
+
severity: "warning",
|
|
2209
|
+
code: "unclosed-block",
|
|
2210
|
+
message: "Missing closing tag [[/math]] for [[math]]",
|
|
2211
|
+
position: openToken.position
|
|
2212
|
+
});
|
|
2213
|
+
}
|
|
2214
|
+
if (!bounds.hasContent) {
|
|
2215
|
+
return { success: false };
|
|
2216
|
+
}
|
|
2217
|
+
const latexSource = ctx.tokens.slice(open.bodyStart, bounds.closeStart).map((token5) => token5.type === "BACKSLASH_BREAK" ? "\\\n" : token5.value).join("").trim();
|
|
2218
|
+
const name = ctx.tokens.slice(open.nameStart, open.nameEnd).map((token5) => token5.value).join("");
|
|
2219
|
+
return {
|
|
2220
|
+
success: true,
|
|
2221
|
+
elements: [
|
|
2222
|
+
{
|
|
2223
|
+
element: "math",
|
|
2224
|
+
data: {
|
|
2225
|
+
name: name || null,
|
|
2226
|
+
"latex-source": latexSource
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
],
|
|
2230
|
+
consumed: bounds.end - ctx.pos
|
|
2231
|
+
};
|
|
2232
|
+
}
|
|
2233
|
+
};
|
|
2234
|
+
|
|
2235
|
+
// packages/parser/src/parser/rules/inline/link-triple/fallback.ts
|
|
2236
|
+
function literalOpenLink(value) {
|
|
2237
|
+
return {
|
|
2238
|
+
success: true,
|
|
2239
|
+
elements: [{ element: "text", data: value }],
|
|
2240
|
+
consumed: 1
|
|
2241
|
+
};
|
|
2242
|
+
}
|
|
2243
|
+
|
|
2244
|
+
// packages/parser/src/parser/rules/inline/link-triple/label.ts
|
|
2245
|
+
function buildTripleLinkLabel(args) {
|
|
2246
|
+
if (args.isPage && args.foundPipe && !args.labelText.trim())
|
|
2247
|
+
return "page";
|
|
2248
|
+
return {
|
|
2249
|
+
text: getTripleLinkDisplayText({
|
|
2250
|
+
...args,
|
|
2251
|
+
originalTarget: args.isPage && !args.foundPipe ? args.originalTarget.split("#")[0] : args.originalTarget
|
|
2252
|
+
})
|
|
2253
|
+
};
|
|
2254
|
+
}
|
|
2255
|
+
function getTripleLinkDisplayText(args) {
|
|
2256
|
+
const trimmedLabel = args.labelText.trim();
|
|
2257
|
+
if (args.foundPipe) {
|
|
2258
|
+
return trimmedLabel || args.finalTarget;
|
|
2259
|
+
}
|
|
2260
|
+
const colonIdx = args.originalTarget.indexOf(":");
|
|
2261
|
+
if (colonIdx !== -1 && !args.originalTarget.startsWith("http") && !args.originalTarget.startsWith("*")) {
|
|
2262
|
+
return args.originalTarget.slice(colonIdx + 1).trim();
|
|
2263
|
+
}
|
|
2264
|
+
return args.originalTarget;
|
|
2265
|
+
}
|
|
2266
|
+
|
|
2267
|
+
// packages/parser/src/parser/rules/inline/link-triple/syntax.ts
|
|
2268
|
+
function hasClosingLinkMarker(ctx, startPos) {
|
|
2269
|
+
let pos = startPos;
|
|
2270
|
+
while (pos < ctx.tokens.length) {
|
|
2271
|
+
const token5 = ctx.tokens[pos];
|
|
2272
|
+
if (!token5 || token5.type === "EOF") {
|
|
2273
|
+
return false;
|
|
2274
|
+
}
|
|
2275
|
+
if (token5.type === "LINK_CLOSE") {
|
|
2276
|
+
return true;
|
|
2277
|
+
}
|
|
2278
|
+
if (token5.type === "NEWLINE") {
|
|
2279
|
+
const next = ctx.tokens[pos + 1];
|
|
2280
|
+
if (next?.type === "NEWLINE" || next?.type === "LINK_CLOSE") {
|
|
2281
|
+
return false;
|
|
2282
|
+
}
|
|
2283
|
+
}
|
|
2284
|
+
pos++;
|
|
2285
|
+
}
|
|
2286
|
+
return false;
|
|
2287
|
+
}
|
|
2288
|
+
function collectTripleLinkParts(ctx, startPos) {
|
|
2289
|
+
let target = "";
|
|
2290
|
+
let labelText = "";
|
|
2291
|
+
let foundPipe = false;
|
|
2292
|
+
let consumed = 1;
|
|
2293
|
+
let pos = startPos;
|
|
2294
|
+
while (pos < ctx.tokens.length) {
|
|
2295
|
+
const token5 = ctx.tokens[pos];
|
|
2296
|
+
if (!token5 || token5.type === "LINK_CLOSE" || token5.type === "EOF") {
|
|
2297
|
+
break;
|
|
2298
|
+
}
|
|
2299
|
+
if (token5.type === "NEWLINE") {
|
|
2300
|
+
if (foundPipe) {
|
|
2301
|
+
labelText += " ";
|
|
2302
|
+
} else {
|
|
2303
|
+
target += " ";
|
|
2304
|
+
}
|
|
2305
|
+
consumed++;
|
|
2306
|
+
pos++;
|
|
2307
|
+
continue;
|
|
2308
|
+
}
|
|
2309
|
+
if (token5.type === "PIPE" && !foundPipe) {
|
|
2310
|
+
foundPipe = true;
|
|
2311
|
+
} else if (foundPipe) {
|
|
2312
|
+
labelText += token5.value;
|
|
2313
|
+
} else {
|
|
2314
|
+
target += token5.value;
|
|
2315
|
+
}
|
|
2316
|
+
consumed++;
|
|
2317
|
+
pos++;
|
|
2318
|
+
}
|
|
2319
|
+
if (ctx.tokens[pos]?.type === "LINK_CLOSE") {
|
|
2320
|
+
consumed++;
|
|
2321
|
+
}
|
|
2322
|
+
return { target, labelText, foundPipe, consumed };
|
|
2323
|
+
}
|
|
2324
|
+
|
|
2325
|
+
// packages/parser/src/parser/rules/inline/link-triple/interwiki.ts
|
|
2326
|
+
var INTERWIKI_PREFIXES = new Set(["wikipedia", "google", "dictionary", "wikidot"]);
|
|
2327
|
+
function isInterwikiTarget(target) {
|
|
2328
|
+
const colonIdx = target.indexOf(":");
|
|
2329
|
+
if (colonIdx <= 0 || target.includes("/")) {
|
|
2330
|
+
return false;
|
|
2331
|
+
}
|
|
2332
|
+
const prefix = target.slice(0, colonIdx).toLowerCase();
|
|
2333
|
+
return INTERWIKI_PREFIXES.has(prefix);
|
|
2334
|
+
}
|
|
2335
|
+
|
|
2336
|
+
// packages/parser/src/parser/rules/inline/link-triple/target.ts
|
|
2337
|
+
function normalizeTripleLinkTarget(trimmedTarget) {
|
|
2338
|
+
if (trimmedTarget.startsWith("*")) {
|
|
2339
|
+
return { target: trimmedTarget.slice(1), hasStar: true };
|
|
2340
|
+
}
|
|
2341
|
+
return { target: trimmedTarget, hasStar: false };
|
|
2342
|
+
}
|
|
2343
|
+
function isInvalidTripleLinkTarget(trimmedTarget, foundPipe) {
|
|
2344
|
+
return trimmedTarget === "" && foundPipe || /#{2,}/.test(trimmedTarget);
|
|
2345
|
+
}
|
|
2346
|
+
function determineLinkTypeAndLocation(target) {
|
|
2347
|
+
if (target.startsWith("#")) {
|
|
2348
|
+
return { linkType: "anchor", link: target };
|
|
2349
|
+
}
|
|
2350
|
+
if (target.startsWith("http://") || target.startsWith("https://")) {
|
|
2351
|
+
return { linkType: "direct", link: target };
|
|
2352
|
+
}
|
|
2353
|
+
if (isInterwikiTarget(target)) {
|
|
2354
|
+
return { linkType: "interwiki", link: target };
|
|
2355
|
+
}
|
|
2356
|
+
return { linkType: "page", link: { site: null, page: target } };
|
|
2357
|
+
}
|
|
2358
|
+
|
|
2359
|
+
// packages/parser/src/parser/rules/inline/link-triple/index.ts
|
|
2360
|
+
var linkTripleRule = {
|
|
2361
|
+
name: "linkTriple",
|
|
2362
|
+
startTokens: ["LINK_OPEN"],
|
|
2363
|
+
parse(ctx) {
|
|
2364
|
+
const startToken = currentToken(ctx);
|
|
2365
|
+
if (!hasClosingLinkMarker(ctx, ctx.pos + 1)) {
|
|
2366
|
+
return literalOpenLink(startToken.value);
|
|
2367
|
+
}
|
|
2368
|
+
const parts = collectTripleLinkParts(ctx, ctx.pos + 1);
|
|
2369
|
+
const trimmedTarget = parts.target.trim();
|
|
2370
|
+
if (isInvalidTripleLinkTarget(trimmedTarget, parts.foundPipe)) {
|
|
2371
|
+
return literalOpenLink(startToken.value);
|
|
2372
|
+
}
|
|
2373
|
+
const normalized = normalizeTripleLinkTarget(trimmedTarget);
|
|
2374
|
+
const { linkType, link } = determineLinkTypeAndLocation(normalized.target);
|
|
2375
|
+
const label = buildTripleLinkLabel({
|
|
2376
|
+
isPage: linkType === "page",
|
|
2377
|
+
foundPipe: parts.foundPipe,
|
|
2378
|
+
labelText: parts.labelText,
|
|
2379
|
+
finalTarget: normalized.target,
|
|
2380
|
+
originalTarget: trimmedTarget
|
|
2381
|
+
});
|
|
2382
|
+
return {
|
|
2383
|
+
success: true,
|
|
2384
|
+
elements: [
|
|
2385
|
+
{
|
|
2386
|
+
element: "link",
|
|
2387
|
+
data: {
|
|
2388
|
+
type: linkType,
|
|
2389
|
+
link,
|
|
2390
|
+
extra: null,
|
|
2391
|
+
label,
|
|
2392
|
+
target: normalized.hasStar && linkType === "direct" ? "new-tab" : null
|
|
2393
|
+
}
|
|
2394
|
+
}
|
|
2395
|
+
],
|
|
2396
|
+
consumed: parts.consumed
|
|
2397
|
+
};
|
|
2398
|
+
}
|
|
2399
|
+
};
|
|
2400
|
+
|
|
2401
|
+
// packages/parser/src/parser/rules/block/note/boundary.ts
|
|
2402
|
+
var opaqueRules = [codeBlockRule, mathBlockRule, linkTripleRule];
|
|
2403
|
+
var boundsCache = new WeakMap;
|
|
2404
|
+
var closeCache = new WeakMap;
|
|
2405
|
+
function tagEnd(tokens, pos, name, close = false) {
|
|
2406
|
+
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;
|
|
2407
|
+
}
|
|
2408
|
+
function findClose(probe, start, name) {
|
|
2409
|
+
let byName = closeCache.get(probe.tokens);
|
|
2410
|
+
if (!byName) {
|
|
2411
|
+
byName = new Map;
|
|
2412
|
+
closeCache.set(probe.tokens, byName);
|
|
2413
|
+
}
|
|
2414
|
+
let cache = byName.get(name);
|
|
2415
|
+
if (!cache) {
|
|
2416
|
+
cache = new Map;
|
|
2417
|
+
byName.set(name, cache);
|
|
2418
|
+
}
|
|
2419
|
+
if (cache.has(start))
|
|
2420
|
+
return cache.get(start);
|
|
2421
|
+
const visited = [];
|
|
2422
|
+
let result = -1;
|
|
2423
|
+
for (let pos = start;pos < probe.tokens.length; pos++) {
|
|
2424
|
+
if (cache.has(pos)) {
|
|
2425
|
+
result = cache.get(pos);
|
|
2426
|
+
break;
|
|
2427
|
+
}
|
|
2428
|
+
visited.push(pos);
|
|
2429
|
+
const protectedEnd = protectedInlineRegionEnd(probe.tokens, pos, probe.tokens.length);
|
|
2430
|
+
if (protectedEnd > pos) {
|
|
2431
|
+
pos = protectedEnd - 1;
|
|
2432
|
+
continue;
|
|
2433
|
+
}
|
|
2434
|
+
if (tagEnd(probe.tokens, pos, name, true) > pos) {
|
|
2435
|
+
result = pos;
|
|
2436
|
+
break;
|
|
2437
|
+
}
|
|
2438
|
+
const opaqueEnd = opaqueRuleEnd(probe, pos, opaqueRules, true);
|
|
2439
|
+
if (opaqueEnd > pos) {
|
|
2440
|
+
pos = opaqueEnd - 1;
|
|
2441
|
+
continue;
|
|
2442
|
+
}
|
|
2443
|
+
if (name === "note") {
|
|
2444
|
+
const footnoteStart = tagEnd(probe.tokens, pos, "footnote");
|
|
2445
|
+
if (footnoteStart > pos) {
|
|
2446
|
+
const end = findClose(probe, footnoteStart, "footnote");
|
|
2447
|
+
if (end >= 0)
|
|
2448
|
+
pos = end + 2;
|
|
2449
|
+
}
|
|
2450
|
+
}
|
|
2451
|
+
}
|
|
2452
|
+
for (const pos of visited)
|
|
2453
|
+
cache.set(pos, result);
|
|
2454
|
+
return result;
|
|
2455
|
+
}
|
|
2456
|
+
function findNoteBounds(ctx, start = ctx.pos) {
|
|
2457
|
+
const openEnd = tagEnd(ctx.tokens, start, "note");
|
|
2458
|
+
if (openEnd === start || ctx.tokens[openEnd]?.type !== "NEWLINE")
|
|
2459
|
+
return null;
|
|
2460
|
+
let cache = boundsCache.get(ctx.tokens);
|
|
2461
|
+
if (!cache) {
|
|
2462
|
+
cache = new Map;
|
|
2463
|
+
boundsCache.set(ctx.tokens, cache);
|
|
2464
|
+
}
|
|
2465
|
+
if (cache.has(start))
|
|
2466
|
+
return cache.get(start);
|
|
2467
|
+
const close = findClose(createOpaqueProbe(ctx), openEnd + 1, "note");
|
|
2468
|
+
const result = close < 0 ? null : { bodyStart: openEnd + 1, close, end: close + 3 };
|
|
2469
|
+
cache.set(start, result);
|
|
2470
|
+
return result;
|
|
2471
|
+
}
|
|
2472
|
+
|
|
2473
|
+
// packages/parser/src/parser/rules/inline/parsing/block-boundary.ts
|
|
2474
|
+
function isExcludedBlockToken(ctx, tokenPos) {
|
|
2475
|
+
const excluded = ctx.scope.excludedBlockNames;
|
|
2476
|
+
if (!excluded?.size)
|
|
2477
|
+
return false;
|
|
2478
|
+
const token5 = ctx.tokens[tokenPos];
|
|
2479
|
+
if (token5?.type !== "BLOCK_OPEN" && token5?.type !== "BLOCK_END_OPEN")
|
|
2480
|
+
return false;
|
|
1219
2481
|
const nameResult = parseBlockName(ctx, tokenPos + 1);
|
|
1220
2482
|
return nameResult !== null && excluded.has(nameResult.name);
|
|
1221
2483
|
}
|
|
@@ -1230,6 +2492,8 @@ function isUnknownBlockToken(ctx, tokenPos) {
|
|
|
1230
2492
|
}
|
|
1231
2493
|
return true;
|
|
1232
2494
|
}
|
|
2495
|
+
if (nameResult.name === "note")
|
|
2496
|
+
return findNoteBounds(ctx, tokenPos) === null;
|
|
1233
2497
|
return !KNOWN_BLOCK_NAMES.has(nameResult.name);
|
|
1234
2498
|
}
|
|
1235
2499
|
function isIndentAcceptingBlock(ctx, tokenPos) {
|
|
@@ -1253,7 +2517,13 @@ function isParagraphBreakingBlockStart(ctx, newlinePos, lookAhead) {
|
|
|
1253
2517
|
if (!nextMeaningfulToken.lineStart && !isIndentedBlockOpener) {
|
|
1254
2518
|
return false;
|
|
1255
2519
|
}
|
|
1256
|
-
return !parseImageOpen({ ...ctx, pos: nextPos }) && !isOrphanCloseSpan(ctx, nextPos) && !isAnchorName(ctx, nextPos) && !isInvalidBlockOpen(ctx, nextPos) && !isInvalidHeading(ctx, nextPos) && !isExcludedBlockStart(ctx, nextPos) && !isUnknownBlockStart(ctx, nextPos);
|
|
2520
|
+
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);
|
|
2521
|
+
}
|
|
2522
|
+
function isInvalidListMarker(ctx, markerPos) {
|
|
2523
|
+
const marker = ctx.tokens[markerPos];
|
|
2524
|
+
if (marker?.type !== "LIST_BULLET" && marker?.type !== "LIST_NUMBER")
|
|
2525
|
+
return false;
|
|
2526
|
+
return ctx.tokens[markerPos + 1]?.type !== "WHITESPACE";
|
|
1257
2527
|
}
|
|
1258
2528
|
function isOrphanCloseSpan(ctx, blockEndOpenPos) {
|
|
1259
2529
|
const token5 = ctx.tokens[blockEndOpenPos];
|
|
@@ -1339,13 +2609,6 @@ function skipWhitespaceAfterNewline(ctx, newlinePos) {
|
|
|
1339
2609
|
return lookAhead;
|
|
1340
2610
|
}
|
|
1341
2611
|
|
|
1342
|
-
// packages/parser/src/parser/rules/inline/parsing/preserved-line-break.ts
|
|
1343
|
-
function createPreservedTrailingLineBreak() {
|
|
1344
|
-
const lineBreak = { element: "line-break" };
|
|
1345
|
-
lineBreak._preservedTrailingBreak = true;
|
|
1346
|
-
return lineBreak;
|
|
1347
|
-
}
|
|
1348
|
-
|
|
1349
2612
|
// packages/parser/src/parser/rules/inline/parsing/simple-token.ts
|
|
1350
2613
|
function parseSimpleInlineToken(token5, nextToken) {
|
|
1351
2614
|
if (token5.type === "TEXT" && token5.value !== "(") {
|
|
@@ -1362,12 +2625,13 @@ function parseInlineUntil(ctx, endType) {
|
|
|
1362
2625
|
const nodes = [];
|
|
1363
2626
|
let consumed = 0;
|
|
1364
2627
|
let pos = ctx.pos;
|
|
2628
|
+
let consumedEmptyRaw = false;
|
|
1365
2629
|
const paragraphMode = endType === "PARAGRAPH_BREAK";
|
|
1366
2630
|
const multiline = paragraphMode || FORMATTING_CLOSE_TOKENS.has(endType);
|
|
1367
2631
|
let inlineEnd = ctx.scope.inlineEnd ?? ctx.tokens.length;
|
|
1368
2632
|
if (!multiline) {
|
|
1369
2633
|
for (let end = ctx.pos;end < inlineEnd; end++) {
|
|
1370
|
-
const protectedEnd = protectedInlineRegionEnd(ctx.tokens, end, inlineEnd);
|
|
2634
|
+
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));
|
|
1371
2635
|
if (protectedEnd > end) {
|
|
1372
2636
|
end = protectedEnd - 1;
|
|
1373
2637
|
continue;
|
|
@@ -1416,10 +2680,11 @@ function parseInlineUntil(ctx, endType) {
|
|
|
1416
2680
|
consumed++;
|
|
1417
2681
|
continue;
|
|
1418
2682
|
}
|
|
1419
|
-
|
|
2683
|
+
const hasEmail = emailRegionEnd(ctx.tokens, pos, inlineEnd) > pos;
|
|
2684
|
+
if (token5.type === endType && !hasEmail) {
|
|
1420
2685
|
break;
|
|
1421
2686
|
}
|
|
1422
|
-
if (canCollectLongPlainTextRuns) {
|
|
2687
|
+
if (canCollectLongPlainTextRuns && !hasEmail) {
|
|
1423
2688
|
const plainTextRun = collectLongPlainTextRun(ctx, pos, endType);
|
|
1424
2689
|
if (plainTextRun) {
|
|
1425
2690
|
nodes.push({ element: "text", data: plainTextRun.value });
|
|
@@ -1429,7 +2694,7 @@ function parseInlineUntil(ctx, endType) {
|
|
|
1429
2694
|
}
|
|
1430
2695
|
}
|
|
1431
2696
|
const simpleToken = parseSimpleInlineToken(token5, ctx.tokens[pos + 1]);
|
|
1432
|
-
if (simpleToken) {
|
|
2697
|
+
if (simpleToken && !hasEmail) {
|
|
1433
2698
|
nodes.push(simpleToken.element);
|
|
1434
2699
|
consumed += simpleToken.consumed;
|
|
1435
2700
|
pos += simpleToken.consumed;
|
|
@@ -1440,6 +2705,10 @@ function parseInlineUntil(ctx, endType) {
|
|
|
1440
2705
|
for (const rule of getCandidateInlineRules(inlineRules, token5.type)) {
|
|
1441
2706
|
const result = rule.parse(inlineCtx);
|
|
1442
2707
|
if (result.success) {
|
|
2708
|
+
stripAutomaticLineBreak(nodes, result.stripLeadingLineBreak);
|
|
2709
|
+
if (rule.name === "raw" && result.elements.length === 0 && nodes.length === 0) {
|
|
2710
|
+
consumedEmptyRaw = true;
|
|
2711
|
+
}
|
|
1443
2712
|
if (rule.name === "comment") {
|
|
1444
2713
|
let after = pos + result.consumed;
|
|
1445
2714
|
while (ctx.tokens[after]?.type === "WHITESPACE")
|
|
@@ -1458,7 +2727,9 @@ function parseInlineUntil(ctx, endType) {
|
|
|
1458
2727
|
nodes.pop();
|
|
1459
2728
|
}
|
|
1460
2729
|
}
|
|
1461
|
-
|
|
2730
|
+
for (const element of result.elements) {
|
|
2731
|
+
nodes.push(paragraphMode && consumedEmptyRaw && nodes.length === 0 && token5.type === "NEWLINE" && element.element === "line-break" ? createPreservedLeadingLineBreak() : element);
|
|
2732
|
+
}
|
|
1462
2733
|
consumed += result.consumed;
|
|
1463
2734
|
pos += result.consumed;
|
|
1464
2735
|
matched = true;
|
|
@@ -1483,138 +2754,10 @@ var FORMATTING_CLOSE_TOKENS = new Set([
|
|
|
1483
2754
|
"MONO_CLOSE",
|
|
1484
2755
|
"COLOR_MARKER"
|
|
1485
2756
|
]);
|
|
1486
|
-
// packages/parser/src/parser/rules/block/parsing/attributes/names.ts
|
|
1487
|
-
function consumeAttributeName(ctx, startPos, startConsumed, startName, options) {
|
|
1488
|
-
if (startName === "_" && isAttributeWordToken(ctx.tokens[startPos])) {
|
|
1489
|
-
startName += ctx.tokens[startPos]?.value ?? "";
|
|
1490
|
-
startPos++;
|
|
1491
|
-
startConsumed++;
|
|
1492
|
-
}
|
|
1493
|
-
return options.strikeHyphens ? consumeRawNameSuffix(ctx, startPos, startConsumed, startName, options.hyphenatedNames) : consumeSafeNameSuffix(ctx, startPos, startConsumed, startName);
|
|
1494
|
-
}
|
|
1495
|
-
function isAttributeNameToken(token5) {
|
|
1496
|
-
return isAttributeWordToken(token5) || token5?.type === "UNDERSCORE";
|
|
1497
|
-
}
|
|
1498
|
-
function consumeSafeNameSuffix(ctx, startPos, startConsumed, startName) {
|
|
1499
|
-
let name = startName;
|
|
1500
|
-
let pos = startPos;
|
|
1501
|
-
let consumed = startConsumed;
|
|
1502
|
-
while (isAttributeNameSeparator(ctx.tokens[pos]) && isAttributeWordToken(ctx.tokens[pos + 1])) {
|
|
1503
|
-
name += ctx.tokens[pos]?.value ?? "";
|
|
1504
|
-
pos++;
|
|
1505
|
-
consumed++;
|
|
1506
|
-
name += ctx.tokens[pos]?.value ?? "";
|
|
1507
|
-
pos++;
|
|
1508
|
-
consumed++;
|
|
1509
|
-
}
|
|
1510
|
-
return { name, pos, consumed };
|
|
1511
|
-
}
|
|
1512
|
-
function consumeRawNameSuffix(ctx, startPos, startConsumed, startName, hyphenatedNames) {
|
|
1513
|
-
let name = startName;
|
|
1514
|
-
let pos = startPos;
|
|
1515
|
-
let consumed = startConsumed;
|
|
1516
|
-
while (isAttributeNameSeparator(ctx.tokens[pos])) {
|
|
1517
|
-
while (isAttributeNameSeparator(ctx.tokens[pos])) {
|
|
1518
|
-
if (hyphenatedNames || ctx.tokens[pos]?.type === "UNDERSCORE") {
|
|
1519
|
-
name += ctx.tokens[pos]?.value ?? "-";
|
|
1520
|
-
}
|
|
1521
|
-
pos++;
|
|
1522
|
-
consumed++;
|
|
1523
|
-
}
|
|
1524
|
-
if (!isAttributeWordToken(ctx.tokens[pos])) {
|
|
1525
|
-
break;
|
|
1526
|
-
}
|
|
1527
|
-
if (hyphenatedNames || name.endsWith("_")) {
|
|
1528
|
-
name += ctx.tokens[pos]?.value ?? "";
|
|
1529
|
-
}
|
|
1530
|
-
pos++;
|
|
1531
|
-
consumed++;
|
|
1532
|
-
}
|
|
1533
|
-
return { name, pos, consumed };
|
|
1534
|
-
}
|
|
1535
|
-
function isAttributeWordToken(token5) {
|
|
1536
|
-
return token5?.type === "TEXT" || token5?.type === "IDENTIFIER";
|
|
1537
|
-
}
|
|
1538
|
-
function isAttributeNameSeparator(token5) {
|
|
1539
|
-
return token5?.type === "TEXT" && token5.value === "-" || token5?.type === "STRIKE_MARKER" || token5?.type === "UNDERSCORE";
|
|
1540
|
-
}
|
|
1541
|
-
|
|
1542
|
-
// packages/parser/src/parser/rules/block/parsing/attributes/values.ts
|
|
1543
|
-
function consumeAttributeValue(token5) {
|
|
1544
|
-
if (!token5) {
|
|
1545
|
-
return null;
|
|
1546
|
-
}
|
|
1547
|
-
if (token5.type === "QUOTED_STRING") {
|
|
1548
|
-
return { value: stripQuotes(token5.value) };
|
|
1549
|
-
}
|
|
1550
|
-
if (isAttributeNameToken(token5)) {
|
|
1551
|
-
return { value: token5.value };
|
|
1552
|
-
}
|
|
1553
|
-
return null;
|
|
1554
|
-
}
|
|
1555
|
-
function stripQuotes(value) {
|
|
1556
|
-
return value.startsWith('"') && value.endsWith('"') ? value.slice(1, -1) : value;
|
|
1557
|
-
}
|
|
1558
|
-
|
|
1559
|
-
// packages/parser/src/parser/rules/block/parsing/attributes/scanner.ts
|
|
1560
|
-
function scanAttributes(ctx, startPos, options) {
|
|
1561
|
-
const attrs = {};
|
|
1562
|
-
let pos = startPos;
|
|
1563
|
-
let consumed = 0;
|
|
1564
|
-
while (pos < ctx.tokens.length) {
|
|
1565
|
-
const token5 = ctx.tokens[pos];
|
|
1566
|
-
if (!token5 || isAttributeTerminator(token5)) {
|
|
1567
|
-
break;
|
|
1568
|
-
}
|
|
1569
|
-
if (token5.type === "WHITESPACE") {
|
|
1570
|
-
pos++;
|
|
1571
|
-
consumed++;
|
|
1572
|
-
continue;
|
|
1573
|
-
}
|
|
1574
|
-
if (!isAttributeNameToken(token5)) {
|
|
1575
|
-
pos++;
|
|
1576
|
-
consumed++;
|
|
1577
|
-
continue;
|
|
1578
|
-
}
|
|
1579
|
-
let name = token5.value;
|
|
1580
|
-
pos++;
|
|
1581
|
-
consumed++;
|
|
1582
|
-
const nameResult = consumeAttributeName(ctx, pos, consumed, name, options);
|
|
1583
|
-
pos = nameResult.pos;
|
|
1584
|
-
consumed = nameResult.consumed;
|
|
1585
|
-
name = nameResult.name.toLowerCase();
|
|
1586
|
-
if (ctx.tokens[pos]?.type !== "EQUALS") {
|
|
1587
|
-
attrs[name] = "true";
|
|
1588
|
-
continue;
|
|
1589
|
-
}
|
|
1590
|
-
pos++;
|
|
1591
|
-
consumed++;
|
|
1592
|
-
const valueResult = consumeAttributeValue(ctx.tokens[pos]);
|
|
1593
|
-
if (!valueResult) {
|
|
1594
|
-
continue;
|
|
1595
|
-
}
|
|
1596
|
-
attrs[name] = valueResult.value;
|
|
1597
|
-
pos++;
|
|
1598
|
-
consumed++;
|
|
1599
|
-
}
|
|
1600
|
-
return { attrs, consumed };
|
|
1601
|
-
}
|
|
1602
|
-
function isAttributeTerminator(token5) {
|
|
1603
|
-
return token5.type === "BLOCK_CLOSE" || token5.type === "NEWLINE" || token5.type === "EOF";
|
|
1604
|
-
}
|
|
1605
|
-
|
|
1606
|
-
// packages/parser/src/parser/rules/block/parsing/attributes/index.ts
|
|
1607
|
-
function parseAttributes(ctx, startPos) {
|
|
1608
|
-
const result = scanAttributes(ctx, startPos, { hyphenatedNames: true, strikeHyphens: false });
|
|
1609
|
-
return { attrs: filterUnsafeAttributes(result.attrs), consumed: result.consumed };
|
|
1610
|
-
}
|
|
1611
|
-
function parseAttributesRaw(ctx, startPos, hyphenatedNames = true) {
|
|
1612
|
-
return scanAttributes(ctx, startPos, { hyphenatedNames, strikeHyphens: true });
|
|
1613
|
-
}
|
|
1614
2757
|
// packages/parser/src/parser/parse/block.ts
|
|
1615
|
-
function parseNextBlock(ctx, skipWhitespace2,
|
|
2758
|
+
function parseNextBlock(ctx, skipWhitespace2, isAtEnd3) {
|
|
1616
2759
|
skipWhitespace2();
|
|
1617
|
-
if (
|
|
2760
|
+
if (isAtEnd3()) {
|
|
1618
2761
|
return [];
|
|
1619
2762
|
}
|
|
1620
2763
|
const token5 = ctx.tokens[ctx.pos];
|
|
@@ -1633,7 +2776,7 @@ function parseNextBlock(ctx, skipWhitespace2, isAtEnd2) {
|
|
|
1633
2776
|
}
|
|
1634
2777
|
}
|
|
1635
2778
|
const result = ctx.blockFallbackRule.parse(ctx);
|
|
1636
|
-
if (result.success
|
|
2779
|
+
if (result.success) {
|
|
1637
2780
|
ctx.pos += result.consumed;
|
|
1638
2781
|
return result.elements;
|
|
1639
2782
|
}
|
|
@@ -1643,35 +2786,6 @@ function parseNextBlock(ctx, skipWhitespace2, isAtEnd2) {
|
|
|
1643
2786
|
|
|
1644
2787
|
// packages/parser/src/parser/parse/context.ts
|
|
1645
2788
|
import { DEFAULT_SETTINGS } from "@wdprlib/ast";
|
|
1646
|
-
|
|
1647
|
-
// packages/parser/src/parser/rules/tokens.ts
|
|
1648
|
-
function currentToken(ctx) {
|
|
1649
|
-
return ctx.tokens[ctx.pos] ?? eofToken();
|
|
1650
|
-
}
|
|
1651
|
-
function eofToken() {
|
|
1652
|
-
return {
|
|
1653
|
-
type: "EOF",
|
|
1654
|
-
value: "",
|
|
1655
|
-
position: { start: { line: 0, column: 0, offset: 0 }, end: { line: 0, column: 0, offset: 0 } },
|
|
1656
|
-
lineStart: false
|
|
1657
|
-
};
|
|
1658
|
-
}
|
|
1659
|
-
function hasClosingMarkerBeforeNewline(ctx, markerType, markerValue) {
|
|
1660
|
-
let pos = ctx.pos;
|
|
1661
|
-
while (pos < (ctx.scope.inlineEnd ?? ctx.tokens.length)) {
|
|
1662
|
-
const token5 = ctx.tokens[pos];
|
|
1663
|
-
if (!token5 || token5.type === "NEWLINE" || token5.type === "EOF") {
|
|
1664
|
-
return false;
|
|
1665
|
-
}
|
|
1666
|
-
if (token5.type === markerType) {
|
|
1667
|
-
if (markerValue === undefined || token5.value === markerValue) {
|
|
1668
|
-
return true;
|
|
1669
|
-
}
|
|
1670
|
-
}
|
|
1671
|
-
pos++;
|
|
1672
|
-
}
|
|
1673
|
-
return false;
|
|
1674
|
-
}
|
|
1675
2789
|
// packages/parser/src/parser/rules/block/heading/open.ts
|
|
1676
2790
|
function parseHeadingOpen(ctx) {
|
|
1677
2791
|
const marker = ctx.tokens[ctx.pos];
|
|
@@ -1917,10 +3031,11 @@ function parseNativeListLine(ctx, startPos) {
|
|
|
1917
3031
|
const ltype = markerToken.type === "LIST_BULLET" ? "bullet" : "numbered";
|
|
1918
3032
|
pos++;
|
|
1919
3033
|
consumed++;
|
|
1920
|
-
if (ctx.tokens[pos]?.type
|
|
1921
|
-
|
|
1922
|
-
consumed++;
|
|
3034
|
+
if (ctx.tokens[pos]?.type !== "WHITESPACE") {
|
|
3035
|
+
return { kind: "stop" };
|
|
1923
3036
|
}
|
|
3037
|
+
pos++;
|
|
3038
|
+
consumed++;
|
|
1924
3039
|
const inlineCtx = { ...ctx, pos };
|
|
1925
3040
|
const inlineResult = parseInlineUntil(inlineCtx, "NEWLINE");
|
|
1926
3041
|
consumed += inlineResult.consumed;
|
|
@@ -2030,9 +3145,9 @@ function appendBareParagraphElements(state, elements) {
|
|
|
2030
3145
|
function appendBareParagraphText(state, text) {
|
|
2031
3146
|
state.current.push({ element: "text", data: text });
|
|
2032
3147
|
}
|
|
2033
|
-
function appendBareParagraphLineBreakIfNeeded(state) {
|
|
3148
|
+
function appendBareParagraphLineBreakIfNeeded(state, token5) {
|
|
2034
3149
|
if (state.current.length > 0) {
|
|
2035
|
-
state.current.push(
|
|
3150
|
+
state.current.push(createAutomaticLineBreak(token5));
|
|
2036
3151
|
}
|
|
2037
3152
|
}
|
|
2038
3153
|
function flushBareParagraph(state) {
|
|
@@ -2137,7 +3252,7 @@ function parseBareListContent(ctx, startPos, listType) {
|
|
|
2137
3252
|
if (consecutiveNewlines >= 2) {
|
|
2138
3253
|
flushBareParagraph(paragraphState);
|
|
2139
3254
|
} else {
|
|
2140
|
-
appendBareParagraphLineBreakIfNeeded(paragraphState);
|
|
3255
|
+
appendBareParagraphLineBreakIfNeeded(paragraphState, token5);
|
|
2141
3256
|
}
|
|
2142
3257
|
continue;
|
|
2143
3258
|
}
|
|
@@ -2149,6 +3264,7 @@ function parseBareListContent(ctx, startPos, listType) {
|
|
|
2149
3264
|
for (const rule of getCandidateInlineRules(ctx.inlineRules, token5.type)) {
|
|
2150
3265
|
const result = rule.parse(inlineCtx);
|
|
2151
3266
|
if (result.success) {
|
|
3267
|
+
stripAutomaticLineBreak(paragraphState.current, result.stripLeadingLineBreak);
|
|
2152
3268
|
appendBareParagraphElements(paragraphState, result.elements);
|
|
2153
3269
|
consumed += result.consumed;
|
|
2154
3270
|
pos += result.consumed;
|
|
@@ -2187,7 +3303,7 @@ function parseListItemBlockContent(ctx, pos, token5) {
|
|
|
2187
3303
|
for (const rule of getCandidateBlockRules(filteredBlockRules, token5)) {
|
|
2188
3304
|
const result = rule.parse(blockCtx);
|
|
2189
3305
|
if (result.success) {
|
|
2190
|
-
return { matched: true,
|
|
3306
|
+
return { matched: true, ...result };
|
|
2191
3307
|
}
|
|
2192
3308
|
}
|
|
2193
3309
|
return { matched: false, elements: [], consumed: 0 };
|
|
@@ -2206,7 +3322,7 @@ function parseListItemInlineContent(ctx, pos, tokenType) {
|
|
|
2206
3322
|
for (const rule of getCandidateInlineRules(ctx.inlineRules, tokenType)) {
|
|
2207
3323
|
const result = rule.parse(inlineCtx);
|
|
2208
3324
|
if (result.success) {
|
|
2209
|
-
return { matched: true,
|
|
3325
|
+
return { matched: true, ...result };
|
|
2210
3326
|
}
|
|
2211
3327
|
}
|
|
2212
3328
|
return { matched: false, elements: [], consumed: 0 };
|
|
@@ -2248,7 +3364,9 @@ function collectPostLiTrailingContent(ctx, startPos, listType) {
|
|
|
2248
3364
|
}
|
|
2249
3365
|
const inlineResult = parseListItemInlineContent(ctx, pos, token5.type);
|
|
2250
3366
|
if (inlineResult.matched) {
|
|
2251
|
-
elements
|
|
3367
|
+
stripAutomaticLineBreak(elements, inlineResult.stripLeadingLineBreak);
|
|
3368
|
+
for (const element of inlineResult.elements)
|
|
3369
|
+
elements.push(element);
|
|
2252
3370
|
consumed += inlineResult.consumed;
|
|
2253
3371
|
pos += inlineResult.consumed;
|
|
2254
3372
|
continue;
|
|
@@ -2293,7 +3411,7 @@ function collectLiItemContent(ctx, startPos, listType, parseNestedList) {
|
|
|
2293
3411
|
if (token5.type === "NEWLINE") {
|
|
2294
3412
|
const newlineResult = consumeLiItemNewlines(ctx, pos, elements.length > 0);
|
|
2295
3413
|
if (newlineResult.addLineBreak) {
|
|
2296
|
-
elements.push(
|
|
3414
|
+
elements.push(createAutomaticLineBreak(token5));
|
|
2297
3415
|
}
|
|
2298
3416
|
pos += newlineResult.consumed;
|
|
2299
3417
|
consumed += newlineResult.consumed;
|
|
@@ -2301,14 +3419,17 @@ function collectLiItemContent(ctx, startPos, listType, parseNestedList) {
|
|
|
2301
3419
|
}
|
|
2302
3420
|
const blockResult = parseListItemBlockContent(ctx, pos, token5);
|
|
2303
3421
|
if (blockResult.matched) {
|
|
2304
|
-
|
|
3422
|
+
for (const element of blockResult.elements)
|
|
3423
|
+
elements.push(element);
|
|
2305
3424
|
consumed += blockResult.consumed;
|
|
2306
3425
|
pos += blockResult.consumed;
|
|
2307
3426
|
continue;
|
|
2308
3427
|
}
|
|
2309
3428
|
const inlineResult = parseListItemInlineContent(ctx, pos, token5.type);
|
|
2310
3429
|
if (inlineResult.matched) {
|
|
2311
|
-
elements
|
|
3430
|
+
stripAutomaticLineBreak(elements, inlineResult.stripLeadingLineBreak);
|
|
3431
|
+
for (const element of inlineResult.elements)
|
|
3432
|
+
elements.push(element);
|
|
2312
3433
|
consumed += inlineResult.consumed;
|
|
2313
3434
|
pos += inlineResult.consumed;
|
|
2314
3435
|
continue;
|
|
@@ -2379,7 +3500,8 @@ function parseLiItem(ctx, startPos, listType, parseNestedList) {
|
|
|
2379
3500
|
consumed += closeConsumed;
|
|
2380
3501
|
pos += closeConsumed;
|
|
2381
3502
|
const trailingResult = collectPostLiTrailingContent(ctx, pos, listType);
|
|
2382
|
-
|
|
3503
|
+
for (const element of trailingResult.elements)
|
|
3504
|
+
contentElements.push(element);
|
|
2383
3505
|
consumed += trailingResult.consumed;
|
|
2384
3506
|
}
|
|
2385
3507
|
return {
|
|
@@ -2639,7 +3761,7 @@ function sliceLineTokens(ctx, lines) {
|
|
|
2639
3761
|
for (const { start, end } of lines) {
|
|
2640
3762
|
for (let pos = start;pos < end; pos++) {
|
|
2641
3763
|
const token5 = ctx.tokens[pos];
|
|
2642
|
-
if (token5) {
|
|
3764
|
+
if (token5 && token5.type !== "BACKSLASH_BREAK") {
|
|
2643
3765
|
tokens.push(token5);
|
|
2644
3766
|
}
|
|
2645
3767
|
}
|
|
@@ -2809,7 +3931,8 @@ function parseDefinitionItemKey(ctx, startPos) {
|
|
|
2809
3931
|
const inlineCtx = { ...ctx, pos };
|
|
2810
3932
|
const result = parseInlineUntil(inlineCtx, "COLON");
|
|
2811
3933
|
if (result.elements.length > 0) {
|
|
2812
|
-
|
|
3934
|
+
for (const element of result.elements)
|
|
3935
|
+
key.push(element);
|
|
2813
3936
|
for (let i = 0;i < result.consumed; i++) {
|
|
2814
3937
|
const t = ctx.tokens[pos + i];
|
|
2815
3938
|
if (t)
|
|
@@ -2865,7 +3988,8 @@ function parseDefinitionItemValue(ctx, startPos) {
|
|
|
2865
3988
|
const inlineCtx = { ...ctx, pos };
|
|
2866
3989
|
const result = parseInlineUntil(inlineCtx, "NEWLINE");
|
|
2867
3990
|
if (result.elements.length > 0) {
|
|
2868
|
-
|
|
3991
|
+
for (const element of result.elements)
|
|
3992
|
+
value.push(element);
|
|
2869
3993
|
pos += result.consumed;
|
|
2870
3994
|
consumed += result.consumed;
|
|
2871
3995
|
} else {
|
|
@@ -2945,80 +4069,95 @@ var definitionListRule = {
|
|
|
2945
4069
|
consumed: result.consumed
|
|
2946
4070
|
};
|
|
2947
4071
|
}
|
|
2948
|
-
};
|
|
2949
|
-
|
|
2950
|
-
// packages/parser/src/parser/
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
4072
|
+
};
|
|
4073
|
+
|
|
4074
|
+
// packages/parser/src/parser/postprocess/divAdjacentParagraph.ts
|
|
4075
|
+
var unparsedDivStarts = new WeakSet;
|
|
4076
|
+
function markUnparsedDivStart(elements) {
|
|
4077
|
+
const first = elements[0];
|
|
4078
|
+
const text = first?.element === "container" && first.data.type === "paragraph" ? first.data.elements[0] : first;
|
|
4079
|
+
if (text?.element === "text")
|
|
4080
|
+
unparsedDivStarts.add(text);
|
|
4081
|
+
}
|
|
4082
|
+
function isUnparsedDivParagraph(el) {
|
|
4083
|
+
if (!el || el.element !== "container")
|
|
4084
|
+
return false;
|
|
4085
|
+
return el.data.type === "paragraph" && el.data.elements.some((child) => unparsedDivStarts.has(child));
|
|
4086
|
+
}
|
|
4087
|
+
function isDivContainer(el) {
|
|
4088
|
+
if (!el || el.element !== "container")
|
|
4089
|
+
return false;
|
|
4090
|
+
return el.data.type === "div";
|
|
4091
|
+
}
|
|
4092
|
+
function suppressAtLevel(elements) {
|
|
4093
|
+
if (elements.length <= 1)
|
|
4094
|
+
return elements;
|
|
4095
|
+
const unwrap = Array.from({ length: elements.length }, () => false);
|
|
4096
|
+
for (let i = 0;i < elements.length; i++) {
|
|
4097
|
+
if (!isUnparsedDivParagraph(elements[i]))
|
|
4098
|
+
continue;
|
|
4099
|
+
const prevIsDiv = i > 0 && isDivContainer(elements[i - 1]);
|
|
4100
|
+
const nextIsDiv = i < elements.length - 1 && isDivContainer(elements[i + 1]);
|
|
4101
|
+
if (prevIsDiv || nextIsDiv) {
|
|
4102
|
+
unwrap[i] = true;
|
|
4103
|
+
}
|
|
4104
|
+
}
|
|
4105
|
+
const result = [];
|
|
2958
4106
|
for (let i = 0;i < elements.length; i++) {
|
|
2959
|
-
const
|
|
2960
|
-
if (!
|
|
4107
|
+
const el = elements[i];
|
|
4108
|
+
if (!el)
|
|
2961
4109
|
continue;
|
|
2962
|
-
if (
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
if (result.length > 0) {
|
|
2967
|
-
const spanContent = [...result];
|
|
2968
|
-
result.length = 0;
|
|
2969
|
-
result.push({
|
|
2970
|
-
element: "container",
|
|
2971
|
-
data: {
|
|
2972
|
-
type: "span",
|
|
2973
|
-
attributes: {},
|
|
2974
|
-
elements: spanContent
|
|
2975
|
-
}
|
|
2976
|
-
});
|
|
4110
|
+
if (unwrap[i] && el.element === "container") {
|
|
4111
|
+
const inner = el.data.elements;
|
|
4112
|
+
if (i > 0 && isDivContainer(elements[i - 1])) {
|
|
4113
|
+
result.push({ element: "line-break" });
|
|
2977
4114
|
}
|
|
4115
|
+
result.push(...inner);
|
|
2978
4116
|
} else {
|
|
2979
|
-
result
|
|
4117
|
+
result.push(el);
|
|
2980
4118
|
}
|
|
2981
4119
|
}
|
|
2982
|
-
return result
|
|
4120
|
+
return result;
|
|
2983
4121
|
}
|
|
2984
|
-
function
|
|
2985
|
-
return
|
|
4122
|
+
function suppressDivAdjacentParagraphs(elements) {
|
|
4123
|
+
return suppressAtLevel(elements);
|
|
2986
4124
|
}
|
|
2987
4125
|
|
|
2988
|
-
// packages/parser/src/parser/rules/block/
|
|
2989
|
-
function
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
return
|
|
4126
|
+
// packages/parser/src/parser/rules/block/div/close.ts
|
|
4127
|
+
function isDivClose(ctx) {
|
|
4128
|
+
const token5 = ctx.tokens[ctx.pos];
|
|
4129
|
+
if (token5?.type !== "BLOCK_END_OPEN")
|
|
4130
|
+
return false;
|
|
4131
|
+
const closeNameResult = parseBlockName(ctx, ctx.pos + 1);
|
|
4132
|
+
return closeNameResult?.name === "div";
|
|
2995
4133
|
}
|
|
2996
|
-
function
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
break;
|
|
3002
|
-
}
|
|
3003
|
-
elements.pop();
|
|
4134
|
+
function consumeDivClose(ctx, startPos) {
|
|
4135
|
+
let pos = startPos;
|
|
4136
|
+
let consumed = 0;
|
|
4137
|
+
if (ctx.tokens[pos]?.type !== "BLOCK_END_OPEN") {
|
|
4138
|
+
return { pos, consumed };
|
|
3004
4139
|
}
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
} else {
|
|
3012
|
-
break;
|
|
3013
|
-
}
|
|
4140
|
+
pos++;
|
|
4141
|
+
consumed++;
|
|
4142
|
+
const closeNameResult = parseBlockName(ctx, pos);
|
|
4143
|
+
if (closeNameResult) {
|
|
4144
|
+
pos += closeNameResult.consumed;
|
|
4145
|
+
consumed += closeNameResult.consumed;
|
|
3014
4146
|
}
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
while (first < elements.length && elements[first]?.element === "line-break") {
|
|
3019
|
-
first++;
|
|
4147
|
+
if (ctx.tokens[pos]?.type === "BLOCK_CLOSE") {
|
|
4148
|
+
pos++;
|
|
4149
|
+
consumed++;
|
|
3020
4150
|
}
|
|
3021
|
-
|
|
4151
|
+
if (ctx.tokens[pos]?.type === "NEWLINE") {
|
|
4152
|
+
pos++;
|
|
4153
|
+
consumed++;
|
|
4154
|
+
}
|
|
4155
|
+
return { pos, consumed };
|
|
4156
|
+
}
|
|
4157
|
+
|
|
4158
|
+
// packages/parser/src/parser/rules/block/paragraph/content.ts
|
|
4159
|
+
function parseInlineContent(ctx) {
|
|
4160
|
+
return parseInlineUntil(ctx, "PARAGRAPH_BREAK");
|
|
3022
4161
|
}
|
|
3023
4162
|
|
|
3024
4163
|
// packages/parser/src/parser/rules/block/paragraph/index.ts
|
|
@@ -3028,25 +4167,30 @@ var paragraphRule = {
|
|
|
3028
4167
|
requiresLineStart: false,
|
|
3029
4168
|
parse(ctx) {
|
|
3030
4169
|
const result = parseInlineContent(ctx);
|
|
3031
|
-
if (result.
|
|
4170
|
+
if (result.consumed === 0) {
|
|
3032
4171
|
return { success: false };
|
|
3033
4172
|
}
|
|
3034
4173
|
const elements = normalizeParagraphElements(result.elements);
|
|
3035
4174
|
if (elements.length === 0) {
|
|
3036
|
-
return { success:
|
|
4175
|
+
return { success: true, elements: [], consumed: result.consumed };
|
|
3037
4176
|
}
|
|
3038
4177
|
const nextPos = ctx.pos + result.consumed;
|
|
3039
4178
|
const nextToken = ctx.tokens[nextPos];
|
|
3040
4179
|
if (nextToken?.type === "COLON" && nextToken.lineStart) {
|
|
4180
|
+
if (isPreservedLeadingLineBreak(elements[0]))
|
|
4181
|
+
elements[0] = { element: "line-break" };
|
|
3041
4182
|
return {
|
|
3042
4183
|
success: true,
|
|
3043
4184
|
elements: [...elements, { element: "line-break" }],
|
|
3044
4185
|
consumed: result.consumed
|
|
3045
4186
|
};
|
|
3046
4187
|
}
|
|
4188
|
+
const wrapped = wrapParagraphElements(elements);
|
|
4189
|
+
if (isDivClose(ctx))
|
|
4190
|
+
markUnparsedDivStart(wrapped);
|
|
3047
4191
|
return {
|
|
3048
4192
|
success: true,
|
|
3049
|
-
elements:
|
|
4193
|
+
elements: wrapped,
|
|
3050
4194
|
consumed: result.consumed
|
|
3051
4195
|
};
|
|
3052
4196
|
}
|
|
@@ -3057,7 +4201,7 @@ function wrapParagraphElements(elements) {
|
|
|
3057
4201
|
let bare = false;
|
|
3058
4202
|
const flush = (trimBreaks = false) => {
|
|
3059
4203
|
const content = trimBreaks ? normalizeParagraphElements(group) : group;
|
|
3060
|
-
while (content[0]?.element === "line-break")
|
|
4204
|
+
while (content[0]?.element === "line-break" && !isPreservedLeadingLineBreak(content[0]))
|
|
3061
4205
|
content.shift();
|
|
3062
4206
|
while (content.length) {
|
|
3063
4207
|
const last = content.at(-1);
|
|
@@ -3069,6 +4213,8 @@ function wrapParagraphElements(elements) {
|
|
|
3069
4213
|
content.shift();
|
|
3070
4214
|
if (content[0]?.element === "text")
|
|
3071
4215
|
content[0] = { element: "text", data: content[0].data.trimStart() };
|
|
4216
|
+
if (isPreservedLeadingLineBreak(content[0]))
|
|
4217
|
+
content[0] = { element: "line-break" };
|
|
3072
4218
|
if (content.length)
|
|
3073
4219
|
output.push(...bare || content.some((el) => el.element === "image") ? content : [
|
|
3074
4220
|
{
|
|
@@ -3090,37 +4236,36 @@ function wrapParagraphElements(elements) {
|
|
|
3090
4236
|
return output;
|
|
3091
4237
|
}
|
|
3092
4238
|
|
|
3093
|
-
// packages/parser/src/parser/rules/block/
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
4239
|
+
// packages/parser/src/parser/rules/block/note/index.ts
|
|
4240
|
+
var excludedBlockNames = new Set(["note"]);
|
|
4241
|
+
var noteRule = {
|
|
4242
|
+
name: "note",
|
|
4243
|
+
startTokens: ["BLOCK_OPEN"],
|
|
4244
|
+
requiresLineStart: false,
|
|
4245
|
+
parse(ctx) {
|
|
4246
|
+
const bounds = findNoteBounds(ctx);
|
|
4247
|
+
if (!bounds)
|
|
4248
|
+
return { success: false };
|
|
4249
|
+
const body = parseBlocksUntil({
|
|
4250
|
+
...ctx,
|
|
4251
|
+
tokens: ctx.tokens.slice(bounds.bodyStart, bounds.close),
|
|
4252
|
+
pos: 0,
|
|
4253
|
+
scope: {
|
|
4254
|
+
...ctx.scope,
|
|
4255
|
+
inlineEnd: undefined,
|
|
4256
|
+
tableFormatting: undefined,
|
|
4257
|
+
blockCloseCondition: undefined
|
|
4258
|
+
}
|
|
4259
|
+
}, () => false, { excludedBlockNames });
|
|
4260
|
+
return {
|
|
4261
|
+
success: true,
|
|
4262
|
+
consumed: bounds.end - ctx.pos,
|
|
4263
|
+
elements: [
|
|
4264
|
+
{ element: "container", data: { type: "note", attributes: {}, elements: body.elements } }
|
|
4265
|
+
]
|
|
4266
|
+
};
|
|
3121
4267
|
}
|
|
3122
|
-
|
|
3123
|
-
}
|
|
4268
|
+
};
|
|
3124
4269
|
|
|
3125
4270
|
// packages/parser/src/parser/rules/block/div/nesting.ts
|
|
3126
4271
|
var divCloseCountCache = new WeakMap;
|
|
@@ -3289,6 +4434,7 @@ function consumeFailedDiv(ctx) {
|
|
|
3289
4434
|
pos++;
|
|
3290
4435
|
consumed++;
|
|
3291
4436
|
}
|
|
4437
|
+
markUnparsedDivStart(elements);
|
|
3292
4438
|
return {
|
|
3293
4439
|
success: true,
|
|
3294
4440
|
elements: [
|
|
@@ -3331,135 +4477,22 @@ function parseDivOpen(ctx) {
|
|
|
3331
4477
|
pos++;
|
|
3332
4478
|
consumed++;
|
|
3333
4479
|
}
|
|
3334
|
-
return {
|
|
3335
|
-
blockName: nameResult.name,
|
|
3336
|
-
paragraphStrip: nameResult.name === "div_",
|
|
3337
|
-
attributes: attrResult.attrs,
|
|
3338
|
-
bodyStart: pos,
|
|
3339
|
-
consumed,
|
|
3340
|
-
hasRequiredNewline
|
|
3341
|
-
};
|
|
3342
|
-
}
|
|
3343
|
-
function isDivBlockName(name) {
|
|
3344
|
-
return name === "div" || name === "div_";
|
|
3345
|
-
}
|
|
3346
|
-
|
|
3347
|
-
// packages/parser/src/parser/rules/block/div/index.ts
|
|
3348
|
-
var divRule = {
|
|
3349
|
-
name: "div",
|
|
3350
|
-
startTokens: ["BLOCK_OPEN"],
|
|
3351
|
-
requiresLineStart: false,
|
|
3352
|
-
parse(ctx) {
|
|
3353
|
-
const openToken = currentToken(ctx);
|
|
3354
|
-
if (openToken.type !== "BLOCK_OPEN") {
|
|
3355
|
-
return { success: false };
|
|
3356
|
-
}
|
|
3357
|
-
const openResult = parseDivOpen(ctx);
|
|
3358
|
-
if (!openResult) {
|
|
3359
|
-
return { success: false };
|
|
3360
|
-
}
|
|
3361
|
-
if (!openResult.hasRequiredNewline) {
|
|
3362
|
-
return consumeFailedDiv(ctx);
|
|
3363
|
-
}
|
|
3364
|
-
if (ctx.scope.divClosesBudget === 0) {
|
|
3365
|
-
return { success: false };
|
|
3366
|
-
}
|
|
3367
|
-
const openPosition = openToken.position;
|
|
3368
|
-
let pos = openResult.bodyStart;
|
|
3369
|
-
let consumed = openResult.consumed;
|
|
3370
|
-
const bodyResult = parseDivBody(ctx, pos, openResult.paragraphStrip);
|
|
3371
|
-
consumed += bodyResult.consumed;
|
|
3372
|
-
pos += bodyResult.consumed;
|
|
3373
|
-
if (ctx.tokens[pos]?.type !== "BLOCK_END_OPEN") {
|
|
3374
|
-
ctx.diagnostics.push({
|
|
3375
|
-
severity: "warning",
|
|
3376
|
-
code: "unclosed-block",
|
|
3377
|
-
message: `Missing closing tag [[/div]] for [[${openResult.blockName}]]`,
|
|
3378
|
-
position: openPosition
|
|
3379
|
-
});
|
|
3380
|
-
}
|
|
3381
|
-
if (ctx.tokens[pos]?.type === "BLOCK_END_OPEN") {
|
|
3382
|
-
const closeResult = consumeDivClose(ctx, pos);
|
|
3383
|
-
pos = closeResult.pos;
|
|
3384
|
-
consumed += closeResult.consumed;
|
|
3385
|
-
}
|
|
3386
|
-
return {
|
|
3387
|
-
success: true,
|
|
3388
|
-
elements: [
|
|
3389
|
-
{
|
|
3390
|
-
element: "container",
|
|
3391
|
-
data: {
|
|
3392
|
-
type: "div",
|
|
3393
|
-
attributes: openResult.attributes,
|
|
3394
|
-
elements: bodyResult.elements
|
|
3395
|
-
}
|
|
3396
|
-
}
|
|
3397
|
-
],
|
|
3398
|
-
consumed
|
|
3399
|
-
};
|
|
3400
|
-
}
|
|
3401
|
-
};
|
|
3402
|
-
|
|
3403
|
-
// packages/parser/src/parser/rules/block/code/attributes.ts
|
|
3404
|
-
function repairSwallowedCodeClose(ctx, pos, attrs) {
|
|
3405
|
-
const prevToken = ctx.tokens[pos - 1];
|
|
3406
|
-
if (prevToken?.type !== "QUOTED_STRING" || !prevToken.value.includes("]]")) {
|
|
3407
|
-
return null;
|
|
3408
|
-
}
|
|
3409
|
-
const rawValue = prevToken.value;
|
|
3410
|
-
const bracketIdx = rawValue.indexOf("]]");
|
|
3411
|
-
const truncatedValue = rawValue.startsWith('"') ? rawValue.slice(1, bracketIdx) : rawValue.slice(0, bracketIdx);
|
|
3412
|
-
for (const key of Object.keys(attrs)) {
|
|
3413
|
-
const stored = attrs[key];
|
|
3414
|
-
if (stored === rawValue || stored === rawValue.slice(1, -1) || stored === rawValue.slice(1)) {
|
|
3415
|
-
attrs[key] = truncatedValue;
|
|
3416
|
-
break;
|
|
3417
|
-
}
|
|
3418
|
-
}
|
|
3419
|
-
return {
|
|
3420
|
-
closingSwallowed: rawValue.includes("[[/code]]")
|
|
3421
|
-
};
|
|
3422
|
-
}
|
|
3423
|
-
|
|
3424
|
-
// packages/parser/src/parser/rules/block/code/content.ts
|
|
3425
|
-
function collectCodeContent(ctx, startPos, closingSwallowed) {
|
|
3426
|
-
const contentParts = [];
|
|
3427
|
-
let pos = startPos;
|
|
3428
|
-
let consumed = 0;
|
|
3429
|
-
let foundClose = closingSwallowed;
|
|
3430
|
-
while (!closingSwallowed && pos < ctx.tokens.length) {
|
|
3431
|
-
const token5 = ctx.tokens[pos];
|
|
3432
|
-
if (!token5 || token5.type === "EOF") {
|
|
3433
|
-
break;
|
|
3434
|
-
}
|
|
3435
|
-
if (token5.type === "BLOCK_END_OPEN") {
|
|
3436
|
-
const closeNameResult = parseBlockName(ctx, pos + 1);
|
|
3437
|
-
if (closeNameResult?.name === "code") {
|
|
3438
|
-
foundClose = true;
|
|
3439
|
-
const closeConsumed = consumeCodeClose(ctx, pos, closeNameResult.consumed);
|
|
3440
|
-
consumed += closeConsumed;
|
|
3441
|
-
break;
|
|
3442
|
-
}
|
|
3443
|
-
}
|
|
3444
|
-
contentParts.push(token5.value);
|
|
3445
|
-
pos++;
|
|
3446
|
-
consumed++;
|
|
3447
|
-
}
|
|
3448
|
-
return { contents: contentParts.join(""), consumed, foundClose };
|
|
4480
|
+
return {
|
|
4481
|
+
blockName: nameResult.name,
|
|
4482
|
+
paragraphStrip: nameResult.name === "div_",
|
|
4483
|
+
attributes: attrResult.attrs,
|
|
4484
|
+
bodyStart: pos,
|
|
4485
|
+
consumed,
|
|
4486
|
+
hasRequiredNewline
|
|
4487
|
+
};
|
|
3449
4488
|
}
|
|
3450
|
-
function
|
|
3451
|
-
|
|
3452
|
-
let consumed = 1 + closeNameConsumed;
|
|
3453
|
-
if (ctx.tokens[pos]?.type === "BLOCK_CLOSE") {
|
|
3454
|
-
pos++;
|
|
3455
|
-
consumed++;
|
|
3456
|
-
}
|
|
3457
|
-
return consumed;
|
|
4489
|
+
function isDivBlockName(name) {
|
|
4490
|
+
return name === "div" || name === "div_";
|
|
3458
4491
|
}
|
|
3459
4492
|
|
|
3460
|
-
// packages/parser/src/parser/rules/block/
|
|
3461
|
-
var
|
|
3462
|
-
name: "
|
|
4493
|
+
// packages/parser/src/parser/rules/block/div/index.ts
|
|
4494
|
+
var divRule = {
|
|
4495
|
+
name: "div",
|
|
3463
4496
|
startTokens: ["BLOCK_OPEN"],
|
|
3464
4497
|
requiresLineStart: false,
|
|
3465
4498
|
parse(ctx) {
|
|
@@ -3467,56 +4500,49 @@ var codeBlockRule = {
|
|
|
3467
4500
|
if (openToken.type !== "BLOCK_OPEN") {
|
|
3468
4501
|
return { success: false };
|
|
3469
4502
|
}
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
const nameResult = parseBlockName(ctx, pos);
|
|
3473
|
-
if (!nameResult || nameResult.name !== "code") {
|
|
4503
|
+
const openResult = parseDivOpen(ctx);
|
|
4504
|
+
if (!openResult) {
|
|
3474
4505
|
return { success: false };
|
|
3475
4506
|
}
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
const attrResult = parseAttributesRaw(ctx, pos);
|
|
3479
|
-
pos += attrResult.consumed;
|
|
3480
|
-
consumed += attrResult.consumed;
|
|
3481
|
-
let closingSwallowed = false;
|
|
3482
|
-
if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
|
|
3483
|
-
const repaired = repairSwallowedCodeClose(ctx, pos, attrResult.attrs);
|
|
3484
|
-
if (!repaired)
|
|
3485
|
-
return { success: false };
|
|
3486
|
-
closingSwallowed = repaired.closingSwallowed;
|
|
3487
|
-
} else {
|
|
3488
|
-
pos++;
|
|
3489
|
-
consumed++;
|
|
4507
|
+
if (!openResult.hasRequiredNewline) {
|
|
4508
|
+
return consumeFailedDiv(ctx);
|
|
3490
4509
|
}
|
|
3491
|
-
if (ctx.
|
|
3492
|
-
|
|
3493
|
-
consumed++;
|
|
4510
|
+
if (ctx.scope.divClosesBudget === 0) {
|
|
4511
|
+
return { success: false };
|
|
3494
4512
|
}
|
|
3495
|
-
const
|
|
3496
|
-
let
|
|
3497
|
-
consumed
|
|
3498
|
-
pos
|
|
3499
|
-
|
|
4513
|
+
const openPosition = openToken.position;
|
|
4514
|
+
let pos = openResult.bodyStart;
|
|
4515
|
+
let consumed = openResult.consumed;
|
|
4516
|
+
const bodyResult = parseDivBody(ctx, pos, openResult.paragraphStrip);
|
|
4517
|
+
consumed += bodyResult.consumed;
|
|
4518
|
+
pos += bodyResult.consumed;
|
|
4519
|
+
if (ctx.tokens[pos]?.type !== "BLOCK_END_OPEN") {
|
|
3500
4520
|
ctx.diagnostics.push({
|
|
3501
4521
|
severity: "warning",
|
|
3502
4522
|
code: "unclosed-block",
|
|
3503
|
-
message:
|
|
3504
|
-
position:
|
|
4523
|
+
message: `Missing closing tag [[/div]] for [[${openResult.blockName}]]`,
|
|
4524
|
+
position: openPosition
|
|
3505
4525
|
});
|
|
3506
4526
|
}
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
};
|
|
3512
|
-
ctx.codeBlocks.push(codeBlockData);
|
|
3513
|
-
const elements = [{ element: "code", data: codeBlockData }];
|
|
3514
|
-
if (ctx.tokens[pos]?.type === "NEWLINE" && !getParagraphNewlineBoundary(ctx, pos, false).shouldBreak && !ctx.scope.blockCloseCondition?.({ ...ctx, pos: pos + 1 })) {
|
|
3515
|
-
const after = parseInlineUntil({ ...ctx, pos: pos + 1 }, "PARAGRAPH_BREAK");
|
|
3516
|
-
elements.push({ element: "line-break" }, ...normalizeParagraphElements(after.elements));
|
|
3517
|
-
consumed += 1 + after.consumed;
|
|
4527
|
+
if (ctx.tokens[pos]?.type === "BLOCK_END_OPEN") {
|
|
4528
|
+
const closeResult = consumeDivClose(ctx, pos);
|
|
4529
|
+
pos = closeResult.pos;
|
|
4530
|
+
consumed += closeResult.consumed;
|
|
3518
4531
|
}
|
|
3519
|
-
return {
|
|
4532
|
+
return {
|
|
4533
|
+
success: true,
|
|
4534
|
+
elements: [
|
|
4535
|
+
{
|
|
4536
|
+
element: "container",
|
|
4537
|
+
data: {
|
|
4538
|
+
type: "div",
|
|
4539
|
+
attributes: openResult.attributes,
|
|
4540
|
+
elements: bodyResult.elements
|
|
4541
|
+
}
|
|
4542
|
+
}
|
|
4543
|
+
],
|
|
4544
|
+
consumed
|
|
4545
|
+
};
|
|
3520
4546
|
}
|
|
3521
4547
|
};
|
|
3522
4548
|
|
|
@@ -3948,7 +4974,9 @@ function parseTableCell(ctx, startPos, cellStart) {
|
|
|
3948
4974
|
for (const rule of getCandidateInlineRules(inlineRules, token5.type)) {
|
|
3949
4975
|
const result = rule.parse(inlineCtx);
|
|
3950
4976
|
if (result.success) {
|
|
3951
|
-
children
|
|
4977
|
+
stripAutomaticLineBreak(children, result.stripLeadingLineBreak);
|
|
4978
|
+
for (const element of result.elements)
|
|
4979
|
+
children.push(element);
|
|
3952
4980
|
consumed += result.consumed;
|
|
3953
4981
|
pos += result.consumed;
|
|
3954
4982
|
matched = true;
|
|
@@ -4215,7 +5243,8 @@ function createCellContentAccumulator() {
|
|
|
4215
5243
|
addInline(element) {
|
|
4216
5244
|
currentSegment.push(element);
|
|
4217
5245
|
},
|
|
4218
|
-
addInlineElements(nextElements) {
|
|
5246
|
+
addInlineElements(nextElements, stripLeadingLineBreak) {
|
|
5247
|
+
stripAutomaticLineBreak(currentSegment, stripLeadingLineBreak);
|
|
4219
5248
|
currentSegment.push(...nextElements);
|
|
4220
5249
|
},
|
|
4221
5250
|
addBlockElements(blockElements) {
|
|
@@ -4315,7 +5344,7 @@ function consumeCellContentNewline(ctx, startPos, content) {
|
|
|
4315
5344
|
return { consumed };
|
|
4316
5345
|
}
|
|
4317
5346
|
if (!content.isEmpty()) {
|
|
4318
|
-
content.addInline(
|
|
5347
|
+
content.addInline(createAutomaticLineBreak(ctx.tokens[startPos]));
|
|
4319
5348
|
}
|
|
4320
5349
|
return { consumed };
|
|
4321
5350
|
}
|
|
@@ -4366,7 +5395,7 @@ function parseCellContent(ctx, closeCondition) {
|
|
|
4366
5395
|
for (const rule of getCandidateInlineRules(ctx.inlineRules, token5.type)) {
|
|
4367
5396
|
const result = rule.parse(inlineCtx);
|
|
4368
5397
|
if (result.success) {
|
|
4369
|
-
content.addInlineElements(result.elements);
|
|
5398
|
+
content.addInlineElements(result.elements, result.stripLeadingLineBreak);
|
|
4370
5399
|
consumed += result.consumed;
|
|
4371
5400
|
pos += result.consumed;
|
|
4372
5401
|
matched = true;
|
|
@@ -6186,9 +7215,9 @@ function renderListPagesItems(module, data, compiledTemplate, parse) {
|
|
|
6186
7215
|
continue;
|
|
6187
7216
|
const ctx = {
|
|
6188
7217
|
page,
|
|
6189
|
-
index: i + 1,
|
|
7218
|
+
index: (data.pagination?.offset ?? 0) + i + 1,
|
|
6190
7219
|
total: data.totalCount,
|
|
6191
|
-
limit: module.limit,
|
|
7220
|
+
limit: data.pagination ? data.pagination.limit : module.limit,
|
|
6192
7221
|
site: data.site
|
|
6193
7222
|
};
|
|
6194
7223
|
const itemAst = getModuleParseAst(parse(compiledTemplate(ctx)));
|
|
@@ -6208,9 +7237,46 @@ function renderListPagesItems(module, data, compiledTemplate, parse) {
|
|
|
6208
7237
|
return items;
|
|
6209
7238
|
}
|
|
6210
7239
|
|
|
7240
|
+
// packages/parser/src/parser/rules/block/module/listpages/resolution/pager.ts
|
|
7241
|
+
function createListPagesPager(data) {
|
|
7242
|
+
const pagination = data.pagination;
|
|
7243
|
+
if (!pagination || pagination.totalPages <= 1)
|
|
7244
|
+
return [];
|
|
7245
|
+
const { currentPage, totalPages, urlPath, parameter } = pagination;
|
|
7246
|
+
const pages = new Set([1, totalPages]);
|
|
7247
|
+
for (let page = Math.max(1, currentPage - 2);page <= Math.min(totalPages, currentPage + 2); page++) {
|
|
7248
|
+
pages.add(page);
|
|
7249
|
+
}
|
|
7250
|
+
return [
|
|
7251
|
+
{
|
|
7252
|
+
element: "pager",
|
|
7253
|
+
data: {
|
|
7254
|
+
currentPage,
|
|
7255
|
+
totalPages,
|
|
7256
|
+
pages: [...pages].sort((a, b) => a - b).map((page) => ({
|
|
7257
|
+
page,
|
|
7258
|
+
href: pageUrl(urlPath, parameter, page)
|
|
7259
|
+
}))
|
|
7260
|
+
}
|
|
7261
|
+
}
|
|
7262
|
+
];
|
|
7263
|
+
}
|
|
7264
|
+
function pageUrl(urlPath, parameter, page) {
|
|
7265
|
+
const suffixStart = urlPath.search(/[?#]/);
|
|
7266
|
+
const path = suffixStart === -1 ? urlPath : urlPath.slice(0, suffixStart);
|
|
7267
|
+
const suffix = suffixStart === -1 ? "" : urlPath.slice(suffixStart);
|
|
7268
|
+
const parts = path.split("/");
|
|
7269
|
+
const result = parts.slice(0, 2);
|
|
7270
|
+
for (let index = 2;index < parts.length; index += 2) {
|
|
7271
|
+
if (parts[index] !== parameter)
|
|
7272
|
+
result.push(...parts.slice(index, index + 2));
|
|
7273
|
+
}
|
|
7274
|
+
return `${result.join("/").replace(/\/$/, "")}/${parameter}/${page}${suffix}`;
|
|
7275
|
+
}
|
|
7276
|
+
|
|
6211
7277
|
// packages/parser/src/parser/rules/block/module/listpages/resolution/wrapper.ts
|
|
6212
|
-
function wrapListPagesResult(module, items, parse) {
|
|
6213
|
-
if (items.length === 0) {
|
|
7278
|
+
function wrapListPagesResult(module, items, parse, data) {
|
|
7279
|
+
if (items.length === 0 && (!data || data.pages.length === 0)) {
|
|
6214
7280
|
return [];
|
|
6215
7281
|
}
|
|
6216
7282
|
const result = [];
|
|
@@ -6223,6 +7289,8 @@ function wrapListPagesResult(module, items, parse) {
|
|
|
6223
7289
|
const appendAst = getModuleParseAst(parse(module["append-line"]));
|
|
6224
7290
|
result.push(...appendAst.elements);
|
|
6225
7291
|
}
|
|
7292
|
+
if (data)
|
|
7293
|
+
result.push(...createListPagesPager(data));
|
|
6226
7294
|
if (module.wrapper) {
|
|
6227
7295
|
return [
|
|
6228
7296
|
{
|
|
@@ -6244,7 +7312,7 @@ function isListPagesModule2(module) {
|
|
|
6244
7312
|
}
|
|
6245
7313
|
function resolveListPages(module, data, compiledTemplate, parse) {
|
|
6246
7314
|
const items = renderListPagesItems(module, data, compiledTemplate, parse);
|
|
6247
|
-
return wrapListPagesResult(module, items, parse);
|
|
7315
|
+
return wrapListPagesResult(module, items, parse, data);
|
|
6248
7316
|
}
|
|
6249
7317
|
// packages/parser/src/parser/rules/block/module/listpages/types/external-data.ts
|
|
6250
7318
|
function definePageData(input) {
|
|
@@ -6341,10 +7409,10 @@ var URL_RESOLVABLE_FIELDS = [
|
|
|
6341
7409
|
];
|
|
6342
7410
|
|
|
6343
7411
|
// packages/parser/src/parser/rules/block/module/listpages/url-resolution/params.ts
|
|
6344
|
-
function parseUrlParams(url) {
|
|
7412
|
+
function parseUrlParams(url, hasPageName = false) {
|
|
6345
7413
|
const params = new Map;
|
|
6346
|
-
const parts = url.split("/").filter(Boolean);
|
|
6347
|
-
const pairStart = isUrlParameter(parts[0]) ? 0 : 1;
|
|
7414
|
+
const parts = url.split(/[?#]/, 1)[0].split("/").filter(Boolean);
|
|
7415
|
+
const pairStart = !hasPageName && isUrlParameter(parts[0]) ? 0 : 1;
|
|
6348
7416
|
for (let i = pairStart;i < parts.length - 1; i += 2) {
|
|
6349
7417
|
const key = parts[i];
|
|
6350
7418
|
const value = parts[i + 1];
|
|
@@ -6747,7 +7815,7 @@ function resolveIfTags(data, pageTags) {
|
|
|
6747
7815
|
// packages/parser/src/parser/preprocess/utils/raw-regions.ts
|
|
6748
7816
|
var BASE_PLACEHOLDER_OPEN = "";
|
|
6749
7817
|
var BASE_PLACEHOLDER_CLOSE = "";
|
|
6750
|
-
var RAW_BLOCK_OPEN_PATTERN = /\[\[
|
|
7818
|
+
var RAW_BLOCK_OPEN_PATTERN = /\[\[html\b[^\]]*\]\]/iy;
|
|
6751
7819
|
function makeUniqueSentinels(source) {
|
|
6752
7820
|
let openRun = 0;
|
|
6753
7821
|
let closeRun = 0;
|
|
@@ -6766,10 +7834,21 @@ function makeUniqueSentinels(source) {
|
|
|
6766
7834
|
}
|
|
6767
7835
|
function maskRawRegions(source, sentinels) {
|
|
6768
7836
|
const placeholders = [];
|
|
7837
|
+
let tokens;
|
|
7838
|
+
const getTokens = () => tokens ??= tokenize(source);
|
|
6769
7839
|
let masked = "";
|
|
6770
7840
|
let i = 0;
|
|
6771
7841
|
while (i < source.length) {
|
|
6772
|
-
|
|
7842
|
+
if (source.startsWith("[!--", i)) {
|
|
7843
|
+
const close = source.indexOf("--]", i + 4);
|
|
7844
|
+
if (close !== -1) {
|
|
7845
|
+
const end = close + 3;
|
|
7846
|
+
masked += source.slice(i, end);
|
|
7847
|
+
i = end;
|
|
7848
|
+
continue;
|
|
7849
|
+
}
|
|
7850
|
+
}
|
|
7851
|
+
const rawBlock = tryMaskRawBlock(source, i, placeholders, sentinels, getTokens);
|
|
6773
7852
|
if (rawBlock) {
|
|
6774
7853
|
masked += rawBlock.placeholder;
|
|
6775
7854
|
i = rawBlock.end;
|
|
@@ -6790,16 +7869,25 @@ function restorePlaceholders(source, placeholders, sentinels) {
|
|
|
6790
7869
|
const pattern = new RegExp(`${escapeRegex(sentinels.open)}(\\d+)${escapeRegex(sentinels.close)}`, "g");
|
|
6791
7870
|
return source.replace(pattern, (_, idx) => placeholders[Number(idx)] ?? "");
|
|
6792
7871
|
}
|
|
6793
|
-
function tryMaskRawBlock(source, pos, placeholders, sentinels) {
|
|
7872
|
+
function tryMaskRawBlock(source, pos, placeholders, sentinels, getTokens) {
|
|
6794
7873
|
if (source[pos] !== "[" || source[pos + 1] !== "[")
|
|
6795
7874
|
return null;
|
|
7875
|
+
if (source.slice(pos, pos + 6).toLowerCase() === "[[code") {
|
|
7876
|
+
const tokens = getTokens();
|
|
7877
|
+
const start = tokenAtOffset(tokens, pos);
|
|
7878
|
+
const open = findCodeOpen(tokens, start);
|
|
7879
|
+
if (!open)
|
|
7880
|
+
return null;
|
|
7881
|
+
const bounds = open.closingSwallowed ? null : findCodeBodyBounds(tokens, open.bodyStart);
|
|
7882
|
+
const end = open.closingSwallowed ? tokens[open.attributesEnd - 1].position.end.offset : bounds.foundClose ? tokens[bounds.end - 1].position.end.offset : source.length;
|
|
7883
|
+
return { placeholder: pushPlaceholder(placeholders, source.slice(pos, end), sentinels), end };
|
|
7884
|
+
}
|
|
6796
7885
|
RAW_BLOCK_OPEN_PATTERN.lastIndex = pos;
|
|
6797
7886
|
const openMatch = RAW_BLOCK_OPEN_PATTERN.exec(source);
|
|
6798
7887
|
if (!openMatch)
|
|
6799
7888
|
return null;
|
|
6800
|
-
const name = openMatch[1].toLowerCase();
|
|
6801
7889
|
const openLen = openMatch[0].length;
|
|
6802
|
-
const closePattern =
|
|
7890
|
+
const closePattern = /\[\[\/\s*html\s*\]\]/gi;
|
|
6803
7891
|
closePattern.lastIndex = pos + openLen;
|
|
6804
7892
|
const closeMatch = closePattern.exec(source);
|
|
6805
7893
|
if (closeMatch) {
|
|
@@ -6809,12 +7897,19 @@ function tryMaskRawBlock(source, pos, placeholders, sentinels) {
|
|
|
6809
7897
|
end
|
|
6810
7898
|
};
|
|
6811
7899
|
}
|
|
6812
|
-
|
|
6813
|
-
|
|
6814
|
-
|
|
6815
|
-
|
|
6816
|
-
|
|
6817
|
-
|
|
7900
|
+
return null;
|
|
7901
|
+
}
|
|
7902
|
+
function tokenAtOffset(tokens, offset) {
|
|
7903
|
+
let low = 0;
|
|
7904
|
+
let high = tokens.length;
|
|
7905
|
+
while (low < high) {
|
|
7906
|
+
const middle = Math.floor((low + high) / 2);
|
|
7907
|
+
if (tokens[middle].position.start.offset < offset)
|
|
7908
|
+
low = middle + 1;
|
|
7909
|
+
else
|
|
7910
|
+
high = middle;
|
|
7911
|
+
}
|
|
7912
|
+
return tokens[low]?.position.start.offset === offset ? low : tokens.length;
|
|
6818
7913
|
}
|
|
6819
7914
|
function tryMaskRawInline(source, pos, placeholders, sentinels) {
|
|
6820
7915
|
if (source[pos] === "@" && source[pos + 1] === "<") {
|
|
@@ -6826,17 +7921,22 @@ function tryMaskRawInline(source, pos, placeholders, sentinels) {
|
|
|
6826
7921
|
return null;
|
|
6827
7922
|
}
|
|
6828
7923
|
function tryMaskSingleLineRaw(source, pos, openerLength, close, placeholders, sentinels) {
|
|
6829
|
-
const
|
|
6830
|
-
|
|
6831
|
-
`, pos + openerLength);
|
|
6832
|
-
if (closePos === -1 || newline !== -1 && newline < closePos)
|
|
7924
|
+
const end = singleLineRawEnd(source, pos, openerLength, close);
|
|
7925
|
+
if (end === pos)
|
|
6833
7926
|
return null;
|
|
6834
|
-
const end = closePos + close.length;
|
|
6835
7927
|
return {
|
|
6836
7928
|
placeholder: pushPlaceholder(placeholders, source.slice(pos, end), sentinels),
|
|
6837
7929
|
end
|
|
6838
7930
|
};
|
|
6839
7931
|
}
|
|
7932
|
+
function singleLineRawEnd(source, pos, openerLength, close) {
|
|
7933
|
+
const closePos = source.indexOf(close, pos + openerLength);
|
|
7934
|
+
const newline = source.indexOf(`
|
|
7935
|
+
`, pos + openerLength);
|
|
7936
|
+
if (closePos === -1 || newline !== -1 && newline < closePos)
|
|
7937
|
+
return pos;
|
|
7938
|
+
return closePos + close.length;
|
|
7939
|
+
}
|
|
6840
7940
|
function pushPlaceholder(placeholders, text, sentinels) {
|
|
6841
7941
|
const idx = placeholders.length;
|
|
6842
7942
|
placeholders.push(text);
|
|
@@ -7442,18 +8542,66 @@ function resolveListUsers(_module, data, compiledTemplate, parse) {
|
|
|
7442
8542
|
return itemAst.elements;
|
|
7443
8543
|
}
|
|
7444
8544
|
// packages/parser/src/parser/rules/block/module/resolution/data-maps.ts
|
|
7445
|
-
async function buildListPagesDataMap(dataProvider, requirements, urlPath) {
|
|
8545
|
+
async function buildListPagesDataMap(dataProvider, requirements, urlPath, paginationState = { nextUnprefixed: 1 }) {
|
|
7446
8546
|
const dataMap = new Map;
|
|
7447
|
-
const urlParams = parseUrlParams(urlPath ?? "");
|
|
8547
|
+
const urlParams = parseUrlParams(urlPath ?? "", true);
|
|
7448
8548
|
for (const req of requirements) {
|
|
7449
8549
|
const normalizedQuery = resolveAndNormalizeQuery(req, urlParams);
|
|
7450
|
-
|
|
8550
|
+
if (!urlPath || !urlPath.startsWith("/") || urlPath.startsWith("//")) {
|
|
8551
|
+
const data2 = await dataProvider.fetchListPages?.(normalizedQuery, req);
|
|
8552
|
+
if (data2)
|
|
8553
|
+
dataMap.set(req.id, data2);
|
|
8554
|
+
continue;
|
|
8555
|
+
}
|
|
8556
|
+
const ordinal = req.urlAttrPrefix ? 0 : paginationState.nextUnprefixed++;
|
|
8557
|
+
const parameter = req.urlAttrPrefix ? `${encodeURIComponent(req.urlAttrPrefix)}_p` : ordinal === 1 ? "p" : `p${ordinal}`;
|
|
8558
|
+
const perPage = Math.min(250, positiveInteger(normalizedQuery.perPage, 20));
|
|
8559
|
+
const baseOffset = positiveInteger(normalizedQuery.offset, 0);
|
|
8560
|
+
const limit = normalizedQuery.limit !== undefined && normalizedQuery.limit >= 0 ? Math.floor(normalizedQuery.limit) : undefined;
|
|
8561
|
+
const rawPage = urlParams.get(parameter) ?? "1";
|
|
8562
|
+
let currentPage = /^\d+$/.test(rawPage) ? positiveInteger(Number(rawPage), 1) : 1;
|
|
8563
|
+
currentPage = Math.min(currentPage, Math.floor((Number.MAX_SAFE_INTEGER - baseOffset) / perPage) + 1);
|
|
8564
|
+
if (limit !== undefined)
|
|
8565
|
+
currentPage = Math.min(currentPage, Math.max(1, Math.ceil(limit / perPage)));
|
|
8566
|
+
const fetchPage = () => {
|
|
8567
|
+
const relativeOffset = (currentPage - 1) * perPage;
|
|
8568
|
+
return dataProvider.fetchListPages?.({
|
|
8569
|
+
...normalizedQuery,
|
|
8570
|
+
offset: baseOffset + relativeOffset,
|
|
8571
|
+
limit: Math.min(perPage, limit === undefined ? perPage : Math.max(0, limit - relativeOffset)),
|
|
8572
|
+
perPage
|
|
8573
|
+
}, req);
|
|
8574
|
+
};
|
|
8575
|
+
let data = await fetchPage();
|
|
7451
8576
|
if (data) {
|
|
7452
|
-
|
|
8577
|
+
const count = Math.min(Math.max(0, data.totalCount - baseOffset), limit ?? Infinity);
|
|
8578
|
+
const totalPages = Math.ceil(count / perPage);
|
|
8579
|
+
const lastPage = Math.max(1, totalPages);
|
|
8580
|
+
if (currentPage > lastPage) {
|
|
8581
|
+
currentPage = lastPage;
|
|
8582
|
+
data = await fetchPage();
|
|
8583
|
+
}
|
|
8584
|
+
if (data)
|
|
8585
|
+
dataMap.set(req.id, {
|
|
8586
|
+
...data,
|
|
8587
|
+
pages: data.pages.slice(0, Math.min(perPage, Math.max(0, count - (currentPage - 1) * perPage))),
|
|
8588
|
+
pagination: {
|
|
8589
|
+
currentPage,
|
|
8590
|
+
perPage,
|
|
8591
|
+
totalPages,
|
|
8592
|
+
offset: baseOffset + (currentPage - 1) * perPage,
|
|
8593
|
+
limit,
|
|
8594
|
+
urlPath,
|
|
8595
|
+
parameter
|
|
8596
|
+
}
|
|
8597
|
+
});
|
|
7453
8598
|
}
|
|
7454
8599
|
}
|
|
7455
8600
|
return dataMap;
|
|
7456
8601
|
}
|
|
8602
|
+
function positiveInteger(value, fallback) {
|
|
8603
|
+
return value !== undefined && Number.isSafeInteger(value) && value > 0 ? value : fallback;
|
|
8604
|
+
}
|
|
7457
8605
|
async function buildListUsersDataMap(dataProvider, requirements) {
|
|
7458
8606
|
const dataMap = new Map;
|
|
7459
8607
|
for (const req of requirements) {
|
|
@@ -8958,167 +10106,32 @@ function parseVariables(tokens) {
|
|
|
8958
10106
|
for (const token5 of tokens) {
|
|
8959
10107
|
if (token5 === "|") {
|
|
8960
10108
|
assignVariable(vars, current2);
|
|
8961
|
-
current2 = "";
|
|
8962
|
-
} else {
|
|
8963
|
-
current2 += token5;
|
|
8964
|
-
}
|
|
8965
|
-
}
|
|
8966
|
-
assignVariable(vars, current2);
|
|
8967
|
-
return vars;
|
|
8968
|
-
}
|
|
8969
|
-
function assignVariable(vars, source) {
|
|
8970
|
-
if (!source.trim()) {
|
|
8971
|
-
return;
|
|
8972
|
-
}
|
|
8973
|
-
const eqIndex = source.indexOf("=");
|
|
8974
|
-
if (eqIndex === -1) {
|
|
8975
|
-
return;
|
|
8976
|
-
}
|
|
8977
|
-
const key = source.slice(0, eqIndex).trim();
|
|
8978
|
-
if (!key) {
|
|
8979
|
-
return;
|
|
8980
|
-
}
|
|
8981
|
-
vars[key] = source.slice(eqIndex + 1).trim();
|
|
8982
|
-
}
|
|
8983
|
-
|
|
8984
|
-
// packages/parser/src/parser/rules/block/include/index.ts
|
|
8985
|
-
var includeRule = {
|
|
8986
|
-
name: "include",
|
|
8987
|
-
startTokens: ["BLOCK_OPEN"],
|
|
8988
|
-
requiresLineStart: false,
|
|
8989
|
-
parse(ctx) {
|
|
8990
|
-
const openToken = currentToken(ctx);
|
|
8991
|
-
if (openToken.type !== "BLOCK_OPEN") {
|
|
8992
|
-
return { success: false };
|
|
8993
|
-
}
|
|
8994
|
-
let pos = ctx.pos + 1;
|
|
8995
|
-
let consumed = 1;
|
|
8996
|
-
const nameResult = parseBlockName(ctx, pos);
|
|
8997
|
-
if (!nameResult || nameResult.name.toLowerCase() !== "include") {
|
|
8998
|
-
return { success: false };
|
|
8999
|
-
}
|
|
9000
|
-
if (!ctx.settings.enablePageSyntax) {
|
|
9001
|
-
return { success: false };
|
|
9002
|
-
}
|
|
9003
|
-
pos += nameResult.consumed;
|
|
9004
|
-
consumed += nameResult.consumed;
|
|
9005
|
-
while (ctx.tokens[pos]?.type === "WHITESPACE") {
|
|
9006
|
-
pos++;
|
|
9007
|
-
consumed++;
|
|
9008
|
-
}
|
|
9009
|
-
const args = collectIncludeArguments(ctx, pos);
|
|
9010
|
-
pos += args.consumed;
|
|
9011
|
-
consumed += args.consumed;
|
|
9012
|
-
if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
|
|
9013
|
-
return { success: false };
|
|
9014
|
-
}
|
|
9015
|
-
pos++;
|
|
9016
|
-
consumed++;
|
|
9017
|
-
const directiveEnd = pos;
|
|
9018
|
-
if (ctx.tokens[pos]?.type === "NEWLINE") {
|
|
9019
|
-
pos++;
|
|
9020
|
-
consumed++;
|
|
9021
|
-
}
|
|
9022
|
-
if (!args.target) {
|
|
9023
|
-
return { success: false };
|
|
9024
|
-
}
|
|
9025
|
-
const location = parsePageRef(args.target);
|
|
9026
|
-
if (ctx.deferInclude?.(location)) {
|
|
9027
|
-
const source = ctx.tokens.slice(ctx.pos, directiveEnd).map((token5) => token5.value).join("");
|
|
9028
|
-
const elements = [];
|
|
9029
|
-
const lines = source.split(`
|
|
9030
|
-
`);
|
|
9031
|
-
for (let index = 0;index < lines.length; index++) {
|
|
9032
|
-
if (index > 0)
|
|
9033
|
-
elements.push(lineBreak());
|
|
9034
|
-
if (lines[index] !== "")
|
|
9035
|
-
elements.push(text(lines[index]));
|
|
9036
|
-
}
|
|
9037
|
-
return { success: true, elements: [paragraph(elements)], consumed };
|
|
9038
|
-
}
|
|
9039
|
-
return {
|
|
9040
|
-
success: true,
|
|
9041
|
-
elements: [
|
|
9042
|
-
{
|
|
9043
|
-
element: "include",
|
|
9044
|
-
data: {
|
|
9045
|
-
"paragraph-safe": false,
|
|
9046
|
-
variables: parseVariables(args.argumentTokens),
|
|
9047
|
-
location,
|
|
9048
|
-
elements: []
|
|
9049
|
-
}
|
|
9050
|
-
}
|
|
9051
|
-
],
|
|
9052
|
-
consumed
|
|
9053
|
-
};
|
|
9054
|
-
}
|
|
9055
|
-
};
|
|
9056
|
-
|
|
9057
|
-
// packages/parser/src/parser/rules/block/math/content.ts
|
|
9058
|
-
function collectMathContent(ctx, startPos) {
|
|
9059
|
-
let latexSource = "";
|
|
9060
|
-
let pos = startPos;
|
|
9061
|
-
let consumed = 0;
|
|
9062
|
-
let foundClose = false;
|
|
9063
|
-
while (pos < ctx.tokens.length) {
|
|
9064
|
-
const token5 = ctx.tokens[pos];
|
|
9065
|
-
if (!token5)
|
|
9066
|
-
break;
|
|
9067
|
-
if (token5.type === "BLOCK_END_OPEN") {
|
|
9068
|
-
const closeNameResult = parseBlockName(ctx, pos + 1);
|
|
9069
|
-
if (closeNameResult?.name === "math") {
|
|
9070
|
-
foundClose = true;
|
|
9071
|
-
break;
|
|
9072
|
-
}
|
|
9073
|
-
}
|
|
9074
|
-
latexSource += token5.type === "BACKSLASH_BREAK" ? "\\\n" : token5.value;
|
|
9075
|
-
pos++;
|
|
9076
|
-
consumed++;
|
|
9077
|
-
}
|
|
9078
|
-
return { latexSource, consumed, foundClose };
|
|
9079
|
-
}
|
|
9080
|
-
function consumeMathClose(ctx, startPos) {
|
|
9081
|
-
let pos = startPos + 1;
|
|
9082
|
-
let consumed = 1;
|
|
9083
|
-
const closeNameResult = parseBlockName(ctx, pos);
|
|
9084
|
-
if (closeNameResult) {
|
|
9085
|
-
pos += closeNameResult.consumed;
|
|
9086
|
-
consumed += closeNameResult.consumed;
|
|
9087
|
-
}
|
|
9088
|
-
if (ctx.tokens[pos]?.type === "BLOCK_CLOSE") {
|
|
9089
|
-
pos++;
|
|
9090
|
-
consumed++;
|
|
9091
|
-
}
|
|
9092
|
-
if (ctx.tokens[pos]?.type === "NEWLINE") {
|
|
9093
|
-
consumed++;
|
|
10109
|
+
current2 = "";
|
|
10110
|
+
} else {
|
|
10111
|
+
current2 += token5;
|
|
10112
|
+
}
|
|
9094
10113
|
}
|
|
9095
|
-
|
|
10114
|
+
assignVariable(vars, current2);
|
|
10115
|
+
return vars;
|
|
9096
10116
|
}
|
|
9097
|
-
|
|
9098
|
-
|
|
9099
|
-
|
|
9100
|
-
let pos = startPos;
|
|
9101
|
-
let consumed = 0;
|
|
9102
|
-
let name = "";
|
|
9103
|
-
const first = ctx.tokens[pos];
|
|
9104
|
-
if (first?.type !== "IDENTIFIER" && first?.type !== "TEXT") {
|
|
9105
|
-
return { name: null, consumed: 0 };
|
|
10117
|
+
function assignVariable(vars, source) {
|
|
10118
|
+
if (!source.trim()) {
|
|
10119
|
+
return;
|
|
9106
10120
|
}
|
|
9107
|
-
|
|
9108
|
-
|
|
9109
|
-
|
|
9110
|
-
|
|
9111
|
-
|
|
9112
|
-
|
|
9113
|
-
|
|
9114
|
-
consumed++;
|
|
10121
|
+
const eqIndex = source.indexOf("=");
|
|
10122
|
+
if (eqIndex === -1) {
|
|
10123
|
+
return;
|
|
10124
|
+
}
|
|
10125
|
+
const key = source.slice(0, eqIndex).trim();
|
|
10126
|
+
if (!key) {
|
|
10127
|
+
return;
|
|
9115
10128
|
}
|
|
9116
|
-
|
|
10129
|
+
vars[key] = source.slice(eqIndex + 1).trim();
|
|
9117
10130
|
}
|
|
9118
10131
|
|
|
9119
|
-
// packages/parser/src/parser/rules/block/
|
|
9120
|
-
var
|
|
9121
|
-
name: "
|
|
10132
|
+
// packages/parser/src/parser/rules/block/include/index.ts
|
|
10133
|
+
var includeRule = {
|
|
10134
|
+
name: "include",
|
|
9122
10135
|
startTokens: ["BLOCK_OPEN"],
|
|
9123
10136
|
requiresLineStart: false,
|
|
9124
10137
|
parse(ctx) {
|
|
@@ -9129,7 +10142,10 @@ var mathBlockRule = {
|
|
|
9129
10142
|
let pos = ctx.pos + 1;
|
|
9130
10143
|
let consumed = 1;
|
|
9131
10144
|
const nameResult = parseBlockName(ctx, pos);
|
|
9132
|
-
if (!nameResult || nameResult.name !== "
|
|
10145
|
+
if (!nameResult || nameResult.name.toLowerCase() !== "include") {
|
|
10146
|
+
return { success: false };
|
|
10147
|
+
}
|
|
10148
|
+
if (!ctx.settings.enablePageSyntax) {
|
|
9133
10149
|
return { success: false };
|
|
9134
10150
|
}
|
|
9135
10151
|
pos += nameResult.consumed;
|
|
@@ -9138,49 +10154,46 @@ var mathBlockRule = {
|
|
|
9138
10154
|
pos++;
|
|
9139
10155
|
consumed++;
|
|
9140
10156
|
}
|
|
9141
|
-
const
|
|
9142
|
-
pos +=
|
|
9143
|
-
consumed +=
|
|
9144
|
-
while (ctx.tokens[pos]?.type === "WHITESPACE") {
|
|
9145
|
-
pos++;
|
|
9146
|
-
consumed++;
|
|
9147
|
-
}
|
|
10157
|
+
const args = collectIncludeArguments(ctx, pos);
|
|
10158
|
+
pos += args.consumed;
|
|
10159
|
+
consumed += args.consumed;
|
|
9148
10160
|
if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
|
|
9149
10161
|
return { success: false };
|
|
9150
10162
|
}
|
|
9151
10163
|
pos++;
|
|
9152
10164
|
consumed++;
|
|
10165
|
+
const directiveEnd = pos;
|
|
9153
10166
|
if (ctx.tokens[pos]?.type === "NEWLINE") {
|
|
9154
10167
|
pos++;
|
|
9155
10168
|
consumed++;
|
|
9156
10169
|
}
|
|
9157
|
-
|
|
9158
|
-
const latexSource = contentResult.latexSource.trim();
|
|
9159
|
-
consumed += contentResult.consumed;
|
|
9160
|
-
pos += contentResult.consumed;
|
|
9161
|
-
if (!contentResult.foundClose) {
|
|
9162
|
-
ctx.diagnostics.push({
|
|
9163
|
-
severity: "warning",
|
|
9164
|
-
code: "unclosed-block",
|
|
9165
|
-
message: "Missing closing tag [[/math]] for [[math]]",
|
|
9166
|
-
position: openToken.position
|
|
9167
|
-
});
|
|
9168
|
-
} else {
|
|
9169
|
-
const closeConsumed = consumeMathClose(ctx, pos);
|
|
9170
|
-
pos += closeConsumed;
|
|
9171
|
-
consumed += closeConsumed;
|
|
9172
|
-
}
|
|
9173
|
-
if (!latexSource) {
|
|
10170
|
+
if (!args.target) {
|
|
9174
10171
|
return { success: false };
|
|
9175
10172
|
}
|
|
10173
|
+
const location = parsePageRef(args.target);
|
|
10174
|
+
if (ctx.deferInclude?.(location)) {
|
|
10175
|
+
const source = ctx.tokens.slice(ctx.pos, directiveEnd).map((token5) => token5.value).join("");
|
|
10176
|
+
const elements = [];
|
|
10177
|
+
const lines = source.split(`
|
|
10178
|
+
`);
|
|
10179
|
+
for (let index = 0;index < lines.length; index++) {
|
|
10180
|
+
if (index > 0)
|
|
10181
|
+
elements.push(lineBreak());
|
|
10182
|
+
if (lines[index] !== "")
|
|
10183
|
+
elements.push(text(lines[index]));
|
|
10184
|
+
}
|
|
10185
|
+
return { success: true, elements: [paragraph(elements)], consumed };
|
|
10186
|
+
}
|
|
9176
10187
|
return {
|
|
9177
10188
|
success: true,
|
|
9178
10189
|
elements: [
|
|
9179
10190
|
{
|
|
9180
|
-
element: "
|
|
10191
|
+
element: "include",
|
|
9181
10192
|
data: {
|
|
9182
|
-
|
|
9183
|
-
|
|
10193
|
+
"paragraph-safe": false,
|
|
10194
|
+
variables: parseVariables(args.argumentTokens),
|
|
10195
|
+
location,
|
|
10196
|
+
elements: []
|
|
9184
10197
|
}
|
|
9185
10198
|
}
|
|
9186
10199
|
],
|
|
@@ -10050,7 +11063,8 @@ function parseBibliographyContent(ctx, startPos) {
|
|
|
10050
11063
|
const inlineCtx = { ...ctx, pos };
|
|
10051
11064
|
const result = parseInlineUntil(inlineCtx, "NEWLINE");
|
|
10052
11065
|
if (result.elements.length > 0) {
|
|
10053
|
-
|
|
11066
|
+
for (const element of result.elements)
|
|
11067
|
+
content.push(element);
|
|
10054
11068
|
pos += result.consumed;
|
|
10055
11069
|
consumed += result.consumed;
|
|
10056
11070
|
} else {
|
|
@@ -10479,6 +11493,7 @@ var blockRules = [
|
|
|
10479
11493
|
iftagsRule,
|
|
10480
11494
|
bibliographyRule,
|
|
10481
11495
|
galleryRule,
|
|
11496
|
+
noteRule,
|
|
10482
11497
|
divRule
|
|
10483
11498
|
];
|
|
10484
11499
|
// packages/parser/src/parser/rules/inline/formatting/close.ts
|
|
@@ -10491,6 +11506,11 @@ function findFormattingClose(ctx, start, marker) {
|
|
|
10491
11506
|
return null;
|
|
10492
11507
|
if (!table && token5.type === "NEWLINE" && getParagraphNewlineBoundary(ctx, pos, true).shouldBreak)
|
|
10493
11508
|
return null;
|
|
11509
|
+
const inlineRegionEnd = Math.max(emailRegionEnd(ctx.tokens, pos, end), parseButtonSyntax(ctx, pos, end)?.end ?? pos, parseSocialSyntax(ctx, pos, end)?.end ?? pos);
|
|
11510
|
+
if (inlineRegionEnd > pos) {
|
|
11511
|
+
pos = inlineRegionEnd - 1;
|
|
11512
|
+
continue;
|
|
11513
|
+
}
|
|
10494
11514
|
if (token5.type === marker && !table?.suppressedClosers.has(pos))
|
|
10495
11515
|
return pos;
|
|
10496
11516
|
const protectedEnd = protectedInlineRegionEnd(ctx.tokens, pos, end);
|
|
@@ -10536,253 +11556,93 @@ function parseDelimitedContainer(ctx, closeToken, type, options = {}) {
|
|
|
10536
11556
|
consumed
|
|
10537
11557
|
};
|
|
10538
11558
|
}
|
|
10539
|
-
return {
|
|
10540
|
-
success: true,
|
|
10541
|
-
elements: [createInlineContainer(type, result.elements)],
|
|
10542
|
-
consumed
|
|
10543
|
-
};
|
|
10544
|
-
}
|
|
10545
|
-
|
|
10546
|
-
// packages/parser/src/parser/rules/inline/bold.ts
|
|
10547
|
-
var boldRule = {
|
|
10548
|
-
name: "bold",
|
|
10549
|
-
startTokens: ["BOLD_MARKER"],
|
|
10550
|
-
parse(ctx) {
|
|
10551
|
-
return parseDelimitedContainer(ctx, "BOLD_MARKER", "bold", { discardEmpty: true });
|
|
10552
|
-
}
|
|
10553
|
-
};
|
|
10554
|
-
|
|
10555
|
-
// packages/parser/src/parser/rules/inline/italic.ts
|
|
10556
|
-
var italicRule = {
|
|
10557
|
-
name: "italic",
|
|
10558
|
-
startTokens: ["ITALIC_MARKER"],
|
|
10559
|
-
parse(ctx) {
|
|
10560
|
-
return parseDelimitedContainer(ctx, "ITALIC_MARKER", "italics");
|
|
10561
|
-
}
|
|
10562
|
-
};
|
|
10563
|
-
|
|
10564
|
-
// packages/parser/src/parser/rules/inline/underline/index.ts
|
|
10565
|
-
var underlineRule = {
|
|
10566
|
-
name: "underline",
|
|
10567
|
-
startTokens: ["UNDERLINE_MARKER"],
|
|
10568
|
-
parse(ctx) {
|
|
10569
|
-
return parseDelimitedContainer(ctx, "UNDERLINE_MARKER", "underline", { discardEmpty: true });
|
|
10570
|
-
}
|
|
10571
|
-
};
|
|
10572
|
-
|
|
10573
|
-
// packages/parser/src/parser/rules/inline/strikethrough/parse.ts
|
|
10574
|
-
function parseStrikethroughContent(ctx) {
|
|
10575
|
-
return parseDelimitedContainer(ctx, "STRIKE_MARKER", "strikethrough");
|
|
10576
|
-
}
|
|
10577
|
-
|
|
10578
|
-
// packages/parser/src/parser/rules/inline/strikethrough/syntax.ts
|
|
10579
|
-
function hasValidStrikethroughClose(ctx) {
|
|
10580
|
-
const close = findFormattingClose(ctx, ctx.pos + 1, "STRIKE_MARKER");
|
|
10581
|
-
return close !== null && close > ctx.pos + 1 && ctx.tokens[close - 1]?.type !== "WHITESPACE";
|
|
10582
|
-
}
|
|
10583
|
-
|
|
10584
|
-
// packages/parser/src/parser/rules/inline/strikethrough/index.ts
|
|
10585
|
-
var strikethroughRule = {
|
|
10586
|
-
name: "strikethrough",
|
|
10587
|
-
startTokens: ["STRIKE_MARKER"],
|
|
10588
|
-
parse(ctx) {
|
|
10589
|
-
if (!hasValidStrikethroughClose(ctx)) {
|
|
10590
|
-
return {
|
|
10591
|
-
success: true,
|
|
10592
|
-
elements: [{ element: "text", data: "—" }],
|
|
10593
|
-
consumed: 1
|
|
10594
|
-
};
|
|
10595
|
-
}
|
|
10596
|
-
return parseStrikethroughContent(ctx);
|
|
10597
|
-
}
|
|
10598
|
-
};
|
|
10599
|
-
|
|
10600
|
-
// packages/parser/src/parser/rules/inline/superscript.ts
|
|
10601
|
-
var superscriptRule = {
|
|
10602
|
-
name: "superscript",
|
|
10603
|
-
startTokens: ["SUPER_MARKER"],
|
|
10604
|
-
parse(ctx) {
|
|
10605
|
-
return parseDelimitedContainer(ctx, "SUPER_MARKER", "superscript", {
|
|
10606
|
-
discardEmpty: true
|
|
10607
|
-
});
|
|
10608
|
-
}
|
|
10609
|
-
};
|
|
10610
|
-
|
|
10611
|
-
// packages/parser/src/parser/rules/inline/subscript.ts
|
|
10612
|
-
var subscriptRule = {
|
|
10613
|
-
name: "subscript",
|
|
10614
|
-
startTokens: ["SUB_MARKER"],
|
|
10615
|
-
parse(ctx) {
|
|
10616
|
-
return parseDelimitedContainer(ctx, "SUB_MARKER", "subscript", { discardEmpty: true });
|
|
10617
|
-
}
|
|
10618
|
-
};
|
|
10619
|
-
|
|
10620
|
-
// packages/parser/src/parser/rules/inline/monospace.ts
|
|
10621
|
-
var monospaceRule = {
|
|
10622
|
-
name: "monospace",
|
|
10623
|
-
startTokens: ["MONO_MARKER"],
|
|
10624
|
-
parse(ctx) {
|
|
10625
|
-
return parseDelimitedContainer(ctx, "MONO_CLOSE", "monospace");
|
|
10626
|
-
}
|
|
10627
|
-
};
|
|
10628
|
-
|
|
10629
|
-
// packages/parser/src/parser/rules/inline/link-triple/fallback.ts
|
|
10630
|
-
function literalOpenLink(value) {
|
|
10631
|
-
return {
|
|
10632
|
-
success: true,
|
|
10633
|
-
elements: [{ element: "text", data: value }],
|
|
10634
|
-
consumed: 1
|
|
10635
|
-
};
|
|
10636
|
-
}
|
|
10637
|
-
|
|
10638
|
-
// packages/parser/src/parser/rules/inline/link-triple/label.ts
|
|
10639
|
-
function buildTripleLinkLabel(args) {
|
|
10640
|
-
return {
|
|
10641
|
-
text: getTripleLinkDisplayText(args)
|
|
10642
|
-
};
|
|
10643
|
-
}
|
|
10644
|
-
function getTripleLinkDisplayText(args) {
|
|
10645
|
-
const trimmedLabel = args.labelText.trim();
|
|
10646
|
-
if (args.foundPipe) {
|
|
10647
|
-
return trimmedLabel || args.finalTarget;
|
|
10648
|
-
}
|
|
10649
|
-
const colonIdx = args.originalTarget.indexOf(":");
|
|
10650
|
-
if (colonIdx !== -1 && !args.originalTarget.startsWith("http") && !args.originalTarget.startsWith("*")) {
|
|
10651
|
-
return args.originalTarget.slice(colonIdx + 1).trim();
|
|
10652
|
-
}
|
|
10653
|
-
return args.originalTarget;
|
|
10654
|
-
}
|
|
10655
|
-
|
|
10656
|
-
// packages/parser/src/parser/rules/inline/link-triple/syntax.ts
|
|
10657
|
-
function hasClosingLinkMarker(ctx, startPos) {
|
|
10658
|
-
let pos = startPos;
|
|
10659
|
-
while (pos < ctx.tokens.length) {
|
|
10660
|
-
const token5 = ctx.tokens[pos];
|
|
10661
|
-
if (!token5 || token5.type === "EOF") {
|
|
10662
|
-
return false;
|
|
10663
|
-
}
|
|
10664
|
-
if (token5.type === "LINK_CLOSE") {
|
|
10665
|
-
return true;
|
|
10666
|
-
}
|
|
10667
|
-
if (token5.type === "NEWLINE") {
|
|
10668
|
-
const next = ctx.tokens[pos + 1];
|
|
10669
|
-
if (next?.type === "NEWLINE" || next?.type === "LINK_CLOSE") {
|
|
10670
|
-
return false;
|
|
10671
|
-
}
|
|
10672
|
-
}
|
|
10673
|
-
pos++;
|
|
10674
|
-
}
|
|
10675
|
-
return false;
|
|
10676
|
-
}
|
|
10677
|
-
function collectTripleLinkParts(ctx, startPos) {
|
|
10678
|
-
let target = "";
|
|
10679
|
-
let labelText = "";
|
|
10680
|
-
let foundPipe = false;
|
|
10681
|
-
let consumed = 1;
|
|
10682
|
-
let pos = startPos;
|
|
10683
|
-
while (pos < ctx.tokens.length) {
|
|
10684
|
-
const token5 = ctx.tokens[pos];
|
|
10685
|
-
if (!token5 || token5.type === "LINK_CLOSE" || token5.type === "EOF") {
|
|
10686
|
-
break;
|
|
10687
|
-
}
|
|
10688
|
-
if (token5.type === "NEWLINE") {
|
|
10689
|
-
if (foundPipe) {
|
|
10690
|
-
labelText += " ";
|
|
10691
|
-
} else {
|
|
10692
|
-
target += " ";
|
|
10693
|
-
}
|
|
10694
|
-
consumed++;
|
|
10695
|
-
pos++;
|
|
10696
|
-
continue;
|
|
10697
|
-
}
|
|
10698
|
-
if (token5.type === "PIPE" && !foundPipe) {
|
|
10699
|
-
foundPipe = true;
|
|
10700
|
-
} else if (foundPipe) {
|
|
10701
|
-
labelText += token5.value;
|
|
10702
|
-
} else {
|
|
10703
|
-
target += token5.value;
|
|
10704
|
-
}
|
|
10705
|
-
consumed++;
|
|
10706
|
-
pos++;
|
|
10707
|
-
}
|
|
10708
|
-
if (ctx.tokens[pos]?.type === "LINK_CLOSE") {
|
|
10709
|
-
consumed++;
|
|
10710
|
-
}
|
|
10711
|
-
return { target, labelText, foundPipe, consumed };
|
|
11559
|
+
return {
|
|
11560
|
+
success: true,
|
|
11561
|
+
elements: [createInlineContainer(type, result.elements)],
|
|
11562
|
+
consumed
|
|
11563
|
+
};
|
|
10712
11564
|
}
|
|
10713
11565
|
|
|
10714
|
-
// packages/parser/src/parser/rules/inline/
|
|
10715
|
-
var
|
|
10716
|
-
|
|
10717
|
-
|
|
10718
|
-
|
|
10719
|
-
return
|
|
11566
|
+
// packages/parser/src/parser/rules/inline/bold.ts
|
|
11567
|
+
var boldRule = {
|
|
11568
|
+
name: "bold",
|
|
11569
|
+
startTokens: ["BOLD_MARKER"],
|
|
11570
|
+
parse(ctx) {
|
|
11571
|
+
return parseDelimitedContainer(ctx, "BOLD_MARKER", "bold", { discardEmpty: true });
|
|
10720
11572
|
}
|
|
10721
|
-
|
|
10722
|
-
return INTERWIKI_PREFIXES.has(prefix);
|
|
10723
|
-
}
|
|
11573
|
+
};
|
|
10724
11574
|
|
|
10725
|
-
// packages/parser/src/parser/rules/inline/
|
|
10726
|
-
|
|
10727
|
-
|
|
10728
|
-
|
|
11575
|
+
// packages/parser/src/parser/rules/inline/italic.ts
|
|
11576
|
+
var italicRule = {
|
|
11577
|
+
name: "italic",
|
|
11578
|
+
startTokens: ["ITALIC_MARKER"],
|
|
11579
|
+
parse(ctx) {
|
|
11580
|
+
return parseDelimitedContainer(ctx, "ITALIC_MARKER", "italics");
|
|
10729
11581
|
}
|
|
10730
|
-
|
|
11582
|
+
};
|
|
11583
|
+
|
|
11584
|
+
// packages/parser/src/parser/rules/inline/underline/index.ts
|
|
11585
|
+
var underlineRule = {
|
|
11586
|
+
name: "underline",
|
|
11587
|
+
startTokens: ["UNDERLINE_MARKER"],
|
|
11588
|
+
parse(ctx) {
|
|
11589
|
+
return parseDelimitedContainer(ctx, "UNDERLINE_MARKER", "underline", { discardEmpty: true });
|
|
11590
|
+
}
|
|
11591
|
+
};
|
|
11592
|
+
|
|
11593
|
+
// packages/parser/src/parser/rules/inline/strikethrough/parse.ts
|
|
11594
|
+
function parseStrikethroughContent(ctx) {
|
|
11595
|
+
return parseDelimitedContainer(ctx, "STRIKE_MARKER", "strikethrough");
|
|
10731
11596
|
}
|
|
10732
|
-
|
|
10733
|
-
|
|
11597
|
+
|
|
11598
|
+
// packages/parser/src/parser/rules/inline/strikethrough/syntax.ts
|
|
11599
|
+
function hasValidStrikethroughClose(ctx) {
|
|
11600
|
+
const close = findFormattingClose(ctx, ctx.pos + 1, "STRIKE_MARKER");
|
|
11601
|
+
return close !== null && close > ctx.pos + 1 && ctx.tokens[close - 1]?.type !== "WHITESPACE";
|
|
10734
11602
|
}
|
|
10735
|
-
|
|
10736
|
-
|
|
10737
|
-
|
|
11603
|
+
|
|
11604
|
+
// packages/parser/src/parser/rules/inline/strikethrough/index.ts
|
|
11605
|
+
var strikethroughRule = {
|
|
11606
|
+
name: "strikethrough",
|
|
11607
|
+
startTokens: ["STRIKE_MARKER"],
|
|
11608
|
+
parse(ctx) {
|
|
11609
|
+
if (!hasValidStrikethroughClose(ctx)) {
|
|
11610
|
+
return {
|
|
11611
|
+
success: true,
|
|
11612
|
+
elements: [{ element: "text", data: "—" }],
|
|
11613
|
+
consumed: 1
|
|
11614
|
+
};
|
|
11615
|
+
}
|
|
11616
|
+
return parseStrikethroughContent(ctx);
|
|
10738
11617
|
}
|
|
10739
|
-
|
|
10740
|
-
|
|
11618
|
+
};
|
|
11619
|
+
|
|
11620
|
+
// packages/parser/src/parser/rules/inline/superscript.ts
|
|
11621
|
+
var superscriptRule = {
|
|
11622
|
+
name: "superscript",
|
|
11623
|
+
startTokens: ["SUPER_MARKER"],
|
|
11624
|
+
parse(ctx) {
|
|
11625
|
+
return parseDelimitedContainer(ctx, "SUPER_MARKER", "superscript", {
|
|
11626
|
+
discardEmpty: true
|
|
11627
|
+
});
|
|
10741
11628
|
}
|
|
10742
|
-
|
|
10743
|
-
|
|
11629
|
+
};
|
|
11630
|
+
|
|
11631
|
+
// packages/parser/src/parser/rules/inline/subscript.ts
|
|
11632
|
+
var subscriptRule = {
|
|
11633
|
+
name: "subscript",
|
|
11634
|
+
startTokens: ["SUB_MARKER"],
|
|
11635
|
+
parse(ctx) {
|
|
11636
|
+
return parseDelimitedContainer(ctx, "SUB_MARKER", "subscript", { discardEmpty: true });
|
|
10744
11637
|
}
|
|
10745
|
-
|
|
10746
|
-
}
|
|
11638
|
+
};
|
|
10747
11639
|
|
|
10748
|
-
// packages/parser/src/parser/rules/inline/
|
|
10749
|
-
var
|
|
10750
|
-
name: "
|
|
10751
|
-
startTokens: ["
|
|
11640
|
+
// packages/parser/src/parser/rules/inline/monospace.ts
|
|
11641
|
+
var monospaceRule = {
|
|
11642
|
+
name: "monospace",
|
|
11643
|
+
startTokens: ["MONO_MARKER"],
|
|
10752
11644
|
parse(ctx) {
|
|
10753
|
-
|
|
10754
|
-
if (!hasClosingLinkMarker(ctx, ctx.pos + 1)) {
|
|
10755
|
-
return literalOpenLink(startToken.value);
|
|
10756
|
-
}
|
|
10757
|
-
const parts = collectTripleLinkParts(ctx, ctx.pos + 1);
|
|
10758
|
-
const trimmedTarget = parts.target.trim();
|
|
10759
|
-
if (isInvalidTripleLinkTarget(trimmedTarget, parts.foundPipe)) {
|
|
10760
|
-
return literalOpenLink(startToken.value);
|
|
10761
|
-
}
|
|
10762
|
-
const normalized = normalizeTripleLinkTarget(trimmedTarget);
|
|
10763
|
-
const { linkType, link } = determineLinkTypeAndLocation(normalized.target);
|
|
10764
|
-
const label = buildTripleLinkLabel({
|
|
10765
|
-
foundPipe: parts.foundPipe,
|
|
10766
|
-
labelText: parts.labelText,
|
|
10767
|
-
finalTarget: normalized.target,
|
|
10768
|
-
originalTarget: trimmedTarget
|
|
10769
|
-
});
|
|
10770
|
-
return {
|
|
10771
|
-
success: true,
|
|
10772
|
-
elements: [
|
|
10773
|
-
{
|
|
10774
|
-
element: "link",
|
|
10775
|
-
data: {
|
|
10776
|
-
type: linkType,
|
|
10777
|
-
link,
|
|
10778
|
-
extra: null,
|
|
10779
|
-
label,
|
|
10780
|
-
target: normalized.hasStar && linkType === "direct" ? "new-tab" : null
|
|
10781
|
-
}
|
|
10782
|
-
}
|
|
10783
|
-
],
|
|
10784
|
-
consumed: parts.consumed
|
|
10785
|
-
};
|
|
11645
|
+
return parseDelimitedContainer(ctx, "MONO_CLOSE", "monospace");
|
|
10786
11646
|
}
|
|
10787
11647
|
};
|
|
10788
11648
|
|
|
@@ -10793,7 +11653,7 @@ function normalizeAnchor(anchor) {
|
|
|
10793
11653
|
|
|
10794
11654
|
// packages/parser/src/parser/rules/inline/link-bracket/direct-url.ts
|
|
10795
11655
|
function isDirectBracketUrl(url) {
|
|
10796
|
-
return url !== "" && (url.startsWith("/") || url
|
|
11656
|
+
return url !== "" && (url.startsWith("/") || startsWithUrlScheme(url, 0));
|
|
10797
11657
|
}
|
|
10798
11658
|
|
|
10799
11659
|
// packages/parser/src/parser/rules/inline/link-bracket/parts.ts
|
|
@@ -10802,35 +11662,24 @@ function collectBracketLinkParts(ctx, startPos) {
|
|
|
10802
11662
|
return null;
|
|
10803
11663
|
}
|
|
10804
11664
|
let pos = startPos;
|
|
10805
|
-
|
|
10806
|
-
|
|
10807
|
-
while (pos <
|
|
10808
|
-
const token5 = ctx.tokens[pos];
|
|
10809
|
-
if (!token5 || token5.type === "WHITESPACE" || token5.type === "BRACKET_CLOSE" || token5.type === "NEWLINE" || token5.type === "EOF") {
|
|
10810
|
-
break;
|
|
10811
|
-
}
|
|
10812
|
-
first += token5.value;
|
|
10813
|
-
pos++;
|
|
10814
|
-
consumed++;
|
|
10815
|
-
}
|
|
10816
|
-
while (ctx.tokens[pos]?.type === "WHITESPACE") {
|
|
10817
|
-
pos++;
|
|
10818
|
-
consumed++;
|
|
10819
|
-
}
|
|
10820
|
-
let label = "";
|
|
10821
|
-
while (pos < ctx.tokens.length) {
|
|
11665
|
+
const end = Math.min(ctx.scope.inlineEnd ?? ctx.tokens.length, ctx.tokens.length);
|
|
11666
|
+
const values = [];
|
|
11667
|
+
while (pos < end) {
|
|
10822
11668
|
const token5 = ctx.tokens[pos];
|
|
10823
|
-
if (!token5 || token5.type === "BRACKET_CLOSE" || token5.type === "NEWLINE" || token5.type === "EOF")
|
|
11669
|
+
if (!token5 || token5.type === "BRACKET_CLOSE" || token5.type === "NEWLINE" || token5.type === "EOF")
|
|
10824
11670
|
break;
|
|
10825
|
-
|
|
10826
|
-
label += token5.value;
|
|
11671
|
+
values.push(token5.value);
|
|
10827
11672
|
pos++;
|
|
10828
|
-
consumed++;
|
|
10829
11673
|
}
|
|
10830
|
-
if (ctx.tokens[pos]?.type !== "BRACKET_CLOSE")
|
|
11674
|
+
if (pos >= end || ctx.tokens[pos]?.type !== "BRACKET_CLOSE")
|
|
10831
11675
|
return null;
|
|
10832
|
-
|
|
10833
|
-
|
|
11676
|
+
const content = values.join("");
|
|
11677
|
+
const separator = content.search(/[ \t]/);
|
|
11678
|
+
return {
|
|
11679
|
+
first: separator === -1 ? content : content.slice(0, separator),
|
|
11680
|
+
label: separator === -1 ? "" : content.slice(separator).trimStart(),
|
|
11681
|
+
consumed: pos - startPos + 1
|
|
11682
|
+
};
|
|
10834
11683
|
}
|
|
10835
11684
|
|
|
10836
11685
|
// packages/parser/src/parser/rules/inline/link-bracket/prefix.ts
|
|
@@ -10841,6 +11690,14 @@ function parseBracketLinkPrefix(ctx, startPos) {
|
|
|
10841
11690
|
return { target: null, bodyStart: startPos, consumed: 0 };
|
|
10842
11691
|
}
|
|
10843
11692
|
|
|
11693
|
+
// packages/parser/src/parser/rules/inline/link-bracket/special-target.ts
|
|
11694
|
+
function isBracketEmail(target) {
|
|
11695
|
+
return /^[_a-z0-9-]+(?:\.[_a-z0-9-]+)*@[a-z0-9-]+(?:\.[a-z0-9-]+)+$/i.test(target);
|
|
11696
|
+
}
|
|
11697
|
+
function wikipediaPage(target) {
|
|
11698
|
+
return /^wikipedia:((?!:)[A-Za-z0-9_/=&~#.:;+-]+)$/.exec(target)?.[1] ?? null;
|
|
11699
|
+
}
|
|
11700
|
+
|
|
10844
11701
|
// packages/parser/src/parser/rules/inline/link-bracket/parsed.ts
|
|
10845
11702
|
function parseSingleBracketLink(ctx) {
|
|
10846
11703
|
const prefix = parseBracketLinkPrefix(ctx, ctx.pos + 1);
|
|
@@ -10849,17 +11706,20 @@ function parseSingleBracketLink(ctx) {
|
|
|
10849
11706
|
return null;
|
|
10850
11707
|
}
|
|
10851
11708
|
const link = parts.first.trim();
|
|
10852
|
-
|
|
11709
|
+
const email = isBracketEmail(link);
|
|
11710
|
+
const wikiPage = wikipediaPage(link);
|
|
11711
|
+
if (!email && wikiPage === null && !isDirectBracketUrl(link)) {
|
|
10853
11712
|
return null;
|
|
10854
11713
|
}
|
|
10855
|
-
const labelText = parts.label.trim();
|
|
11714
|
+
const labelText = parts.label.trim() || wikiPage;
|
|
10856
11715
|
if (!labelText) {
|
|
10857
11716
|
return null;
|
|
10858
11717
|
}
|
|
10859
11718
|
return {
|
|
10860
|
-
link,
|
|
11719
|
+
link: email ? `mailto:${link}` : link,
|
|
11720
|
+
interwiki: wikiPage !== null,
|
|
10861
11721
|
labelText,
|
|
10862
|
-
target: prefix.target,
|
|
11722
|
+
target: wikiPage !== null ? "new-tab" : prefix.target,
|
|
10863
11723
|
consumed: 1 + prefix.consumed + parts.consumed
|
|
10864
11724
|
};
|
|
10865
11725
|
}
|
|
@@ -10912,7 +11772,7 @@ var linkSingleRule = {
|
|
|
10912
11772
|
{
|
|
10913
11773
|
element: "link",
|
|
10914
11774
|
data: {
|
|
10915
|
-
type: "direct",
|
|
11775
|
+
type: parsed.interwiki ? "interwiki" : "direct",
|
|
10916
11776
|
link: parsed.link,
|
|
10917
11777
|
extra: null,
|
|
10918
11778
|
label: linkLabel,
|
|
@@ -10981,6 +11841,134 @@ var linkStarRule = {
|
|
|
10981
11841
|
}
|
|
10982
11842
|
};
|
|
10983
11843
|
|
|
11844
|
+
// packages/parser/src/parser/rules/inline/autolink.ts
|
|
11845
|
+
var URL_BOUNDARY_TOKENS = new Set([
|
|
11846
|
+
"WHITESPACE",
|
|
11847
|
+
"NEWLINE",
|
|
11848
|
+
"EOF",
|
|
11849
|
+
"BLOCK_OPEN",
|
|
11850
|
+
"BLOCK_END_OPEN",
|
|
11851
|
+
"BLOCK_CLOSE",
|
|
11852
|
+
"LINK_OPEN",
|
|
11853
|
+
"LINK_CLOSE",
|
|
11854
|
+
"COMMENT_OPEN",
|
|
11855
|
+
"BACKSLASH_BREAK"
|
|
11856
|
+
]);
|
|
11857
|
+
var autolinkRule = {
|
|
11858
|
+
name: "autolink",
|
|
11859
|
+
startTokens: ["IDENTIFIER", "STAR", "LIST_BULLET"],
|
|
11860
|
+
parse(ctx) {
|
|
11861
|
+
let pos = ctx.pos;
|
|
11862
|
+
let target = null;
|
|
11863
|
+
const first = ctx.tokens[pos];
|
|
11864
|
+
if (!first) {
|
|
11865
|
+
return { success: false };
|
|
11866
|
+
}
|
|
11867
|
+
if (first.type === "STAR" || first.type === "LIST_BULLET") {
|
|
11868
|
+
if (first.value !== "*") {
|
|
11869
|
+
return { success: false };
|
|
11870
|
+
}
|
|
11871
|
+
target = "new-tab";
|
|
11872
|
+
pos++;
|
|
11873
|
+
}
|
|
11874
|
+
const scheme = ctx.tokens[pos];
|
|
11875
|
+
if (scheme?.type !== "IDENTIFIER" || !URL_SCHEME_NAMES.has(scheme.value)) {
|
|
11876
|
+
return { success: false };
|
|
11877
|
+
}
|
|
11878
|
+
if (ctx.tokens[pos + 1]?.type !== "COLON") {
|
|
11879
|
+
return { success: false };
|
|
11880
|
+
}
|
|
11881
|
+
const prev = ctx.tokens[ctx.pos - 1];
|
|
11882
|
+
if (prev && !first.lineStart) {
|
|
11883
|
+
const lastChar = prev.value[prev.value.length - 1] ?? "";
|
|
11884
|
+
if (/[A-Za-z]/.test(lastChar)) {
|
|
11885
|
+
return { success: false };
|
|
11886
|
+
}
|
|
11887
|
+
}
|
|
11888
|
+
const values = [];
|
|
11889
|
+
let end = pos;
|
|
11890
|
+
const inlineEnd = ctx.scope.inlineEnd ?? ctx.tokens.length;
|
|
11891
|
+
while (end < inlineEnd) {
|
|
11892
|
+
const token5 = ctx.tokens[end];
|
|
11893
|
+
if (!token5 || URL_BOUNDARY_TOKENS.has(token5.type)) {
|
|
11894
|
+
break;
|
|
11895
|
+
}
|
|
11896
|
+
if (token5.type === "RAW_OPEN" || token5.type === "RAW_BLOCK_OPEN") {
|
|
11897
|
+
if (rawRegionEnd(ctx.tokens, end, inlineEnd) > end)
|
|
11898
|
+
break;
|
|
11899
|
+
}
|
|
11900
|
+
values.push(token5.value);
|
|
11901
|
+
end++;
|
|
11902
|
+
if (/[ \t\n\\"']/.test(token5.value))
|
|
11903
|
+
break;
|
|
11904
|
+
}
|
|
11905
|
+
const candidate = values.join("");
|
|
11906
|
+
const match = URL_PATTERN.exec(candidate);
|
|
11907
|
+
if (!match) {
|
|
11908
|
+
return { success: false };
|
|
11909
|
+
}
|
|
11910
|
+
const url = match[0];
|
|
11911
|
+
let length = 0;
|
|
11912
|
+
let count = 0;
|
|
11913
|
+
while (length < url.length) {
|
|
11914
|
+
length += values[count]?.length ?? 0;
|
|
11915
|
+
count++;
|
|
11916
|
+
}
|
|
11917
|
+
const rest = candidate.slice(url.length, length);
|
|
11918
|
+
const elements = [
|
|
11919
|
+
{
|
|
11920
|
+
element: "link",
|
|
11921
|
+
data: {
|
|
11922
|
+
type: "direct",
|
|
11923
|
+
link: url,
|
|
11924
|
+
extra: null,
|
|
11925
|
+
label: { text: url },
|
|
11926
|
+
target
|
|
11927
|
+
}
|
|
11928
|
+
}
|
|
11929
|
+
];
|
|
11930
|
+
if (rest !== "") {
|
|
11931
|
+
elements.push({ element: "text", data: rest });
|
|
11932
|
+
}
|
|
11933
|
+
return {
|
|
11934
|
+
success: true,
|
|
11935
|
+
elements,
|
|
11936
|
+
consumed: pos - ctx.pos + count
|
|
11937
|
+
};
|
|
11938
|
+
}
|
|
11939
|
+
};
|
|
11940
|
+
|
|
11941
|
+
// packages/parser/src/parser/rules/inline/email/index.ts
|
|
11942
|
+
var emailRule = {
|
|
11943
|
+
name: "email",
|
|
11944
|
+
startTokens: EMAIL_START_TOKENS,
|
|
11945
|
+
parse(ctx) {
|
|
11946
|
+
const group = getEmailGroup(ctx.tokens, ctx.pos, ctx.scope.inlineEnd ?? ctx.tokens.length);
|
|
11947
|
+
if (!group)
|
|
11948
|
+
return { success: false };
|
|
11949
|
+
const elements = [];
|
|
11950
|
+
let copied = group.start;
|
|
11951
|
+
for (const candidate of group.candidates) {
|
|
11952
|
+
if (copied < candidate.start)
|
|
11953
|
+
elements.push({ element: "text", data: group.source.slice(copied, candidate.start) });
|
|
11954
|
+
elements.push(ctx.scope.suppressEmailLinks ? { element: "text", data: candidate.address } : {
|
|
11955
|
+
element: "link",
|
|
11956
|
+
data: {
|
|
11957
|
+
type: "direct",
|
|
11958
|
+
link: `mailto:${candidate.address}`,
|
|
11959
|
+
label: { text: candidate.address },
|
|
11960
|
+
target: null,
|
|
11961
|
+
extra: null
|
|
11962
|
+
}
|
|
11963
|
+
});
|
|
11964
|
+
copied = candidate.end;
|
|
11965
|
+
}
|
|
11966
|
+
if (copied < group.end)
|
|
11967
|
+
elements.push({ element: "text", data: group.source.slice(copied, group.end) });
|
|
11968
|
+
return { success: true, elements, consumed: group.endToken - ctx.pos };
|
|
11969
|
+
}
|
|
11970
|
+
};
|
|
11971
|
+
|
|
10984
11972
|
// packages/parser/src/parser/rules/inline/color/syntax.ts
|
|
10985
11973
|
function parseColorContent(ctx) {
|
|
10986
11974
|
const close = findFormattingClose(ctx, ctx.pos + 1, "COLOR_MARKER");
|
|
@@ -11067,7 +12055,7 @@ var newlineLineBreakRule = {
|
|
|
11067
12055
|
}
|
|
11068
12056
|
return {
|
|
11069
12057
|
success: true,
|
|
11070
|
-
elements: [
|
|
12058
|
+
elements: [createAutomaticLineBreak(currentTok)],
|
|
11071
12059
|
consumed: 1
|
|
11072
12060
|
};
|
|
11073
12061
|
}
|
|
@@ -11090,6 +12078,9 @@ function isValidBlockStartAfterNewline(ctx, tokenPos) {
|
|
|
11090
12078
|
if (!isBlockStartToken(token5?.type) || !token5?.lineStart) {
|
|
11091
12079
|
return false;
|
|
11092
12080
|
}
|
|
12081
|
+
if (token5.type === "LIST_BULLET" || token5.type === "LIST_NUMBER") {
|
|
12082
|
+
return ctx.tokens[tokenPos + 1]?.type === "WHITESPACE";
|
|
12083
|
+
}
|
|
11093
12084
|
if (token5.type !== "HEADING_MARKER") {
|
|
11094
12085
|
return true;
|
|
11095
12086
|
}
|
|
@@ -11347,6 +12338,9 @@ var htmlInlineRule = {
|
|
|
11347
12338
|
}
|
|
11348
12339
|
};
|
|
11349
12340
|
|
|
12341
|
+
// packages/parser/src/parser/rules/inline/raw/angle.ts
|
|
12342
|
+
import { decodeHTML } from "entities";
|
|
12343
|
+
|
|
11350
12344
|
// packages/parser/src/parser/rules/inline/raw/result.ts
|
|
11351
12345
|
function rawElement(value, consumed) {
|
|
11352
12346
|
return {
|
|
@@ -11394,7 +12388,7 @@ function parseAngleRaw(ctx) {
|
|
|
11394
12388
|
if (ctx.tokens[pos]?.type === "RAW_BLOCK_CLOSE") {
|
|
11395
12389
|
consumed++;
|
|
11396
12390
|
}
|
|
11397
|
-
return rawElement(value, consumed);
|
|
12391
|
+
return rawElement(decodeHTML(value), consumed);
|
|
11398
12392
|
}
|
|
11399
12393
|
|
|
11400
12394
|
// packages/parser/src/parser/rules/inline/raw/double-at.ts
|
|
@@ -11617,7 +12611,7 @@ function consumeSpanNewline(ctx, pos, paragraphStrip, afterBlankLine, children,
|
|
|
11617
12611
|
return { consumed: consumed2, afterBlankLine: paragraphStrip };
|
|
11618
12612
|
}
|
|
11619
12613
|
const targetChildren = paragraphStrip && afterBlankLine ? escapedChildren : children;
|
|
11620
|
-
targetChildren.push(
|
|
12614
|
+
targetChildren.push(createAutomaticLineBreak(ctx.tokens[pos]));
|
|
11621
12615
|
let consumed = 1;
|
|
11622
12616
|
let nextPos = pos + 1;
|
|
11623
12617
|
while (ctx.tokens[nextPos]?.type === "WHITESPACE" && ctx.tokens[nextPos]?.lineStart) {
|
|
@@ -11705,7 +12699,9 @@ function parseOneSpanChild(ctx, pos, targetChildren) {
|
|
|
11705
12699
|
for (const rule of getCandidateInlineRules(inlineRules, token5.type)) {
|
|
11706
12700
|
const result = rule.parse(inlineCtx);
|
|
11707
12701
|
if (result.success) {
|
|
11708
|
-
targetChildren
|
|
12702
|
+
stripAutomaticLineBreak(targetChildren, result.stripLeadingLineBreak);
|
|
12703
|
+
for (const element of result.elements)
|
|
12704
|
+
targetChildren.push(element);
|
|
11709
12705
|
return { consumed: result.consumed };
|
|
11710
12706
|
}
|
|
11711
12707
|
}
|
|
@@ -11773,6 +12769,48 @@ var closeSpanRule = {
|
|
|
11773
12769
|
}
|
|
11774
12770
|
};
|
|
11775
12771
|
|
|
12772
|
+
// packages/parser/src/parser/rules/inline/button/index.ts
|
|
12773
|
+
var buttonRule = {
|
|
12774
|
+
name: "button",
|
|
12775
|
+
startTokens: ["BLOCK_OPEN"],
|
|
12776
|
+
parse(ctx) {
|
|
12777
|
+
const result = parseButtonSyntax(ctx, ctx.pos, ctx.scope.inlineEnd ?? ctx.tokens.length);
|
|
12778
|
+
return result ? {
|
|
12779
|
+
success: true,
|
|
12780
|
+
consumed: result.end - ctx.pos,
|
|
12781
|
+
elements: [{ element: "button", data: result.data }]
|
|
12782
|
+
} : { success: false };
|
|
12783
|
+
}
|
|
12784
|
+
};
|
|
12785
|
+
|
|
12786
|
+
// packages/parser/src/parser/rules/inline/social/index.ts
|
|
12787
|
+
var socialRule = {
|
|
12788
|
+
name: "social",
|
|
12789
|
+
startTokens: ["BLOCK_OPEN"],
|
|
12790
|
+
parse(ctx) {
|
|
12791
|
+
const result = parseSocialSyntax(ctx, ctx.pos, ctx.scope.inlineEnd ?? ctx.tokens.length);
|
|
12792
|
+
return result ? {
|
|
12793
|
+
success: true,
|
|
12794
|
+
consumed: result.end - ctx.pos,
|
|
12795
|
+
elements: [{ element: "social", data: result.data }]
|
|
12796
|
+
} : { success: false };
|
|
12797
|
+
}
|
|
12798
|
+
};
|
|
12799
|
+
|
|
12800
|
+
// packages/parser/src/parser/rules/inline/date/index.ts
|
|
12801
|
+
var dateRule = {
|
|
12802
|
+
name: "date",
|
|
12803
|
+
startTokens: ["BLOCK_OPEN"],
|
|
12804
|
+
parse(ctx) {
|
|
12805
|
+
const parsed = parseDateSyntax(ctx, ctx.pos, ctx.scope.inlineEnd ?? ctx.tokens.length);
|
|
12806
|
+
return parsed ? {
|
|
12807
|
+
success: true,
|
|
12808
|
+
consumed: parsed.end - ctx.pos,
|
|
12809
|
+
elements: [{ element: "date", data: parsed.data }]
|
|
12810
|
+
} : { success: false };
|
|
12811
|
+
}
|
|
12812
|
+
};
|
|
12813
|
+
|
|
11776
12814
|
// packages/parser/src/parser/rules/inline/size/content.ts
|
|
11777
12815
|
function parseSizeContent(ctx, startPos) {
|
|
11778
12816
|
const children = [];
|
|
@@ -11794,7 +12832,8 @@ function parseSizeContent(ctx, startPos) {
|
|
|
11794
12832
|
const inlineCtx = { ...ctx, pos };
|
|
11795
12833
|
const inlineResult = parseInlineUntil(inlineCtx, "BLOCK_END_OPEN");
|
|
11796
12834
|
if (inlineResult.elements.length > 0) {
|
|
11797
|
-
|
|
12835
|
+
for (const element of inlineResult.elements)
|
|
12836
|
+
children.push(element);
|
|
11798
12837
|
pos += inlineResult.consumed;
|
|
11799
12838
|
consumed += inlineResult.consumed;
|
|
11800
12839
|
} else {
|
|
@@ -11823,6 +12862,16 @@ function tryConsumeSizeClose(ctx, pos) {
|
|
|
11823
12862
|
|
|
11824
12863
|
// packages/parser/src/parser/rules/inline/size/value.ts
|
|
11825
12864
|
var VALID_SIZE_UNITS = ["px", "em", "rem", "ex", "%", "cm", "mm", "in", "pc"];
|
|
12865
|
+
var VALID_SIZE_KEYWORDS = [
|
|
12866
|
+
"smaller",
|
|
12867
|
+
"larger",
|
|
12868
|
+
"xx-small",
|
|
12869
|
+
"x-small",
|
|
12870
|
+
"small",
|
|
12871
|
+
"large",
|
|
12872
|
+
"x-large",
|
|
12873
|
+
"xx-large"
|
|
12874
|
+
];
|
|
11826
12875
|
function parseSizeValue(ctx, startPos) {
|
|
11827
12876
|
let pos = startPos;
|
|
11828
12877
|
let consumed = 0;
|
|
@@ -11847,6 +12896,8 @@ function parseSizeValue(ctx, startPos) {
|
|
|
11847
12896
|
return isValidSizeValue(size) ? { size, consumed } : null;
|
|
11848
12897
|
}
|
|
11849
12898
|
function isValidSizeValue(size) {
|
|
12899
|
+
if (VALID_SIZE_KEYWORDS.includes(size))
|
|
12900
|
+
return true;
|
|
11850
12901
|
const unitPattern = VALID_SIZE_UNITS.join("|");
|
|
11851
12902
|
return new RegExp(`^(\\d+(?:\\.\\d+)?)(${unitPattern})$`, "i").test(size);
|
|
11852
12903
|
}
|
|
@@ -11918,19 +12969,6 @@ var sizeRule = {
|
|
|
11918
12969
|
}
|
|
11919
12970
|
};
|
|
11920
12971
|
|
|
11921
|
-
// packages/parser/src/parser/rules/inline/footnote/child.ts
|
|
11922
|
-
function parseFootnoteChild(ctx, pos) {
|
|
11923
|
-
const token5 = ctx.tokens[pos];
|
|
11924
|
-
if (!token5) {
|
|
11925
|
-
return { elements: [], consumed: 0 };
|
|
11926
|
-
}
|
|
11927
|
-
const inlineResult = parseInlineUntil({ ...ctx, pos }, "BLOCK_END_OPEN");
|
|
11928
|
-
if (inlineResult.elements.length > 0) {
|
|
11929
|
-
return { elements: inlineResult.elements, consumed: inlineResult.consumed };
|
|
11930
|
-
}
|
|
11931
|
-
return { elements: [{ element: "text", data: token5.value }], consumed: 1 };
|
|
11932
|
-
}
|
|
11933
|
-
|
|
11934
12972
|
// packages/parser/src/parser/rules/inline/footnote/close.ts
|
|
11935
12973
|
function tryConsumeFootnoteClose(ctx, pos) {
|
|
11936
12974
|
if (ctx.tokens[pos]?.type !== "BLOCK_END_OPEN") {
|
|
@@ -11952,96 +12990,73 @@ function tryConsumeFootnoteClose(ctx, pos) {
|
|
|
11952
12990
|
return { consumed };
|
|
11953
12991
|
}
|
|
11954
12992
|
|
|
11955
|
-
// packages/parser/src/parser/rules/inline/
|
|
11956
|
-
function
|
|
11957
|
-
let
|
|
11958
|
-
let consumed =
|
|
11959
|
-
|
|
11960
|
-
|
|
11961
|
-
consumed++;
|
|
11962
|
-
}
|
|
11963
|
-
if (ctx.tokens[nextPos]?.type !== "NEWLINE") {
|
|
11964
|
-
return { consumed, paragraphBreak: false };
|
|
12993
|
+
// packages/parser/src/parser/rules/inline/math-inline/syntax.ts
|
|
12994
|
+
function parseInlineMathSource(ctx, startPos) {
|
|
12995
|
+
let pos = startPos;
|
|
12996
|
+
let consumed = 0;
|
|
12997
|
+
if (ctx.tokens[pos]?.type !== "TEXT" || ctx.tokens[pos]?.value !== "$") {
|
|
12998
|
+
return null;
|
|
11965
12999
|
}
|
|
11966
|
-
|
|
11967
|
-
|
|
13000
|
+
pos++;
|
|
13001
|
+
consumed++;
|
|
13002
|
+
while (ctx.tokens[pos]?.type === "WHITESPACE") {
|
|
13003
|
+
pos++;
|
|
11968
13004
|
consumed++;
|
|
11969
13005
|
}
|
|
11970
|
-
|
|
11971
|
-
}
|
|
11972
|
-
|
|
11973
|
-
// packages/parser/src/parser/rules/inline/footnote/content.ts
|
|
11974
|
-
function parseFootnoteContent(ctx, startPos) {
|
|
11975
|
-
const paragraphs = [[]];
|
|
11976
|
-
let currentParagraph = 0;
|
|
11977
|
-
let pos = startPos;
|
|
11978
|
-
let consumed = 0;
|
|
13006
|
+
let latexSource = "";
|
|
11979
13007
|
while (pos < ctx.tokens.length) {
|
|
11980
13008
|
const token5 = ctx.tokens[pos];
|
|
11981
|
-
if (!token5 || token5.type === "
|
|
11982
|
-
|
|
11983
|
-
}
|
|
11984
|
-
const closeResult = tryConsumeFootnoteClose(ctx, pos);
|
|
11985
|
-
if (closeResult) {
|
|
11986
|
-
return {
|
|
11987
|
-
paragraphs,
|
|
11988
|
-
consumed: consumed + closeResult.consumed,
|
|
11989
|
-
foundClose: true
|
|
11990
|
-
};
|
|
13009
|
+
if (!token5 || token5.type === "NEWLINE") {
|
|
13010
|
+
return null;
|
|
11991
13011
|
}
|
|
11992
|
-
if (token5.type === "
|
|
11993
|
-
|
|
11994
|
-
pos += newlineResult.consumed;
|
|
11995
|
-
consumed += newlineResult.consumed;
|
|
11996
|
-
if (newlineResult.paragraphBreak) {
|
|
11997
|
-
currentParagraph++;
|
|
11998
|
-
paragraphs[currentParagraph] = [];
|
|
11999
|
-
} else {
|
|
12000
|
-
paragraphs[currentParagraph].push({ element: "line-break" });
|
|
12001
|
-
}
|
|
12002
|
-
continue;
|
|
13012
|
+
if (token5.type === "TEXT" && token5.value === "$" && ctx.tokens[pos + 1]?.type === "BLOCK_CLOSE") {
|
|
13013
|
+
break;
|
|
12003
13014
|
}
|
|
12004
|
-
|
|
12005
|
-
|
|
12006
|
-
|
|
12007
|
-
|
|
13015
|
+
latexSource += token5.value;
|
|
13016
|
+
pos++;
|
|
13017
|
+
consumed++;
|
|
13018
|
+
}
|
|
13019
|
+
if (ctx.tokens[pos]?.type !== "TEXT" || ctx.tokens[pos]?.value !== "$") {
|
|
13020
|
+
return null;
|
|
13021
|
+
}
|
|
13022
|
+
pos++;
|
|
13023
|
+
consumed++;
|
|
13024
|
+
if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
|
|
13025
|
+
return null;
|
|
12008
13026
|
}
|
|
12009
|
-
return {
|
|
13027
|
+
return {
|
|
13028
|
+
latexSource: latexSource.trim(),
|
|
13029
|
+
consumed: consumed + 1
|
|
13030
|
+
};
|
|
12010
13031
|
}
|
|
12011
13032
|
|
|
12012
|
-
// packages/parser/src/parser/rules/inline/
|
|
12013
|
-
|
|
12014
|
-
|
|
12015
|
-
|
|
12016
|
-
|
|
12017
|
-
|
|
12018
|
-
|
|
13033
|
+
// packages/parser/src/parser/rules/inline/math-inline/index.ts
|
|
13034
|
+
var mathInlineRule = {
|
|
13035
|
+
name: "math-inline",
|
|
13036
|
+
startTokens: ["BLOCK_OPEN"],
|
|
13037
|
+
parse(ctx) {
|
|
13038
|
+
const openToken = currentToken(ctx);
|
|
13039
|
+
if (openToken.type !== "BLOCK_OPEN") {
|
|
13040
|
+
return { success: false };
|
|
12019
13041
|
}
|
|
12020
|
-
|
|
12021
|
-
|
|
12022
|
-
|
|
12023
|
-
children.push({
|
|
12024
|
-
element: "container",
|
|
12025
|
-
data: {
|
|
12026
|
-
type: "paragraph",
|
|
12027
|
-
attributes: {},
|
|
12028
|
-
elements: para
|
|
12029
|
-
}
|
|
12030
|
-
});
|
|
13042
|
+
const parsed = parseInlineMathSource(ctx, ctx.pos + 1);
|
|
13043
|
+
if (!parsed) {
|
|
13044
|
+
return { success: false };
|
|
12031
13045
|
}
|
|
13046
|
+
return {
|
|
13047
|
+
success: true,
|
|
13048
|
+
elements: [
|
|
13049
|
+
{
|
|
13050
|
+
element: "math-inline",
|
|
13051
|
+
data: {
|
|
13052
|
+
"latex-source": parsed.latexSource
|
|
13053
|
+
}
|
|
13054
|
+
}
|
|
13055
|
+
],
|
|
13056
|
+
consumed: 1 + parsed.consumed
|
|
13057
|
+
};
|
|
12032
13058
|
}
|
|
12033
|
-
|
|
12034
|
-
}
|
|
12035
|
-
function trimLineBreaks(elements) {
|
|
12036
|
-
const result = [...elements];
|
|
12037
|
-
while (result.length > 0 && result[0]?.element === "line-break") {
|
|
12038
|
-
result.shift();
|
|
12039
|
-
}
|
|
12040
|
-
while (result.length > 0 && result[result.length - 1]?.element === "line-break") {
|
|
12041
|
-
result.pop();
|
|
12042
|
-
}
|
|
12043
|
-
return result;
|
|
12044
|
-
}
|
|
13059
|
+
};
|
|
12045
13060
|
|
|
12046
13061
|
// packages/parser/src/parser/rules/inline/footnote/open.ts
|
|
12047
13062
|
function parseFootnoteOpen(ctx) {
|
|
@@ -12068,6 +13083,91 @@ function parseFootnoteOpen(ctx) {
|
|
|
12068
13083
|
return { bodyStart: pos, consumed };
|
|
12069
13084
|
}
|
|
12070
13085
|
|
|
13086
|
+
// packages/parser/src/parser/rules/inline/footnote/boundary.ts
|
|
13087
|
+
var opaqueRules2 = [
|
|
13088
|
+
codeBlockRule,
|
|
13089
|
+
htmlBlockRule,
|
|
13090
|
+
mathBlockRule,
|
|
13091
|
+
mathInlineRule,
|
|
13092
|
+
linkTripleRule,
|
|
13093
|
+
linkSingleRule,
|
|
13094
|
+
linkStarRule,
|
|
13095
|
+
linkAnchorRule
|
|
13096
|
+
];
|
|
13097
|
+
function findFootnoteEnd(ctx, start) {
|
|
13098
|
+
const probe = createOpaqueProbe(ctx);
|
|
13099
|
+
let depth = 0;
|
|
13100
|
+
for (let pos = start;pos < ctx.tokens.length; pos++) {
|
|
13101
|
+
if (ctx.tokens[pos]?.type === "EOF")
|
|
13102
|
+
return pos;
|
|
13103
|
+
const protectedEnd = protectedInlineRegionEnd(ctx.tokens, pos, ctx.tokens.length);
|
|
13104
|
+
if (protectedEnd > pos) {
|
|
13105
|
+
pos = protectedEnd - 1;
|
|
13106
|
+
continue;
|
|
13107
|
+
}
|
|
13108
|
+
probe.pos = pos;
|
|
13109
|
+
const close = tryConsumeFootnoteClose(probe, pos);
|
|
13110
|
+
if (close) {
|
|
13111
|
+
if (depth === 0)
|
|
13112
|
+
return pos;
|
|
13113
|
+
depth--;
|
|
13114
|
+
pos += close.consumed - 1;
|
|
13115
|
+
continue;
|
|
13116
|
+
}
|
|
13117
|
+
const open = parseFootnoteOpen(probe);
|
|
13118
|
+
if (open) {
|
|
13119
|
+
depth++;
|
|
13120
|
+
pos += open.consumed - 1;
|
|
13121
|
+
continue;
|
|
13122
|
+
}
|
|
13123
|
+
const opaqueEnd = opaqueRuleEnd(probe, pos, opaqueRules2);
|
|
13124
|
+
if (opaqueEnd > pos)
|
|
13125
|
+
pos = opaqueEnd - 1;
|
|
13126
|
+
}
|
|
13127
|
+
return ctx.tokens.length;
|
|
13128
|
+
}
|
|
13129
|
+
|
|
13130
|
+
// packages/parser/src/parser/rules/inline/footnote/content.ts
|
|
13131
|
+
function parseFootnoteContent(ctx, startPos) {
|
|
13132
|
+
const end = findFootnoteEnd(ctx, startPos);
|
|
13133
|
+
let leadingNewlines = 0;
|
|
13134
|
+
for (let pos = startPos;pos < end; pos++) {
|
|
13135
|
+
const type = ctx.tokens[pos]?.type;
|
|
13136
|
+
if (type === "NEWLINE")
|
|
13137
|
+
leadingNewlines++;
|
|
13138
|
+
else if (type !== "WHITESPACE")
|
|
13139
|
+
break;
|
|
13140
|
+
}
|
|
13141
|
+
const bodyCtx = {
|
|
13142
|
+
...ctx,
|
|
13143
|
+
tokens: ctx.tokens.slice(startPos, end),
|
|
13144
|
+
pos: 0,
|
|
13145
|
+
scope: {
|
|
13146
|
+
...ctx.scope,
|
|
13147
|
+
inlineEnd: undefined,
|
|
13148
|
+
tableFormatting: undefined,
|
|
13149
|
+
blockCloseCondition: undefined
|
|
13150
|
+
}
|
|
13151
|
+
};
|
|
13152
|
+
const result = parseBlocksUntil(bodyCtx, () => false);
|
|
13153
|
+
const close = tryConsumeFootnoteClose(ctx, end);
|
|
13154
|
+
return {
|
|
13155
|
+
elements: result.elements,
|
|
13156
|
+
consumed: end - startPos + (close?.consumed ?? 0),
|
|
13157
|
+
foundClose: close !== null,
|
|
13158
|
+
leadingParagraphBreak: leadingNewlines >= 2
|
|
13159
|
+
};
|
|
13160
|
+
}
|
|
13161
|
+
|
|
13162
|
+
// packages/parser/src/parser/rules/inline/footnote/elements.ts
|
|
13163
|
+
function buildFootnoteChildren(elements, leadingParagraphBreak) {
|
|
13164
|
+
const first = elements[0];
|
|
13165
|
+
if (!leadingParagraphBreak && first?.element === "container" && first.data.type === "paragraph") {
|
|
13166
|
+
return [...first.data.elements, ...elements.slice(1)];
|
|
13167
|
+
}
|
|
13168
|
+
return elements;
|
|
13169
|
+
}
|
|
13170
|
+
|
|
12071
13171
|
// packages/parser/src/parser/rules/inline/footnote/index.ts
|
|
12072
13172
|
var footnoteRule = {
|
|
12073
13173
|
name: "footnote",
|
|
@@ -12083,7 +13183,7 @@ var footnoteRule = {
|
|
|
12083
13183
|
}
|
|
12084
13184
|
const contentResult = parseFootnoteContent(ctx, openResult.bodyStart);
|
|
12085
13185
|
const consumed = openResult.consumed + contentResult.consumed;
|
|
12086
|
-
const children = buildFootnoteChildren(contentResult.
|
|
13186
|
+
const children = buildFootnoteChildren(contentResult.elements, contentResult.leadingParagraphBreak);
|
|
12087
13187
|
if (!contentResult.foundClose) {
|
|
12088
13188
|
ctx.diagnostics.push({
|
|
12089
13189
|
severity: "warning",
|
|
@@ -12443,11 +13543,15 @@ function parseAnchorChild(ctx, pos) {
|
|
|
12443
13543
|
if (!token5) {
|
|
12444
13544
|
return { elements: [], consumed: 0 };
|
|
12445
13545
|
}
|
|
12446
|
-
const inlineCtx = {
|
|
13546
|
+
const inlineCtx = {
|
|
13547
|
+
...ctx,
|
|
13548
|
+
pos,
|
|
13549
|
+
scope: { ...ctx.scope, suppressEmailLinks: true }
|
|
13550
|
+
};
|
|
12447
13551
|
for (const rule of getCandidateInlineRules(inlineRules, token5.type)) {
|
|
12448
13552
|
const result = rule.parse(inlineCtx);
|
|
12449
13553
|
if (result.success) {
|
|
12450
|
-
return
|
|
13554
|
+
return result;
|
|
12451
13555
|
}
|
|
12452
13556
|
}
|
|
12453
13557
|
return { elements: [{ element: "text", data: token5.value }], consumed: 1 };
|
|
@@ -12507,7 +13611,7 @@ function consumeAnchorNewline(ctx, pos, paragraphStrip, children) {
|
|
|
12507
13611
|
let consumed = 1;
|
|
12508
13612
|
let nextPos = pos + 1;
|
|
12509
13613
|
if (!paragraphStrip) {
|
|
12510
|
-
children.push(
|
|
13614
|
+
children.push(createAutomaticLineBreak(ctx.tokens[pos]));
|
|
12511
13615
|
while (ctx.tokens[nextPos]?.type === "WHITESPACE" && ctx.tokens[nextPos]?.lineStart) {
|
|
12512
13616
|
nextPos++;
|
|
12513
13617
|
consumed++;
|
|
@@ -12560,7 +13664,9 @@ function parseAnchorContent(ctx, startPos, paragraphStrip) {
|
|
|
12560
13664
|
continue;
|
|
12561
13665
|
}
|
|
12562
13666
|
const child = parseAnchorChild(ctx, pos);
|
|
12563
|
-
children
|
|
13667
|
+
stripAutomaticLineBreak(children, child.stripLeadingLineBreak);
|
|
13668
|
+
for (const element of child.elements)
|
|
13669
|
+
children.push(element);
|
|
12564
13670
|
pos += child.consumed;
|
|
12565
13671
|
consumed += child.consumed;
|
|
12566
13672
|
}
|
|
@@ -12634,75 +13740,8 @@ var anchorRule = {
|
|
|
12634
13740
|
}
|
|
12635
13741
|
}
|
|
12636
13742
|
],
|
|
12637
|
-
consumed
|
|
12638
|
-
|
|
12639
|
-
}
|
|
12640
|
-
};
|
|
12641
|
-
|
|
12642
|
-
// packages/parser/src/parser/rules/inline/math-inline/syntax.ts
|
|
12643
|
-
function parseInlineMathSource(ctx, startPos) {
|
|
12644
|
-
let pos = startPos;
|
|
12645
|
-
let consumed = 0;
|
|
12646
|
-
if (ctx.tokens[pos]?.type !== "TEXT" || ctx.tokens[pos]?.value !== "$") {
|
|
12647
|
-
return null;
|
|
12648
|
-
}
|
|
12649
|
-
pos++;
|
|
12650
|
-
consumed++;
|
|
12651
|
-
while (ctx.tokens[pos]?.type === "WHITESPACE") {
|
|
12652
|
-
pos++;
|
|
12653
|
-
consumed++;
|
|
12654
|
-
}
|
|
12655
|
-
let latexSource = "";
|
|
12656
|
-
while (pos < ctx.tokens.length) {
|
|
12657
|
-
const token5 = ctx.tokens[pos];
|
|
12658
|
-
if (!token5 || token5.type === "NEWLINE") {
|
|
12659
|
-
return null;
|
|
12660
|
-
}
|
|
12661
|
-
if (token5.type === "TEXT" && token5.value === "$" && ctx.tokens[pos + 1]?.type === "BLOCK_CLOSE") {
|
|
12662
|
-
break;
|
|
12663
|
-
}
|
|
12664
|
-
latexSource += token5.value;
|
|
12665
|
-
pos++;
|
|
12666
|
-
consumed++;
|
|
12667
|
-
}
|
|
12668
|
-
if (ctx.tokens[pos]?.type !== "TEXT" || ctx.tokens[pos]?.value !== "$") {
|
|
12669
|
-
return null;
|
|
12670
|
-
}
|
|
12671
|
-
pos++;
|
|
12672
|
-
consumed++;
|
|
12673
|
-
if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
|
|
12674
|
-
return null;
|
|
12675
|
-
}
|
|
12676
|
-
return {
|
|
12677
|
-
latexSource: latexSource.trim(),
|
|
12678
|
-
consumed: consumed + 1
|
|
12679
|
-
};
|
|
12680
|
-
}
|
|
12681
|
-
|
|
12682
|
-
// packages/parser/src/parser/rules/inline/math-inline/index.ts
|
|
12683
|
-
var mathInlineRule = {
|
|
12684
|
-
name: "math-inline",
|
|
12685
|
-
startTokens: ["BLOCK_OPEN"],
|
|
12686
|
-
parse(ctx) {
|
|
12687
|
-
const openToken = currentToken(ctx);
|
|
12688
|
-
if (openToken.type !== "BLOCK_OPEN") {
|
|
12689
|
-
return { success: false };
|
|
12690
|
-
}
|
|
12691
|
-
const parsed = parseInlineMathSource(ctx, ctx.pos + 1);
|
|
12692
|
-
if (!parsed) {
|
|
12693
|
-
return { success: false };
|
|
12694
|
-
}
|
|
12695
|
-
return {
|
|
12696
|
-
success: true,
|
|
12697
|
-
elements: [
|
|
12698
|
-
{
|
|
12699
|
-
element: "math-inline",
|
|
12700
|
-
data: {
|
|
12701
|
-
"latex-source": parsed.latexSource
|
|
12702
|
-
}
|
|
12703
|
-
}
|
|
12704
|
-
],
|
|
12705
|
-
consumed: 1 + parsed.consumed
|
|
13743
|
+
consumed,
|
|
13744
|
+
stripLeadingLineBreak: openResult.paragraphStrip ? precedingSingleNewline(ctx) : undefined
|
|
12706
13745
|
};
|
|
12707
13746
|
}
|
|
12708
13747
|
};
|
|
@@ -12813,7 +13852,9 @@ function parseInlineBranch(ctx, startPos) {
|
|
|
12813
13852
|
}
|
|
12814
13853
|
const result = rule.parse(inlineCtx);
|
|
12815
13854
|
if (result.success) {
|
|
12816
|
-
elements
|
|
13855
|
+
stripAutomaticLineBreak(elements, result.stripLeadingLineBreak);
|
|
13856
|
+
for (const element of result.elements)
|
|
13857
|
+
elements.push(element);
|
|
12817
13858
|
consumed += result.consumed;
|
|
12818
13859
|
pos += result.consumed;
|
|
12819
13860
|
matched = true;
|
|
@@ -13136,6 +14177,7 @@ var textRule = {
|
|
|
13136
14177
|
|
|
13137
14178
|
// packages/parser/src/parser/rules/inline/index.ts
|
|
13138
14179
|
var inlineRules = [
|
|
14180
|
+
emailRule,
|
|
13139
14181
|
boldRule,
|
|
13140
14182
|
italicRule,
|
|
13141
14183
|
underlineRule,
|
|
@@ -13147,6 +14189,7 @@ var inlineRules = [
|
|
|
13147
14189
|
linkSingleRule,
|
|
13148
14190
|
linkAnchorRule,
|
|
13149
14191
|
linkStarRule,
|
|
14192
|
+
autolinkRule,
|
|
13150
14193
|
colorRule,
|
|
13151
14194
|
backslashLineBreakRule,
|
|
13152
14195
|
underscoreLineBreakRule,
|
|
@@ -13156,6 +14199,9 @@ var inlineRules = [
|
|
|
13156
14199
|
rawRule,
|
|
13157
14200
|
imageRule,
|
|
13158
14201
|
embedBlockRule,
|
|
14202
|
+
buttonRule,
|
|
14203
|
+
socialRule,
|
|
14204
|
+
dateRule,
|
|
13159
14205
|
sizeRule,
|
|
13160
14206
|
footnoteRule,
|
|
13161
14207
|
spanRule,
|
|
@@ -13411,6 +14457,8 @@ function mergeSpanStripParagraphs(children) {
|
|
|
13411
14457
|
i++;
|
|
13412
14458
|
continue;
|
|
13413
14459
|
}
|
|
14460
|
+
const firstMeaningful = paraData.elements.find((child) => child.element !== "line-break" && !isWhitespaceText(child));
|
|
14461
|
+
const keepParagraph = firstMeaningful && !isSpanStripMarker(firstMeaningful);
|
|
13414
14462
|
const mergedChildren = [...paraData.elements];
|
|
13415
14463
|
i++;
|
|
13416
14464
|
while (i < expandedChildren.length) {
|
|
@@ -13423,7 +14471,8 @@ function mergeSpanStripParagraphs(children) {
|
|
|
13423
14471
|
break;
|
|
13424
14472
|
}
|
|
13425
14473
|
const hasSpanStrip = hasParagraphStripSpan(nextPara);
|
|
13426
|
-
|
|
14474
|
+
for (const element of nextParaData.elements)
|
|
14475
|
+
mergedChildren.push(element);
|
|
13427
14476
|
i++;
|
|
13428
14477
|
if (!hasSpanStrip) {
|
|
13429
14478
|
const peekNext = expandedChildren[i];
|
|
@@ -13434,7 +14483,7 @@ function mergeSpanStripParagraphs(children) {
|
|
|
13434
14483
|
}
|
|
13435
14484
|
const escapedSpans = extractEscapedSpans(mergedChildren);
|
|
13436
14485
|
removeLineBreaksAroundSpanStrip(mergedChildren);
|
|
13437
|
-
if (escapedSpans.length > 0) {
|
|
14486
|
+
if (escapedSpans.length > 0 || keepParagraph) {
|
|
13438
14487
|
if (mergedChildren.length > 0) {
|
|
13439
14488
|
result.push(paragraphElement(mergedChildren));
|
|
13440
14489
|
}
|
|
@@ -13655,50 +14704,6 @@ function cleanInternalFlags(elements) {
|
|
|
13655
14704
|
}
|
|
13656
14705
|
return removeEmptySpansAndAdjacentWhitespace(cleaned ?? elements);
|
|
13657
14706
|
}
|
|
13658
|
-
// packages/parser/src/parser/postprocess/divAdjacentParagraph.ts
|
|
13659
|
-
function isParagraphContainer2(el) {
|
|
13660
|
-
if (!el || el.element !== "container")
|
|
13661
|
-
return false;
|
|
13662
|
-
return el.data.type === "paragraph";
|
|
13663
|
-
}
|
|
13664
|
-
function isDivContainer(el) {
|
|
13665
|
-
if (!el || el.element !== "container")
|
|
13666
|
-
return false;
|
|
13667
|
-
return el.data.type === "div";
|
|
13668
|
-
}
|
|
13669
|
-
function suppressAtLevel(elements) {
|
|
13670
|
-
if (elements.length <= 1)
|
|
13671
|
-
return elements;
|
|
13672
|
-
const unwrap = Array.from({ length: elements.length }, () => false);
|
|
13673
|
-
for (let i = 0;i < elements.length; i++) {
|
|
13674
|
-
if (!isParagraphContainer2(elements[i]))
|
|
13675
|
-
continue;
|
|
13676
|
-
const prevIsDiv = i > 0 && isDivContainer(elements[i - 1]);
|
|
13677
|
-
const nextIsDiv = i < elements.length - 1 && isDivContainer(elements[i + 1]);
|
|
13678
|
-
if (prevIsDiv || nextIsDiv) {
|
|
13679
|
-
unwrap[i] = true;
|
|
13680
|
-
}
|
|
13681
|
-
}
|
|
13682
|
-
const result = [];
|
|
13683
|
-
for (let i = 0;i < elements.length; i++) {
|
|
13684
|
-
const el = elements[i];
|
|
13685
|
-
if (!el)
|
|
13686
|
-
continue;
|
|
13687
|
-
if (unwrap[i] && el.element === "container") {
|
|
13688
|
-
const inner = el.data.elements;
|
|
13689
|
-
if (i > 0 && isDivContainer(elements[i - 1])) {
|
|
13690
|
-
result.push({ element: "line-break" });
|
|
13691
|
-
}
|
|
13692
|
-
result.push(...inner);
|
|
13693
|
-
} else {
|
|
13694
|
-
result.push(el);
|
|
13695
|
-
}
|
|
13696
|
-
}
|
|
13697
|
-
return result;
|
|
13698
|
-
}
|
|
13699
|
-
function suppressDivAdjacentParagraphs(elements) {
|
|
13700
|
-
return suppressAtLevel(elements);
|
|
13701
|
-
}
|
|
13702
14707
|
// packages/parser/src/parser/parse/footnotes.ts
|
|
13703
14708
|
function containsFootnoteBlock(elements) {
|
|
13704
14709
|
let found = false;
|
|
@@ -13976,7 +14981,9 @@ function substitute(text2) {
|
|
|
13976
14981
|
result = result.replace(WHITESPACE_ONLY_LINE, "");
|
|
13977
14982
|
}
|
|
13978
14983
|
if (result.indexOf("\\\n") !== -1) {
|
|
13979
|
-
|
|
14984
|
+
const sentinels = makeUniqueSentinels(result);
|
|
14985
|
+
const { masked, placeholders } = maskRawRegions(result, sentinels);
|
|
14986
|
+
result = restorePlaceholders(masked.replace(CONCAT_LINES, String.fromCharCode(57344)), placeholders, sentinels);
|
|
13980
14987
|
}
|
|
13981
14988
|
if (result.indexOf("\t") !== -1) {
|
|
13982
14989
|
result = result.replace(TABS, " ");
|
|
@@ -14043,14 +15050,26 @@ function replaceDelimitedTypography(text2, opener, closer, leftQuote, rightQuote
|
|
|
14043
15050
|
let searchFrom = 0;
|
|
14044
15051
|
let result = "";
|
|
14045
15052
|
let lastCopied = 0;
|
|
15053
|
+
let closeIndex = -1;
|
|
15054
|
+
let newlineIndex = -1;
|
|
14046
15055
|
while (searchFrom < text2.length) {
|
|
14047
15056
|
const openIndex = text2.indexOf(opener, searchFrom);
|
|
14048
15057
|
if (openIndex === -1)
|
|
14049
15058
|
break;
|
|
14050
15059
|
const contentStart = openIndex + opener.length;
|
|
14051
|
-
|
|
15060
|
+
if (closeIndex < contentStart)
|
|
15061
|
+
closeIndex = text2.indexOf(closer, contentStart);
|
|
14052
15062
|
if (closeIndex === -1)
|
|
14053
15063
|
break;
|
|
15064
|
+
if (newlineIndex < contentStart) {
|
|
15065
|
+
const nextNewline = text2.indexOf(`
|
|
15066
|
+
`, contentStart);
|
|
15067
|
+
newlineIndex = nextNewline === -1 ? text2.length : nextNewline;
|
|
15068
|
+
}
|
|
15069
|
+
if (newlineIndex < closeIndex) {
|
|
15070
|
+
searchFrom = newlineIndex + 1;
|
|
15071
|
+
continue;
|
|
15072
|
+
}
|
|
14054
15073
|
result += text2.slice(lastCopied, openIndex);
|
|
14055
15074
|
result += leftQuote;
|
|
14056
15075
|
result += text2.slice(contentStart, closeIndex);
|
|
@@ -14061,7 +15080,12 @@ function replaceDelimitedTypography(text2, opener, closer, leftQuote, rightQuote
|
|
|
14061
15080
|
return lastCopied === 0 ? text2 : result + text2.slice(lastCopied);
|
|
14062
15081
|
}
|
|
14063
15082
|
function substitute2(text2) {
|
|
14064
|
-
|
|
15083
|
+
if (!text2.includes("`") && !text2.includes(",,") && !text2.includes("...") && !text2.includes(". . .")) {
|
|
15084
|
+
return text2;
|
|
15085
|
+
}
|
|
15086
|
+
const sentinels = makeUniqueSentinels(text2);
|
|
15087
|
+
const { masked, placeholders } = maskRawRegions(text2, sentinels);
|
|
15088
|
+
let result = masked;
|
|
14065
15089
|
if (result.includes("``") && result.includes("''")) {
|
|
14066
15090
|
result = replaceDelimitedTypography(result, "``", "''", LEFT_DOUBLE_QUOTE, RIGHT_DOUBLE_QUOTE);
|
|
14067
15091
|
}
|
|
@@ -14077,7 +15101,7 @@ function substitute2(text2) {
|
|
|
14077
15101
|
if (result.includes(". . .")) {
|
|
14078
15102
|
result = replaceExactEllipsisPattern(result, ". . .");
|
|
14079
15103
|
}
|
|
14080
|
-
return result;
|
|
15104
|
+
return restorePlaceholders(result, placeholders, sentinels);
|
|
14081
15105
|
}
|
|
14082
15106
|
|
|
14083
15107
|
// packages/parser/src/parser/preprocess/index.ts
|
|
@@ -14326,7 +15350,7 @@ async function resolveModulesWithAsyncParse(ast, dataProvider, options) {
|
|
|
14326
15350
|
registry.register(ast);
|
|
14327
15351
|
const parse2 = async (source) => registry.register(await options.parse(source));
|
|
14328
15352
|
const [listPagesData, listUsersData, tagCloudData] = await Promise.all([
|
|
14329
|
-
buildListPagesDataMap(dataProvider, options.requirements.listPages ?? [], options.urlPath),
|
|
15353
|
+
buildListPagesDataMap(dataProvider, options.requirements.listPages ?? [], options.urlPath, options.paginationState),
|
|
14330
15354
|
buildListUsersDataMap(dataProvider, options.requirements.listUsers ?? []),
|
|
14331
15355
|
buildTagCloudDataMap(dataProvider, options.requirements.tagCloud ?? [])
|
|
14332
15356
|
]);
|
|
@@ -14414,9 +15438,9 @@ async function resolveListPagesAsync(module, data, template, parse2) {
|
|
|
14414
15438
|
continue;
|
|
14415
15439
|
const variableContext = {
|
|
14416
15440
|
page,
|
|
14417
|
-
index: i + 1,
|
|
15441
|
+
index: (data.pagination?.offset ?? 0) + i + 1,
|
|
14418
15442
|
total: data.totalCount,
|
|
14419
|
-
limit: module.limit,
|
|
15443
|
+
limit: data.pagination ? data.pagination.limit : module.limit,
|
|
14420
15444
|
site: data.site
|
|
14421
15445
|
};
|
|
14422
15446
|
const parsed = await parse2(template(variableContext));
|
|
@@ -14436,6 +15460,7 @@ async function resolveListPagesAsync(module, data, template, parse2) {
|
|
|
14436
15460
|
if (module["append-line"] && !module.separate) {
|
|
14437
15461
|
result.push(...(await parse2(module["append-line"])).elements);
|
|
14438
15462
|
}
|
|
15463
|
+
result.push(...createListPagesPager(data));
|
|
14439
15464
|
return module.wrapper ? [
|
|
14440
15465
|
{
|
|
14441
15466
|
element: "container",
|
|
@@ -14536,6 +15561,9 @@ async function processWikitext(source, options) {
|
|
|
14536
15561
|
const dataProvider = createModuleDataProvider(options, callbackContext);
|
|
14537
15562
|
const parseFragment = parseSource2;
|
|
14538
15563
|
let ast = initial.ast;
|
|
15564
|
+
const paginationState = { nextUnprefixed: 1 };
|
|
15565
|
+
const requestedPath = options.page.urlPath;
|
|
15566
|
+
const urlPath = !requestedPath || /^\/(?:[?#]|$)/.test(requestedPath) ? `/${options.page.fullName}${requestedPath?.slice(1) ?? ""}` : requestedPath;
|
|
14539
15567
|
for (let pass = 0;pass < DEFAULT_MODULE_MAX_PASSES; pass++) {
|
|
14540
15568
|
const extraction = extractDataRequirements(ast);
|
|
14541
15569
|
if (pass > 0 && !hasResolvableRequirements(extraction.requirements, options.dataProvider)) {
|
|
@@ -14546,7 +15574,8 @@ async function processWikitext(source, options) {
|
|
|
14546
15574
|
compiledListPagesTemplates: extraction.compiledListPagesTemplates,
|
|
14547
15575
|
compiledListUsersTemplates: extraction.compiledListUsersTemplates,
|
|
14548
15576
|
requirements: extraction.requirements,
|
|
14549
|
-
urlPath
|
|
15577
|
+
urlPath,
|
|
15578
|
+
paginationState,
|
|
14550
15579
|
pageTags: options.page.tags
|
|
14551
15580
|
});
|
|
14552
15581
|
ast = resolved.ast;
|