@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/dist/index.js
CHANGED
|
@@ -1473,6 +1473,17 @@ function parseLiItem(ctx, startPos, listType) {
|
|
|
1473
1473
|
pos++;
|
|
1474
1474
|
}
|
|
1475
1475
|
}
|
|
1476
|
+
if (!isLiClose(ctx, pos)) {
|
|
1477
|
+
ctx.diagnostics.push({
|
|
1478
|
+
severity: "warning",
|
|
1479
|
+
code: "unclosed-block",
|
|
1480
|
+
message: "Missing closing tag [[/li]] for [[li]]",
|
|
1481
|
+
position: ctx.tokens[startPos]?.position ?? {
|
|
1482
|
+
start: { line: 0, column: 0, offset: 0 },
|
|
1483
|
+
end: { line: 0, column: 0, offset: 0 }
|
|
1484
|
+
}
|
|
1485
|
+
});
|
|
1486
|
+
}
|
|
1476
1487
|
if (isLiClose(ctx, pos)) {
|
|
1477
1488
|
const closeConsumed = consumeCloseTag(ctx, pos);
|
|
1478
1489
|
consumed += closeConsumed;
|
|
@@ -1565,11 +1576,13 @@ function parseListBlock(ctx, startPos, listType) {
|
|
|
1565
1576
|
consumed++;
|
|
1566
1577
|
}
|
|
1567
1578
|
const items = [];
|
|
1579
|
+
let foundListClose = false;
|
|
1568
1580
|
while (pos < ctx.tokens.length) {
|
|
1569
1581
|
const token = ctx.tokens[pos];
|
|
1570
1582
|
if (!token || token.type === "EOF")
|
|
1571
1583
|
break;
|
|
1572
1584
|
if (isListClose(ctx, pos, listType)) {
|
|
1585
|
+
foundListClose = true;
|
|
1573
1586
|
const closeConsumed = consumeCloseTag(ctx, pos);
|
|
1574
1587
|
consumed += closeConsumed;
|
|
1575
1588
|
break;
|
|
@@ -1693,6 +1706,17 @@ function parseListBlock(ctx, startPos, listType) {
|
|
|
1693
1706
|
});
|
|
1694
1707
|
}
|
|
1695
1708
|
}
|
|
1709
|
+
if (!foundListClose) {
|
|
1710
|
+
ctx.diagnostics.push({
|
|
1711
|
+
severity: "warning",
|
|
1712
|
+
code: "unclosed-block",
|
|
1713
|
+
message: `Missing closing tag [[/${listType}]] for [[${listType}]]`,
|
|
1714
|
+
position: ctx.tokens[startPos]?.position ?? {
|
|
1715
|
+
start: { line: 0, column: 0, offset: 0 },
|
|
1716
|
+
end: { line: 0, column: 0, offset: 0 }
|
|
1717
|
+
}
|
|
1718
|
+
});
|
|
1719
|
+
}
|
|
1696
1720
|
const listData = {
|
|
1697
1721
|
type: listType === "ol" ? "numbered" : "bullet",
|
|
1698
1722
|
attributes: attrResult.attrs,
|
|
@@ -2128,8 +2152,19 @@ var divRule = {
|
|
|
2128
2152
|
if (ctx.tokens[pos]?.type !== "NEWLINE") {
|
|
2129
2153
|
return consumeFailedDiv(ctx);
|
|
2130
2154
|
}
|
|
2155
|
+
if (ctx.divClosesBudget === 0) {
|
|
2156
|
+
return { success: false };
|
|
2157
|
+
}
|
|
2131
2158
|
pos++;
|
|
2132
2159
|
consumed++;
|
|
2160
|
+
const openPosition = openToken.position;
|
|
2161
|
+
let bodyBudget;
|
|
2162
|
+
if (ctx.divClosesBudget !== undefined) {
|
|
2163
|
+
bodyBudget = ctx.divClosesBudget - 1;
|
|
2164
|
+
} else {
|
|
2165
|
+
const closesInScope = countDivCloses(ctx, pos);
|
|
2166
|
+
bodyBudget = closesInScope > 0 ? closesInScope - 1 : 0;
|
|
2167
|
+
}
|
|
2133
2168
|
const closeCondition = (checkCtx) => {
|
|
2134
2169
|
const token = checkCtx.tokens[checkCtx.pos];
|
|
2135
2170
|
if (token?.type === "BLOCK_END_OPEN") {
|
|
@@ -2140,7 +2175,7 @@ var divRule = {
|
|
|
2140
2175
|
}
|
|
2141
2176
|
return false;
|
|
2142
2177
|
};
|
|
2143
|
-
const bodyCtx = { ...ctx, pos };
|
|
2178
|
+
const bodyCtx = { ...ctx, pos, divClosesBudget: bodyBudget };
|
|
2144
2179
|
let children;
|
|
2145
2180
|
if (paragraphStrip) {
|
|
2146
2181
|
const bodyResult = parseBlocksUntil(bodyCtx, closeCondition);
|
|
@@ -2153,6 +2188,14 @@ var divRule = {
|
|
|
2153
2188
|
pos += bodyResult.consumed;
|
|
2154
2189
|
children = bodyResult.elements;
|
|
2155
2190
|
}
|
|
2191
|
+
if (ctx.tokens[pos]?.type !== "BLOCK_END_OPEN") {
|
|
2192
|
+
ctx.diagnostics.push({
|
|
2193
|
+
severity: "warning",
|
|
2194
|
+
code: "unclosed-block",
|
|
2195
|
+
message: `Missing closing tag [[/div]] for [[${blockName}]]`,
|
|
2196
|
+
position: openPosition
|
|
2197
|
+
});
|
|
2198
|
+
}
|
|
2156
2199
|
if (ctx.tokens[pos]?.type === "BLOCK_END_OPEN") {
|
|
2157
2200
|
pos++;
|
|
2158
2201
|
consumed++;
|
|
@@ -2186,6 +2229,21 @@ var divRule = {
|
|
|
2186
2229
|
};
|
|
2187
2230
|
}
|
|
2188
2231
|
};
|
|
2232
|
+
function countDivCloses(ctx, startPos) {
|
|
2233
|
+
let count = 0;
|
|
2234
|
+
for (let i = startPos;i < ctx.tokens.length; i++) {
|
|
2235
|
+
const t = ctx.tokens[i];
|
|
2236
|
+
if (!t || t.type === "EOF")
|
|
2237
|
+
break;
|
|
2238
|
+
if (t.type === "BLOCK_END_OPEN") {
|
|
2239
|
+
const nameResult = parseBlockName(ctx, i + 1);
|
|
2240
|
+
if (nameResult?.name === "div") {
|
|
2241
|
+
count++;
|
|
2242
|
+
}
|
|
2243
|
+
}
|
|
2244
|
+
}
|
|
2245
|
+
return count;
|
|
2246
|
+
}
|
|
2189
2247
|
function consumeFailedDiv(ctx) {
|
|
2190
2248
|
const elements = [];
|
|
2191
2249
|
let pos = ctx.pos;
|
|
@@ -2197,6 +2255,20 @@ function consumeFailedDiv(ctx) {
|
|
|
2197
2255
|
const t = ctx.tokens[scanPos];
|
|
2198
2256
|
if (!t || t.type === "EOF")
|
|
2199
2257
|
break;
|
|
2258
|
+
if (t.type === "BLOCK_OPEN" && t.lineStart && scanPos > pos) {
|
|
2259
|
+
const nameResult = parseBlockName(ctx, scanPos + 1);
|
|
2260
|
+
if (nameResult?.name === "div" || nameResult?.name === "div_") {
|
|
2261
|
+
let checkPos = scanPos + 1 + nameResult.consumed;
|
|
2262
|
+
const attrResult = parseAttributes(ctx, checkPos);
|
|
2263
|
+
checkPos += attrResult.consumed;
|
|
2264
|
+
if (ctx.tokens[checkPos]?.type === "BLOCK_CLOSE") {
|
|
2265
|
+
checkPos++;
|
|
2266
|
+
if (ctx.tokens[checkPos]?.type === "NEWLINE" || ctx.tokens[checkPos]?.type === "EOF") {
|
|
2267
|
+
break;
|
|
2268
|
+
}
|
|
2269
|
+
}
|
|
2270
|
+
}
|
|
2271
|
+
}
|
|
2200
2272
|
if (t.type === "BLOCK_END_OPEN") {
|
|
2201
2273
|
const nameResult = parseBlockName(ctx, scanPos + 1);
|
|
2202
2274
|
if (nameResult?.name === "div") {
|
|
@@ -2213,6 +2285,23 @@ function consumeFailedDiv(ctx) {
|
|
|
2213
2285
|
if (lastClosePos === -1) {
|
|
2214
2286
|
return { success: false };
|
|
2215
2287
|
}
|
|
2288
|
+
const endPosForDiag = lastClosePos;
|
|
2289
|
+
for (let diagPos = ctx.pos;diagPos < endPosForDiag; diagPos++) {
|
|
2290
|
+
const t = ctx.tokens[diagPos];
|
|
2291
|
+
if (t?.type === "BLOCK_OPEN") {
|
|
2292
|
+
const nameResult = parseBlockName(ctx, diagPos + 1);
|
|
2293
|
+
if (nameResult?.name === "div" || nameResult?.name === "div_") {
|
|
2294
|
+
if (t.position) {
|
|
2295
|
+
ctx.diagnostics.push({
|
|
2296
|
+
severity: "error",
|
|
2297
|
+
code: "inline-block-element",
|
|
2298
|
+
message: `[[${nameResult.name}]] must be followed by a newline to be a block element`,
|
|
2299
|
+
position: t.position
|
|
2300
|
+
});
|
|
2301
|
+
}
|
|
2302
|
+
}
|
|
2303
|
+
}
|
|
2304
|
+
}
|
|
2216
2305
|
const endPos = lastClosePos + lastCloseConsumed;
|
|
2217
2306
|
while (pos < endPos && pos < ctx.tokens.length) {
|
|
2218
2307
|
const t = ctx.tokens[pos];
|
|
@@ -2329,6 +2418,7 @@ var codeBlockRule = {
|
|
|
2329
2418
|
consumed++;
|
|
2330
2419
|
}
|
|
2331
2420
|
let codeContent = "";
|
|
2421
|
+
let foundClose = closingSwallowed;
|
|
2332
2422
|
while (!closingSwallowed && pos < ctx.tokens.length) {
|
|
2333
2423
|
const token = ctx.tokens[pos];
|
|
2334
2424
|
if (!token || token.type === "EOF") {
|
|
@@ -2337,6 +2427,7 @@ var codeBlockRule = {
|
|
|
2337
2427
|
if (token.type === "BLOCK_END_OPEN") {
|
|
2338
2428
|
const closeNameResult = parseBlockName(ctx, pos + 1);
|
|
2339
2429
|
if (closeNameResult && closeNameResult.name === "code") {
|
|
2430
|
+
foundClose = true;
|
|
2340
2431
|
pos++;
|
|
2341
2432
|
consumed++;
|
|
2342
2433
|
pos += closeNameResult.consumed;
|
|
@@ -2356,6 +2447,14 @@ var codeBlockRule = {
|
|
|
2356
2447
|
pos++;
|
|
2357
2448
|
consumed++;
|
|
2358
2449
|
}
|
|
2450
|
+
if (!foundClose) {
|
|
2451
|
+
ctx.diagnostics.push({
|
|
2452
|
+
severity: "warning",
|
|
2453
|
+
code: "unclosed-block",
|
|
2454
|
+
message: "Missing closing tag [[/code]] for [[code]]",
|
|
2455
|
+
position: openToken.position
|
|
2456
|
+
});
|
|
2457
|
+
}
|
|
2359
2458
|
codeContent = codeContent.replace(/\n$/, "");
|
|
2360
2459
|
const codeBlockData = {
|
|
2361
2460
|
contents: codeContent,
|
|
@@ -2514,6 +2613,7 @@ var collapsibleRule = {
|
|
|
2514
2613
|
}
|
|
2515
2614
|
pos++;
|
|
2516
2615
|
consumed++;
|
|
2616
|
+
const openPosition = openToken.position;
|
|
2517
2617
|
const hasNewlineAfterOpen = ctx.tokens[pos]?.type === "NEWLINE";
|
|
2518
2618
|
if (hasNewlineAfterOpen) {
|
|
2519
2619
|
pos++;
|
|
@@ -2564,6 +2664,14 @@ var collapsibleRule = {
|
|
|
2564
2664
|
pos += bodyResult.consumed;
|
|
2565
2665
|
bodyElements = mergeParagraphs(bodyResult.elements);
|
|
2566
2666
|
}
|
|
2667
|
+
if (!isCollapsibleClose(ctx, pos)) {
|
|
2668
|
+
ctx.diagnostics.push({
|
|
2669
|
+
severity: "warning",
|
|
2670
|
+
code: "unclosed-block",
|
|
2671
|
+
message: "Missing closing tag [[/collapsible]] for [[collapsible]]",
|
|
2672
|
+
position: openPosition
|
|
2673
|
+
});
|
|
2674
|
+
}
|
|
2567
2675
|
if (isCollapsibleClose(ctx, pos)) {
|
|
2568
2676
|
const closeConsumed = consumeCloseTag2(ctx, pos);
|
|
2569
2677
|
consumed += closeConsumed;
|
|
@@ -2892,6 +3000,7 @@ var tableBlockRule = {
|
|
|
2892
3000
|
consumed++;
|
|
2893
3001
|
}
|
|
2894
3002
|
const rows = [];
|
|
3003
|
+
let foundTableClose = false;
|
|
2895
3004
|
while (pos < ctx.tokens.length) {
|
|
2896
3005
|
while (ctx.tokens[pos]?.type === "WHITESPACE" || ctx.tokens[pos]?.type === "NEWLINE") {
|
|
2897
3006
|
pos++;
|
|
@@ -2904,6 +3013,7 @@ var tableBlockRule = {
|
|
|
2904
3013
|
if (token.type === "BLOCK_END_OPEN") {
|
|
2905
3014
|
const closeNameResult = parseBlockName(ctx, pos + 1);
|
|
2906
3015
|
if (closeNameResult?.name === "table") {
|
|
3016
|
+
foundTableClose = true;
|
|
2907
3017
|
pos++;
|
|
2908
3018
|
consumed++;
|
|
2909
3019
|
pos += closeNameResult.consumed;
|
|
@@ -2934,6 +3044,14 @@ var tableBlockRule = {
|
|
|
2934
3044
|
pos++;
|
|
2935
3045
|
consumed++;
|
|
2936
3046
|
}
|
|
3047
|
+
if (!foundTableClose) {
|
|
3048
|
+
ctx.diagnostics.push({
|
|
3049
|
+
severity: "warning",
|
|
3050
|
+
code: "unclosed-block",
|
|
3051
|
+
message: "Missing closing tag [[/table]] for [[table]]",
|
|
3052
|
+
position: openToken.position
|
|
3053
|
+
});
|
|
3054
|
+
}
|
|
2937
3055
|
const hasValidContent = rows.some((row) => row.cells.length > 0);
|
|
2938
3056
|
if (!hasValidContent) {
|
|
2939
3057
|
return { success: false };
|
|
@@ -2981,6 +3099,7 @@ function parseRow(ctx, startPos) {
|
|
|
2981
3099
|
consumed++;
|
|
2982
3100
|
}
|
|
2983
3101
|
const cells = [];
|
|
3102
|
+
let foundRowClose = false;
|
|
2984
3103
|
while (pos < ctx.tokens.length) {
|
|
2985
3104
|
while (ctx.tokens[pos]?.type === "WHITESPACE" || ctx.tokens[pos]?.type === "NEWLINE") {
|
|
2986
3105
|
pos++;
|
|
@@ -2993,6 +3112,7 @@ function parseRow(ctx, startPos) {
|
|
|
2993
3112
|
if (token.type === "BLOCK_END_OPEN") {
|
|
2994
3113
|
const closeNameResult = parseBlockName(ctx, pos + 1);
|
|
2995
3114
|
if (closeNameResult?.name === "row") {
|
|
3115
|
+
foundRowClose = true;
|
|
2996
3116
|
pos++;
|
|
2997
3117
|
consumed++;
|
|
2998
3118
|
pos += closeNameResult.consumed;
|
|
@@ -3023,6 +3143,17 @@ function parseRow(ctx, startPos) {
|
|
|
3023
3143
|
pos++;
|
|
3024
3144
|
consumed++;
|
|
3025
3145
|
}
|
|
3146
|
+
if (!foundRowClose) {
|
|
3147
|
+
ctx.diagnostics.push({
|
|
3148
|
+
severity: "warning",
|
|
3149
|
+
code: "unclosed-block",
|
|
3150
|
+
message: "Missing closing tag [[/row]] for [[row]]",
|
|
3151
|
+
position: ctx.tokens[startPos]?.position ?? {
|
|
3152
|
+
start: { line: 0, column: 0, offset: 0 },
|
|
3153
|
+
end: { line: 0, column: 0, offset: 0 }
|
|
3154
|
+
}
|
|
3155
|
+
});
|
|
3156
|
+
}
|
|
3026
3157
|
return {
|
|
3027
3158
|
row: {
|
|
3028
3159
|
attributes: attrResult.attrs,
|
|
@@ -3085,6 +3216,17 @@ function parseCell(ctx, startPos) {
|
|
|
3085
3216
|
consumed += bodyResult.consumed;
|
|
3086
3217
|
pos += bodyResult.consumed;
|
|
3087
3218
|
const hadParagraphBreaks = bodyResult.hadParagraphBreaks;
|
|
3219
|
+
if (ctx.tokens[pos]?.type !== "BLOCK_END_OPEN") {
|
|
3220
|
+
ctx.diagnostics.push({
|
|
3221
|
+
severity: "warning",
|
|
3222
|
+
code: "unclosed-block",
|
|
3223
|
+
message: `Missing closing tag [[/${closeName}]] for [[${closeName}]]`,
|
|
3224
|
+
position: ctx.tokens[startPos]?.position ?? {
|
|
3225
|
+
start: { line: 0, column: 0, offset: 0 },
|
|
3226
|
+
end: { line: 0, column: 0, offset: 0 }
|
|
3227
|
+
}
|
|
3228
|
+
});
|
|
3229
|
+
}
|
|
3088
3230
|
if (ctx.tokens[pos]?.type === "BLOCK_END_OPEN") {
|
|
3089
3231
|
pos++;
|
|
3090
3232
|
consumed++;
|
|
@@ -3542,6 +3684,7 @@ var moduleRule = {
|
|
|
3542
3684
|
pos++;
|
|
3543
3685
|
consumed++;
|
|
3544
3686
|
let bodyContent = "";
|
|
3687
|
+
let foundClose = false;
|
|
3545
3688
|
while (pos < ctx.tokens.length) {
|
|
3546
3689
|
const token = ctx.tokens[pos];
|
|
3547
3690
|
if (!token || token.type === "EOF") {
|
|
@@ -3550,6 +3693,7 @@ var moduleRule = {
|
|
|
3550
3693
|
if (token.type === "BLOCK_END_OPEN") {
|
|
3551
3694
|
const closeNameResult = parseBlockName(ctx, pos + 1);
|
|
3552
3695
|
if (closeNameResult && (closeNameResult.name === "module" || closeNameResult.name === "module654")) {
|
|
3696
|
+
foundClose = true;
|
|
3553
3697
|
pos++;
|
|
3554
3698
|
consumed++;
|
|
3555
3699
|
pos += closeNameResult.consumed;
|
|
@@ -3569,6 +3713,14 @@ var moduleRule = {
|
|
|
3569
3713
|
pos++;
|
|
3570
3714
|
consumed++;
|
|
3571
3715
|
}
|
|
3716
|
+
if (!foundClose) {
|
|
3717
|
+
ctx.diagnostics.push({
|
|
3718
|
+
severity: "warning",
|
|
3719
|
+
code: "unclosed-block",
|
|
3720
|
+
message: "Missing closing tag [[/module]] for [[module]]",
|
|
3721
|
+
position: openToken.position
|
|
3722
|
+
});
|
|
3723
|
+
}
|
|
3572
3724
|
if (bodyContent.trim()) {
|
|
3573
3725
|
body = bodyContent.trim();
|
|
3574
3726
|
}
|
|
@@ -3962,7 +4114,16 @@ var alignRule = {
|
|
|
3962
4114
|
const bodyResult = parseBlocksUntil(bodyCtx, closeCondition);
|
|
3963
4115
|
consumed += bodyResult.consumed;
|
|
3964
4116
|
pos += bodyResult.consumed;
|
|
4117
|
+
const directionSymbol = { left: "<", right: ">", center: "=", justify: "==" }[direction];
|
|
3965
4118
|
const closeCheck = isAlignClose({ ...ctx, pos }, direction);
|
|
4119
|
+
if (!closeCheck.match) {
|
|
4120
|
+
ctx.diagnostics.push({
|
|
4121
|
+
severity: "warning",
|
|
4122
|
+
code: "unclosed-block",
|
|
4123
|
+
message: `Missing closing tag [[/${directionSymbol}]] for [[${directionSymbol}]]`,
|
|
4124
|
+
position: openToken.position
|
|
4125
|
+
});
|
|
4126
|
+
}
|
|
3966
4127
|
if (closeCheck.match) {
|
|
3967
4128
|
consumed += closeCheck.consumed;
|
|
3968
4129
|
pos += closeCheck.consumed;
|
|
@@ -4050,6 +4211,17 @@ function parseTab(ctx) {
|
|
|
4050
4211
|
const bodyResult = parseBlocksUntil(bodyCtx, closeCondition);
|
|
4051
4212
|
consumed += bodyResult.consumed;
|
|
4052
4213
|
pos += bodyResult.consumed;
|
|
4214
|
+
if (ctx.tokens[pos]?.type !== "BLOCK_END_OPEN") {
|
|
4215
|
+
ctx.diagnostics.push({
|
|
4216
|
+
severity: "warning",
|
|
4217
|
+
code: "unclosed-block",
|
|
4218
|
+
message: "Missing closing tag [[/tab]] for [[tab]]",
|
|
4219
|
+
position: ctx.tokens[ctx.pos]?.position ?? {
|
|
4220
|
+
start: { line: 0, column: 0, offset: 0 },
|
|
4221
|
+
end: { line: 0, column: 0, offset: 0 }
|
|
4222
|
+
}
|
|
4223
|
+
});
|
|
4224
|
+
}
|
|
4053
4225
|
if (ctx.tokens[pos]?.type === "BLOCK_END_OPEN") {
|
|
4054
4226
|
pos++;
|
|
4055
4227
|
consumed++;
|
|
@@ -4113,6 +4285,9 @@ var tabviewRule = {
|
|
|
4113
4285
|
const tabs = [];
|
|
4114
4286
|
const tabCtx = { ...ctx, pos };
|
|
4115
4287
|
while (pos < ctx.tokens.length) {
|
|
4288
|
+
if (ctx.tokens[pos]?.type === "EOF") {
|
|
4289
|
+
break;
|
|
4290
|
+
}
|
|
4116
4291
|
if (ctx.tokens[pos]?.type === "BLOCK_END_OPEN") {
|
|
4117
4292
|
const closeNameResult = parseBlockName(ctx, pos + 1);
|
|
4118
4293
|
const closeName = closeNameResult?.name.toLowerCase();
|
|
@@ -4134,6 +4309,19 @@ var tabviewRule = {
|
|
|
4134
4309
|
}
|
|
4135
4310
|
}
|
|
4136
4311
|
}
|
|
4312
|
+
const hasTabviewClose = ctx.tokens[pos]?.type === "BLOCK_END_OPEN" && (() => {
|
|
4313
|
+
const n = parseBlockName(ctx, pos + 1);
|
|
4314
|
+
const name = n?.name.toLowerCase();
|
|
4315
|
+
return name === "tabview" || name === "tabs";
|
|
4316
|
+
})();
|
|
4317
|
+
if (!hasTabviewClose) {
|
|
4318
|
+
ctx.diagnostics.push({
|
|
4319
|
+
severity: "warning",
|
|
4320
|
+
code: "unclosed-block",
|
|
4321
|
+
message: `Missing closing tag [[/${blockName}]] for [[${blockName}]]`,
|
|
4322
|
+
position: openToken.position
|
|
4323
|
+
});
|
|
4324
|
+
}
|
|
4137
4325
|
if (ctx.tokens[pos]?.type === "BLOCK_END_OPEN") {
|
|
4138
4326
|
pos++;
|
|
4139
4327
|
consumed++;
|
|
@@ -4372,6 +4560,14 @@ var mathBlockRule = {
|
|
|
4372
4560
|
pos++;
|
|
4373
4561
|
consumed++;
|
|
4374
4562
|
}
|
|
4563
|
+
if (ctx.tokens[pos]?.type !== "BLOCK_END_OPEN") {
|
|
4564
|
+
ctx.diagnostics.push({
|
|
4565
|
+
severity: "warning",
|
|
4566
|
+
code: "unclosed-block",
|
|
4567
|
+
message: "Missing closing tag [[/math]] for [[math]]",
|
|
4568
|
+
position: openToken.position
|
|
4569
|
+
});
|
|
4570
|
+
}
|
|
4375
4571
|
if (ctx.tokens[pos]?.type === "BLOCK_END_OPEN") {
|
|
4376
4572
|
pos++;
|
|
4377
4573
|
consumed++;
|
|
@@ -4454,6 +4650,12 @@ var htmlBlockRule = {
|
|
|
4454
4650
|
consumed++;
|
|
4455
4651
|
}
|
|
4456
4652
|
if (!foundClose) {
|
|
4653
|
+
ctx.diagnostics.push({
|
|
4654
|
+
severity: "warning",
|
|
4655
|
+
code: "unclosed-block",
|
|
4656
|
+
message: "Missing closing tag [[/html]] for [[html]]",
|
|
4657
|
+
position: openToken.position
|
|
4658
|
+
});
|
|
4457
4659
|
return { success: false };
|
|
4458
4660
|
}
|
|
4459
4661
|
if (ctx.tokens[pos]?.type === "BLOCK_END_OPEN") {
|
|
@@ -4543,6 +4745,12 @@ var embedBlockRule = {
|
|
|
4543
4745
|
consumed++;
|
|
4544
4746
|
}
|
|
4545
4747
|
if (!foundClose) {
|
|
4748
|
+
ctx.diagnostics.push({
|
|
4749
|
+
severity: "warning",
|
|
4750
|
+
code: "unclosed-block",
|
|
4751
|
+
message: `Missing closing tag [[/${blockName}]] for [[${blockName}]]`,
|
|
4752
|
+
position: openToken.position
|
|
4753
|
+
});
|
|
4546
4754
|
return { success: false };
|
|
4547
4755
|
}
|
|
4548
4756
|
if (ctx.tokens[pos]?.type === "BLOCK_END_OPEN") {
|
|
@@ -4772,6 +4980,14 @@ var iftagsRule = {
|
|
|
4772
4980
|
const bodyResult = parseBlocksUntil(bodyCtx, closeCondition);
|
|
4773
4981
|
consumed += bodyResult.consumed;
|
|
4774
4982
|
pos += bodyResult.consumed;
|
|
4983
|
+
if (ctx.tokens[pos]?.type !== "BLOCK_END_OPEN") {
|
|
4984
|
+
ctx.diagnostics.push({
|
|
4985
|
+
severity: "warning",
|
|
4986
|
+
code: "unclosed-block",
|
|
4987
|
+
message: "Missing closing tag [[/iftags]] for [[iftags]]",
|
|
4988
|
+
position: openToken.position
|
|
4989
|
+
});
|
|
4990
|
+
}
|
|
4775
4991
|
if (ctx.tokens[pos]?.type === "BLOCK_END_OPEN") {
|
|
4776
4992
|
pos++;
|
|
4777
4993
|
consumed++;
|
|
@@ -4975,6 +5191,12 @@ var orphanLiRule = {
|
|
|
4975
5191
|
consumed++;
|
|
4976
5192
|
}
|
|
4977
5193
|
if (!foundClose) {
|
|
5194
|
+
ctx.diagnostics.push({
|
|
5195
|
+
severity: "warning",
|
|
5196
|
+
code: "unclosed-block",
|
|
5197
|
+
message: "Missing closing tag [[/li]] for [[li]]",
|
|
5198
|
+
position: openToken.position
|
|
5199
|
+
});
|
|
4978
5200
|
return { success: false };
|
|
4979
5201
|
}
|
|
4980
5202
|
return {
|
|
@@ -5165,6 +5387,12 @@ var bibliographyRule = {
|
|
|
5165
5387
|
consumed++;
|
|
5166
5388
|
}
|
|
5167
5389
|
if (!foundClose) {
|
|
5390
|
+
ctx.diagnostics.push({
|
|
5391
|
+
severity: "warning",
|
|
5392
|
+
code: "unclosed-block",
|
|
5393
|
+
message: "Missing closing tag [[/bibliography]] for [[bibliography]]",
|
|
5394
|
+
position: openToken.position
|
|
5395
|
+
});
|
|
5168
5396
|
return { success: false };
|
|
5169
5397
|
}
|
|
5170
5398
|
const definitionItems = entries.map((entry) => ({
|
|
@@ -6086,6 +6314,7 @@ var commentRule = {
|
|
|
6086
6314
|
name: "comment",
|
|
6087
6315
|
startTokens: ["COMMENT_OPEN"],
|
|
6088
6316
|
parse(ctx) {
|
|
6317
|
+
const openToken = currentToken(ctx);
|
|
6089
6318
|
let pos = ctx.pos + 1;
|
|
6090
6319
|
let consumed = 1;
|
|
6091
6320
|
while (pos < ctx.tokens.length) {
|
|
@@ -6103,11 +6332,23 @@ var commentRule = {
|
|
|
6103
6332
|
};
|
|
6104
6333
|
}
|
|
6105
6334
|
if (token.type === "EOF") {
|
|
6335
|
+
ctx.diagnostics.push({
|
|
6336
|
+
severity: "warning",
|
|
6337
|
+
code: "unclosed-comment",
|
|
6338
|
+
message: "Unterminated comment: missing closing --]",
|
|
6339
|
+
position: openToken.position
|
|
6340
|
+
});
|
|
6106
6341
|
return { success: false };
|
|
6107
6342
|
}
|
|
6108
6343
|
pos++;
|
|
6109
6344
|
consumed++;
|
|
6110
6345
|
}
|
|
6346
|
+
ctx.diagnostics.push({
|
|
6347
|
+
severity: "warning",
|
|
6348
|
+
code: "unclosed-comment",
|
|
6349
|
+
message: "Unterminated comment: missing closing --]",
|
|
6350
|
+
position: openToken.position
|
|
6351
|
+
});
|
|
6111
6352
|
return { success: false };
|
|
6112
6353
|
}
|
|
6113
6354
|
};
|
|
@@ -6365,6 +6606,12 @@ var spanRule = {
|
|
|
6365
6606
|
}
|
|
6366
6607
|
}
|
|
6367
6608
|
if (!foundClose) {
|
|
6609
|
+
ctx.diagnostics.push({
|
|
6610
|
+
severity: "warning",
|
|
6611
|
+
code: "unclosed-block",
|
|
6612
|
+
message: `Missing closing tag [[/span]] for [[${blockName}]]`,
|
|
6613
|
+
position: openToken.position
|
|
6614
|
+
});
|
|
6368
6615
|
return { success: false };
|
|
6369
6616
|
}
|
|
6370
6617
|
if (paragraphStrip) {
|
|
@@ -6565,6 +6812,7 @@ var sizeRule = {
|
|
|
6565
6812
|
pos++;
|
|
6566
6813
|
consumed++;
|
|
6567
6814
|
const children = [];
|
|
6815
|
+
let foundClose = false;
|
|
6568
6816
|
while (pos < ctx.tokens.length) {
|
|
6569
6817
|
const token = ctx.tokens[pos];
|
|
6570
6818
|
if (!token || token.type === "EOF") {
|
|
@@ -6573,6 +6821,7 @@ var sizeRule = {
|
|
|
6573
6821
|
if (token.type === "BLOCK_END_OPEN") {
|
|
6574
6822
|
const closeNameResult = parseBlockName(ctx, pos + 1);
|
|
6575
6823
|
if (closeNameResult && closeNameResult.name === "size") {
|
|
6824
|
+
foundClose = true;
|
|
6576
6825
|
pos++;
|
|
6577
6826
|
consumed++;
|
|
6578
6827
|
pos += closeNameResult.consumed;
|
|
@@ -6596,6 +6845,14 @@ var sizeRule = {
|
|
|
6596
6845
|
consumed++;
|
|
6597
6846
|
}
|
|
6598
6847
|
}
|
|
6848
|
+
if (!foundClose) {
|
|
6849
|
+
ctx.diagnostics.push({
|
|
6850
|
+
severity: "warning",
|
|
6851
|
+
code: "unclosed-block",
|
|
6852
|
+
message: "Missing closing tag [[/size]] for [[size]]",
|
|
6853
|
+
position: openToken.position
|
|
6854
|
+
});
|
|
6855
|
+
}
|
|
6599
6856
|
return {
|
|
6600
6857
|
success: true,
|
|
6601
6858
|
elements: [
|
|
@@ -6645,6 +6902,7 @@ var footnoteRule = {
|
|
|
6645
6902
|
consumed++;
|
|
6646
6903
|
const paragraphs = [[]];
|
|
6647
6904
|
let currentParagraph = 0;
|
|
6905
|
+
let foundClose = false;
|
|
6648
6906
|
while (pos < ctx.tokens.length) {
|
|
6649
6907
|
const token = ctx.tokens[pos];
|
|
6650
6908
|
if (!token || token.type === "EOF") {
|
|
@@ -6653,6 +6911,7 @@ var footnoteRule = {
|
|
|
6653
6911
|
if (token.type === "BLOCK_END_OPEN") {
|
|
6654
6912
|
const closeNameResult = parseBlockName(ctx, pos + 1);
|
|
6655
6913
|
if (closeNameResult && closeNameResult.name === "footnote") {
|
|
6914
|
+
foundClose = true;
|
|
6656
6915
|
pos++;
|
|
6657
6916
|
consumed++;
|
|
6658
6917
|
pos += closeNameResult.consumed;
|
|
@@ -6729,6 +6988,14 @@ var footnoteRule = {
|
|
|
6729
6988
|
});
|
|
6730
6989
|
}
|
|
6731
6990
|
}
|
|
6991
|
+
if (!foundClose) {
|
|
6992
|
+
ctx.diagnostics.push({
|
|
6993
|
+
severity: "warning",
|
|
6994
|
+
code: "unclosed-block",
|
|
6995
|
+
message: "Missing closing tag [[/footnote]] for [[footnote]]",
|
|
6996
|
+
position: openToken.position
|
|
6997
|
+
});
|
|
6998
|
+
}
|
|
6732
6999
|
ctx.footnotes.push(children);
|
|
6733
7000
|
return {
|
|
6734
7001
|
success: true,
|
|
@@ -7224,6 +7491,12 @@ var anchorRule = {
|
|
|
7224
7491
|
}
|
|
7225
7492
|
}
|
|
7226
7493
|
if (!foundClose) {
|
|
7494
|
+
ctx.diagnostics.push({
|
|
7495
|
+
severity: "warning",
|
|
7496
|
+
code: "unclosed-block",
|
|
7497
|
+
message: `Missing closing tag [[/a]] for [[${nameResult.name}]]`,
|
|
7498
|
+
position: openToken.position
|
|
7499
|
+
});
|
|
7227
7500
|
return { success: false };
|
|
7228
7501
|
}
|
|
7229
7502
|
if (paragraphStrip) {
|
|
@@ -8202,6 +8475,50 @@ function cleanElement(el) {
|
|
|
8202
8475
|
}
|
|
8203
8476
|
return el;
|
|
8204
8477
|
}
|
|
8478
|
+
// packages/parser/src/parser/postprocess/divAdjacentParagraph.ts
|
|
8479
|
+
function isParagraphContainer2(el) {
|
|
8480
|
+
if (!el || el.element !== "container")
|
|
8481
|
+
return false;
|
|
8482
|
+
return el.data.type === "paragraph";
|
|
8483
|
+
}
|
|
8484
|
+
function isDivContainer(el) {
|
|
8485
|
+
if (!el || el.element !== "container")
|
|
8486
|
+
return false;
|
|
8487
|
+
return el.data.type === "div";
|
|
8488
|
+
}
|
|
8489
|
+
function suppressAtLevel(elements) {
|
|
8490
|
+
if (elements.length <= 1)
|
|
8491
|
+
return elements;
|
|
8492
|
+
const unwrap = new Array(elements.length).fill(false);
|
|
8493
|
+
for (let i = 0;i < elements.length; i++) {
|
|
8494
|
+
if (!isParagraphContainer2(elements[i]))
|
|
8495
|
+
continue;
|
|
8496
|
+
const prevIsDiv = i > 0 && isDivContainer(elements[i - 1]);
|
|
8497
|
+
const nextIsDiv = i < elements.length - 1 && isDivContainer(elements[i + 1]);
|
|
8498
|
+
if (prevIsDiv || nextIsDiv) {
|
|
8499
|
+
unwrap[i] = true;
|
|
8500
|
+
}
|
|
8501
|
+
}
|
|
8502
|
+
const result = [];
|
|
8503
|
+
for (let i = 0;i < elements.length; i++) {
|
|
8504
|
+
const el = elements[i];
|
|
8505
|
+
if (!el)
|
|
8506
|
+
continue;
|
|
8507
|
+
if (unwrap[i] && el.element === "container") {
|
|
8508
|
+
const inner = el.data.elements;
|
|
8509
|
+
if (i > 0 && isDivContainer(elements[i - 1])) {
|
|
8510
|
+
result.push({ element: "line-break" });
|
|
8511
|
+
}
|
|
8512
|
+
result.push(...inner);
|
|
8513
|
+
} else {
|
|
8514
|
+
result.push(el);
|
|
8515
|
+
}
|
|
8516
|
+
}
|
|
8517
|
+
return result;
|
|
8518
|
+
}
|
|
8519
|
+
function suppressDivAdjacentParagraphs(elements) {
|
|
8520
|
+
return suppressAtLevel(elements);
|
|
8521
|
+
}
|
|
8205
8522
|
// packages/parser/src/parser/toc.ts
|
|
8206
8523
|
class TocIndexer {
|
|
8207
8524
|
index = 0;
|
|
@@ -8279,6 +8596,7 @@ class Parser {
|
|
|
8279
8596
|
htmlBlocks: [],
|
|
8280
8597
|
footnoteBlockParsed: false,
|
|
8281
8598
|
bibcites: [],
|
|
8599
|
+
diagnostics: [],
|
|
8282
8600
|
blockRules,
|
|
8283
8601
|
blockFallbackRule: paragraphRule,
|
|
8284
8602
|
inlineRules
|
|
@@ -8291,7 +8609,8 @@ class Parser {
|
|
|
8291
8609
|
children.push(...blocks);
|
|
8292
8610
|
}
|
|
8293
8611
|
const mergedChildren = mergeSpanStripParagraphs(children);
|
|
8294
|
-
const
|
|
8612
|
+
const divProcessed = suppressDivAdjacentParagraphs(mergedChildren);
|
|
8613
|
+
const cleanedChildren = cleanInternalFlags(divProcessed);
|
|
8295
8614
|
const hasFootnoteBlock = cleanedChildren.some((el) => el.element === "footnote-block");
|
|
8296
8615
|
if (!hasFootnoteBlock) {
|
|
8297
8616
|
cleanedChildren.push({
|
|
@@ -8315,7 +8634,7 @@ class Parser {
|
|
|
8315
8634
|
if (this.ctx.htmlBlocks.length > 0) {
|
|
8316
8635
|
result["html-blocks"] = this.ctx.htmlBlocks;
|
|
8317
8636
|
}
|
|
8318
|
-
return result;
|
|
8637
|
+
return { ast: result, diagnostics: this.ctx.diagnostics };
|
|
8319
8638
|
}
|
|
8320
8639
|
isAtEnd() {
|
|
8321
8640
|
return this.ctx.pos >= this.ctx.tokens.length || this.currentToken().type === "EOF";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wdprlib/parser",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"description": "Parser for Wikidot markup",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ast",
|
|
@@ -39,6 +39,6 @@
|
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@braintree/sanitize-url": "^7.1.1",
|
|
42
|
-
"@wdprlib/ast": "1.
|
|
42
|
+
"@wdprlib/ast": "1.2.1"
|
|
43
43
|
}
|
|
44
44
|
}
|