@wdprlib/parser 1.1.4 → 2.0.2
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/README.md +2 -1
- package/dist/index.cjs +322 -3
- package/dist/index.d.cts +23 -11
- package/dist/index.d.ts +23 -11
- package/dist/index.js +322 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @wdprlib/parser
|
|
2
2
|
|
|
3
|
-
Wikidot markup
|
|
3
|
+
Parser for Wikidot markup.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -56,6 +56,7 @@ const resolved = await resolveModules(ast, {
|
|
|
56
56
|
|
|
57
57
|
- [@wdprlib/ast](https://www.npmjs.com/package/@wdprlib/ast) - AST type definitions
|
|
58
58
|
- [@wdprlib/render](https://www.npmjs.com/package/@wdprlib/render) - HTML renderer
|
|
59
|
+
- [@wdprlib/decompiler](https://www.npmjs.com/package/@wdprlib/decompiler) - HTML to Wikidot decompiler
|
|
59
60
|
- [@wdprlib/runtime](https://www.npmjs.com/package/@wdprlib/runtime) - Client-side runtime
|
|
60
61
|
|
|
61
62
|
## License
|
package/dist/index.cjs
CHANGED
|
@@ -1528,6 +1528,17 @@ function parseLiItem(ctx, startPos, listType) {
|
|
|
1528
1528
|
pos++;
|
|
1529
1529
|
}
|
|
1530
1530
|
}
|
|
1531
|
+
if (!isLiClose(ctx, pos)) {
|
|
1532
|
+
ctx.diagnostics.push({
|
|
1533
|
+
severity: "warning",
|
|
1534
|
+
code: "unclosed-block",
|
|
1535
|
+
message: "Missing closing tag [[/li]] for [[li]]",
|
|
1536
|
+
position: ctx.tokens[startPos]?.position ?? {
|
|
1537
|
+
start: { line: 0, column: 0, offset: 0 },
|
|
1538
|
+
end: { line: 0, column: 0, offset: 0 }
|
|
1539
|
+
}
|
|
1540
|
+
});
|
|
1541
|
+
}
|
|
1531
1542
|
if (isLiClose(ctx, pos)) {
|
|
1532
1543
|
const closeConsumed = consumeCloseTag(ctx, pos);
|
|
1533
1544
|
consumed += closeConsumed;
|
|
@@ -1620,11 +1631,13 @@ function parseListBlock(ctx, startPos, listType) {
|
|
|
1620
1631
|
consumed++;
|
|
1621
1632
|
}
|
|
1622
1633
|
const items = [];
|
|
1634
|
+
let foundListClose = false;
|
|
1623
1635
|
while (pos < ctx.tokens.length) {
|
|
1624
1636
|
const token = ctx.tokens[pos];
|
|
1625
1637
|
if (!token || token.type === "EOF")
|
|
1626
1638
|
break;
|
|
1627
1639
|
if (isListClose(ctx, pos, listType)) {
|
|
1640
|
+
foundListClose = true;
|
|
1628
1641
|
const closeConsumed = consumeCloseTag(ctx, pos);
|
|
1629
1642
|
consumed += closeConsumed;
|
|
1630
1643
|
break;
|
|
@@ -1748,6 +1761,17 @@ function parseListBlock(ctx, startPos, listType) {
|
|
|
1748
1761
|
});
|
|
1749
1762
|
}
|
|
1750
1763
|
}
|
|
1764
|
+
if (!foundListClose) {
|
|
1765
|
+
ctx.diagnostics.push({
|
|
1766
|
+
severity: "warning",
|
|
1767
|
+
code: "unclosed-block",
|
|
1768
|
+
message: `Missing closing tag [[/${listType}]] for [[${listType}]]`,
|
|
1769
|
+
position: ctx.tokens[startPos]?.position ?? {
|
|
1770
|
+
start: { line: 0, column: 0, offset: 0 },
|
|
1771
|
+
end: { line: 0, column: 0, offset: 0 }
|
|
1772
|
+
}
|
|
1773
|
+
});
|
|
1774
|
+
}
|
|
1751
1775
|
const listData = {
|
|
1752
1776
|
type: listType === "ol" ? "numbered" : "bullet",
|
|
1753
1777
|
attributes: attrResult.attrs,
|
|
@@ -2183,8 +2207,19 @@ var divRule = {
|
|
|
2183
2207
|
if (ctx.tokens[pos]?.type !== "NEWLINE") {
|
|
2184
2208
|
return consumeFailedDiv(ctx);
|
|
2185
2209
|
}
|
|
2210
|
+
if (ctx.divClosesBudget === 0) {
|
|
2211
|
+
return { success: false };
|
|
2212
|
+
}
|
|
2186
2213
|
pos++;
|
|
2187
2214
|
consumed++;
|
|
2215
|
+
const openPosition = openToken.position;
|
|
2216
|
+
let bodyBudget;
|
|
2217
|
+
if (ctx.divClosesBudget !== undefined) {
|
|
2218
|
+
bodyBudget = ctx.divClosesBudget - 1;
|
|
2219
|
+
} else {
|
|
2220
|
+
const closesInScope = countDivCloses(ctx, pos);
|
|
2221
|
+
bodyBudget = closesInScope > 0 ? closesInScope - 1 : 0;
|
|
2222
|
+
}
|
|
2188
2223
|
const closeCondition = (checkCtx) => {
|
|
2189
2224
|
const token = checkCtx.tokens[checkCtx.pos];
|
|
2190
2225
|
if (token?.type === "BLOCK_END_OPEN") {
|
|
@@ -2195,7 +2230,7 @@ var divRule = {
|
|
|
2195
2230
|
}
|
|
2196
2231
|
return false;
|
|
2197
2232
|
};
|
|
2198
|
-
const bodyCtx = { ...ctx, pos };
|
|
2233
|
+
const bodyCtx = { ...ctx, pos, divClosesBudget: bodyBudget };
|
|
2199
2234
|
let children;
|
|
2200
2235
|
if (paragraphStrip) {
|
|
2201
2236
|
const bodyResult = parseBlocksUntil(bodyCtx, closeCondition);
|
|
@@ -2208,6 +2243,14 @@ var divRule = {
|
|
|
2208
2243
|
pos += bodyResult.consumed;
|
|
2209
2244
|
children = bodyResult.elements;
|
|
2210
2245
|
}
|
|
2246
|
+
if (ctx.tokens[pos]?.type !== "BLOCK_END_OPEN") {
|
|
2247
|
+
ctx.diagnostics.push({
|
|
2248
|
+
severity: "warning",
|
|
2249
|
+
code: "unclosed-block",
|
|
2250
|
+
message: `Missing closing tag [[/div]] for [[${blockName}]]`,
|
|
2251
|
+
position: openPosition
|
|
2252
|
+
});
|
|
2253
|
+
}
|
|
2211
2254
|
if (ctx.tokens[pos]?.type === "BLOCK_END_OPEN") {
|
|
2212
2255
|
pos++;
|
|
2213
2256
|
consumed++;
|
|
@@ -2241,6 +2284,21 @@ var divRule = {
|
|
|
2241
2284
|
};
|
|
2242
2285
|
}
|
|
2243
2286
|
};
|
|
2287
|
+
function countDivCloses(ctx, startPos) {
|
|
2288
|
+
let count = 0;
|
|
2289
|
+
for (let i = startPos;i < ctx.tokens.length; i++) {
|
|
2290
|
+
const t = ctx.tokens[i];
|
|
2291
|
+
if (!t || t.type === "EOF")
|
|
2292
|
+
break;
|
|
2293
|
+
if (t.type === "BLOCK_END_OPEN") {
|
|
2294
|
+
const nameResult = parseBlockName(ctx, i + 1);
|
|
2295
|
+
if (nameResult?.name === "div") {
|
|
2296
|
+
count++;
|
|
2297
|
+
}
|
|
2298
|
+
}
|
|
2299
|
+
}
|
|
2300
|
+
return count;
|
|
2301
|
+
}
|
|
2244
2302
|
function consumeFailedDiv(ctx) {
|
|
2245
2303
|
const elements = [];
|
|
2246
2304
|
let pos = ctx.pos;
|
|
@@ -2252,6 +2310,20 @@ function consumeFailedDiv(ctx) {
|
|
|
2252
2310
|
const t = ctx.tokens[scanPos];
|
|
2253
2311
|
if (!t || t.type === "EOF")
|
|
2254
2312
|
break;
|
|
2313
|
+
if (t.type === "BLOCK_OPEN" && t.lineStart && scanPos > pos) {
|
|
2314
|
+
const nameResult = parseBlockName(ctx, scanPos + 1);
|
|
2315
|
+
if (nameResult?.name === "div" || nameResult?.name === "div_") {
|
|
2316
|
+
let checkPos = scanPos + 1 + nameResult.consumed;
|
|
2317
|
+
const attrResult = parseAttributes(ctx, checkPos);
|
|
2318
|
+
checkPos += attrResult.consumed;
|
|
2319
|
+
if (ctx.tokens[checkPos]?.type === "BLOCK_CLOSE") {
|
|
2320
|
+
checkPos++;
|
|
2321
|
+
if (ctx.tokens[checkPos]?.type === "NEWLINE" || ctx.tokens[checkPos]?.type === "EOF") {
|
|
2322
|
+
break;
|
|
2323
|
+
}
|
|
2324
|
+
}
|
|
2325
|
+
}
|
|
2326
|
+
}
|
|
2255
2327
|
if (t.type === "BLOCK_END_OPEN") {
|
|
2256
2328
|
const nameResult = parseBlockName(ctx, scanPos + 1);
|
|
2257
2329
|
if (nameResult?.name === "div") {
|
|
@@ -2268,6 +2340,23 @@ function consumeFailedDiv(ctx) {
|
|
|
2268
2340
|
if (lastClosePos === -1) {
|
|
2269
2341
|
return { success: false };
|
|
2270
2342
|
}
|
|
2343
|
+
const endPosForDiag = lastClosePos;
|
|
2344
|
+
for (let diagPos = ctx.pos;diagPos < endPosForDiag; diagPos++) {
|
|
2345
|
+
const t = ctx.tokens[diagPos];
|
|
2346
|
+
if (t?.type === "BLOCK_OPEN") {
|
|
2347
|
+
const nameResult = parseBlockName(ctx, diagPos + 1);
|
|
2348
|
+
if (nameResult?.name === "div" || nameResult?.name === "div_") {
|
|
2349
|
+
if (t.position) {
|
|
2350
|
+
ctx.diagnostics.push({
|
|
2351
|
+
severity: "error",
|
|
2352
|
+
code: "inline-block-element",
|
|
2353
|
+
message: `[[${nameResult.name}]] must be followed by a newline to be a block element`,
|
|
2354
|
+
position: t.position
|
|
2355
|
+
});
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2358
|
+
}
|
|
2359
|
+
}
|
|
2271
2360
|
const endPos = lastClosePos + lastCloseConsumed;
|
|
2272
2361
|
while (pos < endPos && pos < ctx.tokens.length) {
|
|
2273
2362
|
const t = ctx.tokens[pos];
|
|
@@ -2384,6 +2473,7 @@ var codeBlockRule = {
|
|
|
2384
2473
|
consumed++;
|
|
2385
2474
|
}
|
|
2386
2475
|
let codeContent = "";
|
|
2476
|
+
let foundClose = closingSwallowed;
|
|
2387
2477
|
while (!closingSwallowed && pos < ctx.tokens.length) {
|
|
2388
2478
|
const token = ctx.tokens[pos];
|
|
2389
2479
|
if (!token || token.type === "EOF") {
|
|
@@ -2392,6 +2482,7 @@ var codeBlockRule = {
|
|
|
2392
2482
|
if (token.type === "BLOCK_END_OPEN") {
|
|
2393
2483
|
const closeNameResult = parseBlockName(ctx, pos + 1);
|
|
2394
2484
|
if (closeNameResult && closeNameResult.name === "code") {
|
|
2485
|
+
foundClose = true;
|
|
2395
2486
|
pos++;
|
|
2396
2487
|
consumed++;
|
|
2397
2488
|
pos += closeNameResult.consumed;
|
|
@@ -2411,6 +2502,14 @@ var codeBlockRule = {
|
|
|
2411
2502
|
pos++;
|
|
2412
2503
|
consumed++;
|
|
2413
2504
|
}
|
|
2505
|
+
if (!foundClose) {
|
|
2506
|
+
ctx.diagnostics.push({
|
|
2507
|
+
severity: "warning",
|
|
2508
|
+
code: "unclosed-block",
|
|
2509
|
+
message: "Missing closing tag [[/code]] for [[code]]",
|
|
2510
|
+
position: openToken.position
|
|
2511
|
+
});
|
|
2512
|
+
}
|
|
2414
2513
|
codeContent = codeContent.replace(/\n$/, "");
|
|
2415
2514
|
const codeBlockData = {
|
|
2416
2515
|
contents: codeContent,
|
|
@@ -2569,6 +2668,7 @@ var collapsibleRule = {
|
|
|
2569
2668
|
}
|
|
2570
2669
|
pos++;
|
|
2571
2670
|
consumed++;
|
|
2671
|
+
const openPosition = openToken.position;
|
|
2572
2672
|
const hasNewlineAfterOpen = ctx.tokens[pos]?.type === "NEWLINE";
|
|
2573
2673
|
if (hasNewlineAfterOpen) {
|
|
2574
2674
|
pos++;
|
|
@@ -2619,6 +2719,14 @@ var collapsibleRule = {
|
|
|
2619
2719
|
pos += bodyResult.consumed;
|
|
2620
2720
|
bodyElements = mergeParagraphs(bodyResult.elements);
|
|
2621
2721
|
}
|
|
2722
|
+
if (!isCollapsibleClose(ctx, pos)) {
|
|
2723
|
+
ctx.diagnostics.push({
|
|
2724
|
+
severity: "warning",
|
|
2725
|
+
code: "unclosed-block",
|
|
2726
|
+
message: "Missing closing tag [[/collapsible]] for [[collapsible]]",
|
|
2727
|
+
position: openPosition
|
|
2728
|
+
});
|
|
2729
|
+
}
|
|
2622
2730
|
if (isCollapsibleClose(ctx, pos)) {
|
|
2623
2731
|
const closeConsumed = consumeCloseTag2(ctx, pos);
|
|
2624
2732
|
consumed += closeConsumed;
|
|
@@ -2947,6 +3055,7 @@ var tableBlockRule = {
|
|
|
2947
3055
|
consumed++;
|
|
2948
3056
|
}
|
|
2949
3057
|
const rows = [];
|
|
3058
|
+
let foundTableClose = false;
|
|
2950
3059
|
while (pos < ctx.tokens.length) {
|
|
2951
3060
|
while (ctx.tokens[pos]?.type === "WHITESPACE" || ctx.tokens[pos]?.type === "NEWLINE") {
|
|
2952
3061
|
pos++;
|
|
@@ -2959,6 +3068,7 @@ var tableBlockRule = {
|
|
|
2959
3068
|
if (token.type === "BLOCK_END_OPEN") {
|
|
2960
3069
|
const closeNameResult = parseBlockName(ctx, pos + 1);
|
|
2961
3070
|
if (closeNameResult?.name === "table") {
|
|
3071
|
+
foundTableClose = true;
|
|
2962
3072
|
pos++;
|
|
2963
3073
|
consumed++;
|
|
2964
3074
|
pos += closeNameResult.consumed;
|
|
@@ -2989,6 +3099,14 @@ var tableBlockRule = {
|
|
|
2989
3099
|
pos++;
|
|
2990
3100
|
consumed++;
|
|
2991
3101
|
}
|
|
3102
|
+
if (!foundTableClose) {
|
|
3103
|
+
ctx.diagnostics.push({
|
|
3104
|
+
severity: "warning",
|
|
3105
|
+
code: "unclosed-block",
|
|
3106
|
+
message: "Missing closing tag [[/table]] for [[table]]",
|
|
3107
|
+
position: openToken.position
|
|
3108
|
+
});
|
|
3109
|
+
}
|
|
2992
3110
|
const hasValidContent = rows.some((row) => row.cells.length > 0);
|
|
2993
3111
|
if (!hasValidContent) {
|
|
2994
3112
|
return { success: false };
|
|
@@ -3036,6 +3154,7 @@ function parseRow(ctx, startPos) {
|
|
|
3036
3154
|
consumed++;
|
|
3037
3155
|
}
|
|
3038
3156
|
const cells = [];
|
|
3157
|
+
let foundRowClose = false;
|
|
3039
3158
|
while (pos < ctx.tokens.length) {
|
|
3040
3159
|
while (ctx.tokens[pos]?.type === "WHITESPACE" || ctx.tokens[pos]?.type === "NEWLINE") {
|
|
3041
3160
|
pos++;
|
|
@@ -3048,6 +3167,7 @@ function parseRow(ctx, startPos) {
|
|
|
3048
3167
|
if (token.type === "BLOCK_END_OPEN") {
|
|
3049
3168
|
const closeNameResult = parseBlockName(ctx, pos + 1);
|
|
3050
3169
|
if (closeNameResult?.name === "row") {
|
|
3170
|
+
foundRowClose = true;
|
|
3051
3171
|
pos++;
|
|
3052
3172
|
consumed++;
|
|
3053
3173
|
pos += closeNameResult.consumed;
|
|
@@ -3078,6 +3198,17 @@ function parseRow(ctx, startPos) {
|
|
|
3078
3198
|
pos++;
|
|
3079
3199
|
consumed++;
|
|
3080
3200
|
}
|
|
3201
|
+
if (!foundRowClose) {
|
|
3202
|
+
ctx.diagnostics.push({
|
|
3203
|
+
severity: "warning",
|
|
3204
|
+
code: "unclosed-block",
|
|
3205
|
+
message: "Missing closing tag [[/row]] for [[row]]",
|
|
3206
|
+
position: ctx.tokens[startPos]?.position ?? {
|
|
3207
|
+
start: { line: 0, column: 0, offset: 0 },
|
|
3208
|
+
end: { line: 0, column: 0, offset: 0 }
|
|
3209
|
+
}
|
|
3210
|
+
});
|
|
3211
|
+
}
|
|
3081
3212
|
return {
|
|
3082
3213
|
row: {
|
|
3083
3214
|
attributes: attrResult.attrs,
|
|
@@ -3140,6 +3271,17 @@ function parseCell(ctx, startPos) {
|
|
|
3140
3271
|
consumed += bodyResult.consumed;
|
|
3141
3272
|
pos += bodyResult.consumed;
|
|
3142
3273
|
const hadParagraphBreaks = bodyResult.hadParagraphBreaks;
|
|
3274
|
+
if (ctx.tokens[pos]?.type !== "BLOCK_END_OPEN") {
|
|
3275
|
+
ctx.diagnostics.push({
|
|
3276
|
+
severity: "warning",
|
|
3277
|
+
code: "unclosed-block",
|
|
3278
|
+
message: `Missing closing tag [[/${closeName}]] for [[${closeName}]]`,
|
|
3279
|
+
position: ctx.tokens[startPos]?.position ?? {
|
|
3280
|
+
start: { line: 0, column: 0, offset: 0 },
|
|
3281
|
+
end: { line: 0, column: 0, offset: 0 }
|
|
3282
|
+
}
|
|
3283
|
+
});
|
|
3284
|
+
}
|
|
3143
3285
|
if (ctx.tokens[pos]?.type === "BLOCK_END_OPEN") {
|
|
3144
3286
|
pos++;
|
|
3145
3287
|
consumed++;
|
|
@@ -3597,6 +3739,7 @@ var moduleRule = {
|
|
|
3597
3739
|
pos++;
|
|
3598
3740
|
consumed++;
|
|
3599
3741
|
let bodyContent = "";
|
|
3742
|
+
let foundClose = false;
|
|
3600
3743
|
while (pos < ctx.tokens.length) {
|
|
3601
3744
|
const token = ctx.tokens[pos];
|
|
3602
3745
|
if (!token || token.type === "EOF") {
|
|
@@ -3605,6 +3748,7 @@ var moduleRule = {
|
|
|
3605
3748
|
if (token.type === "BLOCK_END_OPEN") {
|
|
3606
3749
|
const closeNameResult = parseBlockName(ctx, pos + 1);
|
|
3607
3750
|
if (closeNameResult && (closeNameResult.name === "module" || closeNameResult.name === "module654")) {
|
|
3751
|
+
foundClose = true;
|
|
3608
3752
|
pos++;
|
|
3609
3753
|
consumed++;
|
|
3610
3754
|
pos += closeNameResult.consumed;
|
|
@@ -3624,6 +3768,14 @@ var moduleRule = {
|
|
|
3624
3768
|
pos++;
|
|
3625
3769
|
consumed++;
|
|
3626
3770
|
}
|
|
3771
|
+
if (!foundClose) {
|
|
3772
|
+
ctx.diagnostics.push({
|
|
3773
|
+
severity: "warning",
|
|
3774
|
+
code: "unclosed-block",
|
|
3775
|
+
message: "Missing closing tag [[/module]] for [[module]]",
|
|
3776
|
+
position: openToken.position
|
|
3777
|
+
});
|
|
3778
|
+
}
|
|
3627
3779
|
if (bodyContent.trim()) {
|
|
3628
3780
|
body = bodyContent.trim();
|
|
3629
3781
|
}
|
|
@@ -4017,7 +4169,16 @@ var alignRule = {
|
|
|
4017
4169
|
const bodyResult = parseBlocksUntil(bodyCtx, closeCondition);
|
|
4018
4170
|
consumed += bodyResult.consumed;
|
|
4019
4171
|
pos += bodyResult.consumed;
|
|
4172
|
+
const directionSymbol = { left: "<", right: ">", center: "=", justify: "==" }[direction];
|
|
4020
4173
|
const closeCheck = isAlignClose({ ...ctx, pos }, direction);
|
|
4174
|
+
if (!closeCheck.match) {
|
|
4175
|
+
ctx.diagnostics.push({
|
|
4176
|
+
severity: "warning",
|
|
4177
|
+
code: "unclosed-block",
|
|
4178
|
+
message: `Missing closing tag [[/${directionSymbol}]] for [[${directionSymbol}]]`,
|
|
4179
|
+
position: openToken.position
|
|
4180
|
+
});
|
|
4181
|
+
}
|
|
4021
4182
|
if (closeCheck.match) {
|
|
4022
4183
|
consumed += closeCheck.consumed;
|
|
4023
4184
|
pos += closeCheck.consumed;
|
|
@@ -4105,6 +4266,17 @@ function parseTab(ctx) {
|
|
|
4105
4266
|
const bodyResult = parseBlocksUntil(bodyCtx, closeCondition);
|
|
4106
4267
|
consumed += bodyResult.consumed;
|
|
4107
4268
|
pos += bodyResult.consumed;
|
|
4269
|
+
if (ctx.tokens[pos]?.type !== "BLOCK_END_OPEN") {
|
|
4270
|
+
ctx.diagnostics.push({
|
|
4271
|
+
severity: "warning",
|
|
4272
|
+
code: "unclosed-block",
|
|
4273
|
+
message: "Missing closing tag [[/tab]] for [[tab]]",
|
|
4274
|
+
position: ctx.tokens[ctx.pos]?.position ?? {
|
|
4275
|
+
start: { line: 0, column: 0, offset: 0 },
|
|
4276
|
+
end: { line: 0, column: 0, offset: 0 }
|
|
4277
|
+
}
|
|
4278
|
+
});
|
|
4279
|
+
}
|
|
4108
4280
|
if (ctx.tokens[pos]?.type === "BLOCK_END_OPEN") {
|
|
4109
4281
|
pos++;
|
|
4110
4282
|
consumed++;
|
|
@@ -4168,6 +4340,9 @@ var tabviewRule = {
|
|
|
4168
4340
|
const tabs = [];
|
|
4169
4341
|
const tabCtx = { ...ctx, pos };
|
|
4170
4342
|
while (pos < ctx.tokens.length) {
|
|
4343
|
+
if (ctx.tokens[pos]?.type === "EOF") {
|
|
4344
|
+
break;
|
|
4345
|
+
}
|
|
4171
4346
|
if (ctx.tokens[pos]?.type === "BLOCK_END_OPEN") {
|
|
4172
4347
|
const closeNameResult = parseBlockName(ctx, pos + 1);
|
|
4173
4348
|
const closeName = closeNameResult?.name.toLowerCase();
|
|
@@ -4189,6 +4364,19 @@ var tabviewRule = {
|
|
|
4189
4364
|
}
|
|
4190
4365
|
}
|
|
4191
4366
|
}
|
|
4367
|
+
const hasTabviewClose = ctx.tokens[pos]?.type === "BLOCK_END_OPEN" && (() => {
|
|
4368
|
+
const n = parseBlockName(ctx, pos + 1);
|
|
4369
|
+
const name = n?.name.toLowerCase();
|
|
4370
|
+
return name === "tabview" || name === "tabs";
|
|
4371
|
+
})();
|
|
4372
|
+
if (!hasTabviewClose) {
|
|
4373
|
+
ctx.diagnostics.push({
|
|
4374
|
+
severity: "warning",
|
|
4375
|
+
code: "unclosed-block",
|
|
4376
|
+
message: `Missing closing tag [[/${blockName}]] for [[${blockName}]]`,
|
|
4377
|
+
position: openToken.position
|
|
4378
|
+
});
|
|
4379
|
+
}
|
|
4192
4380
|
if (ctx.tokens[pos]?.type === "BLOCK_END_OPEN") {
|
|
4193
4381
|
pos++;
|
|
4194
4382
|
consumed++;
|
|
@@ -4427,6 +4615,14 @@ var mathBlockRule = {
|
|
|
4427
4615
|
pos++;
|
|
4428
4616
|
consumed++;
|
|
4429
4617
|
}
|
|
4618
|
+
if (ctx.tokens[pos]?.type !== "BLOCK_END_OPEN") {
|
|
4619
|
+
ctx.diagnostics.push({
|
|
4620
|
+
severity: "warning",
|
|
4621
|
+
code: "unclosed-block",
|
|
4622
|
+
message: "Missing closing tag [[/math]] for [[math]]",
|
|
4623
|
+
position: openToken.position
|
|
4624
|
+
});
|
|
4625
|
+
}
|
|
4430
4626
|
if (ctx.tokens[pos]?.type === "BLOCK_END_OPEN") {
|
|
4431
4627
|
pos++;
|
|
4432
4628
|
consumed++;
|
|
@@ -4509,6 +4705,12 @@ var htmlBlockRule = {
|
|
|
4509
4705
|
consumed++;
|
|
4510
4706
|
}
|
|
4511
4707
|
if (!foundClose) {
|
|
4708
|
+
ctx.diagnostics.push({
|
|
4709
|
+
severity: "warning",
|
|
4710
|
+
code: "unclosed-block",
|
|
4711
|
+
message: "Missing closing tag [[/html]] for [[html]]",
|
|
4712
|
+
position: openToken.position
|
|
4713
|
+
});
|
|
4512
4714
|
return { success: false };
|
|
4513
4715
|
}
|
|
4514
4716
|
if (ctx.tokens[pos]?.type === "BLOCK_END_OPEN") {
|
|
@@ -4598,6 +4800,12 @@ var embedBlockRule = {
|
|
|
4598
4800
|
consumed++;
|
|
4599
4801
|
}
|
|
4600
4802
|
if (!foundClose) {
|
|
4803
|
+
ctx.diagnostics.push({
|
|
4804
|
+
severity: "warning",
|
|
4805
|
+
code: "unclosed-block",
|
|
4806
|
+
message: `Missing closing tag [[/${blockName}]] for [[${blockName}]]`,
|
|
4807
|
+
position: openToken.position
|
|
4808
|
+
});
|
|
4601
4809
|
return { success: false };
|
|
4602
4810
|
}
|
|
4603
4811
|
if (ctx.tokens[pos]?.type === "BLOCK_END_OPEN") {
|
|
@@ -4827,6 +5035,14 @@ var iftagsRule = {
|
|
|
4827
5035
|
const bodyResult = parseBlocksUntil(bodyCtx, closeCondition);
|
|
4828
5036
|
consumed += bodyResult.consumed;
|
|
4829
5037
|
pos += bodyResult.consumed;
|
|
5038
|
+
if (ctx.tokens[pos]?.type !== "BLOCK_END_OPEN") {
|
|
5039
|
+
ctx.diagnostics.push({
|
|
5040
|
+
severity: "warning",
|
|
5041
|
+
code: "unclosed-block",
|
|
5042
|
+
message: "Missing closing tag [[/iftags]] for [[iftags]]",
|
|
5043
|
+
position: openToken.position
|
|
5044
|
+
});
|
|
5045
|
+
}
|
|
4830
5046
|
if (ctx.tokens[pos]?.type === "BLOCK_END_OPEN") {
|
|
4831
5047
|
pos++;
|
|
4832
5048
|
consumed++;
|
|
@@ -5030,6 +5246,12 @@ var orphanLiRule = {
|
|
|
5030
5246
|
consumed++;
|
|
5031
5247
|
}
|
|
5032
5248
|
if (!foundClose) {
|
|
5249
|
+
ctx.diagnostics.push({
|
|
5250
|
+
severity: "warning",
|
|
5251
|
+
code: "unclosed-block",
|
|
5252
|
+
message: "Missing closing tag [[/li]] for [[li]]",
|
|
5253
|
+
position: openToken.position
|
|
5254
|
+
});
|
|
5033
5255
|
return { success: false };
|
|
5034
5256
|
}
|
|
5035
5257
|
return {
|
|
@@ -5220,6 +5442,12 @@ var bibliographyRule = {
|
|
|
5220
5442
|
consumed++;
|
|
5221
5443
|
}
|
|
5222
5444
|
if (!foundClose) {
|
|
5445
|
+
ctx.diagnostics.push({
|
|
5446
|
+
severity: "warning",
|
|
5447
|
+
code: "unclosed-block",
|
|
5448
|
+
message: "Missing closing tag [[/bibliography]] for [[bibliography]]",
|
|
5449
|
+
position: openToken.position
|
|
5450
|
+
});
|
|
5223
5451
|
return { success: false };
|
|
5224
5452
|
}
|
|
5225
5453
|
const definitionItems = entries.map((entry) => ({
|
|
@@ -6141,6 +6369,7 @@ var commentRule = {
|
|
|
6141
6369
|
name: "comment",
|
|
6142
6370
|
startTokens: ["COMMENT_OPEN"],
|
|
6143
6371
|
parse(ctx) {
|
|
6372
|
+
const openToken = currentToken(ctx);
|
|
6144
6373
|
let pos = ctx.pos + 1;
|
|
6145
6374
|
let consumed = 1;
|
|
6146
6375
|
while (pos < ctx.tokens.length) {
|
|
@@ -6158,11 +6387,23 @@ var commentRule = {
|
|
|
6158
6387
|
};
|
|
6159
6388
|
}
|
|
6160
6389
|
if (token.type === "EOF") {
|
|
6390
|
+
ctx.diagnostics.push({
|
|
6391
|
+
severity: "warning",
|
|
6392
|
+
code: "unclosed-comment",
|
|
6393
|
+
message: "Unterminated comment: missing closing --]",
|
|
6394
|
+
position: openToken.position
|
|
6395
|
+
});
|
|
6161
6396
|
return { success: false };
|
|
6162
6397
|
}
|
|
6163
6398
|
pos++;
|
|
6164
6399
|
consumed++;
|
|
6165
6400
|
}
|
|
6401
|
+
ctx.diagnostics.push({
|
|
6402
|
+
severity: "warning",
|
|
6403
|
+
code: "unclosed-comment",
|
|
6404
|
+
message: "Unterminated comment: missing closing --]",
|
|
6405
|
+
position: openToken.position
|
|
6406
|
+
});
|
|
6166
6407
|
return { success: false };
|
|
6167
6408
|
}
|
|
6168
6409
|
};
|
|
@@ -6420,6 +6661,12 @@ var spanRule = {
|
|
|
6420
6661
|
}
|
|
6421
6662
|
}
|
|
6422
6663
|
if (!foundClose) {
|
|
6664
|
+
ctx.diagnostics.push({
|
|
6665
|
+
severity: "warning",
|
|
6666
|
+
code: "unclosed-block",
|
|
6667
|
+
message: `Missing closing tag [[/span]] for [[${blockName}]]`,
|
|
6668
|
+
position: openToken.position
|
|
6669
|
+
});
|
|
6423
6670
|
return { success: false };
|
|
6424
6671
|
}
|
|
6425
6672
|
if (paragraphStrip) {
|
|
@@ -6620,6 +6867,7 @@ var sizeRule = {
|
|
|
6620
6867
|
pos++;
|
|
6621
6868
|
consumed++;
|
|
6622
6869
|
const children = [];
|
|
6870
|
+
let foundClose = false;
|
|
6623
6871
|
while (pos < ctx.tokens.length) {
|
|
6624
6872
|
const token = ctx.tokens[pos];
|
|
6625
6873
|
if (!token || token.type === "EOF") {
|
|
@@ -6628,6 +6876,7 @@ var sizeRule = {
|
|
|
6628
6876
|
if (token.type === "BLOCK_END_OPEN") {
|
|
6629
6877
|
const closeNameResult = parseBlockName(ctx, pos + 1);
|
|
6630
6878
|
if (closeNameResult && closeNameResult.name === "size") {
|
|
6879
|
+
foundClose = true;
|
|
6631
6880
|
pos++;
|
|
6632
6881
|
consumed++;
|
|
6633
6882
|
pos += closeNameResult.consumed;
|
|
@@ -6651,6 +6900,14 @@ var sizeRule = {
|
|
|
6651
6900
|
consumed++;
|
|
6652
6901
|
}
|
|
6653
6902
|
}
|
|
6903
|
+
if (!foundClose) {
|
|
6904
|
+
ctx.diagnostics.push({
|
|
6905
|
+
severity: "warning",
|
|
6906
|
+
code: "unclosed-block",
|
|
6907
|
+
message: "Missing closing tag [[/size]] for [[size]]",
|
|
6908
|
+
position: openToken.position
|
|
6909
|
+
});
|
|
6910
|
+
}
|
|
6654
6911
|
return {
|
|
6655
6912
|
success: true,
|
|
6656
6913
|
elements: [
|
|
@@ -6700,6 +6957,7 @@ var footnoteRule = {
|
|
|
6700
6957
|
consumed++;
|
|
6701
6958
|
const paragraphs = [[]];
|
|
6702
6959
|
let currentParagraph = 0;
|
|
6960
|
+
let foundClose = false;
|
|
6703
6961
|
while (pos < ctx.tokens.length) {
|
|
6704
6962
|
const token = ctx.tokens[pos];
|
|
6705
6963
|
if (!token || token.type === "EOF") {
|
|
@@ -6708,6 +6966,7 @@ var footnoteRule = {
|
|
|
6708
6966
|
if (token.type === "BLOCK_END_OPEN") {
|
|
6709
6967
|
const closeNameResult = parseBlockName(ctx, pos + 1);
|
|
6710
6968
|
if (closeNameResult && closeNameResult.name === "footnote") {
|
|
6969
|
+
foundClose = true;
|
|
6711
6970
|
pos++;
|
|
6712
6971
|
consumed++;
|
|
6713
6972
|
pos += closeNameResult.consumed;
|
|
@@ -6784,6 +7043,14 @@ var footnoteRule = {
|
|
|
6784
7043
|
});
|
|
6785
7044
|
}
|
|
6786
7045
|
}
|
|
7046
|
+
if (!foundClose) {
|
|
7047
|
+
ctx.diagnostics.push({
|
|
7048
|
+
severity: "warning",
|
|
7049
|
+
code: "unclosed-block",
|
|
7050
|
+
message: "Missing closing tag [[/footnote]] for [[footnote]]",
|
|
7051
|
+
position: openToken.position
|
|
7052
|
+
});
|
|
7053
|
+
}
|
|
6787
7054
|
ctx.footnotes.push(children);
|
|
6788
7055
|
return {
|
|
6789
7056
|
success: true,
|
|
@@ -7279,6 +7546,12 @@ var anchorRule = {
|
|
|
7279
7546
|
}
|
|
7280
7547
|
}
|
|
7281
7548
|
if (!foundClose) {
|
|
7549
|
+
ctx.diagnostics.push({
|
|
7550
|
+
severity: "warning",
|
|
7551
|
+
code: "unclosed-block",
|
|
7552
|
+
message: `Missing closing tag [[/a]] for [[${nameResult.name}]]`,
|
|
7553
|
+
position: openToken.position
|
|
7554
|
+
});
|
|
7282
7555
|
return { success: false };
|
|
7283
7556
|
}
|
|
7284
7557
|
if (paragraphStrip) {
|
|
@@ -8257,6 +8530,50 @@ function cleanElement(el) {
|
|
|
8257
8530
|
}
|
|
8258
8531
|
return el;
|
|
8259
8532
|
}
|
|
8533
|
+
// packages/parser/src/parser/postprocess/divAdjacentParagraph.ts
|
|
8534
|
+
function isParagraphContainer2(el) {
|
|
8535
|
+
if (!el || el.element !== "container")
|
|
8536
|
+
return false;
|
|
8537
|
+
return el.data.type === "paragraph";
|
|
8538
|
+
}
|
|
8539
|
+
function isDivContainer(el) {
|
|
8540
|
+
if (!el || el.element !== "container")
|
|
8541
|
+
return false;
|
|
8542
|
+
return el.data.type === "div";
|
|
8543
|
+
}
|
|
8544
|
+
function suppressAtLevel(elements) {
|
|
8545
|
+
if (elements.length <= 1)
|
|
8546
|
+
return elements;
|
|
8547
|
+
const unwrap = new Array(elements.length).fill(false);
|
|
8548
|
+
for (let i = 0;i < elements.length; i++) {
|
|
8549
|
+
if (!isParagraphContainer2(elements[i]))
|
|
8550
|
+
continue;
|
|
8551
|
+
const prevIsDiv = i > 0 && isDivContainer(elements[i - 1]);
|
|
8552
|
+
const nextIsDiv = i < elements.length - 1 && isDivContainer(elements[i + 1]);
|
|
8553
|
+
if (prevIsDiv || nextIsDiv) {
|
|
8554
|
+
unwrap[i] = true;
|
|
8555
|
+
}
|
|
8556
|
+
}
|
|
8557
|
+
const result = [];
|
|
8558
|
+
for (let i = 0;i < elements.length; i++) {
|
|
8559
|
+
const el = elements[i];
|
|
8560
|
+
if (!el)
|
|
8561
|
+
continue;
|
|
8562
|
+
if (unwrap[i] && el.element === "container") {
|
|
8563
|
+
const inner = el.data.elements;
|
|
8564
|
+
if (i > 0 && isDivContainer(elements[i - 1])) {
|
|
8565
|
+
result.push({ element: "line-break" });
|
|
8566
|
+
}
|
|
8567
|
+
result.push(...inner);
|
|
8568
|
+
} else {
|
|
8569
|
+
result.push(el);
|
|
8570
|
+
}
|
|
8571
|
+
}
|
|
8572
|
+
return result;
|
|
8573
|
+
}
|
|
8574
|
+
function suppressDivAdjacentParagraphs(elements) {
|
|
8575
|
+
return suppressAtLevel(elements);
|
|
8576
|
+
}
|
|
8260
8577
|
// packages/parser/src/parser/toc.ts
|
|
8261
8578
|
class TocIndexer {
|
|
8262
8579
|
index = 0;
|
|
@@ -8334,6 +8651,7 @@ class Parser {
|
|
|
8334
8651
|
htmlBlocks: [],
|
|
8335
8652
|
footnoteBlockParsed: false,
|
|
8336
8653
|
bibcites: [],
|
|
8654
|
+
diagnostics: [],
|
|
8337
8655
|
blockRules,
|
|
8338
8656
|
blockFallbackRule: paragraphRule,
|
|
8339
8657
|
inlineRules
|
|
@@ -8346,7 +8664,8 @@ class Parser {
|
|
|
8346
8664
|
children.push(...blocks);
|
|
8347
8665
|
}
|
|
8348
8666
|
const mergedChildren = mergeSpanStripParagraphs(children);
|
|
8349
|
-
const
|
|
8667
|
+
const divProcessed = suppressDivAdjacentParagraphs(mergedChildren);
|
|
8668
|
+
const cleanedChildren = cleanInternalFlags(divProcessed);
|
|
8350
8669
|
const hasFootnoteBlock = cleanedChildren.some((el) => el.element === "footnote-block");
|
|
8351
8670
|
if (!hasFootnoteBlock) {
|
|
8352
8671
|
cleanedChildren.push({
|
|
@@ -8370,7 +8689,7 @@ class Parser {
|
|
|
8370
8689
|
if (this.ctx.htmlBlocks.length > 0) {
|
|
8371
8690
|
result["html-blocks"] = this.ctx.htmlBlocks;
|
|
8372
8691
|
}
|
|
8373
|
-
return result;
|
|
8692
|
+
return { ast: result, diagnostics: this.ctx.diagnostics };
|
|
8374
8693
|
}
|
|
8375
8694
|
isAtEnd() {
|
|
8376
8695
|
return this.ctx.pos >= this.ctx.tokens.length || this.currentToken().type === "EOF";
|