@wdprlib/parser 5.3.0 → 5.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +2074 -1137
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2074 -1137
- package/package.json +3 -2
- package/src/build-info.generated.ts +2 -2
- package/src/lexer/lexer.ts +34 -5
- package/src/lexer/quoted-string.ts +4 -4
- package/src/lexer/syntax-actions.ts +6 -1
- package/src/lexer/text-actions.ts +15 -1
- package/src/lexer/url-schemes.ts +78 -0
- package/src/parser/constants.ts +4 -0
- package/src/parser/parse/block.ts +1 -1
- package/src/parser/postprocess/divAdjacentParagraph.ts +23 -21
- package/src/parser/postprocess/spanStrip/merge.ts +8 -2
- package/src/parser/preprocess/typography.ts +25 -3
- package/src/parser/preprocess/utils/raw-regions.ts +59 -14
- package/src/parser/preprocess/whitespace/index.ts +8 -1
- package/src/parser/rules/block/bibliography/entry-content.ts +1 -1
- package/src/parser/rules/block/block-list/bare-content.ts +3 -1
- package/src/parser/rules/block/block-list/bare-paragraph.ts +7 -2
- package/src/parser/rules/block/block-list/item-content.ts +7 -3
- package/src/parser/rules/block/block-list/li-content.ts +8 -3
- package/src/parser/rules/block/block-list/li-item.ts +1 -1
- package/src/parser/rules/block/blockquote/build.ts +1 -1
- package/src/parser/rules/block/code/boundary.ts +76 -0
- package/src/parser/rules/block/code/content.ts +11 -40
- package/src/parser/rules/block/code/index.ts +8 -31
- package/src/parser/rules/block/code/open.ts +46 -0
- package/src/parser/rules/block/definition-list/item-key.ts +1 -1
- package/src/parser/rules/block/definition-list/item-value.ts +1 -1
- package/src/parser/rules/block/div/failed.ts +2 -0
- package/src/parser/rules/block/index.ts +3 -0
- package/src/parser/rules/block/list/line.ts +6 -3
- package/src/parser/rules/block/math/boundary.ts +104 -0
- package/src/parser/rules/block/math/index.ts +17 -57
- package/src/parser/rules/block/note/boundary.ts +88 -0
- package/src/parser/rules/block/note/index.ts +37 -0
- package/src/parser/rules/block/paragraph/index.ts +12 -4
- package/src/parser/rules/block/paragraph/normalize.ts +6 -1
- package/src/parser/rules/block/parsing/block-item.ts +1 -1
- package/src/parser/rules/block/parsing/content.ts +1 -1
- package/src/parser/rules/block/parsing/inline-content.ts +6 -3
- package/src/parser/rules/block/table/pipe/cell.ts +3 -1
- package/src/parser/rules/block/table-block/cell-content/index.ts +1 -1
- package/src/parser/rules/block/table-block/cell-content/segments.ts +5 -2
- package/src/parser/rules/block/table-block/cell-newline.ts +2 -1
- package/src/parser/rules/contracts/rule.ts +4 -2
- package/src/parser/rules/contracts/scope.ts +2 -0
- package/src/parser/rules/inline/anchor/child.ts +8 -2
- package/src/parser/rules/inline/anchor/content.ts +3 -1
- package/src/parser/rules/inline/anchor/index.ts +4 -1
- package/src/parser/rules/inline/anchor/newline.ts +2 -1
- package/src/parser/rules/inline/autolink.ts +153 -0
- package/src/parser/rules/inline/button/attributes.ts +17 -0
- package/src/parser/rules/inline/button/index.ts +17 -0
- package/src/parser/rules/inline/button/syntax.ts +56 -0
- package/src/parser/rules/inline/date/index.ts +17 -0
- package/src/parser/rules/inline/date/syntax.ts +46 -0
- package/src/parser/rules/inline/email/candidates.ts +134 -0
- package/src/parser/rules/inline/email/index.ts +36 -0
- package/src/parser/rules/inline/email/scan.ts +76 -0
- package/src/parser/rules/inline/expr/branch.ts +3 -1
- package/src/parser/rules/inline/footnote/boundary.ts +56 -0
- package/src/parser/rules/inline/footnote/content.ts +29 -41
- package/src/parser/rules/inline/footnote/elements.ts +9 -34
- package/src/parser/rules/inline/footnote/index.ts +4 -1
- package/src/parser/rules/inline/formatting/close.ts +12 -0
- package/src/parser/rules/inline/index.ts +14 -0
- package/src/parser/rules/inline/line-break/newline.ts +8 -1
- package/src/parser/rules/inline/link-bracket/direct-url.ts +11 -3
- package/src/parser/rules/inline/link-bracket/parsed.ts +9 -4
- package/src/parser/rules/inline/link-bracket/parts.ts +14 -36
- package/src/parser/rules/inline/link-bracket/special-target.ts +9 -0
- package/src/parser/rules/inline/link-single.ts +9 -7
- package/src/parser/rules/inline/link-triple/index.ts +1 -0
- package/src/parser/rules/inline/link-triple/label.ts +7 -1
- package/src/parser/rules/inline/parsing/automatic-line-break.ts +35 -0
- package/src/parser/rules/inline/parsing/block-boundary.ts +2 -0
- package/src/parser/rules/inline/parsing/block-start-predicates.ts +10 -0
- package/src/parser/rules/inline/parsing/inline-content.ts +36 -6
- package/src/parser/rules/inline/parsing/plain-text.ts +7 -2
- package/src/parser/rules/inline/parsing/preserved-line-break.ts +13 -0
- package/src/parser/rules/inline/parsing/raw-tag.ts +19 -0
- package/src/parser/rules/inline/raw/angle.ts +2 -1
- package/src/parser/rules/inline/raw/end.ts +21 -1
- package/src/parser/rules/inline/size/content.ts +1 -1
- package/src/parser/rules/inline/size/value.ts +11 -0
- package/src/parser/rules/inline/social/index.ts +17 -0
- package/src/parser/rules/inline/social/syntax.ts +40 -0
- package/src/parser/rules/inline/span/content.ts +3 -1
- package/src/parser/rules/inline/span/newline.ts +2 -1
- package/src/parser/rules/opaque-probe.ts +58 -0
- package/src/parser/rules/block/math/content.ts +0 -54
- package/src/parser/rules/block/math/name.ts +0 -35
- package/src/parser/rules/inline/footnote/child.ts +0 -22
- package/src/parser/rules/inline/footnote/newline.ts +0 -27
package/dist/index.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")
|
|
@@ -1456,165 +2725,39 @@ function parseInlineUntil(ctx, endType) {
|
|
|
1456
2725
|
}
|
|
1457
2726
|
if (nodes.at(-1)?.element === "line-break")
|
|
1458
2727
|
nodes.pop();
|
|
1459
|
-
}
|
|
1460
|
-
}
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
nodes.push({ element: "text", data: token5.value });
|
|
1470
|
-
consumed++;
|
|
1471
|
-
pos++;
|
|
1472
|
-
}
|
|
1473
|
-
}
|
|
1474
|
-
return { elements: nodes, consumed };
|
|
1475
|
-
}
|
|
1476
|
-
var FORMATTING_CLOSE_TOKENS = new Set([
|
|
1477
|
-
"BOLD_MARKER",
|
|
1478
|
-
"ITALIC_MARKER",
|
|
1479
|
-
"UNDERLINE_MARKER",
|
|
1480
|
-
"STRIKE_MARKER",
|
|
1481
|
-
"SUPER_MARKER",
|
|
1482
|
-
"SUB_MARKER",
|
|
1483
|
-
"MONO_CLOSE",
|
|
1484
|
-
"COLOR_MARKER"
|
|
1485
|
-
]);
|
|
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;
|
|
2728
|
+
}
|
|
2729
|
+
}
|
|
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
|
+
}
|
|
2733
|
+
consumed += result.consumed;
|
|
2734
|
+
pos += result.consumed;
|
|
2735
|
+
matched = true;
|
|
2736
|
+
break;
|
|
2737
|
+
}
|
|
1568
2738
|
}
|
|
1569
|
-
if (
|
|
1570
|
-
|
|
2739
|
+
if (!matched) {
|
|
2740
|
+
nodes.push({ element: "text", data: token5.value });
|
|
1571
2741
|
consumed++;
|
|
1572
|
-
continue;
|
|
1573
|
-
}
|
|
1574
|
-
if (!isAttributeNameToken(token5)) {
|
|
1575
2742
|
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
2743
|
}
|
|
1596
|
-
attrs[name] = valueResult.value;
|
|
1597
|
-
pos++;
|
|
1598
|
-
consumed++;
|
|
1599
2744
|
}
|
|
1600
|
-
return {
|
|
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 });
|
|
2745
|
+
return { elements: nodes, consumed };
|
|
1613
2746
|
}
|
|
2747
|
+
var FORMATTING_CLOSE_TOKENS = new Set([
|
|
2748
|
+
"BOLD_MARKER",
|
|
2749
|
+
"ITALIC_MARKER",
|
|
2750
|
+
"UNDERLINE_MARKER",
|
|
2751
|
+
"STRIKE_MARKER",
|
|
2752
|
+
"SUPER_MARKER",
|
|
2753
|
+
"SUB_MARKER",
|
|
2754
|
+
"MONO_CLOSE",
|
|
2755
|
+
"COLOR_MARKER"
|
|
2756
|
+
]);
|
|
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 {
|
|
@@ -2947,78 +4071,93 @@ var definitionListRule = {
|
|
|
2947
4071
|
}
|
|
2948
4072
|
};
|
|
2949
4073
|
|
|
2950
|
-
// packages/parser/src/parser/
|
|
2951
|
-
|
|
2952
|
-
|
|
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);
|
|
2953
4081
|
}
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
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);
|
|
2958
4096
|
for (let i = 0;i < elements.length; i++) {
|
|
2959
|
-
|
|
2960
|
-
if (!elem)
|
|
4097
|
+
if (!isUnparsedDivParagraph(elements[i]))
|
|
2961
4098
|
continue;
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
});
|
|
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 = [];
|
|
4106
|
+
for (let i = 0;i < elements.length; i++) {
|
|
4107
|
+
const el = elements[i];
|
|
4108
|
+
if (!el)
|
|
4109
|
+
continue;
|
|
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: [
|
|
@@ -3400,126 +4546,6 @@ var divRule = {
|
|
|
3400
4546
|
}
|
|
3401
4547
|
};
|
|
3402
4548
|
|
|
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 };
|
|
3449
|
-
}
|
|
3450
|
-
function consumeCodeClose(ctx, startPos, closeNameConsumed) {
|
|
3451
|
-
let pos = startPos + 1 + closeNameConsumed;
|
|
3452
|
-
let consumed = 1 + closeNameConsumed;
|
|
3453
|
-
if (ctx.tokens[pos]?.type === "BLOCK_CLOSE") {
|
|
3454
|
-
pos++;
|
|
3455
|
-
consumed++;
|
|
3456
|
-
}
|
|
3457
|
-
return consumed;
|
|
3458
|
-
}
|
|
3459
|
-
|
|
3460
|
-
// packages/parser/src/parser/rules/block/code/index.ts
|
|
3461
|
-
var codeBlockRule = {
|
|
3462
|
-
name: "code",
|
|
3463
|
-
startTokens: ["BLOCK_OPEN"],
|
|
3464
|
-
requiresLineStart: false,
|
|
3465
|
-
parse(ctx) {
|
|
3466
|
-
const openToken = currentToken(ctx);
|
|
3467
|
-
if (openToken.type !== "BLOCK_OPEN") {
|
|
3468
|
-
return { success: false };
|
|
3469
|
-
}
|
|
3470
|
-
let pos = ctx.pos + 1;
|
|
3471
|
-
let consumed = 1;
|
|
3472
|
-
const nameResult = parseBlockName(ctx, pos);
|
|
3473
|
-
if (!nameResult || nameResult.name !== "code") {
|
|
3474
|
-
return { success: false };
|
|
3475
|
-
}
|
|
3476
|
-
pos += nameResult.consumed;
|
|
3477
|
-
consumed += nameResult.consumed;
|
|
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++;
|
|
3490
|
-
}
|
|
3491
|
-
if (ctx.tokens[pos]?.type === "NEWLINE") {
|
|
3492
|
-
pos++;
|
|
3493
|
-
consumed++;
|
|
3494
|
-
}
|
|
3495
|
-
const contentResult = collectCodeContent(ctx, pos, closingSwallowed);
|
|
3496
|
-
let codeContent = contentResult.contents.replace(/\n$/, "");
|
|
3497
|
-
consumed += contentResult.consumed;
|
|
3498
|
-
pos += contentResult.consumed;
|
|
3499
|
-
if (!contentResult.foundClose) {
|
|
3500
|
-
ctx.diagnostics.push({
|
|
3501
|
-
severity: "warning",
|
|
3502
|
-
code: "unclosed-block",
|
|
3503
|
-
message: "Missing closing tag [[/code]] for [[code]]",
|
|
3504
|
-
position: openToken.position
|
|
3505
|
-
});
|
|
3506
|
-
}
|
|
3507
|
-
const codeBlockData = {
|
|
3508
|
-
contents: codeContent,
|
|
3509
|
-
language: attrResult.attrs.type ?? null,
|
|
3510
|
-
name: attrResult.attrs.name ?? null
|
|
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;
|
|
3518
|
-
}
|
|
3519
|
-
return { success: true, elements, consumed };
|
|
3520
|
-
}
|
|
3521
|
-
};
|
|
3522
|
-
|
|
3523
4549
|
// packages/parser/src/parser/rules/block/collapsible/attributes.ts
|
|
3524
4550
|
function parseMultilineAttributes(ctx, startPos) {
|
|
3525
4551
|
const attrs = {};
|
|
@@ -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;
|
|
@@ -6786,7 +7815,7 @@ function resolveIfTags(data, pageTags) {
|
|
|
6786
7815
|
// packages/parser/src/parser/preprocess/utils/raw-regions.ts
|
|
6787
7816
|
var BASE_PLACEHOLDER_OPEN = "";
|
|
6788
7817
|
var BASE_PLACEHOLDER_CLOSE = "";
|
|
6789
|
-
var RAW_BLOCK_OPEN_PATTERN = /\[\[
|
|
7818
|
+
var RAW_BLOCK_OPEN_PATTERN = /\[\[html\b[^\]]*\]\]/iy;
|
|
6790
7819
|
function makeUniqueSentinels(source) {
|
|
6791
7820
|
let openRun = 0;
|
|
6792
7821
|
let closeRun = 0;
|
|
@@ -6805,10 +7834,21 @@ function makeUniqueSentinels(source) {
|
|
|
6805
7834
|
}
|
|
6806
7835
|
function maskRawRegions(source, sentinels) {
|
|
6807
7836
|
const placeholders = [];
|
|
7837
|
+
let tokens;
|
|
7838
|
+
const getTokens = () => tokens ??= tokenize(source);
|
|
6808
7839
|
let masked = "";
|
|
6809
7840
|
let i = 0;
|
|
6810
7841
|
while (i < source.length) {
|
|
6811
|
-
|
|
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);
|
|
6812
7852
|
if (rawBlock) {
|
|
6813
7853
|
masked += rawBlock.placeholder;
|
|
6814
7854
|
i = rawBlock.end;
|
|
@@ -6829,16 +7869,25 @@ function restorePlaceholders(source, placeholders, sentinels) {
|
|
|
6829
7869
|
const pattern = new RegExp(`${escapeRegex(sentinels.open)}(\\d+)${escapeRegex(sentinels.close)}`, "g");
|
|
6830
7870
|
return source.replace(pattern, (_, idx) => placeholders[Number(idx)] ?? "");
|
|
6831
7871
|
}
|
|
6832
|
-
function tryMaskRawBlock(source, pos, placeholders, sentinels) {
|
|
7872
|
+
function tryMaskRawBlock(source, pos, placeholders, sentinels, getTokens) {
|
|
6833
7873
|
if (source[pos] !== "[" || source[pos + 1] !== "[")
|
|
6834
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
|
+
}
|
|
6835
7885
|
RAW_BLOCK_OPEN_PATTERN.lastIndex = pos;
|
|
6836
7886
|
const openMatch = RAW_BLOCK_OPEN_PATTERN.exec(source);
|
|
6837
7887
|
if (!openMatch)
|
|
6838
7888
|
return null;
|
|
6839
|
-
const name = openMatch[1].toLowerCase();
|
|
6840
7889
|
const openLen = openMatch[0].length;
|
|
6841
|
-
const closePattern =
|
|
7890
|
+
const closePattern = /\[\[\/\s*html\s*\]\]/gi;
|
|
6842
7891
|
closePattern.lastIndex = pos + openLen;
|
|
6843
7892
|
const closeMatch = closePattern.exec(source);
|
|
6844
7893
|
if (closeMatch) {
|
|
@@ -6848,12 +7897,19 @@ function tryMaskRawBlock(source, pos, placeholders, sentinels) {
|
|
|
6848
7897
|
end
|
|
6849
7898
|
};
|
|
6850
7899
|
}
|
|
6851
|
-
|
|
6852
|
-
|
|
6853
|
-
|
|
6854
|
-
|
|
6855
|
-
|
|
6856
|
-
|
|
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;
|
|
6857
7913
|
}
|
|
6858
7914
|
function tryMaskRawInline(source, pos, placeholders, sentinels) {
|
|
6859
7915
|
if (source[pos] === "@" && source[pos + 1] === "<") {
|
|
@@ -6865,17 +7921,22 @@ function tryMaskRawInline(source, pos, placeholders, sentinels) {
|
|
|
6865
7921
|
return null;
|
|
6866
7922
|
}
|
|
6867
7923
|
function tryMaskSingleLineRaw(source, pos, openerLength, close, placeholders, sentinels) {
|
|
6868
|
-
const
|
|
6869
|
-
|
|
6870
|
-
`, pos + openerLength);
|
|
6871
|
-
if (closePos === -1 || newline !== -1 && newline < closePos)
|
|
7924
|
+
const end = singleLineRawEnd(source, pos, openerLength, close);
|
|
7925
|
+
if (end === pos)
|
|
6872
7926
|
return null;
|
|
6873
|
-
const end = closePos + close.length;
|
|
6874
7927
|
return {
|
|
6875
7928
|
placeholder: pushPlaceholder(placeholders, source.slice(pos, end), sentinels),
|
|
6876
7929
|
end
|
|
6877
7930
|
};
|
|
6878
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
|
+
}
|
|
6879
7940
|
function pushPlaceholder(placeholders, text, sentinels) {
|
|
6880
7941
|
const idx = placeholders.length;
|
|
6881
7942
|
placeholders.push(text);
|
|
@@ -9045,167 +10106,32 @@ function parseVariables(tokens) {
|
|
|
9045
10106
|
for (const token5 of tokens) {
|
|
9046
10107
|
if (token5 === "|") {
|
|
9047
10108
|
assignVariable(vars, current2);
|
|
9048
|
-
current2 = "";
|
|
9049
|
-
} else {
|
|
9050
|
-
current2 += token5;
|
|
9051
|
-
}
|
|
9052
|
-
}
|
|
9053
|
-
assignVariable(vars, current2);
|
|
9054
|
-
return vars;
|
|
9055
|
-
}
|
|
9056
|
-
function assignVariable(vars, source) {
|
|
9057
|
-
if (!source.trim()) {
|
|
9058
|
-
return;
|
|
9059
|
-
}
|
|
9060
|
-
const eqIndex = source.indexOf("=");
|
|
9061
|
-
if (eqIndex === -1) {
|
|
9062
|
-
return;
|
|
9063
|
-
}
|
|
9064
|
-
const key = source.slice(0, eqIndex).trim();
|
|
9065
|
-
if (!key) {
|
|
9066
|
-
return;
|
|
9067
|
-
}
|
|
9068
|
-
vars[key] = source.slice(eqIndex + 1).trim();
|
|
9069
|
-
}
|
|
9070
|
-
|
|
9071
|
-
// packages/parser/src/parser/rules/block/include/index.ts
|
|
9072
|
-
var includeRule = {
|
|
9073
|
-
name: "include",
|
|
9074
|
-
startTokens: ["BLOCK_OPEN"],
|
|
9075
|
-
requiresLineStart: false,
|
|
9076
|
-
parse(ctx) {
|
|
9077
|
-
const openToken = currentToken(ctx);
|
|
9078
|
-
if (openToken.type !== "BLOCK_OPEN") {
|
|
9079
|
-
return { success: false };
|
|
9080
|
-
}
|
|
9081
|
-
let pos = ctx.pos + 1;
|
|
9082
|
-
let consumed = 1;
|
|
9083
|
-
const nameResult = parseBlockName(ctx, pos);
|
|
9084
|
-
if (!nameResult || nameResult.name.toLowerCase() !== "include") {
|
|
9085
|
-
return { success: false };
|
|
9086
|
-
}
|
|
9087
|
-
if (!ctx.settings.enablePageSyntax) {
|
|
9088
|
-
return { success: false };
|
|
9089
|
-
}
|
|
9090
|
-
pos += nameResult.consumed;
|
|
9091
|
-
consumed += nameResult.consumed;
|
|
9092
|
-
while (ctx.tokens[pos]?.type === "WHITESPACE") {
|
|
9093
|
-
pos++;
|
|
9094
|
-
consumed++;
|
|
9095
|
-
}
|
|
9096
|
-
const args = collectIncludeArguments(ctx, pos);
|
|
9097
|
-
pos += args.consumed;
|
|
9098
|
-
consumed += args.consumed;
|
|
9099
|
-
if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
|
|
9100
|
-
return { success: false };
|
|
9101
|
-
}
|
|
9102
|
-
pos++;
|
|
9103
|
-
consumed++;
|
|
9104
|
-
const directiveEnd = pos;
|
|
9105
|
-
if (ctx.tokens[pos]?.type === "NEWLINE") {
|
|
9106
|
-
pos++;
|
|
9107
|
-
consumed++;
|
|
9108
|
-
}
|
|
9109
|
-
if (!args.target) {
|
|
9110
|
-
return { success: false };
|
|
9111
|
-
}
|
|
9112
|
-
const location = parsePageRef(args.target);
|
|
9113
|
-
if (ctx.deferInclude?.(location)) {
|
|
9114
|
-
const source = ctx.tokens.slice(ctx.pos, directiveEnd).map((token5) => token5.value).join("");
|
|
9115
|
-
const elements = [];
|
|
9116
|
-
const lines = source.split(`
|
|
9117
|
-
`);
|
|
9118
|
-
for (let index = 0;index < lines.length; index++) {
|
|
9119
|
-
if (index > 0)
|
|
9120
|
-
elements.push(lineBreak());
|
|
9121
|
-
if (lines[index] !== "")
|
|
9122
|
-
elements.push(text(lines[index]));
|
|
9123
|
-
}
|
|
9124
|
-
return { success: true, elements: [paragraph(elements)], consumed };
|
|
9125
|
-
}
|
|
9126
|
-
return {
|
|
9127
|
-
success: true,
|
|
9128
|
-
elements: [
|
|
9129
|
-
{
|
|
9130
|
-
element: "include",
|
|
9131
|
-
data: {
|
|
9132
|
-
"paragraph-safe": false,
|
|
9133
|
-
variables: parseVariables(args.argumentTokens),
|
|
9134
|
-
location,
|
|
9135
|
-
elements: []
|
|
9136
|
-
}
|
|
9137
|
-
}
|
|
9138
|
-
],
|
|
9139
|
-
consumed
|
|
9140
|
-
};
|
|
9141
|
-
}
|
|
9142
|
-
};
|
|
9143
|
-
|
|
9144
|
-
// packages/parser/src/parser/rules/block/math/content.ts
|
|
9145
|
-
function collectMathContent(ctx, startPos) {
|
|
9146
|
-
let latexSource = "";
|
|
9147
|
-
let pos = startPos;
|
|
9148
|
-
let consumed = 0;
|
|
9149
|
-
let foundClose = false;
|
|
9150
|
-
while (pos < ctx.tokens.length) {
|
|
9151
|
-
const token5 = ctx.tokens[pos];
|
|
9152
|
-
if (!token5)
|
|
9153
|
-
break;
|
|
9154
|
-
if (token5.type === "BLOCK_END_OPEN") {
|
|
9155
|
-
const closeNameResult = parseBlockName(ctx, pos + 1);
|
|
9156
|
-
if (closeNameResult?.name === "math") {
|
|
9157
|
-
foundClose = true;
|
|
9158
|
-
break;
|
|
9159
|
-
}
|
|
9160
|
-
}
|
|
9161
|
-
latexSource += token5.type === "BACKSLASH_BREAK" ? "\\\n" : token5.value;
|
|
9162
|
-
pos++;
|
|
9163
|
-
consumed++;
|
|
9164
|
-
}
|
|
9165
|
-
return { latexSource, consumed, foundClose };
|
|
9166
|
-
}
|
|
9167
|
-
function consumeMathClose(ctx, startPos) {
|
|
9168
|
-
let pos = startPos + 1;
|
|
9169
|
-
let consumed = 1;
|
|
9170
|
-
const closeNameResult = parseBlockName(ctx, pos);
|
|
9171
|
-
if (closeNameResult) {
|
|
9172
|
-
pos += closeNameResult.consumed;
|
|
9173
|
-
consumed += closeNameResult.consumed;
|
|
9174
|
-
}
|
|
9175
|
-
if (ctx.tokens[pos]?.type === "BLOCK_CLOSE") {
|
|
9176
|
-
pos++;
|
|
9177
|
-
consumed++;
|
|
9178
|
-
}
|
|
9179
|
-
if (ctx.tokens[pos]?.type === "NEWLINE") {
|
|
9180
|
-
consumed++;
|
|
10109
|
+
current2 = "";
|
|
10110
|
+
} else {
|
|
10111
|
+
current2 += token5;
|
|
10112
|
+
}
|
|
9181
10113
|
}
|
|
9182
|
-
|
|
10114
|
+
assignVariable(vars, current2);
|
|
10115
|
+
return vars;
|
|
9183
10116
|
}
|
|
9184
|
-
|
|
9185
|
-
|
|
9186
|
-
|
|
9187
|
-
let pos = startPos;
|
|
9188
|
-
let consumed = 0;
|
|
9189
|
-
let name = "";
|
|
9190
|
-
const first = ctx.tokens[pos];
|
|
9191
|
-
if (first?.type !== "IDENTIFIER" && first?.type !== "TEXT") {
|
|
9192
|
-
return { name: null, consumed: 0 };
|
|
10117
|
+
function assignVariable(vars, source) {
|
|
10118
|
+
if (!source.trim()) {
|
|
10119
|
+
return;
|
|
9193
10120
|
}
|
|
9194
|
-
|
|
9195
|
-
|
|
9196
|
-
|
|
9197
|
-
|
|
9198
|
-
|
|
9199
|
-
|
|
9200
|
-
|
|
9201
|
-
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;
|
|
9202
10128
|
}
|
|
9203
|
-
|
|
10129
|
+
vars[key] = source.slice(eqIndex + 1).trim();
|
|
9204
10130
|
}
|
|
9205
10131
|
|
|
9206
|
-
// packages/parser/src/parser/rules/block/
|
|
9207
|
-
var
|
|
9208
|
-
name: "
|
|
10132
|
+
// packages/parser/src/parser/rules/block/include/index.ts
|
|
10133
|
+
var includeRule = {
|
|
10134
|
+
name: "include",
|
|
9209
10135
|
startTokens: ["BLOCK_OPEN"],
|
|
9210
10136
|
requiresLineStart: false,
|
|
9211
10137
|
parse(ctx) {
|
|
@@ -9216,7 +10142,10 @@ var mathBlockRule = {
|
|
|
9216
10142
|
let pos = ctx.pos + 1;
|
|
9217
10143
|
let consumed = 1;
|
|
9218
10144
|
const nameResult = parseBlockName(ctx, pos);
|
|
9219
|
-
if (!nameResult || nameResult.name !== "
|
|
10145
|
+
if (!nameResult || nameResult.name.toLowerCase() !== "include") {
|
|
10146
|
+
return { success: false };
|
|
10147
|
+
}
|
|
10148
|
+
if (!ctx.settings.enablePageSyntax) {
|
|
9220
10149
|
return { success: false };
|
|
9221
10150
|
}
|
|
9222
10151
|
pos += nameResult.consumed;
|
|
@@ -9225,49 +10154,46 @@ var mathBlockRule = {
|
|
|
9225
10154
|
pos++;
|
|
9226
10155
|
consumed++;
|
|
9227
10156
|
}
|
|
9228
|
-
const
|
|
9229
|
-
pos +=
|
|
9230
|
-
consumed +=
|
|
9231
|
-
while (ctx.tokens[pos]?.type === "WHITESPACE") {
|
|
9232
|
-
pos++;
|
|
9233
|
-
consumed++;
|
|
9234
|
-
}
|
|
10157
|
+
const args = collectIncludeArguments(ctx, pos);
|
|
10158
|
+
pos += args.consumed;
|
|
10159
|
+
consumed += args.consumed;
|
|
9235
10160
|
if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
|
|
9236
10161
|
return { success: false };
|
|
9237
10162
|
}
|
|
9238
10163
|
pos++;
|
|
9239
10164
|
consumed++;
|
|
10165
|
+
const directiveEnd = pos;
|
|
9240
10166
|
if (ctx.tokens[pos]?.type === "NEWLINE") {
|
|
9241
10167
|
pos++;
|
|
9242
10168
|
consumed++;
|
|
9243
10169
|
}
|
|
9244
|
-
|
|
9245
|
-
const latexSource = contentResult.latexSource.trim();
|
|
9246
|
-
consumed += contentResult.consumed;
|
|
9247
|
-
pos += contentResult.consumed;
|
|
9248
|
-
if (!contentResult.foundClose) {
|
|
9249
|
-
ctx.diagnostics.push({
|
|
9250
|
-
severity: "warning",
|
|
9251
|
-
code: "unclosed-block",
|
|
9252
|
-
message: "Missing closing tag [[/math]] for [[math]]",
|
|
9253
|
-
position: openToken.position
|
|
9254
|
-
});
|
|
9255
|
-
} else {
|
|
9256
|
-
const closeConsumed = consumeMathClose(ctx, pos);
|
|
9257
|
-
pos += closeConsumed;
|
|
9258
|
-
consumed += closeConsumed;
|
|
9259
|
-
}
|
|
9260
|
-
if (!latexSource) {
|
|
10170
|
+
if (!args.target) {
|
|
9261
10171
|
return { success: false };
|
|
9262
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
|
+
}
|
|
9263
10187
|
return {
|
|
9264
10188
|
success: true,
|
|
9265
10189
|
elements: [
|
|
9266
10190
|
{
|
|
9267
|
-
element: "
|
|
10191
|
+
element: "include",
|
|
9268
10192
|
data: {
|
|
9269
|
-
|
|
9270
|
-
|
|
10193
|
+
"paragraph-safe": false,
|
|
10194
|
+
variables: parseVariables(args.argumentTokens),
|
|
10195
|
+
location,
|
|
10196
|
+
elements: []
|
|
9271
10197
|
}
|
|
9272
10198
|
}
|
|
9273
10199
|
],
|
|
@@ -10137,7 +11063,8 @@ function parseBibliographyContent(ctx, startPos) {
|
|
|
10137
11063
|
const inlineCtx = { ...ctx, pos };
|
|
10138
11064
|
const result = parseInlineUntil(inlineCtx, "NEWLINE");
|
|
10139
11065
|
if (result.elements.length > 0) {
|
|
10140
|
-
|
|
11066
|
+
for (const element of result.elements)
|
|
11067
|
+
content.push(element);
|
|
10141
11068
|
pos += result.consumed;
|
|
10142
11069
|
consumed += result.consumed;
|
|
10143
11070
|
} else {
|
|
@@ -10566,6 +11493,7 @@ var blockRules = [
|
|
|
10566
11493
|
iftagsRule,
|
|
10567
11494
|
bibliographyRule,
|
|
10568
11495
|
galleryRule,
|
|
11496
|
+
noteRule,
|
|
10569
11497
|
divRule
|
|
10570
11498
|
];
|
|
10571
11499
|
// packages/parser/src/parser/rules/inline/formatting/close.ts
|
|
@@ -10578,6 +11506,11 @@ function findFormattingClose(ctx, start, marker) {
|
|
|
10578
11506
|
return null;
|
|
10579
11507
|
if (!table && token5.type === "NEWLINE" && getParagraphNewlineBoundary(ctx, pos, true).shouldBreak)
|
|
10580
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
|
+
}
|
|
10581
11514
|
if (token5.type === marker && !table?.suppressedClosers.has(pos))
|
|
10582
11515
|
return pos;
|
|
10583
11516
|
const protectedEnd = protectedInlineRegionEnd(ctx.tokens, pos, end);
|
|
@@ -10623,253 +11556,93 @@ function parseDelimitedContainer(ctx, closeToken, type, options = {}) {
|
|
|
10623
11556
|
consumed
|
|
10624
11557
|
};
|
|
10625
11558
|
}
|
|
10626
|
-
return {
|
|
10627
|
-
success: true,
|
|
10628
|
-
elements: [createInlineContainer(type, result.elements)],
|
|
10629
|
-
consumed
|
|
10630
|
-
};
|
|
10631
|
-
}
|
|
10632
|
-
|
|
10633
|
-
// packages/parser/src/parser/rules/inline/bold.ts
|
|
10634
|
-
var boldRule = {
|
|
10635
|
-
name: "bold",
|
|
10636
|
-
startTokens: ["BOLD_MARKER"],
|
|
10637
|
-
parse(ctx) {
|
|
10638
|
-
return parseDelimitedContainer(ctx, "BOLD_MARKER", "bold", { discardEmpty: true });
|
|
10639
|
-
}
|
|
10640
|
-
};
|
|
10641
|
-
|
|
10642
|
-
// packages/parser/src/parser/rules/inline/italic.ts
|
|
10643
|
-
var italicRule = {
|
|
10644
|
-
name: "italic",
|
|
10645
|
-
startTokens: ["ITALIC_MARKER"],
|
|
10646
|
-
parse(ctx) {
|
|
10647
|
-
return parseDelimitedContainer(ctx, "ITALIC_MARKER", "italics");
|
|
10648
|
-
}
|
|
10649
|
-
};
|
|
10650
|
-
|
|
10651
|
-
// packages/parser/src/parser/rules/inline/underline/index.ts
|
|
10652
|
-
var underlineRule = {
|
|
10653
|
-
name: "underline",
|
|
10654
|
-
startTokens: ["UNDERLINE_MARKER"],
|
|
10655
|
-
parse(ctx) {
|
|
10656
|
-
return parseDelimitedContainer(ctx, "UNDERLINE_MARKER", "underline", { discardEmpty: true });
|
|
10657
|
-
}
|
|
10658
|
-
};
|
|
10659
|
-
|
|
10660
|
-
// packages/parser/src/parser/rules/inline/strikethrough/parse.ts
|
|
10661
|
-
function parseStrikethroughContent(ctx) {
|
|
10662
|
-
return parseDelimitedContainer(ctx, "STRIKE_MARKER", "strikethrough");
|
|
10663
|
-
}
|
|
10664
|
-
|
|
10665
|
-
// packages/parser/src/parser/rules/inline/strikethrough/syntax.ts
|
|
10666
|
-
function hasValidStrikethroughClose(ctx) {
|
|
10667
|
-
const close = findFormattingClose(ctx, ctx.pos + 1, "STRIKE_MARKER");
|
|
10668
|
-
return close !== null && close > ctx.pos + 1 && ctx.tokens[close - 1]?.type !== "WHITESPACE";
|
|
10669
|
-
}
|
|
10670
|
-
|
|
10671
|
-
// packages/parser/src/parser/rules/inline/strikethrough/index.ts
|
|
10672
|
-
var strikethroughRule = {
|
|
10673
|
-
name: "strikethrough",
|
|
10674
|
-
startTokens: ["STRIKE_MARKER"],
|
|
10675
|
-
parse(ctx) {
|
|
10676
|
-
if (!hasValidStrikethroughClose(ctx)) {
|
|
10677
|
-
return {
|
|
10678
|
-
success: true,
|
|
10679
|
-
elements: [{ element: "text", data: "—" }],
|
|
10680
|
-
consumed: 1
|
|
10681
|
-
};
|
|
10682
|
-
}
|
|
10683
|
-
return parseStrikethroughContent(ctx);
|
|
10684
|
-
}
|
|
10685
|
-
};
|
|
10686
|
-
|
|
10687
|
-
// packages/parser/src/parser/rules/inline/superscript.ts
|
|
10688
|
-
var superscriptRule = {
|
|
10689
|
-
name: "superscript",
|
|
10690
|
-
startTokens: ["SUPER_MARKER"],
|
|
10691
|
-
parse(ctx) {
|
|
10692
|
-
return parseDelimitedContainer(ctx, "SUPER_MARKER", "superscript", {
|
|
10693
|
-
discardEmpty: true
|
|
10694
|
-
});
|
|
10695
|
-
}
|
|
10696
|
-
};
|
|
10697
|
-
|
|
10698
|
-
// packages/parser/src/parser/rules/inline/subscript.ts
|
|
10699
|
-
var subscriptRule = {
|
|
10700
|
-
name: "subscript",
|
|
10701
|
-
startTokens: ["SUB_MARKER"],
|
|
10702
|
-
parse(ctx) {
|
|
10703
|
-
return parseDelimitedContainer(ctx, "SUB_MARKER", "subscript", { discardEmpty: true });
|
|
10704
|
-
}
|
|
10705
|
-
};
|
|
10706
|
-
|
|
10707
|
-
// packages/parser/src/parser/rules/inline/monospace.ts
|
|
10708
|
-
var monospaceRule = {
|
|
10709
|
-
name: "monospace",
|
|
10710
|
-
startTokens: ["MONO_MARKER"],
|
|
10711
|
-
parse(ctx) {
|
|
10712
|
-
return parseDelimitedContainer(ctx, "MONO_CLOSE", "monospace");
|
|
10713
|
-
}
|
|
10714
|
-
};
|
|
10715
|
-
|
|
10716
|
-
// packages/parser/src/parser/rules/inline/link-triple/fallback.ts
|
|
10717
|
-
function literalOpenLink(value) {
|
|
10718
|
-
return {
|
|
10719
|
-
success: true,
|
|
10720
|
-
elements: [{ element: "text", data: value }],
|
|
10721
|
-
consumed: 1
|
|
10722
|
-
};
|
|
10723
|
-
}
|
|
10724
|
-
|
|
10725
|
-
// packages/parser/src/parser/rules/inline/link-triple/label.ts
|
|
10726
|
-
function buildTripleLinkLabel(args) {
|
|
10727
|
-
return {
|
|
10728
|
-
text: getTripleLinkDisplayText(args)
|
|
10729
|
-
};
|
|
10730
|
-
}
|
|
10731
|
-
function getTripleLinkDisplayText(args) {
|
|
10732
|
-
const trimmedLabel = args.labelText.trim();
|
|
10733
|
-
if (args.foundPipe) {
|
|
10734
|
-
return trimmedLabel || args.finalTarget;
|
|
10735
|
-
}
|
|
10736
|
-
const colonIdx = args.originalTarget.indexOf(":");
|
|
10737
|
-
if (colonIdx !== -1 && !args.originalTarget.startsWith("http") && !args.originalTarget.startsWith("*")) {
|
|
10738
|
-
return args.originalTarget.slice(colonIdx + 1).trim();
|
|
10739
|
-
}
|
|
10740
|
-
return args.originalTarget;
|
|
10741
|
-
}
|
|
10742
|
-
|
|
10743
|
-
// packages/parser/src/parser/rules/inline/link-triple/syntax.ts
|
|
10744
|
-
function hasClosingLinkMarker(ctx, startPos) {
|
|
10745
|
-
let pos = startPos;
|
|
10746
|
-
while (pos < ctx.tokens.length) {
|
|
10747
|
-
const token5 = ctx.tokens[pos];
|
|
10748
|
-
if (!token5 || token5.type === "EOF") {
|
|
10749
|
-
return false;
|
|
10750
|
-
}
|
|
10751
|
-
if (token5.type === "LINK_CLOSE") {
|
|
10752
|
-
return true;
|
|
10753
|
-
}
|
|
10754
|
-
if (token5.type === "NEWLINE") {
|
|
10755
|
-
const next = ctx.tokens[pos + 1];
|
|
10756
|
-
if (next?.type === "NEWLINE" || next?.type === "LINK_CLOSE") {
|
|
10757
|
-
return false;
|
|
10758
|
-
}
|
|
10759
|
-
}
|
|
10760
|
-
pos++;
|
|
10761
|
-
}
|
|
10762
|
-
return false;
|
|
10763
|
-
}
|
|
10764
|
-
function collectTripleLinkParts(ctx, startPos) {
|
|
10765
|
-
let target = "";
|
|
10766
|
-
let labelText = "";
|
|
10767
|
-
let foundPipe = false;
|
|
10768
|
-
let consumed = 1;
|
|
10769
|
-
let pos = startPos;
|
|
10770
|
-
while (pos < ctx.tokens.length) {
|
|
10771
|
-
const token5 = ctx.tokens[pos];
|
|
10772
|
-
if (!token5 || token5.type === "LINK_CLOSE" || token5.type === "EOF") {
|
|
10773
|
-
break;
|
|
10774
|
-
}
|
|
10775
|
-
if (token5.type === "NEWLINE") {
|
|
10776
|
-
if (foundPipe) {
|
|
10777
|
-
labelText += " ";
|
|
10778
|
-
} else {
|
|
10779
|
-
target += " ";
|
|
10780
|
-
}
|
|
10781
|
-
consumed++;
|
|
10782
|
-
pos++;
|
|
10783
|
-
continue;
|
|
10784
|
-
}
|
|
10785
|
-
if (token5.type === "PIPE" && !foundPipe) {
|
|
10786
|
-
foundPipe = true;
|
|
10787
|
-
} else if (foundPipe) {
|
|
10788
|
-
labelText += token5.value;
|
|
10789
|
-
} else {
|
|
10790
|
-
target += token5.value;
|
|
10791
|
-
}
|
|
10792
|
-
consumed++;
|
|
10793
|
-
pos++;
|
|
10794
|
-
}
|
|
10795
|
-
if (ctx.tokens[pos]?.type === "LINK_CLOSE") {
|
|
10796
|
-
consumed++;
|
|
10797
|
-
}
|
|
10798
|
-
return { target, labelText, foundPipe, consumed };
|
|
11559
|
+
return {
|
|
11560
|
+
success: true,
|
|
11561
|
+
elements: [createInlineContainer(type, result.elements)],
|
|
11562
|
+
consumed
|
|
11563
|
+
};
|
|
10799
11564
|
}
|
|
10800
11565
|
|
|
10801
|
-
// packages/parser/src/parser/rules/inline/
|
|
10802
|
-
var
|
|
10803
|
-
|
|
10804
|
-
|
|
10805
|
-
|
|
10806
|
-
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 });
|
|
10807
11572
|
}
|
|
10808
|
-
|
|
10809
|
-
return INTERWIKI_PREFIXES.has(prefix);
|
|
10810
|
-
}
|
|
11573
|
+
};
|
|
10811
11574
|
|
|
10812
|
-
// packages/parser/src/parser/rules/inline/
|
|
10813
|
-
|
|
10814
|
-
|
|
10815
|
-
|
|
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");
|
|
10816
11581
|
}
|
|
10817
|
-
|
|
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");
|
|
10818
11596
|
}
|
|
10819
|
-
|
|
10820
|
-
|
|
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";
|
|
10821
11602
|
}
|
|
10822
|
-
|
|
10823
|
-
|
|
10824
|
-
|
|
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);
|
|
10825
11617
|
}
|
|
10826
|
-
|
|
10827
|
-
|
|
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
|
+
});
|
|
10828
11628
|
}
|
|
10829
|
-
|
|
10830
|
-
|
|
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 });
|
|
10831
11637
|
}
|
|
10832
|
-
|
|
10833
|
-
}
|
|
11638
|
+
};
|
|
10834
11639
|
|
|
10835
|
-
// packages/parser/src/parser/rules/inline/
|
|
10836
|
-
var
|
|
10837
|
-
name: "
|
|
10838
|
-
startTokens: ["
|
|
11640
|
+
// packages/parser/src/parser/rules/inline/monospace.ts
|
|
11641
|
+
var monospaceRule = {
|
|
11642
|
+
name: "monospace",
|
|
11643
|
+
startTokens: ["MONO_MARKER"],
|
|
10839
11644
|
parse(ctx) {
|
|
10840
|
-
|
|
10841
|
-
if (!hasClosingLinkMarker(ctx, ctx.pos + 1)) {
|
|
10842
|
-
return literalOpenLink(startToken.value);
|
|
10843
|
-
}
|
|
10844
|
-
const parts = collectTripleLinkParts(ctx, ctx.pos + 1);
|
|
10845
|
-
const trimmedTarget = parts.target.trim();
|
|
10846
|
-
if (isInvalidTripleLinkTarget(trimmedTarget, parts.foundPipe)) {
|
|
10847
|
-
return literalOpenLink(startToken.value);
|
|
10848
|
-
}
|
|
10849
|
-
const normalized = normalizeTripleLinkTarget(trimmedTarget);
|
|
10850
|
-
const { linkType, link } = determineLinkTypeAndLocation(normalized.target);
|
|
10851
|
-
const label = buildTripleLinkLabel({
|
|
10852
|
-
foundPipe: parts.foundPipe,
|
|
10853
|
-
labelText: parts.labelText,
|
|
10854
|
-
finalTarget: normalized.target,
|
|
10855
|
-
originalTarget: trimmedTarget
|
|
10856
|
-
});
|
|
10857
|
-
return {
|
|
10858
|
-
success: true,
|
|
10859
|
-
elements: [
|
|
10860
|
-
{
|
|
10861
|
-
element: "link",
|
|
10862
|
-
data: {
|
|
10863
|
-
type: linkType,
|
|
10864
|
-
link,
|
|
10865
|
-
extra: null,
|
|
10866
|
-
label,
|
|
10867
|
-
target: normalized.hasStar && linkType === "direct" ? "new-tab" : null
|
|
10868
|
-
}
|
|
10869
|
-
}
|
|
10870
|
-
],
|
|
10871
|
-
consumed: parts.consumed
|
|
10872
|
-
};
|
|
11645
|
+
return parseDelimitedContainer(ctx, "MONO_CLOSE", "monospace");
|
|
10873
11646
|
}
|
|
10874
11647
|
};
|
|
10875
11648
|
|
|
@@ -10880,7 +11653,7 @@ function normalizeAnchor(anchor) {
|
|
|
10880
11653
|
|
|
10881
11654
|
// packages/parser/src/parser/rules/inline/link-bracket/direct-url.ts
|
|
10882
11655
|
function isDirectBracketUrl(url) {
|
|
10883
|
-
return url !== "" && (url.startsWith("/") || url
|
|
11656
|
+
return url !== "" && (url.startsWith("/") || startsWithUrlScheme(url, 0));
|
|
10884
11657
|
}
|
|
10885
11658
|
|
|
10886
11659
|
// packages/parser/src/parser/rules/inline/link-bracket/parts.ts
|
|
@@ -10889,35 +11662,24 @@ function collectBracketLinkParts(ctx, startPos) {
|
|
|
10889
11662
|
return null;
|
|
10890
11663
|
}
|
|
10891
11664
|
let pos = startPos;
|
|
10892
|
-
|
|
10893
|
-
|
|
10894
|
-
while (pos <
|
|
10895
|
-
const token5 = ctx.tokens[pos];
|
|
10896
|
-
if (!token5 || token5.type === "WHITESPACE" || token5.type === "BRACKET_CLOSE" || token5.type === "NEWLINE" || token5.type === "EOF") {
|
|
10897
|
-
break;
|
|
10898
|
-
}
|
|
10899
|
-
first += token5.value;
|
|
10900
|
-
pos++;
|
|
10901
|
-
consumed++;
|
|
10902
|
-
}
|
|
10903
|
-
while (ctx.tokens[pos]?.type === "WHITESPACE") {
|
|
10904
|
-
pos++;
|
|
10905
|
-
consumed++;
|
|
10906
|
-
}
|
|
10907
|
-
let label = "";
|
|
10908
|
-
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) {
|
|
10909
11668
|
const token5 = ctx.tokens[pos];
|
|
10910
|
-
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")
|
|
10911
11670
|
break;
|
|
10912
|
-
|
|
10913
|
-
label += token5.value;
|
|
11671
|
+
values.push(token5.value);
|
|
10914
11672
|
pos++;
|
|
10915
|
-
consumed++;
|
|
10916
11673
|
}
|
|
10917
|
-
if (ctx.tokens[pos]?.type !== "BRACKET_CLOSE")
|
|
11674
|
+
if (pos >= end || ctx.tokens[pos]?.type !== "BRACKET_CLOSE")
|
|
10918
11675
|
return null;
|
|
10919
|
-
|
|
10920
|
-
|
|
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
|
+
};
|
|
10921
11683
|
}
|
|
10922
11684
|
|
|
10923
11685
|
// packages/parser/src/parser/rules/inline/link-bracket/prefix.ts
|
|
@@ -10928,6 +11690,14 @@ function parseBracketLinkPrefix(ctx, startPos) {
|
|
|
10928
11690
|
return { target: null, bodyStart: startPos, consumed: 0 };
|
|
10929
11691
|
}
|
|
10930
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
|
+
|
|
10931
11701
|
// packages/parser/src/parser/rules/inline/link-bracket/parsed.ts
|
|
10932
11702
|
function parseSingleBracketLink(ctx) {
|
|
10933
11703
|
const prefix = parseBracketLinkPrefix(ctx, ctx.pos + 1);
|
|
@@ -10936,17 +11706,20 @@ function parseSingleBracketLink(ctx) {
|
|
|
10936
11706
|
return null;
|
|
10937
11707
|
}
|
|
10938
11708
|
const link = parts.first.trim();
|
|
10939
|
-
|
|
11709
|
+
const email = isBracketEmail(link);
|
|
11710
|
+
const wikiPage = wikipediaPage(link);
|
|
11711
|
+
if (!email && wikiPage === null && !isDirectBracketUrl(link)) {
|
|
10940
11712
|
return null;
|
|
10941
11713
|
}
|
|
10942
|
-
const labelText = parts.label.trim();
|
|
11714
|
+
const labelText = parts.label.trim() || wikiPage;
|
|
10943
11715
|
if (!labelText) {
|
|
10944
11716
|
return null;
|
|
10945
11717
|
}
|
|
10946
11718
|
return {
|
|
10947
|
-
link,
|
|
11719
|
+
link: email ? `mailto:${link}` : link,
|
|
11720
|
+
interwiki: wikiPage !== null,
|
|
10948
11721
|
labelText,
|
|
10949
|
-
target: prefix.target,
|
|
11722
|
+
target: wikiPage !== null ? "new-tab" : prefix.target,
|
|
10950
11723
|
consumed: 1 + prefix.consumed + parts.consumed
|
|
10951
11724
|
};
|
|
10952
11725
|
}
|
|
@@ -10999,7 +11772,7 @@ var linkSingleRule = {
|
|
|
10999
11772
|
{
|
|
11000
11773
|
element: "link",
|
|
11001
11774
|
data: {
|
|
11002
|
-
type: "direct",
|
|
11775
|
+
type: parsed.interwiki ? "interwiki" : "direct",
|
|
11003
11776
|
link: parsed.link,
|
|
11004
11777
|
extra: null,
|
|
11005
11778
|
label: linkLabel,
|
|
@@ -11068,6 +11841,134 @@ var linkStarRule = {
|
|
|
11068
11841
|
}
|
|
11069
11842
|
};
|
|
11070
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
|
+
|
|
11071
11972
|
// packages/parser/src/parser/rules/inline/color/syntax.ts
|
|
11072
11973
|
function parseColorContent(ctx) {
|
|
11073
11974
|
const close = findFormattingClose(ctx, ctx.pos + 1, "COLOR_MARKER");
|
|
@@ -11154,7 +12055,7 @@ var newlineLineBreakRule = {
|
|
|
11154
12055
|
}
|
|
11155
12056
|
return {
|
|
11156
12057
|
success: true,
|
|
11157
|
-
elements: [
|
|
12058
|
+
elements: [createAutomaticLineBreak(currentTok)],
|
|
11158
12059
|
consumed: 1
|
|
11159
12060
|
};
|
|
11160
12061
|
}
|
|
@@ -11177,6 +12078,9 @@ function isValidBlockStartAfterNewline(ctx, tokenPos) {
|
|
|
11177
12078
|
if (!isBlockStartToken(token5?.type) || !token5?.lineStart) {
|
|
11178
12079
|
return false;
|
|
11179
12080
|
}
|
|
12081
|
+
if (token5.type === "LIST_BULLET" || token5.type === "LIST_NUMBER") {
|
|
12082
|
+
return ctx.tokens[tokenPos + 1]?.type === "WHITESPACE";
|
|
12083
|
+
}
|
|
11180
12084
|
if (token5.type !== "HEADING_MARKER") {
|
|
11181
12085
|
return true;
|
|
11182
12086
|
}
|
|
@@ -11434,6 +12338,9 @@ var htmlInlineRule = {
|
|
|
11434
12338
|
}
|
|
11435
12339
|
};
|
|
11436
12340
|
|
|
12341
|
+
// packages/parser/src/parser/rules/inline/raw/angle.ts
|
|
12342
|
+
import { decodeHTML } from "entities";
|
|
12343
|
+
|
|
11437
12344
|
// packages/parser/src/parser/rules/inline/raw/result.ts
|
|
11438
12345
|
function rawElement(value, consumed) {
|
|
11439
12346
|
return {
|
|
@@ -11481,7 +12388,7 @@ function parseAngleRaw(ctx) {
|
|
|
11481
12388
|
if (ctx.tokens[pos]?.type === "RAW_BLOCK_CLOSE") {
|
|
11482
12389
|
consumed++;
|
|
11483
12390
|
}
|
|
11484
|
-
return rawElement(value, consumed);
|
|
12391
|
+
return rawElement(decodeHTML(value), consumed);
|
|
11485
12392
|
}
|
|
11486
12393
|
|
|
11487
12394
|
// packages/parser/src/parser/rules/inline/raw/double-at.ts
|
|
@@ -11704,7 +12611,7 @@ function consumeSpanNewline(ctx, pos, paragraphStrip, afterBlankLine, children,
|
|
|
11704
12611
|
return { consumed: consumed2, afterBlankLine: paragraphStrip };
|
|
11705
12612
|
}
|
|
11706
12613
|
const targetChildren = paragraphStrip && afterBlankLine ? escapedChildren : children;
|
|
11707
|
-
targetChildren.push(
|
|
12614
|
+
targetChildren.push(createAutomaticLineBreak(ctx.tokens[pos]));
|
|
11708
12615
|
let consumed = 1;
|
|
11709
12616
|
let nextPos = pos + 1;
|
|
11710
12617
|
while (ctx.tokens[nextPos]?.type === "WHITESPACE" && ctx.tokens[nextPos]?.lineStart) {
|
|
@@ -11792,7 +12699,9 @@ function parseOneSpanChild(ctx, pos, targetChildren) {
|
|
|
11792
12699
|
for (const rule of getCandidateInlineRules(inlineRules, token5.type)) {
|
|
11793
12700
|
const result = rule.parse(inlineCtx);
|
|
11794
12701
|
if (result.success) {
|
|
11795
|
-
targetChildren
|
|
12702
|
+
stripAutomaticLineBreak(targetChildren, result.stripLeadingLineBreak);
|
|
12703
|
+
for (const element of result.elements)
|
|
12704
|
+
targetChildren.push(element);
|
|
11796
12705
|
return { consumed: result.consumed };
|
|
11797
12706
|
}
|
|
11798
12707
|
}
|
|
@@ -11860,6 +12769,48 @@ var closeSpanRule = {
|
|
|
11860
12769
|
}
|
|
11861
12770
|
};
|
|
11862
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
|
+
|
|
11863
12814
|
// packages/parser/src/parser/rules/inline/size/content.ts
|
|
11864
12815
|
function parseSizeContent(ctx, startPos) {
|
|
11865
12816
|
const children = [];
|
|
@@ -11881,7 +12832,8 @@ function parseSizeContent(ctx, startPos) {
|
|
|
11881
12832
|
const inlineCtx = { ...ctx, pos };
|
|
11882
12833
|
const inlineResult = parseInlineUntil(inlineCtx, "BLOCK_END_OPEN");
|
|
11883
12834
|
if (inlineResult.elements.length > 0) {
|
|
11884
|
-
|
|
12835
|
+
for (const element of inlineResult.elements)
|
|
12836
|
+
children.push(element);
|
|
11885
12837
|
pos += inlineResult.consumed;
|
|
11886
12838
|
consumed += inlineResult.consumed;
|
|
11887
12839
|
} else {
|
|
@@ -11910,6 +12862,16 @@ function tryConsumeSizeClose(ctx, pos) {
|
|
|
11910
12862
|
|
|
11911
12863
|
// packages/parser/src/parser/rules/inline/size/value.ts
|
|
11912
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
|
+
];
|
|
11913
12875
|
function parseSizeValue(ctx, startPos) {
|
|
11914
12876
|
let pos = startPos;
|
|
11915
12877
|
let consumed = 0;
|
|
@@ -11934,6 +12896,8 @@ function parseSizeValue(ctx, startPos) {
|
|
|
11934
12896
|
return isValidSizeValue(size) ? { size, consumed } : null;
|
|
11935
12897
|
}
|
|
11936
12898
|
function isValidSizeValue(size) {
|
|
12899
|
+
if (VALID_SIZE_KEYWORDS.includes(size))
|
|
12900
|
+
return true;
|
|
11937
12901
|
const unitPattern = VALID_SIZE_UNITS.join("|");
|
|
11938
12902
|
return new RegExp(`^(\\d+(?:\\.\\d+)?)(${unitPattern})$`, "i").test(size);
|
|
11939
12903
|
}
|
|
@@ -12005,19 +12969,6 @@ var sizeRule = {
|
|
|
12005
12969
|
}
|
|
12006
12970
|
};
|
|
12007
12971
|
|
|
12008
|
-
// packages/parser/src/parser/rules/inline/footnote/child.ts
|
|
12009
|
-
function parseFootnoteChild(ctx, pos) {
|
|
12010
|
-
const token5 = ctx.tokens[pos];
|
|
12011
|
-
if (!token5) {
|
|
12012
|
-
return { elements: [], consumed: 0 };
|
|
12013
|
-
}
|
|
12014
|
-
const inlineResult = parseInlineUntil({ ...ctx, pos }, "BLOCK_END_OPEN");
|
|
12015
|
-
if (inlineResult.elements.length > 0) {
|
|
12016
|
-
return { elements: inlineResult.elements, consumed: inlineResult.consumed };
|
|
12017
|
-
}
|
|
12018
|
-
return { elements: [{ element: "text", data: token5.value }], consumed: 1 };
|
|
12019
|
-
}
|
|
12020
|
-
|
|
12021
12972
|
// packages/parser/src/parser/rules/inline/footnote/close.ts
|
|
12022
12973
|
function tryConsumeFootnoteClose(ctx, pos) {
|
|
12023
12974
|
if (ctx.tokens[pos]?.type !== "BLOCK_END_OPEN") {
|
|
@@ -12039,96 +12990,73 @@ function tryConsumeFootnoteClose(ctx, pos) {
|
|
|
12039
12990
|
return { consumed };
|
|
12040
12991
|
}
|
|
12041
12992
|
|
|
12042
|
-
// packages/parser/src/parser/rules/inline/
|
|
12043
|
-
function
|
|
12044
|
-
let
|
|
12045
|
-
let consumed =
|
|
12046
|
-
|
|
12047
|
-
|
|
12048
|
-
consumed++;
|
|
12049
|
-
}
|
|
12050
|
-
if (ctx.tokens[nextPos]?.type !== "NEWLINE") {
|
|
12051
|
-
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;
|
|
12052
12999
|
}
|
|
12053
|
-
|
|
12054
|
-
|
|
13000
|
+
pos++;
|
|
13001
|
+
consumed++;
|
|
13002
|
+
while (ctx.tokens[pos]?.type === "WHITESPACE") {
|
|
13003
|
+
pos++;
|
|
12055
13004
|
consumed++;
|
|
12056
13005
|
}
|
|
12057
|
-
|
|
12058
|
-
}
|
|
12059
|
-
|
|
12060
|
-
// packages/parser/src/parser/rules/inline/footnote/content.ts
|
|
12061
|
-
function parseFootnoteContent(ctx, startPos) {
|
|
12062
|
-
const paragraphs = [[]];
|
|
12063
|
-
let currentParagraph = 0;
|
|
12064
|
-
let pos = startPos;
|
|
12065
|
-
let consumed = 0;
|
|
13006
|
+
let latexSource = "";
|
|
12066
13007
|
while (pos < ctx.tokens.length) {
|
|
12067
13008
|
const token5 = ctx.tokens[pos];
|
|
12068
|
-
if (!token5 || token5.type === "
|
|
12069
|
-
|
|
12070
|
-
}
|
|
12071
|
-
const closeResult = tryConsumeFootnoteClose(ctx, pos);
|
|
12072
|
-
if (closeResult) {
|
|
12073
|
-
return {
|
|
12074
|
-
paragraphs,
|
|
12075
|
-
consumed: consumed + closeResult.consumed,
|
|
12076
|
-
foundClose: true
|
|
12077
|
-
};
|
|
13009
|
+
if (!token5 || token5.type === "NEWLINE") {
|
|
13010
|
+
return null;
|
|
12078
13011
|
}
|
|
12079
|
-
if (token5.type === "
|
|
12080
|
-
|
|
12081
|
-
pos += newlineResult.consumed;
|
|
12082
|
-
consumed += newlineResult.consumed;
|
|
12083
|
-
if (newlineResult.paragraphBreak) {
|
|
12084
|
-
currentParagraph++;
|
|
12085
|
-
paragraphs[currentParagraph] = [];
|
|
12086
|
-
} else {
|
|
12087
|
-
paragraphs[currentParagraph].push({ element: "line-break" });
|
|
12088
|
-
}
|
|
12089
|
-
continue;
|
|
13012
|
+
if (token5.type === "TEXT" && token5.value === "$" && ctx.tokens[pos + 1]?.type === "BLOCK_CLOSE") {
|
|
13013
|
+
break;
|
|
12090
13014
|
}
|
|
12091
|
-
|
|
12092
|
-
|
|
12093
|
-
|
|
12094
|
-
|
|
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;
|
|
12095
13026
|
}
|
|
12096
|
-
return {
|
|
13027
|
+
return {
|
|
13028
|
+
latexSource: latexSource.trim(),
|
|
13029
|
+
consumed: consumed + 1
|
|
13030
|
+
};
|
|
12097
13031
|
}
|
|
12098
13032
|
|
|
12099
|
-
// packages/parser/src/parser/rules/inline/
|
|
12100
|
-
|
|
12101
|
-
|
|
12102
|
-
|
|
12103
|
-
|
|
12104
|
-
|
|
12105
|
-
|
|
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 };
|
|
12106
13041
|
}
|
|
12107
|
-
|
|
12108
|
-
|
|
12109
|
-
|
|
12110
|
-
children.push({
|
|
12111
|
-
element: "container",
|
|
12112
|
-
data: {
|
|
12113
|
-
type: "paragraph",
|
|
12114
|
-
attributes: {},
|
|
12115
|
-
elements: para
|
|
12116
|
-
}
|
|
12117
|
-
});
|
|
13042
|
+
const parsed = parseInlineMathSource(ctx, ctx.pos + 1);
|
|
13043
|
+
if (!parsed) {
|
|
13044
|
+
return { success: false };
|
|
12118
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
|
+
};
|
|
12119
13058
|
}
|
|
12120
|
-
|
|
12121
|
-
}
|
|
12122
|
-
function trimLineBreaks(elements) {
|
|
12123
|
-
const result = [...elements];
|
|
12124
|
-
while (result.length > 0 && result[0]?.element === "line-break") {
|
|
12125
|
-
result.shift();
|
|
12126
|
-
}
|
|
12127
|
-
while (result.length > 0 && result[result.length - 1]?.element === "line-break") {
|
|
12128
|
-
result.pop();
|
|
12129
|
-
}
|
|
12130
|
-
return result;
|
|
12131
|
-
}
|
|
13059
|
+
};
|
|
12132
13060
|
|
|
12133
13061
|
// packages/parser/src/parser/rules/inline/footnote/open.ts
|
|
12134
13062
|
function parseFootnoteOpen(ctx) {
|
|
@@ -12155,6 +13083,91 @@ function parseFootnoteOpen(ctx) {
|
|
|
12155
13083
|
return { bodyStart: pos, consumed };
|
|
12156
13084
|
}
|
|
12157
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
|
+
|
|
12158
13171
|
// packages/parser/src/parser/rules/inline/footnote/index.ts
|
|
12159
13172
|
var footnoteRule = {
|
|
12160
13173
|
name: "footnote",
|
|
@@ -12170,7 +13183,7 @@ var footnoteRule = {
|
|
|
12170
13183
|
}
|
|
12171
13184
|
const contentResult = parseFootnoteContent(ctx, openResult.bodyStart);
|
|
12172
13185
|
const consumed = openResult.consumed + contentResult.consumed;
|
|
12173
|
-
const children = buildFootnoteChildren(contentResult.
|
|
13186
|
+
const children = buildFootnoteChildren(contentResult.elements, contentResult.leadingParagraphBreak);
|
|
12174
13187
|
if (!contentResult.foundClose) {
|
|
12175
13188
|
ctx.diagnostics.push({
|
|
12176
13189
|
severity: "warning",
|
|
@@ -12530,11 +13543,15 @@ function parseAnchorChild(ctx, pos) {
|
|
|
12530
13543
|
if (!token5) {
|
|
12531
13544
|
return { elements: [], consumed: 0 };
|
|
12532
13545
|
}
|
|
12533
|
-
const inlineCtx = {
|
|
13546
|
+
const inlineCtx = {
|
|
13547
|
+
...ctx,
|
|
13548
|
+
pos,
|
|
13549
|
+
scope: { ...ctx.scope, suppressEmailLinks: true }
|
|
13550
|
+
};
|
|
12534
13551
|
for (const rule of getCandidateInlineRules(inlineRules, token5.type)) {
|
|
12535
13552
|
const result = rule.parse(inlineCtx);
|
|
12536
13553
|
if (result.success) {
|
|
12537
|
-
return
|
|
13554
|
+
return result;
|
|
12538
13555
|
}
|
|
12539
13556
|
}
|
|
12540
13557
|
return { elements: [{ element: "text", data: token5.value }], consumed: 1 };
|
|
@@ -12594,7 +13611,7 @@ function consumeAnchorNewline(ctx, pos, paragraphStrip, children) {
|
|
|
12594
13611
|
let consumed = 1;
|
|
12595
13612
|
let nextPos = pos + 1;
|
|
12596
13613
|
if (!paragraphStrip) {
|
|
12597
|
-
children.push(
|
|
13614
|
+
children.push(createAutomaticLineBreak(ctx.tokens[pos]));
|
|
12598
13615
|
while (ctx.tokens[nextPos]?.type === "WHITESPACE" && ctx.tokens[nextPos]?.lineStart) {
|
|
12599
13616
|
nextPos++;
|
|
12600
13617
|
consumed++;
|
|
@@ -12647,7 +13664,9 @@ function parseAnchorContent(ctx, startPos, paragraphStrip) {
|
|
|
12647
13664
|
continue;
|
|
12648
13665
|
}
|
|
12649
13666
|
const child = parseAnchorChild(ctx, pos);
|
|
12650
|
-
children
|
|
13667
|
+
stripAutomaticLineBreak(children, child.stripLeadingLineBreak);
|
|
13668
|
+
for (const element of child.elements)
|
|
13669
|
+
children.push(element);
|
|
12651
13670
|
pos += child.consumed;
|
|
12652
13671
|
consumed += child.consumed;
|
|
12653
13672
|
}
|
|
@@ -12721,75 +13740,8 @@ var anchorRule = {
|
|
|
12721
13740
|
}
|
|
12722
13741
|
}
|
|
12723
13742
|
],
|
|
12724
|
-
consumed
|
|
12725
|
-
|
|
12726
|
-
}
|
|
12727
|
-
};
|
|
12728
|
-
|
|
12729
|
-
// packages/parser/src/parser/rules/inline/math-inline/syntax.ts
|
|
12730
|
-
function parseInlineMathSource(ctx, startPos) {
|
|
12731
|
-
let pos = startPos;
|
|
12732
|
-
let consumed = 0;
|
|
12733
|
-
if (ctx.tokens[pos]?.type !== "TEXT" || ctx.tokens[pos]?.value !== "$") {
|
|
12734
|
-
return null;
|
|
12735
|
-
}
|
|
12736
|
-
pos++;
|
|
12737
|
-
consumed++;
|
|
12738
|
-
while (ctx.tokens[pos]?.type === "WHITESPACE") {
|
|
12739
|
-
pos++;
|
|
12740
|
-
consumed++;
|
|
12741
|
-
}
|
|
12742
|
-
let latexSource = "";
|
|
12743
|
-
while (pos < ctx.tokens.length) {
|
|
12744
|
-
const token5 = ctx.tokens[pos];
|
|
12745
|
-
if (!token5 || token5.type === "NEWLINE") {
|
|
12746
|
-
return null;
|
|
12747
|
-
}
|
|
12748
|
-
if (token5.type === "TEXT" && token5.value === "$" && ctx.tokens[pos + 1]?.type === "BLOCK_CLOSE") {
|
|
12749
|
-
break;
|
|
12750
|
-
}
|
|
12751
|
-
latexSource += token5.value;
|
|
12752
|
-
pos++;
|
|
12753
|
-
consumed++;
|
|
12754
|
-
}
|
|
12755
|
-
if (ctx.tokens[pos]?.type !== "TEXT" || ctx.tokens[pos]?.value !== "$") {
|
|
12756
|
-
return null;
|
|
12757
|
-
}
|
|
12758
|
-
pos++;
|
|
12759
|
-
consumed++;
|
|
12760
|
-
if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
|
|
12761
|
-
return null;
|
|
12762
|
-
}
|
|
12763
|
-
return {
|
|
12764
|
-
latexSource: latexSource.trim(),
|
|
12765
|
-
consumed: consumed + 1
|
|
12766
|
-
};
|
|
12767
|
-
}
|
|
12768
|
-
|
|
12769
|
-
// packages/parser/src/parser/rules/inline/math-inline/index.ts
|
|
12770
|
-
var mathInlineRule = {
|
|
12771
|
-
name: "math-inline",
|
|
12772
|
-
startTokens: ["BLOCK_OPEN"],
|
|
12773
|
-
parse(ctx) {
|
|
12774
|
-
const openToken = currentToken(ctx);
|
|
12775
|
-
if (openToken.type !== "BLOCK_OPEN") {
|
|
12776
|
-
return { success: false };
|
|
12777
|
-
}
|
|
12778
|
-
const parsed = parseInlineMathSource(ctx, ctx.pos + 1);
|
|
12779
|
-
if (!parsed) {
|
|
12780
|
-
return { success: false };
|
|
12781
|
-
}
|
|
12782
|
-
return {
|
|
12783
|
-
success: true,
|
|
12784
|
-
elements: [
|
|
12785
|
-
{
|
|
12786
|
-
element: "math-inline",
|
|
12787
|
-
data: {
|
|
12788
|
-
"latex-source": parsed.latexSource
|
|
12789
|
-
}
|
|
12790
|
-
}
|
|
12791
|
-
],
|
|
12792
|
-
consumed: 1 + parsed.consumed
|
|
13743
|
+
consumed,
|
|
13744
|
+
stripLeadingLineBreak: openResult.paragraphStrip ? precedingSingleNewline(ctx) : undefined
|
|
12793
13745
|
};
|
|
12794
13746
|
}
|
|
12795
13747
|
};
|
|
@@ -12900,7 +13852,9 @@ function parseInlineBranch(ctx, startPos) {
|
|
|
12900
13852
|
}
|
|
12901
13853
|
const result = rule.parse(inlineCtx);
|
|
12902
13854
|
if (result.success) {
|
|
12903
|
-
elements
|
|
13855
|
+
stripAutomaticLineBreak(elements, result.stripLeadingLineBreak);
|
|
13856
|
+
for (const element of result.elements)
|
|
13857
|
+
elements.push(element);
|
|
12904
13858
|
consumed += result.consumed;
|
|
12905
13859
|
pos += result.consumed;
|
|
12906
13860
|
matched = true;
|
|
@@ -13223,6 +14177,7 @@ var textRule = {
|
|
|
13223
14177
|
|
|
13224
14178
|
// packages/parser/src/parser/rules/inline/index.ts
|
|
13225
14179
|
var inlineRules = [
|
|
14180
|
+
emailRule,
|
|
13226
14181
|
boldRule,
|
|
13227
14182
|
italicRule,
|
|
13228
14183
|
underlineRule,
|
|
@@ -13234,6 +14189,7 @@ var inlineRules = [
|
|
|
13234
14189
|
linkSingleRule,
|
|
13235
14190
|
linkAnchorRule,
|
|
13236
14191
|
linkStarRule,
|
|
14192
|
+
autolinkRule,
|
|
13237
14193
|
colorRule,
|
|
13238
14194
|
backslashLineBreakRule,
|
|
13239
14195
|
underscoreLineBreakRule,
|
|
@@ -13243,6 +14199,9 @@ var inlineRules = [
|
|
|
13243
14199
|
rawRule,
|
|
13244
14200
|
imageRule,
|
|
13245
14201
|
embedBlockRule,
|
|
14202
|
+
buttonRule,
|
|
14203
|
+
socialRule,
|
|
14204
|
+
dateRule,
|
|
13246
14205
|
sizeRule,
|
|
13247
14206
|
footnoteRule,
|
|
13248
14207
|
spanRule,
|
|
@@ -13498,6 +14457,8 @@ function mergeSpanStripParagraphs(children) {
|
|
|
13498
14457
|
i++;
|
|
13499
14458
|
continue;
|
|
13500
14459
|
}
|
|
14460
|
+
const firstMeaningful = paraData.elements.find((child) => child.element !== "line-break" && !isWhitespaceText(child));
|
|
14461
|
+
const keepParagraph = firstMeaningful && !isSpanStripMarker(firstMeaningful);
|
|
13501
14462
|
const mergedChildren = [...paraData.elements];
|
|
13502
14463
|
i++;
|
|
13503
14464
|
while (i < expandedChildren.length) {
|
|
@@ -13510,7 +14471,8 @@ function mergeSpanStripParagraphs(children) {
|
|
|
13510
14471
|
break;
|
|
13511
14472
|
}
|
|
13512
14473
|
const hasSpanStrip = hasParagraphStripSpan(nextPara);
|
|
13513
|
-
|
|
14474
|
+
for (const element of nextParaData.elements)
|
|
14475
|
+
mergedChildren.push(element);
|
|
13514
14476
|
i++;
|
|
13515
14477
|
if (!hasSpanStrip) {
|
|
13516
14478
|
const peekNext = expandedChildren[i];
|
|
@@ -13521,7 +14483,7 @@ function mergeSpanStripParagraphs(children) {
|
|
|
13521
14483
|
}
|
|
13522
14484
|
const escapedSpans = extractEscapedSpans(mergedChildren);
|
|
13523
14485
|
removeLineBreaksAroundSpanStrip(mergedChildren);
|
|
13524
|
-
if (escapedSpans.length > 0) {
|
|
14486
|
+
if (escapedSpans.length > 0 || keepParagraph) {
|
|
13525
14487
|
if (mergedChildren.length > 0) {
|
|
13526
14488
|
result.push(paragraphElement(mergedChildren));
|
|
13527
14489
|
}
|
|
@@ -13742,50 +14704,6 @@ function cleanInternalFlags(elements) {
|
|
|
13742
14704
|
}
|
|
13743
14705
|
return removeEmptySpansAndAdjacentWhitespace(cleaned ?? elements);
|
|
13744
14706
|
}
|
|
13745
|
-
// packages/parser/src/parser/postprocess/divAdjacentParagraph.ts
|
|
13746
|
-
function isParagraphContainer2(el) {
|
|
13747
|
-
if (!el || el.element !== "container")
|
|
13748
|
-
return false;
|
|
13749
|
-
return el.data.type === "paragraph";
|
|
13750
|
-
}
|
|
13751
|
-
function isDivContainer(el) {
|
|
13752
|
-
if (!el || el.element !== "container")
|
|
13753
|
-
return false;
|
|
13754
|
-
return el.data.type === "div";
|
|
13755
|
-
}
|
|
13756
|
-
function suppressAtLevel(elements) {
|
|
13757
|
-
if (elements.length <= 1)
|
|
13758
|
-
return elements;
|
|
13759
|
-
const unwrap = Array.from({ length: elements.length }, () => false);
|
|
13760
|
-
for (let i = 0;i < elements.length; i++) {
|
|
13761
|
-
if (!isParagraphContainer2(elements[i]))
|
|
13762
|
-
continue;
|
|
13763
|
-
const prevIsDiv = i > 0 && isDivContainer(elements[i - 1]);
|
|
13764
|
-
const nextIsDiv = i < elements.length - 1 && isDivContainer(elements[i + 1]);
|
|
13765
|
-
if (prevIsDiv || nextIsDiv) {
|
|
13766
|
-
unwrap[i] = true;
|
|
13767
|
-
}
|
|
13768
|
-
}
|
|
13769
|
-
const result = [];
|
|
13770
|
-
for (let i = 0;i < elements.length; i++) {
|
|
13771
|
-
const el = elements[i];
|
|
13772
|
-
if (!el)
|
|
13773
|
-
continue;
|
|
13774
|
-
if (unwrap[i] && el.element === "container") {
|
|
13775
|
-
const inner = el.data.elements;
|
|
13776
|
-
if (i > 0 && isDivContainer(elements[i - 1])) {
|
|
13777
|
-
result.push({ element: "line-break" });
|
|
13778
|
-
}
|
|
13779
|
-
result.push(...inner);
|
|
13780
|
-
} else {
|
|
13781
|
-
result.push(el);
|
|
13782
|
-
}
|
|
13783
|
-
}
|
|
13784
|
-
return result;
|
|
13785
|
-
}
|
|
13786
|
-
function suppressDivAdjacentParagraphs(elements) {
|
|
13787
|
-
return suppressAtLevel(elements);
|
|
13788
|
-
}
|
|
13789
14707
|
// packages/parser/src/parser/parse/footnotes.ts
|
|
13790
14708
|
function containsFootnoteBlock(elements) {
|
|
13791
14709
|
let found = false;
|
|
@@ -14063,7 +14981,9 @@ function substitute(text2) {
|
|
|
14063
14981
|
result = result.replace(WHITESPACE_ONLY_LINE, "");
|
|
14064
14982
|
}
|
|
14065
14983
|
if (result.indexOf("\\\n") !== -1) {
|
|
14066
|
-
|
|
14984
|
+
const sentinels = makeUniqueSentinels(result);
|
|
14985
|
+
const { masked, placeholders } = maskRawRegions(result, sentinels);
|
|
14986
|
+
result = restorePlaceholders(masked.replace(CONCAT_LINES, String.fromCharCode(57344)), placeholders, sentinels);
|
|
14067
14987
|
}
|
|
14068
14988
|
if (result.indexOf("\t") !== -1) {
|
|
14069
14989
|
result = result.replace(TABS, " ");
|
|
@@ -14130,14 +15050,26 @@ function replaceDelimitedTypography(text2, opener, closer, leftQuote, rightQuote
|
|
|
14130
15050
|
let searchFrom = 0;
|
|
14131
15051
|
let result = "";
|
|
14132
15052
|
let lastCopied = 0;
|
|
15053
|
+
let closeIndex = -1;
|
|
15054
|
+
let newlineIndex = -1;
|
|
14133
15055
|
while (searchFrom < text2.length) {
|
|
14134
15056
|
const openIndex = text2.indexOf(opener, searchFrom);
|
|
14135
15057
|
if (openIndex === -1)
|
|
14136
15058
|
break;
|
|
14137
15059
|
const contentStart = openIndex + opener.length;
|
|
14138
|
-
|
|
15060
|
+
if (closeIndex < contentStart)
|
|
15061
|
+
closeIndex = text2.indexOf(closer, contentStart);
|
|
14139
15062
|
if (closeIndex === -1)
|
|
14140
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
|
+
}
|
|
14141
15073
|
result += text2.slice(lastCopied, openIndex);
|
|
14142
15074
|
result += leftQuote;
|
|
14143
15075
|
result += text2.slice(contentStart, closeIndex);
|
|
@@ -14148,7 +15080,12 @@ function replaceDelimitedTypography(text2, opener, closer, leftQuote, rightQuote
|
|
|
14148
15080
|
return lastCopied === 0 ? text2 : result + text2.slice(lastCopied);
|
|
14149
15081
|
}
|
|
14150
15082
|
function substitute2(text2) {
|
|
14151
|
-
|
|
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;
|
|
14152
15089
|
if (result.includes("``") && result.includes("''")) {
|
|
14153
15090
|
result = replaceDelimitedTypography(result, "``", "''", LEFT_DOUBLE_QUOTE, RIGHT_DOUBLE_QUOTE);
|
|
14154
15091
|
}
|
|
@@ -14164,7 +15101,7 @@ function substitute2(text2) {
|
|
|
14164
15101
|
if (result.includes(". . .")) {
|
|
14165
15102
|
result = replaceExactEllipsisPattern(result, ". . .");
|
|
14166
15103
|
}
|
|
14167
|
-
return result;
|
|
15104
|
+
return restorePlaceholders(result, placeholders, sentinels);
|
|
14168
15105
|
}
|
|
14169
15106
|
|
|
14170
15107
|
// packages/parser/src/parser/preprocess/index.ts
|