@wdprlib/parser 5.3.0 → 6.0.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 +2429 -1199
- package/dist/index.d.cts +95 -8
- package/dist/index.d.ts +95 -8
- package/dist/index.js +2385 -1152
- package/package.json +3 -2
- package/src/build-info.generated.ts +2 -2
- package/src/index.ts +3 -0
- package/src/lexer/lexer.ts +34 -5
- package/src/lexer/quoted-string.ts +4 -4
- package/src/lexer/syntax-actions.ts +6 -1
- package/src/lexer/text-actions.ts +15 -1
- package/src/lexer/url-schemes.ts +78 -0
- package/src/parser/constants.ts +4 -0
- package/src/parser/parse/block.ts +1 -1
- package/src/parser/postprocess/divAdjacentParagraph.ts +23 -21
- package/src/parser/postprocess/spanStrip/merge.ts +8 -2
- package/src/parser/preprocess/typography.ts +25 -3
- package/src/parser/preprocess/utils/raw-regions.ts +59 -14
- package/src/parser/preprocess/whitespace/index.ts +8 -1
- package/src/parser/rules/block/bibliography/entry-content.ts +1 -1
- package/src/parser/rules/block/block-list/bare-content.ts +3 -1
- package/src/parser/rules/block/block-list/bare-paragraph.ts +7 -2
- package/src/parser/rules/block/block-list/item-content.ts +7 -3
- package/src/parser/rules/block/block-list/li-content.ts +8 -3
- package/src/parser/rules/block/block-list/li-item.ts +1 -1
- package/src/parser/rules/block/blockquote/build.ts +1 -1
- package/src/parser/rules/block/code/boundary.ts +76 -0
- package/src/parser/rules/block/code/content.ts +11 -40
- package/src/parser/rules/block/code/index.ts +8 -31
- package/src/parser/rules/block/code/open.ts +46 -0
- package/src/parser/rules/block/definition-list/item-key.ts +1 -1
- package/src/parser/rules/block/definition-list/item-value.ts +1 -1
- package/src/parser/rules/block/div/failed.ts +2 -0
- package/src/parser/rules/block/index.ts +3 -0
- package/src/parser/rules/block/list/line.ts +6 -3
- package/src/parser/rules/block/math/boundary.ts +104 -0
- package/src/parser/rules/block/math/index.ts +17 -57
- package/src/parser/rules/block/module/index.ts +3 -2
- package/src/parser/rules/block/module/listpages/extraction/listpages.ts +5 -0
- package/src/parser/rules/block/module/listpages/extraction/query.ts +1 -0
- package/src/parser/rules/block/module/listpages/extraction/template.ts +16 -0
- package/src/parser/rules/block/module/listpages/extraction/variables.ts +1 -0
- package/src/parser/rules/block/module/listpages/index.ts +1 -0
- package/src/parser/rules/block/module/listpages/normalization/order-parent.ts +9 -1
- package/src/parser/rules/block/module/listpages/normalize.ts +1 -0
- package/src/parser/rules/block/module/listpages/parser.ts +1 -0
- package/src/parser/rules/block/module/listpages/resolve.ts +4 -2
- package/src/parser/rules/block/module/listpages/template/excerpt.ts +63 -0
- package/src/parser/rules/block/module/listpages/template/format/content.ts +0 -32
- package/src/parser/rules/block/module/listpages/template/format/index.ts +1 -1
- package/src/parser/rules/block/module/listpages/template/getters/index.ts +14 -0
- package/src/parser/rules/block/module/listpages/template/getters/parameterized.ts +3 -1
- package/src/parser/rules/block/module/listpages/template/getters/registered.ts +52 -0
- package/src/parser/rules/block/module/listpages/template/getters/simple.ts +15 -5
- package/src/parser/rules/block/module/listpages/template/literal.ts +6 -0
- package/src/parser/rules/block/module/listpages/template/syntax.ts +10 -1
- package/src/parser/rules/block/module/listpages/types/data-requirements.ts +6 -0
- package/src/parser/rules/block/module/listpages/types/external-data.ts +36 -2
- package/src/parser/rules/block/module/listpages/types/normalized-query.ts +14 -4
- package/src/parser/rules/block/module/listpages/types/query.ts +2 -0
- package/src/parser/rules/block/module/listpages/types/variables.ts +5 -0
- package/src/parser/rules/block/module/listpages/url-resolution/fields.ts +2 -0
- package/src/parser/rules/block/module/listusers/resolve.ts +2 -1
- package/src/parser/rules/block/module/mapping.ts +2 -1
- package/src/parser/rules/block/module/rate/index.ts +16 -19
- package/src/parser/rules/block/module/rate/resolve.ts +108 -0
- package/src/parser/rules/block/module/rate/types.ts +6 -16
- package/src/parser/rules/block/module/resolution/resolve-async.ts +2 -1
- package/src/parser/rules/block/module/resolve.ts +10 -8
- package/src/parser/rules/block/module/types-common.ts +4 -0
- 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 +46 -7
- 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 +32 -5
- package/src/parser/rules/inline/size/value.ts +11 -0
- package/src/parser/rules/inline/social/index.ts +17 -0
- package/src/parser/rules/inline/social/syntax.ts +40 -0
- package/src/parser/rules/inline/span/content.ts +3 -1
- package/src/parser/rules/inline/span/newline.ts +2 -1
- package/src/parser/rules/opaque-probe.ts +58 -0
- package/src/pipeline/process.ts +13 -0
- package/src/pipeline/types.ts +19 -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: "
|
|
4
|
-
sha: "
|
|
3
|
+
version: "6.0.0",
|
|
4
|
+
sha: "705ff97e22abd7bfb49d7f8f30087e6f09654c91",
|
|
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,14 @@ 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
|
-
const
|
|
2630
|
+
const preserveNewlines = endType === "EOF";
|
|
2631
|
+
const multiline = paragraphMode || preserveNewlines || FORMATTING_CLOSE_TOKENS.has(endType);
|
|
1367
2632
|
let inlineEnd = ctx.scope.inlineEnd ?? ctx.tokens.length;
|
|
1368
2633
|
if (!multiline) {
|
|
1369
2634
|
for (let end = ctx.pos;end < inlineEnd; end++) {
|
|
1370
|
-
const protectedEnd = protectedInlineRegionEnd(ctx.tokens, end, inlineEnd);
|
|
2635
|
+
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
2636
|
if (protectedEnd > end) {
|
|
1372
2637
|
end = protectedEnd - 1;
|
|
1373
2638
|
continue;
|
|
@@ -1389,232 +2654,117 @@ function parseInlineUntil(ctx, endType) {
|
|
|
1389
2654
|
const canCollectLongPlainTextRuns = ctx.tokens.length >= MIN_INLINE_TEXT_RUN_DOCUMENT_TOKENS;
|
|
1390
2655
|
while (pos < inlineEnd) {
|
|
1391
2656
|
const token5 = ctx.tokens[pos];
|
|
1392
|
-
if (!token5 || token5.type === "EOF") {
|
|
1393
|
-
break;
|
|
1394
|
-
}
|
|
1395
|
-
if (ctx.scope.blockCloseCondition) {
|
|
1396
|
-
const checkCtx = { ...ctx, pos };
|
|
1397
|
-
if (ctx.scope.blockCloseCondition(checkCtx)) {
|
|
1398
|
-
break;
|
|
1399
|
-
}
|
|
1400
|
-
}
|
|
1401
|
-
if (!multiline && token5.type === "NEWLINE") {
|
|
1402
|
-
break;
|
|
1403
|
-
}
|
|
1404
|
-
if (multiline && token5.type === "NEWLINE" && !ctx.scope.tableFormatting) {
|
|
1405
|
-
const boundary = getParagraphNewlineBoundary(ctx, pos, nodes.length > 0);
|
|
1406
|
-
if (boundary.shouldBreak) {
|
|
1407
|
-
if (boundary.preservePrecedingLineBreak) {
|
|
1408
|
-
nodes.push(createPreservedTrailingLineBreak());
|
|
1409
|
-
}
|
|
1410
|
-
consumed += boundary.consumed;
|
|
1411
|
-
break;
|
|
1412
|
-
}
|
|
1413
|
-
}
|
|
1414
|
-
if (ctx.scope.tableFormatting?.suppressedClosers.has(pos)) {
|
|
1415
|
-
pos++;
|
|
1416
|
-
consumed++;
|
|
1417
|
-
continue;
|
|
1418
|
-
}
|
|
1419
|
-
if (token5.type === endType) {
|
|
1420
|
-
break;
|
|
1421
|
-
}
|
|
1422
|
-
if (canCollectLongPlainTextRuns) {
|
|
1423
|
-
const plainTextRun = collectLongPlainTextRun(ctx, pos, endType);
|
|
1424
|
-
if (plainTextRun) {
|
|
1425
|
-
nodes.push({ element: "text", data: plainTextRun.value });
|
|
1426
|
-
consumed += plainTextRun.consumed;
|
|
1427
|
-
pos += plainTextRun.consumed;
|
|
1428
|
-
continue;
|
|
1429
|
-
}
|
|
1430
|
-
}
|
|
1431
|
-
const simpleToken = parseSimpleInlineToken(token5, ctx.tokens[pos + 1]);
|
|
1432
|
-
if (simpleToken) {
|
|
1433
|
-
nodes.push(simpleToken.element);
|
|
1434
|
-
consumed += simpleToken.consumed;
|
|
1435
|
-
pos += simpleToken.consumed;
|
|
1436
|
-
continue;
|
|
1437
|
-
}
|
|
1438
|
-
inlineCtx.pos = pos;
|
|
1439
|
-
let matched = false;
|
|
1440
|
-
for (const rule of getCandidateInlineRules(inlineRules, token5.type)) {
|
|
1441
|
-
const result = rule.parse(inlineCtx);
|
|
1442
|
-
if (result.success) {
|
|
1443
|
-
if (rule.name === "comment") {
|
|
1444
|
-
let after = pos + result.consumed;
|
|
1445
|
-
while (ctx.tokens[after]?.type === "WHITESPACE")
|
|
1446
|
-
after++;
|
|
1447
|
-
if (ctx.tokens[after]?.type === "NEWLINE" || ctx.tokens[after]?.type === "EOF") {
|
|
1448
|
-
while (nodes.at(-1)?.element === "text") {
|
|
1449
|
-
const last = nodes.at(-1);
|
|
1450
|
-
if (last.element !== "text")
|
|
1451
|
-
break;
|
|
1452
|
-
last.data = last.data.trimEnd();
|
|
1453
|
-
if (last.data)
|
|
1454
|
-
break;
|
|
1455
|
-
nodes.pop();
|
|
1456
|
-
}
|
|
1457
|
-
if (nodes.at(-1)?.element === "line-break")
|
|
1458
|
-
nodes.pop();
|
|
1459
|
-
}
|
|
1460
|
-
}
|
|
1461
|
-
nodes.push(...result.elements);
|
|
1462
|
-
consumed += result.consumed;
|
|
1463
|
-
pos += result.consumed;
|
|
1464
|
-
matched = true;
|
|
1465
|
-
break;
|
|
1466
|
-
}
|
|
1467
|
-
}
|
|
1468
|
-
if (!matched) {
|
|
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)) {
|
|
2657
|
+
if (!token5 || token5.type === "EOF") {
|
|
1567
2658
|
break;
|
|
1568
2659
|
}
|
|
1569
|
-
if (
|
|
2660
|
+
if (ctx.scope.blockCloseCondition) {
|
|
2661
|
+
const checkCtx = { ...ctx, pos };
|
|
2662
|
+
if (ctx.scope.blockCloseCondition(checkCtx)) {
|
|
2663
|
+
break;
|
|
2664
|
+
}
|
|
2665
|
+
}
|
|
2666
|
+
if (!multiline && token5.type === "NEWLINE") {
|
|
2667
|
+
break;
|
|
2668
|
+
}
|
|
2669
|
+
if (preserveNewlines && token5.type === "NEWLINE") {
|
|
2670
|
+
nodes.push({ element: "text", data: token5.value });
|
|
1570
2671
|
pos++;
|
|
1571
2672
|
consumed++;
|
|
1572
2673
|
continue;
|
|
1573
2674
|
}
|
|
1574
|
-
if (!
|
|
2675
|
+
if (multiline && token5.type === "NEWLINE" && !ctx.scope.tableFormatting) {
|
|
2676
|
+
const boundary = getParagraphNewlineBoundary(ctx, pos, nodes.length > 0);
|
|
2677
|
+
if (boundary.shouldBreak) {
|
|
2678
|
+
if (boundary.preservePrecedingLineBreak) {
|
|
2679
|
+
nodes.push(createPreservedTrailingLineBreak());
|
|
2680
|
+
}
|
|
2681
|
+
consumed += boundary.consumed;
|
|
2682
|
+
break;
|
|
2683
|
+
}
|
|
2684
|
+
}
|
|
2685
|
+
if (ctx.scope.tableFormatting?.suppressedClosers.has(pos)) {
|
|
1575
2686
|
pos++;
|
|
1576
2687
|
consumed++;
|
|
1577
2688
|
continue;
|
|
1578
2689
|
}
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
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;
|
|
2690
|
+
const hasEmail = emailRegionEnd(ctx.tokens, pos, inlineEnd) > pos;
|
|
2691
|
+
if (token5.type === endType && !hasEmail) {
|
|
2692
|
+
break;
|
|
1589
2693
|
}
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
2694
|
+
if (canCollectLongPlainTextRuns && !hasEmail) {
|
|
2695
|
+
const plainTextRun = collectLongPlainTextRun(ctx, pos, endType);
|
|
2696
|
+
if (plainTextRun) {
|
|
2697
|
+
nodes.push({ element: "text", data: plainTextRun.value });
|
|
2698
|
+
consumed += plainTextRun.consumed;
|
|
2699
|
+
pos += plainTextRun.consumed;
|
|
2700
|
+
continue;
|
|
2701
|
+
}
|
|
2702
|
+
}
|
|
2703
|
+
const simpleToken = parseSimpleInlineToken(token5, ctx.tokens[pos + 1]);
|
|
2704
|
+
if (simpleToken && !hasEmail) {
|
|
2705
|
+
nodes.push(simpleToken.element);
|
|
2706
|
+
consumed += simpleToken.consumed;
|
|
2707
|
+
pos += simpleToken.consumed;
|
|
1594
2708
|
continue;
|
|
1595
2709
|
}
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
2710
|
+
inlineCtx.pos = pos;
|
|
2711
|
+
let matched = false;
|
|
2712
|
+
for (const rule of getCandidateInlineRules(inlineRules, token5.type)) {
|
|
2713
|
+
const result = rule.parse(inlineCtx);
|
|
2714
|
+
if (result.success) {
|
|
2715
|
+
stripAutomaticLineBreak(nodes, result.stripLeadingLineBreak);
|
|
2716
|
+
if (rule.name === "raw" && result.elements.length === 0 && nodes.length === 0) {
|
|
2717
|
+
consumedEmptyRaw = true;
|
|
2718
|
+
}
|
|
2719
|
+
if (rule.name === "comment") {
|
|
2720
|
+
let after = pos + result.consumed;
|
|
2721
|
+
while (ctx.tokens[after]?.type === "WHITESPACE")
|
|
2722
|
+
after++;
|
|
2723
|
+
if (ctx.tokens[after]?.type === "NEWLINE" || ctx.tokens[after]?.type === "EOF") {
|
|
2724
|
+
while (nodes.at(-1)?.element === "text") {
|
|
2725
|
+
const last = nodes.at(-1);
|
|
2726
|
+
if (last.element !== "text")
|
|
2727
|
+
break;
|
|
2728
|
+
last.data = last.data.trimEnd();
|
|
2729
|
+
if (last.data)
|
|
2730
|
+
break;
|
|
2731
|
+
nodes.pop();
|
|
2732
|
+
}
|
|
2733
|
+
if (nodes.at(-1)?.element === "line-break")
|
|
2734
|
+
nodes.pop();
|
|
2735
|
+
}
|
|
2736
|
+
}
|
|
2737
|
+
for (const element of result.elements) {
|
|
2738
|
+
nodes.push(paragraphMode && consumedEmptyRaw && nodes.length === 0 && token5.type === "NEWLINE" && element.element === "line-break" ? createPreservedLeadingLineBreak() : element);
|
|
2739
|
+
}
|
|
2740
|
+
consumed += result.consumed;
|
|
2741
|
+
pos += result.consumed;
|
|
2742
|
+
matched = true;
|
|
2743
|
+
break;
|
|
2744
|
+
}
|
|
2745
|
+
}
|
|
2746
|
+
if (!matched) {
|
|
2747
|
+
nodes.push({ element: "text", data: token5.value });
|
|
2748
|
+
consumed++;
|
|
2749
|
+
pos++;
|
|
2750
|
+
}
|
|
1599
2751
|
}
|
|
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 });
|
|
2752
|
+
return { elements: nodes, consumed };
|
|
1613
2753
|
}
|
|
2754
|
+
var FORMATTING_CLOSE_TOKENS = new Set([
|
|
2755
|
+
"BOLD_MARKER",
|
|
2756
|
+
"ITALIC_MARKER",
|
|
2757
|
+
"UNDERLINE_MARKER",
|
|
2758
|
+
"STRIKE_MARKER",
|
|
2759
|
+
"SUPER_MARKER",
|
|
2760
|
+
"SUB_MARKER",
|
|
2761
|
+
"MONO_CLOSE",
|
|
2762
|
+
"COLOR_MARKER"
|
|
2763
|
+
]);
|
|
1614
2764
|
// packages/parser/src/parser/parse/block.ts
|
|
1615
|
-
function parseNextBlock(ctx, skipWhitespace2,
|
|
2765
|
+
function parseNextBlock(ctx, skipWhitespace2, isAtEnd3) {
|
|
1616
2766
|
skipWhitespace2();
|
|
1617
|
-
if (
|
|
2767
|
+
if (isAtEnd3()) {
|
|
1618
2768
|
return [];
|
|
1619
2769
|
}
|
|
1620
2770
|
const token5 = ctx.tokens[ctx.pos];
|
|
@@ -1633,7 +2783,7 @@ function parseNextBlock(ctx, skipWhitespace2, isAtEnd2) {
|
|
|
1633
2783
|
}
|
|
1634
2784
|
}
|
|
1635
2785
|
const result = ctx.blockFallbackRule.parse(ctx);
|
|
1636
|
-
if (result.success
|
|
2786
|
+
if (result.success) {
|
|
1637
2787
|
ctx.pos += result.consumed;
|
|
1638
2788
|
return result.elements;
|
|
1639
2789
|
}
|
|
@@ -1643,35 +2793,6 @@ function parseNextBlock(ctx, skipWhitespace2, isAtEnd2) {
|
|
|
1643
2793
|
|
|
1644
2794
|
// packages/parser/src/parser/parse/context.ts
|
|
1645
2795
|
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
2796
|
// packages/parser/src/parser/rules/block/heading/open.ts
|
|
1676
2797
|
function parseHeadingOpen(ctx) {
|
|
1677
2798
|
const marker = ctx.tokens[ctx.pos];
|
|
@@ -1917,10 +3038,11 @@ function parseNativeListLine(ctx, startPos) {
|
|
|
1917
3038
|
const ltype = markerToken.type === "LIST_BULLET" ? "bullet" : "numbered";
|
|
1918
3039
|
pos++;
|
|
1919
3040
|
consumed++;
|
|
1920
|
-
if (ctx.tokens[pos]?.type
|
|
1921
|
-
|
|
1922
|
-
consumed++;
|
|
3041
|
+
if (ctx.tokens[pos]?.type !== "WHITESPACE") {
|
|
3042
|
+
return { kind: "stop" };
|
|
1923
3043
|
}
|
|
3044
|
+
pos++;
|
|
3045
|
+
consumed++;
|
|
1924
3046
|
const inlineCtx = { ...ctx, pos };
|
|
1925
3047
|
const inlineResult = parseInlineUntil(inlineCtx, "NEWLINE");
|
|
1926
3048
|
consumed += inlineResult.consumed;
|
|
@@ -2030,9 +3152,9 @@ function appendBareParagraphElements(state, elements) {
|
|
|
2030
3152
|
function appendBareParagraphText(state, text) {
|
|
2031
3153
|
state.current.push({ element: "text", data: text });
|
|
2032
3154
|
}
|
|
2033
|
-
function appendBareParagraphLineBreakIfNeeded(state) {
|
|
3155
|
+
function appendBareParagraphLineBreakIfNeeded(state, token5) {
|
|
2034
3156
|
if (state.current.length > 0) {
|
|
2035
|
-
state.current.push(
|
|
3157
|
+
state.current.push(createAutomaticLineBreak(token5));
|
|
2036
3158
|
}
|
|
2037
3159
|
}
|
|
2038
3160
|
function flushBareParagraph(state) {
|
|
@@ -2137,7 +3259,7 @@ function parseBareListContent(ctx, startPos, listType) {
|
|
|
2137
3259
|
if (consecutiveNewlines >= 2) {
|
|
2138
3260
|
flushBareParagraph(paragraphState);
|
|
2139
3261
|
} else {
|
|
2140
|
-
appendBareParagraphLineBreakIfNeeded(paragraphState);
|
|
3262
|
+
appendBareParagraphLineBreakIfNeeded(paragraphState, token5);
|
|
2141
3263
|
}
|
|
2142
3264
|
continue;
|
|
2143
3265
|
}
|
|
@@ -2149,6 +3271,7 @@ function parseBareListContent(ctx, startPos, listType) {
|
|
|
2149
3271
|
for (const rule of getCandidateInlineRules(ctx.inlineRules, token5.type)) {
|
|
2150
3272
|
const result = rule.parse(inlineCtx);
|
|
2151
3273
|
if (result.success) {
|
|
3274
|
+
stripAutomaticLineBreak(paragraphState.current, result.stripLeadingLineBreak);
|
|
2152
3275
|
appendBareParagraphElements(paragraphState, result.elements);
|
|
2153
3276
|
consumed += result.consumed;
|
|
2154
3277
|
pos += result.consumed;
|
|
@@ -2187,7 +3310,7 @@ function parseListItemBlockContent(ctx, pos, token5) {
|
|
|
2187
3310
|
for (const rule of getCandidateBlockRules(filteredBlockRules, token5)) {
|
|
2188
3311
|
const result = rule.parse(blockCtx);
|
|
2189
3312
|
if (result.success) {
|
|
2190
|
-
return { matched: true,
|
|
3313
|
+
return { matched: true, ...result };
|
|
2191
3314
|
}
|
|
2192
3315
|
}
|
|
2193
3316
|
return { matched: false, elements: [], consumed: 0 };
|
|
@@ -2206,7 +3329,7 @@ function parseListItemInlineContent(ctx, pos, tokenType) {
|
|
|
2206
3329
|
for (const rule of getCandidateInlineRules(ctx.inlineRules, tokenType)) {
|
|
2207
3330
|
const result = rule.parse(inlineCtx);
|
|
2208
3331
|
if (result.success) {
|
|
2209
|
-
return { matched: true,
|
|
3332
|
+
return { matched: true, ...result };
|
|
2210
3333
|
}
|
|
2211
3334
|
}
|
|
2212
3335
|
return { matched: false, elements: [], consumed: 0 };
|
|
@@ -2248,7 +3371,9 @@ function collectPostLiTrailingContent(ctx, startPos, listType) {
|
|
|
2248
3371
|
}
|
|
2249
3372
|
const inlineResult = parseListItemInlineContent(ctx, pos, token5.type);
|
|
2250
3373
|
if (inlineResult.matched) {
|
|
2251
|
-
elements
|
|
3374
|
+
stripAutomaticLineBreak(elements, inlineResult.stripLeadingLineBreak);
|
|
3375
|
+
for (const element of inlineResult.elements)
|
|
3376
|
+
elements.push(element);
|
|
2252
3377
|
consumed += inlineResult.consumed;
|
|
2253
3378
|
pos += inlineResult.consumed;
|
|
2254
3379
|
continue;
|
|
@@ -2293,7 +3418,7 @@ function collectLiItemContent(ctx, startPos, listType, parseNestedList) {
|
|
|
2293
3418
|
if (token5.type === "NEWLINE") {
|
|
2294
3419
|
const newlineResult = consumeLiItemNewlines(ctx, pos, elements.length > 0);
|
|
2295
3420
|
if (newlineResult.addLineBreak) {
|
|
2296
|
-
elements.push(
|
|
3421
|
+
elements.push(createAutomaticLineBreak(token5));
|
|
2297
3422
|
}
|
|
2298
3423
|
pos += newlineResult.consumed;
|
|
2299
3424
|
consumed += newlineResult.consumed;
|
|
@@ -2301,14 +3426,17 @@ function collectLiItemContent(ctx, startPos, listType, parseNestedList) {
|
|
|
2301
3426
|
}
|
|
2302
3427
|
const blockResult = parseListItemBlockContent(ctx, pos, token5);
|
|
2303
3428
|
if (blockResult.matched) {
|
|
2304
|
-
|
|
3429
|
+
for (const element of blockResult.elements)
|
|
3430
|
+
elements.push(element);
|
|
2305
3431
|
consumed += blockResult.consumed;
|
|
2306
3432
|
pos += blockResult.consumed;
|
|
2307
3433
|
continue;
|
|
2308
3434
|
}
|
|
2309
3435
|
const inlineResult = parseListItemInlineContent(ctx, pos, token5.type);
|
|
2310
3436
|
if (inlineResult.matched) {
|
|
2311
|
-
elements
|
|
3437
|
+
stripAutomaticLineBreak(elements, inlineResult.stripLeadingLineBreak);
|
|
3438
|
+
for (const element of inlineResult.elements)
|
|
3439
|
+
elements.push(element);
|
|
2312
3440
|
consumed += inlineResult.consumed;
|
|
2313
3441
|
pos += inlineResult.consumed;
|
|
2314
3442
|
continue;
|
|
@@ -2379,7 +3507,8 @@ function parseLiItem(ctx, startPos, listType, parseNestedList) {
|
|
|
2379
3507
|
consumed += closeConsumed;
|
|
2380
3508
|
pos += closeConsumed;
|
|
2381
3509
|
const trailingResult = collectPostLiTrailingContent(ctx, pos, listType);
|
|
2382
|
-
|
|
3510
|
+
for (const element of trailingResult.elements)
|
|
3511
|
+
contentElements.push(element);
|
|
2383
3512
|
consumed += trailingResult.consumed;
|
|
2384
3513
|
}
|
|
2385
3514
|
return {
|
|
@@ -2639,7 +3768,7 @@ function sliceLineTokens(ctx, lines) {
|
|
|
2639
3768
|
for (const { start, end } of lines) {
|
|
2640
3769
|
for (let pos = start;pos < end; pos++) {
|
|
2641
3770
|
const token5 = ctx.tokens[pos];
|
|
2642
|
-
if (token5) {
|
|
3771
|
+
if (token5 && token5.type !== "BACKSLASH_BREAK") {
|
|
2643
3772
|
tokens.push(token5);
|
|
2644
3773
|
}
|
|
2645
3774
|
}
|
|
@@ -2809,7 +3938,8 @@ function parseDefinitionItemKey(ctx, startPos) {
|
|
|
2809
3938
|
const inlineCtx = { ...ctx, pos };
|
|
2810
3939
|
const result = parseInlineUntil(inlineCtx, "COLON");
|
|
2811
3940
|
if (result.elements.length > 0) {
|
|
2812
|
-
|
|
3941
|
+
for (const element of result.elements)
|
|
3942
|
+
key.push(element);
|
|
2813
3943
|
for (let i = 0;i < result.consumed; i++) {
|
|
2814
3944
|
const t = ctx.tokens[pos + i];
|
|
2815
3945
|
if (t)
|
|
@@ -2865,7 +3995,8 @@ function parseDefinitionItemValue(ctx, startPos) {
|
|
|
2865
3995
|
const inlineCtx = { ...ctx, pos };
|
|
2866
3996
|
const result = parseInlineUntil(inlineCtx, "NEWLINE");
|
|
2867
3997
|
if (result.elements.length > 0) {
|
|
2868
|
-
|
|
3998
|
+
for (const element of result.elements)
|
|
3999
|
+
value.push(element);
|
|
2869
4000
|
pos += result.consumed;
|
|
2870
4001
|
consumed += result.consumed;
|
|
2871
4002
|
} else {
|
|
@@ -2947,78 +4078,93 @@ var definitionListRule = {
|
|
|
2947
4078
|
}
|
|
2948
4079
|
};
|
|
2949
4080
|
|
|
2950
|
-
// packages/parser/src/parser/
|
|
2951
|
-
|
|
2952
|
-
|
|
4081
|
+
// packages/parser/src/parser/postprocess/divAdjacentParagraph.ts
|
|
4082
|
+
var unparsedDivStarts = new WeakSet;
|
|
4083
|
+
function markUnparsedDivStart(elements) {
|
|
4084
|
+
const first = elements[0];
|
|
4085
|
+
const text = first?.element === "container" && first.data.type === "paragraph" ? first.data.elements[0] : first;
|
|
4086
|
+
if (text?.element === "text")
|
|
4087
|
+
unparsedDivStarts.add(text);
|
|
2953
4088
|
}
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
4089
|
+
function isUnparsedDivParagraph(el) {
|
|
4090
|
+
if (!el || el.element !== "container")
|
|
4091
|
+
return false;
|
|
4092
|
+
return el.data.type === "paragraph" && el.data.elements.some((child) => unparsedDivStarts.has(child));
|
|
4093
|
+
}
|
|
4094
|
+
function isDivContainer(el) {
|
|
4095
|
+
if (!el || el.element !== "container")
|
|
4096
|
+
return false;
|
|
4097
|
+
return el.data.type === "div";
|
|
4098
|
+
}
|
|
4099
|
+
function suppressAtLevel(elements) {
|
|
4100
|
+
if (elements.length <= 1)
|
|
4101
|
+
return elements;
|
|
4102
|
+
const unwrap = Array.from({ length: elements.length }, () => false);
|
|
2958
4103
|
for (let i = 0;i < elements.length; i++) {
|
|
2959
|
-
|
|
2960
|
-
if (!elem)
|
|
4104
|
+
if (!isUnparsedDivParagraph(elements[i]))
|
|
2961
4105
|
continue;
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
});
|
|
4106
|
+
const prevIsDiv = i > 0 && isDivContainer(elements[i - 1]);
|
|
4107
|
+
const nextIsDiv = i < elements.length - 1 && isDivContainer(elements[i + 1]);
|
|
4108
|
+
if (prevIsDiv || nextIsDiv) {
|
|
4109
|
+
unwrap[i] = true;
|
|
4110
|
+
}
|
|
4111
|
+
}
|
|
4112
|
+
const result = [];
|
|
4113
|
+
for (let i = 0;i < elements.length; i++) {
|
|
4114
|
+
const el = elements[i];
|
|
4115
|
+
if (!el)
|
|
4116
|
+
continue;
|
|
4117
|
+
if (unwrap[i] && el.element === "container") {
|
|
4118
|
+
const inner = el.data.elements;
|
|
4119
|
+
if (i > 0 && isDivContainer(elements[i - 1])) {
|
|
4120
|
+
result.push({ element: "line-break" });
|
|
2977
4121
|
}
|
|
4122
|
+
result.push(...inner);
|
|
2978
4123
|
} else {
|
|
2979
|
-
result
|
|
4124
|
+
result.push(el);
|
|
2980
4125
|
}
|
|
2981
4126
|
}
|
|
2982
|
-
return result
|
|
4127
|
+
return result;
|
|
2983
4128
|
}
|
|
2984
|
-
function
|
|
2985
|
-
return
|
|
4129
|
+
function suppressDivAdjacentParagraphs(elements) {
|
|
4130
|
+
return suppressAtLevel(elements);
|
|
2986
4131
|
}
|
|
2987
4132
|
|
|
2988
|
-
// packages/parser/src/parser/rules/block/
|
|
2989
|
-
function
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
return
|
|
4133
|
+
// packages/parser/src/parser/rules/block/div/close.ts
|
|
4134
|
+
function isDivClose(ctx) {
|
|
4135
|
+
const token5 = ctx.tokens[ctx.pos];
|
|
4136
|
+
if (token5?.type !== "BLOCK_END_OPEN")
|
|
4137
|
+
return false;
|
|
4138
|
+
const closeNameResult = parseBlockName(ctx, ctx.pos + 1);
|
|
4139
|
+
return closeNameResult?.name === "div";
|
|
2995
4140
|
}
|
|
2996
|
-
function
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
break;
|
|
3002
|
-
}
|
|
3003
|
-
elements.pop();
|
|
4141
|
+
function consumeDivClose(ctx, startPos) {
|
|
4142
|
+
let pos = startPos;
|
|
4143
|
+
let consumed = 0;
|
|
4144
|
+
if (ctx.tokens[pos]?.type !== "BLOCK_END_OPEN") {
|
|
4145
|
+
return { pos, consumed };
|
|
3004
4146
|
}
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
4147
|
+
pos++;
|
|
4148
|
+
consumed++;
|
|
4149
|
+
const closeNameResult = parseBlockName(ctx, pos);
|
|
4150
|
+
if (closeNameResult) {
|
|
4151
|
+
pos += closeNameResult.consumed;
|
|
4152
|
+
consumed += closeNameResult.consumed;
|
|
4153
|
+
}
|
|
4154
|
+
if (ctx.tokens[pos]?.type === "BLOCK_CLOSE") {
|
|
4155
|
+
pos++;
|
|
4156
|
+
consumed++;
|
|
3014
4157
|
}
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
while (first < elements.length && elements[first]?.element === "line-break") {
|
|
3019
|
-
first++;
|
|
4158
|
+
if (ctx.tokens[pos]?.type === "NEWLINE") {
|
|
4159
|
+
pos++;
|
|
4160
|
+
consumed++;
|
|
3020
4161
|
}
|
|
3021
|
-
return
|
|
4162
|
+
return { pos, consumed };
|
|
4163
|
+
}
|
|
4164
|
+
|
|
4165
|
+
// packages/parser/src/parser/rules/block/paragraph/content.ts
|
|
4166
|
+
function parseInlineContent(ctx) {
|
|
4167
|
+
return parseInlineUntil(ctx, "PARAGRAPH_BREAK");
|
|
3022
4168
|
}
|
|
3023
4169
|
|
|
3024
4170
|
// packages/parser/src/parser/rules/block/paragraph/index.ts
|
|
@@ -3028,25 +4174,30 @@ var paragraphRule = {
|
|
|
3028
4174
|
requiresLineStart: false,
|
|
3029
4175
|
parse(ctx) {
|
|
3030
4176
|
const result = parseInlineContent(ctx);
|
|
3031
|
-
if (result.
|
|
4177
|
+
if (result.consumed === 0) {
|
|
3032
4178
|
return { success: false };
|
|
3033
4179
|
}
|
|
3034
4180
|
const elements = normalizeParagraphElements(result.elements);
|
|
3035
4181
|
if (elements.length === 0) {
|
|
3036
|
-
return { success:
|
|
4182
|
+
return { success: true, elements: [], consumed: result.consumed };
|
|
3037
4183
|
}
|
|
3038
4184
|
const nextPos = ctx.pos + result.consumed;
|
|
3039
4185
|
const nextToken = ctx.tokens[nextPos];
|
|
3040
4186
|
if (nextToken?.type === "COLON" && nextToken.lineStart) {
|
|
4187
|
+
if (isPreservedLeadingLineBreak(elements[0]))
|
|
4188
|
+
elements[0] = { element: "line-break" };
|
|
3041
4189
|
return {
|
|
3042
4190
|
success: true,
|
|
3043
4191
|
elements: [...elements, { element: "line-break" }],
|
|
3044
4192
|
consumed: result.consumed
|
|
3045
4193
|
};
|
|
3046
4194
|
}
|
|
4195
|
+
const wrapped = wrapParagraphElements(elements);
|
|
4196
|
+
if (isDivClose(ctx))
|
|
4197
|
+
markUnparsedDivStart(wrapped);
|
|
3047
4198
|
return {
|
|
3048
4199
|
success: true,
|
|
3049
|
-
elements:
|
|
4200
|
+
elements: wrapped,
|
|
3050
4201
|
consumed: result.consumed
|
|
3051
4202
|
};
|
|
3052
4203
|
}
|
|
@@ -3057,7 +4208,7 @@ function wrapParagraphElements(elements) {
|
|
|
3057
4208
|
let bare = false;
|
|
3058
4209
|
const flush = (trimBreaks = false) => {
|
|
3059
4210
|
const content = trimBreaks ? normalizeParagraphElements(group) : group;
|
|
3060
|
-
while (content[0]?.element === "line-break")
|
|
4211
|
+
while (content[0]?.element === "line-break" && !isPreservedLeadingLineBreak(content[0]))
|
|
3061
4212
|
content.shift();
|
|
3062
4213
|
while (content.length) {
|
|
3063
4214
|
const last = content.at(-1);
|
|
@@ -3069,6 +4220,8 @@ function wrapParagraphElements(elements) {
|
|
|
3069
4220
|
content.shift();
|
|
3070
4221
|
if (content[0]?.element === "text")
|
|
3071
4222
|
content[0] = { element: "text", data: content[0].data.trimStart() };
|
|
4223
|
+
if (isPreservedLeadingLineBreak(content[0]))
|
|
4224
|
+
content[0] = { element: "line-break" };
|
|
3072
4225
|
if (content.length)
|
|
3073
4226
|
output.push(...bare || content.some((el) => el.element === "image") ? content : [
|
|
3074
4227
|
{
|
|
@@ -3090,37 +4243,36 @@ function wrapParagraphElements(elements) {
|
|
|
3090
4243
|
return output;
|
|
3091
4244
|
}
|
|
3092
4245
|
|
|
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
|
-
|
|
4246
|
+
// packages/parser/src/parser/rules/block/note/index.ts
|
|
4247
|
+
var excludedBlockNames = new Set(["note"]);
|
|
4248
|
+
var noteRule = {
|
|
4249
|
+
name: "note",
|
|
4250
|
+
startTokens: ["BLOCK_OPEN"],
|
|
4251
|
+
requiresLineStart: false,
|
|
4252
|
+
parse(ctx) {
|
|
4253
|
+
const bounds = findNoteBounds(ctx);
|
|
4254
|
+
if (!bounds)
|
|
4255
|
+
return { success: false };
|
|
4256
|
+
const body = parseBlocksUntil({
|
|
4257
|
+
...ctx,
|
|
4258
|
+
tokens: ctx.tokens.slice(bounds.bodyStart, bounds.close),
|
|
4259
|
+
pos: 0,
|
|
4260
|
+
scope: {
|
|
4261
|
+
...ctx.scope,
|
|
4262
|
+
inlineEnd: undefined,
|
|
4263
|
+
tableFormatting: undefined,
|
|
4264
|
+
blockCloseCondition: undefined
|
|
4265
|
+
}
|
|
4266
|
+
}, () => false, { excludedBlockNames });
|
|
4267
|
+
return {
|
|
4268
|
+
success: true,
|
|
4269
|
+
consumed: bounds.end - ctx.pos,
|
|
4270
|
+
elements: [
|
|
4271
|
+
{ element: "container", data: { type: "note", attributes: {}, elements: body.elements } }
|
|
4272
|
+
]
|
|
4273
|
+
};
|
|
3121
4274
|
}
|
|
3122
|
-
|
|
3123
|
-
}
|
|
4275
|
+
};
|
|
3124
4276
|
|
|
3125
4277
|
// packages/parser/src/parser/rules/block/div/nesting.ts
|
|
3126
4278
|
var divCloseCountCache = new WeakMap;
|
|
@@ -3289,6 +4441,7 @@ function consumeFailedDiv(ctx) {
|
|
|
3289
4441
|
pos++;
|
|
3290
4442
|
consumed++;
|
|
3291
4443
|
}
|
|
4444
|
+
markUnparsedDivStart(elements);
|
|
3292
4445
|
return {
|
|
3293
4446
|
success: true,
|
|
3294
4447
|
elements: [
|
|
@@ -3400,126 +4553,6 @@ var divRule = {
|
|
|
3400
4553
|
}
|
|
3401
4554
|
};
|
|
3402
4555
|
|
|
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
4556
|
// packages/parser/src/parser/rules/block/collapsible/attributes.ts
|
|
3524
4557
|
function parseMultilineAttributes(ctx, startPos) {
|
|
3525
4558
|
const attrs = {};
|
|
@@ -3948,7 +4981,9 @@ function parseTableCell(ctx, startPos, cellStart) {
|
|
|
3948
4981
|
for (const rule of getCandidateInlineRules(inlineRules, token5.type)) {
|
|
3949
4982
|
const result = rule.parse(inlineCtx);
|
|
3950
4983
|
if (result.success) {
|
|
3951
|
-
children
|
|
4984
|
+
stripAutomaticLineBreak(children, result.stripLeadingLineBreak);
|
|
4985
|
+
for (const element of result.elements)
|
|
4986
|
+
children.push(element);
|
|
3952
4987
|
consumed += result.consumed;
|
|
3953
4988
|
pos += result.consumed;
|
|
3954
4989
|
matched = true;
|
|
@@ -4215,7 +5250,8 @@ function createCellContentAccumulator() {
|
|
|
4215
5250
|
addInline(element) {
|
|
4216
5251
|
currentSegment.push(element);
|
|
4217
5252
|
},
|
|
4218
|
-
addInlineElements(nextElements) {
|
|
5253
|
+
addInlineElements(nextElements, stripLeadingLineBreak) {
|
|
5254
|
+
stripAutomaticLineBreak(currentSegment, stripLeadingLineBreak);
|
|
4219
5255
|
currentSegment.push(...nextElements);
|
|
4220
5256
|
},
|
|
4221
5257
|
addBlockElements(blockElements) {
|
|
@@ -4315,7 +5351,7 @@ function consumeCellContentNewline(ctx, startPos, content) {
|
|
|
4315
5351
|
return { consumed };
|
|
4316
5352
|
}
|
|
4317
5353
|
if (!content.isEmpty()) {
|
|
4318
|
-
content.addInline(
|
|
5354
|
+
content.addInline(createAutomaticLineBreak(ctx.tokens[startPos]));
|
|
4319
5355
|
}
|
|
4320
5356
|
return { consumed };
|
|
4321
5357
|
}
|
|
@@ -4366,7 +5402,7 @@ function parseCellContent(ctx, closeCondition) {
|
|
|
4366
5402
|
for (const rule of getCandidateInlineRules(ctx.inlineRules, token5.type)) {
|
|
4367
5403
|
const result = rule.parse(inlineCtx);
|
|
4368
5404
|
if (result.success) {
|
|
4369
|
-
content.addInlineElements(result.elements);
|
|
5405
|
+
content.addInlineElements(result.elements, result.stripLeadingLineBreak);
|
|
4370
5406
|
consumed += result.consumed;
|
|
4371
5407
|
pos += result.consumed;
|
|
4372
5408
|
matched = true;
|
|
@@ -4668,8 +5704,18 @@ var rateModuleRule = {
|
|
|
4668
5704
|
name: "module-rate",
|
|
4669
5705
|
acceptsNames: ["rate"],
|
|
4670
5706
|
hasBody: false,
|
|
4671
|
-
parse() {
|
|
4672
|
-
return { module: "rate" };
|
|
5707
|
+
parse(_ctx, _pos, args) {
|
|
5708
|
+
return { module: "rate", ref: Object.keys(args).length === 0 ? { kind: "main" } : null };
|
|
5709
|
+
}
|
|
5710
|
+
};
|
|
5711
|
+
var customRateModuleRule = {
|
|
5712
|
+
name: "module-custom-rate",
|
|
5713
|
+
acceptsNames: ["customrate"],
|
|
5714
|
+
hasBody: false,
|
|
5715
|
+
parse(_ctx, _pos, args) {
|
|
5716
|
+
const key = args.key;
|
|
5717
|
+
const valid = key !== undefined && key !== "" && Object.keys(args).every((name) => name === "key");
|
|
5718
|
+
return { module: "custom-rate", ref: valid ? { kind: "custom", axisKey: key } : null };
|
|
4673
5719
|
}
|
|
4674
5720
|
};
|
|
4675
5721
|
|
|
@@ -4804,6 +5850,7 @@ var listPagesModuleRule = {
|
|
|
4804
5850
|
"created-at": createdAt,
|
|
4805
5851
|
"updated-at": updatedAt,
|
|
4806
5852
|
rating,
|
|
5853
|
+
"rating-axis": args["rating-axis"],
|
|
4807
5854
|
votes,
|
|
4808
5855
|
name,
|
|
4809
5856
|
fullname,
|
|
@@ -4947,6 +5994,7 @@ var tagCloudModuleRule = {
|
|
|
4947
5994
|
// packages/parser/src/parser/rules/block/module/mapping.ts
|
|
4948
5995
|
var MODULE_RULES = [
|
|
4949
5996
|
rateModuleRule,
|
|
5997
|
+
customRateModuleRule,
|
|
4950
5998
|
cssModuleRule,
|
|
4951
5999
|
backlinksModuleRule,
|
|
4952
6000
|
categoriesModuleRule,
|
|
@@ -5517,22 +6565,6 @@ function getDayOfYear(date) {
|
|
|
5517
6565
|
function splitContentSections(content) {
|
|
5518
6566
|
return content.split(/^={4,}$/m).map((section) => section.trim());
|
|
5519
6567
|
}
|
|
5520
|
-
function getSummary(page) {
|
|
5521
|
-
if (page.content) {
|
|
5522
|
-
const sections = splitContentSections(page.content);
|
|
5523
|
-
if (sections.length > 1) {
|
|
5524
|
-
return sections[0]?.trim() ?? "";
|
|
5525
|
-
}
|
|
5526
|
-
}
|
|
5527
|
-
return getFirstParagraph(page.content);
|
|
5528
|
-
}
|
|
5529
|
-
function getFirstParagraph(content) {
|
|
5530
|
-
if (!content)
|
|
5531
|
-
return "";
|
|
5532
|
-
const stripped = content.replace(/^(\+{1,6}) (.*)/gm, "").replace(/^\[\[toc(\s[^\]]+)?\]\]/gim, "").replace(/^\[\[\/?div(\s[^\]]+)?\]\]/gim, "").replace(/^\[\[\/?module(\s[^\]]+)?\]\]/gim, "").trim();
|
|
5533
|
-
const paragraphs = stripped.split(/\n{2,}/);
|
|
5534
|
-
return paragraphs[0]?.trim() ?? "";
|
|
5535
|
-
}
|
|
5536
6568
|
// packages/parser/src/parser/rules/block/module/listpages/template/format/tags.ts
|
|
5537
6569
|
function formatTagsLinked(tags, prefix) {
|
|
5538
6570
|
if (tags.length === 0)
|
|
@@ -5545,6 +6577,16 @@ function formatUserLinked(user) {
|
|
|
5545
6577
|
return "Anonymous";
|
|
5546
6578
|
return `[[*user ${user.name}]]`;
|
|
5547
6579
|
}
|
|
6580
|
+
// packages/parser/src/parser/rules/block/module/listpages/template/getters/parameterized.ts
|
|
6581
|
+
import { excerptText } from "@wdprlib/ast";
|
|
6582
|
+
|
|
6583
|
+
// packages/parser/src/parser/rules/block/module/listpages/template/literal.ts
|
|
6584
|
+
function literalWikitext(value) {
|
|
6585
|
+
if (value === "")
|
|
6586
|
+
return "";
|
|
6587
|
+
return `@<${Array.from(value, (char) => `&#${char.codePointAt(0)};`).join("")}>@`;
|
|
6588
|
+
}
|
|
6589
|
+
|
|
5548
6590
|
// packages/parser/src/parser/rules/block/module/listpages/template/getters/parameterized.ts
|
|
5549
6591
|
function createBraceParamGetter(name, param) {
|
|
5550
6592
|
switch (name) {
|
|
@@ -5573,7 +6615,7 @@ function createParenParamGetter(name, param) {
|
|
|
5573
6615
|
if (name !== "preview")
|
|
5574
6616
|
return null;
|
|
5575
6617
|
const len = Number(param);
|
|
5576
|
-
return (ctx) => (ctx.page.
|
|
6618
|
+
return (ctx) => literalWikitext(excerptText(ctx.page.readableText ?? "", { maxLength: len }));
|
|
5577
6619
|
}
|
|
5578
6620
|
function createFormattedGetter(name, format) {
|
|
5579
6621
|
switch (name) {
|
|
@@ -5600,6 +6642,7 @@ function createTagsLinkedGetter(name, format) {
|
|
|
5600
6642
|
}
|
|
5601
6643
|
|
|
5602
6644
|
// packages/parser/src/parser/rules/block/module/listpages/template/getters/simple.ts
|
|
6645
|
+
import { countCharacters, excerptText as excerptText2 } from "@wdprlib/ast";
|
|
5603
6646
|
var DEFAULT_PREVIEW_LENGTH = 200;
|
|
5604
6647
|
var SIMPLE_GETTERS = {
|
|
5605
6648
|
created_at: (ctx) => formatDate(ctx.page.createdAt),
|
|
@@ -5629,14 +6672,14 @@ var SIMPLE_GETTERS = {
|
|
|
5629
6672
|
parent_title: (ctx) => ctx.page.parentTitle ?? "",
|
|
5630
6673
|
parent_title_linked: (ctx) => ctx.page.parentFullname ? `[[[${ctx.page.parentFullname} | ${ctx.page.parentTitle}]]]` : "",
|
|
5631
6674
|
content: (ctx) => ctx.page.content ?? "",
|
|
5632
|
-
preview: (ctx) => (ctx.page.
|
|
5633
|
-
summary: (ctx) =>
|
|
5634
|
-
first_paragraph: (ctx) =>
|
|
6675
|
+
preview: (ctx) => literalWikitext(excerptText2(ctx.page.readableText ?? "", { maxLength: DEFAULT_PREVIEW_LENGTH })),
|
|
6676
|
+
summary: (ctx) => literalWikitext(ctx.page.firstParagraph ?? ""),
|
|
6677
|
+
first_paragraph: (ctx) => literalWikitext(ctx.page.firstParagraph ?? ""),
|
|
5635
6678
|
tags: (ctx) => ctx.page.tags.join(" "),
|
|
5636
6679
|
_tags: (ctx) => ctx.page.hiddenTags.join(" "),
|
|
5637
6680
|
children: (ctx) => String(ctx.page.children),
|
|
5638
6681
|
comments: (ctx) => String(ctx.page.comments),
|
|
5639
|
-
size: (ctx) => String(ctx.page.size),
|
|
6682
|
+
size: (ctx) => ctx.page.readableText !== undefined ? String(countCharacters(ctx.page.readableText)) : ctx.page.size !== undefined ? String(ctx.page.size) : "",
|
|
5640
6683
|
rating: (ctx) => String(ctx.page.rating),
|
|
5641
6684
|
rating_votes: (ctx) => String(ctx.page.ratingVotes),
|
|
5642
6685
|
rating_percent: (ctx) => String(ctx.page.ratingPercent ?? 0),
|
|
@@ -5650,11 +6693,136 @@ var SIMPLE_GETTERS = {
|
|
|
5650
6693
|
site_domain: (ctx) => ctx.site.domain
|
|
5651
6694
|
};
|
|
5652
6695
|
|
|
6696
|
+
// packages/parser/src/parser/rules/block/module/listpages/template/getters/registered.ts
|
|
6697
|
+
function createRegisteredGetter(name, key, format) {
|
|
6698
|
+
if (name === "metadata")
|
|
6699
|
+
return (ctx) => {
|
|
6700
|
+
const metadata = ctx.page.metadata;
|
|
6701
|
+
const entry = metadata && Object.hasOwn(metadata, key) ? metadata[key] : null;
|
|
6702
|
+
if (!entry)
|
|
6703
|
+
return "";
|
|
6704
|
+
let value;
|
|
6705
|
+
switch (entry.type) {
|
|
6706
|
+
case "text":
|
|
6707
|
+
value = entry.value;
|
|
6708
|
+
break;
|
|
6709
|
+
case "number":
|
|
6710
|
+
value = String(entry.value);
|
|
6711
|
+
break;
|
|
6712
|
+
case "date":
|
|
6713
|
+
value = formatDate(entry.value, format);
|
|
6714
|
+
break;
|
|
6715
|
+
case "user":
|
|
6716
|
+
value = format === "id" ? String(entry.value.id) : format === "unix" ? entry.value.unixName : entry.value.name;
|
|
6717
|
+
break;
|
|
6718
|
+
}
|
|
6719
|
+
return literalWikitext(value);
|
|
6720
|
+
};
|
|
6721
|
+
if (name === "customrate" || name === "customrate_votes" || name === "customrate_percent")
|
|
6722
|
+
return (ctx) => {
|
|
6723
|
+
const ratings = ctx.page.customRates;
|
|
6724
|
+
const entry = ratings && Object.hasOwn(ratings, key) ? ratings[key] : null;
|
|
6725
|
+
if (!entry)
|
|
6726
|
+
return "";
|
|
6727
|
+
return String(name === "customrate" ? entry.points : name === "customrate_votes" ? entry.votes : entry.percent);
|
|
6728
|
+
};
|
|
6729
|
+
return null;
|
|
6730
|
+
}
|
|
6731
|
+
|
|
6732
|
+
// packages/parser/src/parser/rules/block/module/listpages/template/getters/index.ts
|
|
6733
|
+
import { compileTextExcerpt } from "@wdprlib/ast";
|
|
6734
|
+
|
|
6735
|
+
// packages/parser/src/parser/rules/block/module/listpages/template/excerpt.ts
|
|
6736
|
+
function findExcerptEnd(template, contentStart) {
|
|
6737
|
+
let quote;
|
|
6738
|
+
for (let cursor = contentStart + "excerpt{".length;cursor < template.length; cursor++) {
|
|
6739
|
+
const char = template[cursor];
|
|
6740
|
+
if (quote) {
|
|
6741
|
+
if (char === "\\")
|
|
6742
|
+
cursor++;
|
|
6743
|
+
else if (char === quote)
|
|
6744
|
+
quote = undefined;
|
|
6745
|
+
} else if (char === '"' || char === "'") {
|
|
6746
|
+
quote = char;
|
|
6747
|
+
} else if (char === "}") {
|
|
6748
|
+
return template.startsWith("%%", cursor + 1) ? cursor + 1 : -1;
|
|
6749
|
+
}
|
|
6750
|
+
}
|
|
6751
|
+
return -1;
|
|
6752
|
+
}
|
|
6753
|
+
function parseExcerptOptions(input) {
|
|
6754
|
+
if (input.length > 8192)
|
|
6755
|
+
return null;
|
|
6756
|
+
const attributes = new Map;
|
|
6757
|
+
let cursor = 0;
|
|
6758
|
+
while (cursor < input.length) {
|
|
6759
|
+
while (cursor < input.length && /\s/.test(input[cursor]))
|
|
6760
|
+
cursor++;
|
|
6761
|
+
if (cursor === input.length)
|
|
6762
|
+
break;
|
|
6763
|
+
const start = cursor;
|
|
6764
|
+
while (cursor < input.length && /[a-z]/.test(input[cursor]))
|
|
6765
|
+
cursor++;
|
|
6766
|
+
const name = input.slice(start, cursor);
|
|
6767
|
+
if (!["pattern", "flags", "group", "match", "max"].includes(name) || attributes.has(name))
|
|
6768
|
+
return null;
|
|
6769
|
+
while (cursor < input.length && /\s/.test(input[cursor]))
|
|
6770
|
+
cursor++;
|
|
6771
|
+
if (input[cursor++] !== "=")
|
|
6772
|
+
return null;
|
|
6773
|
+
while (cursor < input.length && /\s/.test(input[cursor]))
|
|
6774
|
+
cursor++;
|
|
6775
|
+
const quote = input[cursor++];
|
|
6776
|
+
if (quote !== '"' && quote !== "'")
|
|
6777
|
+
return null;
|
|
6778
|
+
let value = "";
|
|
6779
|
+
while (cursor < input.length && input[cursor] !== quote) {
|
|
6780
|
+
if (input[cursor] === "\\" && (input[cursor + 1] === quote || input[cursor + 1] === "\\")) {
|
|
6781
|
+
value += input[cursor + 1] === quote ? quote : "\\\\";
|
|
6782
|
+
cursor += 2;
|
|
6783
|
+
} else
|
|
6784
|
+
value += input[cursor++];
|
|
6785
|
+
}
|
|
6786
|
+
if (input[cursor++] !== quote)
|
|
6787
|
+
return null;
|
|
6788
|
+
if (cursor < input.length && !/\s/.test(input[cursor]))
|
|
6789
|
+
return null;
|
|
6790
|
+
attributes.set(name, value);
|
|
6791
|
+
}
|
|
6792
|
+
const pattern = attributes.get("pattern");
|
|
6793
|
+
if (pattern === undefined)
|
|
6794
|
+
return null;
|
|
6795
|
+
const group = attributes.get("group");
|
|
6796
|
+
const match = attributes.get("match");
|
|
6797
|
+
const max = attributes.get("max");
|
|
6798
|
+
if (match !== undefined && !/^\d+$/.test(match) || max !== undefined && !/^\d+$/.test(max))
|
|
6799
|
+
return null;
|
|
6800
|
+
return {
|
|
6801
|
+
pattern,
|
|
6802
|
+
flags: attributes.get("flags"),
|
|
6803
|
+
group: group === undefined ? undefined : /^\d+$/.test(group) ? Number(group) : group,
|
|
6804
|
+
match: match === undefined ? undefined : Number(match),
|
|
6805
|
+
maxLength: max === undefined ? undefined : Number(max)
|
|
6806
|
+
};
|
|
6807
|
+
}
|
|
6808
|
+
|
|
5653
6809
|
// packages/parser/src/parser/rules/block/module/listpages/template/getters/index.ts
|
|
5654
6810
|
function createVariableGetter(name, braceParam, parenParam, format) {
|
|
6811
|
+
if (name === "excerpt") {
|
|
6812
|
+
const options = braceParam === undefined ? null : parseExcerptOptions(braceParam);
|
|
6813
|
+
if (!options || parenParam !== undefined || format !== undefined)
|
|
6814
|
+
return () => "";
|
|
6815
|
+
const extract = compileTextExcerpt(options);
|
|
6816
|
+
return (ctx) => literalWikitext(extract(ctx.page.readableText ?? ""));
|
|
6817
|
+
}
|
|
6818
|
+
const registeredGetter = braceParam !== undefined ? createRegisteredGetter(name, braceParam, format) : null;
|
|
6819
|
+
if (registeredGetter)
|
|
6820
|
+
return registeredGetter;
|
|
5655
6821
|
const braceGetter = braceParam !== undefined ? createBraceParamGetter(name, braceParam) : null;
|
|
5656
6822
|
if (braceGetter)
|
|
5657
6823
|
return braceGetter;
|
|
6824
|
+
if (braceParam !== undefined)
|
|
6825
|
+
return () => "";
|
|
5658
6826
|
const parenGetter = parenParam !== undefined ? createParenParamGetter(name, parenParam) : null;
|
|
5659
6827
|
if (parenGetter)
|
|
5660
6828
|
return parenGetter;
|
|
@@ -5676,7 +6844,7 @@ function scanTemplateVariables(template) {
|
|
|
5676
6844
|
if (start === -1)
|
|
5677
6845
|
break;
|
|
5678
6846
|
const contentStart = start + 2;
|
|
5679
|
-
const end = template.indexOf("%%", contentStart);
|
|
6847
|
+
const end = template.slice(contentStart, contentStart + 8).toLowerCase() === "excerpt{" ? findExcerptEnd(template, contentStart) : template.indexOf("%%", contentStart);
|
|
5680
6848
|
if (end === -1)
|
|
5681
6849
|
break;
|
|
5682
6850
|
const parsed = parseTemplateVariableContent(template.slice(contentStart, end));
|
|
@@ -5699,6 +6867,11 @@ function parseTemplateVariableContent(content) {
|
|
|
5699
6867
|
if (cursor === 0)
|
|
5700
6868
|
return null;
|
|
5701
6869
|
const name = content.slice(0, cursor);
|
|
6870
|
+
if (name.toLowerCase() === "excerpt" && content[cursor] === "{") {
|
|
6871
|
+
if (!content.endsWith("}"))
|
|
6872
|
+
return null;
|
|
6873
|
+
return { name, braceParam: content.slice(cursor + 1, -1) };
|
|
6874
|
+
}
|
|
5702
6875
|
let braceParam;
|
|
5703
6876
|
let parenParam;
|
|
5704
6877
|
let format;
|
|
@@ -5778,6 +6951,7 @@ function buildQuery(module) {
|
|
|
5778
6951
|
updatedAt: module["updated-at"],
|
|
5779
6952
|
createdBy: module["created-by"],
|
|
5780
6953
|
rating: module.rating,
|
|
6954
|
+
ratingAxis: module["rating-axis"],
|
|
5781
6955
|
votes: module.votes,
|
|
5782
6956
|
name: module.name,
|
|
5783
6957
|
fullname: module.fullname,
|
|
@@ -5832,6 +7006,7 @@ var KNOWN_VARIABLES = new Set([
|
|
|
5832
7006
|
"parent_title_linked",
|
|
5833
7007
|
"content",
|
|
5834
7008
|
"preview",
|
|
7009
|
+
"excerpt",
|
|
5835
7010
|
"summary",
|
|
5836
7011
|
"first_paragraph",
|
|
5837
7012
|
"tags",
|
|
@@ -5869,12 +7044,24 @@ function extractVariablesFromTemplate(template) {
|
|
|
5869
7044
|
const contentIndices = new Set;
|
|
5870
7045
|
const previewLengths = new Set;
|
|
5871
7046
|
const formFields = new Set;
|
|
7047
|
+
const metadataKeys = new Set;
|
|
7048
|
+
const customRateKeys = new Set;
|
|
5872
7049
|
let tagsLinkPrefix;
|
|
5873
7050
|
let hiddenTagsLinkPrefix;
|
|
5874
7051
|
for (const match of scanTemplateVariables(template)) {
|
|
5875
7052
|
const varName = match.name.toLowerCase();
|
|
5876
7053
|
if (match.braceParam !== undefined) {
|
|
5877
7054
|
switch (varName) {
|
|
7055
|
+
case "metadata":
|
|
7056
|
+
metadataKeys.add(match.braceParam);
|
|
7057
|
+
variables.add("metadata");
|
|
7058
|
+
continue;
|
|
7059
|
+
case "customrate":
|
|
7060
|
+
case "customrate_votes":
|
|
7061
|
+
case "customrate_percent":
|
|
7062
|
+
customRateKeys.add(match.braceParam);
|
|
7063
|
+
variables.add(varName);
|
|
7064
|
+
continue;
|
|
5878
7065
|
case "content":
|
|
5879
7066
|
contentIndices.add(Number(match.braceParam));
|
|
5880
7067
|
variables.add("content_n");
|
|
@@ -5924,6 +7111,8 @@ function extractVariablesFromTemplate(template) {
|
|
|
5924
7111
|
contentIndices: Array.from(contentIndices).sort((a, b) => a - b),
|
|
5925
7112
|
previewLengths: Array.from(previewLengths).sort((a, b) => a - b),
|
|
5926
7113
|
formFields: Array.from(formFields).sort(),
|
|
7114
|
+
metadataKeys: [...metadataKeys].sort(),
|
|
7115
|
+
customRateKeys: [...customRateKeys].sort(),
|
|
5927
7116
|
tagsLinkPrefix,
|
|
5928
7117
|
hiddenTagsLinkPrefix
|
|
5929
7118
|
};
|
|
@@ -5945,6 +7134,9 @@ function extractListPagesModule(listPages, state, result) {
|
|
|
5945
7134
|
contentSectionIndices: extraction.contentIndices,
|
|
5946
7135
|
previewLengths: extraction.previewLengths,
|
|
5947
7136
|
formFields: extraction.formFields,
|
|
7137
|
+
metadataKeys: extraction.metadataKeys,
|
|
7138
|
+
customRateKeys: extraction.customRateKeys,
|
|
7139
|
+
needsReadableText: extraction.variables.some((name) => ["preview", "preview_n", "summary", "first_paragraph", "excerpt"].includes(name)),
|
|
5948
7140
|
tagsLinkPrefix: extraction.tagsLinkPrefix,
|
|
5949
7141
|
hiddenTagsLinkPrefix: extraction.hiddenTagsLinkPrefix,
|
|
5950
7142
|
urlAttrPrefix: listPages["url-attr-prefix"],
|
|
@@ -6277,13 +7469,101 @@ function wrapListPagesResult(module, items, parse, data) {
|
|
|
6277
7469
|
return result;
|
|
6278
7470
|
}
|
|
6279
7471
|
|
|
7472
|
+
// packages/parser/src/parser/rules/block/module/rate/resolve.ts
|
|
7473
|
+
function refKey(ref) {
|
|
7474
|
+
return ref.kind === "main" ? "main" : `custom:${ref.axisKey}`;
|
|
7475
|
+
}
|
|
7476
|
+
async function resolveRatings(ast, fetchRatings) {
|
|
7477
|
+
const refs = new Map;
|
|
7478
|
+
mapDocument(ast, (element) => {
|
|
7479
|
+
if (isRating(element) && element.data.ref)
|
|
7480
|
+
refs.set(refKey(element.data.ref), element.data.ref);
|
|
7481
|
+
return element;
|
|
7482
|
+
});
|
|
7483
|
+
const states = new Map;
|
|
7484
|
+
if (fetchRatings && refs.size > 0) {
|
|
7485
|
+
for (const state of await fetchRatings([...refs.values()])) {
|
|
7486
|
+
const key = refKey(state.ref);
|
|
7487
|
+
if (refs.has(key))
|
|
7488
|
+
states.set(key, state);
|
|
7489
|
+
}
|
|
7490
|
+
}
|
|
7491
|
+
return mapDocument(ast, (element) => {
|
|
7492
|
+
if (!isRating(element))
|
|
7493
|
+
return element;
|
|
7494
|
+
const { state: _previous, ...data } = element.data;
|
|
7495
|
+
const state = data.ref ? states.get(refKey(data.ref)) : undefined;
|
|
7496
|
+
return { ...element, data: state ? { ...data, state } : data };
|
|
7497
|
+
});
|
|
7498
|
+
}
|
|
7499
|
+
function suppressModuleRatings(result) {
|
|
7500
|
+
const ast = mapDocument(getModuleParseAst(result), (element) => isRating(element) ? null : element);
|
|
7501
|
+
return "ast" in result ? { ...result, ast } : ast;
|
|
7502
|
+
}
|
|
7503
|
+
function isRating(element) {
|
|
7504
|
+
return element.element === "module" && (element.data.module === "rate" || element.data.module === "custom-rate");
|
|
7505
|
+
}
|
|
7506
|
+
function mapDocument(ast, transform) {
|
|
7507
|
+
const map = (elements) => elements.flatMap((original) => {
|
|
7508
|
+
const element = transform(original);
|
|
7509
|
+
if (!element)
|
|
7510
|
+
return [];
|
|
7511
|
+
if (element.element === "if") {
|
|
7512
|
+
return [
|
|
7513
|
+
{
|
|
7514
|
+
...element,
|
|
7515
|
+
data: {
|
|
7516
|
+
...element.data,
|
|
7517
|
+
then: map(element.data.then),
|
|
7518
|
+
else: map(element.data.else)
|
|
7519
|
+
}
|
|
7520
|
+
}
|
|
7521
|
+
];
|
|
7522
|
+
}
|
|
7523
|
+
if (element.element === "ifexpr") {
|
|
7524
|
+
return [
|
|
7525
|
+
{
|
|
7526
|
+
...element,
|
|
7527
|
+
data: {
|
|
7528
|
+
...element.data,
|
|
7529
|
+
then: map(element.data.then),
|
|
7530
|
+
else: map(element.data.else)
|
|
7531
|
+
}
|
|
7532
|
+
}
|
|
7533
|
+
];
|
|
7534
|
+
}
|
|
7535
|
+
if (element.element === "bibliography-block") {
|
|
7536
|
+
return [
|
|
7537
|
+
{
|
|
7538
|
+
...element,
|
|
7539
|
+
data: {
|
|
7540
|
+
...element.data,
|
|
7541
|
+
entries: element.data.entries.map((entry) => ({
|
|
7542
|
+
...entry,
|
|
7543
|
+
key: map(entry.key),
|
|
7544
|
+
value: map(entry.value)
|
|
7545
|
+
}))
|
|
7546
|
+
}
|
|
7547
|
+
}
|
|
7548
|
+
];
|
|
7549
|
+
}
|
|
7550
|
+
return [mapElementChildren(element, map)];
|
|
7551
|
+
});
|
|
7552
|
+
return {
|
|
7553
|
+
...ast,
|
|
7554
|
+
elements: map(ast.elements),
|
|
7555
|
+
...ast.footnotes ? { footnotes: ast.footnotes.map(map) } : {}
|
|
7556
|
+
};
|
|
7557
|
+
}
|
|
7558
|
+
|
|
6280
7559
|
// packages/parser/src/parser/rules/block/module/listpages/resolve.ts
|
|
6281
7560
|
function isListPagesModule2(module) {
|
|
6282
7561
|
return module.module === "list-pages";
|
|
6283
7562
|
}
|
|
6284
7563
|
function resolveListPages(module, data, compiledTemplate, parse) {
|
|
6285
|
-
const
|
|
6286
|
-
|
|
7564
|
+
const parseFragment = (source) => suppressModuleRatings(parse(source));
|
|
7565
|
+
const items = renderListPagesItems(module, data, compiledTemplate, parseFragment);
|
|
7566
|
+
return wrapListPagesResult(module, items, parseFragment, data);
|
|
6287
7567
|
}
|
|
6288
7568
|
// packages/parser/src/parser/rules/block/module/listpages/types/external-data.ts
|
|
6289
7569
|
function definePageData(input) {
|
|
@@ -6297,7 +7577,6 @@ function definePageData(input) {
|
|
|
6297
7577
|
hiddenTags: input.hiddenTags ?? [],
|
|
6298
7578
|
children: input.children ?? 0,
|
|
6299
7579
|
comments: input.comments ?? 0,
|
|
6300
|
-
size: input.size ?? 0,
|
|
6301
7580
|
rating: input.rating ?? 0,
|
|
6302
7581
|
ratingVotes: input.ratingVotes ?? 0,
|
|
6303
7582
|
revisions: input.revisions ?? 0
|
|
@@ -6375,6 +7654,7 @@ var URL_RESOLVABLE_FIELDS = [
|
|
|
6375
7654
|
aliases: ["createdby", "created_by"]
|
|
6376
7655
|
},
|
|
6377
7656
|
{ attr: "rating", queryKey: "rating", type: "string" },
|
|
7657
|
+
{ attr: "rating-axis", queryKey: "ratingAxis", type: "string" },
|
|
6378
7658
|
{ attr: "votes", queryKey: "votes", type: "string" },
|
|
6379
7659
|
{ attr: "reverse", queryKey: "reverse", type: "boolean" }
|
|
6380
7660
|
];
|
|
@@ -6476,6 +7756,7 @@ var ORDER_FIELD_MAP = {
|
|
|
6476
7756
|
votes: "votes",
|
|
6477
7757
|
revisions: "revisions",
|
|
6478
7758
|
comments: "comments",
|
|
7759
|
+
commented_at: "commented_at",
|
|
6479
7760
|
pagelength: "size",
|
|
6480
7761
|
size: "size",
|
|
6481
7762
|
random: "random",
|
|
@@ -6483,6 +7764,13 @@ var ORDER_FIELD_MAP = {
|
|
|
6483
7764
|
updated_at: "updated_at"
|
|
6484
7765
|
};
|
|
6485
7766
|
function parseOrder(value) {
|
|
7767
|
+
const metadata = /^metadata\{([^}]*)\}(?:\s+(asc|desc))?$/i.exec(value.trim());
|
|
7768
|
+
if (metadata)
|
|
7769
|
+
return {
|
|
7770
|
+
field: "metadata",
|
|
7771
|
+
key: metadata[1],
|
|
7772
|
+
direction: metadata[2]?.toLowerCase() === "asc" ? "asc" : "desc"
|
|
7773
|
+
};
|
|
6486
7774
|
const defaultOrder = { field: "created_at", direction: "desc" };
|
|
6487
7775
|
const trimmed = value.trim().toLowerCase();
|
|
6488
7776
|
if (!trimmed)
|
|
@@ -6602,6 +7890,8 @@ function normalizeQuery(query) {
|
|
|
6602
7890
|
result.linkTo = query.linkTo;
|
|
6603
7891
|
if (query.createdBy)
|
|
6604
7892
|
result.createdBy = query.createdBy;
|
|
7893
|
+
if (query.ratingAxis !== undefined)
|
|
7894
|
+
result.ratingAxis = query.ratingAxis;
|
|
6605
7895
|
if (query.name)
|
|
6606
7896
|
result.name = query.name;
|
|
6607
7897
|
if (query.fullname)
|
|
@@ -6786,7 +8076,7 @@ function resolveIfTags(data, pageTags) {
|
|
|
6786
8076
|
// packages/parser/src/parser/preprocess/utils/raw-regions.ts
|
|
6787
8077
|
var BASE_PLACEHOLDER_OPEN = "";
|
|
6788
8078
|
var BASE_PLACEHOLDER_CLOSE = "";
|
|
6789
|
-
var RAW_BLOCK_OPEN_PATTERN = /\[\[
|
|
8079
|
+
var RAW_BLOCK_OPEN_PATTERN = /\[\[html\b[^\]]*\]\]/iy;
|
|
6790
8080
|
function makeUniqueSentinels(source) {
|
|
6791
8081
|
let openRun = 0;
|
|
6792
8082
|
let closeRun = 0;
|
|
@@ -6805,10 +8095,21 @@ function makeUniqueSentinels(source) {
|
|
|
6805
8095
|
}
|
|
6806
8096
|
function maskRawRegions(source, sentinels) {
|
|
6807
8097
|
const placeholders = [];
|
|
8098
|
+
let tokens;
|
|
8099
|
+
const getTokens = () => tokens ??= tokenize(source);
|
|
6808
8100
|
let masked = "";
|
|
6809
8101
|
let i = 0;
|
|
6810
8102
|
while (i < source.length) {
|
|
6811
|
-
|
|
8103
|
+
if (source.startsWith("[!--", i)) {
|
|
8104
|
+
const close = source.indexOf("--]", i + 4);
|
|
8105
|
+
if (close !== -1) {
|
|
8106
|
+
const end = close + 3;
|
|
8107
|
+
masked += source.slice(i, end);
|
|
8108
|
+
i = end;
|
|
8109
|
+
continue;
|
|
8110
|
+
}
|
|
8111
|
+
}
|
|
8112
|
+
const rawBlock = tryMaskRawBlock(source, i, placeholders, sentinels, getTokens);
|
|
6812
8113
|
if (rawBlock) {
|
|
6813
8114
|
masked += rawBlock.placeholder;
|
|
6814
8115
|
i = rawBlock.end;
|
|
@@ -6829,16 +8130,25 @@ function restorePlaceholders(source, placeholders, sentinels) {
|
|
|
6829
8130
|
const pattern = new RegExp(`${escapeRegex(sentinels.open)}(\\d+)${escapeRegex(sentinels.close)}`, "g");
|
|
6830
8131
|
return source.replace(pattern, (_, idx) => placeholders[Number(idx)] ?? "");
|
|
6831
8132
|
}
|
|
6832
|
-
function tryMaskRawBlock(source, pos, placeholders, sentinels) {
|
|
8133
|
+
function tryMaskRawBlock(source, pos, placeholders, sentinels, getTokens) {
|
|
6833
8134
|
if (source[pos] !== "[" || source[pos + 1] !== "[")
|
|
6834
8135
|
return null;
|
|
8136
|
+
if (source.slice(pos, pos + 6).toLowerCase() === "[[code") {
|
|
8137
|
+
const tokens = getTokens();
|
|
8138
|
+
const start = tokenAtOffset(tokens, pos);
|
|
8139
|
+
const open = findCodeOpen(tokens, start);
|
|
8140
|
+
if (!open)
|
|
8141
|
+
return null;
|
|
8142
|
+
const bounds = open.closingSwallowed ? null : findCodeBodyBounds(tokens, open.bodyStart);
|
|
8143
|
+
const end = open.closingSwallowed ? tokens[open.attributesEnd - 1].position.end.offset : bounds.foundClose ? tokens[bounds.end - 1].position.end.offset : source.length;
|
|
8144
|
+
return { placeholder: pushPlaceholder(placeholders, source.slice(pos, end), sentinels), end };
|
|
8145
|
+
}
|
|
6835
8146
|
RAW_BLOCK_OPEN_PATTERN.lastIndex = pos;
|
|
6836
8147
|
const openMatch = RAW_BLOCK_OPEN_PATTERN.exec(source);
|
|
6837
8148
|
if (!openMatch)
|
|
6838
8149
|
return null;
|
|
6839
|
-
const name = openMatch[1].toLowerCase();
|
|
6840
8150
|
const openLen = openMatch[0].length;
|
|
6841
|
-
const closePattern =
|
|
8151
|
+
const closePattern = /\[\[\/\s*html\s*\]\]/gi;
|
|
6842
8152
|
closePattern.lastIndex = pos + openLen;
|
|
6843
8153
|
const closeMatch = closePattern.exec(source);
|
|
6844
8154
|
if (closeMatch) {
|
|
@@ -6848,12 +8158,19 @@ function tryMaskRawBlock(source, pos, placeholders, sentinels) {
|
|
|
6848
8158
|
end
|
|
6849
8159
|
};
|
|
6850
8160
|
}
|
|
6851
|
-
|
|
6852
|
-
|
|
6853
|
-
|
|
6854
|
-
|
|
6855
|
-
|
|
6856
|
-
|
|
8161
|
+
return null;
|
|
8162
|
+
}
|
|
8163
|
+
function tokenAtOffset(tokens, offset) {
|
|
8164
|
+
let low = 0;
|
|
8165
|
+
let high = tokens.length;
|
|
8166
|
+
while (low < high) {
|
|
8167
|
+
const middle = Math.floor((low + high) / 2);
|
|
8168
|
+
if (tokens[middle].position.start.offset < offset)
|
|
8169
|
+
low = middle + 1;
|
|
8170
|
+
else
|
|
8171
|
+
high = middle;
|
|
8172
|
+
}
|
|
8173
|
+
return tokens[low]?.position.start.offset === offset ? low : tokens.length;
|
|
6857
8174
|
}
|
|
6858
8175
|
function tryMaskRawInline(source, pos, placeholders, sentinels) {
|
|
6859
8176
|
if (source[pos] === "@" && source[pos + 1] === "<") {
|
|
@@ -6865,17 +8182,22 @@ function tryMaskRawInline(source, pos, placeholders, sentinels) {
|
|
|
6865
8182
|
return null;
|
|
6866
8183
|
}
|
|
6867
8184
|
function tryMaskSingleLineRaw(source, pos, openerLength, close, placeholders, sentinels) {
|
|
6868
|
-
const
|
|
6869
|
-
|
|
6870
|
-
`, pos + openerLength);
|
|
6871
|
-
if (closePos === -1 || newline !== -1 && newline < closePos)
|
|
8185
|
+
const end = singleLineRawEnd(source, pos, openerLength, close);
|
|
8186
|
+
if (end === pos)
|
|
6872
8187
|
return null;
|
|
6873
|
-
const end = closePos + close.length;
|
|
6874
8188
|
return {
|
|
6875
8189
|
placeholder: pushPlaceholder(placeholders, source.slice(pos, end), sentinels),
|
|
6876
8190
|
end
|
|
6877
8191
|
};
|
|
6878
8192
|
}
|
|
8193
|
+
function singleLineRawEnd(source, pos, openerLength, close) {
|
|
8194
|
+
const closePos = source.indexOf(close, pos + openerLength);
|
|
8195
|
+
const newline = source.indexOf(`
|
|
8196
|
+
`, pos + openerLength);
|
|
8197
|
+
if (closePos === -1 || newline !== -1 && newline < closePos)
|
|
8198
|
+
return pos;
|
|
8199
|
+
return closePos + close.length;
|
|
8200
|
+
}
|
|
6879
8201
|
function pushPlaceholder(placeholders, text, sentinels) {
|
|
6880
8202
|
const idx = placeholders.length;
|
|
6881
8203
|
placeholders.push(text);
|
|
@@ -7477,7 +8799,7 @@ function isListUsersModule2(module) {
|
|
|
7477
8799
|
function resolveListUsers(_module, data, compiledTemplate, parse) {
|
|
7478
8800
|
const ctx = { user: data.user };
|
|
7479
8801
|
const substituted = compiledTemplate(ctx);
|
|
7480
|
-
const itemAst = getModuleParseAst(parse(substituted));
|
|
8802
|
+
const itemAst = getModuleParseAst(suppressModuleRatings(parse(substituted)));
|
|
7481
8803
|
return itemAst.elements;
|
|
7482
8804
|
}
|
|
7483
8805
|
// packages/parser/src/parser/rules/block/module/resolution/data-maps.ts
|
|
@@ -8273,11 +9595,11 @@ async function resolveModules(ast, dataProvider, options) {
|
|
|
8273
9595
|
if (mergedStyles.length > 0)
|
|
8274
9596
|
result.styles = mergedStyles;
|
|
8275
9597
|
options.onDiagnostics?.(registry.diagnostics);
|
|
8276
|
-
return registry.finalize(result, finalElements, pageTags, containsSyntaxFootnoteBlock(ast.elements));
|
|
9598
|
+
return resolveRatings(registry.finalize(result, finalElements, pageTags, containsSyntaxFootnoteBlock(ast.elements)), dataProvider.fetchRatings);
|
|
8277
9599
|
}
|
|
8278
9600
|
function createModuleParseFunction(options, dataProvider, registry) {
|
|
8279
9601
|
const transform = createModuleSourceTransform(options, dataProvider);
|
|
8280
|
-
return (source) => registry.register(options.parse(transform ? transform(source) : source), {
|
|
9602
|
+
return (source) => registry.register(suppressModuleRatings(options.parse(transform ? transform(source) : source)), {
|
|
8281
9603
|
stripLegacyImplicitFootnoteBlock: true
|
|
8282
9604
|
});
|
|
8283
9605
|
}
|
|
@@ -9141,141 +10463,6 @@ var includeRule = {
|
|
|
9141
10463
|
}
|
|
9142
10464
|
};
|
|
9143
10465
|
|
|
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++;
|
|
9181
|
-
}
|
|
9182
|
-
return consumed;
|
|
9183
|
-
}
|
|
9184
|
-
|
|
9185
|
-
// packages/parser/src/parser/rules/block/math/name.ts
|
|
9186
|
-
function parseMathName(ctx, startPos) {
|
|
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 };
|
|
9193
|
-
}
|
|
9194
|
-
while (pos < ctx.tokens.length) {
|
|
9195
|
-
const token5 = ctx.tokens[pos];
|
|
9196
|
-
if (!token5 || token5.type === "BLOCK_CLOSE" || token5.type === "WHITESPACE" || token5.type === "NEWLINE") {
|
|
9197
|
-
break;
|
|
9198
|
-
}
|
|
9199
|
-
name += token5.value;
|
|
9200
|
-
pos++;
|
|
9201
|
-
consumed++;
|
|
9202
|
-
}
|
|
9203
|
-
return { name: name === "" ? null : name, consumed };
|
|
9204
|
-
}
|
|
9205
|
-
|
|
9206
|
-
// packages/parser/src/parser/rules/block/math/index.ts
|
|
9207
|
-
var mathBlockRule = {
|
|
9208
|
-
name: "math",
|
|
9209
|
-
startTokens: ["BLOCK_OPEN"],
|
|
9210
|
-
requiresLineStart: false,
|
|
9211
|
-
parse(ctx) {
|
|
9212
|
-
const openToken = currentToken(ctx);
|
|
9213
|
-
if (openToken.type !== "BLOCK_OPEN") {
|
|
9214
|
-
return { success: false };
|
|
9215
|
-
}
|
|
9216
|
-
let pos = ctx.pos + 1;
|
|
9217
|
-
let consumed = 1;
|
|
9218
|
-
const nameResult = parseBlockName(ctx, pos);
|
|
9219
|
-
if (!nameResult || nameResult.name !== "math") {
|
|
9220
|
-
return { success: false };
|
|
9221
|
-
}
|
|
9222
|
-
pos += nameResult.consumed;
|
|
9223
|
-
consumed += nameResult.consumed;
|
|
9224
|
-
while (ctx.tokens[pos]?.type === "WHITESPACE") {
|
|
9225
|
-
pos++;
|
|
9226
|
-
consumed++;
|
|
9227
|
-
}
|
|
9228
|
-
const mathName = parseMathName(ctx, pos);
|
|
9229
|
-
pos += mathName.consumed;
|
|
9230
|
-
consumed += mathName.consumed;
|
|
9231
|
-
while (ctx.tokens[pos]?.type === "WHITESPACE") {
|
|
9232
|
-
pos++;
|
|
9233
|
-
consumed++;
|
|
9234
|
-
}
|
|
9235
|
-
if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
|
|
9236
|
-
return { success: false };
|
|
9237
|
-
}
|
|
9238
|
-
pos++;
|
|
9239
|
-
consumed++;
|
|
9240
|
-
if (ctx.tokens[pos]?.type === "NEWLINE") {
|
|
9241
|
-
pos++;
|
|
9242
|
-
consumed++;
|
|
9243
|
-
}
|
|
9244
|
-
const contentResult = collectMathContent(ctx, pos);
|
|
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) {
|
|
9261
|
-
return { success: false };
|
|
9262
|
-
}
|
|
9263
|
-
return {
|
|
9264
|
-
success: true,
|
|
9265
|
-
elements: [
|
|
9266
|
-
{
|
|
9267
|
-
element: "math",
|
|
9268
|
-
data: {
|
|
9269
|
-
name: mathName.name,
|
|
9270
|
-
"latex-source": latexSource
|
|
9271
|
-
}
|
|
9272
|
-
}
|
|
9273
|
-
],
|
|
9274
|
-
consumed
|
|
9275
|
-
};
|
|
9276
|
-
}
|
|
9277
|
-
};
|
|
9278
|
-
|
|
9279
10466
|
// packages/parser/src/parser/rules/block/html/body.ts
|
|
9280
10467
|
function lookaheadHasHtmlClose(ctx, from) {
|
|
9281
10468
|
for (let i = from;i < ctx.tokens.length; i++) {
|
|
@@ -10137,7 +11324,8 @@ function parseBibliographyContent(ctx, startPos) {
|
|
|
10137
11324
|
const inlineCtx = { ...ctx, pos };
|
|
10138
11325
|
const result = parseInlineUntil(inlineCtx, "NEWLINE");
|
|
10139
11326
|
if (result.elements.length > 0) {
|
|
10140
|
-
|
|
11327
|
+
for (const element of result.elements)
|
|
11328
|
+
content.push(element);
|
|
10141
11329
|
pos += result.consumed;
|
|
10142
11330
|
consumed += result.consumed;
|
|
10143
11331
|
} else {
|
|
@@ -10566,6 +11754,7 @@ var blockRules = [
|
|
|
10566
11754
|
iftagsRule,
|
|
10567
11755
|
bibliographyRule,
|
|
10568
11756
|
galleryRule,
|
|
11757
|
+
noteRule,
|
|
10569
11758
|
divRule
|
|
10570
11759
|
];
|
|
10571
11760
|
// packages/parser/src/parser/rules/inline/formatting/close.ts
|
|
@@ -10578,6 +11767,11 @@ function findFormattingClose(ctx, start, marker) {
|
|
|
10578
11767
|
return null;
|
|
10579
11768
|
if (!table && token5.type === "NEWLINE" && getParagraphNewlineBoundary(ctx, pos, true).shouldBreak)
|
|
10580
11769
|
return null;
|
|
11770
|
+
const inlineRegionEnd = Math.max(emailRegionEnd(ctx.tokens, pos, end), parseButtonSyntax(ctx, pos, end)?.end ?? pos, parseSocialSyntax(ctx, pos, end)?.end ?? pos);
|
|
11771
|
+
if (inlineRegionEnd > pos) {
|
|
11772
|
+
pos = inlineRegionEnd - 1;
|
|
11773
|
+
continue;
|
|
11774
|
+
}
|
|
10581
11775
|
if (token5.type === marker && !table?.suppressedClosers.has(pos))
|
|
10582
11776
|
return pos;
|
|
10583
11777
|
const protectedEnd = protectedInlineRegionEnd(ctx.tokens, pos, end);
|
|
@@ -10701,175 +11895,15 @@ var subscriptRule = {
|
|
|
10701
11895
|
startTokens: ["SUB_MARKER"],
|
|
10702
11896
|
parse(ctx) {
|
|
10703
11897
|
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 };
|
|
10799
|
-
}
|
|
10800
|
-
|
|
10801
|
-
// packages/parser/src/parser/rules/inline/link-triple/interwiki.ts
|
|
10802
|
-
var INTERWIKI_PREFIXES = new Set(["wikipedia", "google", "dictionary", "wikidot"]);
|
|
10803
|
-
function isInterwikiTarget(target) {
|
|
10804
|
-
const colonIdx = target.indexOf(":");
|
|
10805
|
-
if (colonIdx <= 0 || target.includes("/")) {
|
|
10806
|
-
return false;
|
|
10807
|
-
}
|
|
10808
|
-
const prefix = target.slice(0, colonIdx).toLowerCase();
|
|
10809
|
-
return INTERWIKI_PREFIXES.has(prefix);
|
|
10810
|
-
}
|
|
10811
|
-
|
|
10812
|
-
// packages/parser/src/parser/rules/inline/link-triple/target.ts
|
|
10813
|
-
function normalizeTripleLinkTarget(trimmedTarget) {
|
|
10814
|
-
if (trimmedTarget.startsWith("*")) {
|
|
10815
|
-
return { target: trimmedTarget.slice(1), hasStar: true };
|
|
10816
|
-
}
|
|
10817
|
-
return { target: trimmedTarget, hasStar: false };
|
|
10818
|
-
}
|
|
10819
|
-
function isInvalidTripleLinkTarget(trimmedTarget, foundPipe) {
|
|
10820
|
-
return trimmedTarget === "" && foundPipe || /#{2,}/.test(trimmedTarget);
|
|
10821
|
-
}
|
|
10822
|
-
function determineLinkTypeAndLocation(target) {
|
|
10823
|
-
if (target.startsWith("#")) {
|
|
10824
|
-
return { linkType: "anchor", link: target };
|
|
10825
|
-
}
|
|
10826
|
-
if (target.startsWith("http://") || target.startsWith("https://")) {
|
|
10827
|
-
return { linkType: "direct", link: target };
|
|
10828
|
-
}
|
|
10829
|
-
if (isInterwikiTarget(target)) {
|
|
10830
|
-
return { linkType: "interwiki", link: target };
|
|
10831
|
-
}
|
|
10832
|
-
return { linkType: "page", link: { site: null, page: target } };
|
|
10833
|
-
}
|
|
11898
|
+
}
|
|
11899
|
+
};
|
|
10834
11900
|
|
|
10835
|
-
// packages/parser/src/parser/rules/inline/
|
|
10836
|
-
var
|
|
10837
|
-
name: "
|
|
10838
|
-
startTokens: ["
|
|
11901
|
+
// packages/parser/src/parser/rules/inline/monospace.ts
|
|
11902
|
+
var monospaceRule = {
|
|
11903
|
+
name: "monospace",
|
|
11904
|
+
startTokens: ["MONO_MARKER"],
|
|
10839
11905
|
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
|
-
};
|
|
11906
|
+
return parseDelimitedContainer(ctx, "MONO_CLOSE", "monospace");
|
|
10873
11907
|
}
|
|
10874
11908
|
};
|
|
10875
11909
|
|
|
@@ -10880,7 +11914,7 @@ function normalizeAnchor(anchor) {
|
|
|
10880
11914
|
|
|
10881
11915
|
// packages/parser/src/parser/rules/inline/link-bracket/direct-url.ts
|
|
10882
11916
|
function isDirectBracketUrl(url) {
|
|
10883
|
-
return url !== "" && (url.startsWith("/") || url
|
|
11917
|
+
return url !== "" && (url.startsWith("/") || startsWithUrlScheme(url, 0));
|
|
10884
11918
|
}
|
|
10885
11919
|
|
|
10886
11920
|
// packages/parser/src/parser/rules/inline/link-bracket/parts.ts
|
|
@@ -10889,35 +11923,24 @@ function collectBracketLinkParts(ctx, startPos) {
|
|
|
10889
11923
|
return null;
|
|
10890
11924
|
}
|
|
10891
11925
|
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) {
|
|
11926
|
+
const end = Math.min(ctx.scope.inlineEnd ?? ctx.tokens.length, ctx.tokens.length);
|
|
11927
|
+
const values = [];
|
|
11928
|
+
while (pos < end) {
|
|
10909
11929
|
const token5 = ctx.tokens[pos];
|
|
10910
|
-
if (!token5 || token5.type === "BRACKET_CLOSE" || token5.type === "NEWLINE" || token5.type === "EOF")
|
|
11930
|
+
if (!token5 || token5.type === "BRACKET_CLOSE" || token5.type === "NEWLINE" || token5.type === "EOF")
|
|
10911
11931
|
break;
|
|
10912
|
-
|
|
10913
|
-
label += token5.value;
|
|
11932
|
+
values.push(token5.value);
|
|
10914
11933
|
pos++;
|
|
10915
|
-
consumed++;
|
|
10916
11934
|
}
|
|
10917
|
-
if (ctx.tokens[pos]?.type !== "BRACKET_CLOSE")
|
|
11935
|
+
if (pos >= end || ctx.tokens[pos]?.type !== "BRACKET_CLOSE")
|
|
10918
11936
|
return null;
|
|
10919
|
-
|
|
10920
|
-
|
|
11937
|
+
const content = values.join("");
|
|
11938
|
+
const separator = content.search(/[ \t]/);
|
|
11939
|
+
return {
|
|
11940
|
+
first: separator === -1 ? content : content.slice(0, separator),
|
|
11941
|
+
label: separator === -1 ? "" : content.slice(separator).trimStart(),
|
|
11942
|
+
consumed: pos - startPos + 1
|
|
11943
|
+
};
|
|
10921
11944
|
}
|
|
10922
11945
|
|
|
10923
11946
|
// packages/parser/src/parser/rules/inline/link-bracket/prefix.ts
|
|
@@ -10928,6 +11951,14 @@ function parseBracketLinkPrefix(ctx, startPos) {
|
|
|
10928
11951
|
return { target: null, bodyStart: startPos, consumed: 0 };
|
|
10929
11952
|
}
|
|
10930
11953
|
|
|
11954
|
+
// packages/parser/src/parser/rules/inline/link-bracket/special-target.ts
|
|
11955
|
+
function isBracketEmail(target) {
|
|
11956
|
+
return /^[_a-z0-9-]+(?:\.[_a-z0-9-]+)*@[a-z0-9-]+(?:\.[a-z0-9-]+)+$/i.test(target);
|
|
11957
|
+
}
|
|
11958
|
+
function wikipediaPage(target) {
|
|
11959
|
+
return /^wikipedia:((?!:)[A-Za-z0-9_/=&~#.:;+-]+)$/.exec(target)?.[1] ?? null;
|
|
11960
|
+
}
|
|
11961
|
+
|
|
10931
11962
|
// packages/parser/src/parser/rules/inline/link-bracket/parsed.ts
|
|
10932
11963
|
function parseSingleBracketLink(ctx) {
|
|
10933
11964
|
const prefix = parseBracketLinkPrefix(ctx, ctx.pos + 1);
|
|
@@ -10936,17 +11967,20 @@ function parseSingleBracketLink(ctx) {
|
|
|
10936
11967
|
return null;
|
|
10937
11968
|
}
|
|
10938
11969
|
const link = parts.first.trim();
|
|
10939
|
-
|
|
11970
|
+
const email = isBracketEmail(link);
|
|
11971
|
+
const wikiPage = wikipediaPage(link);
|
|
11972
|
+
if (!email && wikiPage === null && !isDirectBracketUrl(link)) {
|
|
10940
11973
|
return null;
|
|
10941
11974
|
}
|
|
10942
|
-
const labelText = parts.label.trim();
|
|
11975
|
+
const labelText = parts.label.trim() || wikiPage;
|
|
10943
11976
|
if (!labelText) {
|
|
10944
11977
|
return null;
|
|
10945
11978
|
}
|
|
10946
11979
|
return {
|
|
10947
|
-
link,
|
|
11980
|
+
link: email ? `mailto:${link}` : link,
|
|
11981
|
+
interwiki: wikiPage !== null,
|
|
10948
11982
|
labelText,
|
|
10949
|
-
target: prefix.target,
|
|
11983
|
+
target: wikiPage !== null ? "new-tab" : prefix.target,
|
|
10950
11984
|
consumed: 1 + prefix.consumed + parts.consumed
|
|
10951
11985
|
};
|
|
10952
11986
|
}
|
|
@@ -10999,7 +12033,7 @@ var linkSingleRule = {
|
|
|
10999
12033
|
{
|
|
11000
12034
|
element: "link",
|
|
11001
12035
|
data: {
|
|
11002
|
-
type: "direct",
|
|
12036
|
+
type: parsed.interwiki ? "interwiki" : "direct",
|
|
11003
12037
|
link: parsed.link,
|
|
11004
12038
|
extra: null,
|
|
11005
12039
|
label: linkLabel,
|
|
@@ -11068,6 +12102,134 @@ var linkStarRule = {
|
|
|
11068
12102
|
}
|
|
11069
12103
|
};
|
|
11070
12104
|
|
|
12105
|
+
// packages/parser/src/parser/rules/inline/autolink.ts
|
|
12106
|
+
var URL_BOUNDARY_TOKENS = new Set([
|
|
12107
|
+
"WHITESPACE",
|
|
12108
|
+
"NEWLINE",
|
|
12109
|
+
"EOF",
|
|
12110
|
+
"BLOCK_OPEN",
|
|
12111
|
+
"BLOCK_END_OPEN",
|
|
12112
|
+
"BLOCK_CLOSE",
|
|
12113
|
+
"LINK_OPEN",
|
|
12114
|
+
"LINK_CLOSE",
|
|
12115
|
+
"COMMENT_OPEN",
|
|
12116
|
+
"BACKSLASH_BREAK"
|
|
12117
|
+
]);
|
|
12118
|
+
var autolinkRule = {
|
|
12119
|
+
name: "autolink",
|
|
12120
|
+
startTokens: ["IDENTIFIER", "STAR", "LIST_BULLET"],
|
|
12121
|
+
parse(ctx) {
|
|
12122
|
+
let pos = ctx.pos;
|
|
12123
|
+
let target = null;
|
|
12124
|
+
const first = ctx.tokens[pos];
|
|
12125
|
+
if (!first) {
|
|
12126
|
+
return { success: false };
|
|
12127
|
+
}
|
|
12128
|
+
if (first.type === "STAR" || first.type === "LIST_BULLET") {
|
|
12129
|
+
if (first.value !== "*") {
|
|
12130
|
+
return { success: false };
|
|
12131
|
+
}
|
|
12132
|
+
target = "new-tab";
|
|
12133
|
+
pos++;
|
|
12134
|
+
}
|
|
12135
|
+
const scheme = ctx.tokens[pos];
|
|
12136
|
+
if (scheme?.type !== "IDENTIFIER" || !URL_SCHEME_NAMES.has(scheme.value)) {
|
|
12137
|
+
return { success: false };
|
|
12138
|
+
}
|
|
12139
|
+
if (ctx.tokens[pos + 1]?.type !== "COLON") {
|
|
12140
|
+
return { success: false };
|
|
12141
|
+
}
|
|
12142
|
+
const prev = ctx.tokens[ctx.pos - 1];
|
|
12143
|
+
if (prev && !first.lineStart) {
|
|
12144
|
+
const lastChar = prev.value[prev.value.length - 1] ?? "";
|
|
12145
|
+
if (/[A-Za-z]/.test(lastChar)) {
|
|
12146
|
+
return { success: false };
|
|
12147
|
+
}
|
|
12148
|
+
}
|
|
12149
|
+
const values = [];
|
|
12150
|
+
let end = pos;
|
|
12151
|
+
const inlineEnd = ctx.scope.inlineEnd ?? ctx.tokens.length;
|
|
12152
|
+
while (end < inlineEnd) {
|
|
12153
|
+
const token5 = ctx.tokens[end];
|
|
12154
|
+
if (!token5 || URL_BOUNDARY_TOKENS.has(token5.type)) {
|
|
12155
|
+
break;
|
|
12156
|
+
}
|
|
12157
|
+
if (token5.type === "RAW_OPEN" || token5.type === "RAW_BLOCK_OPEN") {
|
|
12158
|
+
if (rawRegionEnd(ctx.tokens, end, inlineEnd) > end)
|
|
12159
|
+
break;
|
|
12160
|
+
}
|
|
12161
|
+
values.push(token5.value);
|
|
12162
|
+
end++;
|
|
12163
|
+
if (/[ \t\n\\"']/.test(token5.value))
|
|
12164
|
+
break;
|
|
12165
|
+
}
|
|
12166
|
+
const candidate = values.join("");
|
|
12167
|
+
const match = URL_PATTERN.exec(candidate);
|
|
12168
|
+
if (!match) {
|
|
12169
|
+
return { success: false };
|
|
12170
|
+
}
|
|
12171
|
+
const url = match[0];
|
|
12172
|
+
let length = 0;
|
|
12173
|
+
let count = 0;
|
|
12174
|
+
while (length < url.length) {
|
|
12175
|
+
length += values[count]?.length ?? 0;
|
|
12176
|
+
count++;
|
|
12177
|
+
}
|
|
12178
|
+
const rest = candidate.slice(url.length, length);
|
|
12179
|
+
const elements = [
|
|
12180
|
+
{
|
|
12181
|
+
element: "link",
|
|
12182
|
+
data: {
|
|
12183
|
+
type: "direct",
|
|
12184
|
+
link: url,
|
|
12185
|
+
extra: null,
|
|
12186
|
+
label: { text: url },
|
|
12187
|
+
target
|
|
12188
|
+
}
|
|
12189
|
+
}
|
|
12190
|
+
];
|
|
12191
|
+
if (rest !== "") {
|
|
12192
|
+
elements.push({ element: "text", data: rest });
|
|
12193
|
+
}
|
|
12194
|
+
return {
|
|
12195
|
+
success: true,
|
|
12196
|
+
elements,
|
|
12197
|
+
consumed: pos - ctx.pos + count
|
|
12198
|
+
};
|
|
12199
|
+
}
|
|
12200
|
+
};
|
|
12201
|
+
|
|
12202
|
+
// packages/parser/src/parser/rules/inline/email/index.ts
|
|
12203
|
+
var emailRule = {
|
|
12204
|
+
name: "email",
|
|
12205
|
+
startTokens: EMAIL_START_TOKENS,
|
|
12206
|
+
parse(ctx) {
|
|
12207
|
+
const group = getEmailGroup(ctx.tokens, ctx.pos, ctx.scope.inlineEnd ?? ctx.tokens.length);
|
|
12208
|
+
if (!group)
|
|
12209
|
+
return { success: false };
|
|
12210
|
+
const elements = [];
|
|
12211
|
+
let copied = group.start;
|
|
12212
|
+
for (const candidate of group.candidates) {
|
|
12213
|
+
if (copied < candidate.start)
|
|
12214
|
+
elements.push({ element: "text", data: group.source.slice(copied, candidate.start) });
|
|
12215
|
+
elements.push(ctx.scope.suppressEmailLinks ? { element: "text", data: candidate.address } : {
|
|
12216
|
+
element: "link",
|
|
12217
|
+
data: {
|
|
12218
|
+
type: "direct",
|
|
12219
|
+
link: `mailto:${candidate.address}`,
|
|
12220
|
+
label: { text: candidate.address },
|
|
12221
|
+
target: null,
|
|
12222
|
+
extra: null
|
|
12223
|
+
}
|
|
12224
|
+
});
|
|
12225
|
+
copied = candidate.end;
|
|
12226
|
+
}
|
|
12227
|
+
if (copied < group.end)
|
|
12228
|
+
elements.push({ element: "text", data: group.source.slice(copied, group.end) });
|
|
12229
|
+
return { success: true, elements, consumed: group.endToken - ctx.pos };
|
|
12230
|
+
}
|
|
12231
|
+
};
|
|
12232
|
+
|
|
11071
12233
|
// packages/parser/src/parser/rules/inline/color/syntax.ts
|
|
11072
12234
|
function parseColorContent(ctx) {
|
|
11073
12235
|
const close = findFormattingClose(ctx, ctx.pos + 1, "COLOR_MARKER");
|
|
@@ -11154,7 +12316,7 @@ var newlineLineBreakRule = {
|
|
|
11154
12316
|
}
|
|
11155
12317
|
return {
|
|
11156
12318
|
success: true,
|
|
11157
|
-
elements: [
|
|
12319
|
+
elements: [createAutomaticLineBreak(currentTok)],
|
|
11158
12320
|
consumed: 1
|
|
11159
12321
|
};
|
|
11160
12322
|
}
|
|
@@ -11177,6 +12339,9 @@ function isValidBlockStartAfterNewline(ctx, tokenPos) {
|
|
|
11177
12339
|
if (!isBlockStartToken(token5?.type) || !token5?.lineStart) {
|
|
11178
12340
|
return false;
|
|
11179
12341
|
}
|
|
12342
|
+
if (token5.type === "LIST_BULLET" || token5.type === "LIST_NUMBER") {
|
|
12343
|
+
return ctx.tokens[tokenPos + 1]?.type === "WHITESPACE";
|
|
12344
|
+
}
|
|
11180
12345
|
if (token5.type !== "HEADING_MARKER") {
|
|
11181
12346
|
return true;
|
|
11182
12347
|
}
|
|
@@ -11434,6 +12599,9 @@ var htmlInlineRule = {
|
|
|
11434
12599
|
}
|
|
11435
12600
|
};
|
|
11436
12601
|
|
|
12602
|
+
// packages/parser/src/parser/rules/inline/raw/angle.ts
|
|
12603
|
+
import { decodeHTML } from "entities";
|
|
12604
|
+
|
|
11437
12605
|
// packages/parser/src/parser/rules/inline/raw/result.ts
|
|
11438
12606
|
function rawElement(value, consumed) {
|
|
11439
12607
|
return {
|
|
@@ -11481,7 +12649,7 @@ function parseAngleRaw(ctx) {
|
|
|
11481
12649
|
if (ctx.tokens[pos]?.type === "RAW_BLOCK_CLOSE") {
|
|
11482
12650
|
consumed++;
|
|
11483
12651
|
}
|
|
11484
|
-
return rawElement(value, consumed);
|
|
12652
|
+
return rawElement(decodeHTML(value), consumed);
|
|
11485
12653
|
}
|
|
11486
12654
|
|
|
11487
12655
|
// packages/parser/src/parser/rules/inline/raw/double-at.ts
|
|
@@ -11704,7 +12872,7 @@ function consumeSpanNewline(ctx, pos, paragraphStrip, afterBlankLine, children,
|
|
|
11704
12872
|
return { consumed: consumed2, afterBlankLine: paragraphStrip };
|
|
11705
12873
|
}
|
|
11706
12874
|
const targetChildren = paragraphStrip && afterBlankLine ? escapedChildren : children;
|
|
11707
|
-
targetChildren.push(
|
|
12875
|
+
targetChildren.push(createAutomaticLineBreak(ctx.tokens[pos]));
|
|
11708
12876
|
let consumed = 1;
|
|
11709
12877
|
let nextPos = pos + 1;
|
|
11710
12878
|
while (ctx.tokens[nextPos]?.type === "WHITESPACE" && ctx.tokens[nextPos]?.lineStart) {
|
|
@@ -11792,7 +12960,9 @@ function parseOneSpanChild(ctx, pos, targetChildren) {
|
|
|
11792
12960
|
for (const rule of getCandidateInlineRules(inlineRules, token5.type)) {
|
|
11793
12961
|
const result = rule.parse(inlineCtx);
|
|
11794
12962
|
if (result.success) {
|
|
11795
|
-
targetChildren
|
|
12963
|
+
stripAutomaticLineBreak(targetChildren, result.stripLeadingLineBreak);
|
|
12964
|
+
for (const element of result.elements)
|
|
12965
|
+
targetChildren.push(element);
|
|
11796
12966
|
return { consumed: result.consumed };
|
|
11797
12967
|
}
|
|
11798
12968
|
}
|
|
@@ -11860,56 +13030,60 @@ var closeSpanRule = {
|
|
|
11860
13030
|
}
|
|
11861
13031
|
};
|
|
11862
13032
|
|
|
11863
|
-
// packages/parser/src/parser/rules/inline/
|
|
11864
|
-
|
|
11865
|
-
|
|
11866
|
-
|
|
11867
|
-
|
|
11868
|
-
|
|
11869
|
-
|
|
11870
|
-
|
|
11871
|
-
|
|
11872
|
-
|
|
11873
|
-
|
|
11874
|
-
if (closeResult) {
|
|
11875
|
-
return {
|
|
11876
|
-
children,
|
|
11877
|
-
consumed: consumed + closeResult.consumed,
|
|
11878
|
-
foundClose: true
|
|
11879
|
-
};
|
|
11880
|
-
}
|
|
11881
|
-
const inlineCtx = { ...ctx, pos };
|
|
11882
|
-
const inlineResult = parseInlineUntil(inlineCtx, "BLOCK_END_OPEN");
|
|
11883
|
-
if (inlineResult.elements.length > 0) {
|
|
11884
|
-
children.push(...inlineResult.elements);
|
|
11885
|
-
pos += inlineResult.consumed;
|
|
11886
|
-
consumed += inlineResult.consumed;
|
|
11887
|
-
} else {
|
|
11888
|
-
children.push({ element: "text", data: token5.value });
|
|
11889
|
-
pos++;
|
|
11890
|
-
consumed++;
|
|
11891
|
-
}
|
|
11892
|
-
}
|
|
11893
|
-
return { children, consumed, foundClose: false };
|
|
11894
|
-
}
|
|
11895
|
-
function tryConsumeSizeClose(ctx, pos) {
|
|
11896
|
-
if (ctx.tokens[pos]?.type !== "BLOCK_END_OPEN") {
|
|
11897
|
-
return null;
|
|
13033
|
+
// packages/parser/src/parser/rules/inline/button/index.ts
|
|
13034
|
+
var buttonRule = {
|
|
13035
|
+
name: "button",
|
|
13036
|
+
startTokens: ["BLOCK_OPEN"],
|
|
13037
|
+
parse(ctx) {
|
|
13038
|
+
const result = parseButtonSyntax(ctx, ctx.pos, ctx.scope.inlineEnd ?? ctx.tokens.length);
|
|
13039
|
+
return result ? {
|
|
13040
|
+
success: true,
|
|
13041
|
+
consumed: result.end - ctx.pos,
|
|
13042
|
+
elements: [{ element: "button", data: result.data }]
|
|
13043
|
+
} : { success: false };
|
|
11898
13044
|
}
|
|
11899
|
-
|
|
11900
|
-
|
|
11901
|
-
|
|
13045
|
+
};
|
|
13046
|
+
|
|
13047
|
+
// packages/parser/src/parser/rules/inline/social/index.ts
|
|
13048
|
+
var socialRule = {
|
|
13049
|
+
name: "social",
|
|
13050
|
+
startTokens: ["BLOCK_OPEN"],
|
|
13051
|
+
parse(ctx) {
|
|
13052
|
+
const result = parseSocialSyntax(ctx, ctx.pos, ctx.scope.inlineEnd ?? ctx.tokens.length);
|
|
13053
|
+
return result ? {
|
|
13054
|
+
success: true,
|
|
13055
|
+
consumed: result.end - ctx.pos,
|
|
13056
|
+
elements: [{ element: "social", data: result.data }]
|
|
13057
|
+
} : { success: false };
|
|
11902
13058
|
}
|
|
11903
|
-
|
|
11904
|
-
|
|
11905
|
-
|
|
11906
|
-
|
|
13059
|
+
};
|
|
13060
|
+
|
|
13061
|
+
// packages/parser/src/parser/rules/inline/date/index.ts
|
|
13062
|
+
var dateRule = {
|
|
13063
|
+
name: "date",
|
|
13064
|
+
startTokens: ["BLOCK_OPEN"],
|
|
13065
|
+
parse(ctx) {
|
|
13066
|
+
const parsed = parseDateSyntax(ctx, ctx.pos, ctx.scope.inlineEnd ?? ctx.tokens.length);
|
|
13067
|
+
return parsed ? {
|
|
13068
|
+
success: true,
|
|
13069
|
+
consumed: parsed.end - ctx.pos,
|
|
13070
|
+
elements: [{ element: "date", data: parsed.data }]
|
|
13071
|
+
} : { success: false };
|
|
11907
13072
|
}
|
|
11908
|
-
|
|
11909
|
-
}
|
|
13073
|
+
};
|
|
11910
13074
|
|
|
11911
13075
|
// packages/parser/src/parser/rules/inline/size/value.ts
|
|
11912
13076
|
var VALID_SIZE_UNITS = ["px", "em", "rem", "ex", "%", "cm", "mm", "in", "pc"];
|
|
13077
|
+
var VALID_SIZE_KEYWORDS = [
|
|
13078
|
+
"smaller",
|
|
13079
|
+
"larger",
|
|
13080
|
+
"xx-small",
|
|
13081
|
+
"x-small",
|
|
13082
|
+
"small",
|
|
13083
|
+
"large",
|
|
13084
|
+
"x-large",
|
|
13085
|
+
"xx-large"
|
|
13086
|
+
];
|
|
11913
13087
|
function parseSizeValue(ctx, startPos) {
|
|
11914
13088
|
let pos = startPos;
|
|
11915
13089
|
let consumed = 0;
|
|
@@ -11934,6 +13108,8 @@ function parseSizeValue(ctx, startPos) {
|
|
|
11934
13108
|
return isValidSizeValue(size) ? { size, consumed } : null;
|
|
11935
13109
|
}
|
|
11936
13110
|
function isValidSizeValue(size) {
|
|
13111
|
+
if (VALID_SIZE_KEYWORDS.includes(size))
|
|
13112
|
+
return true;
|
|
11937
13113
|
const unitPattern = VALID_SIZE_UNITS.join("|");
|
|
11938
13114
|
return new RegExp(`^(\\d+(?:\\.\\d+)?)(${unitPattern})$`, "i").test(size);
|
|
11939
13115
|
}
|
|
@@ -11965,6 +13141,81 @@ function parseSizeOpen(ctx) {
|
|
|
11965
13141
|
return { size: sizeResult.size, bodyStart: pos, consumed };
|
|
11966
13142
|
}
|
|
11967
13143
|
|
|
13144
|
+
// packages/parser/src/parser/rules/inline/size/content.ts
|
|
13145
|
+
function parseSizeContent(ctx, startPos) {
|
|
13146
|
+
const children = [];
|
|
13147
|
+
let pos = startPos;
|
|
13148
|
+
let consumed = 0;
|
|
13149
|
+
const inlineEnd = findSizeClose(ctx, startPos);
|
|
13150
|
+
while (pos < (ctx.scope.inlineEnd ?? ctx.tokens.length)) {
|
|
13151
|
+
const token5 = ctx.tokens[pos];
|
|
13152
|
+
if (!token5 || token5.type === "EOF") {
|
|
13153
|
+
break;
|
|
13154
|
+
}
|
|
13155
|
+
const closeResult = tryConsumeSizeClose(ctx, pos);
|
|
13156
|
+
if (closeResult) {
|
|
13157
|
+
return {
|
|
13158
|
+
children,
|
|
13159
|
+
consumed: consumed + closeResult.consumed,
|
|
13160
|
+
foundClose: true
|
|
13161
|
+
};
|
|
13162
|
+
}
|
|
13163
|
+
const inlineCtx = { ...ctx, pos, scope: { ...ctx.scope, inlineEnd } };
|
|
13164
|
+
const inlineResult = parseInlineUntil(inlineCtx, "EOF");
|
|
13165
|
+
if (inlineResult.consumed > 0) {
|
|
13166
|
+
for (const element of inlineResult.elements)
|
|
13167
|
+
children.push(element);
|
|
13168
|
+
pos += inlineResult.consumed;
|
|
13169
|
+
consumed += inlineResult.consumed;
|
|
13170
|
+
} else {
|
|
13171
|
+
children.push({ element: "text", data: token5.value });
|
|
13172
|
+
pos++;
|
|
13173
|
+
consumed++;
|
|
13174
|
+
}
|
|
13175
|
+
}
|
|
13176
|
+
return { children, consumed, foundClose: false };
|
|
13177
|
+
}
|
|
13178
|
+
function findSizeClose(ctx, startPos) {
|
|
13179
|
+
const end = ctx.scope.inlineEnd ?? ctx.tokens.length;
|
|
13180
|
+
let depth = 0;
|
|
13181
|
+
for (let pos = startPos;pos < end; pos++) {
|
|
13182
|
+
const protectedEnd = protectedInlineRegionEnd(ctx.tokens, pos, end);
|
|
13183
|
+
if (protectedEnd > pos) {
|
|
13184
|
+
pos = protectedEnd - 1;
|
|
13185
|
+
continue;
|
|
13186
|
+
}
|
|
13187
|
+
const open = ctx.tokens[pos]?.type === "BLOCK_OPEN" ? parseSizeOpen({ ...ctx, pos }) : null;
|
|
13188
|
+
if (open) {
|
|
13189
|
+
depth++;
|
|
13190
|
+
pos = open.bodyStart - 1;
|
|
13191
|
+
continue;
|
|
13192
|
+
}
|
|
13193
|
+
const close = tryConsumeSizeClose(ctx, pos);
|
|
13194
|
+
if (!close)
|
|
13195
|
+
continue;
|
|
13196
|
+
if (depth === 0)
|
|
13197
|
+
return pos;
|
|
13198
|
+
depth--;
|
|
13199
|
+
pos += close.consumed - 1;
|
|
13200
|
+
}
|
|
13201
|
+
return end;
|
|
13202
|
+
}
|
|
13203
|
+
function tryConsumeSizeClose(ctx, pos) {
|
|
13204
|
+
if (ctx.tokens[pos]?.type !== "BLOCK_END_OPEN") {
|
|
13205
|
+
return null;
|
|
13206
|
+
}
|
|
13207
|
+
const closeNameResult = parseBlockName(ctx, pos + 1);
|
|
13208
|
+
if (!closeNameResult || closeNameResult.name !== "size") {
|
|
13209
|
+
return null;
|
|
13210
|
+
}
|
|
13211
|
+
let closePos = pos + 1 + closeNameResult.consumed;
|
|
13212
|
+
let consumed = 1 + closeNameResult.consumed;
|
|
13213
|
+
if (ctx.tokens[closePos]?.type === "BLOCK_CLOSE") {
|
|
13214
|
+
consumed++;
|
|
13215
|
+
}
|
|
13216
|
+
return { consumed };
|
|
13217
|
+
}
|
|
13218
|
+
|
|
11968
13219
|
// packages/parser/src/parser/rules/inline/size/index.ts
|
|
11969
13220
|
var sizeRule = {
|
|
11970
13221
|
name: "size",
|
|
@@ -12005,19 +13256,6 @@ var sizeRule = {
|
|
|
12005
13256
|
}
|
|
12006
13257
|
};
|
|
12007
13258
|
|
|
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
13259
|
// packages/parser/src/parser/rules/inline/footnote/close.ts
|
|
12022
13260
|
function tryConsumeFootnoteClose(ctx, pos) {
|
|
12023
13261
|
if (ctx.tokens[pos]?.type !== "BLOCK_END_OPEN") {
|
|
@@ -12039,96 +13277,73 @@ function tryConsumeFootnoteClose(ctx, pos) {
|
|
|
12039
13277
|
return { consumed };
|
|
12040
13278
|
}
|
|
12041
13279
|
|
|
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 };
|
|
13280
|
+
// packages/parser/src/parser/rules/inline/math-inline/syntax.ts
|
|
13281
|
+
function parseInlineMathSource(ctx, startPos) {
|
|
13282
|
+
let pos = startPos;
|
|
13283
|
+
let consumed = 0;
|
|
13284
|
+
if (ctx.tokens[pos]?.type !== "TEXT" || ctx.tokens[pos]?.value !== "$") {
|
|
13285
|
+
return null;
|
|
12052
13286
|
}
|
|
12053
|
-
|
|
12054
|
-
|
|
13287
|
+
pos++;
|
|
13288
|
+
consumed++;
|
|
13289
|
+
while (ctx.tokens[pos]?.type === "WHITESPACE") {
|
|
13290
|
+
pos++;
|
|
12055
13291
|
consumed++;
|
|
12056
13292
|
}
|
|
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;
|
|
13293
|
+
let latexSource = "";
|
|
12066
13294
|
while (pos < ctx.tokens.length) {
|
|
12067
13295
|
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
|
-
};
|
|
13296
|
+
if (!token5 || token5.type === "NEWLINE") {
|
|
13297
|
+
return null;
|
|
12078
13298
|
}
|
|
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;
|
|
13299
|
+
if (token5.type === "TEXT" && token5.value === "$" && ctx.tokens[pos + 1]?.type === "BLOCK_CLOSE") {
|
|
13300
|
+
break;
|
|
12090
13301
|
}
|
|
12091
|
-
|
|
12092
|
-
|
|
12093
|
-
|
|
12094
|
-
|
|
13302
|
+
latexSource += token5.value;
|
|
13303
|
+
pos++;
|
|
13304
|
+
consumed++;
|
|
13305
|
+
}
|
|
13306
|
+
if (ctx.tokens[pos]?.type !== "TEXT" || ctx.tokens[pos]?.value !== "$") {
|
|
13307
|
+
return null;
|
|
13308
|
+
}
|
|
13309
|
+
pos++;
|
|
13310
|
+
consumed++;
|
|
13311
|
+
if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
|
|
13312
|
+
return null;
|
|
12095
13313
|
}
|
|
12096
|
-
return {
|
|
13314
|
+
return {
|
|
13315
|
+
latexSource: latexSource.trim(),
|
|
13316
|
+
consumed: consumed + 1
|
|
13317
|
+
};
|
|
12097
13318
|
}
|
|
12098
13319
|
|
|
12099
|
-
// packages/parser/src/parser/rules/inline/
|
|
12100
|
-
|
|
12101
|
-
|
|
12102
|
-
|
|
12103
|
-
|
|
12104
|
-
|
|
12105
|
-
|
|
13320
|
+
// packages/parser/src/parser/rules/inline/math-inline/index.ts
|
|
13321
|
+
var mathInlineRule = {
|
|
13322
|
+
name: "math-inline",
|
|
13323
|
+
startTokens: ["BLOCK_OPEN"],
|
|
13324
|
+
parse(ctx) {
|
|
13325
|
+
const openToken = currentToken(ctx);
|
|
13326
|
+
if (openToken.type !== "BLOCK_OPEN") {
|
|
13327
|
+
return { success: false };
|
|
12106
13328
|
}
|
|
12107
|
-
|
|
12108
|
-
|
|
12109
|
-
|
|
12110
|
-
children.push({
|
|
12111
|
-
element: "container",
|
|
12112
|
-
data: {
|
|
12113
|
-
type: "paragraph",
|
|
12114
|
-
attributes: {},
|
|
12115
|
-
elements: para
|
|
12116
|
-
}
|
|
12117
|
-
});
|
|
13329
|
+
const parsed = parseInlineMathSource(ctx, ctx.pos + 1);
|
|
13330
|
+
if (!parsed) {
|
|
13331
|
+
return { success: false };
|
|
12118
13332
|
}
|
|
13333
|
+
return {
|
|
13334
|
+
success: true,
|
|
13335
|
+
elements: [
|
|
13336
|
+
{
|
|
13337
|
+
element: "math-inline",
|
|
13338
|
+
data: {
|
|
13339
|
+
"latex-source": parsed.latexSource
|
|
13340
|
+
}
|
|
13341
|
+
}
|
|
13342
|
+
],
|
|
13343
|
+
consumed: 1 + parsed.consumed
|
|
13344
|
+
};
|
|
12119
13345
|
}
|
|
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
|
-
}
|
|
13346
|
+
};
|
|
12132
13347
|
|
|
12133
13348
|
// packages/parser/src/parser/rules/inline/footnote/open.ts
|
|
12134
13349
|
function parseFootnoteOpen(ctx) {
|
|
@@ -12155,6 +13370,91 @@ function parseFootnoteOpen(ctx) {
|
|
|
12155
13370
|
return { bodyStart: pos, consumed };
|
|
12156
13371
|
}
|
|
12157
13372
|
|
|
13373
|
+
// packages/parser/src/parser/rules/inline/footnote/boundary.ts
|
|
13374
|
+
var opaqueRules2 = [
|
|
13375
|
+
codeBlockRule,
|
|
13376
|
+
htmlBlockRule,
|
|
13377
|
+
mathBlockRule,
|
|
13378
|
+
mathInlineRule,
|
|
13379
|
+
linkTripleRule,
|
|
13380
|
+
linkSingleRule,
|
|
13381
|
+
linkStarRule,
|
|
13382
|
+
linkAnchorRule
|
|
13383
|
+
];
|
|
13384
|
+
function findFootnoteEnd(ctx, start) {
|
|
13385
|
+
const probe = createOpaqueProbe(ctx);
|
|
13386
|
+
let depth = 0;
|
|
13387
|
+
for (let pos = start;pos < ctx.tokens.length; pos++) {
|
|
13388
|
+
if (ctx.tokens[pos]?.type === "EOF")
|
|
13389
|
+
return pos;
|
|
13390
|
+
const protectedEnd = protectedInlineRegionEnd(ctx.tokens, pos, ctx.tokens.length);
|
|
13391
|
+
if (protectedEnd > pos) {
|
|
13392
|
+
pos = protectedEnd - 1;
|
|
13393
|
+
continue;
|
|
13394
|
+
}
|
|
13395
|
+
probe.pos = pos;
|
|
13396
|
+
const close = tryConsumeFootnoteClose(probe, pos);
|
|
13397
|
+
if (close) {
|
|
13398
|
+
if (depth === 0)
|
|
13399
|
+
return pos;
|
|
13400
|
+
depth--;
|
|
13401
|
+
pos += close.consumed - 1;
|
|
13402
|
+
continue;
|
|
13403
|
+
}
|
|
13404
|
+
const open = parseFootnoteOpen(probe);
|
|
13405
|
+
if (open) {
|
|
13406
|
+
depth++;
|
|
13407
|
+
pos += open.consumed - 1;
|
|
13408
|
+
continue;
|
|
13409
|
+
}
|
|
13410
|
+
const opaqueEnd = opaqueRuleEnd(probe, pos, opaqueRules2);
|
|
13411
|
+
if (opaqueEnd > pos)
|
|
13412
|
+
pos = opaqueEnd - 1;
|
|
13413
|
+
}
|
|
13414
|
+
return ctx.tokens.length;
|
|
13415
|
+
}
|
|
13416
|
+
|
|
13417
|
+
// packages/parser/src/parser/rules/inline/footnote/content.ts
|
|
13418
|
+
function parseFootnoteContent(ctx, startPos) {
|
|
13419
|
+
const end = findFootnoteEnd(ctx, startPos);
|
|
13420
|
+
let leadingNewlines = 0;
|
|
13421
|
+
for (let pos = startPos;pos < end; pos++) {
|
|
13422
|
+
const type = ctx.tokens[pos]?.type;
|
|
13423
|
+
if (type === "NEWLINE")
|
|
13424
|
+
leadingNewlines++;
|
|
13425
|
+
else if (type !== "WHITESPACE")
|
|
13426
|
+
break;
|
|
13427
|
+
}
|
|
13428
|
+
const bodyCtx = {
|
|
13429
|
+
...ctx,
|
|
13430
|
+
tokens: ctx.tokens.slice(startPos, end),
|
|
13431
|
+
pos: 0,
|
|
13432
|
+
scope: {
|
|
13433
|
+
...ctx.scope,
|
|
13434
|
+
inlineEnd: undefined,
|
|
13435
|
+
tableFormatting: undefined,
|
|
13436
|
+
blockCloseCondition: undefined
|
|
13437
|
+
}
|
|
13438
|
+
};
|
|
13439
|
+
const result = parseBlocksUntil(bodyCtx, () => false);
|
|
13440
|
+
const close = tryConsumeFootnoteClose(ctx, end);
|
|
13441
|
+
return {
|
|
13442
|
+
elements: result.elements,
|
|
13443
|
+
consumed: end - startPos + (close?.consumed ?? 0),
|
|
13444
|
+
foundClose: close !== null,
|
|
13445
|
+
leadingParagraphBreak: leadingNewlines >= 2
|
|
13446
|
+
};
|
|
13447
|
+
}
|
|
13448
|
+
|
|
13449
|
+
// packages/parser/src/parser/rules/inline/footnote/elements.ts
|
|
13450
|
+
function buildFootnoteChildren(elements, leadingParagraphBreak) {
|
|
13451
|
+
const first = elements[0];
|
|
13452
|
+
if (!leadingParagraphBreak && first?.element === "container" && first.data.type === "paragraph") {
|
|
13453
|
+
return [...first.data.elements, ...elements.slice(1)];
|
|
13454
|
+
}
|
|
13455
|
+
return elements;
|
|
13456
|
+
}
|
|
13457
|
+
|
|
12158
13458
|
// packages/parser/src/parser/rules/inline/footnote/index.ts
|
|
12159
13459
|
var footnoteRule = {
|
|
12160
13460
|
name: "footnote",
|
|
@@ -12170,7 +13470,7 @@ var footnoteRule = {
|
|
|
12170
13470
|
}
|
|
12171
13471
|
const contentResult = parseFootnoteContent(ctx, openResult.bodyStart);
|
|
12172
13472
|
const consumed = openResult.consumed + contentResult.consumed;
|
|
12173
|
-
const children = buildFootnoteChildren(contentResult.
|
|
13473
|
+
const children = buildFootnoteChildren(contentResult.elements, contentResult.leadingParagraphBreak);
|
|
12174
13474
|
if (!contentResult.foundClose) {
|
|
12175
13475
|
ctx.diagnostics.push({
|
|
12176
13476
|
severity: "warning",
|
|
@@ -12530,11 +13830,15 @@ function parseAnchorChild(ctx, pos) {
|
|
|
12530
13830
|
if (!token5) {
|
|
12531
13831
|
return { elements: [], consumed: 0 };
|
|
12532
13832
|
}
|
|
12533
|
-
const inlineCtx = {
|
|
13833
|
+
const inlineCtx = {
|
|
13834
|
+
...ctx,
|
|
13835
|
+
pos,
|
|
13836
|
+
scope: { ...ctx.scope, suppressEmailLinks: true }
|
|
13837
|
+
};
|
|
12534
13838
|
for (const rule of getCandidateInlineRules(inlineRules, token5.type)) {
|
|
12535
13839
|
const result = rule.parse(inlineCtx);
|
|
12536
13840
|
if (result.success) {
|
|
12537
|
-
return
|
|
13841
|
+
return result;
|
|
12538
13842
|
}
|
|
12539
13843
|
}
|
|
12540
13844
|
return { elements: [{ element: "text", data: token5.value }], consumed: 1 };
|
|
@@ -12594,7 +13898,7 @@ function consumeAnchorNewline(ctx, pos, paragraphStrip, children) {
|
|
|
12594
13898
|
let consumed = 1;
|
|
12595
13899
|
let nextPos = pos + 1;
|
|
12596
13900
|
if (!paragraphStrip) {
|
|
12597
|
-
children.push(
|
|
13901
|
+
children.push(createAutomaticLineBreak(ctx.tokens[pos]));
|
|
12598
13902
|
while (ctx.tokens[nextPos]?.type === "WHITESPACE" && ctx.tokens[nextPos]?.lineStart) {
|
|
12599
13903
|
nextPos++;
|
|
12600
13904
|
consumed++;
|
|
@@ -12647,7 +13951,9 @@ function parseAnchorContent(ctx, startPos, paragraphStrip) {
|
|
|
12647
13951
|
continue;
|
|
12648
13952
|
}
|
|
12649
13953
|
const child = parseAnchorChild(ctx, pos);
|
|
12650
|
-
children
|
|
13954
|
+
stripAutomaticLineBreak(children, child.stripLeadingLineBreak);
|
|
13955
|
+
for (const element of child.elements)
|
|
13956
|
+
children.push(element);
|
|
12651
13957
|
pos += child.consumed;
|
|
12652
13958
|
consumed += child.consumed;
|
|
12653
13959
|
}
|
|
@@ -12721,75 +14027,8 @@ var anchorRule = {
|
|
|
12721
14027
|
}
|
|
12722
14028
|
}
|
|
12723
14029
|
],
|
|
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
|
|
14030
|
+
consumed,
|
|
14031
|
+
stripLeadingLineBreak: openResult.paragraphStrip ? precedingSingleNewline(ctx) : undefined
|
|
12793
14032
|
};
|
|
12794
14033
|
}
|
|
12795
14034
|
};
|
|
@@ -12900,7 +14139,9 @@ function parseInlineBranch(ctx, startPos) {
|
|
|
12900
14139
|
}
|
|
12901
14140
|
const result = rule.parse(inlineCtx);
|
|
12902
14141
|
if (result.success) {
|
|
12903
|
-
elements
|
|
14142
|
+
stripAutomaticLineBreak(elements, result.stripLeadingLineBreak);
|
|
14143
|
+
for (const element of result.elements)
|
|
14144
|
+
elements.push(element);
|
|
12904
14145
|
consumed += result.consumed;
|
|
12905
14146
|
pos += result.consumed;
|
|
12906
14147
|
matched = true;
|
|
@@ -13223,6 +14464,7 @@ var textRule = {
|
|
|
13223
14464
|
|
|
13224
14465
|
// packages/parser/src/parser/rules/inline/index.ts
|
|
13225
14466
|
var inlineRules = [
|
|
14467
|
+
emailRule,
|
|
13226
14468
|
boldRule,
|
|
13227
14469
|
italicRule,
|
|
13228
14470
|
underlineRule,
|
|
@@ -13234,6 +14476,7 @@ var inlineRules = [
|
|
|
13234
14476
|
linkSingleRule,
|
|
13235
14477
|
linkAnchorRule,
|
|
13236
14478
|
linkStarRule,
|
|
14479
|
+
autolinkRule,
|
|
13237
14480
|
colorRule,
|
|
13238
14481
|
backslashLineBreakRule,
|
|
13239
14482
|
underscoreLineBreakRule,
|
|
@@ -13243,6 +14486,9 @@ var inlineRules = [
|
|
|
13243
14486
|
rawRule,
|
|
13244
14487
|
imageRule,
|
|
13245
14488
|
embedBlockRule,
|
|
14489
|
+
buttonRule,
|
|
14490
|
+
socialRule,
|
|
14491
|
+
dateRule,
|
|
13246
14492
|
sizeRule,
|
|
13247
14493
|
footnoteRule,
|
|
13248
14494
|
spanRule,
|
|
@@ -13498,6 +14744,8 @@ function mergeSpanStripParagraphs(children) {
|
|
|
13498
14744
|
i++;
|
|
13499
14745
|
continue;
|
|
13500
14746
|
}
|
|
14747
|
+
const firstMeaningful = paraData.elements.find((child) => child.element !== "line-break" && !isWhitespaceText(child));
|
|
14748
|
+
const keepParagraph = firstMeaningful && !isSpanStripMarker(firstMeaningful);
|
|
13501
14749
|
const mergedChildren = [...paraData.elements];
|
|
13502
14750
|
i++;
|
|
13503
14751
|
while (i < expandedChildren.length) {
|
|
@@ -13510,7 +14758,8 @@ function mergeSpanStripParagraphs(children) {
|
|
|
13510
14758
|
break;
|
|
13511
14759
|
}
|
|
13512
14760
|
const hasSpanStrip = hasParagraphStripSpan(nextPara);
|
|
13513
|
-
|
|
14761
|
+
for (const element of nextParaData.elements)
|
|
14762
|
+
mergedChildren.push(element);
|
|
13514
14763
|
i++;
|
|
13515
14764
|
if (!hasSpanStrip) {
|
|
13516
14765
|
const peekNext = expandedChildren[i];
|
|
@@ -13521,7 +14770,7 @@ function mergeSpanStripParagraphs(children) {
|
|
|
13521
14770
|
}
|
|
13522
14771
|
const escapedSpans = extractEscapedSpans(mergedChildren);
|
|
13523
14772
|
removeLineBreaksAroundSpanStrip(mergedChildren);
|
|
13524
|
-
if (escapedSpans.length > 0) {
|
|
14773
|
+
if (escapedSpans.length > 0 || keepParagraph) {
|
|
13525
14774
|
if (mergedChildren.length > 0) {
|
|
13526
14775
|
result.push(paragraphElement(mergedChildren));
|
|
13527
14776
|
}
|
|
@@ -13742,50 +14991,6 @@ function cleanInternalFlags(elements) {
|
|
|
13742
14991
|
}
|
|
13743
14992
|
return removeEmptySpansAndAdjacentWhitespace(cleaned ?? elements);
|
|
13744
14993
|
}
|
|
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
14994
|
// packages/parser/src/parser/parse/footnotes.ts
|
|
13790
14995
|
function containsFootnoteBlock(elements) {
|
|
13791
14996
|
let found = false;
|
|
@@ -14063,7 +15268,9 @@ function substitute(text2) {
|
|
|
14063
15268
|
result = result.replace(WHITESPACE_ONLY_LINE, "");
|
|
14064
15269
|
}
|
|
14065
15270
|
if (result.indexOf("\\\n") !== -1) {
|
|
14066
|
-
|
|
15271
|
+
const sentinels = makeUniqueSentinels(result);
|
|
15272
|
+
const { masked, placeholders } = maskRawRegions(result, sentinels);
|
|
15273
|
+
result = restorePlaceholders(masked.replace(CONCAT_LINES, String.fromCharCode(57344)), placeholders, sentinels);
|
|
14067
15274
|
}
|
|
14068
15275
|
if (result.indexOf("\t") !== -1) {
|
|
14069
15276
|
result = result.replace(TABS, " ");
|
|
@@ -14130,14 +15337,26 @@ function replaceDelimitedTypography(text2, opener, closer, leftQuote, rightQuote
|
|
|
14130
15337
|
let searchFrom = 0;
|
|
14131
15338
|
let result = "";
|
|
14132
15339
|
let lastCopied = 0;
|
|
15340
|
+
let closeIndex = -1;
|
|
15341
|
+
let newlineIndex = -1;
|
|
14133
15342
|
while (searchFrom < text2.length) {
|
|
14134
15343
|
const openIndex = text2.indexOf(opener, searchFrom);
|
|
14135
15344
|
if (openIndex === -1)
|
|
14136
15345
|
break;
|
|
14137
15346
|
const contentStart = openIndex + opener.length;
|
|
14138
|
-
|
|
15347
|
+
if (closeIndex < contentStart)
|
|
15348
|
+
closeIndex = text2.indexOf(closer, contentStart);
|
|
14139
15349
|
if (closeIndex === -1)
|
|
14140
15350
|
break;
|
|
15351
|
+
if (newlineIndex < contentStart) {
|
|
15352
|
+
const nextNewline = text2.indexOf(`
|
|
15353
|
+
`, contentStart);
|
|
15354
|
+
newlineIndex = nextNewline === -1 ? text2.length : nextNewline;
|
|
15355
|
+
}
|
|
15356
|
+
if (newlineIndex < closeIndex) {
|
|
15357
|
+
searchFrom = newlineIndex + 1;
|
|
15358
|
+
continue;
|
|
15359
|
+
}
|
|
14141
15360
|
result += text2.slice(lastCopied, openIndex);
|
|
14142
15361
|
result += leftQuote;
|
|
14143
15362
|
result += text2.slice(contentStart, closeIndex);
|
|
@@ -14148,7 +15367,12 @@ function replaceDelimitedTypography(text2, opener, closer, leftQuote, rightQuote
|
|
|
14148
15367
|
return lastCopied === 0 ? text2 : result + text2.slice(lastCopied);
|
|
14149
15368
|
}
|
|
14150
15369
|
function substitute2(text2) {
|
|
14151
|
-
|
|
15370
|
+
if (!text2.includes("`") && !text2.includes(",,") && !text2.includes("...") && !text2.includes(". . .")) {
|
|
15371
|
+
return text2;
|
|
15372
|
+
}
|
|
15373
|
+
const sentinels = makeUniqueSentinels(text2);
|
|
15374
|
+
const { masked, placeholders } = maskRawRegions(text2, sentinels);
|
|
15375
|
+
let result = masked;
|
|
14152
15376
|
if (result.includes("``") && result.includes("''")) {
|
|
14153
15377
|
result = replaceDelimitedTypography(result, "``", "''", LEFT_DOUBLE_QUOTE, RIGHT_DOUBLE_QUOTE);
|
|
14154
15378
|
}
|
|
@@ -14164,7 +15388,7 @@ function substitute2(text2) {
|
|
|
14164
15388
|
if (result.includes(". . .")) {
|
|
14165
15389
|
result = replaceExactEllipsisPattern(result, ". . .");
|
|
14166
15390
|
}
|
|
14167
|
-
return result;
|
|
15391
|
+
return restorePlaceholders(result, placeholders, sentinels);
|
|
14168
15392
|
}
|
|
14169
15393
|
|
|
14170
15394
|
// packages/parser/src/parser/preprocess/index.ts
|
|
@@ -14404,14 +15628,17 @@ function parseSource(source, options, deferInclude) {
|
|
|
14404
15628
|
}
|
|
14405
15629
|
// packages/parser/src/pipeline/process.ts
|
|
14406
15630
|
import {
|
|
14407
|
-
DEFAULT_SETTINGS as DEFAULT_SETTINGS2
|
|
15631
|
+
DEFAULT_SETTINGS as DEFAULT_SETTINGS2,
|
|
15632
|
+
extractReadableText,
|
|
15633
|
+
extractFirstParagraph,
|
|
15634
|
+
countCharacters as countCharacters2
|
|
14408
15635
|
} from "@wdprlib/ast";
|
|
14409
15636
|
|
|
14410
15637
|
// packages/parser/src/parser/rules/block/module/resolution/resolve-async.ts
|
|
14411
15638
|
async function resolveModulesWithAsyncParse(ast, dataProvider, options) {
|
|
14412
15639
|
const registry = new ModuleDocumentRegistry;
|
|
14413
15640
|
registry.register(ast);
|
|
14414
|
-
const parse2 = async (source) => registry.register(await options.parse(source));
|
|
15641
|
+
const parse2 = async (source) => registry.register(suppressModuleRatings(await options.parse(source)));
|
|
14415
15642
|
const [listPagesData, listUsersData, tagCloudData] = await Promise.all([
|
|
14416
15643
|
buildListPagesDataMap(dataProvider, options.requirements.listPages ?? [], options.urlPath, options.paginationState),
|
|
14417
15644
|
buildListUsersDataMap(dataProvider, options.requirements.listUsers ?? []),
|
|
@@ -14647,8 +15874,13 @@ async function processWikitext(source, options) {
|
|
|
14647
15874
|
if (hasResolvableRequirements(extractDataRequirements(ast).requirements, options.dataProvider)) {
|
|
14648
15875
|
diagnostics.push(createLimitDiagnostic("module-resolution-limit", `Module resolution stopped after ${DEFAULT_MODULE_MAX_PASSES} passes.`));
|
|
14649
15876
|
}
|
|
15877
|
+
ast = await resolveRatings(ast, dataProvider.fetchRatings);
|
|
15878
|
+
const readableText = extractReadableText(ast, options.readableText);
|
|
14650
15879
|
return {
|
|
14651
15880
|
ast,
|
|
15881
|
+
readableText,
|
|
15882
|
+
firstParagraph: extractFirstParagraph(ast, options.readableText),
|
|
15883
|
+
characterCount: countCharacters2(readableText),
|
|
14652
15884
|
page: options.page,
|
|
14653
15885
|
settings,
|
|
14654
15886
|
diagnostics,
|
|
@@ -14677,6 +15909,7 @@ function createLimitDiagnostic(code, message) {
|
|
|
14677
15909
|
function createModuleDataProvider(options, context) {
|
|
14678
15910
|
const provider = options.dataProvider;
|
|
14679
15911
|
return {
|
|
15912
|
+
fetchRatings: provider?.fetchRatings ? (refs) => provider.fetchRatings(refs, context) : undefined,
|
|
14680
15913
|
fetchListPages: provider?.fetchListPages ? (query, requirement) => provider.fetchListPages(query, requirement, context) : undefined,
|
|
14681
15914
|
fetchListUsers: provider?.fetchListUsers ? (requirement) => provider.fetchListUsers(requirement, context) : undefined,
|
|
14682
15915
|
fetchTagCloud: provider?.fetchTagCloud ? (requirement) => provider.fetchTagCloud(requirement, context) : undefined,
|