@wdprlib/parser 2.2.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 +806 -439
- package/dist/index.d.cts +31 -1
- package/dist/index.d.ts +31 -1
- package/dist/index.js +806 -439
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -27,6 +27,7 @@ class Lexer {
|
|
|
27
27
|
state;
|
|
28
28
|
options;
|
|
29
29
|
splitBlockClosePositions = new Set;
|
|
30
|
+
blockOpenerDepth = 0;
|
|
30
31
|
constructor(source, options = {}) {
|
|
31
32
|
this.options = {
|
|
32
33
|
trackPositions: options.trackPositions ?? true
|
|
@@ -126,6 +127,11 @@ class Lexer {
|
|
|
126
127
|
const position = this.options.trackPositions ? createPosition(startPos, endPos) : createPosition(createPoint(0, 0, 0), createPoint(0, 0, 0));
|
|
127
128
|
const lineStart = this.state.tokens.length === 0 || this.state.tokens[this.state.tokens.length - 1]?.type === "NEWLINE";
|
|
128
129
|
this.state.tokens.push(createToken(type, value, position, lineStart));
|
|
130
|
+
if (type === "BLOCK_OPEN" || type === "BLOCK_END_OPEN") {
|
|
131
|
+
this.blockOpenerDepth++;
|
|
132
|
+
} else if (type === "BLOCK_CLOSE" && this.blockOpenerDepth > 0) {
|
|
133
|
+
this.blockOpenerDepth--;
|
|
134
|
+
}
|
|
129
135
|
}
|
|
130
136
|
scanToken() {
|
|
131
137
|
const char = this.current();
|
|
@@ -390,7 +396,7 @@ class Lexer {
|
|
|
390
396
|
}
|
|
391
397
|
if (char === '"') {
|
|
392
398
|
const lastNonWs = this.lastNonWhitespaceTokenType();
|
|
393
|
-
if (lastNonWs === "EQUALS") {
|
|
399
|
+
if (this.blockOpenerDepth > 0 && lastNonWs === "EQUALS") {
|
|
394
400
|
let quoted = this.advance();
|
|
395
401
|
while (!this.isAtEnd() && this.current() !== '"' && this.current() !== `
|
|
396
402
|
`) {
|
|
@@ -635,6 +641,28 @@ var KNOWN_BLOCK_NAMES = new Set([
|
|
|
635
641
|
"gallery",
|
|
636
642
|
"file"
|
|
637
643
|
]);
|
|
644
|
+
var INDENT_ACCEPTING_BLOCK_NAMES = new Set([
|
|
645
|
+
"bibliography",
|
|
646
|
+
"ul",
|
|
647
|
+
"ol",
|
|
648
|
+
"li",
|
|
649
|
+
"code",
|
|
650
|
+
"collapsible",
|
|
651
|
+
"div",
|
|
652
|
+
"div_",
|
|
653
|
+
"embed",
|
|
654
|
+
"embedvideo",
|
|
655
|
+
"embedaudio",
|
|
656
|
+
"html",
|
|
657
|
+
"iframe",
|
|
658
|
+
"iftags",
|
|
659
|
+
"math",
|
|
660
|
+
"module",
|
|
661
|
+
"module654",
|
|
662
|
+
"table",
|
|
663
|
+
"tabview",
|
|
664
|
+
"tabs"
|
|
665
|
+
]);
|
|
638
666
|
|
|
639
667
|
// packages/parser/src/parser/rules/utils.ts
|
|
640
668
|
var SAFE_ATTRIBUTES = new Set([
|
|
@@ -761,13 +789,14 @@ function parseBlockName(ctx, startPos) {
|
|
|
761
789
|
|
|
762
790
|
// packages/parser/src/parser/rules/inline/utils.ts
|
|
763
791
|
function isExcludedBlockToken(ctx, tokenPos) {
|
|
764
|
-
|
|
792
|
+
const excluded = ctx.scope.excludedBlockNames;
|
|
793
|
+
if (!excluded?.size)
|
|
765
794
|
return false;
|
|
766
795
|
const token = ctx.tokens[tokenPos];
|
|
767
796
|
if (token?.type !== "BLOCK_OPEN" && token?.type !== "BLOCK_END_OPEN")
|
|
768
797
|
return false;
|
|
769
798
|
const nameResult = parseBlockName(ctx, tokenPos + 1);
|
|
770
|
-
return nameResult !== null &&
|
|
799
|
+
return nameResult !== null && excluded.has(nameResult.name);
|
|
771
800
|
}
|
|
772
801
|
function isUnknownBlockToken(ctx, tokenPos) {
|
|
773
802
|
const token = ctx.tokens[tokenPos];
|
|
@@ -782,6 +811,15 @@ function isUnknownBlockToken(ctx, tokenPos) {
|
|
|
782
811
|
}
|
|
783
812
|
return !KNOWN_BLOCK_NAMES.has(nameResult.name);
|
|
784
813
|
}
|
|
814
|
+
function isIndentAcceptingBlock(ctx, tokenPos) {
|
|
815
|
+
const token = ctx.tokens[tokenPos];
|
|
816
|
+
if (token?.type !== "BLOCK_OPEN" && token?.type !== "BLOCK_END_OPEN")
|
|
817
|
+
return false;
|
|
818
|
+
const nameResult = parseBlockName(ctx, tokenPos + 1);
|
|
819
|
+
if (nameResult === null)
|
|
820
|
+
return false;
|
|
821
|
+
return INDENT_ACCEPTING_BLOCK_NAMES.has(nameResult.name);
|
|
822
|
+
}
|
|
785
823
|
function canApplyInlineRule(rule, token) {
|
|
786
824
|
if (rule.startTokens.length === 0) {
|
|
787
825
|
return true;
|
|
@@ -799,9 +837,9 @@ function parseInlineUntil(ctx, endType) {
|
|
|
799
837
|
if (!token || token.type === "EOF") {
|
|
800
838
|
break;
|
|
801
839
|
}
|
|
802
|
-
if (paragraphMode && ctx.blockCloseCondition) {
|
|
840
|
+
if (paragraphMode && ctx.scope.blockCloseCondition) {
|
|
803
841
|
const checkCtx = { ...ctx, pos };
|
|
804
|
-
if (ctx.blockCloseCondition(checkCtx)) {
|
|
842
|
+
if (ctx.scope.blockCloseCondition(checkCtx)) {
|
|
805
843
|
break;
|
|
806
844
|
}
|
|
807
845
|
}
|
|
@@ -853,7 +891,7 @@ function parseInlineUntil(ctx, endType) {
|
|
|
853
891
|
skipWhitespace++;
|
|
854
892
|
}
|
|
855
893
|
const blockNameToken = ctx.tokens[afterOpen + skipWhitespace];
|
|
856
|
-
if (blockNameToken && (blockNameToken.type === "TEXT" || blockNameToken.type === "IDENTIFIER") && blockNameToken.value.toLowerCase() === "footnoteblock" && ctx.footnoteBlockParsed) {
|
|
894
|
+
if (blockNameToken && (blockNameToken.type === "TEXT" || blockNameToken.type === "IDENTIFIER") && blockNameToken.value.toLowerCase() === "footnoteblock" && ctx.scope.footnoteBlockParsed) {
|
|
857
895
|
isInvalidBlockOpen = true;
|
|
858
896
|
}
|
|
859
897
|
}
|
|
@@ -875,7 +913,8 @@ function parseInlineUntil(ctx, endType) {
|
|
|
875
913
|
}
|
|
876
914
|
const isExcludedBlock = (nextMeaningfulToken?.type === "BLOCK_OPEN" || nextMeaningfulToken?.type === "BLOCK_END_OPEN") && isExcludedBlockToken(ctx, pos + lookAhead);
|
|
877
915
|
const isUnknownBlock = (nextMeaningfulToken?.type === "BLOCK_OPEN" || nextMeaningfulToken?.type === "BLOCK_END_OPEN") && isUnknownBlockToken(ctx, pos + lookAhead);
|
|
878
|
-
const
|
|
916
|
+
const isIndentedBlockOpener = nextMeaningfulToken && (nextMeaningfulToken.type === "BLOCK_OPEN" || nextMeaningfulToken.type === "BLOCK_END_OPEN") && isIndentAcceptingBlock(ctx, pos + lookAhead);
|
|
917
|
+
const isBlockStart = nextMeaningfulToken && BLOCK_START_TOKENS.includes(nextMeaningfulToken.type) && (nextMeaningfulToken.lineStart || isIndentedBlockOpener) && !isOrphanCloseSpan && !isAnchorName && !isInvalidBlockOpen && !isInvalidHeading && !isExcludedBlock && !isUnknownBlock;
|
|
879
918
|
if (!nextMeaningfulToken || nextMeaningfulToken.type === "NEWLINE" || nextMeaningfulToken.type === "EOF" || isBlockStart) {
|
|
880
919
|
if (isBlockStart && nodes.length > 0) {
|
|
881
920
|
const nextPos = pos + lookAhead;
|
|
@@ -1253,8 +1292,11 @@ function parseBlocksUntil(ctx, closeCondition, options) {
|
|
|
1253
1292
|
...ctx,
|
|
1254
1293
|
pos,
|
|
1255
1294
|
blockRules,
|
|
1256
|
-
|
|
1257
|
-
|
|
1295
|
+
scope: {
|
|
1296
|
+
...ctx.scope,
|
|
1297
|
+
blockCloseCondition: closeCondition,
|
|
1298
|
+
excludedBlockNames: excluded
|
|
1299
|
+
}
|
|
1258
1300
|
};
|
|
1259
1301
|
for (const rule of blockRules) {
|
|
1260
1302
|
if (canApplyBlockRule(rule, token)) {
|
|
@@ -2242,15 +2284,15 @@ var divRule = {
|
|
|
2242
2284
|
if (ctx.tokens[pos]?.type !== "NEWLINE") {
|
|
2243
2285
|
return consumeFailedDiv(ctx);
|
|
2244
2286
|
}
|
|
2245
|
-
if (ctx.divClosesBudget === 0) {
|
|
2287
|
+
if (ctx.scope.divClosesBudget === 0) {
|
|
2246
2288
|
return { success: false };
|
|
2247
2289
|
}
|
|
2248
2290
|
pos++;
|
|
2249
2291
|
consumed++;
|
|
2250
2292
|
const openPosition = openToken.position;
|
|
2251
2293
|
let bodyBudget;
|
|
2252
|
-
if (ctx.divClosesBudget !== undefined) {
|
|
2253
|
-
bodyBudget = ctx.divClosesBudget - 1;
|
|
2294
|
+
if (ctx.scope.divClosesBudget !== undefined) {
|
|
2295
|
+
bodyBudget = ctx.scope.divClosesBudget - 1;
|
|
2254
2296
|
} else {
|
|
2255
2297
|
const closesInScope = countDivCloses(ctx, pos);
|
|
2256
2298
|
bodyBudget = closesInScope > 0 ? closesInScope - 1 : 0;
|
|
@@ -2265,7 +2307,11 @@ var divRule = {
|
|
|
2265
2307
|
}
|
|
2266
2308
|
return false;
|
|
2267
2309
|
};
|
|
2268
|
-
const bodyCtx = {
|
|
2310
|
+
const bodyCtx = {
|
|
2311
|
+
...ctx,
|
|
2312
|
+
pos,
|
|
2313
|
+
scope: { ...ctx.scope, divClosesBudget: bodyBudget }
|
|
2314
|
+
};
|
|
2269
2315
|
let children;
|
|
2270
2316
|
if (paragraphStrip) {
|
|
2271
2317
|
const bodyResult = parseBlocksUntil(bodyCtx, closeCondition);
|
|
@@ -3908,10 +3954,10 @@ var footnoteBlockRule = {
|
|
|
3908
3954
|
}
|
|
3909
3955
|
pos++;
|
|
3910
3956
|
consumed++;
|
|
3911
|
-
if (ctx.footnoteBlockParsed) {
|
|
3957
|
+
if (ctx.scope.footnoteBlockParsed) {
|
|
3912
3958
|
return { success: false };
|
|
3913
3959
|
}
|
|
3914
|
-
ctx.
|
|
3960
|
+
ctx.scope = { ...ctx.scope, footnoteBlockParsed: true };
|
|
3915
3961
|
const title = attrs.title !== undefined ? attrs.title : null;
|
|
3916
3962
|
const hide = attrs.hide === "true" || attrs.hide === "yes";
|
|
3917
3963
|
return {
|
|
@@ -4667,6 +4713,24 @@ var mathBlockRule = {
|
|
|
4667
4713
|
};
|
|
4668
4714
|
|
|
4669
4715
|
// packages/parser/src/parser/rules/block/html.ts
|
|
4716
|
+
function lookaheadHasHtmlClose(ctx, from) {
|
|
4717
|
+
for (let i = from;i < ctx.tokens.length; i++) {
|
|
4718
|
+
const t = ctx.tokens[i];
|
|
4719
|
+
if (!t || t.type === "EOF")
|
|
4720
|
+
return false;
|
|
4721
|
+
if (t.type !== "BLOCK_END_OPEN")
|
|
4722
|
+
continue;
|
|
4723
|
+
const closeName = parseBlockName(ctx, i + 1);
|
|
4724
|
+
if (closeName?.name.toLowerCase() !== "html")
|
|
4725
|
+
continue;
|
|
4726
|
+
let cp = i + 1 + closeName.consumed;
|
|
4727
|
+
while (ctx.tokens[cp]?.type === "WHITESPACE")
|
|
4728
|
+
cp++;
|
|
4729
|
+
if (ctx.tokens[cp]?.type === "BLOCK_CLOSE")
|
|
4730
|
+
return true;
|
|
4731
|
+
}
|
|
4732
|
+
return false;
|
|
4733
|
+
}
|
|
4670
4734
|
var htmlBlockRule = {
|
|
4671
4735
|
name: "html",
|
|
4672
4736
|
startTokens: ["BLOCK_OPEN"],
|
|
@@ -4693,20 +4757,32 @@ var htmlBlockRule = {
|
|
|
4693
4757
|
}
|
|
4694
4758
|
pos++;
|
|
4695
4759
|
consumed++;
|
|
4760
|
+
const disabled = ctx.settings.allowHtmlBlocks === false;
|
|
4761
|
+
const hasCloseAhead = disabled && lookaheadHasHtmlClose(ctx, pos);
|
|
4696
4762
|
let contents = "";
|
|
4697
4763
|
let foundClose = false;
|
|
4698
4764
|
while (pos < ctx.tokens.length) {
|
|
4699
4765
|
const token = ctx.tokens[pos];
|
|
4700
4766
|
if (!token || token.type === "EOF")
|
|
4701
4767
|
break;
|
|
4768
|
+
if (disabled && !hasCloseAhead && token.type === "NEWLINE" && ctx.tokens[pos + 1]?.type === "NEWLINE") {
|
|
4769
|
+
break;
|
|
4770
|
+
}
|
|
4702
4771
|
if (token.type === "BLOCK_END_OPEN") {
|
|
4703
4772
|
const closeNameResult = parseBlockName(ctx, pos + 1);
|
|
4704
4773
|
if (closeNameResult?.name.toLowerCase() === "html") {
|
|
4705
|
-
|
|
4706
|
-
|
|
4774
|
+
let checkPos = pos + 1 + closeNameResult.consumed;
|
|
4775
|
+
while (ctx.tokens[checkPos]?.type === "WHITESPACE")
|
|
4776
|
+
checkPos++;
|
|
4777
|
+
if (ctx.tokens[checkPos]?.type === "BLOCK_CLOSE") {
|
|
4778
|
+
foundClose = true;
|
|
4779
|
+
break;
|
|
4780
|
+
}
|
|
4707
4781
|
}
|
|
4708
4782
|
}
|
|
4709
|
-
|
|
4783
|
+
if (!disabled) {
|
|
4784
|
+
contents += token.value;
|
|
4785
|
+
}
|
|
4710
4786
|
pos++;
|
|
4711
4787
|
consumed++;
|
|
4712
4788
|
}
|
|
@@ -4717,7 +4793,16 @@ var htmlBlockRule = {
|
|
|
4717
4793
|
message: "Missing closing tag [[/html]] for [[html]]",
|
|
4718
4794
|
position: openToken.position
|
|
4719
4795
|
});
|
|
4720
|
-
|
|
4796
|
+
if (!disabled) {
|
|
4797
|
+
return { success: false };
|
|
4798
|
+
}
|
|
4799
|
+
ctx.diagnostics.push({
|
|
4800
|
+
severity: "info",
|
|
4801
|
+
code: "html-block-disabled",
|
|
4802
|
+
message: "[[html]] block ignored: disabled by settings",
|
|
4803
|
+
position: openToken.position
|
|
4804
|
+
});
|
|
4805
|
+
return { success: true, elements: [], consumed };
|
|
4721
4806
|
}
|
|
4722
4807
|
if (ctx.tokens[pos]?.type === "BLOCK_END_OPEN") {
|
|
4723
4808
|
pos++;
|
|
@@ -4727,6 +4812,10 @@ var htmlBlockRule = {
|
|
|
4727
4812
|
pos += closeNameResult.consumed;
|
|
4728
4813
|
consumed += closeNameResult.consumed;
|
|
4729
4814
|
}
|
|
4815
|
+
while (ctx.tokens[pos]?.type === "WHITESPACE") {
|
|
4816
|
+
pos++;
|
|
4817
|
+
consumed++;
|
|
4818
|
+
}
|
|
4730
4819
|
if (ctx.tokens[pos]?.type === "BLOCK_CLOSE") {
|
|
4731
4820
|
pos++;
|
|
4732
4821
|
consumed++;
|
|
@@ -4736,6 +4825,15 @@ var htmlBlockRule = {
|
|
|
4736
4825
|
consumed++;
|
|
4737
4826
|
}
|
|
4738
4827
|
}
|
|
4828
|
+
if (disabled) {
|
|
4829
|
+
ctx.diagnostics.push({
|
|
4830
|
+
severity: "info",
|
|
4831
|
+
code: "html-block-disabled",
|
|
4832
|
+
message: "[[html]] block ignored: disabled by settings",
|
|
4833
|
+
position: openToken.position
|
|
4834
|
+
});
|
|
4835
|
+
return { success: true, elements: [], consumed };
|
|
4836
|
+
}
|
|
4739
4837
|
contents = contents.trim();
|
|
4740
4838
|
ctx.htmlBlocks.push(contents);
|
|
4741
4839
|
return {
|
|
@@ -6421,6 +6519,82 @@ var commentRule = {
|
|
|
6421
6519
|
}
|
|
6422
6520
|
};
|
|
6423
6521
|
|
|
6522
|
+
// packages/parser/src/parser/rules/inline/html.ts
|
|
6523
|
+
var htmlInlineRule = {
|
|
6524
|
+
name: "html",
|
|
6525
|
+
startTokens: ["BLOCK_OPEN"],
|
|
6526
|
+
parse(ctx) {
|
|
6527
|
+
const openToken = currentToken(ctx);
|
|
6528
|
+
if (openToken.type !== "BLOCK_OPEN") {
|
|
6529
|
+
return { success: false };
|
|
6530
|
+
}
|
|
6531
|
+
let pos = ctx.pos + 1;
|
|
6532
|
+
let consumed = 1;
|
|
6533
|
+
const nameResult = parseBlockName(ctx, pos);
|
|
6534
|
+
if (!nameResult || nameResult.name.toLowerCase() !== "html") {
|
|
6535
|
+
return { success: false };
|
|
6536
|
+
}
|
|
6537
|
+
pos += nameResult.consumed;
|
|
6538
|
+
consumed += nameResult.consumed;
|
|
6539
|
+
const attrResult = parseAttributesRaw(ctx, pos);
|
|
6540
|
+
pos += attrResult.consumed;
|
|
6541
|
+
consumed += attrResult.consumed;
|
|
6542
|
+
if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
|
|
6543
|
+
return { success: false };
|
|
6544
|
+
}
|
|
6545
|
+
pos++;
|
|
6546
|
+
consumed++;
|
|
6547
|
+
if (ctx.settings.allowHtmlBlocks !== false) {
|
|
6548
|
+
return { success: false };
|
|
6549
|
+
}
|
|
6550
|
+
const hasCloseAhead = lookaheadHasHtmlClose(ctx, pos);
|
|
6551
|
+
let foundClose = false;
|
|
6552
|
+
while (pos < ctx.tokens.length) {
|
|
6553
|
+
const token = ctx.tokens[pos];
|
|
6554
|
+
if (!token || token.type === "EOF")
|
|
6555
|
+
break;
|
|
6556
|
+
if (!hasCloseAhead && token.type === "NEWLINE" && ctx.tokens[pos + 1]?.type === "NEWLINE") {
|
|
6557
|
+
break;
|
|
6558
|
+
}
|
|
6559
|
+
if (token.type === "BLOCK_END_OPEN") {
|
|
6560
|
+
const closeNameResult = parseBlockName(ctx, pos + 1);
|
|
6561
|
+
if (closeNameResult?.name.toLowerCase() === "html") {
|
|
6562
|
+
let checkPos = pos + 1 + closeNameResult.consumed;
|
|
6563
|
+
while (ctx.tokens[checkPos]?.type === "WHITESPACE")
|
|
6564
|
+
checkPos++;
|
|
6565
|
+
if (ctx.tokens[checkPos]?.type === "BLOCK_CLOSE") {
|
|
6566
|
+
foundClose = true;
|
|
6567
|
+
consumed += checkPos - pos + 1;
|
|
6568
|
+
pos = checkPos + 1;
|
|
6569
|
+
if (ctx.tokens[pos]?.type === "NEWLINE") {
|
|
6570
|
+
pos++;
|
|
6571
|
+
consumed++;
|
|
6572
|
+
}
|
|
6573
|
+
break;
|
|
6574
|
+
}
|
|
6575
|
+
}
|
|
6576
|
+
}
|
|
6577
|
+
pos++;
|
|
6578
|
+
consumed++;
|
|
6579
|
+
}
|
|
6580
|
+
if (!foundClose) {
|
|
6581
|
+
ctx.diagnostics.push({
|
|
6582
|
+
severity: "warning",
|
|
6583
|
+
code: "unclosed-block",
|
|
6584
|
+
message: "Missing closing tag [[/html]] for [[html]]",
|
|
6585
|
+
position: openToken.position
|
|
6586
|
+
});
|
|
6587
|
+
}
|
|
6588
|
+
ctx.diagnostics.push({
|
|
6589
|
+
severity: "info",
|
|
6590
|
+
code: "html-block-disabled",
|
|
6591
|
+
message: "[[html]] block ignored: disabled by settings",
|
|
6592
|
+
position: openToken.position
|
|
6593
|
+
});
|
|
6594
|
+
return { success: true, elements: [], consumed };
|
|
6595
|
+
}
|
|
6596
|
+
};
|
|
6597
|
+
|
|
6424
6598
|
// packages/parser/src/parser/rules/inline/raw.ts
|
|
6425
6599
|
var rawRule = {
|
|
6426
6600
|
name: "raw",
|
|
@@ -8131,6 +8305,7 @@ var inlineRules = [
|
|
|
8131
8305
|
underscoreLineBreakRule,
|
|
8132
8306
|
newlineLineBreakRule,
|
|
8133
8307
|
commentRule,
|
|
8308
|
+
htmlInlineRule,
|
|
8134
8309
|
rawRule,
|
|
8135
8310
|
imageRule,
|
|
8136
8311
|
sizeRule,
|
|
@@ -8648,83 +8823,333 @@ function buildTableOfContents(entries) {
|
|
|
8648
8823
|
return trees.map((tree) => buildTocList(indexer, tree.list));
|
|
8649
8824
|
}
|
|
8650
8825
|
|
|
8651
|
-
// packages/parser/src/parser/
|
|
8652
|
-
|
|
8653
|
-
|
|
8654
|
-
|
|
8655
|
-
|
|
8656
|
-
|
|
8657
|
-
|
|
8658
|
-
|
|
8659
|
-
|
|
8660
|
-
|
|
8661
|
-
|
|
8662
|
-
|
|
8663
|
-
|
|
8664
|
-
|
|
8665
|
-
footnoteBlockParsed: false,
|
|
8666
|
-
bibcites: [],
|
|
8667
|
-
diagnostics: [],
|
|
8668
|
-
blockRules,
|
|
8669
|
-
blockFallbackRule: paragraphRule,
|
|
8670
|
-
inlineRules
|
|
8671
|
-
};
|
|
8672
|
-
}
|
|
8673
|
-
parse() {
|
|
8674
|
-
const children = [];
|
|
8675
|
-
while (!this.isAtEnd()) {
|
|
8676
|
-
const blocks = this.parseBlock();
|
|
8677
|
-
children.push(...blocks);
|
|
8678
|
-
}
|
|
8679
|
-
const mergedChildren = mergeSpanStripParagraphs(children);
|
|
8680
|
-
const divProcessed = suppressDivAdjacentParagraphs(mergedChildren);
|
|
8681
|
-
const cleanedChildren = cleanInternalFlags(divProcessed);
|
|
8682
|
-
const hasFootnoteBlock = cleanedChildren.some((el) => el.element === "footnote-block");
|
|
8683
|
-
if (!hasFootnoteBlock) {
|
|
8684
|
-
cleanedChildren.push({
|
|
8685
|
-
element: "footnote-block",
|
|
8686
|
-
data: { title: null, hide: false }
|
|
8687
|
-
});
|
|
8826
|
+
// packages/parser/src/parser/rules/block/module/walk.ts
|
|
8827
|
+
function walkElements(elements, callback) {
|
|
8828
|
+
for (const element of elements) {
|
|
8829
|
+
callback(element);
|
|
8830
|
+
if (element.element === "list") {
|
|
8831
|
+
const listData = element.data;
|
|
8832
|
+
for (const item of listData.items) {
|
|
8833
|
+
if (item["item-type"] === "elements") {
|
|
8834
|
+
walkElements(item.elements, callback);
|
|
8835
|
+
} else if (item["item-type"] === "sub-list") {
|
|
8836
|
+
walkElements([{ element: "list", data: item.data }], callback);
|
|
8837
|
+
}
|
|
8838
|
+
}
|
|
8839
|
+
continue;
|
|
8688
8840
|
}
|
|
8689
|
-
|
|
8690
|
-
|
|
8691
|
-
|
|
8692
|
-
|
|
8693
|
-
|
|
8694
|
-
|
|
8841
|
+
if (element.element === "table") {
|
|
8842
|
+
const tableData = element.data;
|
|
8843
|
+
for (const row of tableData.rows) {
|
|
8844
|
+
for (const cell of row.cells) {
|
|
8845
|
+
walkElements(cell.elements, callback);
|
|
8846
|
+
}
|
|
8847
|
+
}
|
|
8848
|
+
continue;
|
|
8695
8849
|
}
|
|
8696
|
-
if (
|
|
8697
|
-
|
|
8850
|
+
if (element.element === "definition-list") {
|
|
8851
|
+
const defListData = element.data;
|
|
8852
|
+
for (const item of defListData) {
|
|
8853
|
+
walkElements(item.key, callback);
|
|
8854
|
+
walkElements(item.value, callback);
|
|
8855
|
+
}
|
|
8856
|
+
continue;
|
|
8698
8857
|
}
|
|
8699
|
-
if (
|
|
8700
|
-
|
|
8858
|
+
if (element.element === "tab-view") {
|
|
8859
|
+
const tabData = element.data;
|
|
8860
|
+
for (const tab of tabData) {
|
|
8861
|
+
walkElements(tab.elements, callback);
|
|
8862
|
+
}
|
|
8863
|
+
continue;
|
|
8701
8864
|
}
|
|
8702
|
-
if (
|
|
8703
|
-
|
|
8865
|
+
if ("data" in element && element.data && typeof element.data === "object") {
|
|
8866
|
+
const data = element.data;
|
|
8867
|
+
if ("elements" in data && Array.isArray(data.elements)) {
|
|
8868
|
+
walkElements(data.elements, callback);
|
|
8869
|
+
}
|
|
8704
8870
|
}
|
|
8705
|
-
return { ast: result, diagnostics: this.ctx.diagnostics };
|
|
8706
|
-
}
|
|
8707
|
-
isAtEnd() {
|
|
8708
|
-
return this.ctx.pos >= this.ctx.tokens.length || this.currentToken().type === "EOF";
|
|
8709
|
-
}
|
|
8710
|
-
currentToken() {
|
|
8711
|
-
return this.ctx.tokens[this.ctx.pos] ?? this.eofToken();
|
|
8712
8871
|
}
|
|
8713
|
-
|
|
8872
|
+
}
|
|
8873
|
+
function mapElementChildren(element, transform) {
|
|
8874
|
+
if (element.element === "list") {
|
|
8875
|
+
const listData = element.data;
|
|
8876
|
+
const newItems = [];
|
|
8877
|
+
for (const item of listData.items) {
|
|
8878
|
+
if (item["item-type"] === "elements") {
|
|
8879
|
+
newItems.push({
|
|
8880
|
+
"item-type": "elements",
|
|
8881
|
+
attributes: item.attributes,
|
|
8882
|
+
elements: transform(item.elements)
|
|
8883
|
+
});
|
|
8884
|
+
} else if (item["item-type"] === "sub-list") {
|
|
8885
|
+
const subListResult = transform([{ element: "list", data: item.data }]);
|
|
8886
|
+
const resolvedList = subListResult[0];
|
|
8887
|
+
if (resolvedList?.element === "list") {
|
|
8888
|
+
newItems.push({
|
|
8889
|
+
"item-type": "sub-list",
|
|
8890
|
+
element: "list",
|
|
8891
|
+
data: resolvedList.data
|
|
8892
|
+
});
|
|
8893
|
+
} else {
|
|
8894
|
+
newItems.push(item);
|
|
8895
|
+
}
|
|
8896
|
+
}
|
|
8897
|
+
}
|
|
8714
8898
|
return {
|
|
8715
|
-
|
|
8716
|
-
|
|
8717
|
-
position: {
|
|
8718
|
-
start: { line: 0, column: 0, offset: 0 },
|
|
8719
|
-
end: { line: 0, column: 0, offset: 0 }
|
|
8720
|
-
},
|
|
8721
|
-
lineStart: false
|
|
8899
|
+
element: "list",
|
|
8900
|
+
data: { ...listData, items: newItems }
|
|
8722
8901
|
};
|
|
8723
8902
|
}
|
|
8724
|
-
|
|
8725
|
-
|
|
8726
|
-
|
|
8727
|
-
|
|
8903
|
+
if (element.element === "table") {
|
|
8904
|
+
const tableData = element.data;
|
|
8905
|
+
const newRows = [];
|
|
8906
|
+
for (const row of tableData.rows) {
|
|
8907
|
+
const newCells = [];
|
|
8908
|
+
for (const cell of row.cells) {
|
|
8909
|
+
newCells.push({ ...cell, elements: transform(cell.elements) });
|
|
8910
|
+
}
|
|
8911
|
+
newRows.push({ ...row, cells: newCells });
|
|
8912
|
+
}
|
|
8913
|
+
return {
|
|
8914
|
+
element: "table",
|
|
8915
|
+
data: { ...tableData, rows: newRows }
|
|
8916
|
+
};
|
|
8917
|
+
}
|
|
8918
|
+
if (element.element === "definition-list") {
|
|
8919
|
+
const defListData = element.data;
|
|
8920
|
+
const newItems = [];
|
|
8921
|
+
for (const item of defListData) {
|
|
8922
|
+
newItems.push({
|
|
8923
|
+
key_string: item.key_string,
|
|
8924
|
+
key: transform(item.key),
|
|
8925
|
+
value: transform(item.value)
|
|
8926
|
+
});
|
|
8927
|
+
}
|
|
8928
|
+
return {
|
|
8929
|
+
element: "definition-list",
|
|
8930
|
+
data: newItems
|
|
8931
|
+
};
|
|
8932
|
+
}
|
|
8933
|
+
if (element.element === "tab-view") {
|
|
8934
|
+
const tabData = element.data;
|
|
8935
|
+
const newTabs = [];
|
|
8936
|
+
for (const tab of tabData) {
|
|
8937
|
+
newTabs.push({ ...tab, elements: transform(tab.elements) });
|
|
8938
|
+
}
|
|
8939
|
+
return {
|
|
8940
|
+
element: "tab-view",
|
|
8941
|
+
data: newTabs
|
|
8942
|
+
};
|
|
8943
|
+
}
|
|
8944
|
+
if ("data" in element && element.data && typeof element.data === "object") {
|
|
8945
|
+
const data = element.data;
|
|
8946
|
+
if ("elements" in data && Array.isArray(data.elements)) {
|
|
8947
|
+
return {
|
|
8948
|
+
...element,
|
|
8949
|
+
data: {
|
|
8950
|
+
...data,
|
|
8951
|
+
elements: transform(data.elements)
|
|
8952
|
+
}
|
|
8953
|
+
};
|
|
8954
|
+
}
|
|
8955
|
+
}
|
|
8956
|
+
return element;
|
|
8957
|
+
}
|
|
8958
|
+
function mapElementChildrenWithState(element, state, transform) {
|
|
8959
|
+
if (element.element === "list") {
|
|
8960
|
+
const listData = element.data;
|
|
8961
|
+
const newItems = [];
|
|
8962
|
+
let currentState = state;
|
|
8963
|
+
for (const item of listData.items) {
|
|
8964
|
+
if (item["item-type"] === "elements") {
|
|
8965
|
+
const result = transform(item.elements, currentState);
|
|
8966
|
+
newItems.push({
|
|
8967
|
+
"item-type": "elements",
|
|
8968
|
+
attributes: item.attributes,
|
|
8969
|
+
elements: result.elements
|
|
8970
|
+
});
|
|
8971
|
+
currentState = result.state;
|
|
8972
|
+
} else if (item["item-type"] === "sub-list") {
|
|
8973
|
+
const result = transform([{ element: "list", data: item.data }], currentState);
|
|
8974
|
+
const resolvedList = result.elements[0];
|
|
8975
|
+
if (resolvedList?.element === "list") {
|
|
8976
|
+
newItems.push({
|
|
8977
|
+
"item-type": "sub-list",
|
|
8978
|
+
element: "list",
|
|
8979
|
+
data: resolvedList.data
|
|
8980
|
+
});
|
|
8981
|
+
} else {
|
|
8982
|
+
newItems.push(item);
|
|
8983
|
+
}
|
|
8984
|
+
currentState = result.state;
|
|
8985
|
+
}
|
|
8986
|
+
}
|
|
8987
|
+
return {
|
|
8988
|
+
element: {
|
|
8989
|
+
element: "list",
|
|
8990
|
+
data: { ...listData, items: newItems }
|
|
8991
|
+
},
|
|
8992
|
+
state: currentState
|
|
8993
|
+
};
|
|
8994
|
+
}
|
|
8995
|
+
if (element.element === "table") {
|
|
8996
|
+
const tableData = element.data;
|
|
8997
|
+
const newRows = [];
|
|
8998
|
+
let currentState = state;
|
|
8999
|
+
for (const row of tableData.rows) {
|
|
9000
|
+
const newCells = [];
|
|
9001
|
+
for (const cell of row.cells) {
|
|
9002
|
+
const result = transform(cell.elements, currentState);
|
|
9003
|
+
newCells.push({ ...cell, elements: result.elements });
|
|
9004
|
+
currentState = result.state;
|
|
9005
|
+
}
|
|
9006
|
+
newRows.push({ ...row, cells: newCells });
|
|
9007
|
+
}
|
|
9008
|
+
return {
|
|
9009
|
+
element: {
|
|
9010
|
+
element: "table",
|
|
9011
|
+
data: { ...tableData, rows: newRows }
|
|
9012
|
+
},
|
|
9013
|
+
state: currentState
|
|
9014
|
+
};
|
|
9015
|
+
}
|
|
9016
|
+
if (element.element === "definition-list") {
|
|
9017
|
+
const defListData = element.data;
|
|
9018
|
+
const newItems = [];
|
|
9019
|
+
let currentState = state;
|
|
9020
|
+
for (const item of defListData) {
|
|
9021
|
+
const keyResult = transform(item.key, currentState);
|
|
9022
|
+
currentState = keyResult.state;
|
|
9023
|
+
const valueResult = transform(item.value, currentState);
|
|
9024
|
+
currentState = valueResult.state;
|
|
9025
|
+
newItems.push({
|
|
9026
|
+
key_string: item.key_string,
|
|
9027
|
+
key: keyResult.elements,
|
|
9028
|
+
value: valueResult.elements
|
|
9029
|
+
});
|
|
9030
|
+
}
|
|
9031
|
+
return {
|
|
9032
|
+
element: {
|
|
9033
|
+
element: "definition-list",
|
|
9034
|
+
data: newItems
|
|
9035
|
+
},
|
|
9036
|
+
state: currentState
|
|
9037
|
+
};
|
|
9038
|
+
}
|
|
9039
|
+
if (element.element === "tab-view") {
|
|
9040
|
+
const tabData = element.data;
|
|
9041
|
+
const newTabs = [];
|
|
9042
|
+
let currentState = state;
|
|
9043
|
+
for (const tab of tabData) {
|
|
9044
|
+
const result = transform(tab.elements, currentState);
|
|
9045
|
+
newTabs.push({ ...tab, elements: result.elements });
|
|
9046
|
+
currentState = result.state;
|
|
9047
|
+
}
|
|
9048
|
+
return {
|
|
9049
|
+
element: {
|
|
9050
|
+
element: "tab-view",
|
|
9051
|
+
data: newTabs
|
|
9052
|
+
},
|
|
9053
|
+
state: currentState
|
|
9054
|
+
};
|
|
9055
|
+
}
|
|
9056
|
+
if ("data" in element && element.data && typeof element.data === "object") {
|
|
9057
|
+
const data = element.data;
|
|
9058
|
+
if ("elements" in data && Array.isArray(data.elements)) {
|
|
9059
|
+
const result = transform(data.elements, state);
|
|
9060
|
+
return {
|
|
9061
|
+
element: {
|
|
9062
|
+
...element,
|
|
9063
|
+
data: {
|
|
9064
|
+
...data,
|
|
9065
|
+
elements: result.elements
|
|
9066
|
+
}
|
|
9067
|
+
},
|
|
9068
|
+
state: result.state
|
|
9069
|
+
};
|
|
9070
|
+
}
|
|
9071
|
+
}
|
|
9072
|
+
return { element, state };
|
|
9073
|
+
}
|
|
9074
|
+
|
|
9075
|
+
// packages/parser/src/parser/parse.ts
|
|
9076
|
+
class Parser {
|
|
9077
|
+
ctx;
|
|
9078
|
+
constructor(tokens, options = {}) {
|
|
9079
|
+
this.ctx = {
|
|
9080
|
+
tokens,
|
|
9081
|
+
pos: 0,
|
|
9082
|
+
version: options.version ?? "wikidot",
|
|
9083
|
+
trackPositions: options.trackPositions ?? true,
|
|
9084
|
+
settings: options.settings ?? DEFAULT_SETTINGS,
|
|
9085
|
+
footnotes: [],
|
|
9086
|
+
tocEntries: [],
|
|
9087
|
+
codeBlocks: [],
|
|
9088
|
+
htmlBlocks: [],
|
|
9089
|
+
bibcites: [],
|
|
9090
|
+
diagnostics: [],
|
|
9091
|
+
blockRules,
|
|
9092
|
+
blockFallbackRule: paragraphRule,
|
|
9093
|
+
inlineRules,
|
|
9094
|
+
scope: {
|
|
9095
|
+
footnoteBlockParsed: false
|
|
9096
|
+
}
|
|
9097
|
+
};
|
|
9098
|
+
}
|
|
9099
|
+
parse() {
|
|
9100
|
+
const children = [];
|
|
9101
|
+
while (!this.isAtEnd()) {
|
|
9102
|
+
const blocks = this.parseBlock();
|
|
9103
|
+
children.push(...blocks);
|
|
9104
|
+
}
|
|
9105
|
+
const mergedChildren = mergeSpanStripParagraphs(children);
|
|
9106
|
+
const divProcessed = suppressDivAdjacentParagraphs(mergedChildren);
|
|
9107
|
+
const cleanedChildren = cleanInternalFlags(divProcessed);
|
|
9108
|
+
if (!containsFootnoteBlock(cleanedChildren)) {
|
|
9109
|
+
cleanedChildren.push({
|
|
9110
|
+
element: "footnote-block",
|
|
9111
|
+
data: { title: null, hide: false }
|
|
9112
|
+
});
|
|
9113
|
+
}
|
|
9114
|
+
const tableOfContents = buildTableOfContents(this.ctx.tocEntries);
|
|
9115
|
+
const result = {
|
|
9116
|
+
elements: cleanedChildren
|
|
9117
|
+
};
|
|
9118
|
+
if (tableOfContents.length > 0) {
|
|
9119
|
+
result["table-of-contents"] = tableOfContents;
|
|
9120
|
+
}
|
|
9121
|
+
if (this.ctx.footnotes.length > 0) {
|
|
9122
|
+
result.footnotes = this.ctx.footnotes;
|
|
9123
|
+
}
|
|
9124
|
+
if (this.ctx.codeBlocks.length > 0) {
|
|
9125
|
+
result["code-blocks"] = this.ctx.codeBlocks;
|
|
9126
|
+
}
|
|
9127
|
+
if (this.ctx.htmlBlocks.length > 0) {
|
|
9128
|
+
result["html-blocks"] = this.ctx.htmlBlocks;
|
|
9129
|
+
}
|
|
9130
|
+
return { ast: result, diagnostics: this.ctx.diagnostics };
|
|
9131
|
+
}
|
|
9132
|
+
isAtEnd() {
|
|
9133
|
+
return this.ctx.pos >= this.ctx.tokens.length || this.currentToken().type === "EOF";
|
|
9134
|
+
}
|
|
9135
|
+
currentToken() {
|
|
9136
|
+
return this.ctx.tokens[this.ctx.pos] ?? this.eofToken();
|
|
9137
|
+
}
|
|
9138
|
+
eofToken() {
|
|
9139
|
+
return {
|
|
9140
|
+
type: "EOF",
|
|
9141
|
+
value: "",
|
|
9142
|
+
position: {
|
|
9143
|
+
start: { line: 0, column: 0, offset: 0 },
|
|
9144
|
+
end: { line: 0, column: 0, offset: 0 }
|
|
9145
|
+
},
|
|
9146
|
+
lineStart: false
|
|
9147
|
+
};
|
|
9148
|
+
}
|
|
9149
|
+
skipWhitespace() {
|
|
9150
|
+
while (this.currentToken().type === "WHITESPACE") {
|
|
9151
|
+
this.ctx.pos++;
|
|
9152
|
+
}
|
|
8728
9153
|
}
|
|
8729
9154
|
parseBlock() {
|
|
8730
9155
|
this.skipWhitespace();
|
|
@@ -8759,6 +9184,14 @@ function parse(source, options) {
|
|
|
8759
9184
|
const tokens = tokenize(preprocessed, { trackPositions: options?.trackPositions });
|
|
8760
9185
|
return new Parser(tokens, options).parse();
|
|
8761
9186
|
}
|
|
9187
|
+
function containsFootnoteBlock(elements) {
|
|
9188
|
+
let found = false;
|
|
9189
|
+
walkElements(elements, (el) => {
|
|
9190
|
+
if (el.element === "footnote-block")
|
|
9191
|
+
found = true;
|
|
9192
|
+
});
|
|
9193
|
+
return found;
|
|
9194
|
+
}
|
|
8762
9195
|
// packages/parser/src/parser/rules/block/module/listpages/compiler.ts
|
|
8763
9196
|
var DEFAULT_PREVIEW_LENGTH = 200;
|
|
8764
9197
|
var VARIABLE_REGEX = /%%([a-z_]+)(?:\{([^}]+)\})?(?:\((\d+)\))?(?:\|([^%]*(?:%(?!%)[^%]*)*))?%%/gi;
|
|
@@ -8966,348 +9399,99 @@ function strftime(date, format) {
|
|
|
8966
9399
|
return String(date.getDate());
|
|
8967
9400
|
case "H":
|
|
8968
9401
|
return pad(date.getHours());
|
|
8969
|
-
case "I":
|
|
8970
|
-
return pad(date.getHours() % 12 || 12);
|
|
8971
|
-
case "M":
|
|
8972
|
-
return pad(date.getMinutes());
|
|
8973
|
-
case "S":
|
|
8974
|
-
return pad(date.getSeconds());
|
|
8975
|
-
case "p":
|
|
8976
|
-
return date.getHours() < 12 ? "AM" : "PM";
|
|
8977
|
-
case "b":
|
|
8978
|
-
return MONTHS_SHORT[date.getMonth()] ?? "";
|
|
8979
|
-
case "B":
|
|
8980
|
-
return MONTHS[date.getMonth()] ?? "";
|
|
8981
|
-
case "a":
|
|
8982
|
-
return DAYS_SHORT[date.getDay()] ?? "";
|
|
8983
|
-
case "A":
|
|
8984
|
-
return DAYS[date.getDay()] ?? "";
|
|
8985
|
-
case "w":
|
|
8986
|
-
return String(date.getDay());
|
|
8987
|
-
case "j":
|
|
8988
|
-
return pad(getDayOfYear(date), 3);
|
|
8989
|
-
case "Z":
|
|
8990
|
-
return "UTC";
|
|
8991
|
-
case "z":
|
|
8992
|
-
return "+0000";
|
|
8993
|
-
case "%":
|
|
8994
|
-
return "%";
|
|
8995
|
-
default:
|
|
8996
|
-
return `%${token}`;
|
|
8997
|
-
}
|
|
8998
|
-
});
|
|
8999
|
-
}
|
|
9000
|
-
function getDayOfYear(date) {
|
|
9001
|
-
const start = new Date(date.getFullYear(), 0, 0);
|
|
9002
|
-
const diff = date.getTime() - start.getTime();
|
|
9003
|
-
const oneDay = 1000 * 60 * 60 * 24;
|
|
9004
|
-
return Math.floor(diff / oneDay);
|
|
9005
|
-
}
|
|
9006
|
-
|
|
9007
|
-
// packages/parser/src/parser/rules/block/module/listusers/compiler.ts
|
|
9008
|
-
var VARIABLE_REGEX2 = /%%([a-z_]+)%%/gi;
|
|
9009
|
-
function compileListUsersTemplate(template) {
|
|
9010
|
-
const parts = [];
|
|
9011
|
-
let lastIndex = 0;
|
|
9012
|
-
for (const match of template.matchAll(VARIABLE_REGEX2)) {
|
|
9013
|
-
if (match.index !== undefined && match.index > lastIndex) {
|
|
9014
|
-
parts.push(template.slice(lastIndex, match.index));
|
|
9015
|
-
}
|
|
9016
|
-
const [, varName] = match;
|
|
9017
|
-
if (!varName)
|
|
9018
|
-
continue;
|
|
9019
|
-
const getter = createVariableGetter2(varName.toLowerCase());
|
|
9020
|
-
parts.push(getter);
|
|
9021
|
-
lastIndex = match.index !== undefined ? match.index + match[0].length : lastIndex;
|
|
9022
|
-
}
|
|
9023
|
-
if (lastIndex < template.length) {
|
|
9024
|
-
parts.push(template.slice(lastIndex));
|
|
9025
|
-
}
|
|
9026
|
-
return (ctx) => {
|
|
9027
|
-
let result = "";
|
|
9028
|
-
for (const part of parts) {
|
|
9029
|
-
result += typeof part === "string" ? part : part(ctx);
|
|
9030
|
-
}
|
|
9031
|
-
return result;
|
|
9032
|
-
};
|
|
9033
|
-
}
|
|
9034
|
-
function createVariableGetter2(name) {
|
|
9035
|
-
switch (name) {
|
|
9036
|
-
case "number":
|
|
9037
|
-
return (ctx) => String(ctx.user.number);
|
|
9038
|
-
case "title":
|
|
9039
|
-
return (ctx) => ctx.user.title;
|
|
9040
|
-
case "name":
|
|
9041
|
-
return (ctx) => ctx.user.name;
|
|
9042
|
-
default:
|
|
9043
|
-
return () => "";
|
|
9044
|
-
}
|
|
9045
|
-
}
|
|
9046
|
-
|
|
9047
|
-
// packages/parser/src/parser/rules/block/module/listusers/extract.ts
|
|
9048
|
-
var VARIABLE_REGEX3 = /%%([a-z_]+)%%/gi;
|
|
9049
|
-
var KNOWN_VARIABLES = ["number", "title", "name"];
|
|
9050
|
-
function extractListUsersVariables(template) {
|
|
9051
|
-
const variables = new Set;
|
|
9052
|
-
for (const match of template.matchAll(VARIABLE_REGEX3)) {
|
|
9053
|
-
const [, varName] = match;
|
|
9054
|
-
if (!varName)
|
|
9055
|
-
continue;
|
|
9056
|
-
const normalized = varName.toLowerCase();
|
|
9057
|
-
if (KNOWN_VARIABLES.includes(normalized)) {
|
|
9058
|
-
variables.add(normalized);
|
|
9059
|
-
}
|
|
9060
|
-
}
|
|
9061
|
-
return Array.from(variables);
|
|
9062
|
-
}
|
|
9063
|
-
|
|
9064
|
-
// packages/parser/src/parser/rules/block/module/walk.ts
|
|
9065
|
-
function walkElements(elements, callback) {
|
|
9066
|
-
for (const element of elements) {
|
|
9067
|
-
callback(element);
|
|
9068
|
-
if (element.element === "list") {
|
|
9069
|
-
const listData = element.data;
|
|
9070
|
-
for (const item of listData.items) {
|
|
9071
|
-
if (item["item-type"] === "elements") {
|
|
9072
|
-
walkElements(item.elements, callback);
|
|
9073
|
-
} else if (item["item-type"] === "sub-list") {
|
|
9074
|
-
walkElements([{ element: "list", data: item.data }], callback);
|
|
9075
|
-
}
|
|
9076
|
-
}
|
|
9077
|
-
continue;
|
|
9078
|
-
}
|
|
9079
|
-
if (element.element === "table") {
|
|
9080
|
-
const tableData = element.data;
|
|
9081
|
-
for (const row of tableData.rows) {
|
|
9082
|
-
for (const cell of row.cells) {
|
|
9083
|
-
walkElements(cell.elements, callback);
|
|
9084
|
-
}
|
|
9085
|
-
}
|
|
9086
|
-
continue;
|
|
9087
|
-
}
|
|
9088
|
-
if (element.element === "definition-list") {
|
|
9089
|
-
const defListData = element.data;
|
|
9090
|
-
for (const item of defListData) {
|
|
9091
|
-
walkElements(item.key, callback);
|
|
9092
|
-
walkElements(item.value, callback);
|
|
9093
|
-
}
|
|
9094
|
-
continue;
|
|
9095
|
-
}
|
|
9096
|
-
if (element.element === "tab-view") {
|
|
9097
|
-
const tabData = element.data;
|
|
9098
|
-
for (const tab of tabData) {
|
|
9099
|
-
walkElements(tab.elements, callback);
|
|
9100
|
-
}
|
|
9101
|
-
continue;
|
|
9102
|
-
}
|
|
9103
|
-
if ("data" in element && element.data && typeof element.data === "object") {
|
|
9104
|
-
const data = element.data;
|
|
9105
|
-
if ("elements" in data && Array.isArray(data.elements)) {
|
|
9106
|
-
walkElements(data.elements, callback);
|
|
9107
|
-
}
|
|
9108
|
-
}
|
|
9109
|
-
}
|
|
9110
|
-
}
|
|
9111
|
-
function mapElementChildren(element, transform) {
|
|
9112
|
-
if (element.element === "list") {
|
|
9113
|
-
const listData = element.data;
|
|
9114
|
-
const newItems = [];
|
|
9115
|
-
for (const item of listData.items) {
|
|
9116
|
-
if (item["item-type"] === "elements") {
|
|
9117
|
-
newItems.push({
|
|
9118
|
-
"item-type": "elements",
|
|
9119
|
-
attributes: item.attributes,
|
|
9120
|
-
elements: transform(item.elements)
|
|
9121
|
-
});
|
|
9122
|
-
} else if (item["item-type"] === "sub-list") {
|
|
9123
|
-
const subListResult = transform([{ element: "list", data: item.data }]);
|
|
9124
|
-
const resolvedList = subListResult[0];
|
|
9125
|
-
if (resolvedList?.element === "list") {
|
|
9126
|
-
newItems.push({
|
|
9127
|
-
"item-type": "sub-list",
|
|
9128
|
-
element: "list",
|
|
9129
|
-
data: resolvedList.data
|
|
9130
|
-
});
|
|
9131
|
-
} else {
|
|
9132
|
-
newItems.push(item);
|
|
9133
|
-
}
|
|
9134
|
-
}
|
|
9135
|
-
}
|
|
9136
|
-
return {
|
|
9137
|
-
element: "list",
|
|
9138
|
-
data: { ...listData, items: newItems }
|
|
9139
|
-
};
|
|
9140
|
-
}
|
|
9141
|
-
if (element.element === "table") {
|
|
9142
|
-
const tableData = element.data;
|
|
9143
|
-
const newRows = [];
|
|
9144
|
-
for (const row of tableData.rows) {
|
|
9145
|
-
const newCells = [];
|
|
9146
|
-
for (const cell of row.cells) {
|
|
9147
|
-
newCells.push({ ...cell, elements: transform(cell.elements) });
|
|
9148
|
-
}
|
|
9149
|
-
newRows.push({ ...row, cells: newCells });
|
|
9150
|
-
}
|
|
9151
|
-
return {
|
|
9152
|
-
element: "table",
|
|
9153
|
-
data: { ...tableData, rows: newRows }
|
|
9154
|
-
};
|
|
9155
|
-
}
|
|
9156
|
-
if (element.element === "definition-list") {
|
|
9157
|
-
const defListData = element.data;
|
|
9158
|
-
const newItems = [];
|
|
9159
|
-
for (const item of defListData) {
|
|
9160
|
-
newItems.push({
|
|
9161
|
-
key_string: item.key_string,
|
|
9162
|
-
key: transform(item.key),
|
|
9163
|
-
value: transform(item.value)
|
|
9164
|
-
});
|
|
9165
|
-
}
|
|
9166
|
-
return {
|
|
9167
|
-
element: "definition-list",
|
|
9168
|
-
data: newItems
|
|
9169
|
-
};
|
|
9170
|
-
}
|
|
9171
|
-
if (element.element === "tab-view") {
|
|
9172
|
-
const tabData = element.data;
|
|
9173
|
-
const newTabs = [];
|
|
9174
|
-
for (const tab of tabData) {
|
|
9175
|
-
newTabs.push({ ...tab, elements: transform(tab.elements) });
|
|
9176
|
-
}
|
|
9177
|
-
return {
|
|
9178
|
-
element: "tab-view",
|
|
9179
|
-
data: newTabs
|
|
9180
|
-
};
|
|
9181
|
-
}
|
|
9182
|
-
if ("data" in element && element.data && typeof element.data === "object") {
|
|
9183
|
-
const data = element.data;
|
|
9184
|
-
if ("elements" in data && Array.isArray(data.elements)) {
|
|
9185
|
-
return {
|
|
9186
|
-
...element,
|
|
9187
|
-
data: {
|
|
9188
|
-
...data,
|
|
9189
|
-
elements: transform(data.elements)
|
|
9190
|
-
}
|
|
9191
|
-
};
|
|
9402
|
+
case "I":
|
|
9403
|
+
return pad(date.getHours() % 12 || 12);
|
|
9404
|
+
case "M":
|
|
9405
|
+
return pad(date.getMinutes());
|
|
9406
|
+
case "S":
|
|
9407
|
+
return pad(date.getSeconds());
|
|
9408
|
+
case "p":
|
|
9409
|
+
return date.getHours() < 12 ? "AM" : "PM";
|
|
9410
|
+
case "b":
|
|
9411
|
+
return MONTHS_SHORT[date.getMonth()] ?? "";
|
|
9412
|
+
case "B":
|
|
9413
|
+
return MONTHS[date.getMonth()] ?? "";
|
|
9414
|
+
case "a":
|
|
9415
|
+
return DAYS_SHORT[date.getDay()] ?? "";
|
|
9416
|
+
case "A":
|
|
9417
|
+
return DAYS[date.getDay()] ?? "";
|
|
9418
|
+
case "w":
|
|
9419
|
+
return String(date.getDay());
|
|
9420
|
+
case "j":
|
|
9421
|
+
return pad(getDayOfYear(date), 3);
|
|
9422
|
+
case "Z":
|
|
9423
|
+
return "UTC";
|
|
9424
|
+
case "z":
|
|
9425
|
+
return "+0000";
|
|
9426
|
+
case "%":
|
|
9427
|
+
return "%";
|
|
9428
|
+
default:
|
|
9429
|
+
return `%${token}`;
|
|
9192
9430
|
}
|
|
9193
|
-
}
|
|
9194
|
-
return element;
|
|
9431
|
+
});
|
|
9195
9432
|
}
|
|
9196
|
-
function
|
|
9197
|
-
|
|
9198
|
-
|
|
9199
|
-
|
|
9200
|
-
|
|
9201
|
-
|
|
9202
|
-
|
|
9203
|
-
|
|
9204
|
-
|
|
9205
|
-
|
|
9206
|
-
|
|
9207
|
-
|
|
9208
|
-
|
|
9209
|
-
|
|
9210
|
-
|
|
9211
|
-
const result = transform([{ element: "list", data: item.data }], currentState);
|
|
9212
|
-
const resolvedList = result.elements[0];
|
|
9213
|
-
if (resolvedList?.element === "list") {
|
|
9214
|
-
newItems.push({
|
|
9215
|
-
"item-type": "sub-list",
|
|
9216
|
-
element: "list",
|
|
9217
|
-
data: resolvedList.data
|
|
9218
|
-
});
|
|
9219
|
-
} else {
|
|
9220
|
-
newItems.push(item);
|
|
9221
|
-
}
|
|
9222
|
-
currentState = result.state;
|
|
9223
|
-
}
|
|
9224
|
-
}
|
|
9225
|
-
return {
|
|
9226
|
-
element: {
|
|
9227
|
-
element: "list",
|
|
9228
|
-
data: { ...listData, items: newItems }
|
|
9229
|
-
},
|
|
9230
|
-
state: currentState
|
|
9231
|
-
};
|
|
9232
|
-
}
|
|
9233
|
-
if (element.element === "table") {
|
|
9234
|
-
const tableData = element.data;
|
|
9235
|
-
const newRows = [];
|
|
9236
|
-
let currentState = state;
|
|
9237
|
-
for (const row of tableData.rows) {
|
|
9238
|
-
const newCells = [];
|
|
9239
|
-
for (const cell of row.cells) {
|
|
9240
|
-
const result = transform(cell.elements, currentState);
|
|
9241
|
-
newCells.push({ ...cell, elements: result.elements });
|
|
9242
|
-
currentState = result.state;
|
|
9243
|
-
}
|
|
9244
|
-
newRows.push({ ...row, cells: newCells });
|
|
9433
|
+
function getDayOfYear(date) {
|
|
9434
|
+
const start = new Date(date.getFullYear(), 0, 0);
|
|
9435
|
+
const diff = date.getTime() - start.getTime();
|
|
9436
|
+
const oneDay = 1000 * 60 * 60 * 24;
|
|
9437
|
+
return Math.floor(diff / oneDay);
|
|
9438
|
+
}
|
|
9439
|
+
|
|
9440
|
+
// packages/parser/src/parser/rules/block/module/listusers/compiler.ts
|
|
9441
|
+
var VARIABLE_REGEX2 = /%%([a-z_]+)%%/gi;
|
|
9442
|
+
function compileListUsersTemplate(template) {
|
|
9443
|
+
const parts = [];
|
|
9444
|
+
let lastIndex = 0;
|
|
9445
|
+
for (const match of template.matchAll(VARIABLE_REGEX2)) {
|
|
9446
|
+
if (match.index !== undefined && match.index > lastIndex) {
|
|
9447
|
+
parts.push(template.slice(lastIndex, match.index));
|
|
9245
9448
|
}
|
|
9246
|
-
|
|
9247
|
-
|
|
9248
|
-
|
|
9249
|
-
|
|
9250
|
-
|
|
9251
|
-
|
|
9252
|
-
};
|
|
9449
|
+
const [, varName] = match;
|
|
9450
|
+
if (!varName)
|
|
9451
|
+
continue;
|
|
9452
|
+
const getter = createVariableGetter2(varName.toLowerCase());
|
|
9453
|
+
parts.push(getter);
|
|
9454
|
+
lastIndex = match.index !== undefined ? match.index + match[0].length : lastIndex;
|
|
9253
9455
|
}
|
|
9254
|
-
if (
|
|
9255
|
-
|
|
9256
|
-
const newItems = [];
|
|
9257
|
-
let currentState = state;
|
|
9258
|
-
for (const item of defListData) {
|
|
9259
|
-
const keyResult = transform(item.key, currentState);
|
|
9260
|
-
currentState = keyResult.state;
|
|
9261
|
-
const valueResult = transform(item.value, currentState);
|
|
9262
|
-
currentState = valueResult.state;
|
|
9263
|
-
newItems.push({
|
|
9264
|
-
key_string: item.key_string,
|
|
9265
|
-
key: keyResult.elements,
|
|
9266
|
-
value: valueResult.elements
|
|
9267
|
-
});
|
|
9268
|
-
}
|
|
9269
|
-
return {
|
|
9270
|
-
element: {
|
|
9271
|
-
element: "definition-list",
|
|
9272
|
-
data: newItems
|
|
9273
|
-
},
|
|
9274
|
-
state: currentState
|
|
9275
|
-
};
|
|
9456
|
+
if (lastIndex < template.length) {
|
|
9457
|
+
parts.push(template.slice(lastIndex));
|
|
9276
9458
|
}
|
|
9277
|
-
|
|
9278
|
-
|
|
9279
|
-
const
|
|
9280
|
-
|
|
9281
|
-
for (const tab of tabData) {
|
|
9282
|
-
const result = transform(tab.elements, currentState);
|
|
9283
|
-
newTabs.push({ ...tab, elements: result.elements });
|
|
9284
|
-
currentState = result.state;
|
|
9459
|
+
return (ctx) => {
|
|
9460
|
+
let result = "";
|
|
9461
|
+
for (const part of parts) {
|
|
9462
|
+
result += typeof part === "string" ? part : part(ctx);
|
|
9285
9463
|
}
|
|
9286
|
-
return
|
|
9287
|
-
|
|
9288
|
-
|
|
9289
|
-
|
|
9290
|
-
|
|
9291
|
-
|
|
9292
|
-
|
|
9464
|
+
return result;
|
|
9465
|
+
};
|
|
9466
|
+
}
|
|
9467
|
+
function createVariableGetter2(name) {
|
|
9468
|
+
switch (name) {
|
|
9469
|
+
case "number":
|
|
9470
|
+
return (ctx) => String(ctx.user.number);
|
|
9471
|
+
case "title":
|
|
9472
|
+
return (ctx) => ctx.user.title;
|
|
9473
|
+
case "name":
|
|
9474
|
+
return (ctx) => ctx.user.name;
|
|
9475
|
+
default:
|
|
9476
|
+
return () => "";
|
|
9293
9477
|
}
|
|
9294
|
-
|
|
9295
|
-
|
|
9296
|
-
|
|
9297
|
-
|
|
9298
|
-
|
|
9299
|
-
|
|
9300
|
-
|
|
9301
|
-
|
|
9302
|
-
|
|
9303
|
-
|
|
9304
|
-
|
|
9305
|
-
|
|
9306
|
-
|
|
9307
|
-
|
|
9478
|
+
}
|
|
9479
|
+
|
|
9480
|
+
// packages/parser/src/parser/rules/block/module/listusers/extract.ts
|
|
9481
|
+
var VARIABLE_REGEX3 = /%%([a-z_]+)%%/gi;
|
|
9482
|
+
var KNOWN_VARIABLES = ["number", "title", "name"];
|
|
9483
|
+
function extractListUsersVariables(template) {
|
|
9484
|
+
const variables = new Set;
|
|
9485
|
+
for (const match of template.matchAll(VARIABLE_REGEX3)) {
|
|
9486
|
+
const [, varName] = match;
|
|
9487
|
+
if (!varName)
|
|
9488
|
+
continue;
|
|
9489
|
+
const normalized = varName.toLowerCase();
|
|
9490
|
+
if (KNOWN_VARIABLES.includes(normalized)) {
|
|
9491
|
+
variables.add(normalized);
|
|
9308
9492
|
}
|
|
9309
9493
|
}
|
|
9310
|
-
return
|
|
9494
|
+
return Array.from(variables);
|
|
9311
9495
|
}
|
|
9312
9496
|
|
|
9313
9497
|
// packages/parser/src/parser/rules/block/module/listpages/extract.ts
|
|
@@ -9966,6 +10150,110 @@ function resolveIfTags(data, pageTags) {
|
|
|
9966
10150
|
const matched = evaluateTagCondition(condition, pageTags);
|
|
9967
10151
|
return { evaluated: true, matched };
|
|
9968
10152
|
}
|
|
10153
|
+
// packages/parser/src/parser/rules/block/module/iftags/preprocess.ts
|
|
10154
|
+
var BASE_PLACEHOLDER_OPEN = "";
|
|
10155
|
+
var BASE_PLACEHOLDER_CLOSE = "";
|
|
10156
|
+
var INNERMOST_IFTAGS_PATTERN = /\[\[\s*iftags\b([^\]]*)\]\]((?:(?!\[\[\s*iftags\b|\[\[\/\s*iftags\s*\]\]).)*)\[\[\/\s*iftags\s*\]\]/gis;
|
|
10157
|
+
var RAW_BLOCK_OPEN_PATTERN = /\[\[\s*(code|html)\b[^\]]*\]\]/iy;
|
|
10158
|
+
function preprocessIftags(source, pageTags) {
|
|
10159
|
+
if (pageTags === null)
|
|
10160
|
+
return source;
|
|
10161
|
+
if (!source.includes("[["))
|
|
10162
|
+
return source;
|
|
10163
|
+
const sentinels = makeUniqueSentinels(source);
|
|
10164
|
+
const { masked, placeholders } = maskRawRegions(source, sentinels);
|
|
10165
|
+
const reduced = reduceIftags(masked, pageTags);
|
|
10166
|
+
return restorePlaceholders(reduced, placeholders, sentinels);
|
|
10167
|
+
}
|
|
10168
|
+
function makeUniqueSentinels(source) {
|
|
10169
|
+
let open = BASE_PLACEHOLDER_OPEN;
|
|
10170
|
+
let close = BASE_PLACEHOLDER_CLOSE;
|
|
10171
|
+
while (source.includes(open) || source.includes(close)) {
|
|
10172
|
+
open += BASE_PLACEHOLDER_OPEN;
|
|
10173
|
+
close += BASE_PLACEHOLDER_CLOSE;
|
|
10174
|
+
}
|
|
10175
|
+
return { open, close };
|
|
10176
|
+
}
|
|
10177
|
+
function reduceIftags(source, pageTags) {
|
|
10178
|
+
let current = source;
|
|
10179
|
+
const maxIterations = source.length + 1;
|
|
10180
|
+
for (let i = 0;i < maxIterations; i++) {
|
|
10181
|
+
const next = current.replace(INNERMOST_IFTAGS_PATTERN, (_, cond, body) => {
|
|
10182
|
+
const condition = parseTagCondition(cond);
|
|
10183
|
+
return evaluateTagCondition(condition, pageTags) ? body : "";
|
|
10184
|
+
});
|
|
10185
|
+
if (next === current)
|
|
10186
|
+
return current;
|
|
10187
|
+
current = next;
|
|
10188
|
+
}
|
|
10189
|
+
return current;
|
|
10190
|
+
}
|
|
10191
|
+
function maskRawRegions(source, sentinels) {
|
|
10192
|
+
const placeholders = [];
|
|
10193
|
+
let masked = "";
|
|
10194
|
+
let i = 0;
|
|
10195
|
+
while (i < source.length) {
|
|
10196
|
+
if (source[i] === "[" && source[i + 1] === "[") {
|
|
10197
|
+
RAW_BLOCK_OPEN_PATTERN.lastIndex = i;
|
|
10198
|
+
const openMatch = RAW_BLOCK_OPEN_PATTERN.exec(source);
|
|
10199
|
+
if (openMatch) {
|
|
10200
|
+
const name = openMatch[1].toLowerCase();
|
|
10201
|
+
const openLen = openMatch[0].length;
|
|
10202
|
+
const closePattern = new RegExp(`\\[\\[\\/\\s*${name}\\s*\\]\\]`, "ig");
|
|
10203
|
+
closePattern.lastIndex = i + openLen;
|
|
10204
|
+
const closeMatch = closePattern.exec(source);
|
|
10205
|
+
if (closeMatch) {
|
|
10206
|
+
const regionEnd = closeMatch.index + closeMatch[0].length;
|
|
10207
|
+
masked += pushPlaceholder(placeholders, source.slice(i, regionEnd), sentinels);
|
|
10208
|
+
i = regionEnd;
|
|
10209
|
+
continue;
|
|
10210
|
+
}
|
|
10211
|
+
if (name === "code") {
|
|
10212
|
+
masked += pushPlaceholder(placeholders, source.slice(i), sentinels);
|
|
10213
|
+
i = source.length;
|
|
10214
|
+
continue;
|
|
10215
|
+
}
|
|
10216
|
+
}
|
|
10217
|
+
}
|
|
10218
|
+
if (source[i] === "@" && source[i + 1] === "<") {
|
|
10219
|
+
const close = source.indexOf(">@", i + 2);
|
|
10220
|
+
const newline = source.indexOf(`
|
|
10221
|
+
`, i + 2);
|
|
10222
|
+
if (close !== -1 && (newline === -1 || close < newline)) {
|
|
10223
|
+
const regionEnd = close + 2;
|
|
10224
|
+
masked += pushPlaceholder(placeholders, source.slice(i, regionEnd), sentinels);
|
|
10225
|
+
i = regionEnd;
|
|
10226
|
+
continue;
|
|
10227
|
+
}
|
|
10228
|
+
}
|
|
10229
|
+
if (source[i] === "@" && source[i + 1] === "@") {
|
|
10230
|
+
const close = source.indexOf("@@", i + 2);
|
|
10231
|
+
const newline = source.indexOf(`
|
|
10232
|
+
`, i + 2);
|
|
10233
|
+
if (close !== -1 && (newline === -1 || close < newline)) {
|
|
10234
|
+
const regionEnd = close + 2;
|
|
10235
|
+
masked += pushPlaceholder(placeholders, source.slice(i, regionEnd), sentinels);
|
|
10236
|
+
i = regionEnd;
|
|
10237
|
+
continue;
|
|
10238
|
+
}
|
|
10239
|
+
}
|
|
10240
|
+
masked += source[i];
|
|
10241
|
+
i++;
|
|
10242
|
+
}
|
|
10243
|
+
return { masked, placeholders };
|
|
10244
|
+
}
|
|
10245
|
+
function pushPlaceholder(placeholders, text, sentinels) {
|
|
10246
|
+
const idx = placeholders.length;
|
|
10247
|
+
placeholders.push(text);
|
|
10248
|
+
return `${sentinels.open}${idx}${sentinels.close}`;
|
|
10249
|
+
}
|
|
10250
|
+
function escapeRegex(str) {
|
|
10251
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
10252
|
+
}
|
|
10253
|
+
function restorePlaceholders(source, placeholders, sentinels) {
|
|
10254
|
+
const pattern = new RegExp(`${escapeRegex(sentinels.open)}(\\d+)${escapeRegex(sentinels.close)}`, "g");
|
|
10255
|
+
return source.replace(pattern, (_, idx) => placeholders[Number(idx)] ?? "");
|
|
10256
|
+
}
|
|
9969
10257
|
// packages/parser/src/parser/rules/block/module/include/resolve.ts
|
|
9970
10258
|
function resolveIncludes(source, fetcher, options) {
|
|
9971
10259
|
if (options?.settings && !options.settings.enablePageSyntax) {
|
|
@@ -10011,7 +10299,67 @@ async function resolveIncludesAsync(source, fetcher, options) {
|
|
|
10011
10299
|
};
|
|
10012
10300
|
return expandIterativeAsync(source, cachedFetcher, maxIterations);
|
|
10013
10301
|
}
|
|
10014
|
-
var
|
|
10302
|
+
var INCLUDE_OPEN_PATTERN = /^\[\[include\s/gim;
|
|
10303
|
+
function isRestOfLineBlank(source, pos) {
|
|
10304
|
+
for (let i = pos;i < source.length; i++) {
|
|
10305
|
+
const ch = source[i];
|
|
10306
|
+
if (ch === `
|
|
10307
|
+
`)
|
|
10308
|
+
return true;
|
|
10309
|
+
if (ch !== " " && ch !== "\t" && ch !== "\r")
|
|
10310
|
+
return false;
|
|
10311
|
+
}
|
|
10312
|
+
return true;
|
|
10313
|
+
}
|
|
10314
|
+
function scanIncludeDirectives(source) {
|
|
10315
|
+
const matches = [];
|
|
10316
|
+
const opener = new RegExp(INCLUDE_OPEN_PATTERN.source, INCLUDE_OPEN_PATTERN.flags);
|
|
10317
|
+
let m;
|
|
10318
|
+
while ((m = opener.exec(source)) !== null) {
|
|
10319
|
+
const start = m.index;
|
|
10320
|
+
const contentStart = start + m[0].length;
|
|
10321
|
+
const firstNewline = source.indexOf(`
|
|
10322
|
+
`, start);
|
|
10323
|
+
let depth = 0;
|
|
10324
|
+
let linkDepth = 0;
|
|
10325
|
+
let i = start;
|
|
10326
|
+
let closeEnd = -1;
|
|
10327
|
+
while (i < source.length) {
|
|
10328
|
+
if (source.startsWith("[[[", i)) {
|
|
10329
|
+
linkDepth++;
|
|
10330
|
+
i += 3;
|
|
10331
|
+
} else if (linkDepth > 0 && source.startsWith("]]]", i)) {
|
|
10332
|
+
linkDepth--;
|
|
10333
|
+
i += 3;
|
|
10334
|
+
} else if (linkDepth > 0) {
|
|
10335
|
+
i++;
|
|
10336
|
+
} else if (source.startsWith("[[", i)) {
|
|
10337
|
+
depth++;
|
|
10338
|
+
i += 2;
|
|
10339
|
+
} else if (source.startsWith("]]", i)) {
|
|
10340
|
+
const closeStart = i;
|
|
10341
|
+
depth--;
|
|
10342
|
+
i += 2;
|
|
10343
|
+
if (depth <= 0) {
|
|
10344
|
+
const onOpenerLine = firstNewline === -1 || closeStart < firstNewline;
|
|
10345
|
+
if (onOpenerLine || isRestOfLineBlank(source, i)) {
|
|
10346
|
+
closeEnd = i;
|
|
10347
|
+
break;
|
|
10348
|
+
}
|
|
10349
|
+
}
|
|
10350
|
+
} else {
|
|
10351
|
+
i++;
|
|
10352
|
+
}
|
|
10353
|
+
}
|
|
10354
|
+
if (closeEnd === -1) {
|
|
10355
|
+
opener.lastIndex = start + 2;
|
|
10356
|
+
continue;
|
|
10357
|
+
}
|
|
10358
|
+
matches.push({ start, end: closeEnd, inner: source.slice(contentStart, closeEnd - 2) });
|
|
10359
|
+
opener.lastIndex = closeEnd;
|
|
10360
|
+
}
|
|
10361
|
+
return matches;
|
|
10362
|
+
}
|
|
10015
10363
|
function parseIncludeDirective(inner) {
|
|
10016
10364
|
const normalized = inner.replace(/\n/g, " ");
|
|
10017
10365
|
const parts = normalized.split("|");
|
|
@@ -10035,14 +10383,24 @@ function parseIncludeDirective(inner) {
|
|
|
10035
10383
|
}
|
|
10036
10384
|
}
|
|
10037
10385
|
const variables = {};
|
|
10386
|
+
const hasConcrete = new Set;
|
|
10038
10387
|
for (const segment of varSegments) {
|
|
10039
10388
|
const eqIndex = segment.indexOf("=");
|
|
10040
|
-
if (eqIndex
|
|
10041
|
-
|
|
10042
|
-
|
|
10043
|
-
|
|
10389
|
+
if (eqIndex === -1)
|
|
10390
|
+
continue;
|
|
10391
|
+
const key = segment.slice(0, eqIndex).trim();
|
|
10392
|
+
if (!key)
|
|
10393
|
+
continue;
|
|
10394
|
+
const value = segment.slice(eqIndex + 1).trim();
|
|
10395
|
+
const isPlaceholder = /^\{\$[^}]*\}$/.test(value);
|
|
10396
|
+
const isConcrete = value !== "" && !isPlaceholder;
|
|
10397
|
+
if (isConcrete) {
|
|
10398
|
+
if (!hasConcrete.has(key)) {
|
|
10044
10399
|
variables[key] = value;
|
|
10400
|
+
hasConcrete.add(key);
|
|
10045
10401
|
}
|
|
10402
|
+
} else if (!Object.hasOwn(variables, key)) {
|
|
10403
|
+
variables[key] = value;
|
|
10046
10404
|
}
|
|
10047
10405
|
}
|
|
10048
10406
|
let location;
|
|
@@ -10059,7 +10417,7 @@ function parseIncludeDirective(inner) {
|
|
|
10059
10417
|
}
|
|
10060
10418
|
return { location, variables };
|
|
10061
10419
|
}
|
|
10062
|
-
function replaceOneInclude(
|
|
10420
|
+
function replaceOneInclude(inner, fetcher) {
|
|
10063
10421
|
const { location, variables } = parseIncludeDirective(inner);
|
|
10064
10422
|
const content = fetcher(location);
|
|
10065
10423
|
if (content === null) {
|
|
@@ -10072,25 +10430,33 @@ Page to be included "${location.page}" cannot be found!
|
|
|
10072
10430
|
function expandIterative(source, fetcher, maxIterations) {
|
|
10073
10431
|
let current = source;
|
|
10074
10432
|
for (let i = 0;i < maxIterations; i++) {
|
|
10075
|
-
const
|
|
10076
|
-
|
|
10077
|
-
|
|
10433
|
+
const directives = scanIncludeDirectives(current);
|
|
10434
|
+
if (directives.length === 0)
|
|
10435
|
+
break;
|
|
10436
|
+
let result = "";
|
|
10437
|
+
let lastPos = 0;
|
|
10438
|
+
for (const { start, end, inner } of directives) {
|
|
10439
|
+
result += current.slice(lastPos, start);
|
|
10440
|
+
result += replaceOneInclude(inner, fetcher);
|
|
10441
|
+
lastPos = end;
|
|
10442
|
+
}
|
|
10443
|
+
result += current.slice(lastPos);
|
|
10444
|
+
if (result === current)
|
|
10078
10445
|
break;
|
|
10446
|
+
current = result;
|
|
10079
10447
|
}
|
|
10080
10448
|
return current;
|
|
10081
10449
|
}
|
|
10082
10450
|
async function expandIterativeAsync(source, fetcher, maxIterations) {
|
|
10083
10451
|
let current = source;
|
|
10084
10452
|
for (let i = 0;i < maxIterations; i++) {
|
|
10085
|
-
const
|
|
10086
|
-
|
|
10453
|
+
const directives = scanIncludeDirectives(current);
|
|
10454
|
+
if (directives.length === 0)
|
|
10455
|
+
break;
|
|
10087
10456
|
let result = "";
|
|
10088
10457
|
let lastPos = 0;
|
|
10089
|
-
|
|
10090
|
-
|
|
10091
|
-
const fullMatch = match[0];
|
|
10092
|
-
const inner = match[1];
|
|
10093
|
-
result += current.slice(lastPos, match.index);
|
|
10458
|
+
for (const { start, end, inner } of directives) {
|
|
10459
|
+
result += current.slice(lastPos, start);
|
|
10094
10460
|
const { location, variables } = parseIncludeDirective(inner);
|
|
10095
10461
|
const content = await fetcher(location);
|
|
10096
10462
|
if (content === null) {
|
|
@@ -10100,12 +10466,12 @@ Page to be included "${location.page}" cannot be found!
|
|
|
10100
10466
|
} else {
|
|
10101
10467
|
result += substituteVariables(content, variables);
|
|
10102
10468
|
}
|
|
10103
|
-
lastPos =
|
|
10469
|
+
lastPos = end;
|
|
10104
10470
|
}
|
|
10105
10471
|
result += current.slice(lastPos);
|
|
10106
|
-
|
|
10107
|
-
if (current === previous)
|
|
10472
|
+
if (result === current)
|
|
10108
10473
|
break;
|
|
10474
|
+
current = result;
|
|
10109
10475
|
}
|
|
10110
10476
|
return current;
|
|
10111
10477
|
}
|
|
@@ -10338,6 +10704,7 @@ export {
|
|
|
10338
10704
|
resolveListUsers,
|
|
10339
10705
|
resolveIncludesAsync,
|
|
10340
10706
|
resolveIncludes,
|
|
10707
|
+
preprocessIftags,
|
|
10341
10708
|
parseTags,
|
|
10342
10709
|
parseParent,
|
|
10343
10710
|
parseOrder,
|