@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.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
|
`) {
|
|
@@ -590,6 +596,73 @@ var BLOCK_START_TOKENS = [
|
|
|
590
596
|
"CLEAR_FLOAT_LEFT",
|
|
591
597
|
"CLEAR_FLOAT_RIGHT"
|
|
592
598
|
];
|
|
599
|
+
var KNOWN_BLOCK_NAMES = new Set([
|
|
600
|
+
"collapsible",
|
|
601
|
+
"div",
|
|
602
|
+
"div_",
|
|
603
|
+
"code",
|
|
604
|
+
"ul",
|
|
605
|
+
"ol",
|
|
606
|
+
"li",
|
|
607
|
+
"table",
|
|
608
|
+
"row",
|
|
609
|
+
"cell",
|
|
610
|
+
"hcell",
|
|
611
|
+
"tabview",
|
|
612
|
+
"tabs",
|
|
613
|
+
"module",
|
|
614
|
+
"module654",
|
|
615
|
+
"bibliography",
|
|
616
|
+
"footnoteblock",
|
|
617
|
+
"toc",
|
|
618
|
+
"iframe",
|
|
619
|
+
"math",
|
|
620
|
+
"html",
|
|
621
|
+
"iftags",
|
|
622
|
+
"include",
|
|
623
|
+
"f",
|
|
624
|
+
"embed",
|
|
625
|
+
"embedvideo",
|
|
626
|
+
"embedaudio",
|
|
627
|
+
"<",
|
|
628
|
+
">",
|
|
629
|
+
"=",
|
|
630
|
+
"==",
|
|
631
|
+
"span",
|
|
632
|
+
"span_",
|
|
633
|
+
"user",
|
|
634
|
+
"a",
|
|
635
|
+
"anchor",
|
|
636
|
+
"size",
|
|
637
|
+
"footnote",
|
|
638
|
+
"eref",
|
|
639
|
+
"$",
|
|
640
|
+
"image",
|
|
641
|
+
"gallery",
|
|
642
|
+
"file"
|
|
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
|
+
]);
|
|
593
666
|
|
|
594
667
|
// packages/parser/src/parser/rules/utils.ts
|
|
595
668
|
var SAFE_ATTRIBUTES = new Set([
|
|
@@ -716,13 +789,36 @@ function parseBlockName(ctx, startPos) {
|
|
|
716
789
|
|
|
717
790
|
// packages/parser/src/parser/rules/inline/utils.ts
|
|
718
791
|
function isExcludedBlockToken(ctx, tokenPos) {
|
|
719
|
-
|
|
792
|
+
const excluded = ctx.scope.excludedBlockNames;
|
|
793
|
+
if (!excluded?.size)
|
|
794
|
+
return false;
|
|
795
|
+
const token = ctx.tokens[tokenPos];
|
|
796
|
+
if (token?.type !== "BLOCK_OPEN" && token?.type !== "BLOCK_END_OPEN")
|
|
720
797
|
return false;
|
|
798
|
+
const nameResult = parseBlockName(ctx, tokenPos + 1);
|
|
799
|
+
return nameResult !== null && excluded.has(nameResult.name);
|
|
800
|
+
}
|
|
801
|
+
function isUnknownBlockToken(ctx, tokenPos) {
|
|
802
|
+
const token = ctx.tokens[tokenPos];
|
|
803
|
+
if (token?.type !== "BLOCK_OPEN" && token?.type !== "BLOCK_END_OPEN")
|
|
804
|
+
return false;
|
|
805
|
+
const nameResult = parseBlockName(ctx, tokenPos + 1);
|
|
806
|
+
if (nameResult === null) {
|
|
807
|
+
if (ctx.tokens[tokenPos + 1]?.type === "EQUALS") {
|
|
808
|
+
return false;
|
|
809
|
+
}
|
|
810
|
+
return true;
|
|
811
|
+
}
|
|
812
|
+
return !KNOWN_BLOCK_NAMES.has(nameResult.name);
|
|
813
|
+
}
|
|
814
|
+
function isIndentAcceptingBlock(ctx, tokenPos) {
|
|
721
815
|
const token = ctx.tokens[tokenPos];
|
|
722
816
|
if (token?.type !== "BLOCK_OPEN" && token?.type !== "BLOCK_END_OPEN")
|
|
723
817
|
return false;
|
|
724
818
|
const nameResult = parseBlockName(ctx, tokenPos + 1);
|
|
725
|
-
|
|
819
|
+
if (nameResult === null)
|
|
820
|
+
return false;
|
|
821
|
+
return INDENT_ACCEPTING_BLOCK_NAMES.has(nameResult.name);
|
|
726
822
|
}
|
|
727
823
|
function canApplyInlineRule(rule, token) {
|
|
728
824
|
if (rule.startTokens.length === 0) {
|
|
@@ -741,9 +837,9 @@ function parseInlineUntil(ctx, endType) {
|
|
|
741
837
|
if (!token || token.type === "EOF") {
|
|
742
838
|
break;
|
|
743
839
|
}
|
|
744
|
-
if (paragraphMode && ctx.blockCloseCondition) {
|
|
840
|
+
if (paragraphMode && ctx.scope.blockCloseCondition) {
|
|
745
841
|
const checkCtx = { ...ctx, pos };
|
|
746
|
-
if (ctx.blockCloseCondition(checkCtx)) {
|
|
842
|
+
if (ctx.scope.blockCloseCondition(checkCtx)) {
|
|
747
843
|
break;
|
|
748
844
|
}
|
|
749
845
|
}
|
|
@@ -795,7 +891,7 @@ function parseInlineUntil(ctx, endType) {
|
|
|
795
891
|
skipWhitespace++;
|
|
796
892
|
}
|
|
797
893
|
const blockNameToken = ctx.tokens[afterOpen + skipWhitespace];
|
|
798
|
-
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) {
|
|
799
895
|
isInvalidBlockOpen = true;
|
|
800
896
|
}
|
|
801
897
|
}
|
|
@@ -816,7 +912,9 @@ function parseInlineUntil(ctx, endType) {
|
|
|
816
912
|
}
|
|
817
913
|
}
|
|
818
914
|
const isExcludedBlock = (nextMeaningfulToken?.type === "BLOCK_OPEN" || nextMeaningfulToken?.type === "BLOCK_END_OPEN") && isExcludedBlockToken(ctx, pos + lookAhead);
|
|
819
|
-
const
|
|
915
|
+
const isUnknownBlock = (nextMeaningfulToken?.type === "BLOCK_OPEN" || nextMeaningfulToken?.type === "BLOCK_END_OPEN") && isUnknownBlockToken(ctx, pos + lookAhead);
|
|
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;
|
|
820
918
|
if (!nextMeaningfulToken || nextMeaningfulToken.type === "NEWLINE" || nextMeaningfulToken.type === "EOF" || isBlockStart) {
|
|
821
919
|
if (isBlockStart && nodes.length > 0) {
|
|
822
920
|
const nextPos = pos + lookAhead;
|
|
@@ -1153,7 +1251,6 @@ function buildListData(topLtype, list) {
|
|
|
1153
1251
|
items
|
|
1154
1252
|
};
|
|
1155
1253
|
}
|
|
1156
|
-
|
|
1157
1254
|
// packages/parser/src/parser/rules/block/utils.ts
|
|
1158
1255
|
function canApplyBlockRule(rule, token) {
|
|
1159
1256
|
if (rule.requiresLineStart && !token.lineStart) {
|
|
@@ -1195,8 +1292,11 @@ function parseBlocksUntil(ctx, closeCondition, options) {
|
|
|
1195
1292
|
...ctx,
|
|
1196
1293
|
pos,
|
|
1197
1294
|
blockRules,
|
|
1198
|
-
|
|
1199
|
-
|
|
1295
|
+
scope: {
|
|
1296
|
+
...ctx.scope,
|
|
1297
|
+
blockCloseCondition: closeCondition,
|
|
1298
|
+
excludedBlockNames: excluded
|
|
1299
|
+
}
|
|
1200
1300
|
};
|
|
1201
1301
|
for (const rule of blockRules) {
|
|
1202
1302
|
if (canApplyBlockRule(rule, token)) {
|
|
@@ -2184,15 +2284,15 @@ var divRule = {
|
|
|
2184
2284
|
if (ctx.tokens[pos]?.type !== "NEWLINE") {
|
|
2185
2285
|
return consumeFailedDiv(ctx);
|
|
2186
2286
|
}
|
|
2187
|
-
if (ctx.divClosesBudget === 0) {
|
|
2287
|
+
if (ctx.scope.divClosesBudget === 0) {
|
|
2188
2288
|
return { success: false };
|
|
2189
2289
|
}
|
|
2190
2290
|
pos++;
|
|
2191
2291
|
consumed++;
|
|
2192
2292
|
const openPosition = openToken.position;
|
|
2193
2293
|
let bodyBudget;
|
|
2194
|
-
if (ctx.divClosesBudget !== undefined) {
|
|
2195
|
-
bodyBudget = ctx.divClosesBudget - 1;
|
|
2294
|
+
if (ctx.scope.divClosesBudget !== undefined) {
|
|
2295
|
+
bodyBudget = ctx.scope.divClosesBudget - 1;
|
|
2196
2296
|
} else {
|
|
2197
2297
|
const closesInScope = countDivCloses(ctx, pos);
|
|
2198
2298
|
bodyBudget = closesInScope > 0 ? closesInScope - 1 : 0;
|
|
@@ -2207,7 +2307,11 @@ var divRule = {
|
|
|
2207
2307
|
}
|
|
2208
2308
|
return false;
|
|
2209
2309
|
};
|
|
2210
|
-
const bodyCtx = {
|
|
2310
|
+
const bodyCtx = {
|
|
2311
|
+
...ctx,
|
|
2312
|
+
pos,
|
|
2313
|
+
scope: { ...ctx.scope, divClosesBudget: bodyBudget }
|
|
2314
|
+
};
|
|
2211
2315
|
let children;
|
|
2212
2316
|
if (paragraphStrip) {
|
|
2213
2317
|
const bodyResult = parseBlocksUntil(bodyCtx, closeCondition);
|
|
@@ -3850,10 +3954,10 @@ var footnoteBlockRule = {
|
|
|
3850
3954
|
}
|
|
3851
3955
|
pos++;
|
|
3852
3956
|
consumed++;
|
|
3853
|
-
if (ctx.footnoteBlockParsed) {
|
|
3957
|
+
if (ctx.scope.footnoteBlockParsed) {
|
|
3854
3958
|
return { success: false };
|
|
3855
3959
|
}
|
|
3856
|
-
ctx.
|
|
3960
|
+
ctx.scope = { ...ctx.scope, footnoteBlockParsed: true };
|
|
3857
3961
|
const title = attrs.title !== undefined ? attrs.title : null;
|
|
3858
3962
|
const hide = attrs.hide === "true" || attrs.hide === "yes";
|
|
3859
3963
|
return {
|
|
@@ -4609,6 +4713,24 @@ var mathBlockRule = {
|
|
|
4609
4713
|
};
|
|
4610
4714
|
|
|
4611
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
|
+
}
|
|
4612
4734
|
var htmlBlockRule = {
|
|
4613
4735
|
name: "html",
|
|
4614
4736
|
startTokens: ["BLOCK_OPEN"],
|
|
@@ -4635,20 +4757,32 @@ var htmlBlockRule = {
|
|
|
4635
4757
|
}
|
|
4636
4758
|
pos++;
|
|
4637
4759
|
consumed++;
|
|
4760
|
+
const disabled = ctx.settings.allowHtmlBlocks === false;
|
|
4761
|
+
const hasCloseAhead = disabled && lookaheadHasHtmlClose(ctx, pos);
|
|
4638
4762
|
let contents = "";
|
|
4639
4763
|
let foundClose = false;
|
|
4640
4764
|
while (pos < ctx.tokens.length) {
|
|
4641
4765
|
const token = ctx.tokens[pos];
|
|
4642
4766
|
if (!token || token.type === "EOF")
|
|
4643
4767
|
break;
|
|
4768
|
+
if (disabled && !hasCloseAhead && token.type === "NEWLINE" && ctx.tokens[pos + 1]?.type === "NEWLINE") {
|
|
4769
|
+
break;
|
|
4770
|
+
}
|
|
4644
4771
|
if (token.type === "BLOCK_END_OPEN") {
|
|
4645
4772
|
const closeNameResult = parseBlockName(ctx, pos + 1);
|
|
4646
4773
|
if (closeNameResult?.name.toLowerCase() === "html") {
|
|
4647
|
-
|
|
4648
|
-
|
|
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
|
+
}
|
|
4649
4781
|
}
|
|
4650
4782
|
}
|
|
4651
|
-
|
|
4783
|
+
if (!disabled) {
|
|
4784
|
+
contents += token.value;
|
|
4785
|
+
}
|
|
4652
4786
|
pos++;
|
|
4653
4787
|
consumed++;
|
|
4654
4788
|
}
|
|
@@ -4659,7 +4793,16 @@ var htmlBlockRule = {
|
|
|
4659
4793
|
message: "Missing closing tag [[/html]] for [[html]]",
|
|
4660
4794
|
position: openToken.position
|
|
4661
4795
|
});
|
|
4662
|
-
|
|
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 };
|
|
4663
4806
|
}
|
|
4664
4807
|
if (ctx.tokens[pos]?.type === "BLOCK_END_OPEN") {
|
|
4665
4808
|
pos++;
|
|
@@ -4669,6 +4812,10 @@ var htmlBlockRule = {
|
|
|
4669
4812
|
pos += closeNameResult.consumed;
|
|
4670
4813
|
consumed += closeNameResult.consumed;
|
|
4671
4814
|
}
|
|
4815
|
+
while (ctx.tokens[pos]?.type === "WHITESPACE") {
|
|
4816
|
+
pos++;
|
|
4817
|
+
consumed++;
|
|
4818
|
+
}
|
|
4672
4819
|
if (ctx.tokens[pos]?.type === "BLOCK_CLOSE") {
|
|
4673
4820
|
pos++;
|
|
4674
4821
|
consumed++;
|
|
@@ -4678,6 +4825,15 @@ var htmlBlockRule = {
|
|
|
4678
4825
|
consumed++;
|
|
4679
4826
|
}
|
|
4680
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
|
+
}
|
|
4681
4837
|
contents = contents.trim();
|
|
4682
4838
|
ctx.htmlBlocks.push(contents);
|
|
4683
4839
|
return {
|
|
@@ -6363,6 +6519,82 @@ var commentRule = {
|
|
|
6363
6519
|
}
|
|
6364
6520
|
};
|
|
6365
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
|
+
|
|
6366
6598
|
// packages/parser/src/parser/rules/inline/raw.ts
|
|
6367
6599
|
var rawRule = {
|
|
6368
6600
|
name: "raw",
|
|
@@ -8073,6 +8305,7 @@ var inlineRules = [
|
|
|
8073
8305
|
underscoreLineBreakRule,
|
|
8074
8306
|
newlineLineBreakRule,
|
|
8075
8307
|
commentRule,
|
|
8308
|
+
htmlInlineRule,
|
|
8076
8309
|
rawRule,
|
|
8077
8310
|
imageRule,
|
|
8078
8311
|
sizeRule,
|
|
@@ -8590,89 +8823,339 @@ function buildTableOfContents(entries) {
|
|
|
8590
8823
|
return trees.map((tree) => buildTocList(indexer, tree.list));
|
|
8591
8824
|
}
|
|
8592
8825
|
|
|
8593
|
-
// packages/parser/src/parser/
|
|
8594
|
-
|
|
8595
|
-
|
|
8596
|
-
|
|
8597
|
-
|
|
8598
|
-
|
|
8599
|
-
|
|
8600
|
-
|
|
8601
|
-
|
|
8602
|
-
|
|
8603
|
-
|
|
8604
|
-
|
|
8605
|
-
|
|
8606
|
-
|
|
8607
|
-
footnoteBlockParsed: false,
|
|
8608
|
-
bibcites: [],
|
|
8609
|
-
diagnostics: [],
|
|
8610
|
-
blockRules,
|
|
8611
|
-
blockFallbackRule: paragraphRule,
|
|
8612
|
-
inlineRules
|
|
8613
|
-
};
|
|
8614
|
-
}
|
|
8615
|
-
parse() {
|
|
8616
|
-
const children = [];
|
|
8617
|
-
while (!this.isAtEnd()) {
|
|
8618
|
-
const blocks = this.parseBlock();
|
|
8619
|
-
children.push(...blocks);
|
|
8620
|
-
}
|
|
8621
|
-
const mergedChildren = mergeSpanStripParagraphs(children);
|
|
8622
|
-
const divProcessed = suppressDivAdjacentParagraphs(mergedChildren);
|
|
8623
|
-
const cleanedChildren = cleanInternalFlags(divProcessed);
|
|
8624
|
-
const hasFootnoteBlock = cleanedChildren.some((el) => el.element === "footnote-block");
|
|
8625
|
-
if (!hasFootnoteBlock) {
|
|
8626
|
-
cleanedChildren.push({
|
|
8627
|
-
element: "footnote-block",
|
|
8628
|
-
data: { title: null, hide: false }
|
|
8629
|
-
});
|
|
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;
|
|
8630
8840
|
}
|
|
8631
|
-
|
|
8632
|
-
|
|
8633
|
-
|
|
8634
|
-
|
|
8635
|
-
|
|
8636
|
-
|
|
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;
|
|
8637
8849
|
}
|
|
8638
|
-
if (
|
|
8639
|
-
|
|
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;
|
|
8640
8857
|
}
|
|
8641
|
-
if (
|
|
8642
|
-
|
|
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;
|
|
8643
8864
|
}
|
|
8644
|
-
if (
|
|
8645
|
-
|
|
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
|
+
}
|
|
8646
8870
|
}
|
|
8647
|
-
return { ast: result, diagnostics: this.ctx.diagnostics };
|
|
8648
|
-
}
|
|
8649
|
-
isAtEnd() {
|
|
8650
|
-
return this.ctx.pos >= this.ctx.tokens.length || this.currentToken().type === "EOF";
|
|
8651
|
-
}
|
|
8652
|
-
currentToken() {
|
|
8653
|
-
return this.ctx.tokens[this.ctx.pos] ?? this.eofToken();
|
|
8654
8871
|
}
|
|
8655
|
-
|
|
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
|
+
}
|
|
8656
8898
|
return {
|
|
8657
|
-
|
|
8658
|
-
|
|
8659
|
-
position: {
|
|
8660
|
-
start: { line: 0, column: 0, offset: 0 },
|
|
8661
|
-
end: { line: 0, column: 0, offset: 0 }
|
|
8662
|
-
},
|
|
8663
|
-
lineStart: false
|
|
8899
|
+
element: "list",
|
|
8900
|
+
data: { ...listData, items: newItems }
|
|
8664
8901
|
};
|
|
8665
8902
|
}
|
|
8666
|
-
|
|
8667
|
-
|
|
8668
|
-
|
|
8669
|
-
|
|
8670
|
-
|
|
8671
|
-
|
|
8672
|
-
|
|
8673
|
-
|
|
8674
|
-
|
|
8675
|
-
}
|
|
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
|
+
}
|
|
9153
|
+
}
|
|
9154
|
+
parseBlock() {
|
|
9155
|
+
this.skipWhitespace();
|
|
9156
|
+
if (this.isAtEnd()) {
|
|
9157
|
+
return [];
|
|
9158
|
+
}
|
|
8676
9159
|
const token = this.currentToken();
|
|
8677
9160
|
if (token.type === "NEWLINE") {
|
|
8678
9161
|
this.ctx.pos++;
|
|
@@ -8701,6 +9184,14 @@ function parse(source, options) {
|
|
|
8701
9184
|
const tokens = tokenize(preprocessed, { trackPositions: options?.trackPositions });
|
|
8702
9185
|
return new Parser(tokens, options).parse();
|
|
8703
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
|
+
}
|
|
8704
9195
|
// packages/parser/src/parser/rules/block/module/listpages/compiler.ts
|
|
8705
9196
|
var DEFAULT_PREVIEW_LENGTH = 200;
|
|
8706
9197
|
var VARIABLE_REGEX = /%%([a-z_]+)(?:\{([^}]+)\})?(?:\((\d+)\))?(?:\|([^%]*(?:%(?!%)[^%]*)*))?%%/gi;
|
|
@@ -8908,348 +9399,99 @@ function strftime(date, format) {
|
|
|
8908
9399
|
return String(date.getDate());
|
|
8909
9400
|
case "H":
|
|
8910
9401
|
return pad(date.getHours());
|
|
8911
|
-
case "I":
|
|
8912
|
-
return pad(date.getHours() % 12 || 12);
|
|
8913
|
-
case "M":
|
|
8914
|
-
return pad(date.getMinutes());
|
|
8915
|
-
case "S":
|
|
8916
|
-
return pad(date.getSeconds());
|
|
8917
|
-
case "p":
|
|
8918
|
-
return date.getHours() < 12 ? "AM" : "PM";
|
|
8919
|
-
case "b":
|
|
8920
|
-
return MONTHS_SHORT[date.getMonth()] ?? "";
|
|
8921
|
-
case "B":
|
|
8922
|
-
return MONTHS[date.getMonth()] ?? "";
|
|
8923
|
-
case "a":
|
|
8924
|
-
return DAYS_SHORT[date.getDay()] ?? "";
|
|
8925
|
-
case "A":
|
|
8926
|
-
return DAYS[date.getDay()] ?? "";
|
|
8927
|
-
case "w":
|
|
8928
|
-
return String(date.getDay());
|
|
8929
|
-
case "j":
|
|
8930
|
-
return pad(getDayOfYear(date), 3);
|
|
8931
|
-
case "Z":
|
|
8932
|
-
return "UTC";
|
|
8933
|
-
case "z":
|
|
8934
|
-
return "+0000";
|
|
8935
|
-
case "%":
|
|
8936
|
-
return "%";
|
|
8937
|
-
default:
|
|
8938
|
-
return `%${token}`;
|
|
8939
|
-
}
|
|
8940
|
-
});
|
|
8941
|
-
}
|
|
8942
|
-
function getDayOfYear(date) {
|
|
8943
|
-
const start = new Date(date.getFullYear(), 0, 0);
|
|
8944
|
-
const diff = date.getTime() - start.getTime();
|
|
8945
|
-
const oneDay = 1000 * 60 * 60 * 24;
|
|
8946
|
-
return Math.floor(diff / oneDay);
|
|
8947
|
-
}
|
|
8948
|
-
|
|
8949
|
-
// packages/parser/src/parser/rules/block/module/listusers/compiler.ts
|
|
8950
|
-
var VARIABLE_REGEX2 = /%%([a-z_]+)%%/gi;
|
|
8951
|
-
function compileListUsersTemplate(template) {
|
|
8952
|
-
const parts = [];
|
|
8953
|
-
let lastIndex = 0;
|
|
8954
|
-
for (const match of template.matchAll(VARIABLE_REGEX2)) {
|
|
8955
|
-
if (match.index !== undefined && match.index > lastIndex) {
|
|
8956
|
-
parts.push(template.slice(lastIndex, match.index));
|
|
8957
|
-
}
|
|
8958
|
-
const [, varName] = match;
|
|
8959
|
-
if (!varName)
|
|
8960
|
-
continue;
|
|
8961
|
-
const getter = createVariableGetter2(varName.toLowerCase());
|
|
8962
|
-
parts.push(getter);
|
|
8963
|
-
lastIndex = match.index !== undefined ? match.index + match[0].length : lastIndex;
|
|
8964
|
-
}
|
|
8965
|
-
if (lastIndex < template.length) {
|
|
8966
|
-
parts.push(template.slice(lastIndex));
|
|
8967
|
-
}
|
|
8968
|
-
return (ctx) => {
|
|
8969
|
-
let result = "";
|
|
8970
|
-
for (const part of parts) {
|
|
8971
|
-
result += typeof part === "string" ? part : part(ctx);
|
|
8972
|
-
}
|
|
8973
|
-
return result;
|
|
8974
|
-
};
|
|
8975
|
-
}
|
|
8976
|
-
function createVariableGetter2(name) {
|
|
8977
|
-
switch (name) {
|
|
8978
|
-
case "number":
|
|
8979
|
-
return (ctx) => String(ctx.user.number);
|
|
8980
|
-
case "title":
|
|
8981
|
-
return (ctx) => ctx.user.title;
|
|
8982
|
-
case "name":
|
|
8983
|
-
return (ctx) => ctx.user.name;
|
|
8984
|
-
default:
|
|
8985
|
-
return () => "";
|
|
8986
|
-
}
|
|
8987
|
-
}
|
|
8988
|
-
|
|
8989
|
-
// packages/parser/src/parser/rules/block/module/listusers/extract.ts
|
|
8990
|
-
var VARIABLE_REGEX3 = /%%([a-z_]+)%%/gi;
|
|
8991
|
-
var KNOWN_VARIABLES = ["number", "title", "name"];
|
|
8992
|
-
function extractListUsersVariables(template) {
|
|
8993
|
-
const variables = new Set;
|
|
8994
|
-
for (const match of template.matchAll(VARIABLE_REGEX3)) {
|
|
8995
|
-
const [, varName] = match;
|
|
8996
|
-
if (!varName)
|
|
8997
|
-
continue;
|
|
8998
|
-
const normalized = varName.toLowerCase();
|
|
8999
|
-
if (KNOWN_VARIABLES.includes(normalized)) {
|
|
9000
|
-
variables.add(normalized);
|
|
9001
|
-
}
|
|
9002
|
-
}
|
|
9003
|
-
return Array.from(variables);
|
|
9004
|
-
}
|
|
9005
|
-
|
|
9006
|
-
// packages/parser/src/parser/rules/block/module/walk.ts
|
|
9007
|
-
function walkElements(elements, callback) {
|
|
9008
|
-
for (const element of elements) {
|
|
9009
|
-
callback(element);
|
|
9010
|
-
if (element.element === "list") {
|
|
9011
|
-
const listData = element.data;
|
|
9012
|
-
for (const item of listData.items) {
|
|
9013
|
-
if (item["item-type"] === "elements") {
|
|
9014
|
-
walkElements(item.elements, callback);
|
|
9015
|
-
} else if (item["item-type"] === "sub-list") {
|
|
9016
|
-
walkElements([{ element: "list", data: item.data }], callback);
|
|
9017
|
-
}
|
|
9018
|
-
}
|
|
9019
|
-
continue;
|
|
9020
|
-
}
|
|
9021
|
-
if (element.element === "table") {
|
|
9022
|
-
const tableData = element.data;
|
|
9023
|
-
for (const row of tableData.rows) {
|
|
9024
|
-
for (const cell of row.cells) {
|
|
9025
|
-
walkElements(cell.elements, callback);
|
|
9026
|
-
}
|
|
9027
|
-
}
|
|
9028
|
-
continue;
|
|
9029
|
-
}
|
|
9030
|
-
if (element.element === "definition-list") {
|
|
9031
|
-
const defListData = element.data;
|
|
9032
|
-
for (const item of defListData) {
|
|
9033
|
-
walkElements(item.key, callback);
|
|
9034
|
-
walkElements(item.value, callback);
|
|
9035
|
-
}
|
|
9036
|
-
continue;
|
|
9037
|
-
}
|
|
9038
|
-
if (element.element === "tab-view") {
|
|
9039
|
-
const tabData = element.data;
|
|
9040
|
-
for (const tab of tabData) {
|
|
9041
|
-
walkElements(tab.elements, callback);
|
|
9042
|
-
}
|
|
9043
|
-
continue;
|
|
9044
|
-
}
|
|
9045
|
-
if ("data" in element && element.data && typeof element.data === "object") {
|
|
9046
|
-
const data = element.data;
|
|
9047
|
-
if ("elements" in data && Array.isArray(data.elements)) {
|
|
9048
|
-
walkElements(data.elements, callback);
|
|
9049
|
-
}
|
|
9050
|
-
}
|
|
9051
|
-
}
|
|
9052
|
-
}
|
|
9053
|
-
function mapElementChildren(element, transform) {
|
|
9054
|
-
if (element.element === "list") {
|
|
9055
|
-
const listData = element.data;
|
|
9056
|
-
const newItems = [];
|
|
9057
|
-
for (const item of listData.items) {
|
|
9058
|
-
if (item["item-type"] === "elements") {
|
|
9059
|
-
newItems.push({
|
|
9060
|
-
"item-type": "elements",
|
|
9061
|
-
attributes: item.attributes,
|
|
9062
|
-
elements: transform(item.elements)
|
|
9063
|
-
});
|
|
9064
|
-
} else if (item["item-type"] === "sub-list") {
|
|
9065
|
-
const subListResult = transform([{ element: "list", data: item.data }]);
|
|
9066
|
-
const resolvedList = subListResult[0];
|
|
9067
|
-
if (resolvedList?.element === "list") {
|
|
9068
|
-
newItems.push({
|
|
9069
|
-
"item-type": "sub-list",
|
|
9070
|
-
element: "list",
|
|
9071
|
-
data: resolvedList.data
|
|
9072
|
-
});
|
|
9073
|
-
} else {
|
|
9074
|
-
newItems.push(item);
|
|
9075
|
-
}
|
|
9076
|
-
}
|
|
9077
|
-
}
|
|
9078
|
-
return {
|
|
9079
|
-
element: "list",
|
|
9080
|
-
data: { ...listData, items: newItems }
|
|
9081
|
-
};
|
|
9082
|
-
}
|
|
9083
|
-
if (element.element === "table") {
|
|
9084
|
-
const tableData = element.data;
|
|
9085
|
-
const newRows = [];
|
|
9086
|
-
for (const row of tableData.rows) {
|
|
9087
|
-
const newCells = [];
|
|
9088
|
-
for (const cell of row.cells) {
|
|
9089
|
-
newCells.push({ ...cell, elements: transform(cell.elements) });
|
|
9090
|
-
}
|
|
9091
|
-
newRows.push({ ...row, cells: newCells });
|
|
9092
|
-
}
|
|
9093
|
-
return {
|
|
9094
|
-
element: "table",
|
|
9095
|
-
data: { ...tableData, rows: newRows }
|
|
9096
|
-
};
|
|
9097
|
-
}
|
|
9098
|
-
if (element.element === "definition-list") {
|
|
9099
|
-
const defListData = element.data;
|
|
9100
|
-
const newItems = [];
|
|
9101
|
-
for (const item of defListData) {
|
|
9102
|
-
newItems.push({
|
|
9103
|
-
key_string: item.key_string,
|
|
9104
|
-
key: transform(item.key),
|
|
9105
|
-
value: transform(item.value)
|
|
9106
|
-
});
|
|
9107
|
-
}
|
|
9108
|
-
return {
|
|
9109
|
-
element: "definition-list",
|
|
9110
|
-
data: newItems
|
|
9111
|
-
};
|
|
9112
|
-
}
|
|
9113
|
-
if (element.element === "tab-view") {
|
|
9114
|
-
const tabData = element.data;
|
|
9115
|
-
const newTabs = [];
|
|
9116
|
-
for (const tab of tabData) {
|
|
9117
|
-
newTabs.push({ ...tab, elements: transform(tab.elements) });
|
|
9118
|
-
}
|
|
9119
|
-
return {
|
|
9120
|
-
element: "tab-view",
|
|
9121
|
-
data: newTabs
|
|
9122
|
-
};
|
|
9123
|
-
}
|
|
9124
|
-
if ("data" in element && element.data && typeof element.data === "object") {
|
|
9125
|
-
const data = element.data;
|
|
9126
|
-
if ("elements" in data && Array.isArray(data.elements)) {
|
|
9127
|
-
return {
|
|
9128
|
-
...element,
|
|
9129
|
-
data: {
|
|
9130
|
-
...data,
|
|
9131
|
-
elements: transform(data.elements)
|
|
9132
|
-
}
|
|
9133
|
-
};
|
|
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}`;
|
|
9134
9430
|
}
|
|
9135
|
-
}
|
|
9136
|
-
return element;
|
|
9431
|
+
});
|
|
9137
9432
|
}
|
|
9138
|
-
function
|
|
9139
|
-
|
|
9140
|
-
|
|
9141
|
-
|
|
9142
|
-
|
|
9143
|
-
|
|
9144
|
-
|
|
9145
|
-
|
|
9146
|
-
|
|
9147
|
-
|
|
9148
|
-
|
|
9149
|
-
|
|
9150
|
-
|
|
9151
|
-
|
|
9152
|
-
|
|
9153
|
-
const result = transform([{ element: "list", data: item.data }], currentState);
|
|
9154
|
-
const resolvedList = result.elements[0];
|
|
9155
|
-
if (resolvedList?.element === "list") {
|
|
9156
|
-
newItems.push({
|
|
9157
|
-
"item-type": "sub-list",
|
|
9158
|
-
element: "list",
|
|
9159
|
-
data: resolvedList.data
|
|
9160
|
-
});
|
|
9161
|
-
} else {
|
|
9162
|
-
newItems.push(item);
|
|
9163
|
-
}
|
|
9164
|
-
currentState = result.state;
|
|
9165
|
-
}
|
|
9166
|
-
}
|
|
9167
|
-
return {
|
|
9168
|
-
element: {
|
|
9169
|
-
element: "list",
|
|
9170
|
-
data: { ...listData, items: newItems }
|
|
9171
|
-
},
|
|
9172
|
-
state: currentState
|
|
9173
|
-
};
|
|
9174
|
-
}
|
|
9175
|
-
if (element.element === "table") {
|
|
9176
|
-
const tableData = element.data;
|
|
9177
|
-
const newRows = [];
|
|
9178
|
-
let currentState = state;
|
|
9179
|
-
for (const row of tableData.rows) {
|
|
9180
|
-
const newCells = [];
|
|
9181
|
-
for (const cell of row.cells) {
|
|
9182
|
-
const result = transform(cell.elements, currentState);
|
|
9183
|
-
newCells.push({ ...cell, elements: result.elements });
|
|
9184
|
-
currentState = result.state;
|
|
9185
|
-
}
|
|
9186
|
-
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));
|
|
9187
9448
|
}
|
|
9188
|
-
|
|
9189
|
-
|
|
9190
|
-
|
|
9191
|
-
|
|
9192
|
-
|
|
9193
|
-
|
|
9194
|
-
};
|
|
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;
|
|
9195
9455
|
}
|
|
9196
|
-
if (
|
|
9197
|
-
|
|
9198
|
-
const newItems = [];
|
|
9199
|
-
let currentState = state;
|
|
9200
|
-
for (const item of defListData) {
|
|
9201
|
-
const keyResult = transform(item.key, currentState);
|
|
9202
|
-
currentState = keyResult.state;
|
|
9203
|
-
const valueResult = transform(item.value, currentState);
|
|
9204
|
-
currentState = valueResult.state;
|
|
9205
|
-
newItems.push({
|
|
9206
|
-
key_string: item.key_string,
|
|
9207
|
-
key: keyResult.elements,
|
|
9208
|
-
value: valueResult.elements
|
|
9209
|
-
});
|
|
9210
|
-
}
|
|
9211
|
-
return {
|
|
9212
|
-
element: {
|
|
9213
|
-
element: "definition-list",
|
|
9214
|
-
data: newItems
|
|
9215
|
-
},
|
|
9216
|
-
state: currentState
|
|
9217
|
-
};
|
|
9456
|
+
if (lastIndex < template.length) {
|
|
9457
|
+
parts.push(template.slice(lastIndex));
|
|
9218
9458
|
}
|
|
9219
|
-
|
|
9220
|
-
|
|
9221
|
-
const
|
|
9222
|
-
|
|
9223
|
-
for (const tab of tabData) {
|
|
9224
|
-
const result = transform(tab.elements, currentState);
|
|
9225
|
-
newTabs.push({ ...tab, elements: result.elements });
|
|
9226
|
-
currentState = result.state;
|
|
9459
|
+
return (ctx) => {
|
|
9460
|
+
let result = "";
|
|
9461
|
+
for (const part of parts) {
|
|
9462
|
+
result += typeof part === "string" ? part : part(ctx);
|
|
9227
9463
|
}
|
|
9228
|
-
return
|
|
9229
|
-
|
|
9230
|
-
|
|
9231
|
-
|
|
9232
|
-
|
|
9233
|
-
|
|
9234
|
-
|
|
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 () => "";
|
|
9235
9477
|
}
|
|
9236
|
-
|
|
9237
|
-
|
|
9238
|
-
|
|
9239
|
-
|
|
9240
|
-
|
|
9241
|
-
|
|
9242
|
-
|
|
9243
|
-
|
|
9244
|
-
|
|
9245
|
-
|
|
9246
|
-
|
|
9247
|
-
|
|
9248
|
-
|
|
9249
|
-
|
|
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);
|
|
9250
9492
|
}
|
|
9251
9493
|
}
|
|
9252
|
-
return
|
|
9494
|
+
return Array.from(variables);
|
|
9253
9495
|
}
|
|
9254
9496
|
|
|
9255
9497
|
// packages/parser/src/parser/rules/block/module/listpages/extract.ts
|
|
@@ -9908,6 +10150,110 @@ function resolveIfTags(data, pageTags) {
|
|
|
9908
10150
|
const matched = evaluateTagCondition(condition, pageTags);
|
|
9909
10151
|
return { evaluated: true, matched };
|
|
9910
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
|
+
}
|
|
9911
10257
|
// packages/parser/src/parser/rules/block/module/include/resolve.ts
|
|
9912
10258
|
function resolveIncludes(source, fetcher, options) {
|
|
9913
10259
|
if (options?.settings && !options.settings.enablePageSyntax) {
|
|
@@ -9953,7 +10299,67 @@ async function resolveIncludesAsync(source, fetcher, options) {
|
|
|
9953
10299
|
};
|
|
9954
10300
|
return expandIterativeAsync(source, cachedFetcher, maxIterations);
|
|
9955
10301
|
}
|
|
9956
|
-
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
|
+
}
|
|
9957
10363
|
function parseIncludeDirective(inner) {
|
|
9958
10364
|
const normalized = inner.replace(/\n/g, " ");
|
|
9959
10365
|
const parts = normalized.split("|");
|
|
@@ -9977,14 +10383,24 @@ function parseIncludeDirective(inner) {
|
|
|
9977
10383
|
}
|
|
9978
10384
|
}
|
|
9979
10385
|
const variables = {};
|
|
10386
|
+
const hasConcrete = new Set;
|
|
9980
10387
|
for (const segment of varSegments) {
|
|
9981
10388
|
const eqIndex = segment.indexOf("=");
|
|
9982
|
-
if (eqIndex
|
|
9983
|
-
|
|
9984
|
-
|
|
9985
|
-
|
|
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)) {
|
|
9986
10399
|
variables[key] = value;
|
|
10400
|
+
hasConcrete.add(key);
|
|
9987
10401
|
}
|
|
10402
|
+
} else if (!Object.hasOwn(variables, key)) {
|
|
10403
|
+
variables[key] = value;
|
|
9988
10404
|
}
|
|
9989
10405
|
}
|
|
9990
10406
|
let location;
|
|
@@ -10001,7 +10417,7 @@ function parseIncludeDirective(inner) {
|
|
|
10001
10417
|
}
|
|
10002
10418
|
return { location, variables };
|
|
10003
10419
|
}
|
|
10004
|
-
function replaceOneInclude(
|
|
10420
|
+
function replaceOneInclude(inner, fetcher) {
|
|
10005
10421
|
const { location, variables } = parseIncludeDirective(inner);
|
|
10006
10422
|
const content = fetcher(location);
|
|
10007
10423
|
if (content === null) {
|
|
@@ -10014,25 +10430,33 @@ Page to be included "${location.page}" cannot be found!
|
|
|
10014
10430
|
function expandIterative(source, fetcher, maxIterations) {
|
|
10015
10431
|
let current = source;
|
|
10016
10432
|
for (let i = 0;i < maxIterations; i++) {
|
|
10017
|
-
const
|
|
10018
|
-
|
|
10019
|
-
|
|
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)
|
|
10020
10445
|
break;
|
|
10446
|
+
current = result;
|
|
10021
10447
|
}
|
|
10022
10448
|
return current;
|
|
10023
10449
|
}
|
|
10024
10450
|
async function expandIterativeAsync(source, fetcher, maxIterations) {
|
|
10025
10451
|
let current = source;
|
|
10026
10452
|
for (let i = 0;i < maxIterations; i++) {
|
|
10027
|
-
const
|
|
10028
|
-
|
|
10453
|
+
const directives = scanIncludeDirectives(current);
|
|
10454
|
+
if (directives.length === 0)
|
|
10455
|
+
break;
|
|
10029
10456
|
let result = "";
|
|
10030
10457
|
let lastPos = 0;
|
|
10031
|
-
|
|
10032
|
-
|
|
10033
|
-
const fullMatch = match[0];
|
|
10034
|
-
const inner = match[1];
|
|
10035
|
-
result += current.slice(lastPos, match.index);
|
|
10458
|
+
for (const { start, end, inner } of directives) {
|
|
10459
|
+
result += current.slice(lastPos, start);
|
|
10036
10460
|
const { location, variables } = parseIncludeDirective(inner);
|
|
10037
10461
|
const content = await fetcher(location);
|
|
10038
10462
|
if (content === null) {
|
|
@@ -10042,12 +10466,12 @@ Page to be included "${location.page}" cannot be found!
|
|
|
10042
10466
|
} else {
|
|
10043
10467
|
result += substituteVariables(content, variables);
|
|
10044
10468
|
}
|
|
10045
|
-
lastPos =
|
|
10469
|
+
lastPos = end;
|
|
10046
10470
|
}
|
|
10047
10471
|
result += current.slice(lastPos);
|
|
10048
|
-
|
|
10049
|
-
if (current === previous)
|
|
10472
|
+
if (result === current)
|
|
10050
10473
|
break;
|
|
10474
|
+
current = result;
|
|
10051
10475
|
}
|
|
10052
10476
|
return current;
|
|
10053
10477
|
}
|
|
@@ -10280,6 +10704,7 @@ export {
|
|
|
10280
10704
|
resolveListUsers,
|
|
10281
10705
|
resolveIncludesAsync,
|
|
10282
10706
|
resolveIncludes,
|
|
10707
|
+
preprocessIftags,
|
|
10283
10708
|
parseTags,
|
|
10284
10709
|
parseParent,
|
|
10285
10710
|
parseOrder,
|