@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.cjs
CHANGED
|
@@ -30,7 +30,7 @@ var __export = (target, all) => {
|
|
|
30
30
|
var exports_src = {};
|
|
31
31
|
__export(exports_src, {
|
|
32
32
|
tokenize: () => tokenize,
|
|
33
|
-
text: () =>
|
|
33
|
+
text: () => import_ast12.text,
|
|
34
34
|
resolveTagCloud: () => resolveTagCloud,
|
|
35
35
|
resolveModules: () => resolveModules,
|
|
36
36
|
resolveListUsers: () => resolveListUsers,
|
|
@@ -47,49 +47,49 @@ __export(exports_src, {
|
|
|
47
47
|
parseDateSelector: () => parseDateSelector,
|
|
48
48
|
parseCategory: () => parseCategory,
|
|
49
49
|
parse: () => parse,
|
|
50
|
-
paragraph: () =>
|
|
50
|
+
paragraph: () => import_ast12.paragraph,
|
|
51
51
|
normalizeQuery: () => normalizeQuery,
|
|
52
52
|
matchesListPagesSelectors: () => matchesListPagesSelectors,
|
|
53
|
-
listItemSubList: () =>
|
|
54
|
-
listItemElements: () =>
|
|
55
|
-
list: () =>
|
|
56
|
-
link: () =>
|
|
57
|
-
lineBreak: () =>
|
|
58
|
-
italics: () =>
|
|
53
|
+
listItemSubList: () => import_ast12.listItemSubList,
|
|
54
|
+
listItemElements: () => import_ast12.listItemElements,
|
|
55
|
+
list: () => import_ast12.list,
|
|
56
|
+
link: () => import_ast12.link,
|
|
57
|
+
lineBreak: () => import_ast12.lineBreak,
|
|
58
|
+
italics: () => import_ast12.italics,
|
|
59
59
|
isTagCloudModule: () => isTagCloudModule,
|
|
60
60
|
isListUsersModule: () => isListUsersModule2,
|
|
61
|
-
horizontalRule: () =>
|
|
62
|
-
heading: () =>
|
|
61
|
+
horizontalRule: () => import_ast12.horizontalRule,
|
|
62
|
+
heading: () => import_ast12.heading,
|
|
63
63
|
extractListUsersVariables: () => extractListUsersVariables,
|
|
64
64
|
extractIncludeReferences: () => extractIncludeReferences,
|
|
65
65
|
extractDataRequirements: () => extractDataRequirements,
|
|
66
66
|
definePageData: () => definePageData,
|
|
67
67
|
createToken: () => createToken,
|
|
68
|
-
createSettings: () =>
|
|
69
|
-
createPosition: () =>
|
|
70
|
-
createPoint: () =>
|
|
71
|
-
container: () =>
|
|
68
|
+
createSettings: () => import_ast13.createSettings,
|
|
69
|
+
createPosition: () => import_ast12.createPosition,
|
|
70
|
+
createPoint: () => import_ast12.createPoint,
|
|
71
|
+
container: () => import_ast12.container,
|
|
72
72
|
compileTemplate: () => compileTemplate,
|
|
73
73
|
compileListUsersTemplate: () => compileListUsersTemplate,
|
|
74
74
|
buildInfo: () => buildInfo,
|
|
75
|
-
bold: () =>
|
|
76
|
-
STYLE_SLOT_PREFIX: () =>
|
|
75
|
+
bold: () => import_ast12.bold,
|
|
76
|
+
STYLE_SLOT_PREFIX: () => import_ast7.STYLE_SLOT_PREFIX,
|
|
77
77
|
Parser: () => Parser,
|
|
78
78
|
Lexer: () => Lexer,
|
|
79
|
-
DEFAULT_SETTINGS: () =>
|
|
79
|
+
DEFAULT_SETTINGS: () => import_ast13.DEFAULT_SETTINGS
|
|
80
80
|
});
|
|
81
81
|
module.exports = __toCommonJS(exports_src);
|
|
82
82
|
|
|
83
83
|
// packages/parser/src/build-info.generated.ts
|
|
84
84
|
var buildInfo = Object.freeze({
|
|
85
|
-
version: "
|
|
86
|
-
sha: "
|
|
85
|
+
version: "6.0.0",
|
|
86
|
+
sha: "705ff97e22abd7bfb49d7f8f30087e6f09654c91",
|
|
87
87
|
dirty: false
|
|
88
88
|
});
|
|
89
89
|
|
|
90
90
|
// packages/parser/src/index.ts
|
|
91
|
-
var
|
|
92
|
-
var
|
|
91
|
+
var import_ast12 = require("@wdprlib/ast");
|
|
92
|
+
var import_ast13 = require("@wdprlib/ast");
|
|
93
93
|
|
|
94
94
|
// packages/parser/src/lexer/tokens.ts
|
|
95
95
|
function createToken(type, value, position, lineStart = false) {
|
|
@@ -272,13 +272,13 @@ function isValidAnchorNameChar(code) {
|
|
|
272
272
|
}
|
|
273
273
|
|
|
274
274
|
// packages/parser/src/lexer/quoted-string.ts
|
|
275
|
-
function scanQuotedString(state) {
|
|
275
|
+
function scanQuotedString(state, end = state.source.length) {
|
|
276
276
|
let quoted = advance(state);
|
|
277
|
-
while (
|
|
277
|
+
while (state.pos < end && current(state) !== '"' && current(state) !== `
|
|
278
278
|
`) {
|
|
279
279
|
quoted += advance(state);
|
|
280
280
|
}
|
|
281
|
-
if (current(state) === '"') {
|
|
281
|
+
if (state.pos < end && current(state) === '"') {
|
|
282
282
|
quoted += advance(state);
|
|
283
283
|
}
|
|
284
284
|
return quoted;
|
|
@@ -363,6 +363,26 @@ function isCompactPlainTextBoundary(code) {
|
|
|
363
363
|
}
|
|
364
364
|
}
|
|
365
365
|
|
|
366
|
+
// packages/parser/src/lexer/url-schemes.ts
|
|
367
|
+
var URL_SCHEME_NAMES = new Set([
|
|
368
|
+
"http",
|
|
369
|
+
"https",
|
|
370
|
+
"ftp",
|
|
371
|
+
"gopher",
|
|
372
|
+
"news",
|
|
373
|
+
"mailto",
|
|
374
|
+
"mms"
|
|
375
|
+
]);
|
|
376
|
+
var TRAILING_URL_SCHEME = /(?:^|[^A-Za-z0-9])(https?|ftp|gopher|news|mailto|mms)$/;
|
|
377
|
+
var URL_SCHEME_PREFIX = /^(?:(?:https?|ftp|gopher|news|mms):\/\/|mailto:)/;
|
|
378
|
+
var URL_PATTERN = /^(?:(?:https?|ftp|gopher|news|mms):\/\/|mailto:)(?:[^ \\/"']*\/)*[^ \t\n\\/"']*[A-Za-z%0-9/?=&~_]/;
|
|
379
|
+
function startsWithUrlScheme(src, pos) {
|
|
380
|
+
return URL_SCHEME_PREFIX.test(src.slice(pos, pos + 10));
|
|
381
|
+
}
|
|
382
|
+
function startsWithUrl(src, pos) {
|
|
383
|
+
return URL_PATTERN.test(src.slice(pos, pos + 2048));
|
|
384
|
+
}
|
|
385
|
+
|
|
366
386
|
// packages/parser/src/lexer/syntax-actions.ts
|
|
367
387
|
function scanSimpleSyntaxToken(src, pos, isLineStart) {
|
|
368
388
|
switch (src[pos]) {
|
|
@@ -399,7 +419,7 @@ function scanSimpleSyntaxToken(src, pos, isLineStart) {
|
|
|
399
419
|
}
|
|
400
420
|
}
|
|
401
421
|
function scanStarToken(src, pos, isLineStart) {
|
|
402
|
-
if (src[pos + 1] === "*") {
|
|
422
|
+
if (src[pos + 1] === "*" && !startsWithUrl(src, pos + 2)) {
|
|
403
423
|
return token("BOLD_MARKER", "**");
|
|
404
424
|
}
|
|
405
425
|
return isLineStart ? token("LIST_BULLET", "*") : token("STAR", "*");
|
|
@@ -585,7 +605,13 @@ function scanTextToken(src, pos) {
|
|
|
585
605
|
return token3("TEXT", char);
|
|
586
606
|
}
|
|
587
607
|
function scanCompactTextToken(src, pos) {
|
|
588
|
-
|
|
608
|
+
let end = findCompactPlainTextRunEnd(src, pos);
|
|
609
|
+
if (end > pos && src[end] === ":") {
|
|
610
|
+
const match = TRAILING_URL_SCHEME.exec(src.slice(pos, end));
|
|
611
|
+
if (match) {
|
|
612
|
+
end -= match[1].length;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
589
615
|
return end > pos ? runToken3(src, pos, end, "TEXT") : null;
|
|
590
616
|
}
|
|
591
617
|
function token3(type, value) {
|
|
@@ -631,6 +657,8 @@ class Lexer {
|
|
|
631
657
|
splitBlockClosePositions = new Set;
|
|
632
658
|
lastNonWhitespaceType = null;
|
|
633
659
|
blockOpenerDepth = 0;
|
|
660
|
+
rawTagBounds = null;
|
|
661
|
+
rawClosesExhausted = false;
|
|
634
662
|
constructor(source, options = {}) {
|
|
635
663
|
this.options = {
|
|
636
664
|
trackPositions: options.trackPositions ?? true,
|
|
@@ -651,8 +679,8 @@ class Lexer {
|
|
|
651
679
|
current() {
|
|
652
680
|
return current(this.state);
|
|
653
681
|
}
|
|
654
|
-
findInvalidAnchorNameEnd() {
|
|
655
|
-
return findInvalidAnchorNameEnd(
|
|
682
|
+
findInvalidAnchorNameEnd(source) {
|
|
683
|
+
return findInvalidAnchorNameEnd(source, this.state.pos);
|
|
656
684
|
}
|
|
657
685
|
advance(n = 1) {
|
|
658
686
|
return advance(this.state, n);
|
|
@@ -664,6 +692,18 @@ class Lexer {
|
|
|
664
692
|
this.state.tokens.push(createLexerToken(this.state, type, value, this.options.trackPositions));
|
|
665
693
|
this.lastNonWhitespaceType = updateLastNonWhitespaceType(this.lastNonWhitespaceType, type);
|
|
666
694
|
this.blockOpenerDepth = nextBlockOpenerDepth(this.blockOpenerDepth, type);
|
|
695
|
+
if (this.rawTagBounds === null && !this.rawClosesExhausted && (value.toLowerCase() === "button" || value.toLowerCase() === "social") && this.state.tokens.at(-2)?.type === "BLOCK_OPEN" && /\s/.test(this.current())) {
|
|
696
|
+
const close = this.state.source.indexOf("]]", this.state.pos);
|
|
697
|
+
if (close < 0) {
|
|
698
|
+
this.rawClosesExhausted = true;
|
|
699
|
+
} else {
|
|
700
|
+
this.rawTagBounds = {
|
|
701
|
+
source: this.state.source.slice(0, close),
|
|
702
|
+
close,
|
|
703
|
+
outerDepth: this.blockOpenerDepth - 1
|
|
704
|
+
};
|
|
705
|
+
}
|
|
706
|
+
}
|
|
667
707
|
}
|
|
668
708
|
emitTokenAction(action) {
|
|
669
709
|
advanceByToken(this.state, action.type, action.length, action.value);
|
|
@@ -681,7 +721,14 @@ class Lexer {
|
|
|
681
721
|
scanToken() {
|
|
682
722
|
const char = this.current();
|
|
683
723
|
const isLineStart = isSyntaxLineStart(this.state);
|
|
684
|
-
const
|
|
724
|
+
const bounds = this.rawTagBounds;
|
|
725
|
+
const src = bounds?.source ?? this.state.source;
|
|
726
|
+
if (bounds && this.state.pos === bounds.close) {
|
|
727
|
+
this.emitTokenAction({ type: "BLOCK_CLOSE", value: "]]", length: 2 });
|
|
728
|
+
this.blockOpenerDepth = bounds.outerDepth;
|
|
729
|
+
this.rawTagBounds = null;
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
685
732
|
const spacingAction = scanSpacingToken(src, this.state.pos);
|
|
686
733
|
if (spacingAction) {
|
|
687
734
|
this.emitTokenAction(limitBlockquotePrefixSpace(spacingAction, this.state.tokens.at(-1)));
|
|
@@ -694,7 +741,7 @@ class Lexer {
|
|
|
694
741
|
lineStart: isLineStart,
|
|
695
742
|
physicalLineStart: this.state.lineStart,
|
|
696
743
|
splitBlockClose: this.splitBlockClosePositions.has(this.state.pos),
|
|
697
|
-
findInvalidAnchorNameEnd: () => this.findInvalidAnchorNameEnd()
|
|
744
|
+
findInvalidAnchorNameEnd: () => this.findInvalidAnchorNameEnd(src)
|
|
698
745
|
});
|
|
699
746
|
if (punctuation.handled) {
|
|
700
747
|
if (punctuation.clearSplitBlockCloseAt !== undefined) {
|
|
@@ -709,7 +756,7 @@ class Lexer {
|
|
|
709
756
|
if (char === '"') {
|
|
710
757
|
const lastNonWs = this.lastNonWhitespaceTokenType();
|
|
711
758
|
if (this.blockOpenerDepth > 0 && lastNonWs === "EQUALS") {
|
|
712
|
-
this.addToken("QUOTED_STRING", scanQuotedString(this.state));
|
|
759
|
+
this.addToken("QUOTED_STRING", scanQuotedString(this.state, src.length));
|
|
713
760
|
return;
|
|
714
761
|
}
|
|
715
762
|
this.advance();
|
|
@@ -897,7 +944,7 @@ function parseBlockItem(ctx) {
|
|
|
897
944
|
}
|
|
898
945
|
}
|
|
899
946
|
const fallback = ctx.blockFallbackRule.parse(ctx);
|
|
900
|
-
if (fallback.success
|
|
947
|
+
if (fallback.success) {
|
|
901
948
|
return { elements: fallback.elements, consumed: fallback.consumed };
|
|
902
949
|
}
|
|
903
950
|
return { elements: [], consumed: 1 };
|
|
@@ -945,7 +992,8 @@ function parseBlocksUntil(ctx, closeCondition, options) {
|
|
|
945
992
|
blockCtx.pos = pos;
|
|
946
993
|
blockCtx.scope = blockScope;
|
|
947
994
|
const result = parseBlockItem(blockCtx);
|
|
948
|
-
|
|
995
|
+
for (const element of result.elements)
|
|
996
|
+
elements.push(element);
|
|
949
997
|
consumed += result.consumed;
|
|
950
998
|
pos += result.consumed;
|
|
951
999
|
}
|
|
@@ -972,6 +1020,42 @@ function getExcludedBlockRules(blockRules, excluded) {
|
|
|
972
1020
|
byExcluded.set(excluded, filtered);
|
|
973
1021
|
return filtered;
|
|
974
1022
|
}
|
|
1023
|
+
// packages/parser/src/parser/rules/inline/parsing/automatic-line-break.ts
|
|
1024
|
+
var origins = new WeakMap;
|
|
1025
|
+
function createAutomaticLineBreak(token5) {
|
|
1026
|
+
const element = { element: "line-break" };
|
|
1027
|
+
origins.set(element, token5);
|
|
1028
|
+
return element;
|
|
1029
|
+
}
|
|
1030
|
+
function precedingSingleNewline(ctx) {
|
|
1031
|
+
let pos = ctx.pos - 1;
|
|
1032
|
+
while (ctx.tokens[pos]?.type === "WHITESPACE")
|
|
1033
|
+
pos--;
|
|
1034
|
+
const newline = ctx.tokens[pos];
|
|
1035
|
+
if (newline?.type !== "NEWLINE")
|
|
1036
|
+
return;
|
|
1037
|
+
pos--;
|
|
1038
|
+
while (ctx.tokens[pos]?.type === "WHITESPACE")
|
|
1039
|
+
pos--;
|
|
1040
|
+
if (ctx.tokens[pos]?.type === "NEWLINE")
|
|
1041
|
+
return;
|
|
1042
|
+
return newline;
|
|
1043
|
+
}
|
|
1044
|
+
function stripAutomaticLineBreak(elements, token5) {
|
|
1045
|
+
if (!token5)
|
|
1046
|
+
return;
|
|
1047
|
+
let index = elements.length - 1;
|
|
1048
|
+
while (index >= 0) {
|
|
1049
|
+
const element2 = elements[index];
|
|
1050
|
+
if (element2?.element !== "text" || !/^[ \t]*$/.test(element2.data))
|
|
1051
|
+
break;
|
|
1052
|
+
index--;
|
|
1053
|
+
}
|
|
1054
|
+
const element = elements[index];
|
|
1055
|
+
if (element && origins.get(element) === token5)
|
|
1056
|
+
elements.length = index;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
975
1059
|
// packages/parser/src/parser/rules/inline/parsing/rules.ts
|
|
976
1060
|
function canApplyInlineRule(rule, token5) {
|
|
977
1061
|
if (rule.startTokens.length === 0) {
|
|
@@ -994,18 +1078,479 @@ function getCandidateInlineRules(inlineRules, tokenType) {
|
|
|
994
1078
|
byType.set(tokenType, candidates);
|
|
995
1079
|
return candidates;
|
|
996
1080
|
}
|
|
1081
|
+
// packages/parser/src/parser/rules/inline/parsing/raw-tag.ts
|
|
1082
|
+
var unclosedRanges = new WeakMap;
|
|
1083
|
+
function findRawTagClose(tokens, start, end) {
|
|
1084
|
+
const unclosed = unclosedRanges.get(tokens);
|
|
1085
|
+
if (unclosed && start >= unclosed.start && end <= unclosed.end)
|
|
1086
|
+
return null;
|
|
1087
|
+
for (let close = start;close < end; close++) {
|
|
1088
|
+
if (tokens[close]?.type === "BLOCK_CLOSE")
|
|
1089
|
+
return close;
|
|
1090
|
+
if (!tokens[close] || tokens[close]?.type === "EOF")
|
|
1091
|
+
break;
|
|
1092
|
+
}
|
|
1093
|
+
unclosedRanges.set(tokens, { start, end });
|
|
1094
|
+
return null;
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
// packages/parser/src/parser/rules/inline/button/attributes.ts
|
|
1098
|
+
function parseButtonAttributes(source) {
|
|
1099
|
+
const sections = source.trim().split('="');
|
|
1100
|
+
const attrs = {};
|
|
1101
|
+
let key = sections[0].trim();
|
|
1102
|
+
for (const section of sections.slice(1)) {
|
|
1103
|
+
const quote = section.lastIndexOf('"');
|
|
1104
|
+
if (quote < 0)
|
|
1105
|
+
continue;
|
|
1106
|
+
if (key === "text" || key === "class" || key === "style") {
|
|
1107
|
+
attrs[key] = section.slice(0, quote).replace(/\\([\s\S]|$)/g, (_match, char) => char === "0" ? "\x00" : char);
|
|
1108
|
+
}
|
|
1109
|
+
key = section.slice(quote + 1).trim();
|
|
1110
|
+
}
|
|
1111
|
+
return attrs;
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
// packages/parser/src/parser/rules/inline/button/syntax.ts
|
|
1115
|
+
function parseButtonSyntax(ctx, start, end) {
|
|
1116
|
+
const tokens = ctx.tokens;
|
|
1117
|
+
if (tokens[start]?.type !== "BLOCK_OPEN" || tokens[start + 1]?.value.toLowerCase() !== "button")
|
|
1118
|
+
return null;
|
|
1119
|
+
let pos = start + 2;
|
|
1120
|
+
const skipSpace = () => {
|
|
1121
|
+
const before = pos;
|
|
1122
|
+
while (pos < end && /^\s+$/.test(tokens[pos]?.value ?? ""))
|
|
1123
|
+
pos++;
|
|
1124
|
+
return pos > before;
|
|
1125
|
+
};
|
|
1126
|
+
if (!skipSpace())
|
|
1127
|
+
return null;
|
|
1128
|
+
let action = "";
|
|
1129
|
+
while (pos < end && tokens[pos]?.type !== "BLOCK_CLOSE" && !/^\s+$/.test(tokens[pos]?.value ?? "")) {
|
|
1130
|
+
const part = tokens[pos]?.value ?? "";
|
|
1131
|
+
if (!/^[a-z0-9_-]+$/i.test(part))
|
|
1132
|
+
return null;
|
|
1133
|
+
action += part;
|
|
1134
|
+
pos++;
|
|
1135
|
+
}
|
|
1136
|
+
if (!action)
|
|
1137
|
+
return null;
|
|
1138
|
+
action = action.replaceAll("_", "-");
|
|
1139
|
+
skipSpace();
|
|
1140
|
+
const close = findRawTagClose(tokens, pos, end);
|
|
1141
|
+
if (close === null)
|
|
1142
|
+
return null;
|
|
1143
|
+
const attrs = parseButtonAttributes(tokens.slice(pos, close).map((token5) => token5.value).join(""));
|
|
1144
|
+
const value = (key) => attrs[key] && attrs[key] !== "0" ? attrs[key] : null;
|
|
1145
|
+
const attributes = {};
|
|
1146
|
+
for (const name of ["class", "style"]) {
|
|
1147
|
+
const attr = value(name);
|
|
1148
|
+
if (attr !== null)
|
|
1149
|
+
attributes[name] = attr;
|
|
1150
|
+
}
|
|
1151
|
+
return { data: { action, text: value("text"), attributes }, end: close + 1 };
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
// packages/parser/src/parser/rules/inline/social/syntax.ts
|
|
1155
|
+
var invalidBodies = new WeakMap;
|
|
1156
|
+
function parseSocialSyntax(ctx, start, end) {
|
|
1157
|
+
const tokens = ctx.tokens;
|
|
1158
|
+
if (tokens[start]?.type !== "BLOCK_OPEN" || tokens[start + 1]?.value.toLowerCase() !== "social")
|
|
1159
|
+
return null;
|
|
1160
|
+
const bodyStart = start + 2;
|
|
1161
|
+
if (tokens[bodyStart]?.type !== "BLOCK_CLOSE" && !/^\s+$/.test(tokens[bodyStart]?.value ?? ""))
|
|
1162
|
+
return null;
|
|
1163
|
+
const invalid = invalidBodies.get(tokens);
|
|
1164
|
+
if (invalid && bodyStart >= invalid.start && bodyStart <= invalid.bracket)
|
|
1165
|
+
return null;
|
|
1166
|
+
const close = findRawTagClose(tokens, bodyStart, end);
|
|
1167
|
+
if (close === null)
|
|
1168
|
+
return null;
|
|
1169
|
+
for (let pos = bodyStart;pos < close; pos++) {
|
|
1170
|
+
if (tokens[pos].value.includes("]")) {
|
|
1171
|
+
invalidBodies.set(tokens, { start: bodyStart, bracket: pos });
|
|
1172
|
+
return null;
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
const body = tokens.slice(bodyStart, close).map((token5) => token5.value).join("");
|
|
1176
|
+
const sites = body.trim() ? body.split(",").map((site) => site.trim().toLowerCase()).filter(Boolean) : null;
|
|
1177
|
+
return { data: { sites }, end: close + 1 };
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
// packages/parser/src/parser/rules/block/parsing/attributes/names.ts
|
|
1181
|
+
function consumeAttributeName(ctx, startPos, startConsumed, startName, options) {
|
|
1182
|
+
if (startName === "_" && isAttributeWordToken(ctx.tokens[startPos])) {
|
|
1183
|
+
startName += ctx.tokens[startPos]?.value ?? "";
|
|
1184
|
+
startPos++;
|
|
1185
|
+
startConsumed++;
|
|
1186
|
+
}
|
|
1187
|
+
return options.strikeHyphens ? consumeRawNameSuffix(ctx, startPos, startConsumed, startName, options.hyphenatedNames) : consumeSafeNameSuffix(ctx, startPos, startConsumed, startName);
|
|
1188
|
+
}
|
|
1189
|
+
function isAttributeNameToken(token5) {
|
|
1190
|
+
return isAttributeWordToken(token5) || token5?.type === "UNDERSCORE";
|
|
1191
|
+
}
|
|
1192
|
+
function consumeSafeNameSuffix(ctx, startPos, startConsumed, startName) {
|
|
1193
|
+
let name = startName;
|
|
1194
|
+
let pos = startPos;
|
|
1195
|
+
let consumed = startConsumed;
|
|
1196
|
+
while (isAttributeNameSeparator(ctx.tokens[pos]) && isAttributeWordToken(ctx.tokens[pos + 1])) {
|
|
1197
|
+
name += ctx.tokens[pos]?.value ?? "";
|
|
1198
|
+
pos++;
|
|
1199
|
+
consumed++;
|
|
1200
|
+
name += ctx.tokens[pos]?.value ?? "";
|
|
1201
|
+
pos++;
|
|
1202
|
+
consumed++;
|
|
1203
|
+
}
|
|
1204
|
+
return { name, pos, consumed };
|
|
1205
|
+
}
|
|
1206
|
+
function consumeRawNameSuffix(ctx, startPos, startConsumed, startName, hyphenatedNames) {
|
|
1207
|
+
let name = startName;
|
|
1208
|
+
let pos = startPos;
|
|
1209
|
+
let consumed = startConsumed;
|
|
1210
|
+
while (isAttributeNameSeparator(ctx.tokens[pos])) {
|
|
1211
|
+
while (isAttributeNameSeparator(ctx.tokens[pos])) {
|
|
1212
|
+
if (hyphenatedNames || ctx.tokens[pos]?.type === "UNDERSCORE") {
|
|
1213
|
+
name += ctx.tokens[pos]?.value ?? "-";
|
|
1214
|
+
}
|
|
1215
|
+
pos++;
|
|
1216
|
+
consumed++;
|
|
1217
|
+
}
|
|
1218
|
+
if (!isAttributeWordToken(ctx.tokens[pos])) {
|
|
1219
|
+
break;
|
|
1220
|
+
}
|
|
1221
|
+
if (hyphenatedNames || name.endsWith("_")) {
|
|
1222
|
+
name += ctx.tokens[pos]?.value ?? "";
|
|
1223
|
+
}
|
|
1224
|
+
pos++;
|
|
1225
|
+
consumed++;
|
|
1226
|
+
}
|
|
1227
|
+
return { name, pos, consumed };
|
|
1228
|
+
}
|
|
1229
|
+
function isAttributeWordToken(token5) {
|
|
1230
|
+
return token5?.type === "TEXT" || token5?.type === "IDENTIFIER";
|
|
1231
|
+
}
|
|
1232
|
+
function isAttributeNameSeparator(token5) {
|
|
1233
|
+
return token5?.type === "TEXT" && token5.value === "-" || token5?.type === "STRIKE_MARKER" || token5?.type === "UNDERSCORE";
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
// packages/parser/src/parser/rules/block/parsing/attributes/values.ts
|
|
1237
|
+
function consumeAttributeValue(token5) {
|
|
1238
|
+
if (!token5) {
|
|
1239
|
+
return null;
|
|
1240
|
+
}
|
|
1241
|
+
if (token5.type === "QUOTED_STRING") {
|
|
1242
|
+
return { value: stripQuotes(token5.value) };
|
|
1243
|
+
}
|
|
1244
|
+
if (isAttributeNameToken(token5)) {
|
|
1245
|
+
return { value: token5.value };
|
|
1246
|
+
}
|
|
1247
|
+
return null;
|
|
1248
|
+
}
|
|
1249
|
+
function stripQuotes(value) {
|
|
1250
|
+
return value.startsWith('"') && value.endsWith('"') ? value.slice(1, -1) : value;
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
// packages/parser/src/parser/rules/block/parsing/attributes/scanner.ts
|
|
1254
|
+
function scanAttributes(ctx, startPos, options) {
|
|
1255
|
+
const attrs = {};
|
|
1256
|
+
let pos = startPos;
|
|
1257
|
+
let consumed = 0;
|
|
1258
|
+
while (pos < ctx.tokens.length) {
|
|
1259
|
+
const token5 = ctx.tokens[pos];
|
|
1260
|
+
if (!token5 || isAttributeTerminator(token5)) {
|
|
1261
|
+
break;
|
|
1262
|
+
}
|
|
1263
|
+
if (token5.type === "WHITESPACE") {
|
|
1264
|
+
pos++;
|
|
1265
|
+
consumed++;
|
|
1266
|
+
continue;
|
|
1267
|
+
}
|
|
1268
|
+
if (!isAttributeNameToken(token5)) {
|
|
1269
|
+
pos++;
|
|
1270
|
+
consumed++;
|
|
1271
|
+
continue;
|
|
1272
|
+
}
|
|
1273
|
+
let name = token5.value;
|
|
1274
|
+
pos++;
|
|
1275
|
+
consumed++;
|
|
1276
|
+
const nameResult = consumeAttributeName(ctx, pos, consumed, name, options);
|
|
1277
|
+
pos = nameResult.pos;
|
|
1278
|
+
consumed = nameResult.consumed;
|
|
1279
|
+
name = nameResult.name.toLowerCase();
|
|
1280
|
+
if (ctx.tokens[pos]?.type !== "EQUALS") {
|
|
1281
|
+
attrs[name] = "true";
|
|
1282
|
+
continue;
|
|
1283
|
+
}
|
|
1284
|
+
pos++;
|
|
1285
|
+
consumed++;
|
|
1286
|
+
const valueResult = consumeAttributeValue(ctx.tokens[pos]);
|
|
1287
|
+
if (!valueResult) {
|
|
1288
|
+
continue;
|
|
1289
|
+
}
|
|
1290
|
+
attrs[name] = valueResult.value;
|
|
1291
|
+
pos++;
|
|
1292
|
+
consumed++;
|
|
1293
|
+
}
|
|
1294
|
+
return { attrs, consumed };
|
|
1295
|
+
}
|
|
1296
|
+
function isAttributeTerminator(token5) {
|
|
1297
|
+
return token5.type === "BLOCK_CLOSE" || token5.type === "NEWLINE" || token5.type === "EOF";
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
// packages/parser/src/parser/rules/block/parsing/attributes/index.ts
|
|
1301
|
+
function parseAttributes(ctx, startPos) {
|
|
1302
|
+
const result = scanAttributes(ctx, startPos, { hyphenatedNames: true, strikeHyphens: false });
|
|
1303
|
+
return { attrs: filterUnsafeAttributes(result.attrs), consumed: result.consumed };
|
|
1304
|
+
}
|
|
1305
|
+
function parseAttributesRaw(ctx, startPos, hyphenatedNames = true) {
|
|
1306
|
+
return scanAttributes(ctx, startPos, { hyphenatedNames, strikeHyphens: true });
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
// packages/parser/src/parser/rules/inline/date/syntax.ts
|
|
1310
|
+
function parseDateSyntax(ctx, start, end) {
|
|
1311
|
+
const tokens = ctx.tokens;
|
|
1312
|
+
if (tokens[start]?.type !== "BLOCK_OPEN" || tokens[start + 1]?.value !== "date")
|
|
1313
|
+
return null;
|
|
1314
|
+
let pos = start + 2;
|
|
1315
|
+
const skipSpace = () => {
|
|
1316
|
+
const before = pos;
|
|
1317
|
+
while (pos < end && /^(?:\s+)$/.test(tokens[pos]?.value ?? ""))
|
|
1318
|
+
pos++;
|
|
1319
|
+
return pos > before;
|
|
1320
|
+
};
|
|
1321
|
+
if (!skipSpace())
|
|
1322
|
+
return null;
|
|
1323
|
+
const value = tokens[pos]?.value ?? "";
|
|
1324
|
+
if (pos >= end || !/^\d+$/.test(value))
|
|
1325
|
+
return null;
|
|
1326
|
+
const timestamp = Number(value);
|
|
1327
|
+
if (!Number.isSafeInteger(timestamp) || timestamp > 8640000000000)
|
|
1328
|
+
return null;
|
|
1329
|
+
pos++;
|
|
1330
|
+
const separator = skipSpace();
|
|
1331
|
+
if (tokens[pos]?.type !== "BLOCK_CLOSE" && !separator)
|
|
1332
|
+
return null;
|
|
1333
|
+
let close = pos;
|
|
1334
|
+
for (;close < end; close++) {
|
|
1335
|
+
const token5 = tokens[close];
|
|
1336
|
+
if (!token5 || token5.type === "EOF" || token5.type === "BLOCK_OPEN" || /[\r\n]/.test(token5.value))
|
|
1337
|
+
return null;
|
|
1338
|
+
if (token5.type === "BLOCK_CLOSE")
|
|
1339
|
+
break;
|
|
1340
|
+
}
|
|
1341
|
+
if (close >= end)
|
|
1342
|
+
return null;
|
|
1343
|
+
const attributes = parseAttributesRaw(ctx, pos).attrs;
|
|
1344
|
+
const format = attributes.format || null;
|
|
1345
|
+
return {
|
|
1346
|
+
data: {
|
|
1347
|
+
value: { timestamp, timezone: "UTC" },
|
|
1348
|
+
format,
|
|
1349
|
+
hover: format?.split("|").slice(1).includes("agohover") ?? false
|
|
1350
|
+
},
|
|
1351
|
+
end: close + 1
|
|
1352
|
+
};
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
// packages/parser/src/parser/rules/inline/email/scan.ts
|
|
1356
|
+
function isDomainChar(code) {
|
|
1357
|
+
return code >= 48 && code <= 57 || code >= 65 && code <= 90 || code >= 97 && code <= 122 || code === 45;
|
|
1358
|
+
}
|
|
1359
|
+
function isLocalChar(code) {
|
|
1360
|
+
return isDomainChar(code) || code === 95;
|
|
1361
|
+
}
|
|
1362
|
+
function scanEmail(source, start, commentEnd) {
|
|
1363
|
+
const comments = [];
|
|
1364
|
+
let pos = start;
|
|
1365
|
+
const skipComments = () => {
|
|
1366
|
+
let end2 = commentEnd(pos);
|
|
1367
|
+
while (end2 > pos) {
|
|
1368
|
+
comments.push({ start: pos, end: end2 });
|
|
1369
|
+
pos = end2;
|
|
1370
|
+
end2 = commentEnd(pos);
|
|
1371
|
+
}
|
|
1372
|
+
};
|
|
1373
|
+
let localPart = false;
|
|
1374
|
+
while (pos < source.length) {
|
|
1375
|
+
skipComments();
|
|
1376
|
+
if (isLocalChar(source.charCodeAt(pos))) {
|
|
1377
|
+
localPart = true;
|
|
1378
|
+
pos++;
|
|
1379
|
+
} else if (source[pos] === "." && localPart) {
|
|
1380
|
+
localPart = false;
|
|
1381
|
+
pos++;
|
|
1382
|
+
} else
|
|
1383
|
+
break;
|
|
1384
|
+
}
|
|
1385
|
+
const localEnd = pos;
|
|
1386
|
+
if (!localPart || source[pos] !== "@")
|
|
1387
|
+
return { localEnd, comments };
|
|
1388
|
+
pos++;
|
|
1389
|
+
let domainPart = false;
|
|
1390
|
+
let dots = 0;
|
|
1391
|
+
let end = -1;
|
|
1392
|
+
while (pos < source.length) {
|
|
1393
|
+
skipComments();
|
|
1394
|
+
if (isDomainChar(source.charCodeAt(pos))) {
|
|
1395
|
+
domainPart = true;
|
|
1396
|
+
pos++;
|
|
1397
|
+
if (dots > 0)
|
|
1398
|
+
end = pos;
|
|
1399
|
+
} else if (source[pos] === "." && domainPart) {
|
|
1400
|
+
domainPart = false;
|
|
1401
|
+
dots++;
|
|
1402
|
+
pos++;
|
|
1403
|
+
} else
|
|
1404
|
+
break;
|
|
1405
|
+
}
|
|
1406
|
+
if (end === -1)
|
|
1407
|
+
return { localEnd, comments };
|
|
1408
|
+
const parts = [];
|
|
1409
|
+
let copied = start;
|
|
1410
|
+
for (const comment of comments) {
|
|
1411
|
+
if (comment.start >= end)
|
|
1412
|
+
break;
|
|
1413
|
+
parts.push(source.slice(copied, comment.start));
|
|
1414
|
+
copied = comment.end;
|
|
1415
|
+
}
|
|
1416
|
+
parts.push(source.slice(copied, end));
|
|
1417
|
+
return { end, address: parts.join(""), localEnd, comments };
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
// packages/parser/src/parser/rules/inline/email/candidates.ts
|
|
1421
|
+
var caches = new WeakMap;
|
|
1422
|
+
var EMAIL_START_TOKENS = [
|
|
1423
|
+
"TEXT",
|
|
1424
|
+
"IDENTIFIER",
|
|
1425
|
+
"UNDERSCORE",
|
|
1426
|
+
"UNDERLINE_MARKER",
|
|
1427
|
+
"STRIKE_MARKER"
|
|
1428
|
+
];
|
|
1429
|
+
function getCache(tokens) {
|
|
1430
|
+
let cache = caches.get(tokens);
|
|
1431
|
+
if (cache)
|
|
1432
|
+
return cache;
|
|
1433
|
+
const offsets = [0];
|
|
1434
|
+
const values = [];
|
|
1435
|
+
for (const token5 of tokens) {
|
|
1436
|
+
values.push(token5.value);
|
|
1437
|
+
offsets.push(offsets.at(-1) + token5.value.length);
|
|
1438
|
+
}
|
|
1439
|
+
cache = {
|
|
1440
|
+
source: values.join(""),
|
|
1441
|
+
offsets,
|
|
1442
|
+
candidates: new Map,
|
|
1443
|
+
commentEnds: new Map,
|
|
1444
|
+
unclosedComment: Infinity
|
|
1445
|
+
};
|
|
1446
|
+
caches.set(tokens, cache);
|
|
1447
|
+
return cache;
|
|
1448
|
+
}
|
|
1449
|
+
function commentEnd(cache, pos) {
|
|
1450
|
+
const opener = cache.source[pos] === `
|
|
1451
|
+
` ? pos + 1 : pos;
|
|
1452
|
+
if (!cache.source.startsWith("[!--", opener))
|
|
1453
|
+
return pos;
|
|
1454
|
+
const cached = cache.commentEnds.get(pos);
|
|
1455
|
+
if (cached !== undefined)
|
|
1456
|
+
return cached;
|
|
1457
|
+
const close = opener >= cache.unclosedComment ? -1 : cache.source.indexOf("--]", opener + 4);
|
|
1458
|
+
if (close === -1)
|
|
1459
|
+
cache.unclosedComment = Math.min(cache.unclosedComment, opener);
|
|
1460
|
+
const end = close === -1 ? pos : close + 3;
|
|
1461
|
+
cache.commentEnds.set(pos, end);
|
|
1462
|
+
return end;
|
|
1463
|
+
}
|
|
1464
|
+
function getEmailCandidate(tokens, index) {
|
|
1465
|
+
const token5 = tokens[index];
|
|
1466
|
+
if (!token5 || !EMAIL_START_TOKENS.includes(token5.type))
|
|
1467
|
+
return null;
|
|
1468
|
+
const cache = getCache(tokens);
|
|
1469
|
+
if (cache.candidates.has(index))
|
|
1470
|
+
return cache.candidates.get(index);
|
|
1471
|
+
const value = tokens[index]?.value ?? "";
|
|
1472
|
+
let suffix = value.length;
|
|
1473
|
+
while (suffix > 0 && (isLocalChar(value.charCodeAt(suffix - 1)) || value[suffix - 1] === "."))
|
|
1474
|
+
suffix--;
|
|
1475
|
+
const doubled = value.lastIndexOf("..");
|
|
1476
|
+
if (doubled >= suffix)
|
|
1477
|
+
suffix = doubled + 2;
|
|
1478
|
+
while (value[suffix] === ".")
|
|
1479
|
+
suffix++;
|
|
1480
|
+
if (suffix >= value.length || !isLocalChar(value.charCodeAt(suffix))) {
|
|
1481
|
+
cache.candidates.set(index, null);
|
|
1482
|
+
return null;
|
|
1483
|
+
}
|
|
1484
|
+
const start = cache.offsets[index] + suffix;
|
|
1485
|
+
const scanned = scanEmail(cache.source, start, (pos) => commentEnd(cache, pos));
|
|
1486
|
+
if (scanned.end === undefined) {
|
|
1487
|
+
cache.candidates.set(index, null);
|
|
1488
|
+
let comment = 0;
|
|
1489
|
+
for (let i = index + 1;i < tokens.length && cache.offsets[i + 1] <= scanned.localEnd; i++) {
|
|
1490
|
+
const offset = cache.offsets[i];
|
|
1491
|
+
while (scanned.comments[comment] && scanned.comments[comment].end <= offset)
|
|
1492
|
+
comment++;
|
|
1493
|
+
const region = scanned.comments[comment];
|
|
1494
|
+
if (!region || offset < region.start)
|
|
1495
|
+
cache.candidates.set(i, null);
|
|
1496
|
+
}
|
|
1497
|
+
return null;
|
|
1498
|
+
}
|
|
1499
|
+
let endToken = index;
|
|
1500
|
+
while (cache.offsets[endToken + 1] < scanned.end)
|
|
1501
|
+
endToken++;
|
|
1502
|
+
const candidate = { start, end: scanned.end, endToken, address: scanned.address };
|
|
1503
|
+
cache.candidates.set(index, candidate);
|
|
1504
|
+
return candidate;
|
|
1505
|
+
}
|
|
1506
|
+
function getEmailGroup(tokens, index, limit) {
|
|
1507
|
+
const first = getEmailCandidate(tokens, index);
|
|
1508
|
+
if (!first || first.endToken >= limit)
|
|
1509
|
+
return null;
|
|
1510
|
+
const candidates = [first];
|
|
1511
|
+
let last = first;
|
|
1512
|
+
while (last.endToken > index) {
|
|
1513
|
+
const next = getEmailCandidate(tokens, last.endToken);
|
|
1514
|
+
if (!next || next.start < last.end || next.endToken >= limit)
|
|
1515
|
+
break;
|
|
1516
|
+
candidates.push(next);
|
|
1517
|
+
last = next;
|
|
1518
|
+
}
|
|
1519
|
+
const cache = getCache(tokens);
|
|
1520
|
+
return {
|
|
1521
|
+
candidates,
|
|
1522
|
+
source: cache.source,
|
|
1523
|
+
start: cache.offsets[index],
|
|
1524
|
+
end: cache.offsets[last.endToken + 1],
|
|
1525
|
+
endToken: last.endToken + 1
|
|
1526
|
+
};
|
|
1527
|
+
}
|
|
1528
|
+
function emailRegionEnd(tokens, index, limit) {
|
|
1529
|
+
return getEmailGroup(tokens, index, limit)?.endToken ?? index;
|
|
1530
|
+
}
|
|
1531
|
+
|
|
997
1532
|
// packages/parser/src/parser/rules/inline/raw/end.ts
|
|
1533
|
+
var unclosedAngleRanges = new WeakMap;
|
|
998
1534
|
function rawRegionEnd(tokens, start, end) {
|
|
999
1535
|
const type = tokens[start]?.type;
|
|
1000
1536
|
const close = type === "RAW_OPEN" ? "RAW_OPEN" : type === "RAW_BLOCK_OPEN" ? "RAW_BLOCK_CLOSE" : null;
|
|
1001
1537
|
if (!close)
|
|
1002
1538
|
return start;
|
|
1539
|
+
const cached = type === "RAW_BLOCK_OPEN" ? unclosedAngleRanges.get(tokens) : undefined;
|
|
1540
|
+
if (cached && start >= cached.start && start < cached.end && (cached.lineEnd || end <= cached.end)) {
|
|
1541
|
+
return start;
|
|
1542
|
+
}
|
|
1003
1543
|
for (let pos = start + 1;pos < end; pos++) {
|
|
1004
|
-
if (tokens[pos]?.type === "NEWLINE" || tokens[pos]?.type === "EOF")
|
|
1005
|
-
|
|
1544
|
+
if (tokens[pos]?.type === "NEWLINE" || tokens[pos]?.type === "EOF") {
|
|
1545
|
+
if (type === "RAW_BLOCK_OPEN")
|
|
1546
|
+
unclosedAngleRanges.set(tokens, { start, end: pos, lineEnd: true });
|
|
1547
|
+
return start;
|
|
1548
|
+
}
|
|
1006
1549
|
if (tokens[pos]?.type === close)
|
|
1007
1550
|
return pos + 1;
|
|
1008
1551
|
}
|
|
1552
|
+
if (type === "RAW_BLOCK_OPEN")
|
|
1553
|
+
unclosedAngleRanges.set(tokens, { start, end, lineEnd: false });
|
|
1009
1554
|
return start;
|
|
1010
1555
|
}
|
|
1011
1556
|
function protectedInlineRegionEnd(tokens, start, end) {
|
|
@@ -1024,7 +1569,7 @@ var MIN_INLINE_TEXT_RUN_LENGTH = 32;
|
|
|
1024
1569
|
var MIN_INLINE_TEXT_RUN_DOCUMENT_TOKENS = 1e5;
|
|
1025
1570
|
function collectLongPlainTextRun(ctx, startPos, endType) {
|
|
1026
1571
|
const firstToken = ctx.tokens[startPos];
|
|
1027
|
-
if (firstToken?.type === "TEXT" && firstToken.value.length >= MIN_INLINE_TEXT_RUN_LENGTH && firstToken.value !== "(") {
|
|
1572
|
+
if (!getEmailCandidate(ctx.tokens, startPos) && firstToken?.type === "TEXT" && firstToken.value.length >= MIN_INLINE_TEXT_RUN_LENGTH && firstToken.value !== "(") {
|
|
1028
1573
|
return { value: firstToken.value, consumed: 1 };
|
|
1029
1574
|
}
|
|
1030
1575
|
let pos = startPos;
|
|
@@ -1046,10 +1591,10 @@ function collectLongPlainTextRun(ctx, startPos, endType) {
|
|
|
1046
1591
|
}
|
|
1047
1592
|
function isPlainTextRunToken(ctx, pos) {
|
|
1048
1593
|
const token5 = ctx.tokens[pos];
|
|
1049
|
-
if (!token5)
|
|
1594
|
+
if (!token5 || getEmailCandidate(ctx.tokens, pos))
|
|
1050
1595
|
return false;
|
|
1051
1596
|
if (token5.type === "IDENTIFIER") {
|
|
1052
|
-
return
|
|
1597
|
+
return !(URL_SCHEME_NAMES.has(token5.value) && ctx.tokens[pos + 1]?.type === "COLON");
|
|
1053
1598
|
}
|
|
1054
1599
|
if (token5.type === "WHITESPACE") {
|
|
1055
1600
|
const next = ctx.tokens[pos + 1];
|
|
@@ -1198,6 +1743,10 @@ var BLOCK_START_TOKENS = [
|
|
|
1198
1743
|
"HEADING_MARKER",
|
|
1199
1744
|
"HR_MARKER",
|
|
1200
1745
|
"TABLE_MARKER",
|
|
1746
|
+
"TABLE_HEADER",
|
|
1747
|
+
"TABLE_LEFT",
|
|
1748
|
+
"TABLE_CENTER",
|
|
1749
|
+
"TABLE_RIGHT",
|
|
1201
1750
|
"COLON",
|
|
1202
1751
|
"BLOCK_OPEN",
|
|
1203
1752
|
"BLOCK_END_OPEN",
|
|
@@ -1275,12 +1824,725 @@ var INDENT_ACCEPTING_BLOCK_NAMES = new Set([
|
|
|
1275
1824
|
"tabs"
|
|
1276
1825
|
]);
|
|
1277
1826
|
|
|
1278
|
-
// packages/parser/src/parser/rules/
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1827
|
+
// packages/parser/src/parser/rules/block/code/open.ts
|
|
1828
|
+
var attributeRanges = new WeakMap;
|
|
1829
|
+
function findAttributesEnd(tokens, start) {
|
|
1830
|
+
const cached = attributeRanges.get(tokens);
|
|
1831
|
+
if (cached && start >= cached.start && start <= cached.end)
|
|
1832
|
+
return cached.end;
|
|
1833
|
+
let end = start;
|
|
1834
|
+
while (end < tokens.length) {
|
|
1835
|
+
const type = tokens[end]?.type;
|
|
1836
|
+
if (type === "BLOCK_CLOSE" || type === "NEWLINE" || type === "EOF")
|
|
1837
|
+
break;
|
|
1838
|
+
end++;
|
|
1839
|
+
}
|
|
1840
|
+
attributeRanges.set(tokens, { start, end });
|
|
1841
|
+
return end;
|
|
1842
|
+
}
|
|
1843
|
+
function findCodeOpen(tokens, start) {
|
|
1844
|
+
const name = tokens[start + 1];
|
|
1845
|
+
if (tokens[start]?.type !== "BLOCK_OPEN" || name?.type !== "IDENTIFIER" && name?.type !== "TEXT" || name.value.toLowerCase() !== "code" || tokens[start + 2]?.type === "UNDERSCORE")
|
|
1846
|
+
return null;
|
|
1847
|
+
const attributesEnd = findAttributesEnd(tokens, start + 2);
|
|
1848
|
+
const repaired = tokens[attributesEnd]?.type !== "BLOCK_CLOSE";
|
|
1849
|
+
const last = tokens[attributesEnd - 1];
|
|
1850
|
+
if (repaired && (last?.type !== "QUOTED_STRING" || !last.value.includes("]]")))
|
|
1851
|
+
return null;
|
|
1852
|
+
let bodyStart = attributesEnd + (repaired ? 0 : 1);
|
|
1853
|
+
if (tokens[bodyStart]?.type === "NEWLINE")
|
|
1854
|
+
bodyStart++;
|
|
1855
|
+
return {
|
|
1856
|
+
attributesEnd,
|
|
1857
|
+
bodyStart,
|
|
1858
|
+
repaired,
|
|
1859
|
+
closingSwallowed: repaired && last.value.includes("[[/code]]")
|
|
1860
|
+
};
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
// packages/parser/src/parser/rules/block/code/boundary.ts
|
|
1864
|
+
var caches2 = new WeakMap;
|
|
1865
|
+
function codeCloseEnd(tokens, start) {
|
|
1866
|
+
if (tokens[start]?.type !== "BLOCK_END_OPEN" || tokens[start + 1]?.value.toLowerCase() !== "code")
|
|
1867
|
+
return start;
|
|
1868
|
+
let end = start + 2;
|
|
1869
|
+
while (tokens[end]?.type === "WHITESPACE")
|
|
1870
|
+
end++;
|
|
1871
|
+
return tokens[end]?.type === "BLOCK_CLOSE" ? end + 1 : start;
|
|
1872
|
+
}
|
|
1873
|
+
function nestedCodeBodyStart(tokens, start) {
|
|
1874
|
+
if (tokens[start]?.type !== "BLOCK_OPEN" || tokens[start + 1]?.value.toLowerCase() !== "code")
|
|
1875
|
+
return start;
|
|
1876
|
+
for (let pos = start + 2;pos < tokens.length; pos++) {
|
|
1877
|
+
const type = tokens[pos]?.type;
|
|
1878
|
+
if (type === "NEWLINE" || type === "EOF" || type === "BLOCK_OPEN")
|
|
1879
|
+
return start;
|
|
1880
|
+
if (type === "BLOCK_CLOSE") {
|
|
1881
|
+
const open = findCodeOpen(tokens, start);
|
|
1882
|
+
return open && !open.repaired ? open.bodyStart : start;
|
|
1883
|
+
}
|
|
1884
|
+
}
|
|
1885
|
+
return start;
|
|
1886
|
+
}
|
|
1887
|
+
function findCodeBodyBounds(tokens, start) {
|
|
1888
|
+
let cache = caches2.get(tokens);
|
|
1889
|
+
if (!cache) {
|
|
1890
|
+
cache = new Map;
|
|
1891
|
+
caches2.set(tokens, cache);
|
|
1892
|
+
}
|
|
1893
|
+
const cached = cache.get(start);
|
|
1894
|
+
if (cached)
|
|
1895
|
+
return cached;
|
|
1896
|
+
const stack = [start];
|
|
1897
|
+
let pos = start;
|
|
1898
|
+
while (pos < tokens.length && tokens[pos]?.type !== "EOF") {
|
|
1899
|
+
const rawEnd = rawRegionEnd(tokens, pos, tokens.length);
|
|
1900
|
+
if (rawEnd > pos) {
|
|
1901
|
+
pos = rawEnd;
|
|
1902
|
+
continue;
|
|
1903
|
+
}
|
|
1904
|
+
const end = codeCloseEnd(tokens, pos);
|
|
1905
|
+
if (end > pos) {
|
|
1906
|
+
const result2 = { closeStart: pos, end, foundClose: true };
|
|
1907
|
+
cache.set(stack.pop(), result2);
|
|
1908
|
+
if (stack.length === 0)
|
|
1909
|
+
return result2;
|
|
1910
|
+
pos = end;
|
|
1911
|
+
continue;
|
|
1912
|
+
}
|
|
1913
|
+
const bodyStart = nestedCodeBodyStart(tokens, pos);
|
|
1914
|
+
if (bodyStart > pos) {
|
|
1915
|
+
const child = cache.get(bodyStart);
|
|
1916
|
+
if (child) {
|
|
1917
|
+
pos = child.end;
|
|
1918
|
+
if (!child.foundClose)
|
|
1919
|
+
break;
|
|
1920
|
+
} else {
|
|
1921
|
+
stack.push(bodyStart);
|
|
1922
|
+
pos = bodyStart;
|
|
1923
|
+
}
|
|
1924
|
+
continue;
|
|
1925
|
+
}
|
|
1926
|
+
pos++;
|
|
1927
|
+
}
|
|
1928
|
+
const result = { closeStart: pos, end: pos, foundClose: false };
|
|
1929
|
+
for (const bodyStart of stack)
|
|
1930
|
+
cache.set(bodyStart, result);
|
|
1931
|
+
return result;
|
|
1932
|
+
}
|
|
1933
|
+
|
|
1934
|
+
// packages/parser/src/parser/rules/block/math/boundary.ts
|
|
1935
|
+
var nameRanges = new WeakMap;
|
|
1936
|
+
var bodyCaches = new WeakMap;
|
|
1937
|
+
function findNameEnd(tokens, start) {
|
|
1938
|
+
const cached = nameRanges.get(tokens);
|
|
1939
|
+
if (cached && start >= cached.start && start <= cached.end)
|
|
1940
|
+
return cached.end;
|
|
1941
|
+
let end = start;
|
|
1942
|
+
while (end < tokens.length) {
|
|
1943
|
+
const type = tokens[end]?.type;
|
|
1944
|
+
if (type === "BLOCK_CLOSE" || type === "WHITESPACE" || type === "NEWLINE" || type === "EOF")
|
|
1945
|
+
break;
|
|
1946
|
+
end++;
|
|
1947
|
+
}
|
|
1948
|
+
nameRanges.set(tokens, { start, end });
|
|
1949
|
+
return end;
|
|
1950
|
+
}
|
|
1951
|
+
function findMathOpen(tokens, start) {
|
|
1952
|
+
const name = tokens[start + 1];
|
|
1953
|
+
if (tokens[start]?.type !== "BLOCK_OPEN" || name?.type !== "IDENTIFIER" && name?.type !== "TEXT" || name.value.toLowerCase() !== "math" || tokens[start + 2]?.type === "UNDERSCORE")
|
|
1954
|
+
return null;
|
|
1955
|
+
let pos = start + 2;
|
|
1956
|
+
while (tokens[pos]?.type === "WHITESPACE")
|
|
1957
|
+
pos++;
|
|
1958
|
+
const nameStart = pos;
|
|
1959
|
+
if (tokens[pos]?.type === "IDENTIFIER" || tokens[pos]?.type === "TEXT") {
|
|
1960
|
+
pos = findNameEnd(tokens, pos);
|
|
1961
|
+
}
|
|
1962
|
+
const nameEnd = pos;
|
|
1963
|
+
while (tokens[pos]?.type === "WHITESPACE")
|
|
1964
|
+
pos++;
|
|
1965
|
+
if (tokens[pos]?.type !== "BLOCK_CLOSE")
|
|
1966
|
+
return null;
|
|
1967
|
+
pos++;
|
|
1968
|
+
if (tokens[pos]?.type === "NEWLINE")
|
|
1969
|
+
pos++;
|
|
1970
|
+
return { nameStart, nameEnd, bodyStart: pos };
|
|
1971
|
+
}
|
|
1972
|
+
function mathCloseEnd(tokens, start) {
|
|
1973
|
+
if (tokens[start]?.type !== "BLOCK_END_OPEN" || tokens[start + 1]?.value.toLowerCase() !== "math" || tokens[start + 2]?.type !== "BLOCK_CLOSE")
|
|
1974
|
+
return start;
|
|
1975
|
+
const end = start + 3;
|
|
1976
|
+
return tokens[end]?.type === "NEWLINE" ? end + 1 : end;
|
|
1977
|
+
}
|
|
1978
|
+
function findMathBodyBounds(tokens, start) {
|
|
1979
|
+
let cache = bodyCaches.get(tokens);
|
|
1980
|
+
if (!cache) {
|
|
1981
|
+
cache = new Map;
|
|
1982
|
+
bodyCaches.set(tokens, cache);
|
|
1983
|
+
}
|
|
1984
|
+
const visited = [];
|
|
1985
|
+
let result = {
|
|
1986
|
+
closeStart: tokens.length,
|
|
1987
|
+
end: tokens.length,
|
|
1988
|
+
foundClose: false,
|
|
1989
|
+
hasContent: false
|
|
1990
|
+
};
|
|
1991
|
+
for (let pos = start;pos < tokens.length; pos++) {
|
|
1992
|
+
const cached = cache.get(pos);
|
|
1993
|
+
if (cached) {
|
|
1994
|
+
result = cached;
|
|
1995
|
+
break;
|
|
1996
|
+
}
|
|
1997
|
+
const end = mathCloseEnd(tokens, pos);
|
|
1998
|
+
if (end > pos) {
|
|
1999
|
+
result = { closeStart: pos, end, foundClose: true, hasContent: false };
|
|
2000
|
+
cache.set(pos, result);
|
|
2001
|
+
break;
|
|
2002
|
+
}
|
|
2003
|
+
visited.push(pos);
|
|
2004
|
+
}
|
|
2005
|
+
for (let i = visited.length - 1;i >= 0; i--) {
|
|
2006
|
+
const pos = visited[i];
|
|
2007
|
+
const token5 = tokens[pos];
|
|
2008
|
+
if (!result.hasContent && (token5.type === "BACKSLASH_BREAK" || token5.value.trim() !== "")) {
|
|
2009
|
+
result = { ...result, hasContent: true };
|
|
2010
|
+
}
|
|
2011
|
+
cache.set(pos, result);
|
|
2012
|
+
}
|
|
2013
|
+
return result;
|
|
2014
|
+
}
|
|
2015
|
+
|
|
2016
|
+
// packages/parser/src/parser/rules/opaque-probe.ts
|
|
2017
|
+
function createOpaqueProbe(ctx) {
|
|
2018
|
+
return {
|
|
2019
|
+
...ctx,
|
|
2020
|
+
diagnostics: [],
|
|
2021
|
+
footnotes: [],
|
|
2022
|
+
tocEntries: [],
|
|
2023
|
+
codeBlocks: [],
|
|
2024
|
+
htmlBlocks: [],
|
|
2025
|
+
bibcites: [],
|
|
2026
|
+
scope: {
|
|
2027
|
+
...ctx.scope,
|
|
2028
|
+
inlineEnd: undefined,
|
|
2029
|
+
tableFormatting: undefined,
|
|
2030
|
+
blockCloseCondition: () => true
|
|
2031
|
+
}
|
|
2032
|
+
};
|
|
2033
|
+
}
|
|
2034
|
+
function opaqueRuleEnd(probe, pos, rules, requireClosed = false) {
|
|
2035
|
+
const token5 = probe.tokens[pos];
|
|
2036
|
+
if (!token5)
|
|
2037
|
+
return pos;
|
|
2038
|
+
probe.pos = pos;
|
|
2039
|
+
for (const rule of rules) {
|
|
2040
|
+
if (!rule.startTokens.includes(token5.type))
|
|
2041
|
+
continue;
|
|
2042
|
+
if (rule.name === "code") {
|
|
2043
|
+
const open = findCodeOpen(probe.tokens, pos);
|
|
2044
|
+
if (!open)
|
|
2045
|
+
continue;
|
|
2046
|
+
if (open.closingSwallowed) {
|
|
2047
|
+
if (!requireClosed)
|
|
2048
|
+
return open.bodyStart;
|
|
2049
|
+
continue;
|
|
2050
|
+
}
|
|
2051
|
+
const bounds = findCodeBodyBounds(probe.tokens, open.bodyStart);
|
|
2052
|
+
if (!requireClosed || bounds.foundClose)
|
|
2053
|
+
return bounds.end;
|
|
2054
|
+
continue;
|
|
2055
|
+
}
|
|
2056
|
+
if (rule.name === "math") {
|
|
2057
|
+
const open = findMathOpen(probe.tokens, pos);
|
|
2058
|
+
if (!open)
|
|
2059
|
+
continue;
|
|
2060
|
+
const bounds = findMathBodyBounds(probe.tokens, open.bodyStart);
|
|
2061
|
+
if (bounds.hasContent && (!requireClosed || bounds.foundClose))
|
|
2062
|
+
return bounds.end;
|
|
2063
|
+
continue;
|
|
2064
|
+
}
|
|
2065
|
+
const result = rule.parse(probe);
|
|
2066
|
+
if (result.success)
|
|
2067
|
+
return pos + result.consumed;
|
|
2068
|
+
}
|
|
2069
|
+
return pos;
|
|
2070
|
+
}
|
|
2071
|
+
|
|
2072
|
+
// packages/parser/src/parser/rules/tokens.ts
|
|
2073
|
+
function currentToken(ctx) {
|
|
2074
|
+
return ctx.tokens[ctx.pos] ?? eofToken();
|
|
2075
|
+
}
|
|
2076
|
+
function eofToken() {
|
|
2077
|
+
return {
|
|
2078
|
+
type: "EOF",
|
|
2079
|
+
value: "",
|
|
2080
|
+
position: { start: { line: 0, column: 0, offset: 0 }, end: { line: 0, column: 0, offset: 0 } },
|
|
2081
|
+
lineStart: false
|
|
2082
|
+
};
|
|
2083
|
+
}
|
|
2084
|
+
function hasClosingMarkerBeforeNewline(ctx, markerType, markerValue) {
|
|
2085
|
+
let pos = ctx.pos;
|
|
2086
|
+
while (pos < (ctx.scope.inlineEnd ?? ctx.tokens.length)) {
|
|
2087
|
+
const token5 = ctx.tokens[pos];
|
|
2088
|
+
if (!token5 || token5.type === "NEWLINE" || token5.type === "EOF") {
|
|
2089
|
+
return false;
|
|
2090
|
+
}
|
|
2091
|
+
if (token5.type === markerType) {
|
|
2092
|
+
if (markerValue === undefined || token5.value === markerValue) {
|
|
2093
|
+
return true;
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
2096
|
+
pos++;
|
|
2097
|
+
}
|
|
2098
|
+
return false;
|
|
2099
|
+
}
|
|
2100
|
+
// packages/parser/src/parser/rules/block/code/attributes.ts
|
|
2101
|
+
function repairSwallowedCodeClose(ctx, pos, attrs) {
|
|
2102
|
+
const prevToken = ctx.tokens[pos - 1];
|
|
2103
|
+
if (prevToken?.type !== "QUOTED_STRING" || !prevToken.value.includes("]]")) {
|
|
2104
|
+
return null;
|
|
2105
|
+
}
|
|
2106
|
+
const rawValue = prevToken.value;
|
|
2107
|
+
const bracketIdx = rawValue.indexOf("]]");
|
|
2108
|
+
const truncatedValue = rawValue.startsWith('"') ? rawValue.slice(1, bracketIdx) : rawValue.slice(0, bracketIdx);
|
|
2109
|
+
for (const key of Object.keys(attrs)) {
|
|
2110
|
+
const stored = attrs[key];
|
|
2111
|
+
if (stored === rawValue || stored === rawValue.slice(1, -1) || stored === rawValue.slice(1)) {
|
|
2112
|
+
attrs[key] = truncatedValue;
|
|
2113
|
+
break;
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2116
|
+
return {
|
|
2117
|
+
closingSwallowed: rawValue.includes("[[/code]]")
|
|
2118
|
+
};
|
|
2119
|
+
}
|
|
2120
|
+
|
|
2121
|
+
// packages/parser/src/parser/rules/block/paragraph/span-markers.ts
|
|
2122
|
+
function processCloseSpanMarkers(elements) {
|
|
2123
|
+
let result = null;
|
|
2124
|
+
for (let i = 0;i < elements.length; i++) {
|
|
2125
|
+
const elem = elements[i];
|
|
2126
|
+
if (!elem)
|
|
2127
|
+
continue;
|
|
2128
|
+
if (isCloseSpanMarker(elem)) {
|
|
2129
|
+
if (result === null) {
|
|
2130
|
+
result = elements.slice(0, i);
|
|
2131
|
+
}
|
|
2132
|
+
if (result.length > 0) {
|
|
2133
|
+
const spanContent = [...result];
|
|
2134
|
+
result.length = 0;
|
|
2135
|
+
result.push({
|
|
2136
|
+
element: "container",
|
|
2137
|
+
data: {
|
|
2138
|
+
type: "span",
|
|
2139
|
+
attributes: {},
|
|
2140
|
+
elements: spanContent
|
|
2141
|
+
}
|
|
2142
|
+
});
|
|
2143
|
+
}
|
|
2144
|
+
} else {
|
|
2145
|
+
result?.push(elem);
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
return result ?? elements;
|
|
2149
|
+
}
|
|
2150
|
+
function isCloseSpanMarker(elem) {
|
|
2151
|
+
return elem.element === "container" && elem.data && typeof elem.data === "object" && "type" in elem.data && elem.data.type === "span" && "attributes" in elem.data && typeof elem.data.attributes === "object" && elem.data.attributes !== null && "_closeSpan" in elem.data.attributes;
|
|
2152
|
+
}
|
|
2153
|
+
|
|
2154
|
+
// packages/parser/src/parser/rules/inline/parsing/preserved-line-break.ts
|
|
2155
|
+
function createPreservedTrailingLineBreak() {
|
|
2156
|
+
const lineBreak = { element: "line-break" };
|
|
2157
|
+
lineBreak._preservedTrailingBreak = true;
|
|
2158
|
+
return lineBreak;
|
|
2159
|
+
}
|
|
2160
|
+
function createPreservedLeadingLineBreak() {
|
|
2161
|
+
const lineBreak = { element: "line-break", _preservedLeadingBreak: true };
|
|
2162
|
+
return lineBreak;
|
|
2163
|
+
}
|
|
2164
|
+
function isPreservedLeadingLineBreak(element) {
|
|
2165
|
+
return element?.element === "line-break" && element._preservedLeadingBreak === true;
|
|
2166
|
+
}
|
|
2167
|
+
|
|
2168
|
+
// packages/parser/src/parser/rules/block/paragraph/normalize.ts
|
|
2169
|
+
function normalizeParagraphElements(source) {
|
|
2170
|
+
let elements = processCloseSpanMarkers(source);
|
|
2171
|
+
removeTrailingLineBreaks(elements);
|
|
2172
|
+
removeTrailingWhitespaceText(elements);
|
|
2173
|
+
elements = removeLeadingLineBreaks(elements);
|
|
2174
|
+
return elements;
|
|
2175
|
+
}
|
|
2176
|
+
function removeTrailingLineBreaks(elements) {
|
|
2177
|
+
while (elements.length > 0 && elements[elements.length - 1]?.element === "line-break") {
|
|
2178
|
+
const lastEl = elements[elements.length - 1];
|
|
2179
|
+
if (lastEl._preservedTrailingBreak) {
|
|
2180
|
+
delete lastEl._preservedTrailingBreak;
|
|
2181
|
+
break;
|
|
2182
|
+
}
|
|
2183
|
+
elements.pop();
|
|
2184
|
+
}
|
|
2185
|
+
}
|
|
2186
|
+
function removeTrailingWhitespaceText(elements) {
|
|
2187
|
+
while (elements.length > 0) {
|
|
2188
|
+
const last = elements[elements.length - 1];
|
|
2189
|
+
if (last?.element === "text" && "data" in last && typeof last.data === "string" && last.data.trim() === "") {
|
|
2190
|
+
elements.pop();
|
|
2191
|
+
} else {
|
|
2192
|
+
break;
|
|
2193
|
+
}
|
|
2194
|
+
}
|
|
2195
|
+
}
|
|
2196
|
+
function removeLeadingLineBreaks(elements) {
|
|
2197
|
+
let first = 0;
|
|
2198
|
+
while (first < elements.length && elements[first]?.element === "line-break" && !isPreservedLeadingLineBreak(elements[first])) {
|
|
2199
|
+
first++;
|
|
2200
|
+
}
|
|
2201
|
+
return first > 0 ? elements.slice(first) : elements;
|
|
2202
|
+
}
|
|
2203
|
+
|
|
2204
|
+
// packages/parser/src/parser/rules/block/code/content.ts
|
|
2205
|
+
function collectCodeContent(ctx, startPos, closingSwallowed) {
|
|
2206
|
+
if (closingSwallowed)
|
|
2207
|
+
return { contents: "", consumed: 0, foundClose: true };
|
|
2208
|
+
const bounds = findCodeBodyBounds(ctx.tokens, startPos);
|
|
2209
|
+
return {
|
|
2210
|
+
contents: ctx.tokens.slice(startPos, bounds.closeStart).map((token5) => token5.value).join(""),
|
|
2211
|
+
consumed: bounds.end - startPos,
|
|
2212
|
+
foundClose: bounds.foundClose
|
|
2213
|
+
};
|
|
2214
|
+
}
|
|
2215
|
+
|
|
2216
|
+
// packages/parser/src/parser/rules/block/code/index.ts
|
|
2217
|
+
var codeBlockRule = {
|
|
2218
|
+
name: "code",
|
|
2219
|
+
startTokens: ["BLOCK_OPEN"],
|
|
2220
|
+
requiresLineStart: false,
|
|
2221
|
+
parse(ctx) {
|
|
2222
|
+
const openToken = currentToken(ctx);
|
|
2223
|
+
if (openToken.type !== "BLOCK_OPEN") {
|
|
2224
|
+
return { success: false };
|
|
2225
|
+
}
|
|
2226
|
+
const open = findCodeOpen(ctx.tokens, ctx.pos);
|
|
2227
|
+
if (!open)
|
|
2228
|
+
return { success: false };
|
|
2229
|
+
const attrResult = parseAttributesRaw(ctx, ctx.pos + 2);
|
|
2230
|
+
if (open.repaired)
|
|
2231
|
+
repairSwallowedCodeClose(ctx, open.attributesEnd, attrResult.attrs);
|
|
2232
|
+
let pos = open.bodyStart;
|
|
2233
|
+
let consumed = pos - ctx.pos;
|
|
2234
|
+
const contentResult = collectCodeContent(ctx, pos, open.closingSwallowed);
|
|
2235
|
+
let codeContent = contentResult.contents.replace(/\n$/, "");
|
|
2236
|
+
consumed += contentResult.consumed;
|
|
2237
|
+
pos += contentResult.consumed;
|
|
2238
|
+
if (!contentResult.foundClose) {
|
|
2239
|
+
ctx.diagnostics.push({
|
|
2240
|
+
severity: "warning",
|
|
2241
|
+
code: "unclosed-block",
|
|
2242
|
+
message: "Missing closing tag [[/code]] for [[code]]",
|
|
2243
|
+
position: openToken.position
|
|
2244
|
+
});
|
|
2245
|
+
}
|
|
2246
|
+
const codeBlockData = {
|
|
2247
|
+
contents: codeContent,
|
|
2248
|
+
language: attrResult.attrs.type ?? null,
|
|
2249
|
+
name: attrResult.attrs.name ?? null
|
|
2250
|
+
};
|
|
2251
|
+
ctx.codeBlocks.push(codeBlockData);
|
|
2252
|
+
const elements = [{ element: "code", data: codeBlockData }];
|
|
2253
|
+
if (ctx.tokens[pos]?.type === "NEWLINE" && !getParagraphNewlineBoundary(ctx, pos, false).shouldBreak && !ctx.scope.blockCloseCondition?.({ ...ctx, pos: pos + 1 })) {
|
|
2254
|
+
const after = parseInlineUntil({ ...ctx, pos: pos + 1 }, "PARAGRAPH_BREAK");
|
|
2255
|
+
elements.push({ element: "line-break" }, ...normalizeParagraphElements(after.elements));
|
|
2256
|
+
consumed += 1 + after.consumed;
|
|
2257
|
+
}
|
|
2258
|
+
return { success: true, elements, consumed };
|
|
2259
|
+
}
|
|
2260
|
+
};
|
|
2261
|
+
|
|
2262
|
+
// packages/parser/src/parser/rules/block/math/index.ts
|
|
2263
|
+
var mathBlockRule = {
|
|
2264
|
+
name: "math",
|
|
2265
|
+
startTokens: ["BLOCK_OPEN"],
|
|
2266
|
+
requiresLineStart: false,
|
|
2267
|
+
parse(ctx) {
|
|
2268
|
+
const openToken = currentToken(ctx);
|
|
2269
|
+
const open = findMathOpen(ctx.tokens, ctx.pos);
|
|
2270
|
+
if (!open)
|
|
2271
|
+
return { success: false };
|
|
2272
|
+
const bounds = findMathBodyBounds(ctx.tokens, open.bodyStart);
|
|
2273
|
+
if (!bounds.foundClose) {
|
|
2274
|
+
ctx.diagnostics.push({
|
|
2275
|
+
severity: "warning",
|
|
2276
|
+
code: "unclosed-block",
|
|
2277
|
+
message: "Missing closing tag [[/math]] for [[math]]",
|
|
2278
|
+
position: openToken.position
|
|
2279
|
+
});
|
|
2280
|
+
}
|
|
2281
|
+
if (!bounds.hasContent) {
|
|
2282
|
+
return { success: false };
|
|
2283
|
+
}
|
|
2284
|
+
const latexSource = ctx.tokens.slice(open.bodyStart, bounds.closeStart).map((token5) => token5.type === "BACKSLASH_BREAK" ? "\\\n" : token5.value).join("").trim();
|
|
2285
|
+
const name = ctx.tokens.slice(open.nameStart, open.nameEnd).map((token5) => token5.value).join("");
|
|
2286
|
+
return {
|
|
2287
|
+
success: true,
|
|
2288
|
+
elements: [
|
|
2289
|
+
{
|
|
2290
|
+
element: "math",
|
|
2291
|
+
data: {
|
|
2292
|
+
name: name || null,
|
|
2293
|
+
"latex-source": latexSource
|
|
2294
|
+
}
|
|
2295
|
+
}
|
|
2296
|
+
],
|
|
2297
|
+
consumed: bounds.end - ctx.pos
|
|
2298
|
+
};
|
|
2299
|
+
}
|
|
2300
|
+
};
|
|
2301
|
+
|
|
2302
|
+
// packages/parser/src/parser/rules/inline/link-triple/fallback.ts
|
|
2303
|
+
function literalOpenLink(value) {
|
|
2304
|
+
return {
|
|
2305
|
+
success: true,
|
|
2306
|
+
elements: [{ element: "text", data: value }],
|
|
2307
|
+
consumed: 1
|
|
2308
|
+
};
|
|
2309
|
+
}
|
|
2310
|
+
|
|
2311
|
+
// packages/parser/src/parser/rules/inline/link-triple/label.ts
|
|
2312
|
+
function buildTripleLinkLabel(args) {
|
|
2313
|
+
if (args.isPage && args.foundPipe && !args.labelText.trim())
|
|
2314
|
+
return "page";
|
|
2315
|
+
return {
|
|
2316
|
+
text: getTripleLinkDisplayText({
|
|
2317
|
+
...args,
|
|
2318
|
+
originalTarget: args.isPage && !args.foundPipe ? args.originalTarget.split("#")[0] : args.originalTarget
|
|
2319
|
+
})
|
|
2320
|
+
};
|
|
2321
|
+
}
|
|
2322
|
+
function getTripleLinkDisplayText(args) {
|
|
2323
|
+
const trimmedLabel = args.labelText.trim();
|
|
2324
|
+
if (args.foundPipe) {
|
|
2325
|
+
return trimmedLabel || args.finalTarget;
|
|
2326
|
+
}
|
|
2327
|
+
const colonIdx = args.originalTarget.indexOf(":");
|
|
2328
|
+
if (colonIdx !== -1 && !args.originalTarget.startsWith("http") && !args.originalTarget.startsWith("*")) {
|
|
2329
|
+
return args.originalTarget.slice(colonIdx + 1).trim();
|
|
2330
|
+
}
|
|
2331
|
+
return args.originalTarget;
|
|
2332
|
+
}
|
|
2333
|
+
|
|
2334
|
+
// packages/parser/src/parser/rules/inline/link-triple/syntax.ts
|
|
2335
|
+
function hasClosingLinkMarker(ctx, startPos) {
|
|
2336
|
+
let pos = startPos;
|
|
2337
|
+
while (pos < ctx.tokens.length) {
|
|
2338
|
+
const token5 = ctx.tokens[pos];
|
|
2339
|
+
if (!token5 || token5.type === "EOF") {
|
|
2340
|
+
return false;
|
|
2341
|
+
}
|
|
2342
|
+
if (token5.type === "LINK_CLOSE") {
|
|
2343
|
+
return true;
|
|
2344
|
+
}
|
|
2345
|
+
if (token5.type === "NEWLINE") {
|
|
2346
|
+
const next = ctx.tokens[pos + 1];
|
|
2347
|
+
if (next?.type === "NEWLINE" || next?.type === "LINK_CLOSE") {
|
|
2348
|
+
return false;
|
|
2349
|
+
}
|
|
2350
|
+
}
|
|
2351
|
+
pos++;
|
|
2352
|
+
}
|
|
2353
|
+
return false;
|
|
2354
|
+
}
|
|
2355
|
+
function collectTripleLinkParts(ctx, startPos) {
|
|
2356
|
+
let target = "";
|
|
2357
|
+
let labelText = "";
|
|
2358
|
+
let foundPipe = false;
|
|
2359
|
+
let consumed = 1;
|
|
2360
|
+
let pos = startPos;
|
|
2361
|
+
while (pos < ctx.tokens.length) {
|
|
2362
|
+
const token5 = ctx.tokens[pos];
|
|
2363
|
+
if (!token5 || token5.type === "LINK_CLOSE" || token5.type === "EOF") {
|
|
2364
|
+
break;
|
|
2365
|
+
}
|
|
2366
|
+
if (token5.type === "NEWLINE") {
|
|
2367
|
+
if (foundPipe) {
|
|
2368
|
+
labelText += " ";
|
|
2369
|
+
} else {
|
|
2370
|
+
target += " ";
|
|
2371
|
+
}
|
|
2372
|
+
consumed++;
|
|
2373
|
+
pos++;
|
|
2374
|
+
continue;
|
|
2375
|
+
}
|
|
2376
|
+
if (token5.type === "PIPE" && !foundPipe) {
|
|
2377
|
+
foundPipe = true;
|
|
2378
|
+
} else if (foundPipe) {
|
|
2379
|
+
labelText += token5.value;
|
|
2380
|
+
} else {
|
|
2381
|
+
target += token5.value;
|
|
2382
|
+
}
|
|
2383
|
+
consumed++;
|
|
2384
|
+
pos++;
|
|
2385
|
+
}
|
|
2386
|
+
if (ctx.tokens[pos]?.type === "LINK_CLOSE") {
|
|
2387
|
+
consumed++;
|
|
2388
|
+
}
|
|
2389
|
+
return { target, labelText, foundPipe, consumed };
|
|
2390
|
+
}
|
|
2391
|
+
|
|
2392
|
+
// packages/parser/src/parser/rules/inline/link-triple/interwiki.ts
|
|
2393
|
+
var INTERWIKI_PREFIXES = new Set(["wikipedia", "google", "dictionary", "wikidot"]);
|
|
2394
|
+
function isInterwikiTarget(target) {
|
|
2395
|
+
const colonIdx = target.indexOf(":");
|
|
2396
|
+
if (colonIdx <= 0 || target.includes("/")) {
|
|
2397
|
+
return false;
|
|
2398
|
+
}
|
|
2399
|
+
const prefix = target.slice(0, colonIdx).toLowerCase();
|
|
2400
|
+
return INTERWIKI_PREFIXES.has(prefix);
|
|
2401
|
+
}
|
|
2402
|
+
|
|
2403
|
+
// packages/parser/src/parser/rules/inline/link-triple/target.ts
|
|
2404
|
+
function normalizeTripleLinkTarget(trimmedTarget) {
|
|
2405
|
+
if (trimmedTarget.startsWith("*")) {
|
|
2406
|
+
return { target: trimmedTarget.slice(1), hasStar: true };
|
|
2407
|
+
}
|
|
2408
|
+
return { target: trimmedTarget, hasStar: false };
|
|
2409
|
+
}
|
|
2410
|
+
function isInvalidTripleLinkTarget(trimmedTarget, foundPipe) {
|
|
2411
|
+
return trimmedTarget === "" && foundPipe || /#{2,}/.test(trimmedTarget);
|
|
2412
|
+
}
|
|
2413
|
+
function determineLinkTypeAndLocation(target) {
|
|
2414
|
+
if (target.startsWith("#")) {
|
|
2415
|
+
return { linkType: "anchor", link: target };
|
|
2416
|
+
}
|
|
2417
|
+
if (target.startsWith("http://") || target.startsWith("https://")) {
|
|
2418
|
+
return { linkType: "direct", link: target };
|
|
2419
|
+
}
|
|
2420
|
+
if (isInterwikiTarget(target)) {
|
|
2421
|
+
return { linkType: "interwiki", link: target };
|
|
2422
|
+
}
|
|
2423
|
+
return { linkType: "page", link: { site: null, page: target } };
|
|
2424
|
+
}
|
|
2425
|
+
|
|
2426
|
+
// packages/parser/src/parser/rules/inline/link-triple/index.ts
|
|
2427
|
+
var linkTripleRule = {
|
|
2428
|
+
name: "linkTriple",
|
|
2429
|
+
startTokens: ["LINK_OPEN"],
|
|
2430
|
+
parse(ctx) {
|
|
2431
|
+
const startToken = currentToken(ctx);
|
|
2432
|
+
if (!hasClosingLinkMarker(ctx, ctx.pos + 1)) {
|
|
2433
|
+
return literalOpenLink(startToken.value);
|
|
2434
|
+
}
|
|
2435
|
+
const parts = collectTripleLinkParts(ctx, ctx.pos + 1);
|
|
2436
|
+
const trimmedTarget = parts.target.trim();
|
|
2437
|
+
if (isInvalidTripleLinkTarget(trimmedTarget, parts.foundPipe)) {
|
|
2438
|
+
return literalOpenLink(startToken.value);
|
|
2439
|
+
}
|
|
2440
|
+
const normalized = normalizeTripleLinkTarget(trimmedTarget);
|
|
2441
|
+
const { linkType, link } = determineLinkTypeAndLocation(normalized.target);
|
|
2442
|
+
const label = buildTripleLinkLabel({
|
|
2443
|
+
isPage: linkType === "page",
|
|
2444
|
+
foundPipe: parts.foundPipe,
|
|
2445
|
+
labelText: parts.labelText,
|
|
2446
|
+
finalTarget: normalized.target,
|
|
2447
|
+
originalTarget: trimmedTarget
|
|
2448
|
+
});
|
|
2449
|
+
return {
|
|
2450
|
+
success: true,
|
|
2451
|
+
elements: [
|
|
2452
|
+
{
|
|
2453
|
+
element: "link",
|
|
2454
|
+
data: {
|
|
2455
|
+
type: linkType,
|
|
2456
|
+
link,
|
|
2457
|
+
extra: null,
|
|
2458
|
+
label,
|
|
2459
|
+
target: normalized.hasStar && linkType === "direct" ? "new-tab" : null
|
|
2460
|
+
}
|
|
2461
|
+
}
|
|
2462
|
+
],
|
|
2463
|
+
consumed: parts.consumed
|
|
2464
|
+
};
|
|
2465
|
+
}
|
|
2466
|
+
};
|
|
2467
|
+
|
|
2468
|
+
// packages/parser/src/parser/rules/block/note/boundary.ts
|
|
2469
|
+
var opaqueRules = [codeBlockRule, mathBlockRule, linkTripleRule];
|
|
2470
|
+
var boundsCache = new WeakMap;
|
|
2471
|
+
var closeCache = new WeakMap;
|
|
2472
|
+
function tagEnd(tokens, pos, name, close = false) {
|
|
2473
|
+
return tokens[pos]?.type === (close ? "BLOCK_END_OPEN" : "BLOCK_OPEN") && tokens[pos + 1]?.value.toLowerCase() === name && tokens[pos + 2]?.type === "BLOCK_CLOSE" ? pos + 3 : pos;
|
|
2474
|
+
}
|
|
2475
|
+
function findClose(probe, start, name) {
|
|
2476
|
+
let byName = closeCache.get(probe.tokens);
|
|
2477
|
+
if (!byName) {
|
|
2478
|
+
byName = new Map;
|
|
2479
|
+
closeCache.set(probe.tokens, byName);
|
|
2480
|
+
}
|
|
2481
|
+
let cache = byName.get(name);
|
|
2482
|
+
if (!cache) {
|
|
2483
|
+
cache = new Map;
|
|
2484
|
+
byName.set(name, cache);
|
|
2485
|
+
}
|
|
2486
|
+
if (cache.has(start))
|
|
2487
|
+
return cache.get(start);
|
|
2488
|
+
const visited = [];
|
|
2489
|
+
let result = -1;
|
|
2490
|
+
for (let pos = start;pos < probe.tokens.length; pos++) {
|
|
2491
|
+
if (cache.has(pos)) {
|
|
2492
|
+
result = cache.get(pos);
|
|
2493
|
+
break;
|
|
2494
|
+
}
|
|
2495
|
+
visited.push(pos);
|
|
2496
|
+
const protectedEnd = protectedInlineRegionEnd(probe.tokens, pos, probe.tokens.length);
|
|
2497
|
+
if (protectedEnd > pos) {
|
|
2498
|
+
pos = protectedEnd - 1;
|
|
2499
|
+
continue;
|
|
2500
|
+
}
|
|
2501
|
+
if (tagEnd(probe.tokens, pos, name, true) > pos) {
|
|
2502
|
+
result = pos;
|
|
2503
|
+
break;
|
|
2504
|
+
}
|
|
2505
|
+
const opaqueEnd = opaqueRuleEnd(probe, pos, opaqueRules, true);
|
|
2506
|
+
if (opaqueEnd > pos) {
|
|
2507
|
+
pos = opaqueEnd - 1;
|
|
2508
|
+
continue;
|
|
2509
|
+
}
|
|
2510
|
+
if (name === "note") {
|
|
2511
|
+
const footnoteStart = tagEnd(probe.tokens, pos, "footnote");
|
|
2512
|
+
if (footnoteStart > pos) {
|
|
2513
|
+
const end = findClose(probe, footnoteStart, "footnote");
|
|
2514
|
+
if (end >= 0)
|
|
2515
|
+
pos = end + 2;
|
|
2516
|
+
}
|
|
2517
|
+
}
|
|
2518
|
+
}
|
|
2519
|
+
for (const pos of visited)
|
|
2520
|
+
cache.set(pos, result);
|
|
2521
|
+
return result;
|
|
2522
|
+
}
|
|
2523
|
+
function findNoteBounds(ctx, start = ctx.pos) {
|
|
2524
|
+
const openEnd = tagEnd(ctx.tokens, start, "note");
|
|
2525
|
+
if (openEnd === start || ctx.tokens[openEnd]?.type !== "NEWLINE")
|
|
2526
|
+
return null;
|
|
2527
|
+
let cache = boundsCache.get(ctx.tokens);
|
|
2528
|
+
if (!cache) {
|
|
2529
|
+
cache = new Map;
|
|
2530
|
+
boundsCache.set(ctx.tokens, cache);
|
|
2531
|
+
}
|
|
2532
|
+
if (cache.has(start))
|
|
2533
|
+
return cache.get(start);
|
|
2534
|
+
const close = findClose(createOpaqueProbe(ctx), openEnd + 1, "note");
|
|
2535
|
+
const result = close < 0 ? null : { bodyStart: openEnd + 1, close, end: close + 3 };
|
|
2536
|
+
cache.set(start, result);
|
|
2537
|
+
return result;
|
|
2538
|
+
}
|
|
2539
|
+
|
|
2540
|
+
// packages/parser/src/parser/rules/inline/parsing/block-boundary.ts
|
|
2541
|
+
function isExcludedBlockToken(ctx, tokenPos) {
|
|
2542
|
+
const excluded = ctx.scope.excludedBlockNames;
|
|
2543
|
+
if (!excluded?.size)
|
|
2544
|
+
return false;
|
|
2545
|
+
const token5 = ctx.tokens[tokenPos];
|
|
1284
2546
|
if (token5?.type !== "BLOCK_OPEN" && token5?.type !== "BLOCK_END_OPEN")
|
|
1285
2547
|
return false;
|
|
1286
2548
|
const nameResult = parseBlockName(ctx, tokenPos + 1);
|
|
@@ -1297,6 +2559,8 @@ function isUnknownBlockToken(ctx, tokenPos) {
|
|
|
1297
2559
|
}
|
|
1298
2560
|
return true;
|
|
1299
2561
|
}
|
|
2562
|
+
if (nameResult.name === "note")
|
|
2563
|
+
return findNoteBounds(ctx, tokenPos) === null;
|
|
1300
2564
|
return !KNOWN_BLOCK_NAMES.has(nameResult.name);
|
|
1301
2565
|
}
|
|
1302
2566
|
function isIndentAcceptingBlock(ctx, tokenPos) {
|
|
@@ -1320,7 +2584,13 @@ function isParagraphBreakingBlockStart(ctx, newlinePos, lookAhead) {
|
|
|
1320
2584
|
if (!nextMeaningfulToken.lineStart && !isIndentedBlockOpener) {
|
|
1321
2585
|
return false;
|
|
1322
2586
|
}
|
|
1323
|
-
return !parseImageOpen({ ...ctx, pos: nextPos }) && !isOrphanCloseSpan(ctx, nextPos) && !isAnchorName(ctx, nextPos) && !isInvalidBlockOpen(ctx, nextPos) && !isInvalidHeading(ctx, nextPos) && !isExcludedBlockStart(ctx, nextPos) && !isUnknownBlockStart(ctx, nextPos);
|
|
2587
|
+
return !parseImageOpen({ ...ctx, pos: nextPos }) && !isOrphanCloseSpan(ctx, nextPos) && !isAnchorName(ctx, nextPos) && !isInvalidBlockOpen(ctx, nextPos) && !isInvalidHeading(ctx, nextPos) && !isInvalidListMarker(ctx, nextPos) && !isExcludedBlockStart(ctx, nextPos) && !isUnknownBlockStart(ctx, nextPos);
|
|
2588
|
+
}
|
|
2589
|
+
function isInvalidListMarker(ctx, markerPos) {
|
|
2590
|
+
const marker = ctx.tokens[markerPos];
|
|
2591
|
+
if (marker?.type !== "LIST_BULLET" && marker?.type !== "LIST_NUMBER")
|
|
2592
|
+
return false;
|
|
2593
|
+
return ctx.tokens[markerPos + 1]?.type !== "WHITESPACE";
|
|
1324
2594
|
}
|
|
1325
2595
|
function isOrphanCloseSpan(ctx, blockEndOpenPos) {
|
|
1326
2596
|
const token5 = ctx.tokens[blockEndOpenPos];
|
|
@@ -1406,13 +2676,6 @@ function skipWhitespaceAfterNewline(ctx, newlinePos) {
|
|
|
1406
2676
|
return lookAhead;
|
|
1407
2677
|
}
|
|
1408
2678
|
|
|
1409
|
-
// packages/parser/src/parser/rules/inline/parsing/preserved-line-break.ts
|
|
1410
|
-
function createPreservedTrailingLineBreak() {
|
|
1411
|
-
const lineBreak = { element: "line-break" };
|
|
1412
|
-
lineBreak._preservedTrailingBreak = true;
|
|
1413
|
-
return lineBreak;
|
|
1414
|
-
}
|
|
1415
|
-
|
|
1416
2679
|
// packages/parser/src/parser/rules/inline/parsing/simple-token.ts
|
|
1417
2680
|
function parseSimpleInlineToken(token5, nextToken) {
|
|
1418
2681
|
if (token5.type === "TEXT" && token5.value !== "(") {
|
|
@@ -1429,12 +2692,14 @@ function parseInlineUntil(ctx, endType) {
|
|
|
1429
2692
|
const nodes = [];
|
|
1430
2693
|
let consumed = 0;
|
|
1431
2694
|
let pos = ctx.pos;
|
|
2695
|
+
let consumedEmptyRaw = false;
|
|
1432
2696
|
const paragraphMode = endType === "PARAGRAPH_BREAK";
|
|
1433
|
-
const
|
|
2697
|
+
const preserveNewlines = endType === "EOF";
|
|
2698
|
+
const multiline = paragraphMode || preserveNewlines || FORMATTING_CLOSE_TOKENS.has(endType);
|
|
1434
2699
|
let inlineEnd = ctx.scope.inlineEnd ?? ctx.tokens.length;
|
|
1435
2700
|
if (!multiline) {
|
|
1436
2701
|
for (let end = ctx.pos;end < inlineEnd; end++) {
|
|
1437
|
-
const protectedEnd = protectedInlineRegionEnd(ctx.tokens, end, inlineEnd);
|
|
2702
|
+
const protectedEnd = Math.max(parseButtonSyntax(ctx, end, inlineEnd)?.end ?? end, parseSocialSyntax(ctx, end, inlineEnd)?.end ?? end, parseDateSyntax(ctx, end, inlineEnd)?.end ?? end, emailRegionEnd(ctx.tokens, end, inlineEnd), protectedInlineRegionEnd(ctx.tokens, end, inlineEnd));
|
|
1438
2703
|
if (protectedEnd > end) {
|
|
1439
2704
|
end = protectedEnd - 1;
|
|
1440
2705
|
continue;
|
|
@@ -1468,6 +2733,12 @@ function parseInlineUntil(ctx, endType) {
|
|
|
1468
2733
|
if (!multiline && token5.type === "NEWLINE") {
|
|
1469
2734
|
break;
|
|
1470
2735
|
}
|
|
2736
|
+
if (preserveNewlines && token5.type === "NEWLINE") {
|
|
2737
|
+
nodes.push({ element: "text", data: token5.value });
|
|
2738
|
+
pos++;
|
|
2739
|
+
consumed++;
|
|
2740
|
+
continue;
|
|
2741
|
+
}
|
|
1471
2742
|
if (multiline && token5.type === "NEWLINE" && !ctx.scope.tableFormatting) {
|
|
1472
2743
|
const boundary = getParagraphNewlineBoundary(ctx, pos, nodes.length > 0);
|
|
1473
2744
|
if (boundary.shouldBreak) {
|
|
@@ -1483,10 +2754,11 @@ function parseInlineUntil(ctx, endType) {
|
|
|
1483
2754
|
consumed++;
|
|
1484
2755
|
continue;
|
|
1485
2756
|
}
|
|
1486
|
-
|
|
2757
|
+
const hasEmail = emailRegionEnd(ctx.tokens, pos, inlineEnd) > pos;
|
|
2758
|
+
if (token5.type === endType && !hasEmail) {
|
|
1487
2759
|
break;
|
|
1488
2760
|
}
|
|
1489
|
-
if (canCollectLongPlainTextRuns) {
|
|
2761
|
+
if (canCollectLongPlainTextRuns && !hasEmail) {
|
|
1490
2762
|
const plainTextRun = collectLongPlainTextRun(ctx, pos, endType);
|
|
1491
2763
|
if (plainTextRun) {
|
|
1492
2764
|
nodes.push({ element: "text", data: plainTextRun.value });
|
|
@@ -1496,7 +2768,7 @@ function parseInlineUntil(ctx, endType) {
|
|
|
1496
2768
|
}
|
|
1497
2769
|
}
|
|
1498
2770
|
const simpleToken = parseSimpleInlineToken(token5, ctx.tokens[pos + 1]);
|
|
1499
|
-
if (simpleToken) {
|
|
2771
|
+
if (simpleToken && !hasEmail) {
|
|
1500
2772
|
nodes.push(simpleToken.element);
|
|
1501
2773
|
consumed += simpleToken.consumed;
|
|
1502
2774
|
pos += simpleToken.consumed;
|
|
@@ -1507,6 +2779,10 @@ function parseInlineUntil(ctx, endType) {
|
|
|
1507
2779
|
for (const rule of getCandidateInlineRules(inlineRules, token5.type)) {
|
|
1508
2780
|
const result = rule.parse(inlineCtx);
|
|
1509
2781
|
if (result.success) {
|
|
2782
|
+
stripAutomaticLineBreak(nodes, result.stripLeadingLineBreak);
|
|
2783
|
+
if (rule.name === "raw" && result.elements.length === 0 && nodes.length === 0) {
|
|
2784
|
+
consumedEmptyRaw = true;
|
|
2785
|
+
}
|
|
1510
2786
|
if (rule.name === "comment") {
|
|
1511
2787
|
let after = pos + result.consumed;
|
|
1512
2788
|
while (ctx.tokens[after]?.type === "WHITESPACE")
|
|
@@ -1525,7 +2801,9 @@ function parseInlineUntil(ctx, endType) {
|
|
|
1525
2801
|
nodes.pop();
|
|
1526
2802
|
}
|
|
1527
2803
|
}
|
|
1528
|
-
|
|
2804
|
+
for (const element of result.elements) {
|
|
2805
|
+
nodes.push(paragraphMode && consumedEmptyRaw && nodes.length === 0 && token5.type === "NEWLINE" && element.element === "line-break" ? createPreservedLeadingLineBreak() : element);
|
|
2806
|
+
}
|
|
1529
2807
|
consumed += result.consumed;
|
|
1530
2808
|
pos += result.consumed;
|
|
1531
2809
|
matched = true;
|
|
@@ -1550,138 +2828,10 @@ var FORMATTING_CLOSE_TOKENS = new Set([
|
|
|
1550
2828
|
"MONO_CLOSE",
|
|
1551
2829
|
"COLOR_MARKER"
|
|
1552
2830
|
]);
|
|
1553
|
-
// packages/parser/src/parser/rules/block/parsing/attributes/names.ts
|
|
1554
|
-
function consumeAttributeName(ctx, startPos, startConsumed, startName, options) {
|
|
1555
|
-
if (startName === "_" && isAttributeWordToken(ctx.tokens[startPos])) {
|
|
1556
|
-
startName += ctx.tokens[startPos]?.value ?? "";
|
|
1557
|
-
startPos++;
|
|
1558
|
-
startConsumed++;
|
|
1559
|
-
}
|
|
1560
|
-
return options.strikeHyphens ? consumeRawNameSuffix(ctx, startPos, startConsumed, startName, options.hyphenatedNames) : consumeSafeNameSuffix(ctx, startPos, startConsumed, startName);
|
|
1561
|
-
}
|
|
1562
|
-
function isAttributeNameToken(token5) {
|
|
1563
|
-
return isAttributeWordToken(token5) || token5?.type === "UNDERSCORE";
|
|
1564
|
-
}
|
|
1565
|
-
function consumeSafeNameSuffix(ctx, startPos, startConsumed, startName) {
|
|
1566
|
-
let name = startName;
|
|
1567
|
-
let pos = startPos;
|
|
1568
|
-
let consumed = startConsumed;
|
|
1569
|
-
while (isAttributeNameSeparator(ctx.tokens[pos]) && isAttributeWordToken(ctx.tokens[pos + 1])) {
|
|
1570
|
-
name += ctx.tokens[pos]?.value ?? "";
|
|
1571
|
-
pos++;
|
|
1572
|
-
consumed++;
|
|
1573
|
-
name += ctx.tokens[pos]?.value ?? "";
|
|
1574
|
-
pos++;
|
|
1575
|
-
consumed++;
|
|
1576
|
-
}
|
|
1577
|
-
return { name, pos, consumed };
|
|
1578
|
-
}
|
|
1579
|
-
function consumeRawNameSuffix(ctx, startPos, startConsumed, startName, hyphenatedNames) {
|
|
1580
|
-
let name = startName;
|
|
1581
|
-
let pos = startPos;
|
|
1582
|
-
let consumed = startConsumed;
|
|
1583
|
-
while (isAttributeNameSeparator(ctx.tokens[pos])) {
|
|
1584
|
-
while (isAttributeNameSeparator(ctx.tokens[pos])) {
|
|
1585
|
-
if (hyphenatedNames || ctx.tokens[pos]?.type === "UNDERSCORE") {
|
|
1586
|
-
name += ctx.tokens[pos]?.value ?? "-";
|
|
1587
|
-
}
|
|
1588
|
-
pos++;
|
|
1589
|
-
consumed++;
|
|
1590
|
-
}
|
|
1591
|
-
if (!isAttributeWordToken(ctx.tokens[pos])) {
|
|
1592
|
-
break;
|
|
1593
|
-
}
|
|
1594
|
-
if (hyphenatedNames || name.endsWith("_")) {
|
|
1595
|
-
name += ctx.tokens[pos]?.value ?? "";
|
|
1596
|
-
}
|
|
1597
|
-
pos++;
|
|
1598
|
-
consumed++;
|
|
1599
|
-
}
|
|
1600
|
-
return { name, pos, consumed };
|
|
1601
|
-
}
|
|
1602
|
-
function isAttributeWordToken(token5) {
|
|
1603
|
-
return token5?.type === "TEXT" || token5?.type === "IDENTIFIER";
|
|
1604
|
-
}
|
|
1605
|
-
function isAttributeNameSeparator(token5) {
|
|
1606
|
-
return token5?.type === "TEXT" && token5.value === "-" || token5?.type === "STRIKE_MARKER" || token5?.type === "UNDERSCORE";
|
|
1607
|
-
}
|
|
1608
|
-
|
|
1609
|
-
// packages/parser/src/parser/rules/block/parsing/attributes/values.ts
|
|
1610
|
-
function consumeAttributeValue(token5) {
|
|
1611
|
-
if (!token5) {
|
|
1612
|
-
return null;
|
|
1613
|
-
}
|
|
1614
|
-
if (token5.type === "QUOTED_STRING") {
|
|
1615
|
-
return { value: stripQuotes(token5.value) };
|
|
1616
|
-
}
|
|
1617
|
-
if (isAttributeNameToken(token5)) {
|
|
1618
|
-
return { value: token5.value };
|
|
1619
|
-
}
|
|
1620
|
-
return null;
|
|
1621
|
-
}
|
|
1622
|
-
function stripQuotes(value) {
|
|
1623
|
-
return value.startsWith('"') && value.endsWith('"') ? value.slice(1, -1) : value;
|
|
1624
|
-
}
|
|
1625
|
-
|
|
1626
|
-
// packages/parser/src/parser/rules/block/parsing/attributes/scanner.ts
|
|
1627
|
-
function scanAttributes(ctx, startPos, options) {
|
|
1628
|
-
const attrs = {};
|
|
1629
|
-
let pos = startPos;
|
|
1630
|
-
let consumed = 0;
|
|
1631
|
-
while (pos < ctx.tokens.length) {
|
|
1632
|
-
const token5 = ctx.tokens[pos];
|
|
1633
|
-
if (!token5 || isAttributeTerminator(token5)) {
|
|
1634
|
-
break;
|
|
1635
|
-
}
|
|
1636
|
-
if (token5.type === "WHITESPACE") {
|
|
1637
|
-
pos++;
|
|
1638
|
-
consumed++;
|
|
1639
|
-
continue;
|
|
1640
|
-
}
|
|
1641
|
-
if (!isAttributeNameToken(token5)) {
|
|
1642
|
-
pos++;
|
|
1643
|
-
consumed++;
|
|
1644
|
-
continue;
|
|
1645
|
-
}
|
|
1646
|
-
let name = token5.value;
|
|
1647
|
-
pos++;
|
|
1648
|
-
consumed++;
|
|
1649
|
-
const nameResult = consumeAttributeName(ctx, pos, consumed, name, options);
|
|
1650
|
-
pos = nameResult.pos;
|
|
1651
|
-
consumed = nameResult.consumed;
|
|
1652
|
-
name = nameResult.name.toLowerCase();
|
|
1653
|
-
if (ctx.tokens[pos]?.type !== "EQUALS") {
|
|
1654
|
-
attrs[name] = "true";
|
|
1655
|
-
continue;
|
|
1656
|
-
}
|
|
1657
|
-
pos++;
|
|
1658
|
-
consumed++;
|
|
1659
|
-
const valueResult = consumeAttributeValue(ctx.tokens[pos]);
|
|
1660
|
-
if (!valueResult) {
|
|
1661
|
-
continue;
|
|
1662
|
-
}
|
|
1663
|
-
attrs[name] = valueResult.value;
|
|
1664
|
-
pos++;
|
|
1665
|
-
consumed++;
|
|
1666
|
-
}
|
|
1667
|
-
return { attrs, consumed };
|
|
1668
|
-
}
|
|
1669
|
-
function isAttributeTerminator(token5) {
|
|
1670
|
-
return token5.type === "BLOCK_CLOSE" || token5.type === "NEWLINE" || token5.type === "EOF";
|
|
1671
|
-
}
|
|
1672
|
-
|
|
1673
|
-
// packages/parser/src/parser/rules/block/parsing/attributes/index.ts
|
|
1674
|
-
function parseAttributes(ctx, startPos) {
|
|
1675
|
-
const result = scanAttributes(ctx, startPos, { hyphenatedNames: true, strikeHyphens: false });
|
|
1676
|
-
return { attrs: filterUnsafeAttributes(result.attrs), consumed: result.consumed };
|
|
1677
|
-
}
|
|
1678
|
-
function parseAttributesRaw(ctx, startPos, hyphenatedNames = true) {
|
|
1679
|
-
return scanAttributes(ctx, startPos, { hyphenatedNames, strikeHyphens: true });
|
|
1680
|
-
}
|
|
1681
2831
|
// packages/parser/src/parser/parse/block.ts
|
|
1682
|
-
function parseNextBlock(ctx, skipWhitespace2,
|
|
2832
|
+
function parseNextBlock(ctx, skipWhitespace2, isAtEnd3) {
|
|
1683
2833
|
skipWhitespace2();
|
|
1684
|
-
if (
|
|
2834
|
+
if (isAtEnd3()) {
|
|
1685
2835
|
return [];
|
|
1686
2836
|
}
|
|
1687
2837
|
const token5 = ctx.tokens[ctx.pos];
|
|
@@ -1700,7 +2850,7 @@ function parseNextBlock(ctx, skipWhitespace2, isAtEnd2) {
|
|
|
1700
2850
|
}
|
|
1701
2851
|
}
|
|
1702
2852
|
const result = ctx.blockFallbackRule.parse(ctx);
|
|
1703
|
-
if (result.success
|
|
2853
|
+
if (result.success) {
|
|
1704
2854
|
ctx.pos += result.consumed;
|
|
1705
2855
|
return result.elements;
|
|
1706
2856
|
}
|
|
@@ -1709,36 +2859,7 @@ function parseNextBlock(ctx, skipWhitespace2, isAtEnd2) {
|
|
|
1709
2859
|
}
|
|
1710
2860
|
|
|
1711
2861
|
// packages/parser/src/parser/parse/context.ts
|
|
1712
|
-
var
|
|
1713
|
-
|
|
1714
|
-
// packages/parser/src/parser/rules/tokens.ts
|
|
1715
|
-
function currentToken(ctx) {
|
|
1716
|
-
return ctx.tokens[ctx.pos] ?? eofToken();
|
|
1717
|
-
}
|
|
1718
|
-
function eofToken() {
|
|
1719
|
-
return {
|
|
1720
|
-
type: "EOF",
|
|
1721
|
-
value: "",
|
|
1722
|
-
position: { start: { line: 0, column: 0, offset: 0 }, end: { line: 0, column: 0, offset: 0 } },
|
|
1723
|
-
lineStart: false
|
|
1724
|
-
};
|
|
1725
|
-
}
|
|
1726
|
-
function hasClosingMarkerBeforeNewline(ctx, markerType, markerValue) {
|
|
1727
|
-
let pos = ctx.pos;
|
|
1728
|
-
while (pos < (ctx.scope.inlineEnd ?? ctx.tokens.length)) {
|
|
1729
|
-
const token5 = ctx.tokens[pos];
|
|
1730
|
-
if (!token5 || token5.type === "NEWLINE" || token5.type === "EOF") {
|
|
1731
|
-
return false;
|
|
1732
|
-
}
|
|
1733
|
-
if (token5.type === markerType) {
|
|
1734
|
-
if (markerValue === undefined || token5.value === markerValue) {
|
|
1735
|
-
return true;
|
|
1736
|
-
}
|
|
1737
|
-
}
|
|
1738
|
-
pos++;
|
|
1739
|
-
}
|
|
1740
|
-
return false;
|
|
1741
|
-
}
|
|
2862
|
+
var import_ast9 = require("@wdprlib/ast");
|
|
1742
2863
|
// packages/parser/src/parser/rules/block/heading/open.ts
|
|
1743
2864
|
function parseHeadingOpen(ctx) {
|
|
1744
2865
|
const marker = ctx.tokens[ctx.pos];
|
|
@@ -1984,10 +3105,11 @@ function parseNativeListLine(ctx, startPos) {
|
|
|
1984
3105
|
const ltype = markerToken.type === "LIST_BULLET" ? "bullet" : "numbered";
|
|
1985
3106
|
pos++;
|
|
1986
3107
|
consumed++;
|
|
1987
|
-
if (ctx.tokens[pos]?.type
|
|
1988
|
-
|
|
1989
|
-
consumed++;
|
|
3108
|
+
if (ctx.tokens[pos]?.type !== "WHITESPACE") {
|
|
3109
|
+
return { kind: "stop" };
|
|
1990
3110
|
}
|
|
3111
|
+
pos++;
|
|
3112
|
+
consumed++;
|
|
1991
3113
|
const inlineCtx = { ...ctx, pos };
|
|
1992
3114
|
const inlineResult = parseInlineUntil(inlineCtx, "NEWLINE");
|
|
1993
3115
|
consumed += inlineResult.consumed;
|
|
@@ -2097,9 +3219,9 @@ function appendBareParagraphElements(state, elements) {
|
|
|
2097
3219
|
function appendBareParagraphText(state, text) {
|
|
2098
3220
|
state.current.push({ element: "text", data: text });
|
|
2099
3221
|
}
|
|
2100
|
-
function appendBareParagraphLineBreakIfNeeded(state) {
|
|
3222
|
+
function appendBareParagraphLineBreakIfNeeded(state, token5) {
|
|
2101
3223
|
if (state.current.length > 0) {
|
|
2102
|
-
state.current.push(
|
|
3224
|
+
state.current.push(createAutomaticLineBreak(token5));
|
|
2103
3225
|
}
|
|
2104
3226
|
}
|
|
2105
3227
|
function flushBareParagraph(state) {
|
|
@@ -2204,7 +3326,7 @@ function parseBareListContent(ctx, startPos, listType) {
|
|
|
2204
3326
|
if (consecutiveNewlines >= 2) {
|
|
2205
3327
|
flushBareParagraph(paragraphState);
|
|
2206
3328
|
} else {
|
|
2207
|
-
appendBareParagraphLineBreakIfNeeded(paragraphState);
|
|
3329
|
+
appendBareParagraphLineBreakIfNeeded(paragraphState, token5);
|
|
2208
3330
|
}
|
|
2209
3331
|
continue;
|
|
2210
3332
|
}
|
|
@@ -2216,6 +3338,7 @@ function parseBareListContent(ctx, startPos, listType) {
|
|
|
2216
3338
|
for (const rule of getCandidateInlineRules(ctx.inlineRules, token5.type)) {
|
|
2217
3339
|
const result = rule.parse(inlineCtx);
|
|
2218
3340
|
if (result.success) {
|
|
3341
|
+
stripAutomaticLineBreak(paragraphState.current, result.stripLeadingLineBreak);
|
|
2219
3342
|
appendBareParagraphElements(paragraphState, result.elements);
|
|
2220
3343
|
consumed += result.consumed;
|
|
2221
3344
|
pos += result.consumed;
|
|
@@ -2254,7 +3377,7 @@ function parseListItemBlockContent(ctx, pos, token5) {
|
|
|
2254
3377
|
for (const rule of getCandidateBlockRules(filteredBlockRules, token5)) {
|
|
2255
3378
|
const result = rule.parse(blockCtx);
|
|
2256
3379
|
if (result.success) {
|
|
2257
|
-
return { matched: true,
|
|
3380
|
+
return { matched: true, ...result };
|
|
2258
3381
|
}
|
|
2259
3382
|
}
|
|
2260
3383
|
return { matched: false, elements: [], consumed: 0 };
|
|
@@ -2273,7 +3396,7 @@ function parseListItemInlineContent(ctx, pos, tokenType) {
|
|
|
2273
3396
|
for (const rule of getCandidateInlineRules(ctx.inlineRules, tokenType)) {
|
|
2274
3397
|
const result = rule.parse(inlineCtx);
|
|
2275
3398
|
if (result.success) {
|
|
2276
|
-
return { matched: true,
|
|
3399
|
+
return { matched: true, ...result };
|
|
2277
3400
|
}
|
|
2278
3401
|
}
|
|
2279
3402
|
return { matched: false, elements: [], consumed: 0 };
|
|
@@ -2315,7 +3438,9 @@ function collectPostLiTrailingContent(ctx, startPos, listType) {
|
|
|
2315
3438
|
}
|
|
2316
3439
|
const inlineResult = parseListItemInlineContent(ctx, pos, token5.type);
|
|
2317
3440
|
if (inlineResult.matched) {
|
|
2318
|
-
elements
|
|
3441
|
+
stripAutomaticLineBreak(elements, inlineResult.stripLeadingLineBreak);
|
|
3442
|
+
for (const element of inlineResult.elements)
|
|
3443
|
+
elements.push(element);
|
|
2319
3444
|
consumed += inlineResult.consumed;
|
|
2320
3445
|
pos += inlineResult.consumed;
|
|
2321
3446
|
continue;
|
|
@@ -2360,7 +3485,7 @@ function collectLiItemContent(ctx, startPos, listType, parseNestedList) {
|
|
|
2360
3485
|
if (token5.type === "NEWLINE") {
|
|
2361
3486
|
const newlineResult = consumeLiItemNewlines(ctx, pos, elements.length > 0);
|
|
2362
3487
|
if (newlineResult.addLineBreak) {
|
|
2363
|
-
elements.push(
|
|
3488
|
+
elements.push(createAutomaticLineBreak(token5));
|
|
2364
3489
|
}
|
|
2365
3490
|
pos += newlineResult.consumed;
|
|
2366
3491
|
consumed += newlineResult.consumed;
|
|
@@ -2368,14 +3493,17 @@ function collectLiItemContent(ctx, startPos, listType, parseNestedList) {
|
|
|
2368
3493
|
}
|
|
2369
3494
|
const blockResult = parseListItemBlockContent(ctx, pos, token5);
|
|
2370
3495
|
if (blockResult.matched) {
|
|
2371
|
-
|
|
3496
|
+
for (const element of blockResult.elements)
|
|
3497
|
+
elements.push(element);
|
|
2372
3498
|
consumed += blockResult.consumed;
|
|
2373
3499
|
pos += blockResult.consumed;
|
|
2374
3500
|
continue;
|
|
2375
3501
|
}
|
|
2376
3502
|
const inlineResult = parseListItemInlineContent(ctx, pos, token5.type);
|
|
2377
3503
|
if (inlineResult.matched) {
|
|
2378
|
-
elements
|
|
3504
|
+
stripAutomaticLineBreak(elements, inlineResult.stripLeadingLineBreak);
|
|
3505
|
+
for (const element of inlineResult.elements)
|
|
3506
|
+
elements.push(element);
|
|
2379
3507
|
consumed += inlineResult.consumed;
|
|
2380
3508
|
pos += inlineResult.consumed;
|
|
2381
3509
|
continue;
|
|
@@ -2446,7 +3574,8 @@ function parseLiItem(ctx, startPos, listType, parseNestedList) {
|
|
|
2446
3574
|
consumed += closeConsumed;
|
|
2447
3575
|
pos += closeConsumed;
|
|
2448
3576
|
const trailingResult = collectPostLiTrailingContent(ctx, pos, listType);
|
|
2449
|
-
|
|
3577
|
+
for (const element of trailingResult.elements)
|
|
3578
|
+
contentElements.push(element);
|
|
2450
3579
|
consumed += trailingResult.consumed;
|
|
2451
3580
|
}
|
|
2452
3581
|
return {
|
|
@@ -2706,7 +3835,7 @@ function sliceLineTokens(ctx, lines) {
|
|
|
2706
3835
|
for (const { start, end } of lines) {
|
|
2707
3836
|
for (let pos = start;pos < end; pos++) {
|
|
2708
3837
|
const token5 = ctx.tokens[pos];
|
|
2709
|
-
if (token5) {
|
|
3838
|
+
if (token5 && token5.type !== "BACKSLASH_BREAK") {
|
|
2710
3839
|
tokens.push(token5);
|
|
2711
3840
|
}
|
|
2712
3841
|
}
|
|
@@ -2876,7 +4005,8 @@ function parseDefinitionItemKey(ctx, startPos) {
|
|
|
2876
4005
|
const inlineCtx = { ...ctx, pos };
|
|
2877
4006
|
const result = parseInlineUntil(inlineCtx, "COLON");
|
|
2878
4007
|
if (result.elements.length > 0) {
|
|
2879
|
-
|
|
4008
|
+
for (const element of result.elements)
|
|
4009
|
+
key.push(element);
|
|
2880
4010
|
for (let i = 0;i < result.consumed; i++) {
|
|
2881
4011
|
const t = ctx.tokens[pos + i];
|
|
2882
4012
|
if (t)
|
|
@@ -2932,7 +4062,8 @@ function parseDefinitionItemValue(ctx, startPos) {
|
|
|
2932
4062
|
const inlineCtx = { ...ctx, pos };
|
|
2933
4063
|
const result = parseInlineUntil(inlineCtx, "NEWLINE");
|
|
2934
4064
|
if (result.elements.length > 0) {
|
|
2935
|
-
|
|
4065
|
+
for (const element of result.elements)
|
|
4066
|
+
value.push(element);
|
|
2936
4067
|
pos += result.consumed;
|
|
2937
4068
|
consumed += result.consumed;
|
|
2938
4069
|
} else {
|
|
@@ -3005,87 +4136,102 @@ var definitionListRule = {
|
|
|
3005
4136
|
if (result.items.length === 0) {
|
|
3006
4137
|
return { success: false };
|
|
3007
4138
|
}
|
|
3008
|
-
const items = toDefinitionListItems(result.items.filter((item) => item.value.length > 0));
|
|
3009
|
-
return {
|
|
3010
|
-
success: true,
|
|
3011
|
-
elements: items.length > 0 ? [{ element: "definition-list", data: items }] : [],
|
|
3012
|
-
consumed: result.consumed
|
|
3013
|
-
};
|
|
4139
|
+
const items = toDefinitionListItems(result.items.filter((item) => item.value.length > 0));
|
|
4140
|
+
return {
|
|
4141
|
+
success: true,
|
|
4142
|
+
elements: items.length > 0 ? [{ element: "definition-list", data: items }] : [],
|
|
4143
|
+
consumed: result.consumed
|
|
4144
|
+
};
|
|
4145
|
+
}
|
|
4146
|
+
};
|
|
4147
|
+
|
|
4148
|
+
// packages/parser/src/parser/postprocess/divAdjacentParagraph.ts
|
|
4149
|
+
var unparsedDivStarts = new WeakSet;
|
|
4150
|
+
function markUnparsedDivStart(elements) {
|
|
4151
|
+
const first = elements[0];
|
|
4152
|
+
const text = first?.element === "container" && first.data.type === "paragraph" ? first.data.elements[0] : first;
|
|
4153
|
+
if (text?.element === "text")
|
|
4154
|
+
unparsedDivStarts.add(text);
|
|
4155
|
+
}
|
|
4156
|
+
function isUnparsedDivParagraph(el) {
|
|
4157
|
+
if (!el || el.element !== "container")
|
|
4158
|
+
return false;
|
|
4159
|
+
return el.data.type === "paragraph" && el.data.elements.some((child) => unparsedDivStarts.has(child));
|
|
4160
|
+
}
|
|
4161
|
+
function isDivContainer(el) {
|
|
4162
|
+
if (!el || el.element !== "container")
|
|
4163
|
+
return false;
|
|
4164
|
+
return el.data.type === "div";
|
|
4165
|
+
}
|
|
4166
|
+
function suppressAtLevel(elements) {
|
|
4167
|
+
if (elements.length <= 1)
|
|
4168
|
+
return elements;
|
|
4169
|
+
const unwrap = Array.from({ length: elements.length }, () => false);
|
|
4170
|
+
for (let i = 0;i < elements.length; i++) {
|
|
4171
|
+
if (!isUnparsedDivParagraph(elements[i]))
|
|
4172
|
+
continue;
|
|
4173
|
+
const prevIsDiv = i > 0 && isDivContainer(elements[i - 1]);
|
|
4174
|
+
const nextIsDiv = i < elements.length - 1 && isDivContainer(elements[i + 1]);
|
|
4175
|
+
if (prevIsDiv || nextIsDiv) {
|
|
4176
|
+
unwrap[i] = true;
|
|
4177
|
+
}
|
|
3014
4178
|
}
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
// packages/parser/src/parser/rules/block/paragraph/content.ts
|
|
3018
|
-
function parseInlineContent(ctx) {
|
|
3019
|
-
return parseInlineUntil(ctx, "PARAGRAPH_BREAK");
|
|
3020
|
-
}
|
|
3021
|
-
|
|
3022
|
-
// packages/parser/src/parser/rules/block/paragraph/span-markers.ts
|
|
3023
|
-
function processCloseSpanMarkers(elements) {
|
|
3024
|
-
let result = null;
|
|
4179
|
+
const result = [];
|
|
3025
4180
|
for (let i = 0;i < elements.length; i++) {
|
|
3026
|
-
const
|
|
3027
|
-
if (!
|
|
4181
|
+
const el = elements[i];
|
|
4182
|
+
if (!el)
|
|
3028
4183
|
continue;
|
|
3029
|
-
if (
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
if (result.length > 0) {
|
|
3034
|
-
const spanContent = [...result];
|
|
3035
|
-
result.length = 0;
|
|
3036
|
-
result.push({
|
|
3037
|
-
element: "container",
|
|
3038
|
-
data: {
|
|
3039
|
-
type: "span",
|
|
3040
|
-
attributes: {},
|
|
3041
|
-
elements: spanContent
|
|
3042
|
-
}
|
|
3043
|
-
});
|
|
4184
|
+
if (unwrap[i] && el.element === "container") {
|
|
4185
|
+
const inner = el.data.elements;
|
|
4186
|
+
if (i > 0 && isDivContainer(elements[i - 1])) {
|
|
4187
|
+
result.push({ element: "line-break" });
|
|
3044
4188
|
}
|
|
4189
|
+
result.push(...inner);
|
|
3045
4190
|
} else {
|
|
3046
|
-
result
|
|
4191
|
+
result.push(el);
|
|
3047
4192
|
}
|
|
3048
4193
|
}
|
|
3049
|
-
return result
|
|
4194
|
+
return result;
|
|
3050
4195
|
}
|
|
3051
|
-
function
|
|
3052
|
-
return
|
|
4196
|
+
function suppressDivAdjacentParagraphs(elements) {
|
|
4197
|
+
return suppressAtLevel(elements);
|
|
3053
4198
|
}
|
|
3054
4199
|
|
|
3055
|
-
// packages/parser/src/parser/rules/block/
|
|
3056
|
-
function
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
return
|
|
4200
|
+
// packages/parser/src/parser/rules/block/div/close.ts
|
|
4201
|
+
function isDivClose(ctx) {
|
|
4202
|
+
const token5 = ctx.tokens[ctx.pos];
|
|
4203
|
+
if (token5?.type !== "BLOCK_END_OPEN")
|
|
4204
|
+
return false;
|
|
4205
|
+
const closeNameResult = parseBlockName(ctx, ctx.pos + 1);
|
|
4206
|
+
return closeNameResult?.name === "div";
|
|
3062
4207
|
}
|
|
3063
|
-
function
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
break;
|
|
3069
|
-
}
|
|
3070
|
-
elements.pop();
|
|
4208
|
+
function consumeDivClose(ctx, startPos) {
|
|
4209
|
+
let pos = startPos;
|
|
4210
|
+
let consumed = 0;
|
|
4211
|
+
if (ctx.tokens[pos]?.type !== "BLOCK_END_OPEN") {
|
|
4212
|
+
return { pos, consumed };
|
|
3071
4213
|
}
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
} else {
|
|
3079
|
-
break;
|
|
3080
|
-
}
|
|
4214
|
+
pos++;
|
|
4215
|
+
consumed++;
|
|
4216
|
+
const closeNameResult = parseBlockName(ctx, pos);
|
|
4217
|
+
if (closeNameResult) {
|
|
4218
|
+
pos += closeNameResult.consumed;
|
|
4219
|
+
consumed += closeNameResult.consumed;
|
|
3081
4220
|
}
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
while (first < elements.length && elements[first]?.element === "line-break") {
|
|
3086
|
-
first++;
|
|
4221
|
+
if (ctx.tokens[pos]?.type === "BLOCK_CLOSE") {
|
|
4222
|
+
pos++;
|
|
4223
|
+
consumed++;
|
|
3087
4224
|
}
|
|
3088
|
-
|
|
4225
|
+
if (ctx.tokens[pos]?.type === "NEWLINE") {
|
|
4226
|
+
pos++;
|
|
4227
|
+
consumed++;
|
|
4228
|
+
}
|
|
4229
|
+
return { pos, consumed };
|
|
4230
|
+
}
|
|
4231
|
+
|
|
4232
|
+
// packages/parser/src/parser/rules/block/paragraph/content.ts
|
|
4233
|
+
function parseInlineContent(ctx) {
|
|
4234
|
+
return parseInlineUntil(ctx, "PARAGRAPH_BREAK");
|
|
3089
4235
|
}
|
|
3090
4236
|
|
|
3091
4237
|
// packages/parser/src/parser/rules/block/paragraph/index.ts
|
|
@@ -3095,25 +4241,30 @@ var paragraphRule = {
|
|
|
3095
4241
|
requiresLineStart: false,
|
|
3096
4242
|
parse(ctx) {
|
|
3097
4243
|
const result = parseInlineContent(ctx);
|
|
3098
|
-
if (result.
|
|
4244
|
+
if (result.consumed === 0) {
|
|
3099
4245
|
return { success: false };
|
|
3100
4246
|
}
|
|
3101
4247
|
const elements = normalizeParagraphElements(result.elements);
|
|
3102
4248
|
if (elements.length === 0) {
|
|
3103
|
-
return { success:
|
|
4249
|
+
return { success: true, elements: [], consumed: result.consumed };
|
|
3104
4250
|
}
|
|
3105
4251
|
const nextPos = ctx.pos + result.consumed;
|
|
3106
4252
|
const nextToken = ctx.tokens[nextPos];
|
|
3107
4253
|
if (nextToken?.type === "COLON" && nextToken.lineStart) {
|
|
4254
|
+
if (isPreservedLeadingLineBreak(elements[0]))
|
|
4255
|
+
elements[0] = { element: "line-break" };
|
|
3108
4256
|
return {
|
|
3109
4257
|
success: true,
|
|
3110
4258
|
elements: [...elements, { element: "line-break" }],
|
|
3111
4259
|
consumed: result.consumed
|
|
3112
4260
|
};
|
|
3113
4261
|
}
|
|
4262
|
+
const wrapped = wrapParagraphElements(elements);
|
|
4263
|
+
if (isDivClose(ctx))
|
|
4264
|
+
markUnparsedDivStart(wrapped);
|
|
3114
4265
|
return {
|
|
3115
4266
|
success: true,
|
|
3116
|
-
elements:
|
|
4267
|
+
elements: wrapped,
|
|
3117
4268
|
consumed: result.consumed
|
|
3118
4269
|
};
|
|
3119
4270
|
}
|
|
@@ -3124,7 +4275,7 @@ function wrapParagraphElements(elements) {
|
|
|
3124
4275
|
let bare = false;
|
|
3125
4276
|
const flush = (trimBreaks = false) => {
|
|
3126
4277
|
const content = trimBreaks ? normalizeParagraphElements(group) : group;
|
|
3127
|
-
while (content[0]?.element === "line-break")
|
|
4278
|
+
while (content[0]?.element === "line-break" && !isPreservedLeadingLineBreak(content[0]))
|
|
3128
4279
|
content.shift();
|
|
3129
4280
|
while (content.length) {
|
|
3130
4281
|
const last = content.at(-1);
|
|
@@ -3136,6 +4287,8 @@ function wrapParagraphElements(elements) {
|
|
|
3136
4287
|
content.shift();
|
|
3137
4288
|
if (content[0]?.element === "text")
|
|
3138
4289
|
content[0] = { element: "text", data: content[0].data.trimStart() };
|
|
4290
|
+
if (isPreservedLeadingLineBreak(content[0]))
|
|
4291
|
+
content[0] = { element: "line-break" };
|
|
3139
4292
|
if (content.length)
|
|
3140
4293
|
output.push(...bare || content.some((el) => el.element === "image") ? content : [
|
|
3141
4294
|
{
|
|
@@ -3157,37 +4310,36 @@ function wrapParagraphElements(elements) {
|
|
|
3157
4310
|
return output;
|
|
3158
4311
|
}
|
|
3159
4312
|
|
|
3160
|
-
// packages/parser/src/parser/rules/block/
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
4313
|
+
// packages/parser/src/parser/rules/block/note/index.ts
|
|
4314
|
+
var excludedBlockNames = new Set(["note"]);
|
|
4315
|
+
var noteRule = {
|
|
4316
|
+
name: "note",
|
|
4317
|
+
startTokens: ["BLOCK_OPEN"],
|
|
4318
|
+
requiresLineStart: false,
|
|
4319
|
+
parse(ctx) {
|
|
4320
|
+
const bounds = findNoteBounds(ctx);
|
|
4321
|
+
if (!bounds)
|
|
4322
|
+
return { success: false };
|
|
4323
|
+
const body = parseBlocksUntil({
|
|
4324
|
+
...ctx,
|
|
4325
|
+
tokens: ctx.tokens.slice(bounds.bodyStart, bounds.close),
|
|
4326
|
+
pos: 0,
|
|
4327
|
+
scope: {
|
|
4328
|
+
...ctx.scope,
|
|
4329
|
+
inlineEnd: undefined,
|
|
4330
|
+
tableFormatting: undefined,
|
|
4331
|
+
blockCloseCondition: undefined
|
|
4332
|
+
}
|
|
4333
|
+
}, () => false, { excludedBlockNames });
|
|
4334
|
+
return {
|
|
4335
|
+
success: true,
|
|
4336
|
+
consumed: bounds.end - ctx.pos,
|
|
4337
|
+
elements: [
|
|
4338
|
+
{ element: "container", data: { type: "note", attributes: {}, elements: body.elements } }
|
|
4339
|
+
]
|
|
4340
|
+
};
|
|
3188
4341
|
}
|
|
3189
|
-
|
|
3190
|
-
}
|
|
4342
|
+
};
|
|
3191
4343
|
|
|
3192
4344
|
// packages/parser/src/parser/rules/block/div/nesting.ts
|
|
3193
4345
|
var divCloseCountCache = new WeakMap;
|
|
@@ -3356,6 +4508,7 @@ function consumeFailedDiv(ctx) {
|
|
|
3356
4508
|
pos++;
|
|
3357
4509
|
consumed++;
|
|
3358
4510
|
}
|
|
4511
|
+
markUnparsedDivStart(elements);
|
|
3359
4512
|
return {
|
|
3360
4513
|
success: true,
|
|
3361
4514
|
elements: [
|
|
@@ -3467,126 +4620,6 @@ var divRule = {
|
|
|
3467
4620
|
}
|
|
3468
4621
|
};
|
|
3469
4622
|
|
|
3470
|
-
// packages/parser/src/parser/rules/block/code/attributes.ts
|
|
3471
|
-
function repairSwallowedCodeClose(ctx, pos, attrs) {
|
|
3472
|
-
const prevToken = ctx.tokens[pos - 1];
|
|
3473
|
-
if (prevToken?.type !== "QUOTED_STRING" || !prevToken.value.includes("]]")) {
|
|
3474
|
-
return null;
|
|
3475
|
-
}
|
|
3476
|
-
const rawValue = prevToken.value;
|
|
3477
|
-
const bracketIdx = rawValue.indexOf("]]");
|
|
3478
|
-
const truncatedValue = rawValue.startsWith('"') ? rawValue.slice(1, bracketIdx) : rawValue.slice(0, bracketIdx);
|
|
3479
|
-
for (const key of Object.keys(attrs)) {
|
|
3480
|
-
const stored = attrs[key];
|
|
3481
|
-
if (stored === rawValue || stored === rawValue.slice(1, -1) || stored === rawValue.slice(1)) {
|
|
3482
|
-
attrs[key] = truncatedValue;
|
|
3483
|
-
break;
|
|
3484
|
-
}
|
|
3485
|
-
}
|
|
3486
|
-
return {
|
|
3487
|
-
closingSwallowed: rawValue.includes("[[/code]]")
|
|
3488
|
-
};
|
|
3489
|
-
}
|
|
3490
|
-
|
|
3491
|
-
// packages/parser/src/parser/rules/block/code/content.ts
|
|
3492
|
-
function collectCodeContent(ctx, startPos, closingSwallowed) {
|
|
3493
|
-
const contentParts = [];
|
|
3494
|
-
let pos = startPos;
|
|
3495
|
-
let consumed = 0;
|
|
3496
|
-
let foundClose = closingSwallowed;
|
|
3497
|
-
while (!closingSwallowed && pos < ctx.tokens.length) {
|
|
3498
|
-
const token5 = ctx.tokens[pos];
|
|
3499
|
-
if (!token5 || token5.type === "EOF") {
|
|
3500
|
-
break;
|
|
3501
|
-
}
|
|
3502
|
-
if (token5.type === "BLOCK_END_OPEN") {
|
|
3503
|
-
const closeNameResult = parseBlockName(ctx, pos + 1);
|
|
3504
|
-
if (closeNameResult?.name === "code") {
|
|
3505
|
-
foundClose = true;
|
|
3506
|
-
const closeConsumed = consumeCodeClose(ctx, pos, closeNameResult.consumed);
|
|
3507
|
-
consumed += closeConsumed;
|
|
3508
|
-
break;
|
|
3509
|
-
}
|
|
3510
|
-
}
|
|
3511
|
-
contentParts.push(token5.value);
|
|
3512
|
-
pos++;
|
|
3513
|
-
consumed++;
|
|
3514
|
-
}
|
|
3515
|
-
return { contents: contentParts.join(""), consumed, foundClose };
|
|
3516
|
-
}
|
|
3517
|
-
function consumeCodeClose(ctx, startPos, closeNameConsumed) {
|
|
3518
|
-
let pos = startPos + 1 + closeNameConsumed;
|
|
3519
|
-
let consumed = 1 + closeNameConsumed;
|
|
3520
|
-
if (ctx.tokens[pos]?.type === "BLOCK_CLOSE") {
|
|
3521
|
-
pos++;
|
|
3522
|
-
consumed++;
|
|
3523
|
-
}
|
|
3524
|
-
return consumed;
|
|
3525
|
-
}
|
|
3526
|
-
|
|
3527
|
-
// packages/parser/src/parser/rules/block/code/index.ts
|
|
3528
|
-
var codeBlockRule = {
|
|
3529
|
-
name: "code",
|
|
3530
|
-
startTokens: ["BLOCK_OPEN"],
|
|
3531
|
-
requiresLineStart: false,
|
|
3532
|
-
parse(ctx) {
|
|
3533
|
-
const openToken = currentToken(ctx);
|
|
3534
|
-
if (openToken.type !== "BLOCK_OPEN") {
|
|
3535
|
-
return { success: false };
|
|
3536
|
-
}
|
|
3537
|
-
let pos = ctx.pos + 1;
|
|
3538
|
-
let consumed = 1;
|
|
3539
|
-
const nameResult = parseBlockName(ctx, pos);
|
|
3540
|
-
if (!nameResult || nameResult.name !== "code") {
|
|
3541
|
-
return { success: false };
|
|
3542
|
-
}
|
|
3543
|
-
pos += nameResult.consumed;
|
|
3544
|
-
consumed += nameResult.consumed;
|
|
3545
|
-
const attrResult = parseAttributesRaw(ctx, pos);
|
|
3546
|
-
pos += attrResult.consumed;
|
|
3547
|
-
consumed += attrResult.consumed;
|
|
3548
|
-
let closingSwallowed = false;
|
|
3549
|
-
if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
|
|
3550
|
-
const repaired = repairSwallowedCodeClose(ctx, pos, attrResult.attrs);
|
|
3551
|
-
if (!repaired)
|
|
3552
|
-
return { success: false };
|
|
3553
|
-
closingSwallowed = repaired.closingSwallowed;
|
|
3554
|
-
} else {
|
|
3555
|
-
pos++;
|
|
3556
|
-
consumed++;
|
|
3557
|
-
}
|
|
3558
|
-
if (ctx.tokens[pos]?.type === "NEWLINE") {
|
|
3559
|
-
pos++;
|
|
3560
|
-
consumed++;
|
|
3561
|
-
}
|
|
3562
|
-
const contentResult = collectCodeContent(ctx, pos, closingSwallowed);
|
|
3563
|
-
let codeContent = contentResult.contents.replace(/\n$/, "");
|
|
3564
|
-
consumed += contentResult.consumed;
|
|
3565
|
-
pos += contentResult.consumed;
|
|
3566
|
-
if (!contentResult.foundClose) {
|
|
3567
|
-
ctx.diagnostics.push({
|
|
3568
|
-
severity: "warning",
|
|
3569
|
-
code: "unclosed-block",
|
|
3570
|
-
message: "Missing closing tag [[/code]] for [[code]]",
|
|
3571
|
-
position: openToken.position
|
|
3572
|
-
});
|
|
3573
|
-
}
|
|
3574
|
-
const codeBlockData = {
|
|
3575
|
-
contents: codeContent,
|
|
3576
|
-
language: attrResult.attrs.type ?? null,
|
|
3577
|
-
name: attrResult.attrs.name ?? null
|
|
3578
|
-
};
|
|
3579
|
-
ctx.codeBlocks.push(codeBlockData);
|
|
3580
|
-
const elements = [{ element: "code", data: codeBlockData }];
|
|
3581
|
-
if (ctx.tokens[pos]?.type === "NEWLINE" && !getParagraphNewlineBoundary(ctx, pos, false).shouldBreak && !ctx.scope.blockCloseCondition?.({ ...ctx, pos: pos + 1 })) {
|
|
3582
|
-
const after = parseInlineUntil({ ...ctx, pos: pos + 1 }, "PARAGRAPH_BREAK");
|
|
3583
|
-
elements.push({ element: "line-break" }, ...normalizeParagraphElements(after.elements));
|
|
3584
|
-
consumed += 1 + after.consumed;
|
|
3585
|
-
}
|
|
3586
|
-
return { success: true, elements, consumed };
|
|
3587
|
-
}
|
|
3588
|
-
};
|
|
3589
|
-
|
|
3590
4623
|
// packages/parser/src/parser/rules/block/collapsible/attributes.ts
|
|
3591
4624
|
function parseMultilineAttributes(ctx, startPos) {
|
|
3592
4625
|
const attrs = {};
|
|
@@ -4015,7 +5048,9 @@ function parseTableCell(ctx, startPos, cellStart) {
|
|
|
4015
5048
|
for (const rule of getCandidateInlineRules(inlineRules, token5.type)) {
|
|
4016
5049
|
const result = rule.parse(inlineCtx);
|
|
4017
5050
|
if (result.success) {
|
|
4018
|
-
children
|
|
5051
|
+
stripAutomaticLineBreak(children, result.stripLeadingLineBreak);
|
|
5052
|
+
for (const element of result.elements)
|
|
5053
|
+
children.push(element);
|
|
4019
5054
|
consumed += result.consumed;
|
|
4020
5055
|
pos += result.consumed;
|
|
4021
5056
|
matched = true;
|
|
@@ -4282,7 +5317,8 @@ function createCellContentAccumulator() {
|
|
|
4282
5317
|
addInline(element) {
|
|
4283
5318
|
currentSegment.push(element);
|
|
4284
5319
|
},
|
|
4285
|
-
addInlineElements(nextElements) {
|
|
5320
|
+
addInlineElements(nextElements, stripLeadingLineBreak) {
|
|
5321
|
+
stripAutomaticLineBreak(currentSegment, stripLeadingLineBreak);
|
|
4286
5322
|
currentSegment.push(...nextElements);
|
|
4287
5323
|
},
|
|
4288
5324
|
addBlockElements(blockElements) {
|
|
@@ -4382,7 +5418,7 @@ function consumeCellContentNewline(ctx, startPos, content) {
|
|
|
4382
5418
|
return { consumed };
|
|
4383
5419
|
}
|
|
4384
5420
|
if (!content.isEmpty()) {
|
|
4385
|
-
content.addInline(
|
|
5421
|
+
content.addInline(createAutomaticLineBreak(ctx.tokens[startPos]));
|
|
4386
5422
|
}
|
|
4387
5423
|
return { consumed };
|
|
4388
5424
|
}
|
|
@@ -4433,7 +5469,7 @@ function parseCellContent(ctx, closeCondition) {
|
|
|
4433
5469
|
for (const rule of getCandidateInlineRules(ctx.inlineRules, token5.type)) {
|
|
4434
5470
|
const result = rule.parse(inlineCtx);
|
|
4435
5471
|
if (result.success) {
|
|
4436
|
-
content.addInlineElements(result.elements);
|
|
5472
|
+
content.addInlineElements(result.elements, result.stripLeadingLineBreak);
|
|
4437
5473
|
consumed += result.consumed;
|
|
4438
5474
|
pos += result.consumed;
|
|
4439
5475
|
matched = true;
|
|
@@ -4735,8 +5771,18 @@ var rateModuleRule = {
|
|
|
4735
5771
|
name: "module-rate",
|
|
4736
5772
|
acceptsNames: ["rate"],
|
|
4737
5773
|
hasBody: false,
|
|
4738
|
-
parse() {
|
|
4739
|
-
return { module: "rate" };
|
|
5774
|
+
parse(_ctx, _pos, args) {
|
|
5775
|
+
return { module: "rate", ref: Object.keys(args).length === 0 ? { kind: "main" } : null };
|
|
5776
|
+
}
|
|
5777
|
+
};
|
|
5778
|
+
var customRateModuleRule = {
|
|
5779
|
+
name: "module-custom-rate",
|
|
5780
|
+
acceptsNames: ["customrate"],
|
|
5781
|
+
hasBody: false,
|
|
5782
|
+
parse(_ctx, _pos, args) {
|
|
5783
|
+
const key = args.key;
|
|
5784
|
+
const valid = key !== undefined && key !== "" && Object.keys(args).every((name) => name === "key");
|
|
5785
|
+
return { module: "custom-rate", ref: valid ? { kind: "custom", axisKey: key } : null };
|
|
4740
5786
|
}
|
|
4741
5787
|
};
|
|
4742
5788
|
|
|
@@ -4871,6 +5917,7 @@ var listPagesModuleRule = {
|
|
|
4871
5917
|
"created-at": createdAt,
|
|
4872
5918
|
"updated-at": updatedAt,
|
|
4873
5919
|
rating,
|
|
5920
|
+
"rating-axis": args["rating-axis"],
|
|
4874
5921
|
votes,
|
|
4875
5922
|
name,
|
|
4876
5923
|
fullname,
|
|
@@ -5014,6 +6061,7 @@ var tagCloudModuleRule = {
|
|
|
5014
6061
|
// packages/parser/src/parser/rules/block/module/mapping.ts
|
|
5015
6062
|
var MODULE_RULES = [
|
|
5016
6063
|
rateModuleRule,
|
|
6064
|
+
customRateModuleRule,
|
|
5017
6065
|
cssModuleRule,
|
|
5018
6066
|
backlinksModuleRule,
|
|
5019
6067
|
categoriesModuleRule,
|
|
@@ -5584,22 +6632,6 @@ function getDayOfYear(date) {
|
|
|
5584
6632
|
function splitContentSections(content) {
|
|
5585
6633
|
return content.split(/^={4,}$/m).map((section) => section.trim());
|
|
5586
6634
|
}
|
|
5587
|
-
function getSummary(page) {
|
|
5588
|
-
if (page.content) {
|
|
5589
|
-
const sections = splitContentSections(page.content);
|
|
5590
|
-
if (sections.length > 1) {
|
|
5591
|
-
return sections[0]?.trim() ?? "";
|
|
5592
|
-
}
|
|
5593
|
-
}
|
|
5594
|
-
return getFirstParagraph(page.content);
|
|
5595
|
-
}
|
|
5596
|
-
function getFirstParagraph(content) {
|
|
5597
|
-
if (!content)
|
|
5598
|
-
return "";
|
|
5599
|
-
const stripped = content.replace(/^(\+{1,6}) (.*)/gm, "").replace(/^\[\[toc(\s[^\]]+)?\]\]/gim, "").replace(/^\[\[\/?div(\s[^\]]+)?\]\]/gim, "").replace(/^\[\[\/?module(\s[^\]]+)?\]\]/gim, "").trim();
|
|
5600
|
-
const paragraphs = stripped.split(/\n{2,}/);
|
|
5601
|
-
return paragraphs[0]?.trim() ?? "";
|
|
5602
|
-
}
|
|
5603
6635
|
// packages/parser/src/parser/rules/block/module/listpages/template/format/tags.ts
|
|
5604
6636
|
function formatTagsLinked(tags, prefix) {
|
|
5605
6637
|
if (tags.length === 0)
|
|
@@ -5612,6 +6644,16 @@ function formatUserLinked(user) {
|
|
|
5612
6644
|
return "Anonymous";
|
|
5613
6645
|
return `[[*user ${user.name}]]`;
|
|
5614
6646
|
}
|
|
6647
|
+
// packages/parser/src/parser/rules/block/module/listpages/template/getters/parameterized.ts
|
|
6648
|
+
var import_ast2 = require("@wdprlib/ast");
|
|
6649
|
+
|
|
6650
|
+
// packages/parser/src/parser/rules/block/module/listpages/template/literal.ts
|
|
6651
|
+
function literalWikitext(value) {
|
|
6652
|
+
if (value === "")
|
|
6653
|
+
return "";
|
|
6654
|
+
return `@<${Array.from(value, (char) => `&#${char.codePointAt(0)};`).join("")}>@`;
|
|
6655
|
+
}
|
|
6656
|
+
|
|
5615
6657
|
// packages/parser/src/parser/rules/block/module/listpages/template/getters/parameterized.ts
|
|
5616
6658
|
function createBraceParamGetter(name, param) {
|
|
5617
6659
|
switch (name) {
|
|
@@ -5640,7 +6682,7 @@ function createParenParamGetter(name, param) {
|
|
|
5640
6682
|
if (name !== "preview")
|
|
5641
6683
|
return null;
|
|
5642
6684
|
const len = Number(param);
|
|
5643
|
-
return (ctx) => (ctx.page.
|
|
6685
|
+
return (ctx) => literalWikitext(import_ast2.excerptText(ctx.page.readableText ?? "", { maxLength: len }));
|
|
5644
6686
|
}
|
|
5645
6687
|
function createFormattedGetter(name, format) {
|
|
5646
6688
|
switch (name) {
|
|
@@ -5667,6 +6709,7 @@ function createTagsLinkedGetter(name, format) {
|
|
|
5667
6709
|
}
|
|
5668
6710
|
|
|
5669
6711
|
// packages/parser/src/parser/rules/block/module/listpages/template/getters/simple.ts
|
|
6712
|
+
var import_ast3 = require("@wdprlib/ast");
|
|
5670
6713
|
var DEFAULT_PREVIEW_LENGTH = 200;
|
|
5671
6714
|
var SIMPLE_GETTERS = {
|
|
5672
6715
|
created_at: (ctx) => formatDate(ctx.page.createdAt),
|
|
@@ -5696,14 +6739,14 @@ var SIMPLE_GETTERS = {
|
|
|
5696
6739
|
parent_title: (ctx) => ctx.page.parentTitle ?? "",
|
|
5697
6740
|
parent_title_linked: (ctx) => ctx.page.parentFullname ? `[[[${ctx.page.parentFullname} | ${ctx.page.parentTitle}]]]` : "",
|
|
5698
6741
|
content: (ctx) => ctx.page.content ?? "",
|
|
5699
|
-
preview: (ctx) => (ctx.page.
|
|
5700
|
-
summary: (ctx) =>
|
|
5701
|
-
first_paragraph: (ctx) =>
|
|
6742
|
+
preview: (ctx) => literalWikitext(import_ast3.excerptText(ctx.page.readableText ?? "", { maxLength: DEFAULT_PREVIEW_LENGTH })),
|
|
6743
|
+
summary: (ctx) => literalWikitext(ctx.page.firstParagraph ?? ""),
|
|
6744
|
+
first_paragraph: (ctx) => literalWikitext(ctx.page.firstParagraph ?? ""),
|
|
5702
6745
|
tags: (ctx) => ctx.page.tags.join(" "),
|
|
5703
6746
|
_tags: (ctx) => ctx.page.hiddenTags.join(" "),
|
|
5704
6747
|
children: (ctx) => String(ctx.page.children),
|
|
5705
6748
|
comments: (ctx) => String(ctx.page.comments),
|
|
5706
|
-
size: (ctx) => String(ctx.page.size),
|
|
6749
|
+
size: (ctx) => ctx.page.readableText !== undefined ? String(import_ast3.countCharacters(ctx.page.readableText)) : ctx.page.size !== undefined ? String(ctx.page.size) : "",
|
|
5707
6750
|
rating: (ctx) => String(ctx.page.rating),
|
|
5708
6751
|
rating_votes: (ctx) => String(ctx.page.ratingVotes),
|
|
5709
6752
|
rating_percent: (ctx) => String(ctx.page.ratingPercent ?? 0),
|
|
@@ -5717,11 +6760,136 @@ var SIMPLE_GETTERS = {
|
|
|
5717
6760
|
site_domain: (ctx) => ctx.site.domain
|
|
5718
6761
|
};
|
|
5719
6762
|
|
|
6763
|
+
// packages/parser/src/parser/rules/block/module/listpages/template/getters/registered.ts
|
|
6764
|
+
function createRegisteredGetter(name, key, format) {
|
|
6765
|
+
if (name === "metadata")
|
|
6766
|
+
return (ctx) => {
|
|
6767
|
+
const metadata = ctx.page.metadata;
|
|
6768
|
+
const entry = metadata && Object.hasOwn(metadata, key) ? metadata[key] : null;
|
|
6769
|
+
if (!entry)
|
|
6770
|
+
return "";
|
|
6771
|
+
let value;
|
|
6772
|
+
switch (entry.type) {
|
|
6773
|
+
case "text":
|
|
6774
|
+
value = entry.value;
|
|
6775
|
+
break;
|
|
6776
|
+
case "number":
|
|
6777
|
+
value = String(entry.value);
|
|
6778
|
+
break;
|
|
6779
|
+
case "date":
|
|
6780
|
+
value = formatDate(entry.value, format);
|
|
6781
|
+
break;
|
|
6782
|
+
case "user":
|
|
6783
|
+
value = format === "id" ? String(entry.value.id) : format === "unix" ? entry.value.unixName : entry.value.name;
|
|
6784
|
+
break;
|
|
6785
|
+
}
|
|
6786
|
+
return literalWikitext(value);
|
|
6787
|
+
};
|
|
6788
|
+
if (name === "customrate" || name === "customrate_votes" || name === "customrate_percent")
|
|
6789
|
+
return (ctx) => {
|
|
6790
|
+
const ratings = ctx.page.customRates;
|
|
6791
|
+
const entry = ratings && Object.hasOwn(ratings, key) ? ratings[key] : null;
|
|
6792
|
+
if (!entry)
|
|
6793
|
+
return "";
|
|
6794
|
+
return String(name === "customrate" ? entry.points : name === "customrate_votes" ? entry.votes : entry.percent);
|
|
6795
|
+
};
|
|
6796
|
+
return null;
|
|
6797
|
+
}
|
|
6798
|
+
|
|
6799
|
+
// packages/parser/src/parser/rules/block/module/listpages/template/getters/index.ts
|
|
6800
|
+
var import_ast4 = require("@wdprlib/ast");
|
|
6801
|
+
|
|
6802
|
+
// packages/parser/src/parser/rules/block/module/listpages/template/excerpt.ts
|
|
6803
|
+
function findExcerptEnd(template, contentStart) {
|
|
6804
|
+
let quote;
|
|
6805
|
+
for (let cursor = contentStart + "excerpt{".length;cursor < template.length; cursor++) {
|
|
6806
|
+
const char = template[cursor];
|
|
6807
|
+
if (quote) {
|
|
6808
|
+
if (char === "\\")
|
|
6809
|
+
cursor++;
|
|
6810
|
+
else if (char === quote)
|
|
6811
|
+
quote = undefined;
|
|
6812
|
+
} else if (char === '"' || char === "'") {
|
|
6813
|
+
quote = char;
|
|
6814
|
+
} else if (char === "}") {
|
|
6815
|
+
return template.startsWith("%%", cursor + 1) ? cursor + 1 : -1;
|
|
6816
|
+
}
|
|
6817
|
+
}
|
|
6818
|
+
return -1;
|
|
6819
|
+
}
|
|
6820
|
+
function parseExcerptOptions(input) {
|
|
6821
|
+
if (input.length > 8192)
|
|
6822
|
+
return null;
|
|
6823
|
+
const attributes = new Map;
|
|
6824
|
+
let cursor = 0;
|
|
6825
|
+
while (cursor < input.length) {
|
|
6826
|
+
while (cursor < input.length && /\s/.test(input[cursor]))
|
|
6827
|
+
cursor++;
|
|
6828
|
+
if (cursor === input.length)
|
|
6829
|
+
break;
|
|
6830
|
+
const start = cursor;
|
|
6831
|
+
while (cursor < input.length && /[a-z]/.test(input[cursor]))
|
|
6832
|
+
cursor++;
|
|
6833
|
+
const name = input.slice(start, cursor);
|
|
6834
|
+
if (!["pattern", "flags", "group", "match", "max"].includes(name) || attributes.has(name))
|
|
6835
|
+
return null;
|
|
6836
|
+
while (cursor < input.length && /\s/.test(input[cursor]))
|
|
6837
|
+
cursor++;
|
|
6838
|
+
if (input[cursor++] !== "=")
|
|
6839
|
+
return null;
|
|
6840
|
+
while (cursor < input.length && /\s/.test(input[cursor]))
|
|
6841
|
+
cursor++;
|
|
6842
|
+
const quote = input[cursor++];
|
|
6843
|
+
if (quote !== '"' && quote !== "'")
|
|
6844
|
+
return null;
|
|
6845
|
+
let value = "";
|
|
6846
|
+
while (cursor < input.length && input[cursor] !== quote) {
|
|
6847
|
+
if (input[cursor] === "\\" && (input[cursor + 1] === quote || input[cursor + 1] === "\\")) {
|
|
6848
|
+
value += input[cursor + 1] === quote ? quote : "\\\\";
|
|
6849
|
+
cursor += 2;
|
|
6850
|
+
} else
|
|
6851
|
+
value += input[cursor++];
|
|
6852
|
+
}
|
|
6853
|
+
if (input[cursor++] !== quote)
|
|
6854
|
+
return null;
|
|
6855
|
+
if (cursor < input.length && !/\s/.test(input[cursor]))
|
|
6856
|
+
return null;
|
|
6857
|
+
attributes.set(name, value);
|
|
6858
|
+
}
|
|
6859
|
+
const pattern = attributes.get("pattern");
|
|
6860
|
+
if (pattern === undefined)
|
|
6861
|
+
return null;
|
|
6862
|
+
const group = attributes.get("group");
|
|
6863
|
+
const match = attributes.get("match");
|
|
6864
|
+
const max = attributes.get("max");
|
|
6865
|
+
if (match !== undefined && !/^\d+$/.test(match) || max !== undefined && !/^\d+$/.test(max))
|
|
6866
|
+
return null;
|
|
6867
|
+
return {
|
|
6868
|
+
pattern,
|
|
6869
|
+
flags: attributes.get("flags"),
|
|
6870
|
+
group: group === undefined ? undefined : /^\d+$/.test(group) ? Number(group) : group,
|
|
6871
|
+
match: match === undefined ? undefined : Number(match),
|
|
6872
|
+
maxLength: max === undefined ? undefined : Number(max)
|
|
6873
|
+
};
|
|
6874
|
+
}
|
|
6875
|
+
|
|
5720
6876
|
// packages/parser/src/parser/rules/block/module/listpages/template/getters/index.ts
|
|
5721
6877
|
function createVariableGetter(name, braceParam, parenParam, format) {
|
|
6878
|
+
if (name === "excerpt") {
|
|
6879
|
+
const options = braceParam === undefined ? null : parseExcerptOptions(braceParam);
|
|
6880
|
+
if (!options || parenParam !== undefined || format !== undefined)
|
|
6881
|
+
return () => "";
|
|
6882
|
+
const extract = import_ast4.compileTextExcerpt(options);
|
|
6883
|
+
return (ctx) => literalWikitext(extract(ctx.page.readableText ?? ""));
|
|
6884
|
+
}
|
|
6885
|
+
const registeredGetter = braceParam !== undefined ? createRegisteredGetter(name, braceParam, format) : null;
|
|
6886
|
+
if (registeredGetter)
|
|
6887
|
+
return registeredGetter;
|
|
5722
6888
|
const braceGetter = braceParam !== undefined ? createBraceParamGetter(name, braceParam) : null;
|
|
5723
6889
|
if (braceGetter)
|
|
5724
6890
|
return braceGetter;
|
|
6891
|
+
if (braceParam !== undefined)
|
|
6892
|
+
return () => "";
|
|
5725
6893
|
const parenGetter = parenParam !== undefined ? createParenParamGetter(name, parenParam) : null;
|
|
5726
6894
|
if (parenGetter)
|
|
5727
6895
|
return parenGetter;
|
|
@@ -5743,7 +6911,7 @@ function scanTemplateVariables(template) {
|
|
|
5743
6911
|
if (start === -1)
|
|
5744
6912
|
break;
|
|
5745
6913
|
const contentStart = start + 2;
|
|
5746
|
-
const end = template.indexOf("%%", contentStart);
|
|
6914
|
+
const end = template.slice(contentStart, contentStart + 8).toLowerCase() === "excerpt{" ? findExcerptEnd(template, contentStart) : template.indexOf("%%", contentStart);
|
|
5747
6915
|
if (end === -1)
|
|
5748
6916
|
break;
|
|
5749
6917
|
const parsed = parseTemplateVariableContent(template.slice(contentStart, end));
|
|
@@ -5766,6 +6934,11 @@ function parseTemplateVariableContent(content) {
|
|
|
5766
6934
|
if (cursor === 0)
|
|
5767
6935
|
return null;
|
|
5768
6936
|
const name = content.slice(0, cursor);
|
|
6937
|
+
if (name.toLowerCase() === "excerpt" && content[cursor] === "{") {
|
|
6938
|
+
if (!content.endsWith("}"))
|
|
6939
|
+
return null;
|
|
6940
|
+
return { name, braceParam: content.slice(cursor + 1, -1) };
|
|
6941
|
+
}
|
|
5769
6942
|
let braceParam;
|
|
5770
6943
|
let parenParam;
|
|
5771
6944
|
let format;
|
|
@@ -5845,6 +7018,7 @@ function buildQuery(module2) {
|
|
|
5845
7018
|
updatedAt: module2["updated-at"],
|
|
5846
7019
|
createdBy: module2["created-by"],
|
|
5847
7020
|
rating: module2.rating,
|
|
7021
|
+
ratingAxis: module2["rating-axis"],
|
|
5848
7022
|
votes: module2.votes,
|
|
5849
7023
|
name: module2.name,
|
|
5850
7024
|
fullname: module2.fullname,
|
|
@@ -5899,6 +7073,7 @@ var KNOWN_VARIABLES = new Set([
|
|
|
5899
7073
|
"parent_title_linked",
|
|
5900
7074
|
"content",
|
|
5901
7075
|
"preview",
|
|
7076
|
+
"excerpt",
|
|
5902
7077
|
"summary",
|
|
5903
7078
|
"first_paragraph",
|
|
5904
7079
|
"tags",
|
|
@@ -5936,12 +7111,24 @@ function extractVariablesFromTemplate(template) {
|
|
|
5936
7111
|
const contentIndices = new Set;
|
|
5937
7112
|
const previewLengths = new Set;
|
|
5938
7113
|
const formFields = new Set;
|
|
7114
|
+
const metadataKeys = new Set;
|
|
7115
|
+
const customRateKeys = new Set;
|
|
5939
7116
|
let tagsLinkPrefix;
|
|
5940
7117
|
let hiddenTagsLinkPrefix;
|
|
5941
7118
|
for (const match of scanTemplateVariables(template)) {
|
|
5942
7119
|
const varName = match.name.toLowerCase();
|
|
5943
7120
|
if (match.braceParam !== undefined) {
|
|
5944
7121
|
switch (varName) {
|
|
7122
|
+
case "metadata":
|
|
7123
|
+
metadataKeys.add(match.braceParam);
|
|
7124
|
+
variables.add("metadata");
|
|
7125
|
+
continue;
|
|
7126
|
+
case "customrate":
|
|
7127
|
+
case "customrate_votes":
|
|
7128
|
+
case "customrate_percent":
|
|
7129
|
+
customRateKeys.add(match.braceParam);
|
|
7130
|
+
variables.add(varName);
|
|
7131
|
+
continue;
|
|
5945
7132
|
case "content":
|
|
5946
7133
|
contentIndices.add(Number(match.braceParam));
|
|
5947
7134
|
variables.add("content_n");
|
|
@@ -5991,6 +7178,8 @@ function extractVariablesFromTemplate(template) {
|
|
|
5991
7178
|
contentIndices: Array.from(contentIndices).sort((a, b) => a - b),
|
|
5992
7179
|
previewLengths: Array.from(previewLengths).sort((a, b) => a - b),
|
|
5993
7180
|
formFields: Array.from(formFields).sort(),
|
|
7181
|
+
metadataKeys: [...metadataKeys].sort(),
|
|
7182
|
+
customRateKeys: [...customRateKeys].sort(),
|
|
5994
7183
|
tagsLinkPrefix,
|
|
5995
7184
|
hiddenTagsLinkPrefix
|
|
5996
7185
|
};
|
|
@@ -6012,6 +7201,9 @@ function extractListPagesModule(listPages, state, result) {
|
|
|
6012
7201
|
contentSectionIndices: extraction.contentIndices,
|
|
6013
7202
|
previewLengths: extraction.previewLengths,
|
|
6014
7203
|
formFields: extraction.formFields,
|
|
7204
|
+
metadataKeys: extraction.metadataKeys,
|
|
7205
|
+
customRateKeys: extraction.customRateKeys,
|
|
7206
|
+
needsReadableText: extraction.variables.some((name) => ["preview", "preview_n", "summary", "first_paragraph", "excerpt"].includes(name)),
|
|
6015
7207
|
tagsLinkPrefix: extraction.tagsLinkPrefix,
|
|
6016
7208
|
hiddenTagsLinkPrefix: extraction.hiddenTagsLinkPrefix,
|
|
6017
7209
|
urlAttrPrefix: listPages["url-attr-prefix"],
|
|
@@ -6344,13 +7536,101 @@ function wrapListPagesResult(module2, items, parse, data) {
|
|
|
6344
7536
|
return result;
|
|
6345
7537
|
}
|
|
6346
7538
|
|
|
7539
|
+
// packages/parser/src/parser/rules/block/module/rate/resolve.ts
|
|
7540
|
+
function refKey(ref) {
|
|
7541
|
+
return ref.kind === "main" ? "main" : `custom:${ref.axisKey}`;
|
|
7542
|
+
}
|
|
7543
|
+
async function resolveRatings(ast, fetchRatings) {
|
|
7544
|
+
const refs = new Map;
|
|
7545
|
+
mapDocument(ast, (element) => {
|
|
7546
|
+
if (isRating(element) && element.data.ref)
|
|
7547
|
+
refs.set(refKey(element.data.ref), element.data.ref);
|
|
7548
|
+
return element;
|
|
7549
|
+
});
|
|
7550
|
+
const states = new Map;
|
|
7551
|
+
if (fetchRatings && refs.size > 0) {
|
|
7552
|
+
for (const state of await fetchRatings([...refs.values()])) {
|
|
7553
|
+
const key = refKey(state.ref);
|
|
7554
|
+
if (refs.has(key))
|
|
7555
|
+
states.set(key, state);
|
|
7556
|
+
}
|
|
7557
|
+
}
|
|
7558
|
+
return mapDocument(ast, (element) => {
|
|
7559
|
+
if (!isRating(element))
|
|
7560
|
+
return element;
|
|
7561
|
+
const { state: _previous, ...data } = element.data;
|
|
7562
|
+
const state = data.ref ? states.get(refKey(data.ref)) : undefined;
|
|
7563
|
+
return { ...element, data: state ? { ...data, state } : data };
|
|
7564
|
+
});
|
|
7565
|
+
}
|
|
7566
|
+
function suppressModuleRatings(result) {
|
|
7567
|
+
const ast = mapDocument(getModuleParseAst(result), (element) => isRating(element) ? null : element);
|
|
7568
|
+
return "ast" in result ? { ...result, ast } : ast;
|
|
7569
|
+
}
|
|
7570
|
+
function isRating(element) {
|
|
7571
|
+
return element.element === "module" && (element.data.module === "rate" || element.data.module === "custom-rate");
|
|
7572
|
+
}
|
|
7573
|
+
function mapDocument(ast, transform) {
|
|
7574
|
+
const map = (elements) => elements.flatMap((original) => {
|
|
7575
|
+
const element = transform(original);
|
|
7576
|
+
if (!element)
|
|
7577
|
+
return [];
|
|
7578
|
+
if (element.element === "if") {
|
|
7579
|
+
return [
|
|
7580
|
+
{
|
|
7581
|
+
...element,
|
|
7582
|
+
data: {
|
|
7583
|
+
...element.data,
|
|
7584
|
+
then: map(element.data.then),
|
|
7585
|
+
else: map(element.data.else)
|
|
7586
|
+
}
|
|
7587
|
+
}
|
|
7588
|
+
];
|
|
7589
|
+
}
|
|
7590
|
+
if (element.element === "ifexpr") {
|
|
7591
|
+
return [
|
|
7592
|
+
{
|
|
7593
|
+
...element,
|
|
7594
|
+
data: {
|
|
7595
|
+
...element.data,
|
|
7596
|
+
then: map(element.data.then),
|
|
7597
|
+
else: map(element.data.else)
|
|
7598
|
+
}
|
|
7599
|
+
}
|
|
7600
|
+
];
|
|
7601
|
+
}
|
|
7602
|
+
if (element.element === "bibliography-block") {
|
|
7603
|
+
return [
|
|
7604
|
+
{
|
|
7605
|
+
...element,
|
|
7606
|
+
data: {
|
|
7607
|
+
...element.data,
|
|
7608
|
+
entries: element.data.entries.map((entry) => ({
|
|
7609
|
+
...entry,
|
|
7610
|
+
key: map(entry.key),
|
|
7611
|
+
value: map(entry.value)
|
|
7612
|
+
}))
|
|
7613
|
+
}
|
|
7614
|
+
}
|
|
7615
|
+
];
|
|
7616
|
+
}
|
|
7617
|
+
return [mapElementChildren(element, map)];
|
|
7618
|
+
});
|
|
7619
|
+
return {
|
|
7620
|
+
...ast,
|
|
7621
|
+
elements: map(ast.elements),
|
|
7622
|
+
...ast.footnotes ? { footnotes: ast.footnotes.map(map) } : {}
|
|
7623
|
+
};
|
|
7624
|
+
}
|
|
7625
|
+
|
|
6347
7626
|
// packages/parser/src/parser/rules/block/module/listpages/resolve.ts
|
|
6348
7627
|
function isListPagesModule2(module2) {
|
|
6349
7628
|
return module2.module === "list-pages";
|
|
6350
7629
|
}
|
|
6351
7630
|
function resolveListPages(module2, data, compiledTemplate, parse) {
|
|
6352
|
-
const
|
|
6353
|
-
|
|
7631
|
+
const parseFragment = (source) => suppressModuleRatings(parse(source));
|
|
7632
|
+
const items = renderListPagesItems(module2, data, compiledTemplate, parseFragment);
|
|
7633
|
+
return wrapListPagesResult(module2, items, parseFragment, data);
|
|
6354
7634
|
}
|
|
6355
7635
|
// packages/parser/src/parser/rules/block/module/listpages/types/external-data.ts
|
|
6356
7636
|
function definePageData(input) {
|
|
@@ -6364,7 +7644,6 @@ function definePageData(input) {
|
|
|
6364
7644
|
hiddenTags: input.hiddenTags ?? [],
|
|
6365
7645
|
children: input.children ?? 0,
|
|
6366
7646
|
comments: input.comments ?? 0,
|
|
6367
|
-
size: input.size ?? 0,
|
|
6368
7647
|
rating: input.rating ?? 0,
|
|
6369
7648
|
ratingVotes: input.ratingVotes ?? 0,
|
|
6370
7649
|
revisions: input.revisions ?? 0
|
|
@@ -6442,6 +7721,7 @@ var URL_RESOLVABLE_FIELDS = [
|
|
|
6442
7721
|
aliases: ["createdby", "created_by"]
|
|
6443
7722
|
},
|
|
6444
7723
|
{ attr: "rating", queryKey: "rating", type: "string" },
|
|
7724
|
+
{ attr: "rating-axis", queryKey: "ratingAxis", type: "string" },
|
|
6445
7725
|
{ attr: "votes", queryKey: "votes", type: "string" },
|
|
6446
7726
|
{ attr: "reverse", queryKey: "reverse", type: "boolean" }
|
|
6447
7727
|
];
|
|
@@ -6543,6 +7823,7 @@ var ORDER_FIELD_MAP = {
|
|
|
6543
7823
|
votes: "votes",
|
|
6544
7824
|
revisions: "revisions",
|
|
6545
7825
|
comments: "comments",
|
|
7826
|
+
commented_at: "commented_at",
|
|
6546
7827
|
pagelength: "size",
|
|
6547
7828
|
size: "size",
|
|
6548
7829
|
random: "random",
|
|
@@ -6550,6 +7831,13 @@ var ORDER_FIELD_MAP = {
|
|
|
6550
7831
|
updated_at: "updated_at"
|
|
6551
7832
|
};
|
|
6552
7833
|
function parseOrder(value) {
|
|
7834
|
+
const metadata = /^metadata\{([^}]*)\}(?:\s+(asc|desc))?$/i.exec(value.trim());
|
|
7835
|
+
if (metadata)
|
|
7836
|
+
return {
|
|
7837
|
+
field: "metadata",
|
|
7838
|
+
key: metadata[1],
|
|
7839
|
+
direction: metadata[2]?.toLowerCase() === "asc" ? "asc" : "desc"
|
|
7840
|
+
};
|
|
6553
7841
|
const defaultOrder = { field: "created_at", direction: "desc" };
|
|
6554
7842
|
const trimmed = value.trim().toLowerCase();
|
|
6555
7843
|
if (!trimmed)
|
|
@@ -6669,6 +7957,8 @@ function normalizeQuery(query) {
|
|
|
6669
7957
|
result.linkTo = query.linkTo;
|
|
6670
7958
|
if (query.createdBy)
|
|
6671
7959
|
result.createdBy = query.createdBy;
|
|
7960
|
+
if (query.ratingAxis !== undefined)
|
|
7961
|
+
result.ratingAxis = query.ratingAxis;
|
|
6672
7962
|
if (query.name)
|
|
6673
7963
|
result.name = query.name;
|
|
6674
7964
|
if (query.fullname)
|
|
@@ -6853,7 +8143,7 @@ function resolveIfTags(data, pageTags) {
|
|
|
6853
8143
|
// packages/parser/src/parser/preprocess/utils/raw-regions.ts
|
|
6854
8144
|
var BASE_PLACEHOLDER_OPEN = "";
|
|
6855
8145
|
var BASE_PLACEHOLDER_CLOSE = "";
|
|
6856
|
-
var RAW_BLOCK_OPEN_PATTERN = /\[\[
|
|
8146
|
+
var RAW_BLOCK_OPEN_PATTERN = /\[\[html\b[^\]]*\]\]/iy;
|
|
6857
8147
|
function makeUniqueSentinels(source) {
|
|
6858
8148
|
let openRun = 0;
|
|
6859
8149
|
let closeRun = 0;
|
|
@@ -6872,10 +8162,21 @@ function makeUniqueSentinels(source) {
|
|
|
6872
8162
|
}
|
|
6873
8163
|
function maskRawRegions(source, sentinels) {
|
|
6874
8164
|
const placeholders = [];
|
|
8165
|
+
let tokens;
|
|
8166
|
+
const getTokens = () => tokens ??= tokenize(source);
|
|
6875
8167
|
let masked = "";
|
|
6876
8168
|
let i = 0;
|
|
6877
8169
|
while (i < source.length) {
|
|
6878
|
-
|
|
8170
|
+
if (source.startsWith("[!--", i)) {
|
|
8171
|
+
const close = source.indexOf("--]", i + 4);
|
|
8172
|
+
if (close !== -1) {
|
|
8173
|
+
const end = close + 3;
|
|
8174
|
+
masked += source.slice(i, end);
|
|
8175
|
+
i = end;
|
|
8176
|
+
continue;
|
|
8177
|
+
}
|
|
8178
|
+
}
|
|
8179
|
+
const rawBlock = tryMaskRawBlock(source, i, placeholders, sentinels, getTokens);
|
|
6879
8180
|
if (rawBlock) {
|
|
6880
8181
|
masked += rawBlock.placeholder;
|
|
6881
8182
|
i = rawBlock.end;
|
|
@@ -6896,16 +8197,25 @@ function restorePlaceholders(source, placeholders, sentinels) {
|
|
|
6896
8197
|
const pattern = new RegExp(`${escapeRegex(sentinels.open)}(\\d+)${escapeRegex(sentinels.close)}`, "g");
|
|
6897
8198
|
return source.replace(pattern, (_, idx) => placeholders[Number(idx)] ?? "");
|
|
6898
8199
|
}
|
|
6899
|
-
function tryMaskRawBlock(source, pos, placeholders, sentinels) {
|
|
8200
|
+
function tryMaskRawBlock(source, pos, placeholders, sentinels, getTokens) {
|
|
6900
8201
|
if (source[pos] !== "[" || source[pos + 1] !== "[")
|
|
6901
8202
|
return null;
|
|
8203
|
+
if (source.slice(pos, pos + 6).toLowerCase() === "[[code") {
|
|
8204
|
+
const tokens = getTokens();
|
|
8205
|
+
const start = tokenAtOffset(tokens, pos);
|
|
8206
|
+
const open = findCodeOpen(tokens, start);
|
|
8207
|
+
if (!open)
|
|
8208
|
+
return null;
|
|
8209
|
+
const bounds = open.closingSwallowed ? null : findCodeBodyBounds(tokens, open.bodyStart);
|
|
8210
|
+
const end = open.closingSwallowed ? tokens[open.attributesEnd - 1].position.end.offset : bounds.foundClose ? tokens[bounds.end - 1].position.end.offset : source.length;
|
|
8211
|
+
return { placeholder: pushPlaceholder(placeholders, source.slice(pos, end), sentinels), end };
|
|
8212
|
+
}
|
|
6902
8213
|
RAW_BLOCK_OPEN_PATTERN.lastIndex = pos;
|
|
6903
8214
|
const openMatch = RAW_BLOCK_OPEN_PATTERN.exec(source);
|
|
6904
8215
|
if (!openMatch)
|
|
6905
8216
|
return null;
|
|
6906
|
-
const name = openMatch[1].toLowerCase();
|
|
6907
8217
|
const openLen = openMatch[0].length;
|
|
6908
|
-
const closePattern =
|
|
8218
|
+
const closePattern = /\[\[\/\s*html\s*\]\]/gi;
|
|
6909
8219
|
closePattern.lastIndex = pos + openLen;
|
|
6910
8220
|
const closeMatch = closePattern.exec(source);
|
|
6911
8221
|
if (closeMatch) {
|
|
@@ -6915,12 +8225,19 @@ function tryMaskRawBlock(source, pos, placeholders, sentinels) {
|
|
|
6915
8225
|
end
|
|
6916
8226
|
};
|
|
6917
8227
|
}
|
|
6918
|
-
|
|
6919
|
-
|
|
6920
|
-
|
|
6921
|
-
|
|
6922
|
-
|
|
6923
|
-
|
|
8228
|
+
return null;
|
|
8229
|
+
}
|
|
8230
|
+
function tokenAtOffset(tokens, offset) {
|
|
8231
|
+
let low = 0;
|
|
8232
|
+
let high = tokens.length;
|
|
8233
|
+
while (low < high) {
|
|
8234
|
+
const middle = Math.floor((low + high) / 2);
|
|
8235
|
+
if (tokens[middle].position.start.offset < offset)
|
|
8236
|
+
low = middle + 1;
|
|
8237
|
+
else
|
|
8238
|
+
high = middle;
|
|
8239
|
+
}
|
|
8240
|
+
return tokens[low]?.position.start.offset === offset ? low : tokens.length;
|
|
6924
8241
|
}
|
|
6925
8242
|
function tryMaskRawInline(source, pos, placeholders, sentinels) {
|
|
6926
8243
|
if (source[pos] === "@" && source[pos + 1] === "<") {
|
|
@@ -6932,17 +8249,22 @@ function tryMaskRawInline(source, pos, placeholders, sentinels) {
|
|
|
6932
8249
|
return null;
|
|
6933
8250
|
}
|
|
6934
8251
|
function tryMaskSingleLineRaw(source, pos, openerLength, close, placeholders, sentinels) {
|
|
6935
|
-
const
|
|
6936
|
-
|
|
6937
|
-
`, pos + openerLength);
|
|
6938
|
-
if (closePos === -1 || newline !== -1 && newline < closePos)
|
|
8252
|
+
const end = singleLineRawEnd(source, pos, openerLength, close);
|
|
8253
|
+
if (end === pos)
|
|
6939
8254
|
return null;
|
|
6940
|
-
const end = closePos + close.length;
|
|
6941
8255
|
return {
|
|
6942
8256
|
placeholder: pushPlaceholder(placeholders, source.slice(pos, end), sentinels),
|
|
6943
8257
|
end
|
|
6944
8258
|
};
|
|
6945
8259
|
}
|
|
8260
|
+
function singleLineRawEnd(source, pos, openerLength, close) {
|
|
8261
|
+
const closePos = source.indexOf(close, pos + openerLength);
|
|
8262
|
+
const newline = source.indexOf(`
|
|
8263
|
+
`, pos + openerLength);
|
|
8264
|
+
if (closePos === -1 || newline !== -1 && newline < closePos)
|
|
8265
|
+
return pos;
|
|
8266
|
+
return closePos + close.length;
|
|
8267
|
+
}
|
|
6946
8268
|
function pushPlaceholder(placeholders, text, sentinels) {
|
|
6947
8269
|
const idx = placeholders.length;
|
|
6948
8270
|
placeholders.push(text);
|
|
@@ -7544,7 +8866,7 @@ function isListUsersModule2(module2) {
|
|
|
7544
8866
|
function resolveListUsers(_module, data, compiledTemplate, parse) {
|
|
7545
8867
|
const ctx = { user: data.user };
|
|
7546
8868
|
const substituted = compiledTemplate(ctx);
|
|
7547
|
-
const itemAst = getModuleParseAst(parse(substituted));
|
|
8869
|
+
const itemAst = getModuleParseAst(suppressModuleRatings(parse(substituted)));
|
|
7548
8870
|
return itemAst.elements;
|
|
7549
8871
|
}
|
|
7550
8872
|
// packages/parser/src/parser/rules/block/module/resolution/data-maps.ts
|
|
@@ -7746,7 +9068,7 @@ function countDynamicModules(elements) {
|
|
|
7746
9068
|
}
|
|
7747
9069
|
|
|
7748
9070
|
// packages/parser/src/parser/rules/block/module/resolution/styles.ts
|
|
7749
|
-
var
|
|
9071
|
+
var import_ast5 = require("@wdprlib/ast");
|
|
7750
9072
|
function collectStyles(elements, ignoredAnchors = new WeakSet) {
|
|
7751
9073
|
const styles = [];
|
|
7752
9074
|
const anchoredStyles = [];
|
|
@@ -7774,10 +9096,10 @@ function mergeCollectedStyles(existing, collected, resolvedSlots = new Map, anch
|
|
|
7774
9096
|
return merged;
|
|
7775
9097
|
}
|
|
7776
9098
|
function isStyleSlotMarker(style) {
|
|
7777
|
-
return style.startsWith(
|
|
9099
|
+
return style.startsWith(import_ast5.STYLE_SLOT_PREFIX);
|
|
7778
9100
|
}
|
|
7779
9101
|
function createStyleSlotMarker(slotId) {
|
|
7780
|
-
return `${
|
|
9102
|
+
return `${import_ast5.STYLE_SLOT_PREFIX}${slotId}`;
|
|
7781
9103
|
}
|
|
7782
9104
|
function getStyleSlotId(data) {
|
|
7783
9105
|
const slotId = data._styleSlot;
|
|
@@ -7789,7 +9111,7 @@ function removeFirst(values, value) {
|
|
|
7789
9111
|
values.splice(index, 1);
|
|
7790
9112
|
}
|
|
7791
9113
|
function appendStyleSlot(target, marker, resolvedSlots) {
|
|
7792
|
-
const slotId = Number(marker.slice(
|
|
9114
|
+
const slotId = Number(marker.slice(import_ast5.STYLE_SLOT_PREFIX.length));
|
|
7793
9115
|
const replacement = resolvedSlots.get(slotId);
|
|
7794
9116
|
if (replacement)
|
|
7795
9117
|
target.push(...replacement);
|
|
@@ -7819,24 +9141,24 @@ function collectStylesFromElements(elements, styles, anchoredStyles, anchors, ig
|
|
|
7819
9141
|
for (const element of elements) {
|
|
7820
9142
|
if (element.element === "style") {
|
|
7821
9143
|
const css = element.data;
|
|
7822
|
-
if (css.startsWith(
|
|
9144
|
+
if (css.startsWith(import_ast5.STYLE_SLOT_PREFIX)) {
|
|
7823
9145
|
styles.push(css);
|
|
7824
9146
|
continue;
|
|
7825
9147
|
}
|
|
7826
|
-
if (css.startsWith(
|
|
9148
|
+
if (css.startsWith(import_ast5.STYLE_ANCHOR_PREFIX)) {
|
|
7827
9149
|
anchors.push(element);
|
|
7828
9150
|
if (ignoredAnchors.has(element)) {
|
|
7829
9151
|
result.push(element);
|
|
7830
9152
|
continue;
|
|
7831
9153
|
}
|
|
7832
|
-
const anchoredCss = css.slice(
|
|
9154
|
+
const anchoredCss = css.slice(import_ast5.STYLE_ANCHOR_PREFIX.length);
|
|
7833
9155
|
styles.push(anchoredCss);
|
|
7834
9156
|
anchoredStyles.push(anchoredCss);
|
|
7835
9157
|
result.push(element);
|
|
7836
9158
|
continue;
|
|
7837
9159
|
}
|
|
7838
9160
|
styles.push(css);
|
|
7839
|
-
const anchor = { element: "style", data: `${
|
|
9161
|
+
const anchor = { element: "style", data: `${import_ast5.STYLE_ANCHOR_PREFIX}${css}` };
|
|
7840
9162
|
anchors.push(anchor);
|
|
7841
9163
|
result.push(anchor);
|
|
7842
9164
|
continue;
|
|
@@ -7959,7 +9281,7 @@ function walkAndResolve(elements, ctx) {
|
|
|
7959
9281
|
}
|
|
7960
9282
|
|
|
7961
9283
|
// packages/parser/src/parser/rules/block/module/resolution/document.ts
|
|
7962
|
-
var
|
|
9284
|
+
var import_ast6 = require("@wdprlib/ast");
|
|
7963
9285
|
|
|
7964
9286
|
// packages/parser/src/parser/toc.ts
|
|
7965
9287
|
class TocIndexer {
|
|
@@ -8221,11 +9543,11 @@ function walkRenderOrder(elements, pageTags, callback) {
|
|
|
8221
9543
|
for (const element of elements) {
|
|
8222
9544
|
callback(element);
|
|
8223
9545
|
if (element.element === "if") {
|
|
8224
|
-
walkRenderOrder(
|
|
9546
|
+
walkRenderOrder(import_ast6.isTruthy(element.data.condition) ? element.data.then : element.data.else, pageTags, callback);
|
|
8225
9547
|
continue;
|
|
8226
9548
|
}
|
|
8227
9549
|
if (element.element === "ifexpr") {
|
|
8228
|
-
const evaluated =
|
|
9550
|
+
const evaluated = import_ast6.evaluateExpression(element.data.expression);
|
|
8229
9551
|
if (evaluated.success) {
|
|
8230
9552
|
walkRenderOrder(evaluated.value !== 0 ? element.data.then : element.data.else, pageTags, callback);
|
|
8231
9553
|
}
|
|
@@ -8337,11 +9659,11 @@ async function resolveModules(ast, dataProvider, options) {
|
|
|
8337
9659
|
if (mergedStyles.length > 0)
|
|
8338
9660
|
result.styles = mergedStyles;
|
|
8339
9661
|
options.onDiagnostics?.(registry.diagnostics);
|
|
8340
|
-
return registry.finalize(result, finalElements, pageTags, containsSyntaxFootnoteBlock(ast.elements));
|
|
9662
|
+
return resolveRatings(registry.finalize(result, finalElements, pageTags, containsSyntaxFootnoteBlock(ast.elements)), dataProvider.fetchRatings);
|
|
8341
9663
|
}
|
|
8342
9664
|
function createModuleParseFunction(options, dataProvider, registry) {
|
|
8343
9665
|
const transform = createModuleSourceTransform(options, dataProvider);
|
|
8344
|
-
return (source) => registry.register(options.parse(transform ? transform(source) : source), {
|
|
9666
|
+
return (source) => registry.register(suppressModuleRatings(options.parse(transform ? transform(source) : source)), {
|
|
8345
9667
|
stripLegacyImplicitFootnoteBlock: true
|
|
8346
9668
|
});
|
|
8347
9669
|
}
|
|
@@ -8358,7 +9680,7 @@ function createModuleSourceTransform(options, dataProvider) {
|
|
|
8358
9680
|
}
|
|
8359
9681
|
|
|
8360
9682
|
// packages/parser/src/parser/rules/block/module/index.ts
|
|
8361
|
-
var
|
|
9683
|
+
var import_ast7 = require("@wdprlib/ast");
|
|
8362
9684
|
|
|
8363
9685
|
// packages/parser/src/parser/rules/block/footnoteblock/attributes.ts
|
|
8364
9686
|
function parseFootnoteBlockAttributes(ctx, startPos) {
|
|
@@ -9048,7 +10370,7 @@ var tabviewRule = {
|
|
|
9048
10370
|
};
|
|
9049
10371
|
|
|
9050
10372
|
// packages/parser/src/parser/rules/block/include/index.ts
|
|
9051
|
-
var
|
|
10373
|
+
var import_ast8 = require("@wdprlib/ast");
|
|
9052
10374
|
|
|
9053
10375
|
// packages/parser/src/parser/rules/block/include/arguments.ts
|
|
9054
10376
|
function collectIncludeArguments(ctx, startPos) {
|
|
@@ -9099,177 +10421,42 @@ function parsePageRef(target) {
|
|
|
9099
10421
|
};
|
|
9100
10422
|
}
|
|
9101
10423
|
}
|
|
9102
|
-
return { site: null, page: target };
|
|
9103
|
-
}
|
|
9104
|
-
|
|
9105
|
-
// packages/parser/src/parser/rules/block/include/variables.ts
|
|
9106
|
-
function parseVariables(tokens) {
|
|
9107
|
-
const vars = {};
|
|
9108
|
-
let current2 = "";
|
|
9109
|
-
for (const token5 of tokens) {
|
|
9110
|
-
if (token5 === "|") {
|
|
9111
|
-
assignVariable(vars, current2);
|
|
9112
|
-
current2 = "";
|
|
9113
|
-
} else {
|
|
9114
|
-
current2 += token5;
|
|
9115
|
-
}
|
|
9116
|
-
}
|
|
9117
|
-
assignVariable(vars, current2);
|
|
9118
|
-
return vars;
|
|
9119
|
-
}
|
|
9120
|
-
function assignVariable(vars, source) {
|
|
9121
|
-
if (!source.trim()) {
|
|
9122
|
-
return;
|
|
9123
|
-
}
|
|
9124
|
-
const eqIndex = source.indexOf("=");
|
|
9125
|
-
if (eqIndex === -1) {
|
|
9126
|
-
return;
|
|
9127
|
-
}
|
|
9128
|
-
const key = source.slice(0, eqIndex).trim();
|
|
9129
|
-
if (!key) {
|
|
9130
|
-
return;
|
|
9131
|
-
}
|
|
9132
|
-
vars[key] = source.slice(eqIndex + 1).trim();
|
|
9133
|
-
}
|
|
9134
|
-
|
|
9135
|
-
// packages/parser/src/parser/rules/block/include/index.ts
|
|
9136
|
-
var includeRule = {
|
|
9137
|
-
name: "include",
|
|
9138
|
-
startTokens: ["BLOCK_OPEN"],
|
|
9139
|
-
requiresLineStart: false,
|
|
9140
|
-
parse(ctx) {
|
|
9141
|
-
const openToken = currentToken(ctx);
|
|
9142
|
-
if (openToken.type !== "BLOCK_OPEN") {
|
|
9143
|
-
return { success: false };
|
|
9144
|
-
}
|
|
9145
|
-
let pos = ctx.pos + 1;
|
|
9146
|
-
let consumed = 1;
|
|
9147
|
-
const nameResult = parseBlockName(ctx, pos);
|
|
9148
|
-
if (!nameResult || nameResult.name.toLowerCase() !== "include") {
|
|
9149
|
-
return { success: false };
|
|
9150
|
-
}
|
|
9151
|
-
if (!ctx.settings.enablePageSyntax) {
|
|
9152
|
-
return { success: false };
|
|
9153
|
-
}
|
|
9154
|
-
pos += nameResult.consumed;
|
|
9155
|
-
consumed += nameResult.consumed;
|
|
9156
|
-
while (ctx.tokens[pos]?.type === "WHITESPACE") {
|
|
9157
|
-
pos++;
|
|
9158
|
-
consumed++;
|
|
9159
|
-
}
|
|
9160
|
-
const args = collectIncludeArguments(ctx, pos);
|
|
9161
|
-
pos += args.consumed;
|
|
9162
|
-
consumed += args.consumed;
|
|
9163
|
-
if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
|
|
9164
|
-
return { success: false };
|
|
9165
|
-
}
|
|
9166
|
-
pos++;
|
|
9167
|
-
consumed++;
|
|
9168
|
-
const directiveEnd = pos;
|
|
9169
|
-
if (ctx.tokens[pos]?.type === "NEWLINE") {
|
|
9170
|
-
pos++;
|
|
9171
|
-
consumed++;
|
|
9172
|
-
}
|
|
9173
|
-
if (!args.target) {
|
|
9174
|
-
return { success: false };
|
|
9175
|
-
}
|
|
9176
|
-
const location = parsePageRef(args.target);
|
|
9177
|
-
if (ctx.deferInclude?.(location)) {
|
|
9178
|
-
const source = ctx.tokens.slice(ctx.pos, directiveEnd).map((token5) => token5.value).join("");
|
|
9179
|
-
const elements = [];
|
|
9180
|
-
const lines = source.split(`
|
|
9181
|
-
`);
|
|
9182
|
-
for (let index = 0;index < lines.length; index++) {
|
|
9183
|
-
if (index > 0)
|
|
9184
|
-
elements.push(import_ast5.lineBreak());
|
|
9185
|
-
if (lines[index] !== "")
|
|
9186
|
-
elements.push(import_ast5.text(lines[index]));
|
|
9187
|
-
}
|
|
9188
|
-
return { success: true, elements: [import_ast5.paragraph(elements)], consumed };
|
|
9189
|
-
}
|
|
9190
|
-
return {
|
|
9191
|
-
success: true,
|
|
9192
|
-
elements: [
|
|
9193
|
-
{
|
|
9194
|
-
element: "include",
|
|
9195
|
-
data: {
|
|
9196
|
-
"paragraph-safe": false,
|
|
9197
|
-
variables: parseVariables(args.argumentTokens),
|
|
9198
|
-
location,
|
|
9199
|
-
elements: []
|
|
9200
|
-
}
|
|
9201
|
-
}
|
|
9202
|
-
],
|
|
9203
|
-
consumed
|
|
9204
|
-
};
|
|
9205
|
-
}
|
|
9206
|
-
};
|
|
9207
|
-
|
|
9208
|
-
// packages/parser/src/parser/rules/block/math/content.ts
|
|
9209
|
-
function collectMathContent(ctx, startPos) {
|
|
9210
|
-
let latexSource = "";
|
|
9211
|
-
let pos = startPos;
|
|
9212
|
-
let consumed = 0;
|
|
9213
|
-
let foundClose = false;
|
|
9214
|
-
while (pos < ctx.tokens.length) {
|
|
9215
|
-
const token5 = ctx.tokens[pos];
|
|
9216
|
-
if (!token5)
|
|
9217
|
-
break;
|
|
9218
|
-
if (token5.type === "BLOCK_END_OPEN") {
|
|
9219
|
-
const closeNameResult = parseBlockName(ctx, pos + 1);
|
|
9220
|
-
if (closeNameResult?.name === "math") {
|
|
9221
|
-
foundClose = true;
|
|
9222
|
-
break;
|
|
9223
|
-
}
|
|
9224
|
-
}
|
|
9225
|
-
latexSource += token5.type === "BACKSLASH_BREAK" ? "\\\n" : token5.value;
|
|
9226
|
-
pos++;
|
|
9227
|
-
consumed++;
|
|
9228
|
-
}
|
|
9229
|
-
return { latexSource, consumed, foundClose };
|
|
9230
|
-
}
|
|
9231
|
-
function consumeMathClose(ctx, startPos) {
|
|
9232
|
-
let pos = startPos + 1;
|
|
9233
|
-
let consumed = 1;
|
|
9234
|
-
const closeNameResult = parseBlockName(ctx, pos);
|
|
9235
|
-
if (closeNameResult) {
|
|
9236
|
-
pos += closeNameResult.consumed;
|
|
9237
|
-
consumed += closeNameResult.consumed;
|
|
9238
|
-
}
|
|
9239
|
-
if (ctx.tokens[pos]?.type === "BLOCK_CLOSE") {
|
|
9240
|
-
pos++;
|
|
9241
|
-
consumed++;
|
|
9242
|
-
}
|
|
9243
|
-
if (ctx.tokens[pos]?.type === "NEWLINE") {
|
|
9244
|
-
consumed++;
|
|
9245
|
-
}
|
|
9246
|
-
return consumed;
|
|
10424
|
+
return { site: null, page: target };
|
|
9247
10425
|
}
|
|
9248
10426
|
|
|
9249
|
-
// packages/parser/src/parser/rules/block/
|
|
9250
|
-
function
|
|
9251
|
-
|
|
9252
|
-
let
|
|
9253
|
-
|
|
9254
|
-
|
|
9255
|
-
|
|
9256
|
-
|
|
9257
|
-
|
|
9258
|
-
|
|
9259
|
-
const token5 = ctx.tokens[pos];
|
|
9260
|
-
if (!token5 || token5.type === "BLOCK_CLOSE" || token5.type === "WHITESPACE" || token5.type === "NEWLINE") {
|
|
9261
|
-
break;
|
|
10427
|
+
// packages/parser/src/parser/rules/block/include/variables.ts
|
|
10428
|
+
function parseVariables(tokens) {
|
|
10429
|
+
const vars = {};
|
|
10430
|
+
let current2 = "";
|
|
10431
|
+
for (const token5 of tokens) {
|
|
10432
|
+
if (token5 === "|") {
|
|
10433
|
+
assignVariable(vars, current2);
|
|
10434
|
+
current2 = "";
|
|
10435
|
+
} else {
|
|
10436
|
+
current2 += token5;
|
|
9262
10437
|
}
|
|
9263
|
-
name += token5.value;
|
|
9264
|
-
pos++;
|
|
9265
|
-
consumed++;
|
|
9266
10438
|
}
|
|
9267
|
-
|
|
10439
|
+
assignVariable(vars, current2);
|
|
10440
|
+
return vars;
|
|
10441
|
+
}
|
|
10442
|
+
function assignVariable(vars, source) {
|
|
10443
|
+
if (!source.trim()) {
|
|
10444
|
+
return;
|
|
10445
|
+
}
|
|
10446
|
+
const eqIndex = source.indexOf("=");
|
|
10447
|
+
if (eqIndex === -1) {
|
|
10448
|
+
return;
|
|
10449
|
+
}
|
|
10450
|
+
const key = source.slice(0, eqIndex).trim();
|
|
10451
|
+
if (!key) {
|
|
10452
|
+
return;
|
|
10453
|
+
}
|
|
10454
|
+
vars[key] = source.slice(eqIndex + 1).trim();
|
|
9268
10455
|
}
|
|
9269
10456
|
|
|
9270
|
-
// packages/parser/src/parser/rules/block/
|
|
9271
|
-
var
|
|
9272
|
-
name: "
|
|
10457
|
+
// packages/parser/src/parser/rules/block/include/index.ts
|
|
10458
|
+
var includeRule = {
|
|
10459
|
+
name: "include",
|
|
9273
10460
|
startTokens: ["BLOCK_OPEN"],
|
|
9274
10461
|
requiresLineStart: false,
|
|
9275
10462
|
parse(ctx) {
|
|
@@ -9280,7 +10467,10 @@ var mathBlockRule = {
|
|
|
9280
10467
|
let pos = ctx.pos + 1;
|
|
9281
10468
|
let consumed = 1;
|
|
9282
10469
|
const nameResult = parseBlockName(ctx, pos);
|
|
9283
|
-
if (!nameResult || nameResult.name !== "
|
|
10470
|
+
if (!nameResult || nameResult.name.toLowerCase() !== "include") {
|
|
10471
|
+
return { success: false };
|
|
10472
|
+
}
|
|
10473
|
+
if (!ctx.settings.enablePageSyntax) {
|
|
9284
10474
|
return { success: false };
|
|
9285
10475
|
}
|
|
9286
10476
|
pos += nameResult.consumed;
|
|
@@ -9289,49 +10479,46 @@ var mathBlockRule = {
|
|
|
9289
10479
|
pos++;
|
|
9290
10480
|
consumed++;
|
|
9291
10481
|
}
|
|
9292
|
-
const
|
|
9293
|
-
pos +=
|
|
9294
|
-
consumed +=
|
|
9295
|
-
while (ctx.tokens[pos]?.type === "WHITESPACE") {
|
|
9296
|
-
pos++;
|
|
9297
|
-
consumed++;
|
|
9298
|
-
}
|
|
10482
|
+
const args = collectIncludeArguments(ctx, pos);
|
|
10483
|
+
pos += args.consumed;
|
|
10484
|
+
consumed += args.consumed;
|
|
9299
10485
|
if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
|
|
9300
10486
|
return { success: false };
|
|
9301
10487
|
}
|
|
9302
10488
|
pos++;
|
|
9303
10489
|
consumed++;
|
|
10490
|
+
const directiveEnd = pos;
|
|
9304
10491
|
if (ctx.tokens[pos]?.type === "NEWLINE") {
|
|
9305
10492
|
pos++;
|
|
9306
10493
|
consumed++;
|
|
9307
10494
|
}
|
|
9308
|
-
|
|
9309
|
-
const latexSource = contentResult.latexSource.trim();
|
|
9310
|
-
consumed += contentResult.consumed;
|
|
9311
|
-
pos += contentResult.consumed;
|
|
9312
|
-
if (!contentResult.foundClose) {
|
|
9313
|
-
ctx.diagnostics.push({
|
|
9314
|
-
severity: "warning",
|
|
9315
|
-
code: "unclosed-block",
|
|
9316
|
-
message: "Missing closing tag [[/math]] for [[math]]",
|
|
9317
|
-
position: openToken.position
|
|
9318
|
-
});
|
|
9319
|
-
} else {
|
|
9320
|
-
const closeConsumed = consumeMathClose(ctx, pos);
|
|
9321
|
-
pos += closeConsumed;
|
|
9322
|
-
consumed += closeConsumed;
|
|
9323
|
-
}
|
|
9324
|
-
if (!latexSource) {
|
|
10495
|
+
if (!args.target) {
|
|
9325
10496
|
return { success: false };
|
|
9326
10497
|
}
|
|
10498
|
+
const location = parsePageRef(args.target);
|
|
10499
|
+
if (ctx.deferInclude?.(location)) {
|
|
10500
|
+
const source = ctx.tokens.slice(ctx.pos, directiveEnd).map((token5) => token5.value).join("");
|
|
10501
|
+
const elements = [];
|
|
10502
|
+
const lines = source.split(`
|
|
10503
|
+
`);
|
|
10504
|
+
for (let index = 0;index < lines.length; index++) {
|
|
10505
|
+
if (index > 0)
|
|
10506
|
+
elements.push(import_ast8.lineBreak());
|
|
10507
|
+
if (lines[index] !== "")
|
|
10508
|
+
elements.push(import_ast8.text(lines[index]));
|
|
10509
|
+
}
|
|
10510
|
+
return { success: true, elements: [import_ast8.paragraph(elements)], consumed };
|
|
10511
|
+
}
|
|
9327
10512
|
return {
|
|
9328
10513
|
success: true,
|
|
9329
10514
|
elements: [
|
|
9330
10515
|
{
|
|
9331
|
-
element: "
|
|
10516
|
+
element: "include",
|
|
9332
10517
|
data: {
|
|
9333
|
-
|
|
9334
|
-
|
|
10518
|
+
"paragraph-safe": false,
|
|
10519
|
+
variables: parseVariables(args.argumentTokens),
|
|
10520
|
+
location,
|
|
10521
|
+
elements: []
|
|
9335
10522
|
}
|
|
9336
10523
|
}
|
|
9337
10524
|
],
|
|
@@ -10201,7 +11388,8 @@ function parseBibliographyContent(ctx, startPos) {
|
|
|
10201
11388
|
const inlineCtx = { ...ctx, pos };
|
|
10202
11389
|
const result = parseInlineUntil(inlineCtx, "NEWLINE");
|
|
10203
11390
|
if (result.elements.length > 0) {
|
|
10204
|
-
|
|
11391
|
+
for (const element of result.elements)
|
|
11392
|
+
content.push(element);
|
|
10205
11393
|
pos += result.consumed;
|
|
10206
11394
|
consumed += result.consumed;
|
|
10207
11395
|
} else {
|
|
@@ -10630,6 +11818,7 @@ var blockRules = [
|
|
|
10630
11818
|
iftagsRule,
|
|
10631
11819
|
bibliographyRule,
|
|
10632
11820
|
galleryRule,
|
|
11821
|
+
noteRule,
|
|
10633
11822
|
divRule
|
|
10634
11823
|
];
|
|
10635
11824
|
// packages/parser/src/parser/rules/inline/formatting/close.ts
|
|
@@ -10642,6 +11831,11 @@ function findFormattingClose(ctx, start, marker) {
|
|
|
10642
11831
|
return null;
|
|
10643
11832
|
if (!table && token5.type === "NEWLINE" && getParagraphNewlineBoundary(ctx, pos, true).shouldBreak)
|
|
10644
11833
|
return null;
|
|
11834
|
+
const inlineRegionEnd = Math.max(emailRegionEnd(ctx.tokens, pos, end), parseButtonSyntax(ctx, pos, end)?.end ?? pos, parseSocialSyntax(ctx, pos, end)?.end ?? pos);
|
|
11835
|
+
if (inlineRegionEnd > pos) {
|
|
11836
|
+
pos = inlineRegionEnd - 1;
|
|
11837
|
+
continue;
|
|
11838
|
+
}
|
|
10645
11839
|
if (token5.type === marker && !table?.suppressedClosers.has(pos))
|
|
10646
11840
|
return pos;
|
|
10647
11841
|
const protectedEnd = protectedInlineRegionEnd(ctx.tokens, pos, end);
|
|
@@ -10750,190 +11944,30 @@ var strikethroughRule = {
|
|
|
10750
11944
|
|
|
10751
11945
|
// packages/parser/src/parser/rules/inline/superscript.ts
|
|
10752
11946
|
var superscriptRule = {
|
|
10753
|
-
name: "superscript",
|
|
10754
|
-
startTokens: ["SUPER_MARKER"],
|
|
10755
|
-
parse(ctx) {
|
|
10756
|
-
return parseDelimitedContainer(ctx, "SUPER_MARKER", "superscript", {
|
|
10757
|
-
discardEmpty: true
|
|
10758
|
-
});
|
|
10759
|
-
}
|
|
10760
|
-
};
|
|
10761
|
-
|
|
10762
|
-
// packages/parser/src/parser/rules/inline/subscript.ts
|
|
10763
|
-
var subscriptRule = {
|
|
10764
|
-
name: "subscript",
|
|
10765
|
-
startTokens: ["SUB_MARKER"],
|
|
10766
|
-
parse(ctx) {
|
|
10767
|
-
return parseDelimitedContainer(ctx, "SUB_MARKER", "subscript", { discardEmpty: true });
|
|
10768
|
-
}
|
|
10769
|
-
};
|
|
10770
|
-
|
|
10771
|
-
// packages/parser/src/parser/rules/inline/monospace.ts
|
|
10772
|
-
var monospaceRule = {
|
|
10773
|
-
name: "monospace",
|
|
10774
|
-
startTokens: ["MONO_MARKER"],
|
|
10775
|
-
parse(ctx) {
|
|
10776
|
-
return parseDelimitedContainer(ctx, "MONO_CLOSE", "monospace");
|
|
10777
|
-
}
|
|
10778
|
-
};
|
|
10779
|
-
|
|
10780
|
-
// packages/parser/src/parser/rules/inline/link-triple/fallback.ts
|
|
10781
|
-
function literalOpenLink(value) {
|
|
10782
|
-
return {
|
|
10783
|
-
success: true,
|
|
10784
|
-
elements: [{ element: "text", data: value }],
|
|
10785
|
-
consumed: 1
|
|
10786
|
-
};
|
|
10787
|
-
}
|
|
10788
|
-
|
|
10789
|
-
// packages/parser/src/parser/rules/inline/link-triple/label.ts
|
|
10790
|
-
function buildTripleLinkLabel(args) {
|
|
10791
|
-
return {
|
|
10792
|
-
text: getTripleLinkDisplayText(args)
|
|
10793
|
-
};
|
|
10794
|
-
}
|
|
10795
|
-
function getTripleLinkDisplayText(args) {
|
|
10796
|
-
const trimmedLabel = args.labelText.trim();
|
|
10797
|
-
if (args.foundPipe) {
|
|
10798
|
-
return trimmedLabel || args.finalTarget;
|
|
10799
|
-
}
|
|
10800
|
-
const colonIdx = args.originalTarget.indexOf(":");
|
|
10801
|
-
if (colonIdx !== -1 && !args.originalTarget.startsWith("http") && !args.originalTarget.startsWith("*")) {
|
|
10802
|
-
return args.originalTarget.slice(colonIdx + 1).trim();
|
|
10803
|
-
}
|
|
10804
|
-
return args.originalTarget;
|
|
10805
|
-
}
|
|
10806
|
-
|
|
10807
|
-
// packages/parser/src/parser/rules/inline/link-triple/syntax.ts
|
|
10808
|
-
function hasClosingLinkMarker(ctx, startPos) {
|
|
10809
|
-
let pos = startPos;
|
|
10810
|
-
while (pos < ctx.tokens.length) {
|
|
10811
|
-
const token5 = ctx.tokens[pos];
|
|
10812
|
-
if (!token5 || token5.type === "EOF") {
|
|
10813
|
-
return false;
|
|
10814
|
-
}
|
|
10815
|
-
if (token5.type === "LINK_CLOSE") {
|
|
10816
|
-
return true;
|
|
10817
|
-
}
|
|
10818
|
-
if (token5.type === "NEWLINE") {
|
|
10819
|
-
const next = ctx.tokens[pos + 1];
|
|
10820
|
-
if (next?.type === "NEWLINE" || next?.type === "LINK_CLOSE") {
|
|
10821
|
-
return false;
|
|
10822
|
-
}
|
|
10823
|
-
}
|
|
10824
|
-
pos++;
|
|
10825
|
-
}
|
|
10826
|
-
return false;
|
|
10827
|
-
}
|
|
10828
|
-
function collectTripleLinkParts(ctx, startPos) {
|
|
10829
|
-
let target = "";
|
|
10830
|
-
let labelText = "";
|
|
10831
|
-
let foundPipe = false;
|
|
10832
|
-
let consumed = 1;
|
|
10833
|
-
let pos = startPos;
|
|
10834
|
-
while (pos < ctx.tokens.length) {
|
|
10835
|
-
const token5 = ctx.tokens[pos];
|
|
10836
|
-
if (!token5 || token5.type === "LINK_CLOSE" || token5.type === "EOF") {
|
|
10837
|
-
break;
|
|
10838
|
-
}
|
|
10839
|
-
if (token5.type === "NEWLINE") {
|
|
10840
|
-
if (foundPipe) {
|
|
10841
|
-
labelText += " ";
|
|
10842
|
-
} else {
|
|
10843
|
-
target += " ";
|
|
10844
|
-
}
|
|
10845
|
-
consumed++;
|
|
10846
|
-
pos++;
|
|
10847
|
-
continue;
|
|
10848
|
-
}
|
|
10849
|
-
if (token5.type === "PIPE" && !foundPipe) {
|
|
10850
|
-
foundPipe = true;
|
|
10851
|
-
} else if (foundPipe) {
|
|
10852
|
-
labelText += token5.value;
|
|
10853
|
-
} else {
|
|
10854
|
-
target += token5.value;
|
|
10855
|
-
}
|
|
10856
|
-
consumed++;
|
|
10857
|
-
pos++;
|
|
10858
|
-
}
|
|
10859
|
-
if (ctx.tokens[pos]?.type === "LINK_CLOSE") {
|
|
10860
|
-
consumed++;
|
|
10861
|
-
}
|
|
10862
|
-
return { target, labelText, foundPipe, consumed };
|
|
10863
|
-
}
|
|
10864
|
-
|
|
10865
|
-
// packages/parser/src/parser/rules/inline/link-triple/interwiki.ts
|
|
10866
|
-
var INTERWIKI_PREFIXES = new Set(["wikipedia", "google", "dictionary", "wikidot"]);
|
|
10867
|
-
function isInterwikiTarget(target) {
|
|
10868
|
-
const colonIdx = target.indexOf(":");
|
|
10869
|
-
if (colonIdx <= 0 || target.includes("/")) {
|
|
10870
|
-
return false;
|
|
10871
|
-
}
|
|
10872
|
-
const prefix = target.slice(0, colonIdx).toLowerCase();
|
|
10873
|
-
return INTERWIKI_PREFIXES.has(prefix);
|
|
10874
|
-
}
|
|
10875
|
-
|
|
10876
|
-
// packages/parser/src/parser/rules/inline/link-triple/target.ts
|
|
10877
|
-
function normalizeTripleLinkTarget(trimmedTarget) {
|
|
10878
|
-
if (trimmedTarget.startsWith("*")) {
|
|
10879
|
-
return { target: trimmedTarget.slice(1), hasStar: true };
|
|
10880
|
-
}
|
|
10881
|
-
return { target: trimmedTarget, hasStar: false };
|
|
10882
|
-
}
|
|
10883
|
-
function isInvalidTripleLinkTarget(trimmedTarget, foundPipe) {
|
|
10884
|
-
return trimmedTarget === "" && foundPipe || /#{2,}/.test(trimmedTarget);
|
|
10885
|
-
}
|
|
10886
|
-
function determineLinkTypeAndLocation(target) {
|
|
10887
|
-
if (target.startsWith("#")) {
|
|
10888
|
-
return { linkType: "anchor", link: target };
|
|
10889
|
-
}
|
|
10890
|
-
if (target.startsWith("http://") || target.startsWith("https://")) {
|
|
10891
|
-
return { linkType: "direct", link: target };
|
|
10892
|
-
}
|
|
10893
|
-
if (isInterwikiTarget(target)) {
|
|
10894
|
-
return { linkType: "interwiki", link: target };
|
|
10895
|
-
}
|
|
10896
|
-
return { linkType: "page", link: { site: null, page: target } };
|
|
10897
|
-
}
|
|
10898
|
-
|
|
10899
|
-
// packages/parser/src/parser/rules/inline/link-triple/index.ts
|
|
10900
|
-
var linkTripleRule = {
|
|
10901
|
-
name: "linkTriple",
|
|
10902
|
-
startTokens: ["LINK_OPEN"],
|
|
10903
|
-
parse(ctx) {
|
|
10904
|
-
const startToken = currentToken(ctx);
|
|
10905
|
-
if (!hasClosingLinkMarker(ctx, ctx.pos + 1)) {
|
|
10906
|
-
return literalOpenLink(startToken.value);
|
|
10907
|
-
}
|
|
10908
|
-
const parts = collectTripleLinkParts(ctx, ctx.pos + 1);
|
|
10909
|
-
const trimmedTarget = parts.target.trim();
|
|
10910
|
-
if (isInvalidTripleLinkTarget(trimmedTarget, parts.foundPipe)) {
|
|
10911
|
-
return literalOpenLink(startToken.value);
|
|
10912
|
-
}
|
|
10913
|
-
const normalized = normalizeTripleLinkTarget(trimmedTarget);
|
|
10914
|
-
const { linkType, link } = determineLinkTypeAndLocation(normalized.target);
|
|
10915
|
-
const label = buildTripleLinkLabel({
|
|
10916
|
-
foundPipe: parts.foundPipe,
|
|
10917
|
-
labelText: parts.labelText,
|
|
10918
|
-
finalTarget: normalized.target,
|
|
10919
|
-
originalTarget: trimmedTarget
|
|
11947
|
+
name: "superscript",
|
|
11948
|
+
startTokens: ["SUPER_MARKER"],
|
|
11949
|
+
parse(ctx) {
|
|
11950
|
+
return parseDelimitedContainer(ctx, "SUPER_MARKER", "superscript", {
|
|
11951
|
+
discardEmpty: true
|
|
10920
11952
|
});
|
|
10921
|
-
|
|
10922
|
-
|
|
10923
|
-
|
|
10924
|
-
|
|
10925
|
-
|
|
10926
|
-
|
|
10927
|
-
|
|
10928
|
-
|
|
10929
|
-
|
|
10930
|
-
|
|
10931
|
-
|
|
10932
|
-
|
|
10933
|
-
|
|
10934
|
-
|
|
10935
|
-
|
|
10936
|
-
|
|
11953
|
+
}
|
|
11954
|
+
};
|
|
11955
|
+
|
|
11956
|
+
// packages/parser/src/parser/rules/inline/subscript.ts
|
|
11957
|
+
var subscriptRule = {
|
|
11958
|
+
name: "subscript",
|
|
11959
|
+
startTokens: ["SUB_MARKER"],
|
|
11960
|
+
parse(ctx) {
|
|
11961
|
+
return parseDelimitedContainer(ctx, "SUB_MARKER", "subscript", { discardEmpty: true });
|
|
11962
|
+
}
|
|
11963
|
+
};
|
|
11964
|
+
|
|
11965
|
+
// packages/parser/src/parser/rules/inline/monospace.ts
|
|
11966
|
+
var monospaceRule = {
|
|
11967
|
+
name: "monospace",
|
|
11968
|
+
startTokens: ["MONO_MARKER"],
|
|
11969
|
+
parse(ctx) {
|
|
11970
|
+
return parseDelimitedContainer(ctx, "MONO_CLOSE", "monospace");
|
|
10937
11971
|
}
|
|
10938
11972
|
};
|
|
10939
11973
|
|
|
@@ -10944,7 +11978,7 @@ function normalizeAnchor(anchor) {
|
|
|
10944
11978
|
|
|
10945
11979
|
// packages/parser/src/parser/rules/inline/link-bracket/direct-url.ts
|
|
10946
11980
|
function isDirectBracketUrl(url) {
|
|
10947
|
-
return url !== "" && (url.startsWith("/") || url
|
|
11981
|
+
return url !== "" && (url.startsWith("/") || startsWithUrlScheme(url, 0));
|
|
10948
11982
|
}
|
|
10949
11983
|
|
|
10950
11984
|
// packages/parser/src/parser/rules/inline/link-bracket/parts.ts
|
|
@@ -10953,35 +11987,24 @@ function collectBracketLinkParts(ctx, startPos) {
|
|
|
10953
11987
|
return null;
|
|
10954
11988
|
}
|
|
10955
11989
|
let pos = startPos;
|
|
10956
|
-
|
|
10957
|
-
|
|
10958
|
-
while (pos <
|
|
10959
|
-
const token5 = ctx.tokens[pos];
|
|
10960
|
-
if (!token5 || token5.type === "WHITESPACE" || token5.type === "BRACKET_CLOSE" || token5.type === "NEWLINE" || token5.type === "EOF") {
|
|
10961
|
-
break;
|
|
10962
|
-
}
|
|
10963
|
-
first += token5.value;
|
|
10964
|
-
pos++;
|
|
10965
|
-
consumed++;
|
|
10966
|
-
}
|
|
10967
|
-
while (ctx.tokens[pos]?.type === "WHITESPACE") {
|
|
10968
|
-
pos++;
|
|
10969
|
-
consumed++;
|
|
10970
|
-
}
|
|
10971
|
-
let label = "";
|
|
10972
|
-
while (pos < ctx.tokens.length) {
|
|
11990
|
+
const end = Math.min(ctx.scope.inlineEnd ?? ctx.tokens.length, ctx.tokens.length);
|
|
11991
|
+
const values = [];
|
|
11992
|
+
while (pos < end) {
|
|
10973
11993
|
const token5 = ctx.tokens[pos];
|
|
10974
|
-
if (!token5 || token5.type === "BRACKET_CLOSE" || token5.type === "NEWLINE" || token5.type === "EOF")
|
|
11994
|
+
if (!token5 || token5.type === "BRACKET_CLOSE" || token5.type === "NEWLINE" || token5.type === "EOF")
|
|
10975
11995
|
break;
|
|
10976
|
-
|
|
10977
|
-
label += token5.value;
|
|
11996
|
+
values.push(token5.value);
|
|
10978
11997
|
pos++;
|
|
10979
|
-
consumed++;
|
|
10980
11998
|
}
|
|
10981
|
-
if (ctx.tokens[pos]?.type !== "BRACKET_CLOSE")
|
|
11999
|
+
if (pos >= end || ctx.tokens[pos]?.type !== "BRACKET_CLOSE")
|
|
10982
12000
|
return null;
|
|
10983
|
-
|
|
10984
|
-
|
|
12001
|
+
const content = values.join("");
|
|
12002
|
+
const separator = content.search(/[ \t]/);
|
|
12003
|
+
return {
|
|
12004
|
+
first: separator === -1 ? content : content.slice(0, separator),
|
|
12005
|
+
label: separator === -1 ? "" : content.slice(separator).trimStart(),
|
|
12006
|
+
consumed: pos - startPos + 1
|
|
12007
|
+
};
|
|
10985
12008
|
}
|
|
10986
12009
|
|
|
10987
12010
|
// packages/parser/src/parser/rules/inline/link-bracket/prefix.ts
|
|
@@ -10992,6 +12015,14 @@ function parseBracketLinkPrefix(ctx, startPos) {
|
|
|
10992
12015
|
return { target: null, bodyStart: startPos, consumed: 0 };
|
|
10993
12016
|
}
|
|
10994
12017
|
|
|
12018
|
+
// packages/parser/src/parser/rules/inline/link-bracket/special-target.ts
|
|
12019
|
+
function isBracketEmail(target) {
|
|
12020
|
+
return /^[_a-z0-9-]+(?:\.[_a-z0-9-]+)*@[a-z0-9-]+(?:\.[a-z0-9-]+)+$/i.test(target);
|
|
12021
|
+
}
|
|
12022
|
+
function wikipediaPage(target) {
|
|
12023
|
+
return /^wikipedia:((?!:)[A-Za-z0-9_/=&~#.:;+-]+)$/.exec(target)?.[1] ?? null;
|
|
12024
|
+
}
|
|
12025
|
+
|
|
10995
12026
|
// packages/parser/src/parser/rules/inline/link-bracket/parsed.ts
|
|
10996
12027
|
function parseSingleBracketLink(ctx) {
|
|
10997
12028
|
const prefix = parseBracketLinkPrefix(ctx, ctx.pos + 1);
|
|
@@ -11000,17 +12031,20 @@ function parseSingleBracketLink(ctx) {
|
|
|
11000
12031
|
return null;
|
|
11001
12032
|
}
|
|
11002
12033
|
const link = parts.first.trim();
|
|
11003
|
-
|
|
12034
|
+
const email = isBracketEmail(link);
|
|
12035
|
+
const wikiPage = wikipediaPage(link);
|
|
12036
|
+
if (!email && wikiPage === null && !isDirectBracketUrl(link)) {
|
|
11004
12037
|
return null;
|
|
11005
12038
|
}
|
|
11006
|
-
const labelText = parts.label.trim();
|
|
12039
|
+
const labelText = parts.label.trim() || wikiPage;
|
|
11007
12040
|
if (!labelText) {
|
|
11008
12041
|
return null;
|
|
11009
12042
|
}
|
|
11010
12043
|
return {
|
|
11011
|
-
link,
|
|
12044
|
+
link: email ? `mailto:${link}` : link,
|
|
12045
|
+
interwiki: wikiPage !== null,
|
|
11012
12046
|
labelText,
|
|
11013
|
-
target: prefix.target,
|
|
12047
|
+
target: wikiPage !== null ? "new-tab" : prefix.target,
|
|
11014
12048
|
consumed: 1 + prefix.consumed + parts.consumed
|
|
11015
12049
|
};
|
|
11016
12050
|
}
|
|
@@ -11063,7 +12097,7 @@ var linkSingleRule = {
|
|
|
11063
12097
|
{
|
|
11064
12098
|
element: "link",
|
|
11065
12099
|
data: {
|
|
11066
|
-
type: "direct",
|
|
12100
|
+
type: parsed.interwiki ? "interwiki" : "direct",
|
|
11067
12101
|
link: parsed.link,
|
|
11068
12102
|
extra: null,
|
|
11069
12103
|
label: linkLabel,
|
|
@@ -11132,6 +12166,134 @@ var linkStarRule = {
|
|
|
11132
12166
|
}
|
|
11133
12167
|
};
|
|
11134
12168
|
|
|
12169
|
+
// packages/parser/src/parser/rules/inline/autolink.ts
|
|
12170
|
+
var URL_BOUNDARY_TOKENS = new Set([
|
|
12171
|
+
"WHITESPACE",
|
|
12172
|
+
"NEWLINE",
|
|
12173
|
+
"EOF",
|
|
12174
|
+
"BLOCK_OPEN",
|
|
12175
|
+
"BLOCK_END_OPEN",
|
|
12176
|
+
"BLOCK_CLOSE",
|
|
12177
|
+
"LINK_OPEN",
|
|
12178
|
+
"LINK_CLOSE",
|
|
12179
|
+
"COMMENT_OPEN",
|
|
12180
|
+
"BACKSLASH_BREAK"
|
|
12181
|
+
]);
|
|
12182
|
+
var autolinkRule = {
|
|
12183
|
+
name: "autolink",
|
|
12184
|
+
startTokens: ["IDENTIFIER", "STAR", "LIST_BULLET"],
|
|
12185
|
+
parse(ctx) {
|
|
12186
|
+
let pos = ctx.pos;
|
|
12187
|
+
let target = null;
|
|
12188
|
+
const first = ctx.tokens[pos];
|
|
12189
|
+
if (!first) {
|
|
12190
|
+
return { success: false };
|
|
12191
|
+
}
|
|
12192
|
+
if (first.type === "STAR" || first.type === "LIST_BULLET") {
|
|
12193
|
+
if (first.value !== "*") {
|
|
12194
|
+
return { success: false };
|
|
12195
|
+
}
|
|
12196
|
+
target = "new-tab";
|
|
12197
|
+
pos++;
|
|
12198
|
+
}
|
|
12199
|
+
const scheme = ctx.tokens[pos];
|
|
12200
|
+
if (scheme?.type !== "IDENTIFIER" || !URL_SCHEME_NAMES.has(scheme.value)) {
|
|
12201
|
+
return { success: false };
|
|
12202
|
+
}
|
|
12203
|
+
if (ctx.tokens[pos + 1]?.type !== "COLON") {
|
|
12204
|
+
return { success: false };
|
|
12205
|
+
}
|
|
12206
|
+
const prev = ctx.tokens[ctx.pos - 1];
|
|
12207
|
+
if (prev && !first.lineStart) {
|
|
12208
|
+
const lastChar = prev.value[prev.value.length - 1] ?? "";
|
|
12209
|
+
if (/[A-Za-z]/.test(lastChar)) {
|
|
12210
|
+
return { success: false };
|
|
12211
|
+
}
|
|
12212
|
+
}
|
|
12213
|
+
const values = [];
|
|
12214
|
+
let end = pos;
|
|
12215
|
+
const inlineEnd = ctx.scope.inlineEnd ?? ctx.tokens.length;
|
|
12216
|
+
while (end < inlineEnd) {
|
|
12217
|
+
const token5 = ctx.tokens[end];
|
|
12218
|
+
if (!token5 || URL_BOUNDARY_TOKENS.has(token5.type)) {
|
|
12219
|
+
break;
|
|
12220
|
+
}
|
|
12221
|
+
if (token5.type === "RAW_OPEN" || token5.type === "RAW_BLOCK_OPEN") {
|
|
12222
|
+
if (rawRegionEnd(ctx.tokens, end, inlineEnd) > end)
|
|
12223
|
+
break;
|
|
12224
|
+
}
|
|
12225
|
+
values.push(token5.value);
|
|
12226
|
+
end++;
|
|
12227
|
+
if (/[ \t\n\\"']/.test(token5.value))
|
|
12228
|
+
break;
|
|
12229
|
+
}
|
|
12230
|
+
const candidate = values.join("");
|
|
12231
|
+
const match = URL_PATTERN.exec(candidate);
|
|
12232
|
+
if (!match) {
|
|
12233
|
+
return { success: false };
|
|
12234
|
+
}
|
|
12235
|
+
const url = match[0];
|
|
12236
|
+
let length = 0;
|
|
12237
|
+
let count = 0;
|
|
12238
|
+
while (length < url.length) {
|
|
12239
|
+
length += values[count]?.length ?? 0;
|
|
12240
|
+
count++;
|
|
12241
|
+
}
|
|
12242
|
+
const rest = candidate.slice(url.length, length);
|
|
12243
|
+
const elements = [
|
|
12244
|
+
{
|
|
12245
|
+
element: "link",
|
|
12246
|
+
data: {
|
|
12247
|
+
type: "direct",
|
|
12248
|
+
link: url,
|
|
12249
|
+
extra: null,
|
|
12250
|
+
label: { text: url },
|
|
12251
|
+
target
|
|
12252
|
+
}
|
|
12253
|
+
}
|
|
12254
|
+
];
|
|
12255
|
+
if (rest !== "") {
|
|
12256
|
+
elements.push({ element: "text", data: rest });
|
|
12257
|
+
}
|
|
12258
|
+
return {
|
|
12259
|
+
success: true,
|
|
12260
|
+
elements,
|
|
12261
|
+
consumed: pos - ctx.pos + count
|
|
12262
|
+
};
|
|
12263
|
+
}
|
|
12264
|
+
};
|
|
12265
|
+
|
|
12266
|
+
// packages/parser/src/parser/rules/inline/email/index.ts
|
|
12267
|
+
var emailRule = {
|
|
12268
|
+
name: "email",
|
|
12269
|
+
startTokens: EMAIL_START_TOKENS,
|
|
12270
|
+
parse(ctx) {
|
|
12271
|
+
const group = getEmailGroup(ctx.tokens, ctx.pos, ctx.scope.inlineEnd ?? ctx.tokens.length);
|
|
12272
|
+
if (!group)
|
|
12273
|
+
return { success: false };
|
|
12274
|
+
const elements = [];
|
|
12275
|
+
let copied = group.start;
|
|
12276
|
+
for (const candidate of group.candidates) {
|
|
12277
|
+
if (copied < candidate.start)
|
|
12278
|
+
elements.push({ element: "text", data: group.source.slice(copied, candidate.start) });
|
|
12279
|
+
elements.push(ctx.scope.suppressEmailLinks ? { element: "text", data: candidate.address } : {
|
|
12280
|
+
element: "link",
|
|
12281
|
+
data: {
|
|
12282
|
+
type: "direct",
|
|
12283
|
+
link: `mailto:${candidate.address}`,
|
|
12284
|
+
label: { text: candidate.address },
|
|
12285
|
+
target: null,
|
|
12286
|
+
extra: null
|
|
12287
|
+
}
|
|
12288
|
+
});
|
|
12289
|
+
copied = candidate.end;
|
|
12290
|
+
}
|
|
12291
|
+
if (copied < group.end)
|
|
12292
|
+
elements.push({ element: "text", data: group.source.slice(copied, group.end) });
|
|
12293
|
+
return { success: true, elements, consumed: group.endToken - ctx.pos };
|
|
12294
|
+
}
|
|
12295
|
+
};
|
|
12296
|
+
|
|
11135
12297
|
// packages/parser/src/parser/rules/inline/color/syntax.ts
|
|
11136
12298
|
function parseColorContent(ctx) {
|
|
11137
12299
|
const close = findFormattingClose(ctx, ctx.pos + 1, "COLOR_MARKER");
|
|
@@ -11218,7 +12380,7 @@ var newlineLineBreakRule = {
|
|
|
11218
12380
|
}
|
|
11219
12381
|
return {
|
|
11220
12382
|
success: true,
|
|
11221
|
-
elements: [
|
|
12383
|
+
elements: [createAutomaticLineBreak(currentTok)],
|
|
11222
12384
|
consumed: 1
|
|
11223
12385
|
};
|
|
11224
12386
|
}
|
|
@@ -11241,6 +12403,9 @@ function isValidBlockStartAfterNewline(ctx, tokenPos) {
|
|
|
11241
12403
|
if (!isBlockStartToken(token5?.type) || !token5?.lineStart) {
|
|
11242
12404
|
return false;
|
|
11243
12405
|
}
|
|
12406
|
+
if (token5.type === "LIST_BULLET" || token5.type === "LIST_NUMBER") {
|
|
12407
|
+
return ctx.tokens[tokenPos + 1]?.type === "WHITESPACE";
|
|
12408
|
+
}
|
|
11244
12409
|
if (token5.type !== "HEADING_MARKER") {
|
|
11245
12410
|
return true;
|
|
11246
12411
|
}
|
|
@@ -11498,6 +12663,9 @@ var htmlInlineRule = {
|
|
|
11498
12663
|
}
|
|
11499
12664
|
};
|
|
11500
12665
|
|
|
12666
|
+
// packages/parser/src/parser/rules/inline/raw/angle.ts
|
|
12667
|
+
var import_entities = require("entities");
|
|
12668
|
+
|
|
11501
12669
|
// packages/parser/src/parser/rules/inline/raw/result.ts
|
|
11502
12670
|
function rawElement(value, consumed) {
|
|
11503
12671
|
return {
|
|
@@ -11545,7 +12713,7 @@ function parseAngleRaw(ctx) {
|
|
|
11545
12713
|
if (ctx.tokens[pos]?.type === "RAW_BLOCK_CLOSE") {
|
|
11546
12714
|
consumed++;
|
|
11547
12715
|
}
|
|
11548
|
-
return rawElement(value, consumed);
|
|
12716
|
+
return rawElement(import_entities.decodeHTML(value), consumed);
|
|
11549
12717
|
}
|
|
11550
12718
|
|
|
11551
12719
|
// packages/parser/src/parser/rules/inline/raw/double-at.ts
|
|
@@ -11768,7 +12936,7 @@ function consumeSpanNewline(ctx, pos, paragraphStrip, afterBlankLine, children,
|
|
|
11768
12936
|
return { consumed: consumed2, afterBlankLine: paragraphStrip };
|
|
11769
12937
|
}
|
|
11770
12938
|
const targetChildren = paragraphStrip && afterBlankLine ? escapedChildren : children;
|
|
11771
|
-
targetChildren.push(
|
|
12939
|
+
targetChildren.push(createAutomaticLineBreak(ctx.tokens[pos]));
|
|
11772
12940
|
let consumed = 1;
|
|
11773
12941
|
let nextPos = pos + 1;
|
|
11774
12942
|
while (ctx.tokens[nextPos]?.type === "WHITESPACE" && ctx.tokens[nextPos]?.lineStart) {
|
|
@@ -11856,7 +13024,9 @@ function parseOneSpanChild(ctx, pos, targetChildren) {
|
|
|
11856
13024
|
for (const rule of getCandidateInlineRules(inlineRules, token5.type)) {
|
|
11857
13025
|
const result = rule.parse(inlineCtx);
|
|
11858
13026
|
if (result.success) {
|
|
11859
|
-
targetChildren
|
|
13027
|
+
stripAutomaticLineBreak(targetChildren, result.stripLeadingLineBreak);
|
|
13028
|
+
for (const element of result.elements)
|
|
13029
|
+
targetChildren.push(element);
|
|
11860
13030
|
return { consumed: result.consumed };
|
|
11861
13031
|
}
|
|
11862
13032
|
}
|
|
@@ -11924,56 +13094,60 @@ var closeSpanRule = {
|
|
|
11924
13094
|
}
|
|
11925
13095
|
};
|
|
11926
13096
|
|
|
11927
|
-
// packages/parser/src/parser/rules/inline/
|
|
11928
|
-
|
|
11929
|
-
|
|
11930
|
-
|
|
11931
|
-
|
|
11932
|
-
|
|
11933
|
-
|
|
11934
|
-
|
|
11935
|
-
|
|
11936
|
-
|
|
11937
|
-
|
|
11938
|
-
if (closeResult) {
|
|
11939
|
-
return {
|
|
11940
|
-
children,
|
|
11941
|
-
consumed: consumed + closeResult.consumed,
|
|
11942
|
-
foundClose: true
|
|
11943
|
-
};
|
|
11944
|
-
}
|
|
11945
|
-
const inlineCtx = { ...ctx, pos };
|
|
11946
|
-
const inlineResult = parseInlineUntil(inlineCtx, "BLOCK_END_OPEN");
|
|
11947
|
-
if (inlineResult.elements.length > 0) {
|
|
11948
|
-
children.push(...inlineResult.elements);
|
|
11949
|
-
pos += inlineResult.consumed;
|
|
11950
|
-
consumed += inlineResult.consumed;
|
|
11951
|
-
} else {
|
|
11952
|
-
children.push({ element: "text", data: token5.value });
|
|
11953
|
-
pos++;
|
|
11954
|
-
consumed++;
|
|
11955
|
-
}
|
|
11956
|
-
}
|
|
11957
|
-
return { children, consumed, foundClose: false };
|
|
11958
|
-
}
|
|
11959
|
-
function tryConsumeSizeClose(ctx, pos) {
|
|
11960
|
-
if (ctx.tokens[pos]?.type !== "BLOCK_END_OPEN") {
|
|
11961
|
-
return null;
|
|
13097
|
+
// packages/parser/src/parser/rules/inline/button/index.ts
|
|
13098
|
+
var buttonRule = {
|
|
13099
|
+
name: "button",
|
|
13100
|
+
startTokens: ["BLOCK_OPEN"],
|
|
13101
|
+
parse(ctx) {
|
|
13102
|
+
const result = parseButtonSyntax(ctx, ctx.pos, ctx.scope.inlineEnd ?? ctx.tokens.length);
|
|
13103
|
+
return result ? {
|
|
13104
|
+
success: true,
|
|
13105
|
+
consumed: result.end - ctx.pos,
|
|
13106
|
+
elements: [{ element: "button", data: result.data }]
|
|
13107
|
+
} : { success: false };
|
|
11962
13108
|
}
|
|
11963
|
-
|
|
11964
|
-
|
|
11965
|
-
|
|
13109
|
+
};
|
|
13110
|
+
|
|
13111
|
+
// packages/parser/src/parser/rules/inline/social/index.ts
|
|
13112
|
+
var socialRule = {
|
|
13113
|
+
name: "social",
|
|
13114
|
+
startTokens: ["BLOCK_OPEN"],
|
|
13115
|
+
parse(ctx) {
|
|
13116
|
+
const result = parseSocialSyntax(ctx, ctx.pos, ctx.scope.inlineEnd ?? ctx.tokens.length);
|
|
13117
|
+
return result ? {
|
|
13118
|
+
success: true,
|
|
13119
|
+
consumed: result.end - ctx.pos,
|
|
13120
|
+
elements: [{ element: "social", data: result.data }]
|
|
13121
|
+
} : { success: false };
|
|
11966
13122
|
}
|
|
11967
|
-
|
|
11968
|
-
|
|
11969
|
-
|
|
11970
|
-
|
|
13123
|
+
};
|
|
13124
|
+
|
|
13125
|
+
// packages/parser/src/parser/rules/inline/date/index.ts
|
|
13126
|
+
var dateRule = {
|
|
13127
|
+
name: "date",
|
|
13128
|
+
startTokens: ["BLOCK_OPEN"],
|
|
13129
|
+
parse(ctx) {
|
|
13130
|
+
const parsed = parseDateSyntax(ctx, ctx.pos, ctx.scope.inlineEnd ?? ctx.tokens.length);
|
|
13131
|
+
return parsed ? {
|
|
13132
|
+
success: true,
|
|
13133
|
+
consumed: parsed.end - ctx.pos,
|
|
13134
|
+
elements: [{ element: "date", data: parsed.data }]
|
|
13135
|
+
} : { success: false };
|
|
11971
13136
|
}
|
|
11972
|
-
|
|
11973
|
-
}
|
|
13137
|
+
};
|
|
11974
13138
|
|
|
11975
13139
|
// packages/parser/src/parser/rules/inline/size/value.ts
|
|
11976
13140
|
var VALID_SIZE_UNITS = ["px", "em", "rem", "ex", "%", "cm", "mm", "in", "pc"];
|
|
13141
|
+
var VALID_SIZE_KEYWORDS = [
|
|
13142
|
+
"smaller",
|
|
13143
|
+
"larger",
|
|
13144
|
+
"xx-small",
|
|
13145
|
+
"x-small",
|
|
13146
|
+
"small",
|
|
13147
|
+
"large",
|
|
13148
|
+
"x-large",
|
|
13149
|
+
"xx-large"
|
|
13150
|
+
];
|
|
11977
13151
|
function parseSizeValue(ctx, startPos) {
|
|
11978
13152
|
let pos = startPos;
|
|
11979
13153
|
let consumed = 0;
|
|
@@ -11998,6 +13172,8 @@ function parseSizeValue(ctx, startPos) {
|
|
|
11998
13172
|
return isValidSizeValue(size) ? { size, consumed } : null;
|
|
11999
13173
|
}
|
|
12000
13174
|
function isValidSizeValue(size) {
|
|
13175
|
+
if (VALID_SIZE_KEYWORDS.includes(size))
|
|
13176
|
+
return true;
|
|
12001
13177
|
const unitPattern = VALID_SIZE_UNITS.join("|");
|
|
12002
13178
|
return new RegExp(`^(\\d+(?:\\.\\d+)?)(${unitPattern})$`, "i").test(size);
|
|
12003
13179
|
}
|
|
@@ -12029,6 +13205,81 @@ function parseSizeOpen(ctx) {
|
|
|
12029
13205
|
return { size: sizeResult.size, bodyStart: pos, consumed };
|
|
12030
13206
|
}
|
|
12031
13207
|
|
|
13208
|
+
// packages/parser/src/parser/rules/inline/size/content.ts
|
|
13209
|
+
function parseSizeContent(ctx, startPos) {
|
|
13210
|
+
const children = [];
|
|
13211
|
+
let pos = startPos;
|
|
13212
|
+
let consumed = 0;
|
|
13213
|
+
const inlineEnd = findSizeClose(ctx, startPos);
|
|
13214
|
+
while (pos < (ctx.scope.inlineEnd ?? ctx.tokens.length)) {
|
|
13215
|
+
const token5 = ctx.tokens[pos];
|
|
13216
|
+
if (!token5 || token5.type === "EOF") {
|
|
13217
|
+
break;
|
|
13218
|
+
}
|
|
13219
|
+
const closeResult = tryConsumeSizeClose(ctx, pos);
|
|
13220
|
+
if (closeResult) {
|
|
13221
|
+
return {
|
|
13222
|
+
children,
|
|
13223
|
+
consumed: consumed + closeResult.consumed,
|
|
13224
|
+
foundClose: true
|
|
13225
|
+
};
|
|
13226
|
+
}
|
|
13227
|
+
const inlineCtx = { ...ctx, pos, scope: { ...ctx.scope, inlineEnd } };
|
|
13228
|
+
const inlineResult = parseInlineUntil(inlineCtx, "EOF");
|
|
13229
|
+
if (inlineResult.consumed > 0) {
|
|
13230
|
+
for (const element of inlineResult.elements)
|
|
13231
|
+
children.push(element);
|
|
13232
|
+
pos += inlineResult.consumed;
|
|
13233
|
+
consumed += inlineResult.consumed;
|
|
13234
|
+
} else {
|
|
13235
|
+
children.push({ element: "text", data: token5.value });
|
|
13236
|
+
pos++;
|
|
13237
|
+
consumed++;
|
|
13238
|
+
}
|
|
13239
|
+
}
|
|
13240
|
+
return { children, consumed, foundClose: false };
|
|
13241
|
+
}
|
|
13242
|
+
function findSizeClose(ctx, startPos) {
|
|
13243
|
+
const end = ctx.scope.inlineEnd ?? ctx.tokens.length;
|
|
13244
|
+
let depth = 0;
|
|
13245
|
+
for (let pos = startPos;pos < end; pos++) {
|
|
13246
|
+
const protectedEnd = protectedInlineRegionEnd(ctx.tokens, pos, end);
|
|
13247
|
+
if (protectedEnd > pos) {
|
|
13248
|
+
pos = protectedEnd - 1;
|
|
13249
|
+
continue;
|
|
13250
|
+
}
|
|
13251
|
+
const open = ctx.tokens[pos]?.type === "BLOCK_OPEN" ? parseSizeOpen({ ...ctx, pos }) : null;
|
|
13252
|
+
if (open) {
|
|
13253
|
+
depth++;
|
|
13254
|
+
pos = open.bodyStart - 1;
|
|
13255
|
+
continue;
|
|
13256
|
+
}
|
|
13257
|
+
const close = tryConsumeSizeClose(ctx, pos);
|
|
13258
|
+
if (!close)
|
|
13259
|
+
continue;
|
|
13260
|
+
if (depth === 0)
|
|
13261
|
+
return pos;
|
|
13262
|
+
depth--;
|
|
13263
|
+
pos += close.consumed - 1;
|
|
13264
|
+
}
|
|
13265
|
+
return end;
|
|
13266
|
+
}
|
|
13267
|
+
function tryConsumeSizeClose(ctx, pos) {
|
|
13268
|
+
if (ctx.tokens[pos]?.type !== "BLOCK_END_OPEN") {
|
|
13269
|
+
return null;
|
|
13270
|
+
}
|
|
13271
|
+
const closeNameResult = parseBlockName(ctx, pos + 1);
|
|
13272
|
+
if (!closeNameResult || closeNameResult.name !== "size") {
|
|
13273
|
+
return null;
|
|
13274
|
+
}
|
|
13275
|
+
let closePos = pos + 1 + closeNameResult.consumed;
|
|
13276
|
+
let consumed = 1 + closeNameResult.consumed;
|
|
13277
|
+
if (ctx.tokens[closePos]?.type === "BLOCK_CLOSE") {
|
|
13278
|
+
consumed++;
|
|
13279
|
+
}
|
|
13280
|
+
return { consumed };
|
|
13281
|
+
}
|
|
13282
|
+
|
|
12032
13283
|
// packages/parser/src/parser/rules/inline/size/index.ts
|
|
12033
13284
|
var sizeRule = {
|
|
12034
13285
|
name: "size",
|
|
@@ -12069,19 +13320,6 @@ var sizeRule = {
|
|
|
12069
13320
|
}
|
|
12070
13321
|
};
|
|
12071
13322
|
|
|
12072
|
-
// packages/parser/src/parser/rules/inline/footnote/child.ts
|
|
12073
|
-
function parseFootnoteChild(ctx, pos) {
|
|
12074
|
-
const token5 = ctx.tokens[pos];
|
|
12075
|
-
if (!token5) {
|
|
12076
|
-
return { elements: [], consumed: 0 };
|
|
12077
|
-
}
|
|
12078
|
-
const inlineResult = parseInlineUntil({ ...ctx, pos }, "BLOCK_END_OPEN");
|
|
12079
|
-
if (inlineResult.elements.length > 0) {
|
|
12080
|
-
return { elements: inlineResult.elements, consumed: inlineResult.consumed };
|
|
12081
|
-
}
|
|
12082
|
-
return { elements: [{ element: "text", data: token5.value }], consumed: 1 };
|
|
12083
|
-
}
|
|
12084
|
-
|
|
12085
13323
|
// packages/parser/src/parser/rules/inline/footnote/close.ts
|
|
12086
13324
|
function tryConsumeFootnoteClose(ctx, pos) {
|
|
12087
13325
|
if (ctx.tokens[pos]?.type !== "BLOCK_END_OPEN") {
|
|
@@ -12103,96 +13341,73 @@ function tryConsumeFootnoteClose(ctx, pos) {
|
|
|
12103
13341
|
return { consumed };
|
|
12104
13342
|
}
|
|
12105
13343
|
|
|
12106
|
-
// packages/parser/src/parser/rules/inline/
|
|
12107
|
-
function
|
|
12108
|
-
let nextPos = pos + 1;
|
|
12109
|
-
let consumed = 1;
|
|
12110
|
-
while (ctx.tokens[nextPos]?.type === "WHITESPACE") {
|
|
12111
|
-
nextPos++;
|
|
12112
|
-
consumed++;
|
|
12113
|
-
}
|
|
12114
|
-
if (ctx.tokens[nextPos]?.type !== "NEWLINE") {
|
|
12115
|
-
return { consumed, paragraphBreak: false };
|
|
12116
|
-
}
|
|
12117
|
-
while (ctx.tokens[nextPos]?.type === "NEWLINE") {
|
|
12118
|
-
nextPos++;
|
|
12119
|
-
consumed++;
|
|
12120
|
-
}
|
|
12121
|
-
return { consumed, paragraphBreak: true };
|
|
12122
|
-
}
|
|
12123
|
-
|
|
12124
|
-
// packages/parser/src/parser/rules/inline/footnote/content.ts
|
|
12125
|
-
function parseFootnoteContent(ctx, startPos) {
|
|
12126
|
-
const paragraphs = [[]];
|
|
12127
|
-
let currentParagraph = 0;
|
|
13344
|
+
// packages/parser/src/parser/rules/inline/math-inline/syntax.ts
|
|
13345
|
+
function parseInlineMathSource(ctx, startPos) {
|
|
12128
13346
|
let pos = startPos;
|
|
12129
13347
|
let consumed = 0;
|
|
13348
|
+
if (ctx.tokens[pos]?.type !== "TEXT" || ctx.tokens[pos]?.value !== "$") {
|
|
13349
|
+
return null;
|
|
13350
|
+
}
|
|
13351
|
+
pos++;
|
|
13352
|
+
consumed++;
|
|
13353
|
+
while (ctx.tokens[pos]?.type === "WHITESPACE") {
|
|
13354
|
+
pos++;
|
|
13355
|
+
consumed++;
|
|
13356
|
+
}
|
|
13357
|
+
let latexSource = "";
|
|
12130
13358
|
while (pos < ctx.tokens.length) {
|
|
12131
13359
|
const token5 = ctx.tokens[pos];
|
|
12132
|
-
if (!token5 || token5.type === "
|
|
12133
|
-
|
|
12134
|
-
}
|
|
12135
|
-
const closeResult = tryConsumeFootnoteClose(ctx, pos);
|
|
12136
|
-
if (closeResult) {
|
|
12137
|
-
return {
|
|
12138
|
-
paragraphs,
|
|
12139
|
-
consumed: consumed + closeResult.consumed,
|
|
12140
|
-
foundClose: true
|
|
12141
|
-
};
|
|
13360
|
+
if (!token5 || token5.type === "NEWLINE") {
|
|
13361
|
+
return null;
|
|
12142
13362
|
}
|
|
12143
|
-
if (token5.type === "
|
|
12144
|
-
|
|
12145
|
-
pos += newlineResult.consumed;
|
|
12146
|
-
consumed += newlineResult.consumed;
|
|
12147
|
-
if (newlineResult.paragraphBreak) {
|
|
12148
|
-
currentParagraph++;
|
|
12149
|
-
paragraphs[currentParagraph] = [];
|
|
12150
|
-
} else {
|
|
12151
|
-
paragraphs[currentParagraph].push({ element: "line-break" });
|
|
12152
|
-
}
|
|
12153
|
-
continue;
|
|
13363
|
+
if (token5.type === "TEXT" && token5.value === "$" && ctx.tokens[pos + 1]?.type === "BLOCK_CLOSE") {
|
|
13364
|
+
break;
|
|
12154
13365
|
}
|
|
12155
|
-
|
|
12156
|
-
|
|
12157
|
-
|
|
12158
|
-
|
|
13366
|
+
latexSource += token5.value;
|
|
13367
|
+
pos++;
|
|
13368
|
+
consumed++;
|
|
13369
|
+
}
|
|
13370
|
+
if (ctx.tokens[pos]?.type !== "TEXT" || ctx.tokens[pos]?.value !== "$") {
|
|
13371
|
+
return null;
|
|
13372
|
+
}
|
|
13373
|
+
pos++;
|
|
13374
|
+
consumed++;
|
|
13375
|
+
if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
|
|
13376
|
+
return null;
|
|
12159
13377
|
}
|
|
12160
|
-
return {
|
|
13378
|
+
return {
|
|
13379
|
+
latexSource: latexSource.trim(),
|
|
13380
|
+
consumed: consumed + 1
|
|
13381
|
+
};
|
|
12161
13382
|
}
|
|
12162
13383
|
|
|
12163
|
-
// packages/parser/src/parser/rules/inline/
|
|
12164
|
-
|
|
12165
|
-
|
|
12166
|
-
|
|
12167
|
-
|
|
12168
|
-
|
|
12169
|
-
|
|
13384
|
+
// packages/parser/src/parser/rules/inline/math-inline/index.ts
|
|
13385
|
+
var mathInlineRule = {
|
|
13386
|
+
name: "math-inline",
|
|
13387
|
+
startTokens: ["BLOCK_OPEN"],
|
|
13388
|
+
parse(ctx) {
|
|
13389
|
+
const openToken = currentToken(ctx);
|
|
13390
|
+
if (openToken.type !== "BLOCK_OPEN") {
|
|
13391
|
+
return { success: false };
|
|
12170
13392
|
}
|
|
12171
|
-
|
|
12172
|
-
|
|
12173
|
-
|
|
12174
|
-
children.push({
|
|
12175
|
-
element: "container",
|
|
12176
|
-
data: {
|
|
12177
|
-
type: "paragraph",
|
|
12178
|
-
attributes: {},
|
|
12179
|
-
elements: para
|
|
12180
|
-
}
|
|
12181
|
-
});
|
|
13393
|
+
const parsed = parseInlineMathSource(ctx, ctx.pos + 1);
|
|
13394
|
+
if (!parsed) {
|
|
13395
|
+
return { success: false };
|
|
12182
13396
|
}
|
|
13397
|
+
return {
|
|
13398
|
+
success: true,
|
|
13399
|
+
elements: [
|
|
13400
|
+
{
|
|
13401
|
+
element: "math-inline",
|
|
13402
|
+
data: {
|
|
13403
|
+
"latex-source": parsed.latexSource
|
|
13404
|
+
}
|
|
13405
|
+
}
|
|
13406
|
+
],
|
|
13407
|
+
consumed: 1 + parsed.consumed
|
|
13408
|
+
};
|
|
12183
13409
|
}
|
|
12184
|
-
|
|
12185
|
-
}
|
|
12186
|
-
function trimLineBreaks(elements) {
|
|
12187
|
-
const result = [...elements];
|
|
12188
|
-
while (result.length > 0 && result[0]?.element === "line-break") {
|
|
12189
|
-
result.shift();
|
|
12190
|
-
}
|
|
12191
|
-
while (result.length > 0 && result[result.length - 1]?.element === "line-break") {
|
|
12192
|
-
result.pop();
|
|
12193
|
-
}
|
|
12194
|
-
return result;
|
|
12195
|
-
}
|
|
13410
|
+
};
|
|
12196
13411
|
|
|
12197
13412
|
// packages/parser/src/parser/rules/inline/footnote/open.ts
|
|
12198
13413
|
function parseFootnoteOpen(ctx) {
|
|
@@ -12219,6 +13434,91 @@ function parseFootnoteOpen(ctx) {
|
|
|
12219
13434
|
return { bodyStart: pos, consumed };
|
|
12220
13435
|
}
|
|
12221
13436
|
|
|
13437
|
+
// packages/parser/src/parser/rules/inline/footnote/boundary.ts
|
|
13438
|
+
var opaqueRules2 = [
|
|
13439
|
+
codeBlockRule,
|
|
13440
|
+
htmlBlockRule,
|
|
13441
|
+
mathBlockRule,
|
|
13442
|
+
mathInlineRule,
|
|
13443
|
+
linkTripleRule,
|
|
13444
|
+
linkSingleRule,
|
|
13445
|
+
linkStarRule,
|
|
13446
|
+
linkAnchorRule
|
|
13447
|
+
];
|
|
13448
|
+
function findFootnoteEnd(ctx, start) {
|
|
13449
|
+
const probe = createOpaqueProbe(ctx);
|
|
13450
|
+
let depth = 0;
|
|
13451
|
+
for (let pos = start;pos < ctx.tokens.length; pos++) {
|
|
13452
|
+
if (ctx.tokens[pos]?.type === "EOF")
|
|
13453
|
+
return pos;
|
|
13454
|
+
const protectedEnd = protectedInlineRegionEnd(ctx.tokens, pos, ctx.tokens.length);
|
|
13455
|
+
if (protectedEnd > pos) {
|
|
13456
|
+
pos = protectedEnd - 1;
|
|
13457
|
+
continue;
|
|
13458
|
+
}
|
|
13459
|
+
probe.pos = pos;
|
|
13460
|
+
const close = tryConsumeFootnoteClose(probe, pos);
|
|
13461
|
+
if (close) {
|
|
13462
|
+
if (depth === 0)
|
|
13463
|
+
return pos;
|
|
13464
|
+
depth--;
|
|
13465
|
+
pos += close.consumed - 1;
|
|
13466
|
+
continue;
|
|
13467
|
+
}
|
|
13468
|
+
const open = parseFootnoteOpen(probe);
|
|
13469
|
+
if (open) {
|
|
13470
|
+
depth++;
|
|
13471
|
+
pos += open.consumed - 1;
|
|
13472
|
+
continue;
|
|
13473
|
+
}
|
|
13474
|
+
const opaqueEnd = opaqueRuleEnd(probe, pos, opaqueRules2);
|
|
13475
|
+
if (opaqueEnd > pos)
|
|
13476
|
+
pos = opaqueEnd - 1;
|
|
13477
|
+
}
|
|
13478
|
+
return ctx.tokens.length;
|
|
13479
|
+
}
|
|
13480
|
+
|
|
13481
|
+
// packages/parser/src/parser/rules/inline/footnote/content.ts
|
|
13482
|
+
function parseFootnoteContent(ctx, startPos) {
|
|
13483
|
+
const end = findFootnoteEnd(ctx, startPos);
|
|
13484
|
+
let leadingNewlines = 0;
|
|
13485
|
+
for (let pos = startPos;pos < end; pos++) {
|
|
13486
|
+
const type = ctx.tokens[pos]?.type;
|
|
13487
|
+
if (type === "NEWLINE")
|
|
13488
|
+
leadingNewlines++;
|
|
13489
|
+
else if (type !== "WHITESPACE")
|
|
13490
|
+
break;
|
|
13491
|
+
}
|
|
13492
|
+
const bodyCtx = {
|
|
13493
|
+
...ctx,
|
|
13494
|
+
tokens: ctx.tokens.slice(startPos, end),
|
|
13495
|
+
pos: 0,
|
|
13496
|
+
scope: {
|
|
13497
|
+
...ctx.scope,
|
|
13498
|
+
inlineEnd: undefined,
|
|
13499
|
+
tableFormatting: undefined,
|
|
13500
|
+
blockCloseCondition: undefined
|
|
13501
|
+
}
|
|
13502
|
+
};
|
|
13503
|
+
const result = parseBlocksUntil(bodyCtx, () => false);
|
|
13504
|
+
const close = tryConsumeFootnoteClose(ctx, end);
|
|
13505
|
+
return {
|
|
13506
|
+
elements: result.elements,
|
|
13507
|
+
consumed: end - startPos + (close?.consumed ?? 0),
|
|
13508
|
+
foundClose: close !== null,
|
|
13509
|
+
leadingParagraphBreak: leadingNewlines >= 2
|
|
13510
|
+
};
|
|
13511
|
+
}
|
|
13512
|
+
|
|
13513
|
+
// packages/parser/src/parser/rules/inline/footnote/elements.ts
|
|
13514
|
+
function buildFootnoteChildren(elements, leadingParagraphBreak) {
|
|
13515
|
+
const first = elements[0];
|
|
13516
|
+
if (!leadingParagraphBreak && first?.element === "container" && first.data.type === "paragraph") {
|
|
13517
|
+
return [...first.data.elements, ...elements.slice(1)];
|
|
13518
|
+
}
|
|
13519
|
+
return elements;
|
|
13520
|
+
}
|
|
13521
|
+
|
|
12222
13522
|
// packages/parser/src/parser/rules/inline/footnote/index.ts
|
|
12223
13523
|
var footnoteRule = {
|
|
12224
13524
|
name: "footnote",
|
|
@@ -12234,7 +13534,7 @@ var footnoteRule = {
|
|
|
12234
13534
|
}
|
|
12235
13535
|
const contentResult = parseFootnoteContent(ctx, openResult.bodyStart);
|
|
12236
13536
|
const consumed = openResult.consumed + contentResult.consumed;
|
|
12237
|
-
const children = buildFootnoteChildren(contentResult.
|
|
13537
|
+
const children = buildFootnoteChildren(contentResult.elements, contentResult.leadingParagraphBreak);
|
|
12238
13538
|
if (!contentResult.foundClose) {
|
|
12239
13539
|
ctx.diagnostics.push({
|
|
12240
13540
|
severity: "warning",
|
|
@@ -12594,11 +13894,15 @@ function parseAnchorChild(ctx, pos) {
|
|
|
12594
13894
|
if (!token5) {
|
|
12595
13895
|
return { elements: [], consumed: 0 };
|
|
12596
13896
|
}
|
|
12597
|
-
const inlineCtx = {
|
|
13897
|
+
const inlineCtx = {
|
|
13898
|
+
...ctx,
|
|
13899
|
+
pos,
|
|
13900
|
+
scope: { ...ctx.scope, suppressEmailLinks: true }
|
|
13901
|
+
};
|
|
12598
13902
|
for (const rule of getCandidateInlineRules(inlineRules, token5.type)) {
|
|
12599
13903
|
const result = rule.parse(inlineCtx);
|
|
12600
13904
|
if (result.success) {
|
|
12601
|
-
return
|
|
13905
|
+
return result;
|
|
12602
13906
|
}
|
|
12603
13907
|
}
|
|
12604
13908
|
return { elements: [{ element: "text", data: token5.value }], consumed: 1 };
|
|
@@ -12658,7 +13962,7 @@ function consumeAnchorNewline(ctx, pos, paragraphStrip, children) {
|
|
|
12658
13962
|
let consumed = 1;
|
|
12659
13963
|
let nextPos = pos + 1;
|
|
12660
13964
|
if (!paragraphStrip) {
|
|
12661
|
-
children.push(
|
|
13965
|
+
children.push(createAutomaticLineBreak(ctx.tokens[pos]));
|
|
12662
13966
|
while (ctx.tokens[nextPos]?.type === "WHITESPACE" && ctx.tokens[nextPos]?.lineStart) {
|
|
12663
13967
|
nextPos++;
|
|
12664
13968
|
consumed++;
|
|
@@ -12711,7 +14015,9 @@ function parseAnchorContent(ctx, startPos, paragraphStrip) {
|
|
|
12711
14015
|
continue;
|
|
12712
14016
|
}
|
|
12713
14017
|
const child = parseAnchorChild(ctx, pos);
|
|
12714
|
-
children
|
|
14018
|
+
stripAutomaticLineBreak(children, child.stripLeadingLineBreak);
|
|
14019
|
+
for (const element of child.elements)
|
|
14020
|
+
children.push(element);
|
|
12715
14021
|
pos += child.consumed;
|
|
12716
14022
|
consumed += child.consumed;
|
|
12717
14023
|
}
|
|
@@ -12785,75 +14091,8 @@ var anchorRule = {
|
|
|
12785
14091
|
}
|
|
12786
14092
|
}
|
|
12787
14093
|
],
|
|
12788
|
-
consumed
|
|
12789
|
-
|
|
12790
|
-
}
|
|
12791
|
-
};
|
|
12792
|
-
|
|
12793
|
-
// packages/parser/src/parser/rules/inline/math-inline/syntax.ts
|
|
12794
|
-
function parseInlineMathSource(ctx, startPos) {
|
|
12795
|
-
let pos = startPos;
|
|
12796
|
-
let consumed = 0;
|
|
12797
|
-
if (ctx.tokens[pos]?.type !== "TEXT" || ctx.tokens[pos]?.value !== "$") {
|
|
12798
|
-
return null;
|
|
12799
|
-
}
|
|
12800
|
-
pos++;
|
|
12801
|
-
consumed++;
|
|
12802
|
-
while (ctx.tokens[pos]?.type === "WHITESPACE") {
|
|
12803
|
-
pos++;
|
|
12804
|
-
consumed++;
|
|
12805
|
-
}
|
|
12806
|
-
let latexSource = "";
|
|
12807
|
-
while (pos < ctx.tokens.length) {
|
|
12808
|
-
const token5 = ctx.tokens[pos];
|
|
12809
|
-
if (!token5 || token5.type === "NEWLINE") {
|
|
12810
|
-
return null;
|
|
12811
|
-
}
|
|
12812
|
-
if (token5.type === "TEXT" && token5.value === "$" && ctx.tokens[pos + 1]?.type === "BLOCK_CLOSE") {
|
|
12813
|
-
break;
|
|
12814
|
-
}
|
|
12815
|
-
latexSource += token5.value;
|
|
12816
|
-
pos++;
|
|
12817
|
-
consumed++;
|
|
12818
|
-
}
|
|
12819
|
-
if (ctx.tokens[pos]?.type !== "TEXT" || ctx.tokens[pos]?.value !== "$") {
|
|
12820
|
-
return null;
|
|
12821
|
-
}
|
|
12822
|
-
pos++;
|
|
12823
|
-
consumed++;
|
|
12824
|
-
if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
|
|
12825
|
-
return null;
|
|
12826
|
-
}
|
|
12827
|
-
return {
|
|
12828
|
-
latexSource: latexSource.trim(),
|
|
12829
|
-
consumed: consumed + 1
|
|
12830
|
-
};
|
|
12831
|
-
}
|
|
12832
|
-
|
|
12833
|
-
// packages/parser/src/parser/rules/inline/math-inline/index.ts
|
|
12834
|
-
var mathInlineRule = {
|
|
12835
|
-
name: "math-inline",
|
|
12836
|
-
startTokens: ["BLOCK_OPEN"],
|
|
12837
|
-
parse(ctx) {
|
|
12838
|
-
const openToken = currentToken(ctx);
|
|
12839
|
-
if (openToken.type !== "BLOCK_OPEN") {
|
|
12840
|
-
return { success: false };
|
|
12841
|
-
}
|
|
12842
|
-
const parsed = parseInlineMathSource(ctx, ctx.pos + 1);
|
|
12843
|
-
if (!parsed) {
|
|
12844
|
-
return { success: false };
|
|
12845
|
-
}
|
|
12846
|
-
return {
|
|
12847
|
-
success: true,
|
|
12848
|
-
elements: [
|
|
12849
|
-
{
|
|
12850
|
-
element: "math-inline",
|
|
12851
|
-
data: {
|
|
12852
|
-
"latex-source": parsed.latexSource
|
|
12853
|
-
}
|
|
12854
|
-
}
|
|
12855
|
-
],
|
|
12856
|
-
consumed: 1 + parsed.consumed
|
|
14094
|
+
consumed,
|
|
14095
|
+
stripLeadingLineBreak: openResult.paragraphStrip ? precedingSingleNewline(ctx) : undefined
|
|
12857
14096
|
};
|
|
12858
14097
|
}
|
|
12859
14098
|
};
|
|
@@ -12964,7 +14203,9 @@ function parseInlineBranch(ctx, startPos) {
|
|
|
12964
14203
|
}
|
|
12965
14204
|
const result = rule.parse(inlineCtx);
|
|
12966
14205
|
if (result.success) {
|
|
12967
|
-
elements
|
|
14206
|
+
stripAutomaticLineBreak(elements, result.stripLeadingLineBreak);
|
|
14207
|
+
for (const element of result.elements)
|
|
14208
|
+
elements.push(element);
|
|
12968
14209
|
consumed += result.consumed;
|
|
12969
14210
|
pos += result.consumed;
|
|
12970
14211
|
matched = true;
|
|
@@ -13287,6 +14528,7 @@ var textRule = {
|
|
|
13287
14528
|
|
|
13288
14529
|
// packages/parser/src/parser/rules/inline/index.ts
|
|
13289
14530
|
var inlineRules = [
|
|
14531
|
+
emailRule,
|
|
13290
14532
|
boldRule,
|
|
13291
14533
|
italicRule,
|
|
13292
14534
|
underlineRule,
|
|
@@ -13298,6 +14540,7 @@ var inlineRules = [
|
|
|
13298
14540
|
linkSingleRule,
|
|
13299
14541
|
linkAnchorRule,
|
|
13300
14542
|
linkStarRule,
|
|
14543
|
+
autolinkRule,
|
|
13301
14544
|
colorRule,
|
|
13302
14545
|
backslashLineBreakRule,
|
|
13303
14546
|
underscoreLineBreakRule,
|
|
@@ -13307,6 +14550,9 @@ var inlineRules = [
|
|
|
13307
14550
|
rawRule,
|
|
13308
14551
|
imageRule,
|
|
13309
14552
|
embedBlockRule,
|
|
14553
|
+
buttonRule,
|
|
14554
|
+
socialRule,
|
|
14555
|
+
dateRule,
|
|
13310
14556
|
sizeRule,
|
|
13311
14557
|
footnoteRule,
|
|
13312
14558
|
spanRule,
|
|
@@ -13330,7 +14576,7 @@ function createParseContext(tokens, options = {}, deferInclude) {
|
|
|
13330
14576
|
pos: 0,
|
|
13331
14577
|
version: options.version ?? "wikidot",
|
|
13332
14578
|
trackPositions: options.trackPositions ?? true,
|
|
13333
|
-
settings: options.settings ??
|
|
14579
|
+
settings: options.settings ?? import_ast9.DEFAULT_SETTINGS,
|
|
13334
14580
|
appendImplicitFootnoteBlock: options.appendImplicitFootnoteBlock ?? true,
|
|
13335
14581
|
deferInclude,
|
|
13336
14582
|
footnotes: [],
|
|
@@ -13562,6 +14808,8 @@ function mergeSpanStripParagraphs(children) {
|
|
|
13562
14808
|
i++;
|
|
13563
14809
|
continue;
|
|
13564
14810
|
}
|
|
14811
|
+
const firstMeaningful = paraData.elements.find((child) => child.element !== "line-break" && !isWhitespaceText(child));
|
|
14812
|
+
const keepParagraph = firstMeaningful && !isSpanStripMarker(firstMeaningful);
|
|
13565
14813
|
const mergedChildren = [...paraData.elements];
|
|
13566
14814
|
i++;
|
|
13567
14815
|
while (i < expandedChildren.length) {
|
|
@@ -13574,7 +14822,8 @@ function mergeSpanStripParagraphs(children) {
|
|
|
13574
14822
|
break;
|
|
13575
14823
|
}
|
|
13576
14824
|
const hasSpanStrip = hasParagraphStripSpan(nextPara);
|
|
13577
|
-
|
|
14825
|
+
for (const element of nextParaData.elements)
|
|
14826
|
+
mergedChildren.push(element);
|
|
13578
14827
|
i++;
|
|
13579
14828
|
if (!hasSpanStrip) {
|
|
13580
14829
|
const peekNext = expandedChildren[i];
|
|
@@ -13585,7 +14834,7 @@ function mergeSpanStripParagraphs(children) {
|
|
|
13585
14834
|
}
|
|
13586
14835
|
const escapedSpans = extractEscapedSpans(mergedChildren);
|
|
13587
14836
|
removeLineBreaksAroundSpanStrip(mergedChildren);
|
|
13588
|
-
if (escapedSpans.length > 0) {
|
|
14837
|
+
if (escapedSpans.length > 0 || keepParagraph) {
|
|
13589
14838
|
if (mergedChildren.length > 0) {
|
|
13590
14839
|
result.push(paragraphElement(mergedChildren));
|
|
13591
14840
|
}
|
|
@@ -13806,50 +15055,6 @@ function cleanInternalFlags(elements) {
|
|
|
13806
15055
|
}
|
|
13807
15056
|
return removeEmptySpansAndAdjacentWhitespace(cleaned ?? elements);
|
|
13808
15057
|
}
|
|
13809
|
-
// packages/parser/src/parser/postprocess/divAdjacentParagraph.ts
|
|
13810
|
-
function isParagraphContainer2(el) {
|
|
13811
|
-
if (!el || el.element !== "container")
|
|
13812
|
-
return false;
|
|
13813
|
-
return el.data.type === "paragraph";
|
|
13814
|
-
}
|
|
13815
|
-
function isDivContainer(el) {
|
|
13816
|
-
if (!el || el.element !== "container")
|
|
13817
|
-
return false;
|
|
13818
|
-
return el.data.type === "div";
|
|
13819
|
-
}
|
|
13820
|
-
function suppressAtLevel(elements) {
|
|
13821
|
-
if (elements.length <= 1)
|
|
13822
|
-
return elements;
|
|
13823
|
-
const unwrap = Array.from({ length: elements.length }, () => false);
|
|
13824
|
-
for (let i = 0;i < elements.length; i++) {
|
|
13825
|
-
if (!isParagraphContainer2(elements[i]))
|
|
13826
|
-
continue;
|
|
13827
|
-
const prevIsDiv = i > 0 && isDivContainer(elements[i - 1]);
|
|
13828
|
-
const nextIsDiv = i < elements.length - 1 && isDivContainer(elements[i + 1]);
|
|
13829
|
-
if (prevIsDiv || nextIsDiv) {
|
|
13830
|
-
unwrap[i] = true;
|
|
13831
|
-
}
|
|
13832
|
-
}
|
|
13833
|
-
const result = [];
|
|
13834
|
-
for (let i = 0;i < elements.length; i++) {
|
|
13835
|
-
const el = elements[i];
|
|
13836
|
-
if (!el)
|
|
13837
|
-
continue;
|
|
13838
|
-
if (unwrap[i] && el.element === "container") {
|
|
13839
|
-
const inner = el.data.elements;
|
|
13840
|
-
if (i > 0 && isDivContainer(elements[i - 1])) {
|
|
13841
|
-
result.push({ element: "line-break" });
|
|
13842
|
-
}
|
|
13843
|
-
result.push(...inner);
|
|
13844
|
-
} else {
|
|
13845
|
-
result.push(el);
|
|
13846
|
-
}
|
|
13847
|
-
}
|
|
13848
|
-
return result;
|
|
13849
|
-
}
|
|
13850
|
-
function suppressDivAdjacentParagraphs(elements) {
|
|
13851
|
-
return suppressAtLevel(elements);
|
|
13852
|
-
}
|
|
13853
15058
|
// packages/parser/src/parser/parse/footnotes.ts
|
|
13854
15059
|
function containsFootnoteBlock(elements) {
|
|
13855
15060
|
let found = false;
|
|
@@ -14127,7 +15332,9 @@ function substitute(text2) {
|
|
|
14127
15332
|
result = result.replace(WHITESPACE_ONLY_LINE, "");
|
|
14128
15333
|
}
|
|
14129
15334
|
if (result.indexOf("\\\n") !== -1) {
|
|
14130
|
-
|
|
15335
|
+
const sentinels = makeUniqueSentinels(result);
|
|
15336
|
+
const { masked, placeholders } = maskRawRegions(result, sentinels);
|
|
15337
|
+
result = restorePlaceholders(masked.replace(CONCAT_LINES, String.fromCharCode(57344)), placeholders, sentinels);
|
|
14131
15338
|
}
|
|
14132
15339
|
if (result.indexOf("\t") !== -1) {
|
|
14133
15340
|
result = result.replace(TABS, " ");
|
|
@@ -14194,14 +15401,26 @@ function replaceDelimitedTypography(text2, opener, closer, leftQuote, rightQuote
|
|
|
14194
15401
|
let searchFrom = 0;
|
|
14195
15402
|
let result = "";
|
|
14196
15403
|
let lastCopied = 0;
|
|
15404
|
+
let closeIndex = -1;
|
|
15405
|
+
let newlineIndex = -1;
|
|
14197
15406
|
while (searchFrom < text2.length) {
|
|
14198
15407
|
const openIndex = text2.indexOf(opener, searchFrom);
|
|
14199
15408
|
if (openIndex === -1)
|
|
14200
15409
|
break;
|
|
14201
15410
|
const contentStart = openIndex + opener.length;
|
|
14202
|
-
|
|
15411
|
+
if (closeIndex < contentStart)
|
|
15412
|
+
closeIndex = text2.indexOf(closer, contentStart);
|
|
14203
15413
|
if (closeIndex === -1)
|
|
14204
15414
|
break;
|
|
15415
|
+
if (newlineIndex < contentStart) {
|
|
15416
|
+
const nextNewline = text2.indexOf(`
|
|
15417
|
+
`, contentStart);
|
|
15418
|
+
newlineIndex = nextNewline === -1 ? text2.length : nextNewline;
|
|
15419
|
+
}
|
|
15420
|
+
if (newlineIndex < closeIndex) {
|
|
15421
|
+
searchFrom = newlineIndex + 1;
|
|
15422
|
+
continue;
|
|
15423
|
+
}
|
|
14205
15424
|
result += text2.slice(lastCopied, openIndex);
|
|
14206
15425
|
result += leftQuote;
|
|
14207
15426
|
result += text2.slice(contentStart, closeIndex);
|
|
@@ -14212,7 +15431,12 @@ function replaceDelimitedTypography(text2, opener, closer, leftQuote, rightQuote
|
|
|
14212
15431
|
return lastCopied === 0 ? text2 : result + text2.slice(lastCopied);
|
|
14213
15432
|
}
|
|
14214
15433
|
function substitute2(text2) {
|
|
14215
|
-
|
|
15434
|
+
if (!text2.includes("`") && !text2.includes(",,") && !text2.includes("...") && !text2.includes(". . .")) {
|
|
15435
|
+
return text2;
|
|
15436
|
+
}
|
|
15437
|
+
const sentinels = makeUniqueSentinels(text2);
|
|
15438
|
+
const { masked, placeholders } = maskRawRegions(text2, sentinels);
|
|
15439
|
+
let result = masked;
|
|
14216
15440
|
if (result.includes("``") && result.includes("''")) {
|
|
14217
15441
|
result = replaceDelimitedTypography(result, "``", "''", LEFT_DOUBLE_QUOTE, RIGHT_DOUBLE_QUOTE);
|
|
14218
15442
|
}
|
|
@@ -14228,7 +15452,7 @@ function substitute2(text2) {
|
|
|
14228
15452
|
if (result.includes(". . .")) {
|
|
14229
15453
|
result = replaceExactEllipsisPattern(result, ". . .");
|
|
14230
15454
|
}
|
|
14231
|
-
return result;
|
|
15455
|
+
return restorePlaceholders(result, placeholders, sentinels);
|
|
14232
15456
|
}
|
|
14233
15457
|
|
|
14234
15458
|
// packages/parser/src/parser/preprocess/index.ts
|
|
@@ -14268,12 +15492,12 @@ function matchDirectiveKind(source, i) {
|
|
|
14268
15492
|
}
|
|
14269
15493
|
|
|
14270
15494
|
// packages/parser/src/parser/preprocess/expr/evaluate.ts
|
|
14271
|
-
var
|
|
15495
|
+
var import_ast10 = require("@wdprlib/ast");
|
|
14272
15496
|
function evaluateDirective(kind, match) {
|
|
14273
15497
|
if (kind === "expr") {
|
|
14274
|
-
const result2 =
|
|
15498
|
+
const result2 = import_ast10.evaluateExpression(match.head);
|
|
14275
15499
|
if (result2.success)
|
|
14276
|
-
return
|
|
15500
|
+
return import_ast10.formatExprValue(result2.value);
|
|
14277
15501
|
if (result2.error === "empty expression")
|
|
14278
15502
|
return "";
|
|
14279
15503
|
return "ERROR";
|
|
@@ -14281,11 +15505,11 @@ function evaluateDirective(kind, match) {
|
|
|
14281
15505
|
if (kind === "if") {
|
|
14282
15506
|
if (!match.hasPipe)
|
|
14283
15507
|
return "";
|
|
14284
|
-
return
|
|
15508
|
+
return import_ast10.isTruthy(match.head) ? match.thenText : match.elseText;
|
|
14285
15509
|
}
|
|
14286
15510
|
if (!match.hasPipe)
|
|
14287
15511
|
return "";
|
|
14288
|
-
const result =
|
|
15512
|
+
const result = import_ast10.evaluateExpression(match.head);
|
|
14289
15513
|
if (!result.success)
|
|
14290
15514
|
return "ERROR";
|
|
14291
15515
|
return result.value !== 0 && !Number.isNaN(result.value) ? match.thenText : match.elseText;
|
|
@@ -14467,13 +15691,13 @@ function parseSource(source, options, deferInclude) {
|
|
|
14467
15691
|
return deferInclude ? parseTokensWithIncludeDeferral(tokens, options ?? {}, deferInclude) : new Parser(tokens, options).parse();
|
|
14468
15692
|
}
|
|
14469
15693
|
// packages/parser/src/pipeline/process.ts
|
|
14470
|
-
var
|
|
15694
|
+
var import_ast11 = require("@wdprlib/ast");
|
|
14471
15695
|
|
|
14472
15696
|
// packages/parser/src/parser/rules/block/module/resolution/resolve-async.ts
|
|
14473
15697
|
async function resolveModulesWithAsyncParse(ast, dataProvider, options) {
|
|
14474
15698
|
const registry = new ModuleDocumentRegistry;
|
|
14475
15699
|
registry.register(ast);
|
|
14476
|
-
const parse2 = async (source) => registry.register(await options.parse(source));
|
|
15700
|
+
const parse2 = async (source) => registry.register(suppressModuleRatings(await options.parse(source)));
|
|
14477
15701
|
const [listPagesData, listUsersData, tagCloudData] = await Promise.all([
|
|
14478
15702
|
buildListPagesDataMap(dataProvider, options.requirements.listPages ?? [], options.urlPath, options.paginationState),
|
|
14479
15703
|
buildListUsersDataMap(dataProvider, options.requirements.listUsers ?? []),
|
|
@@ -14650,7 +15874,7 @@ var PIPELINE_DIAGNOSTIC_POSITION = {
|
|
|
14650
15874
|
end: { line: 1, column: 1, offset: 0 }
|
|
14651
15875
|
};
|
|
14652
15876
|
async function processWikitext(source, options) {
|
|
14653
|
-
const settings = options.settings ??
|
|
15877
|
+
const settings = options.settings ?? import_ast11.DEFAULT_SETTINGS;
|
|
14654
15878
|
const callbackContext = {
|
|
14655
15879
|
page: options.page,
|
|
14656
15880
|
settings
|
|
@@ -14709,8 +15933,13 @@ async function processWikitext(source, options) {
|
|
|
14709
15933
|
if (hasResolvableRequirements(extractDataRequirements(ast).requirements, options.dataProvider)) {
|
|
14710
15934
|
diagnostics.push(createLimitDiagnostic("module-resolution-limit", `Module resolution stopped after ${DEFAULT_MODULE_MAX_PASSES} passes.`));
|
|
14711
15935
|
}
|
|
15936
|
+
ast = await resolveRatings(ast, dataProvider.fetchRatings);
|
|
15937
|
+
const readableText = import_ast11.extractReadableText(ast, options.readableText);
|
|
14712
15938
|
return {
|
|
14713
15939
|
ast,
|
|
15940
|
+
readableText,
|
|
15941
|
+
firstParagraph: import_ast11.extractFirstParagraph(ast, options.readableText),
|
|
15942
|
+
characterCount: import_ast11.countCharacters(readableText),
|
|
14714
15943
|
page: options.page,
|
|
14715
15944
|
settings,
|
|
14716
15945
|
diagnostics,
|
|
@@ -14739,6 +15968,7 @@ function createLimitDiagnostic(code, message) {
|
|
|
14739
15968
|
function createModuleDataProvider(options, context) {
|
|
14740
15969
|
const provider = options.dataProvider;
|
|
14741
15970
|
return {
|
|
15971
|
+
fetchRatings: provider?.fetchRatings ? (refs) => provider.fetchRatings(refs, context) : undefined,
|
|
14742
15972
|
fetchListPages: provider?.fetchListPages ? (query, requirement) => provider.fetchListPages(query, requirement, context) : undefined,
|
|
14743
15973
|
fetchListUsers: provider?.fetchListUsers ? (requirement) => provider.fetchListUsers(requirement, context) : undefined,
|
|
14744
15974
|
fetchTagCloud: provider?.fetchTagCloud ? (requirement) => provider.fetchTagCloud(requirement, context) : undefined,
|