@wdprlib/parser 2.1.0 → 3.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 +871 -446
- package/dist/index.d.cts +31 -1
- package/dist/index.d.ts +31 -1
- package/dist/index.js +871 -446
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -36,6 +36,7 @@ __export(exports_src, {
|
|
|
36
36
|
resolveListUsers: () => resolveListUsers,
|
|
37
37
|
resolveIncludesAsync: () => resolveIncludesAsync,
|
|
38
38
|
resolveIncludes: () => resolveIncludes,
|
|
39
|
+
preprocessIftags: () => preprocessIftags,
|
|
39
40
|
parseTags: () => parseTags,
|
|
40
41
|
parseParent: () => parseParent,
|
|
41
42
|
parseOrder: () => parseOrder,
|
|
@@ -83,6 +84,7 @@ class Lexer {
|
|
|
83
84
|
state;
|
|
84
85
|
options;
|
|
85
86
|
splitBlockClosePositions = new Set;
|
|
87
|
+
blockOpenerDepth = 0;
|
|
86
88
|
constructor(source, options = {}) {
|
|
87
89
|
this.options = {
|
|
88
90
|
trackPositions: options.trackPositions ?? true
|
|
@@ -182,6 +184,11 @@ class Lexer {
|
|
|
182
184
|
const position = this.options.trackPositions ? import_ast.createPosition(startPos, endPos) : import_ast.createPosition(import_ast.createPoint(0, 0, 0), import_ast.createPoint(0, 0, 0));
|
|
183
185
|
const lineStart = this.state.tokens.length === 0 || this.state.tokens[this.state.tokens.length - 1]?.type === "NEWLINE";
|
|
184
186
|
this.state.tokens.push(createToken(type, value, position, lineStart));
|
|
187
|
+
if (type === "BLOCK_OPEN" || type === "BLOCK_END_OPEN") {
|
|
188
|
+
this.blockOpenerDepth++;
|
|
189
|
+
} else if (type === "BLOCK_CLOSE" && this.blockOpenerDepth > 0) {
|
|
190
|
+
this.blockOpenerDepth--;
|
|
191
|
+
}
|
|
185
192
|
}
|
|
186
193
|
scanToken() {
|
|
187
194
|
const char = this.current();
|
|
@@ -446,7 +453,7 @@ class Lexer {
|
|
|
446
453
|
}
|
|
447
454
|
if (char === '"') {
|
|
448
455
|
const lastNonWs = this.lastNonWhitespaceTokenType();
|
|
449
|
-
if (lastNonWs === "EQUALS") {
|
|
456
|
+
if (this.blockOpenerDepth > 0 && lastNonWs === "EQUALS") {
|
|
450
457
|
let quoted = this.advance();
|
|
451
458
|
while (!this.isAtEnd() && this.current() !== '"' && this.current() !== `
|
|
452
459
|
`) {
|
|
@@ -646,6 +653,73 @@ var BLOCK_START_TOKENS = [
|
|
|
646
653
|
"CLEAR_FLOAT_LEFT",
|
|
647
654
|
"CLEAR_FLOAT_RIGHT"
|
|
648
655
|
];
|
|
656
|
+
var KNOWN_BLOCK_NAMES = new Set([
|
|
657
|
+
"collapsible",
|
|
658
|
+
"div",
|
|
659
|
+
"div_",
|
|
660
|
+
"code",
|
|
661
|
+
"ul",
|
|
662
|
+
"ol",
|
|
663
|
+
"li",
|
|
664
|
+
"table",
|
|
665
|
+
"row",
|
|
666
|
+
"cell",
|
|
667
|
+
"hcell",
|
|
668
|
+
"tabview",
|
|
669
|
+
"tabs",
|
|
670
|
+
"module",
|
|
671
|
+
"module654",
|
|
672
|
+
"bibliography",
|
|
673
|
+
"footnoteblock",
|
|
674
|
+
"toc",
|
|
675
|
+
"iframe",
|
|
676
|
+
"math",
|
|
677
|
+
"html",
|
|
678
|
+
"iftags",
|
|
679
|
+
"include",
|
|
680
|
+
"f",
|
|
681
|
+
"embed",
|
|
682
|
+
"embedvideo",
|
|
683
|
+
"embedaudio",
|
|
684
|
+
"<",
|
|
685
|
+
">",
|
|
686
|
+
"=",
|
|
687
|
+
"==",
|
|
688
|
+
"span",
|
|
689
|
+
"span_",
|
|
690
|
+
"user",
|
|
691
|
+
"a",
|
|
692
|
+
"anchor",
|
|
693
|
+
"size",
|
|
694
|
+
"footnote",
|
|
695
|
+
"eref",
|
|
696
|
+
"$",
|
|
697
|
+
"image",
|
|
698
|
+
"gallery",
|
|
699
|
+
"file"
|
|
700
|
+
]);
|
|
701
|
+
var INDENT_ACCEPTING_BLOCK_NAMES = new Set([
|
|
702
|
+
"bibliography",
|
|
703
|
+
"ul",
|
|
704
|
+
"ol",
|
|
705
|
+
"li",
|
|
706
|
+
"code",
|
|
707
|
+
"collapsible",
|
|
708
|
+
"div",
|
|
709
|
+
"div_",
|
|
710
|
+
"embed",
|
|
711
|
+
"embedvideo",
|
|
712
|
+
"embedaudio",
|
|
713
|
+
"html",
|
|
714
|
+
"iframe",
|
|
715
|
+
"iftags",
|
|
716
|
+
"math",
|
|
717
|
+
"module",
|
|
718
|
+
"module654",
|
|
719
|
+
"table",
|
|
720
|
+
"tabview",
|
|
721
|
+
"tabs"
|
|
722
|
+
]);
|
|
649
723
|
|
|
650
724
|
// packages/parser/src/parser/rules/utils.ts
|
|
651
725
|
var SAFE_ATTRIBUTES = new Set([
|
|
@@ -772,13 +846,36 @@ function parseBlockName(ctx, startPos) {
|
|
|
772
846
|
|
|
773
847
|
// packages/parser/src/parser/rules/inline/utils.ts
|
|
774
848
|
function isExcludedBlockToken(ctx, tokenPos) {
|
|
775
|
-
|
|
849
|
+
const excluded = ctx.scope.excludedBlockNames;
|
|
850
|
+
if (!excluded?.size)
|
|
851
|
+
return false;
|
|
852
|
+
const token = ctx.tokens[tokenPos];
|
|
853
|
+
if (token?.type !== "BLOCK_OPEN" && token?.type !== "BLOCK_END_OPEN")
|
|
776
854
|
return false;
|
|
855
|
+
const nameResult = parseBlockName(ctx, tokenPos + 1);
|
|
856
|
+
return nameResult !== null && excluded.has(nameResult.name);
|
|
857
|
+
}
|
|
858
|
+
function isUnknownBlockToken(ctx, tokenPos) {
|
|
859
|
+
const token = ctx.tokens[tokenPos];
|
|
860
|
+
if (token?.type !== "BLOCK_OPEN" && token?.type !== "BLOCK_END_OPEN")
|
|
861
|
+
return false;
|
|
862
|
+
const nameResult = parseBlockName(ctx, tokenPos + 1);
|
|
863
|
+
if (nameResult === null) {
|
|
864
|
+
if (ctx.tokens[tokenPos + 1]?.type === "EQUALS") {
|
|
865
|
+
return false;
|
|
866
|
+
}
|
|
867
|
+
return true;
|
|
868
|
+
}
|
|
869
|
+
return !KNOWN_BLOCK_NAMES.has(nameResult.name);
|
|
870
|
+
}
|
|
871
|
+
function isIndentAcceptingBlock(ctx, tokenPos) {
|
|
777
872
|
const token = ctx.tokens[tokenPos];
|
|
778
873
|
if (token?.type !== "BLOCK_OPEN" && token?.type !== "BLOCK_END_OPEN")
|
|
779
874
|
return false;
|
|
780
875
|
const nameResult = parseBlockName(ctx, tokenPos + 1);
|
|
781
|
-
|
|
876
|
+
if (nameResult === null)
|
|
877
|
+
return false;
|
|
878
|
+
return INDENT_ACCEPTING_BLOCK_NAMES.has(nameResult.name);
|
|
782
879
|
}
|
|
783
880
|
function canApplyInlineRule(rule, token) {
|
|
784
881
|
if (rule.startTokens.length === 0) {
|
|
@@ -797,9 +894,9 @@ function parseInlineUntil(ctx, endType) {
|
|
|
797
894
|
if (!token || token.type === "EOF") {
|
|
798
895
|
break;
|
|
799
896
|
}
|
|
800
|
-
if (paragraphMode && ctx.blockCloseCondition) {
|
|
897
|
+
if (paragraphMode && ctx.scope.blockCloseCondition) {
|
|
801
898
|
const checkCtx = { ...ctx, pos };
|
|
802
|
-
if (ctx.blockCloseCondition(checkCtx)) {
|
|
899
|
+
if (ctx.scope.blockCloseCondition(checkCtx)) {
|
|
803
900
|
break;
|
|
804
901
|
}
|
|
805
902
|
}
|
|
@@ -851,7 +948,7 @@ function parseInlineUntil(ctx, endType) {
|
|
|
851
948
|
skipWhitespace++;
|
|
852
949
|
}
|
|
853
950
|
const blockNameToken = ctx.tokens[afterOpen + skipWhitespace];
|
|
854
|
-
if (blockNameToken && (blockNameToken.type === "TEXT" || blockNameToken.type === "IDENTIFIER") && blockNameToken.value.toLowerCase() === "footnoteblock" && ctx.footnoteBlockParsed) {
|
|
951
|
+
if (blockNameToken && (blockNameToken.type === "TEXT" || blockNameToken.type === "IDENTIFIER") && blockNameToken.value.toLowerCase() === "footnoteblock" && ctx.scope.footnoteBlockParsed) {
|
|
855
952
|
isInvalidBlockOpen = true;
|
|
856
953
|
}
|
|
857
954
|
}
|
|
@@ -872,7 +969,9 @@ function parseInlineUntil(ctx, endType) {
|
|
|
872
969
|
}
|
|
873
970
|
}
|
|
874
971
|
const isExcludedBlock = (nextMeaningfulToken?.type === "BLOCK_OPEN" || nextMeaningfulToken?.type === "BLOCK_END_OPEN") && isExcludedBlockToken(ctx, pos + lookAhead);
|
|
875
|
-
const
|
|
972
|
+
const isUnknownBlock = (nextMeaningfulToken?.type === "BLOCK_OPEN" || nextMeaningfulToken?.type === "BLOCK_END_OPEN") && isUnknownBlockToken(ctx, pos + lookAhead);
|
|
973
|
+
const isIndentedBlockOpener = nextMeaningfulToken && (nextMeaningfulToken.type === "BLOCK_OPEN" || nextMeaningfulToken.type === "BLOCK_END_OPEN") && isIndentAcceptingBlock(ctx, pos + lookAhead);
|
|
974
|
+
const isBlockStart = nextMeaningfulToken && BLOCK_START_TOKENS.includes(nextMeaningfulToken.type) && (nextMeaningfulToken.lineStart || isIndentedBlockOpener) && !isOrphanCloseSpan && !isAnchorName && !isInvalidBlockOpen && !isInvalidHeading && !isExcludedBlock && !isUnknownBlock;
|
|
876
975
|
if (!nextMeaningfulToken || nextMeaningfulToken.type === "NEWLINE" || nextMeaningfulToken.type === "EOF" || isBlockStart) {
|
|
877
976
|
if (isBlockStart && nodes.length > 0) {
|
|
878
977
|
const nextPos = pos + lookAhead;
|
|
@@ -1209,7 +1308,6 @@ function buildListData(topLtype, list) {
|
|
|
1209
1308
|
items
|
|
1210
1309
|
};
|
|
1211
1310
|
}
|
|
1212
|
-
|
|
1213
1311
|
// packages/parser/src/parser/rules/block/utils.ts
|
|
1214
1312
|
function canApplyBlockRule(rule, token) {
|
|
1215
1313
|
if (rule.requiresLineStart && !token.lineStart) {
|
|
@@ -1251,8 +1349,11 @@ function parseBlocksUntil(ctx, closeCondition, options) {
|
|
|
1251
1349
|
...ctx,
|
|
1252
1350
|
pos,
|
|
1253
1351
|
blockRules,
|
|
1254
|
-
|
|
1255
|
-
|
|
1352
|
+
scope: {
|
|
1353
|
+
...ctx.scope,
|
|
1354
|
+
blockCloseCondition: closeCondition,
|
|
1355
|
+
excludedBlockNames: excluded
|
|
1356
|
+
}
|
|
1256
1357
|
};
|
|
1257
1358
|
for (const rule of blockRules) {
|
|
1258
1359
|
if (canApplyBlockRule(rule, token)) {
|
|
@@ -2240,15 +2341,15 @@ var divRule = {
|
|
|
2240
2341
|
if (ctx.tokens[pos]?.type !== "NEWLINE") {
|
|
2241
2342
|
return consumeFailedDiv(ctx);
|
|
2242
2343
|
}
|
|
2243
|
-
if (ctx.divClosesBudget === 0) {
|
|
2344
|
+
if (ctx.scope.divClosesBudget === 0) {
|
|
2244
2345
|
return { success: false };
|
|
2245
2346
|
}
|
|
2246
2347
|
pos++;
|
|
2247
2348
|
consumed++;
|
|
2248
2349
|
const openPosition = openToken.position;
|
|
2249
2350
|
let bodyBudget;
|
|
2250
|
-
if (ctx.divClosesBudget !== undefined) {
|
|
2251
|
-
bodyBudget = ctx.divClosesBudget - 1;
|
|
2351
|
+
if (ctx.scope.divClosesBudget !== undefined) {
|
|
2352
|
+
bodyBudget = ctx.scope.divClosesBudget - 1;
|
|
2252
2353
|
} else {
|
|
2253
2354
|
const closesInScope = countDivCloses(ctx, pos);
|
|
2254
2355
|
bodyBudget = closesInScope > 0 ? closesInScope - 1 : 0;
|
|
@@ -2263,7 +2364,11 @@ var divRule = {
|
|
|
2263
2364
|
}
|
|
2264
2365
|
return false;
|
|
2265
2366
|
};
|
|
2266
|
-
const bodyCtx = {
|
|
2367
|
+
const bodyCtx = {
|
|
2368
|
+
...ctx,
|
|
2369
|
+
pos,
|
|
2370
|
+
scope: { ...ctx.scope, divClosesBudget: bodyBudget }
|
|
2371
|
+
};
|
|
2267
2372
|
let children;
|
|
2268
2373
|
if (paragraphStrip) {
|
|
2269
2374
|
const bodyResult = parseBlocksUntil(bodyCtx, closeCondition);
|
|
@@ -3906,10 +4011,10 @@ var footnoteBlockRule = {
|
|
|
3906
4011
|
}
|
|
3907
4012
|
pos++;
|
|
3908
4013
|
consumed++;
|
|
3909
|
-
if (ctx.footnoteBlockParsed) {
|
|
4014
|
+
if (ctx.scope.footnoteBlockParsed) {
|
|
3910
4015
|
return { success: false };
|
|
3911
4016
|
}
|
|
3912
|
-
ctx.
|
|
4017
|
+
ctx.scope = { ...ctx.scope, footnoteBlockParsed: true };
|
|
3913
4018
|
const title = attrs.title !== undefined ? attrs.title : null;
|
|
3914
4019
|
const hide = attrs.hide === "true" || attrs.hide === "yes";
|
|
3915
4020
|
return {
|
|
@@ -4665,6 +4770,24 @@ var mathBlockRule = {
|
|
|
4665
4770
|
};
|
|
4666
4771
|
|
|
4667
4772
|
// packages/parser/src/parser/rules/block/html.ts
|
|
4773
|
+
function lookaheadHasHtmlClose(ctx, from) {
|
|
4774
|
+
for (let i = from;i < ctx.tokens.length; i++) {
|
|
4775
|
+
const t = ctx.tokens[i];
|
|
4776
|
+
if (!t || t.type === "EOF")
|
|
4777
|
+
return false;
|
|
4778
|
+
if (t.type !== "BLOCK_END_OPEN")
|
|
4779
|
+
continue;
|
|
4780
|
+
const closeName = parseBlockName(ctx, i + 1);
|
|
4781
|
+
if (closeName?.name.toLowerCase() !== "html")
|
|
4782
|
+
continue;
|
|
4783
|
+
let cp = i + 1 + closeName.consumed;
|
|
4784
|
+
while (ctx.tokens[cp]?.type === "WHITESPACE")
|
|
4785
|
+
cp++;
|
|
4786
|
+
if (ctx.tokens[cp]?.type === "BLOCK_CLOSE")
|
|
4787
|
+
return true;
|
|
4788
|
+
}
|
|
4789
|
+
return false;
|
|
4790
|
+
}
|
|
4668
4791
|
var htmlBlockRule = {
|
|
4669
4792
|
name: "html",
|
|
4670
4793
|
startTokens: ["BLOCK_OPEN"],
|
|
@@ -4691,20 +4814,32 @@ var htmlBlockRule = {
|
|
|
4691
4814
|
}
|
|
4692
4815
|
pos++;
|
|
4693
4816
|
consumed++;
|
|
4817
|
+
const disabled = ctx.settings.allowHtmlBlocks === false;
|
|
4818
|
+
const hasCloseAhead = disabled && lookaheadHasHtmlClose(ctx, pos);
|
|
4694
4819
|
let contents = "";
|
|
4695
4820
|
let foundClose = false;
|
|
4696
4821
|
while (pos < ctx.tokens.length) {
|
|
4697
4822
|
const token = ctx.tokens[pos];
|
|
4698
4823
|
if (!token || token.type === "EOF")
|
|
4699
4824
|
break;
|
|
4825
|
+
if (disabled && !hasCloseAhead && token.type === "NEWLINE" && ctx.tokens[pos + 1]?.type === "NEWLINE") {
|
|
4826
|
+
break;
|
|
4827
|
+
}
|
|
4700
4828
|
if (token.type === "BLOCK_END_OPEN") {
|
|
4701
4829
|
const closeNameResult = parseBlockName(ctx, pos + 1);
|
|
4702
4830
|
if (closeNameResult?.name.toLowerCase() === "html") {
|
|
4703
|
-
|
|
4704
|
-
|
|
4831
|
+
let checkPos = pos + 1 + closeNameResult.consumed;
|
|
4832
|
+
while (ctx.tokens[checkPos]?.type === "WHITESPACE")
|
|
4833
|
+
checkPos++;
|
|
4834
|
+
if (ctx.tokens[checkPos]?.type === "BLOCK_CLOSE") {
|
|
4835
|
+
foundClose = true;
|
|
4836
|
+
break;
|
|
4837
|
+
}
|
|
4705
4838
|
}
|
|
4706
4839
|
}
|
|
4707
|
-
|
|
4840
|
+
if (!disabled) {
|
|
4841
|
+
contents += token.value;
|
|
4842
|
+
}
|
|
4708
4843
|
pos++;
|
|
4709
4844
|
consumed++;
|
|
4710
4845
|
}
|
|
@@ -4715,7 +4850,16 @@ var htmlBlockRule = {
|
|
|
4715
4850
|
message: "Missing closing tag [[/html]] for [[html]]",
|
|
4716
4851
|
position: openToken.position
|
|
4717
4852
|
});
|
|
4718
|
-
|
|
4853
|
+
if (!disabled) {
|
|
4854
|
+
return { success: false };
|
|
4855
|
+
}
|
|
4856
|
+
ctx.diagnostics.push({
|
|
4857
|
+
severity: "info",
|
|
4858
|
+
code: "html-block-disabled",
|
|
4859
|
+
message: "[[html]] block ignored: disabled by settings",
|
|
4860
|
+
position: openToken.position
|
|
4861
|
+
});
|
|
4862
|
+
return { success: true, elements: [], consumed };
|
|
4719
4863
|
}
|
|
4720
4864
|
if (ctx.tokens[pos]?.type === "BLOCK_END_OPEN") {
|
|
4721
4865
|
pos++;
|
|
@@ -4725,6 +4869,10 @@ var htmlBlockRule = {
|
|
|
4725
4869
|
pos += closeNameResult.consumed;
|
|
4726
4870
|
consumed += closeNameResult.consumed;
|
|
4727
4871
|
}
|
|
4872
|
+
while (ctx.tokens[pos]?.type === "WHITESPACE") {
|
|
4873
|
+
pos++;
|
|
4874
|
+
consumed++;
|
|
4875
|
+
}
|
|
4728
4876
|
if (ctx.tokens[pos]?.type === "BLOCK_CLOSE") {
|
|
4729
4877
|
pos++;
|
|
4730
4878
|
consumed++;
|
|
@@ -4734,6 +4882,15 @@ var htmlBlockRule = {
|
|
|
4734
4882
|
consumed++;
|
|
4735
4883
|
}
|
|
4736
4884
|
}
|
|
4885
|
+
if (disabled) {
|
|
4886
|
+
ctx.diagnostics.push({
|
|
4887
|
+
severity: "info",
|
|
4888
|
+
code: "html-block-disabled",
|
|
4889
|
+
message: "[[html]] block ignored: disabled by settings",
|
|
4890
|
+
position: openToken.position
|
|
4891
|
+
});
|
|
4892
|
+
return { success: true, elements: [], consumed };
|
|
4893
|
+
}
|
|
4737
4894
|
contents = contents.trim();
|
|
4738
4895
|
ctx.htmlBlocks.push(contents);
|
|
4739
4896
|
return {
|
|
@@ -6419,6 +6576,82 @@ var commentRule = {
|
|
|
6419
6576
|
}
|
|
6420
6577
|
};
|
|
6421
6578
|
|
|
6579
|
+
// packages/parser/src/parser/rules/inline/html.ts
|
|
6580
|
+
var htmlInlineRule = {
|
|
6581
|
+
name: "html",
|
|
6582
|
+
startTokens: ["BLOCK_OPEN"],
|
|
6583
|
+
parse(ctx) {
|
|
6584
|
+
const openToken = currentToken(ctx);
|
|
6585
|
+
if (openToken.type !== "BLOCK_OPEN") {
|
|
6586
|
+
return { success: false };
|
|
6587
|
+
}
|
|
6588
|
+
let pos = ctx.pos + 1;
|
|
6589
|
+
let consumed = 1;
|
|
6590
|
+
const nameResult = parseBlockName(ctx, pos);
|
|
6591
|
+
if (!nameResult || nameResult.name.toLowerCase() !== "html") {
|
|
6592
|
+
return { success: false };
|
|
6593
|
+
}
|
|
6594
|
+
pos += nameResult.consumed;
|
|
6595
|
+
consumed += nameResult.consumed;
|
|
6596
|
+
const attrResult = parseAttributesRaw(ctx, pos);
|
|
6597
|
+
pos += attrResult.consumed;
|
|
6598
|
+
consumed += attrResult.consumed;
|
|
6599
|
+
if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
|
|
6600
|
+
return { success: false };
|
|
6601
|
+
}
|
|
6602
|
+
pos++;
|
|
6603
|
+
consumed++;
|
|
6604
|
+
if (ctx.settings.allowHtmlBlocks !== false) {
|
|
6605
|
+
return { success: false };
|
|
6606
|
+
}
|
|
6607
|
+
const hasCloseAhead = lookaheadHasHtmlClose(ctx, pos);
|
|
6608
|
+
let foundClose = false;
|
|
6609
|
+
while (pos < ctx.tokens.length) {
|
|
6610
|
+
const token = ctx.tokens[pos];
|
|
6611
|
+
if (!token || token.type === "EOF")
|
|
6612
|
+
break;
|
|
6613
|
+
if (!hasCloseAhead && token.type === "NEWLINE" && ctx.tokens[pos + 1]?.type === "NEWLINE") {
|
|
6614
|
+
break;
|
|
6615
|
+
}
|
|
6616
|
+
if (token.type === "BLOCK_END_OPEN") {
|
|
6617
|
+
const closeNameResult = parseBlockName(ctx, pos + 1);
|
|
6618
|
+
if (closeNameResult?.name.toLowerCase() === "html") {
|
|
6619
|
+
let checkPos = pos + 1 + closeNameResult.consumed;
|
|
6620
|
+
while (ctx.tokens[checkPos]?.type === "WHITESPACE")
|
|
6621
|
+
checkPos++;
|
|
6622
|
+
if (ctx.tokens[checkPos]?.type === "BLOCK_CLOSE") {
|
|
6623
|
+
foundClose = true;
|
|
6624
|
+
consumed += checkPos - pos + 1;
|
|
6625
|
+
pos = checkPos + 1;
|
|
6626
|
+
if (ctx.tokens[pos]?.type === "NEWLINE") {
|
|
6627
|
+
pos++;
|
|
6628
|
+
consumed++;
|
|
6629
|
+
}
|
|
6630
|
+
break;
|
|
6631
|
+
}
|
|
6632
|
+
}
|
|
6633
|
+
}
|
|
6634
|
+
pos++;
|
|
6635
|
+
consumed++;
|
|
6636
|
+
}
|
|
6637
|
+
if (!foundClose) {
|
|
6638
|
+
ctx.diagnostics.push({
|
|
6639
|
+
severity: "warning",
|
|
6640
|
+
code: "unclosed-block",
|
|
6641
|
+
message: "Missing closing tag [[/html]] for [[html]]",
|
|
6642
|
+
position: openToken.position
|
|
6643
|
+
});
|
|
6644
|
+
}
|
|
6645
|
+
ctx.diagnostics.push({
|
|
6646
|
+
severity: "info",
|
|
6647
|
+
code: "html-block-disabled",
|
|
6648
|
+
message: "[[html]] block ignored: disabled by settings",
|
|
6649
|
+
position: openToken.position
|
|
6650
|
+
});
|
|
6651
|
+
return { success: true, elements: [], consumed };
|
|
6652
|
+
}
|
|
6653
|
+
};
|
|
6654
|
+
|
|
6422
6655
|
// packages/parser/src/parser/rules/inline/raw.ts
|
|
6423
6656
|
var rawRule = {
|
|
6424
6657
|
name: "raw",
|
|
@@ -8129,6 +8362,7 @@ var inlineRules = [
|
|
|
8129
8362
|
underscoreLineBreakRule,
|
|
8130
8363
|
newlineLineBreakRule,
|
|
8131
8364
|
commentRule,
|
|
8365
|
+
htmlInlineRule,
|
|
8132
8366
|
rawRule,
|
|
8133
8367
|
imageRule,
|
|
8134
8368
|
sizeRule,
|
|
@@ -8646,89 +8880,339 @@ function buildTableOfContents(entries) {
|
|
|
8646
8880
|
return trees.map((tree) => buildTocList(indexer, tree.list));
|
|
8647
8881
|
}
|
|
8648
8882
|
|
|
8649
|
-
// packages/parser/src/parser/
|
|
8650
|
-
|
|
8651
|
-
|
|
8652
|
-
|
|
8653
|
-
|
|
8654
|
-
|
|
8655
|
-
|
|
8656
|
-
|
|
8657
|
-
|
|
8658
|
-
|
|
8659
|
-
|
|
8660
|
-
|
|
8661
|
-
|
|
8662
|
-
|
|
8663
|
-
footnoteBlockParsed: false,
|
|
8664
|
-
bibcites: [],
|
|
8665
|
-
diagnostics: [],
|
|
8666
|
-
blockRules,
|
|
8667
|
-
blockFallbackRule: paragraphRule,
|
|
8668
|
-
inlineRules
|
|
8669
|
-
};
|
|
8670
|
-
}
|
|
8671
|
-
parse() {
|
|
8672
|
-
const children = [];
|
|
8673
|
-
while (!this.isAtEnd()) {
|
|
8674
|
-
const blocks = this.parseBlock();
|
|
8675
|
-
children.push(...blocks);
|
|
8676
|
-
}
|
|
8677
|
-
const mergedChildren = mergeSpanStripParagraphs(children);
|
|
8678
|
-
const divProcessed = suppressDivAdjacentParagraphs(mergedChildren);
|
|
8679
|
-
const cleanedChildren = cleanInternalFlags(divProcessed);
|
|
8680
|
-
const hasFootnoteBlock = cleanedChildren.some((el) => el.element === "footnote-block");
|
|
8681
|
-
if (!hasFootnoteBlock) {
|
|
8682
|
-
cleanedChildren.push({
|
|
8683
|
-
element: "footnote-block",
|
|
8684
|
-
data: { title: null, hide: false }
|
|
8685
|
-
});
|
|
8883
|
+
// packages/parser/src/parser/rules/block/module/walk.ts
|
|
8884
|
+
function walkElements(elements, callback) {
|
|
8885
|
+
for (const element of elements) {
|
|
8886
|
+
callback(element);
|
|
8887
|
+
if (element.element === "list") {
|
|
8888
|
+
const listData = element.data;
|
|
8889
|
+
for (const item of listData.items) {
|
|
8890
|
+
if (item["item-type"] === "elements") {
|
|
8891
|
+
walkElements(item.elements, callback);
|
|
8892
|
+
} else if (item["item-type"] === "sub-list") {
|
|
8893
|
+
walkElements([{ element: "list", data: item.data }], callback);
|
|
8894
|
+
}
|
|
8895
|
+
}
|
|
8896
|
+
continue;
|
|
8686
8897
|
}
|
|
8687
|
-
|
|
8688
|
-
|
|
8689
|
-
|
|
8690
|
-
|
|
8691
|
-
|
|
8692
|
-
|
|
8898
|
+
if (element.element === "table") {
|
|
8899
|
+
const tableData = element.data;
|
|
8900
|
+
for (const row of tableData.rows) {
|
|
8901
|
+
for (const cell of row.cells) {
|
|
8902
|
+
walkElements(cell.elements, callback);
|
|
8903
|
+
}
|
|
8904
|
+
}
|
|
8905
|
+
continue;
|
|
8693
8906
|
}
|
|
8694
|
-
if (
|
|
8695
|
-
|
|
8907
|
+
if (element.element === "definition-list") {
|
|
8908
|
+
const defListData = element.data;
|
|
8909
|
+
for (const item of defListData) {
|
|
8910
|
+
walkElements(item.key, callback);
|
|
8911
|
+
walkElements(item.value, callback);
|
|
8912
|
+
}
|
|
8913
|
+
continue;
|
|
8696
8914
|
}
|
|
8697
|
-
if (
|
|
8698
|
-
|
|
8915
|
+
if (element.element === "tab-view") {
|
|
8916
|
+
const tabData = element.data;
|
|
8917
|
+
for (const tab of tabData) {
|
|
8918
|
+
walkElements(tab.elements, callback);
|
|
8919
|
+
}
|
|
8920
|
+
continue;
|
|
8699
8921
|
}
|
|
8700
|
-
if (
|
|
8701
|
-
|
|
8922
|
+
if ("data" in element && element.data && typeof element.data === "object") {
|
|
8923
|
+
const data = element.data;
|
|
8924
|
+
if ("elements" in data && Array.isArray(data.elements)) {
|
|
8925
|
+
walkElements(data.elements, callback);
|
|
8926
|
+
}
|
|
8702
8927
|
}
|
|
8703
|
-
return { ast: result, diagnostics: this.ctx.diagnostics };
|
|
8704
|
-
}
|
|
8705
|
-
isAtEnd() {
|
|
8706
|
-
return this.ctx.pos >= this.ctx.tokens.length || this.currentToken().type === "EOF";
|
|
8707
|
-
}
|
|
8708
|
-
currentToken() {
|
|
8709
|
-
return this.ctx.tokens[this.ctx.pos] ?? this.eofToken();
|
|
8710
8928
|
}
|
|
8711
|
-
|
|
8929
|
+
}
|
|
8930
|
+
function mapElementChildren(element, transform) {
|
|
8931
|
+
if (element.element === "list") {
|
|
8932
|
+
const listData = element.data;
|
|
8933
|
+
const newItems = [];
|
|
8934
|
+
for (const item of listData.items) {
|
|
8935
|
+
if (item["item-type"] === "elements") {
|
|
8936
|
+
newItems.push({
|
|
8937
|
+
"item-type": "elements",
|
|
8938
|
+
attributes: item.attributes,
|
|
8939
|
+
elements: transform(item.elements)
|
|
8940
|
+
});
|
|
8941
|
+
} else if (item["item-type"] === "sub-list") {
|
|
8942
|
+
const subListResult = transform([{ element: "list", data: item.data }]);
|
|
8943
|
+
const resolvedList = subListResult[0];
|
|
8944
|
+
if (resolvedList?.element === "list") {
|
|
8945
|
+
newItems.push({
|
|
8946
|
+
"item-type": "sub-list",
|
|
8947
|
+
element: "list",
|
|
8948
|
+
data: resolvedList.data
|
|
8949
|
+
});
|
|
8950
|
+
} else {
|
|
8951
|
+
newItems.push(item);
|
|
8952
|
+
}
|
|
8953
|
+
}
|
|
8954
|
+
}
|
|
8712
8955
|
return {
|
|
8713
|
-
|
|
8714
|
-
|
|
8715
|
-
position: {
|
|
8716
|
-
start: { line: 0, column: 0, offset: 0 },
|
|
8717
|
-
end: { line: 0, column: 0, offset: 0 }
|
|
8718
|
-
},
|
|
8719
|
-
lineStart: false
|
|
8956
|
+
element: "list",
|
|
8957
|
+
data: { ...listData, items: newItems }
|
|
8720
8958
|
};
|
|
8721
8959
|
}
|
|
8722
|
-
|
|
8723
|
-
|
|
8724
|
-
|
|
8725
|
-
|
|
8726
|
-
|
|
8727
|
-
|
|
8728
|
-
|
|
8729
|
-
|
|
8730
|
-
|
|
8731
|
-
}
|
|
8960
|
+
if (element.element === "table") {
|
|
8961
|
+
const tableData = element.data;
|
|
8962
|
+
const newRows = [];
|
|
8963
|
+
for (const row of tableData.rows) {
|
|
8964
|
+
const newCells = [];
|
|
8965
|
+
for (const cell of row.cells) {
|
|
8966
|
+
newCells.push({ ...cell, elements: transform(cell.elements) });
|
|
8967
|
+
}
|
|
8968
|
+
newRows.push({ ...row, cells: newCells });
|
|
8969
|
+
}
|
|
8970
|
+
return {
|
|
8971
|
+
element: "table",
|
|
8972
|
+
data: { ...tableData, rows: newRows }
|
|
8973
|
+
};
|
|
8974
|
+
}
|
|
8975
|
+
if (element.element === "definition-list") {
|
|
8976
|
+
const defListData = element.data;
|
|
8977
|
+
const newItems = [];
|
|
8978
|
+
for (const item of defListData) {
|
|
8979
|
+
newItems.push({
|
|
8980
|
+
key_string: item.key_string,
|
|
8981
|
+
key: transform(item.key),
|
|
8982
|
+
value: transform(item.value)
|
|
8983
|
+
});
|
|
8984
|
+
}
|
|
8985
|
+
return {
|
|
8986
|
+
element: "definition-list",
|
|
8987
|
+
data: newItems
|
|
8988
|
+
};
|
|
8989
|
+
}
|
|
8990
|
+
if (element.element === "tab-view") {
|
|
8991
|
+
const tabData = element.data;
|
|
8992
|
+
const newTabs = [];
|
|
8993
|
+
for (const tab of tabData) {
|
|
8994
|
+
newTabs.push({ ...tab, elements: transform(tab.elements) });
|
|
8995
|
+
}
|
|
8996
|
+
return {
|
|
8997
|
+
element: "tab-view",
|
|
8998
|
+
data: newTabs
|
|
8999
|
+
};
|
|
9000
|
+
}
|
|
9001
|
+
if ("data" in element && element.data && typeof element.data === "object") {
|
|
9002
|
+
const data = element.data;
|
|
9003
|
+
if ("elements" in data && Array.isArray(data.elements)) {
|
|
9004
|
+
return {
|
|
9005
|
+
...element,
|
|
9006
|
+
data: {
|
|
9007
|
+
...data,
|
|
9008
|
+
elements: transform(data.elements)
|
|
9009
|
+
}
|
|
9010
|
+
};
|
|
9011
|
+
}
|
|
9012
|
+
}
|
|
9013
|
+
return element;
|
|
9014
|
+
}
|
|
9015
|
+
function mapElementChildrenWithState(element, state, transform) {
|
|
9016
|
+
if (element.element === "list") {
|
|
9017
|
+
const listData = element.data;
|
|
9018
|
+
const newItems = [];
|
|
9019
|
+
let currentState = state;
|
|
9020
|
+
for (const item of listData.items) {
|
|
9021
|
+
if (item["item-type"] === "elements") {
|
|
9022
|
+
const result = transform(item.elements, currentState);
|
|
9023
|
+
newItems.push({
|
|
9024
|
+
"item-type": "elements",
|
|
9025
|
+
attributes: item.attributes,
|
|
9026
|
+
elements: result.elements
|
|
9027
|
+
});
|
|
9028
|
+
currentState = result.state;
|
|
9029
|
+
} else if (item["item-type"] === "sub-list") {
|
|
9030
|
+
const result = transform([{ element: "list", data: item.data }], currentState);
|
|
9031
|
+
const resolvedList = result.elements[0];
|
|
9032
|
+
if (resolvedList?.element === "list") {
|
|
9033
|
+
newItems.push({
|
|
9034
|
+
"item-type": "sub-list",
|
|
9035
|
+
element: "list",
|
|
9036
|
+
data: resolvedList.data
|
|
9037
|
+
});
|
|
9038
|
+
} else {
|
|
9039
|
+
newItems.push(item);
|
|
9040
|
+
}
|
|
9041
|
+
currentState = result.state;
|
|
9042
|
+
}
|
|
9043
|
+
}
|
|
9044
|
+
return {
|
|
9045
|
+
element: {
|
|
9046
|
+
element: "list",
|
|
9047
|
+
data: { ...listData, items: newItems }
|
|
9048
|
+
},
|
|
9049
|
+
state: currentState
|
|
9050
|
+
};
|
|
9051
|
+
}
|
|
9052
|
+
if (element.element === "table") {
|
|
9053
|
+
const tableData = element.data;
|
|
9054
|
+
const newRows = [];
|
|
9055
|
+
let currentState = state;
|
|
9056
|
+
for (const row of tableData.rows) {
|
|
9057
|
+
const newCells = [];
|
|
9058
|
+
for (const cell of row.cells) {
|
|
9059
|
+
const result = transform(cell.elements, currentState);
|
|
9060
|
+
newCells.push({ ...cell, elements: result.elements });
|
|
9061
|
+
currentState = result.state;
|
|
9062
|
+
}
|
|
9063
|
+
newRows.push({ ...row, cells: newCells });
|
|
9064
|
+
}
|
|
9065
|
+
return {
|
|
9066
|
+
element: {
|
|
9067
|
+
element: "table",
|
|
9068
|
+
data: { ...tableData, rows: newRows }
|
|
9069
|
+
},
|
|
9070
|
+
state: currentState
|
|
9071
|
+
};
|
|
9072
|
+
}
|
|
9073
|
+
if (element.element === "definition-list") {
|
|
9074
|
+
const defListData = element.data;
|
|
9075
|
+
const newItems = [];
|
|
9076
|
+
let currentState = state;
|
|
9077
|
+
for (const item of defListData) {
|
|
9078
|
+
const keyResult = transform(item.key, currentState);
|
|
9079
|
+
currentState = keyResult.state;
|
|
9080
|
+
const valueResult = transform(item.value, currentState);
|
|
9081
|
+
currentState = valueResult.state;
|
|
9082
|
+
newItems.push({
|
|
9083
|
+
key_string: item.key_string,
|
|
9084
|
+
key: keyResult.elements,
|
|
9085
|
+
value: valueResult.elements
|
|
9086
|
+
});
|
|
9087
|
+
}
|
|
9088
|
+
return {
|
|
9089
|
+
element: {
|
|
9090
|
+
element: "definition-list",
|
|
9091
|
+
data: newItems
|
|
9092
|
+
},
|
|
9093
|
+
state: currentState
|
|
9094
|
+
};
|
|
9095
|
+
}
|
|
9096
|
+
if (element.element === "tab-view") {
|
|
9097
|
+
const tabData = element.data;
|
|
9098
|
+
const newTabs = [];
|
|
9099
|
+
let currentState = state;
|
|
9100
|
+
for (const tab of tabData) {
|
|
9101
|
+
const result = transform(tab.elements, currentState);
|
|
9102
|
+
newTabs.push({ ...tab, elements: result.elements });
|
|
9103
|
+
currentState = result.state;
|
|
9104
|
+
}
|
|
9105
|
+
return {
|
|
9106
|
+
element: {
|
|
9107
|
+
element: "tab-view",
|
|
9108
|
+
data: newTabs
|
|
9109
|
+
},
|
|
9110
|
+
state: currentState
|
|
9111
|
+
};
|
|
9112
|
+
}
|
|
9113
|
+
if ("data" in element && element.data && typeof element.data === "object") {
|
|
9114
|
+
const data = element.data;
|
|
9115
|
+
if ("elements" in data && Array.isArray(data.elements)) {
|
|
9116
|
+
const result = transform(data.elements, state);
|
|
9117
|
+
return {
|
|
9118
|
+
element: {
|
|
9119
|
+
...element,
|
|
9120
|
+
data: {
|
|
9121
|
+
...data,
|
|
9122
|
+
elements: result.elements
|
|
9123
|
+
}
|
|
9124
|
+
},
|
|
9125
|
+
state: result.state
|
|
9126
|
+
};
|
|
9127
|
+
}
|
|
9128
|
+
}
|
|
9129
|
+
return { element, state };
|
|
9130
|
+
}
|
|
9131
|
+
|
|
9132
|
+
// packages/parser/src/parser/parse.ts
|
|
9133
|
+
class Parser {
|
|
9134
|
+
ctx;
|
|
9135
|
+
constructor(tokens, options = {}) {
|
|
9136
|
+
this.ctx = {
|
|
9137
|
+
tokens,
|
|
9138
|
+
pos: 0,
|
|
9139
|
+
version: options.version ?? "wikidot",
|
|
9140
|
+
trackPositions: options.trackPositions ?? true,
|
|
9141
|
+
settings: options.settings ?? import_ast2.DEFAULT_SETTINGS,
|
|
9142
|
+
footnotes: [],
|
|
9143
|
+
tocEntries: [],
|
|
9144
|
+
codeBlocks: [],
|
|
9145
|
+
htmlBlocks: [],
|
|
9146
|
+
bibcites: [],
|
|
9147
|
+
diagnostics: [],
|
|
9148
|
+
blockRules,
|
|
9149
|
+
blockFallbackRule: paragraphRule,
|
|
9150
|
+
inlineRules,
|
|
9151
|
+
scope: {
|
|
9152
|
+
footnoteBlockParsed: false
|
|
9153
|
+
}
|
|
9154
|
+
};
|
|
9155
|
+
}
|
|
9156
|
+
parse() {
|
|
9157
|
+
const children = [];
|
|
9158
|
+
while (!this.isAtEnd()) {
|
|
9159
|
+
const blocks = this.parseBlock();
|
|
9160
|
+
children.push(...blocks);
|
|
9161
|
+
}
|
|
9162
|
+
const mergedChildren = mergeSpanStripParagraphs(children);
|
|
9163
|
+
const divProcessed = suppressDivAdjacentParagraphs(mergedChildren);
|
|
9164
|
+
const cleanedChildren = cleanInternalFlags(divProcessed);
|
|
9165
|
+
if (!containsFootnoteBlock(cleanedChildren)) {
|
|
9166
|
+
cleanedChildren.push({
|
|
9167
|
+
element: "footnote-block",
|
|
9168
|
+
data: { title: null, hide: false }
|
|
9169
|
+
});
|
|
9170
|
+
}
|
|
9171
|
+
const tableOfContents = buildTableOfContents(this.ctx.tocEntries);
|
|
9172
|
+
const result = {
|
|
9173
|
+
elements: cleanedChildren
|
|
9174
|
+
};
|
|
9175
|
+
if (tableOfContents.length > 0) {
|
|
9176
|
+
result["table-of-contents"] = tableOfContents;
|
|
9177
|
+
}
|
|
9178
|
+
if (this.ctx.footnotes.length > 0) {
|
|
9179
|
+
result.footnotes = this.ctx.footnotes;
|
|
9180
|
+
}
|
|
9181
|
+
if (this.ctx.codeBlocks.length > 0) {
|
|
9182
|
+
result["code-blocks"] = this.ctx.codeBlocks;
|
|
9183
|
+
}
|
|
9184
|
+
if (this.ctx.htmlBlocks.length > 0) {
|
|
9185
|
+
result["html-blocks"] = this.ctx.htmlBlocks;
|
|
9186
|
+
}
|
|
9187
|
+
return { ast: result, diagnostics: this.ctx.diagnostics };
|
|
9188
|
+
}
|
|
9189
|
+
isAtEnd() {
|
|
9190
|
+
return this.ctx.pos >= this.ctx.tokens.length || this.currentToken().type === "EOF";
|
|
9191
|
+
}
|
|
9192
|
+
currentToken() {
|
|
9193
|
+
return this.ctx.tokens[this.ctx.pos] ?? this.eofToken();
|
|
9194
|
+
}
|
|
9195
|
+
eofToken() {
|
|
9196
|
+
return {
|
|
9197
|
+
type: "EOF",
|
|
9198
|
+
value: "",
|
|
9199
|
+
position: {
|
|
9200
|
+
start: { line: 0, column: 0, offset: 0 },
|
|
9201
|
+
end: { line: 0, column: 0, offset: 0 }
|
|
9202
|
+
},
|
|
9203
|
+
lineStart: false
|
|
9204
|
+
};
|
|
9205
|
+
}
|
|
9206
|
+
skipWhitespace() {
|
|
9207
|
+
while (this.currentToken().type === "WHITESPACE") {
|
|
9208
|
+
this.ctx.pos++;
|
|
9209
|
+
}
|
|
9210
|
+
}
|
|
9211
|
+
parseBlock() {
|
|
9212
|
+
this.skipWhitespace();
|
|
9213
|
+
if (this.isAtEnd()) {
|
|
9214
|
+
return [];
|
|
9215
|
+
}
|
|
8732
9216
|
const token = this.currentToken();
|
|
8733
9217
|
if (token.type === "NEWLINE") {
|
|
8734
9218
|
this.ctx.pos++;
|
|
@@ -8757,6 +9241,14 @@ function parse(source, options) {
|
|
|
8757
9241
|
const tokens = tokenize(preprocessed, { trackPositions: options?.trackPositions });
|
|
8758
9242
|
return new Parser(tokens, options).parse();
|
|
8759
9243
|
}
|
|
9244
|
+
function containsFootnoteBlock(elements) {
|
|
9245
|
+
let found = false;
|
|
9246
|
+
walkElements(elements, (el) => {
|
|
9247
|
+
if (el.element === "footnote-block")
|
|
9248
|
+
found = true;
|
|
9249
|
+
});
|
|
9250
|
+
return found;
|
|
9251
|
+
}
|
|
8760
9252
|
// packages/parser/src/parser/rules/block/module/listpages/compiler.ts
|
|
8761
9253
|
var DEFAULT_PREVIEW_LENGTH = 200;
|
|
8762
9254
|
var VARIABLE_REGEX = /%%([a-z_]+)(?:\{([^}]+)\})?(?:\((\d+)\))?(?:\|([^%]*(?:%(?!%)[^%]*)*))?%%/gi;
|
|
@@ -8964,348 +9456,99 @@ function strftime(date, format) {
|
|
|
8964
9456
|
return String(date.getDate());
|
|
8965
9457
|
case "H":
|
|
8966
9458
|
return pad(date.getHours());
|
|
8967
|
-
case "I":
|
|
8968
|
-
return pad(date.getHours() % 12 || 12);
|
|
8969
|
-
case "M":
|
|
8970
|
-
return pad(date.getMinutes());
|
|
8971
|
-
case "S":
|
|
8972
|
-
return pad(date.getSeconds());
|
|
8973
|
-
case "p":
|
|
8974
|
-
return date.getHours() < 12 ? "AM" : "PM";
|
|
8975
|
-
case "b":
|
|
8976
|
-
return MONTHS_SHORT[date.getMonth()] ?? "";
|
|
8977
|
-
case "B":
|
|
8978
|
-
return MONTHS[date.getMonth()] ?? "";
|
|
8979
|
-
case "a":
|
|
8980
|
-
return DAYS_SHORT[date.getDay()] ?? "";
|
|
8981
|
-
case "A":
|
|
8982
|
-
return DAYS[date.getDay()] ?? "";
|
|
8983
|
-
case "w":
|
|
8984
|
-
return String(date.getDay());
|
|
8985
|
-
case "j":
|
|
8986
|
-
return pad(getDayOfYear(date), 3);
|
|
8987
|
-
case "Z":
|
|
8988
|
-
return "UTC";
|
|
8989
|
-
case "z":
|
|
8990
|
-
return "+0000";
|
|
8991
|
-
case "%":
|
|
8992
|
-
return "%";
|
|
8993
|
-
default:
|
|
8994
|
-
return `%${token}`;
|
|
8995
|
-
}
|
|
8996
|
-
});
|
|
8997
|
-
}
|
|
8998
|
-
function getDayOfYear(date) {
|
|
8999
|
-
const start = new Date(date.getFullYear(), 0, 0);
|
|
9000
|
-
const diff = date.getTime() - start.getTime();
|
|
9001
|
-
const oneDay = 1000 * 60 * 60 * 24;
|
|
9002
|
-
return Math.floor(diff / oneDay);
|
|
9003
|
-
}
|
|
9004
|
-
|
|
9005
|
-
// packages/parser/src/parser/rules/block/module/listusers/compiler.ts
|
|
9006
|
-
var VARIABLE_REGEX2 = /%%([a-z_]+)%%/gi;
|
|
9007
|
-
function compileListUsersTemplate(template) {
|
|
9008
|
-
const parts = [];
|
|
9009
|
-
let lastIndex = 0;
|
|
9010
|
-
for (const match of template.matchAll(VARIABLE_REGEX2)) {
|
|
9011
|
-
if (match.index !== undefined && match.index > lastIndex) {
|
|
9012
|
-
parts.push(template.slice(lastIndex, match.index));
|
|
9013
|
-
}
|
|
9014
|
-
const [, varName] = match;
|
|
9015
|
-
if (!varName)
|
|
9016
|
-
continue;
|
|
9017
|
-
const getter = createVariableGetter2(varName.toLowerCase());
|
|
9018
|
-
parts.push(getter);
|
|
9019
|
-
lastIndex = match.index !== undefined ? match.index + match[0].length : lastIndex;
|
|
9020
|
-
}
|
|
9021
|
-
if (lastIndex < template.length) {
|
|
9022
|
-
parts.push(template.slice(lastIndex));
|
|
9023
|
-
}
|
|
9024
|
-
return (ctx) => {
|
|
9025
|
-
let result = "";
|
|
9026
|
-
for (const part of parts) {
|
|
9027
|
-
result += typeof part === "string" ? part : part(ctx);
|
|
9028
|
-
}
|
|
9029
|
-
return result;
|
|
9030
|
-
};
|
|
9031
|
-
}
|
|
9032
|
-
function createVariableGetter2(name) {
|
|
9033
|
-
switch (name) {
|
|
9034
|
-
case "number":
|
|
9035
|
-
return (ctx) => String(ctx.user.number);
|
|
9036
|
-
case "title":
|
|
9037
|
-
return (ctx) => ctx.user.title;
|
|
9038
|
-
case "name":
|
|
9039
|
-
return (ctx) => ctx.user.name;
|
|
9040
|
-
default:
|
|
9041
|
-
return () => "";
|
|
9042
|
-
}
|
|
9043
|
-
}
|
|
9044
|
-
|
|
9045
|
-
// packages/parser/src/parser/rules/block/module/listusers/extract.ts
|
|
9046
|
-
var VARIABLE_REGEX3 = /%%([a-z_]+)%%/gi;
|
|
9047
|
-
var KNOWN_VARIABLES = ["number", "title", "name"];
|
|
9048
|
-
function extractListUsersVariables(template) {
|
|
9049
|
-
const variables = new Set;
|
|
9050
|
-
for (const match of template.matchAll(VARIABLE_REGEX3)) {
|
|
9051
|
-
const [, varName] = match;
|
|
9052
|
-
if (!varName)
|
|
9053
|
-
continue;
|
|
9054
|
-
const normalized = varName.toLowerCase();
|
|
9055
|
-
if (KNOWN_VARIABLES.includes(normalized)) {
|
|
9056
|
-
variables.add(normalized);
|
|
9057
|
-
}
|
|
9058
|
-
}
|
|
9059
|
-
return Array.from(variables);
|
|
9060
|
-
}
|
|
9061
|
-
|
|
9062
|
-
// packages/parser/src/parser/rules/block/module/walk.ts
|
|
9063
|
-
function walkElements(elements, callback) {
|
|
9064
|
-
for (const element of elements) {
|
|
9065
|
-
callback(element);
|
|
9066
|
-
if (element.element === "list") {
|
|
9067
|
-
const listData = element.data;
|
|
9068
|
-
for (const item of listData.items) {
|
|
9069
|
-
if (item["item-type"] === "elements") {
|
|
9070
|
-
walkElements(item.elements, callback);
|
|
9071
|
-
} else if (item["item-type"] === "sub-list") {
|
|
9072
|
-
walkElements([{ element: "list", data: item.data }], callback);
|
|
9073
|
-
}
|
|
9074
|
-
}
|
|
9075
|
-
continue;
|
|
9076
|
-
}
|
|
9077
|
-
if (element.element === "table") {
|
|
9078
|
-
const tableData = element.data;
|
|
9079
|
-
for (const row of tableData.rows) {
|
|
9080
|
-
for (const cell of row.cells) {
|
|
9081
|
-
walkElements(cell.elements, callback);
|
|
9082
|
-
}
|
|
9083
|
-
}
|
|
9084
|
-
continue;
|
|
9085
|
-
}
|
|
9086
|
-
if (element.element === "definition-list") {
|
|
9087
|
-
const defListData = element.data;
|
|
9088
|
-
for (const item of defListData) {
|
|
9089
|
-
walkElements(item.key, callback);
|
|
9090
|
-
walkElements(item.value, callback);
|
|
9091
|
-
}
|
|
9092
|
-
continue;
|
|
9093
|
-
}
|
|
9094
|
-
if (element.element === "tab-view") {
|
|
9095
|
-
const tabData = element.data;
|
|
9096
|
-
for (const tab of tabData) {
|
|
9097
|
-
walkElements(tab.elements, callback);
|
|
9098
|
-
}
|
|
9099
|
-
continue;
|
|
9100
|
-
}
|
|
9101
|
-
if ("data" in element && element.data && typeof element.data === "object") {
|
|
9102
|
-
const data = element.data;
|
|
9103
|
-
if ("elements" in data && Array.isArray(data.elements)) {
|
|
9104
|
-
walkElements(data.elements, callback);
|
|
9105
|
-
}
|
|
9106
|
-
}
|
|
9107
|
-
}
|
|
9108
|
-
}
|
|
9109
|
-
function mapElementChildren(element, transform) {
|
|
9110
|
-
if (element.element === "list") {
|
|
9111
|
-
const listData = element.data;
|
|
9112
|
-
const newItems = [];
|
|
9113
|
-
for (const item of listData.items) {
|
|
9114
|
-
if (item["item-type"] === "elements") {
|
|
9115
|
-
newItems.push({
|
|
9116
|
-
"item-type": "elements",
|
|
9117
|
-
attributes: item.attributes,
|
|
9118
|
-
elements: transform(item.elements)
|
|
9119
|
-
});
|
|
9120
|
-
} else if (item["item-type"] === "sub-list") {
|
|
9121
|
-
const subListResult = transform([{ element: "list", data: item.data }]);
|
|
9122
|
-
const resolvedList = subListResult[0];
|
|
9123
|
-
if (resolvedList?.element === "list") {
|
|
9124
|
-
newItems.push({
|
|
9125
|
-
"item-type": "sub-list",
|
|
9126
|
-
element: "list",
|
|
9127
|
-
data: resolvedList.data
|
|
9128
|
-
});
|
|
9129
|
-
} else {
|
|
9130
|
-
newItems.push(item);
|
|
9131
|
-
}
|
|
9132
|
-
}
|
|
9133
|
-
}
|
|
9134
|
-
return {
|
|
9135
|
-
element: "list",
|
|
9136
|
-
data: { ...listData, items: newItems }
|
|
9137
|
-
};
|
|
9138
|
-
}
|
|
9139
|
-
if (element.element === "table") {
|
|
9140
|
-
const tableData = element.data;
|
|
9141
|
-
const newRows = [];
|
|
9142
|
-
for (const row of tableData.rows) {
|
|
9143
|
-
const newCells = [];
|
|
9144
|
-
for (const cell of row.cells) {
|
|
9145
|
-
newCells.push({ ...cell, elements: transform(cell.elements) });
|
|
9146
|
-
}
|
|
9147
|
-
newRows.push({ ...row, cells: newCells });
|
|
9148
|
-
}
|
|
9149
|
-
return {
|
|
9150
|
-
element: "table",
|
|
9151
|
-
data: { ...tableData, rows: newRows }
|
|
9152
|
-
};
|
|
9153
|
-
}
|
|
9154
|
-
if (element.element === "definition-list") {
|
|
9155
|
-
const defListData = element.data;
|
|
9156
|
-
const newItems = [];
|
|
9157
|
-
for (const item of defListData) {
|
|
9158
|
-
newItems.push({
|
|
9159
|
-
key_string: item.key_string,
|
|
9160
|
-
key: transform(item.key),
|
|
9161
|
-
value: transform(item.value)
|
|
9162
|
-
});
|
|
9163
|
-
}
|
|
9164
|
-
return {
|
|
9165
|
-
element: "definition-list",
|
|
9166
|
-
data: newItems
|
|
9167
|
-
};
|
|
9168
|
-
}
|
|
9169
|
-
if (element.element === "tab-view") {
|
|
9170
|
-
const tabData = element.data;
|
|
9171
|
-
const newTabs = [];
|
|
9172
|
-
for (const tab of tabData) {
|
|
9173
|
-
newTabs.push({ ...tab, elements: transform(tab.elements) });
|
|
9174
|
-
}
|
|
9175
|
-
return {
|
|
9176
|
-
element: "tab-view",
|
|
9177
|
-
data: newTabs
|
|
9178
|
-
};
|
|
9179
|
-
}
|
|
9180
|
-
if ("data" in element && element.data && typeof element.data === "object") {
|
|
9181
|
-
const data = element.data;
|
|
9182
|
-
if ("elements" in data && Array.isArray(data.elements)) {
|
|
9183
|
-
return {
|
|
9184
|
-
...element,
|
|
9185
|
-
data: {
|
|
9186
|
-
...data,
|
|
9187
|
-
elements: transform(data.elements)
|
|
9188
|
-
}
|
|
9189
|
-
};
|
|
9459
|
+
case "I":
|
|
9460
|
+
return pad(date.getHours() % 12 || 12);
|
|
9461
|
+
case "M":
|
|
9462
|
+
return pad(date.getMinutes());
|
|
9463
|
+
case "S":
|
|
9464
|
+
return pad(date.getSeconds());
|
|
9465
|
+
case "p":
|
|
9466
|
+
return date.getHours() < 12 ? "AM" : "PM";
|
|
9467
|
+
case "b":
|
|
9468
|
+
return MONTHS_SHORT[date.getMonth()] ?? "";
|
|
9469
|
+
case "B":
|
|
9470
|
+
return MONTHS[date.getMonth()] ?? "";
|
|
9471
|
+
case "a":
|
|
9472
|
+
return DAYS_SHORT[date.getDay()] ?? "";
|
|
9473
|
+
case "A":
|
|
9474
|
+
return DAYS[date.getDay()] ?? "";
|
|
9475
|
+
case "w":
|
|
9476
|
+
return String(date.getDay());
|
|
9477
|
+
case "j":
|
|
9478
|
+
return pad(getDayOfYear(date), 3);
|
|
9479
|
+
case "Z":
|
|
9480
|
+
return "UTC";
|
|
9481
|
+
case "z":
|
|
9482
|
+
return "+0000";
|
|
9483
|
+
case "%":
|
|
9484
|
+
return "%";
|
|
9485
|
+
default:
|
|
9486
|
+
return `%${token}`;
|
|
9190
9487
|
}
|
|
9191
|
-
}
|
|
9192
|
-
return element;
|
|
9488
|
+
});
|
|
9193
9489
|
}
|
|
9194
|
-
function
|
|
9195
|
-
|
|
9196
|
-
|
|
9197
|
-
|
|
9198
|
-
|
|
9199
|
-
|
|
9200
|
-
|
|
9201
|
-
|
|
9202
|
-
|
|
9203
|
-
|
|
9204
|
-
|
|
9205
|
-
|
|
9206
|
-
|
|
9207
|
-
|
|
9208
|
-
|
|
9209
|
-
const result = transform([{ element: "list", data: item.data }], currentState);
|
|
9210
|
-
const resolvedList = result.elements[0];
|
|
9211
|
-
if (resolvedList?.element === "list") {
|
|
9212
|
-
newItems.push({
|
|
9213
|
-
"item-type": "sub-list",
|
|
9214
|
-
element: "list",
|
|
9215
|
-
data: resolvedList.data
|
|
9216
|
-
});
|
|
9217
|
-
} else {
|
|
9218
|
-
newItems.push(item);
|
|
9219
|
-
}
|
|
9220
|
-
currentState = result.state;
|
|
9221
|
-
}
|
|
9222
|
-
}
|
|
9223
|
-
return {
|
|
9224
|
-
element: {
|
|
9225
|
-
element: "list",
|
|
9226
|
-
data: { ...listData, items: newItems }
|
|
9227
|
-
},
|
|
9228
|
-
state: currentState
|
|
9229
|
-
};
|
|
9230
|
-
}
|
|
9231
|
-
if (element.element === "table") {
|
|
9232
|
-
const tableData = element.data;
|
|
9233
|
-
const newRows = [];
|
|
9234
|
-
let currentState = state;
|
|
9235
|
-
for (const row of tableData.rows) {
|
|
9236
|
-
const newCells = [];
|
|
9237
|
-
for (const cell of row.cells) {
|
|
9238
|
-
const result = transform(cell.elements, currentState);
|
|
9239
|
-
newCells.push({ ...cell, elements: result.elements });
|
|
9240
|
-
currentState = result.state;
|
|
9241
|
-
}
|
|
9242
|
-
newRows.push({ ...row, cells: newCells });
|
|
9490
|
+
function getDayOfYear(date) {
|
|
9491
|
+
const start = new Date(date.getFullYear(), 0, 0);
|
|
9492
|
+
const diff = date.getTime() - start.getTime();
|
|
9493
|
+
const oneDay = 1000 * 60 * 60 * 24;
|
|
9494
|
+
return Math.floor(diff / oneDay);
|
|
9495
|
+
}
|
|
9496
|
+
|
|
9497
|
+
// packages/parser/src/parser/rules/block/module/listusers/compiler.ts
|
|
9498
|
+
var VARIABLE_REGEX2 = /%%([a-z_]+)%%/gi;
|
|
9499
|
+
function compileListUsersTemplate(template) {
|
|
9500
|
+
const parts = [];
|
|
9501
|
+
let lastIndex = 0;
|
|
9502
|
+
for (const match of template.matchAll(VARIABLE_REGEX2)) {
|
|
9503
|
+
if (match.index !== undefined && match.index > lastIndex) {
|
|
9504
|
+
parts.push(template.slice(lastIndex, match.index));
|
|
9243
9505
|
}
|
|
9244
|
-
|
|
9245
|
-
|
|
9246
|
-
|
|
9247
|
-
|
|
9248
|
-
|
|
9249
|
-
|
|
9250
|
-
};
|
|
9506
|
+
const [, varName] = match;
|
|
9507
|
+
if (!varName)
|
|
9508
|
+
continue;
|
|
9509
|
+
const getter = createVariableGetter2(varName.toLowerCase());
|
|
9510
|
+
parts.push(getter);
|
|
9511
|
+
lastIndex = match.index !== undefined ? match.index + match[0].length : lastIndex;
|
|
9251
9512
|
}
|
|
9252
|
-
if (
|
|
9253
|
-
|
|
9254
|
-
const newItems = [];
|
|
9255
|
-
let currentState = state;
|
|
9256
|
-
for (const item of defListData) {
|
|
9257
|
-
const keyResult = transform(item.key, currentState);
|
|
9258
|
-
currentState = keyResult.state;
|
|
9259
|
-
const valueResult = transform(item.value, currentState);
|
|
9260
|
-
currentState = valueResult.state;
|
|
9261
|
-
newItems.push({
|
|
9262
|
-
key_string: item.key_string,
|
|
9263
|
-
key: keyResult.elements,
|
|
9264
|
-
value: valueResult.elements
|
|
9265
|
-
});
|
|
9266
|
-
}
|
|
9267
|
-
return {
|
|
9268
|
-
element: {
|
|
9269
|
-
element: "definition-list",
|
|
9270
|
-
data: newItems
|
|
9271
|
-
},
|
|
9272
|
-
state: currentState
|
|
9273
|
-
};
|
|
9513
|
+
if (lastIndex < template.length) {
|
|
9514
|
+
parts.push(template.slice(lastIndex));
|
|
9274
9515
|
}
|
|
9275
|
-
|
|
9276
|
-
|
|
9277
|
-
const
|
|
9278
|
-
|
|
9279
|
-
for (const tab of tabData) {
|
|
9280
|
-
const result = transform(tab.elements, currentState);
|
|
9281
|
-
newTabs.push({ ...tab, elements: result.elements });
|
|
9282
|
-
currentState = result.state;
|
|
9516
|
+
return (ctx) => {
|
|
9517
|
+
let result = "";
|
|
9518
|
+
for (const part of parts) {
|
|
9519
|
+
result += typeof part === "string" ? part : part(ctx);
|
|
9283
9520
|
}
|
|
9284
|
-
return
|
|
9285
|
-
|
|
9286
|
-
|
|
9287
|
-
|
|
9288
|
-
|
|
9289
|
-
|
|
9290
|
-
|
|
9521
|
+
return result;
|
|
9522
|
+
};
|
|
9523
|
+
}
|
|
9524
|
+
function createVariableGetter2(name) {
|
|
9525
|
+
switch (name) {
|
|
9526
|
+
case "number":
|
|
9527
|
+
return (ctx) => String(ctx.user.number);
|
|
9528
|
+
case "title":
|
|
9529
|
+
return (ctx) => ctx.user.title;
|
|
9530
|
+
case "name":
|
|
9531
|
+
return (ctx) => ctx.user.name;
|
|
9532
|
+
default:
|
|
9533
|
+
return () => "";
|
|
9291
9534
|
}
|
|
9292
|
-
|
|
9293
|
-
|
|
9294
|
-
|
|
9295
|
-
|
|
9296
|
-
|
|
9297
|
-
|
|
9298
|
-
|
|
9299
|
-
|
|
9300
|
-
|
|
9301
|
-
|
|
9302
|
-
|
|
9303
|
-
|
|
9304
|
-
|
|
9305
|
-
|
|
9535
|
+
}
|
|
9536
|
+
|
|
9537
|
+
// packages/parser/src/parser/rules/block/module/listusers/extract.ts
|
|
9538
|
+
var VARIABLE_REGEX3 = /%%([a-z_]+)%%/gi;
|
|
9539
|
+
var KNOWN_VARIABLES = ["number", "title", "name"];
|
|
9540
|
+
function extractListUsersVariables(template) {
|
|
9541
|
+
const variables = new Set;
|
|
9542
|
+
for (const match of template.matchAll(VARIABLE_REGEX3)) {
|
|
9543
|
+
const [, varName] = match;
|
|
9544
|
+
if (!varName)
|
|
9545
|
+
continue;
|
|
9546
|
+
const normalized = varName.toLowerCase();
|
|
9547
|
+
if (KNOWN_VARIABLES.includes(normalized)) {
|
|
9548
|
+
variables.add(normalized);
|
|
9306
9549
|
}
|
|
9307
9550
|
}
|
|
9308
|
-
return
|
|
9551
|
+
return Array.from(variables);
|
|
9309
9552
|
}
|
|
9310
9553
|
|
|
9311
9554
|
// packages/parser/src/parser/rules/block/module/listpages/extract.ts
|
|
@@ -9964,6 +10207,110 @@ function resolveIfTags(data, pageTags) {
|
|
|
9964
10207
|
const matched = evaluateTagCondition(condition, pageTags);
|
|
9965
10208
|
return { evaluated: true, matched };
|
|
9966
10209
|
}
|
|
10210
|
+
// packages/parser/src/parser/rules/block/module/iftags/preprocess.ts
|
|
10211
|
+
var BASE_PLACEHOLDER_OPEN = "";
|
|
10212
|
+
var BASE_PLACEHOLDER_CLOSE = "";
|
|
10213
|
+
var INNERMOST_IFTAGS_PATTERN = /\[\[\s*iftags\b([^\]]*)\]\]((?:(?!\[\[\s*iftags\b|\[\[\/\s*iftags\s*\]\]).)*)\[\[\/\s*iftags\s*\]\]/gis;
|
|
10214
|
+
var RAW_BLOCK_OPEN_PATTERN = /\[\[\s*(code|html)\b[^\]]*\]\]/iy;
|
|
10215
|
+
function preprocessIftags(source, pageTags) {
|
|
10216
|
+
if (pageTags === null)
|
|
10217
|
+
return source;
|
|
10218
|
+
if (!source.includes("[["))
|
|
10219
|
+
return source;
|
|
10220
|
+
const sentinels = makeUniqueSentinels(source);
|
|
10221
|
+
const { masked, placeholders } = maskRawRegions(source, sentinels);
|
|
10222
|
+
const reduced = reduceIftags(masked, pageTags);
|
|
10223
|
+
return restorePlaceholders(reduced, placeholders, sentinels);
|
|
10224
|
+
}
|
|
10225
|
+
function makeUniqueSentinels(source) {
|
|
10226
|
+
let open = BASE_PLACEHOLDER_OPEN;
|
|
10227
|
+
let close = BASE_PLACEHOLDER_CLOSE;
|
|
10228
|
+
while (source.includes(open) || source.includes(close)) {
|
|
10229
|
+
open += BASE_PLACEHOLDER_OPEN;
|
|
10230
|
+
close += BASE_PLACEHOLDER_CLOSE;
|
|
10231
|
+
}
|
|
10232
|
+
return { open, close };
|
|
10233
|
+
}
|
|
10234
|
+
function reduceIftags(source, pageTags) {
|
|
10235
|
+
let current = source;
|
|
10236
|
+
const maxIterations = source.length + 1;
|
|
10237
|
+
for (let i = 0;i < maxIterations; i++) {
|
|
10238
|
+
const next = current.replace(INNERMOST_IFTAGS_PATTERN, (_, cond, body) => {
|
|
10239
|
+
const condition = parseTagCondition(cond);
|
|
10240
|
+
return evaluateTagCondition(condition, pageTags) ? body : "";
|
|
10241
|
+
});
|
|
10242
|
+
if (next === current)
|
|
10243
|
+
return current;
|
|
10244
|
+
current = next;
|
|
10245
|
+
}
|
|
10246
|
+
return current;
|
|
10247
|
+
}
|
|
10248
|
+
function maskRawRegions(source, sentinels) {
|
|
10249
|
+
const placeholders = [];
|
|
10250
|
+
let masked = "";
|
|
10251
|
+
let i = 0;
|
|
10252
|
+
while (i < source.length) {
|
|
10253
|
+
if (source[i] === "[" && source[i + 1] === "[") {
|
|
10254
|
+
RAW_BLOCK_OPEN_PATTERN.lastIndex = i;
|
|
10255
|
+
const openMatch = RAW_BLOCK_OPEN_PATTERN.exec(source);
|
|
10256
|
+
if (openMatch) {
|
|
10257
|
+
const name = openMatch[1].toLowerCase();
|
|
10258
|
+
const openLen = openMatch[0].length;
|
|
10259
|
+
const closePattern = new RegExp(`\\[\\[\\/\\s*${name}\\s*\\]\\]`, "ig");
|
|
10260
|
+
closePattern.lastIndex = i + openLen;
|
|
10261
|
+
const closeMatch = closePattern.exec(source);
|
|
10262
|
+
if (closeMatch) {
|
|
10263
|
+
const regionEnd = closeMatch.index + closeMatch[0].length;
|
|
10264
|
+
masked += pushPlaceholder(placeholders, source.slice(i, regionEnd), sentinels);
|
|
10265
|
+
i = regionEnd;
|
|
10266
|
+
continue;
|
|
10267
|
+
}
|
|
10268
|
+
if (name === "code") {
|
|
10269
|
+
masked += pushPlaceholder(placeholders, source.slice(i), sentinels);
|
|
10270
|
+
i = source.length;
|
|
10271
|
+
continue;
|
|
10272
|
+
}
|
|
10273
|
+
}
|
|
10274
|
+
}
|
|
10275
|
+
if (source[i] === "@" && source[i + 1] === "<") {
|
|
10276
|
+
const close = source.indexOf(">@", i + 2);
|
|
10277
|
+
const newline = source.indexOf(`
|
|
10278
|
+
`, i + 2);
|
|
10279
|
+
if (close !== -1 && (newline === -1 || close < newline)) {
|
|
10280
|
+
const regionEnd = close + 2;
|
|
10281
|
+
masked += pushPlaceholder(placeholders, source.slice(i, regionEnd), sentinels);
|
|
10282
|
+
i = regionEnd;
|
|
10283
|
+
continue;
|
|
10284
|
+
}
|
|
10285
|
+
}
|
|
10286
|
+
if (source[i] === "@" && source[i + 1] === "@") {
|
|
10287
|
+
const close = source.indexOf("@@", i + 2);
|
|
10288
|
+
const newline = source.indexOf(`
|
|
10289
|
+
`, i + 2);
|
|
10290
|
+
if (close !== -1 && (newline === -1 || close < newline)) {
|
|
10291
|
+
const regionEnd = close + 2;
|
|
10292
|
+
masked += pushPlaceholder(placeholders, source.slice(i, regionEnd), sentinels);
|
|
10293
|
+
i = regionEnd;
|
|
10294
|
+
continue;
|
|
10295
|
+
}
|
|
10296
|
+
}
|
|
10297
|
+
masked += source[i];
|
|
10298
|
+
i++;
|
|
10299
|
+
}
|
|
10300
|
+
return { masked, placeholders };
|
|
10301
|
+
}
|
|
10302
|
+
function pushPlaceholder(placeholders, text, sentinels) {
|
|
10303
|
+
const idx = placeholders.length;
|
|
10304
|
+
placeholders.push(text);
|
|
10305
|
+
return `${sentinels.open}${idx}${sentinels.close}`;
|
|
10306
|
+
}
|
|
10307
|
+
function escapeRegex(str) {
|
|
10308
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
10309
|
+
}
|
|
10310
|
+
function restorePlaceholders(source, placeholders, sentinels) {
|
|
10311
|
+
const pattern = new RegExp(`${escapeRegex(sentinels.open)}(\\d+)${escapeRegex(sentinels.close)}`, "g");
|
|
10312
|
+
return source.replace(pattern, (_, idx) => placeholders[Number(idx)] ?? "");
|
|
10313
|
+
}
|
|
9967
10314
|
// packages/parser/src/parser/rules/block/module/include/resolve.ts
|
|
9968
10315
|
function resolveIncludes(source, fetcher, options) {
|
|
9969
10316
|
if (options?.settings && !options.settings.enablePageSyntax) {
|
|
@@ -10009,7 +10356,67 @@ async function resolveIncludesAsync(source, fetcher, options) {
|
|
|
10009
10356
|
};
|
|
10010
10357
|
return expandIterativeAsync(source, cachedFetcher, maxIterations);
|
|
10011
10358
|
}
|
|
10012
|
-
var
|
|
10359
|
+
var INCLUDE_OPEN_PATTERN = /^\[\[include\s/gim;
|
|
10360
|
+
function isRestOfLineBlank(source, pos) {
|
|
10361
|
+
for (let i = pos;i < source.length; i++) {
|
|
10362
|
+
const ch = source[i];
|
|
10363
|
+
if (ch === `
|
|
10364
|
+
`)
|
|
10365
|
+
return true;
|
|
10366
|
+
if (ch !== " " && ch !== "\t" && ch !== "\r")
|
|
10367
|
+
return false;
|
|
10368
|
+
}
|
|
10369
|
+
return true;
|
|
10370
|
+
}
|
|
10371
|
+
function scanIncludeDirectives(source) {
|
|
10372
|
+
const matches = [];
|
|
10373
|
+
const opener = new RegExp(INCLUDE_OPEN_PATTERN.source, INCLUDE_OPEN_PATTERN.flags);
|
|
10374
|
+
let m;
|
|
10375
|
+
while ((m = opener.exec(source)) !== null) {
|
|
10376
|
+
const start = m.index;
|
|
10377
|
+
const contentStart = start + m[0].length;
|
|
10378
|
+
const firstNewline = source.indexOf(`
|
|
10379
|
+
`, start);
|
|
10380
|
+
let depth = 0;
|
|
10381
|
+
let linkDepth = 0;
|
|
10382
|
+
let i = start;
|
|
10383
|
+
let closeEnd = -1;
|
|
10384
|
+
while (i < source.length) {
|
|
10385
|
+
if (source.startsWith("[[[", i)) {
|
|
10386
|
+
linkDepth++;
|
|
10387
|
+
i += 3;
|
|
10388
|
+
} else if (linkDepth > 0 && source.startsWith("]]]", i)) {
|
|
10389
|
+
linkDepth--;
|
|
10390
|
+
i += 3;
|
|
10391
|
+
} else if (linkDepth > 0) {
|
|
10392
|
+
i++;
|
|
10393
|
+
} else if (source.startsWith("[[", i)) {
|
|
10394
|
+
depth++;
|
|
10395
|
+
i += 2;
|
|
10396
|
+
} else if (source.startsWith("]]", i)) {
|
|
10397
|
+
const closeStart = i;
|
|
10398
|
+
depth--;
|
|
10399
|
+
i += 2;
|
|
10400
|
+
if (depth <= 0) {
|
|
10401
|
+
const onOpenerLine = firstNewline === -1 || closeStart < firstNewline;
|
|
10402
|
+
if (onOpenerLine || isRestOfLineBlank(source, i)) {
|
|
10403
|
+
closeEnd = i;
|
|
10404
|
+
break;
|
|
10405
|
+
}
|
|
10406
|
+
}
|
|
10407
|
+
} else {
|
|
10408
|
+
i++;
|
|
10409
|
+
}
|
|
10410
|
+
}
|
|
10411
|
+
if (closeEnd === -1) {
|
|
10412
|
+
opener.lastIndex = start + 2;
|
|
10413
|
+
continue;
|
|
10414
|
+
}
|
|
10415
|
+
matches.push({ start, end: closeEnd, inner: source.slice(contentStart, closeEnd - 2) });
|
|
10416
|
+
opener.lastIndex = closeEnd;
|
|
10417
|
+
}
|
|
10418
|
+
return matches;
|
|
10419
|
+
}
|
|
10013
10420
|
function parseIncludeDirective(inner) {
|
|
10014
10421
|
const normalized = inner.replace(/\n/g, " ");
|
|
10015
10422
|
const parts = normalized.split("|");
|
|
@@ -10033,14 +10440,24 @@ function parseIncludeDirective(inner) {
|
|
|
10033
10440
|
}
|
|
10034
10441
|
}
|
|
10035
10442
|
const variables = {};
|
|
10443
|
+
const hasConcrete = new Set;
|
|
10036
10444
|
for (const segment of varSegments) {
|
|
10037
10445
|
const eqIndex = segment.indexOf("=");
|
|
10038
|
-
if (eqIndex
|
|
10039
|
-
|
|
10040
|
-
|
|
10041
|
-
|
|
10446
|
+
if (eqIndex === -1)
|
|
10447
|
+
continue;
|
|
10448
|
+
const key = segment.slice(0, eqIndex).trim();
|
|
10449
|
+
if (!key)
|
|
10450
|
+
continue;
|
|
10451
|
+
const value = segment.slice(eqIndex + 1).trim();
|
|
10452
|
+
const isPlaceholder = /^\{\$[^}]*\}$/.test(value);
|
|
10453
|
+
const isConcrete = value !== "" && !isPlaceholder;
|
|
10454
|
+
if (isConcrete) {
|
|
10455
|
+
if (!hasConcrete.has(key)) {
|
|
10042
10456
|
variables[key] = value;
|
|
10457
|
+
hasConcrete.add(key);
|
|
10043
10458
|
}
|
|
10459
|
+
} else if (!Object.hasOwn(variables, key)) {
|
|
10460
|
+
variables[key] = value;
|
|
10044
10461
|
}
|
|
10045
10462
|
}
|
|
10046
10463
|
let location;
|
|
@@ -10057,7 +10474,7 @@ function parseIncludeDirective(inner) {
|
|
|
10057
10474
|
}
|
|
10058
10475
|
return { location, variables };
|
|
10059
10476
|
}
|
|
10060
|
-
function replaceOneInclude(
|
|
10477
|
+
function replaceOneInclude(inner, fetcher) {
|
|
10061
10478
|
const { location, variables } = parseIncludeDirective(inner);
|
|
10062
10479
|
const content = fetcher(location);
|
|
10063
10480
|
if (content === null) {
|
|
@@ -10070,25 +10487,33 @@ Page to be included "${location.page}" cannot be found!
|
|
|
10070
10487
|
function expandIterative(source, fetcher, maxIterations) {
|
|
10071
10488
|
let current = source;
|
|
10072
10489
|
for (let i = 0;i < maxIterations; i++) {
|
|
10073
|
-
const
|
|
10074
|
-
|
|
10075
|
-
|
|
10490
|
+
const directives = scanIncludeDirectives(current);
|
|
10491
|
+
if (directives.length === 0)
|
|
10492
|
+
break;
|
|
10493
|
+
let result = "";
|
|
10494
|
+
let lastPos = 0;
|
|
10495
|
+
for (const { start, end, inner } of directives) {
|
|
10496
|
+
result += current.slice(lastPos, start);
|
|
10497
|
+
result += replaceOneInclude(inner, fetcher);
|
|
10498
|
+
lastPos = end;
|
|
10499
|
+
}
|
|
10500
|
+
result += current.slice(lastPos);
|
|
10501
|
+
if (result === current)
|
|
10076
10502
|
break;
|
|
10503
|
+
current = result;
|
|
10077
10504
|
}
|
|
10078
10505
|
return current;
|
|
10079
10506
|
}
|
|
10080
10507
|
async function expandIterativeAsync(source, fetcher, maxIterations) {
|
|
10081
10508
|
let current = source;
|
|
10082
10509
|
for (let i = 0;i < maxIterations; i++) {
|
|
10083
|
-
const
|
|
10084
|
-
|
|
10510
|
+
const directives = scanIncludeDirectives(current);
|
|
10511
|
+
if (directives.length === 0)
|
|
10512
|
+
break;
|
|
10085
10513
|
let result = "";
|
|
10086
10514
|
let lastPos = 0;
|
|
10087
|
-
|
|
10088
|
-
|
|
10089
|
-
const fullMatch = match[0];
|
|
10090
|
-
const inner = match[1];
|
|
10091
|
-
result += current.slice(lastPos, match.index);
|
|
10515
|
+
for (const { start, end, inner } of directives) {
|
|
10516
|
+
result += current.slice(lastPos, start);
|
|
10092
10517
|
const { location, variables } = parseIncludeDirective(inner);
|
|
10093
10518
|
const content = await fetcher(location);
|
|
10094
10519
|
if (content === null) {
|
|
@@ -10098,12 +10523,12 @@ Page to be included "${location.page}" cannot be found!
|
|
|
10098
10523
|
} else {
|
|
10099
10524
|
result += substituteVariables(content, variables);
|
|
10100
10525
|
}
|
|
10101
|
-
lastPos =
|
|
10526
|
+
lastPos = end;
|
|
10102
10527
|
}
|
|
10103
10528
|
result += current.slice(lastPos);
|
|
10104
|
-
|
|
10105
|
-
if (current === previous)
|
|
10529
|
+
if (result === current)
|
|
10106
10530
|
break;
|
|
10531
|
+
current = result;
|
|
10107
10532
|
}
|
|
10108
10533
|
return current;
|
|
10109
10534
|
}
|