@wdprlib/parser 3.1.1 → 3.2.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 +312 -121
- package/dist/index.js +289 -98
- package/package.json +5 -3
- package/src/index.ts +163 -0
- package/src/lexer/index.ts +20 -0
- package/src/lexer/lexer.ts +687 -0
- package/src/lexer/tokens.ts +141 -0
- package/src/parser/constants.ts +173 -0
- package/src/parser/depth.ts +251 -0
- package/src/parser/index.ts +18 -0
- package/src/parser/parse.ts +315 -0
- package/src/parser/postprocess/divAdjacentParagraph.ts +76 -0
- package/src/parser/postprocess/index.ts +15 -0
- package/src/parser/postprocess/spanStrip.ts +697 -0
- package/src/parser/preprocess/expr.ts +265 -0
- package/src/parser/preprocess/index.ts +38 -0
- package/src/parser/preprocess/typography.ts +67 -0
- package/src/parser/preprocess/utils.ts +250 -0
- package/src/parser/preprocess/whitespace.ts +111 -0
- package/src/parser/rules/block/align.ts +282 -0
- package/src/parser/rules/block/bibliography.ts +359 -0
- package/src/parser/rules/block/block-list.ts +689 -0
- package/src/parser/rules/block/blockquote.ts +238 -0
- package/src/parser/rules/block/center.ts +87 -0
- package/src/parser/rules/block/clear-float.ts +75 -0
- package/src/parser/rules/block/code.ts +187 -0
- package/src/parser/rules/block/collapsible.ts +337 -0
- package/src/parser/rules/block/comment.ts +73 -0
- package/src/parser/rules/block/content-separator.ts +79 -0
- package/src/parser/rules/block/definition-list.ts +270 -0
- package/src/parser/rules/block/div.ts +400 -0
- package/src/parser/rules/block/embed-block.ts +153 -0
- package/src/parser/rules/block/footnoteblock.ts +200 -0
- package/src/parser/rules/block/heading.ts +142 -0
- package/src/parser/rules/block/horizontal-rule.ts +61 -0
- package/src/parser/rules/block/html.ts +222 -0
- package/src/parser/rules/block/iframe.ts +239 -0
- package/src/parser/rules/block/iftags.ts +150 -0
- package/src/parser/rules/block/include.ts +179 -0
- package/src/parser/rules/block/index.ts +127 -0
- package/src/parser/rules/block/list.ts +244 -0
- package/src/parser/rules/block/math.ts +183 -0
- package/src/parser/rules/block/module/backlinks/index.ts +31 -0
- package/src/parser/rules/block/module/backlinks/types.ts +21 -0
- package/src/parser/rules/block/module/categories/index.ts +34 -0
- package/src/parser/rules/block/module/categories/types.ts +21 -0
- package/src/parser/rules/block/module/css/index.ts +37 -0
- package/src/parser/rules/block/module/iftags/condition.ts +109 -0
- package/src/parser/rules/block/module/iftags/index.ts +26 -0
- package/src/parser/rules/block/module/iftags/preprocess.ts +140 -0
- package/src/parser/rules/block/module/iftags/resolve.ts +73 -0
- package/src/parser/rules/block/module/iftags/types.ts +63 -0
- package/src/parser/rules/block/module/include/index.ts +20 -0
- package/src/parser/rules/block/module/include/resolve.ts +556 -0
- package/src/parser/rules/block/module/index.ts +122 -0
- package/src/parser/rules/block/module/join/index.ts +34 -0
- package/src/parser/rules/block/module/join/types.ts +23 -0
- package/src/parser/rules/block/module/listpages/compiler.ts +453 -0
- package/src/parser/rules/block/module/listpages/extract.ts +410 -0
- package/src/parser/rules/block/module/listpages/index.ts +83 -0
- package/src/parser/rules/block/module/listpages/normalize.ts +390 -0
- package/src/parser/rules/block/module/listpages/parser.ts +106 -0
- package/src/parser/rules/block/module/listpages/resolve.ts +130 -0
- package/src/parser/rules/block/module/listpages/types.ts +513 -0
- package/src/parser/rules/block/module/listpages/url-resolver.ts +186 -0
- package/src/parser/rules/block/module/listusers/compiler.ts +77 -0
- package/src/parser/rules/block/module/listusers/extract.ts +45 -0
- package/src/parser/rules/block/module/listusers/index.ts +36 -0
- package/src/parser/rules/block/module/listusers/parser.ts +54 -0
- package/src/parser/rules/block/module/listusers/resolve.ts +58 -0
- package/src/parser/rules/block/module/listusers/types.ts +93 -0
- package/src/parser/rules/block/module/mapping.ts +61 -0
- package/src/parser/rules/block/module/page-tree/index.ts +38 -0
- package/src/parser/rules/block/module/page-tree/types.ts +29 -0
- package/src/parser/rules/block/module/rate/index.ts +28 -0
- package/src/parser/rules/block/module/rate/types.ts +19 -0
- package/src/parser/rules/block/module/resolve.ts +411 -0
- package/src/parser/rules/block/module/types-common.ts +59 -0
- package/src/parser/rules/block/module/types.ts +61 -0
- package/src/parser/rules/block/module/utils.ts +43 -0
- package/src/parser/rules/block/module/walk.ts +380 -0
- package/src/parser/rules/block/module.ts +164 -0
- package/src/parser/rules/block/orphan-li.ts +177 -0
- package/src/parser/rules/block/paragraph.ts +157 -0
- package/src/parser/rules/block/table-block.ts +726 -0
- package/src/parser/rules/block/table.ts +441 -0
- package/src/parser/rules/block/tabview.ts +331 -0
- package/src/parser/rules/block/toc.ts +129 -0
- package/src/parser/rules/block/utils.ts +615 -0
- package/src/parser/rules/index.ts +49 -0
- package/src/parser/rules/inline/anchor-name.ts +154 -0
- package/src/parser/rules/inline/anchor.ts +327 -0
- package/src/parser/rules/inline/bibcite.ts +153 -0
- package/src/parser/rules/inline/bold.ts +86 -0
- package/src/parser/rules/inline/color.ts +140 -0
- package/src/parser/rules/inline/comment.ts +90 -0
- package/src/parser/rules/inline/equation-ref.ts +115 -0
- package/src/parser/rules/inline/expr.ts +526 -0
- package/src/parser/rules/inline/footnote.ts +223 -0
- package/src/parser/rules/inline/guillemet.ts +64 -0
- package/src/parser/rules/inline/html.ts +132 -0
- package/src/parser/rules/inline/image.ts +328 -0
- package/src/parser/rules/inline/index.ts +150 -0
- package/src/parser/rules/inline/italic.ts +74 -0
- package/src/parser/rules/inline/line-break.ts +326 -0
- package/src/parser/rules/inline/link-anchor.ts +147 -0
- package/src/parser/rules/inline/link-single.ts +164 -0
- package/src/parser/rules/inline/link-star.ts +134 -0
- package/src/parser/rules/inline/link-triple.ts +267 -0
- package/src/parser/rules/inline/math-inline.ts +126 -0
- package/src/parser/rules/inline/monospace.ts +78 -0
- package/src/parser/rules/inline/raw.ts +262 -0
- package/src/parser/rules/inline/size.ts +244 -0
- package/src/parser/rules/inline/span.ts +424 -0
- package/src/parser/rules/inline/strikethrough.ts +115 -0
- package/src/parser/rules/inline/subscript.ts +84 -0
- package/src/parser/rules/inline/superscript.ts +84 -0
- package/src/parser/rules/inline/text.ts +84 -0
- package/src/parser/rules/inline/underline.ts +127 -0
- package/src/parser/rules/inline/user.ts +147 -0
- package/src/parser/rules/inline/utils.ts +344 -0
- package/src/parser/rules/types.ts +252 -0
- package/src/parser/rules/utils.ts +155 -0
- package/src/parser/toc.ts +130 -0
package/dist/index.js
CHANGED
|
@@ -9077,6 +9077,8 @@ function parseTagCondition(condition) {
|
|
|
9077
9077
|
const required = [];
|
|
9078
9078
|
const forbidden = [];
|
|
9079
9079
|
const optional = [];
|
|
9080
|
+
let hasEmptyRequired = false;
|
|
9081
|
+
let hasEmptyForbidden = false;
|
|
9080
9082
|
const parts = condition.trim().split(/\s+/);
|
|
9081
9083
|
for (const part of parts) {
|
|
9082
9084
|
if (!part)
|
|
@@ -9085,20 +9087,31 @@ function parseTagCondition(condition) {
|
|
|
9085
9087
|
const tag = part.slice(1);
|
|
9086
9088
|
if (tag)
|
|
9087
9089
|
required.push(tag);
|
|
9090
|
+
else
|
|
9091
|
+
hasEmptyRequired = true;
|
|
9088
9092
|
} else if (part.startsWith("-")) {
|
|
9089
9093
|
const tag = part.slice(1);
|
|
9090
9094
|
if (tag)
|
|
9091
9095
|
forbidden.push(tag);
|
|
9096
|
+
else
|
|
9097
|
+
hasEmptyForbidden = true;
|
|
9092
9098
|
} else {
|
|
9093
9099
|
optional.push(part);
|
|
9094
9100
|
}
|
|
9095
9101
|
}
|
|
9096
|
-
return { required, forbidden, optional };
|
|
9102
|
+
return { required, forbidden, optional, hasEmptyRequired, hasEmptyForbidden };
|
|
9097
9103
|
}
|
|
9098
9104
|
function evaluateTagCondition(condition, pageTags) {
|
|
9099
|
-
|
|
9105
|
+
const noNamedTokens = condition.required.length === 0 && condition.forbidden.length === 0 && condition.optional.length === 0;
|
|
9106
|
+
if (noNamedTokens && !condition.hasEmptyRequired && !condition.hasEmptyForbidden) {
|
|
9100
9107
|
return false;
|
|
9101
9108
|
}
|
|
9109
|
+
if (condition.hasEmptyRequired) {
|
|
9110
|
+
return false;
|
|
9111
|
+
}
|
|
9112
|
+
if (condition.hasEmptyForbidden && noNamedTokens) {
|
|
9113
|
+
return true;
|
|
9114
|
+
}
|
|
9102
9115
|
const tagSet = new Set(pageTags);
|
|
9103
9116
|
for (const tag of condition.required) {
|
|
9104
9117
|
if (!tagSet.has(tag)) {
|
|
@@ -9118,19 +9131,10 @@ function evaluateTagCondition(condition, pageTags) {
|
|
|
9118
9131
|
return true;
|
|
9119
9132
|
}
|
|
9120
9133
|
|
|
9121
|
-
// packages/parser/src/parser/
|
|
9122
|
-
var BASE_PLACEHOLDER_OPEN = "
|
|
9123
|
-
var BASE_PLACEHOLDER_CLOSE = "
|
|
9124
|
-
var INNERMOST_IFTAGS_PATTERN = /\[\[\s*iftags\b([^\]]*)\]\]((?:(?!\[\[\s*iftags\b|\[\[\/\s*iftags\s*\]\]).)*)\[\[\/\s*iftags\s*\]\]/gis;
|
|
9134
|
+
// packages/parser/src/parser/preprocess/utils.ts
|
|
9135
|
+
var BASE_PLACEHOLDER_OPEN = "";
|
|
9136
|
+
var BASE_PLACEHOLDER_CLOSE = "";
|
|
9125
9137
|
var RAW_BLOCK_OPEN_PATTERN = /\[\[\s*(code|html)\b[^\]]*\]\]/iy;
|
|
9126
|
-
function preprocessIftags(source, pageTags) {
|
|
9127
|
-
if (!source.includes("[["))
|
|
9128
|
-
return source;
|
|
9129
|
-
const sentinels = makeUniqueSentinels(source);
|
|
9130
|
-
const { masked, placeholders } = maskRawRegions(source, sentinels);
|
|
9131
|
-
const reduced = reduceIftags(masked, pageTags);
|
|
9132
|
-
return restorePlaceholders(reduced, placeholders, sentinels);
|
|
9133
|
-
}
|
|
9134
9138
|
function makeUniqueSentinels(source) {
|
|
9135
9139
|
let open = BASE_PLACEHOLDER_OPEN;
|
|
9136
9140
|
let close = BASE_PLACEHOLDER_CLOSE;
|
|
@@ -9140,46 +9144,91 @@ function makeUniqueSentinels(source) {
|
|
|
9140
9144
|
}
|
|
9141
9145
|
return { open, close };
|
|
9142
9146
|
}
|
|
9143
|
-
function
|
|
9144
|
-
|
|
9145
|
-
|
|
9146
|
-
|
|
9147
|
-
|
|
9148
|
-
|
|
9149
|
-
|
|
9150
|
-
|
|
9151
|
-
if (
|
|
9152
|
-
|
|
9147
|
+
function maskRawRegions(source, sentinels) {
|
|
9148
|
+
const placeholders = [];
|
|
9149
|
+
let masked = "";
|
|
9150
|
+
let i = 0;
|
|
9151
|
+
while (i < source.length) {
|
|
9152
|
+
if (source[i] === "[" && source[i + 1] === "[") {
|
|
9153
|
+
RAW_BLOCK_OPEN_PATTERN.lastIndex = i;
|
|
9154
|
+
const openMatch = RAW_BLOCK_OPEN_PATTERN.exec(source);
|
|
9155
|
+
if (openMatch) {
|
|
9156
|
+
const name = openMatch[1].toLowerCase();
|
|
9157
|
+
const openLen = openMatch[0].length;
|
|
9158
|
+
const closePattern = new RegExp(`\\[\\[\\/\\s*${name}\\s*\\]\\]`, "ig");
|
|
9159
|
+
closePattern.lastIndex = i + openLen;
|
|
9160
|
+
const closeMatch = closePattern.exec(source);
|
|
9161
|
+
if (closeMatch) {
|
|
9162
|
+
const regionEnd = closeMatch.index + closeMatch[0].length;
|
|
9163
|
+
masked += pushPlaceholder(placeholders, source.slice(i, regionEnd), sentinels);
|
|
9164
|
+
i = regionEnd;
|
|
9165
|
+
continue;
|
|
9166
|
+
}
|
|
9167
|
+
if (name === "code") {
|
|
9168
|
+
masked += pushPlaceholder(placeholders, source.slice(i), sentinels);
|
|
9169
|
+
i = source.length;
|
|
9170
|
+
continue;
|
|
9171
|
+
}
|
|
9153
9172
|
}
|
|
9154
|
-
|
|
9155
|
-
|
|
9156
|
-
|
|
9157
|
-
|
|
9158
|
-
|
|
9159
|
-
|
|
9160
|
-
|
|
9173
|
+
}
|
|
9174
|
+
if (source[i] === "@" && source[i + 1] === "<") {
|
|
9175
|
+
const close = source.indexOf(">@", i + 2);
|
|
9176
|
+
const newline = source.indexOf(`
|
|
9177
|
+
`, i + 2);
|
|
9178
|
+
if (close !== -1 && (newline === -1 || close < newline)) {
|
|
9179
|
+
const regionEnd = close + 2;
|
|
9180
|
+
masked += pushPlaceholder(placeholders, source.slice(i, regionEnd), sentinels);
|
|
9181
|
+
i = regionEnd;
|
|
9182
|
+
continue;
|
|
9183
|
+
}
|
|
9184
|
+
}
|
|
9185
|
+
if (source[i] === "@" && source[i + 1] === "@") {
|
|
9186
|
+
const close = source.indexOf("@@", i + 2);
|
|
9187
|
+
const newline = source.indexOf(`
|
|
9188
|
+
`, i + 2);
|
|
9189
|
+
if (close !== -1 && (newline === -1 || close < newline)) {
|
|
9190
|
+
const regionEnd = close + 2;
|
|
9191
|
+
masked += pushPlaceholder(placeholders, source.slice(i, regionEnd), sentinels);
|
|
9192
|
+
i = regionEnd;
|
|
9193
|
+
continue;
|
|
9194
|
+
}
|
|
9195
|
+
}
|
|
9196
|
+
masked += source[i];
|
|
9197
|
+
i++;
|
|
9161
9198
|
}
|
|
9162
|
-
return
|
|
9199
|
+
return { masked, placeholders };
|
|
9200
|
+
}
|
|
9201
|
+
function pushPlaceholder(placeholders, text, sentinels) {
|
|
9202
|
+
const idx = placeholders.length;
|
|
9203
|
+
placeholders.push(text);
|
|
9204
|
+
return `${sentinels.open}${idx}${sentinels.close}`;
|
|
9205
|
+
}
|
|
9206
|
+
function escapeRegex(str) {
|
|
9207
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
9208
|
+
}
|
|
9209
|
+
function restorePlaceholders(source, placeholders, sentinels) {
|
|
9210
|
+
const pattern = new RegExp(`${escapeRegex(sentinels.open)}(\\d+)${escapeRegex(sentinels.close)}`, "g");
|
|
9211
|
+
return source.replace(pattern, (_, idx) => placeholders[Number(idx)] ?? "");
|
|
9163
9212
|
}
|
|
9164
|
-
function computeBracketDepths(
|
|
9165
|
-
const n =
|
|
9213
|
+
function computeBracketDepths(source) {
|
|
9214
|
+
const n = source.length;
|
|
9166
9215
|
const depths = new Int32Array(n + 1);
|
|
9167
9216
|
let depth = 0;
|
|
9168
9217
|
let i = 0;
|
|
9169
9218
|
while (i < n) {
|
|
9170
9219
|
depths[i] = depth;
|
|
9171
|
-
const c =
|
|
9172
|
-
const c1 = i + 1 < n ?
|
|
9173
|
-
const c2 = i + 2 < n ?
|
|
9174
|
-
if (depth > 0 && c === 34 && precededByEqualsAttr(
|
|
9175
|
-
const end = findQuoteEnd(
|
|
9220
|
+
const c = source.charCodeAt(i);
|
|
9221
|
+
const c1 = i + 1 < n ? source.charCodeAt(i + 1) : -1;
|
|
9222
|
+
const c2 = i + 2 < n ? source.charCodeAt(i + 2) : -1;
|
|
9223
|
+
if (depth > 0 && c === 34 && precededByEqualsAttr(source, i)) {
|
|
9224
|
+
const end = findQuoteEnd(source, i + 1);
|
|
9176
9225
|
for (let k = i;k <= end; k++)
|
|
9177
9226
|
depths[k] = depth;
|
|
9178
9227
|
i = end + 1;
|
|
9179
9228
|
continue;
|
|
9180
9229
|
}
|
|
9181
9230
|
if (c === 91 && c1 === 91 && c2 === 91) {
|
|
9182
|
-
const end = findTripleLinkEnd(
|
|
9231
|
+
const end = findTripleLinkEnd(source, i + 3);
|
|
9183
9232
|
for (let k = i;k <= end; k++)
|
|
9184
9233
|
depths[k] = depth;
|
|
9185
9234
|
i = end + 1;
|
|
@@ -9236,71 +9285,198 @@ function findTripleLinkEnd(s, from) {
|
|
|
9236
9285
|
}
|
|
9237
9286
|
return s.length - 1;
|
|
9238
9287
|
}
|
|
9239
|
-
|
|
9240
|
-
|
|
9241
|
-
|
|
9288
|
+
|
|
9289
|
+
// packages/parser/src/parser/rules/block/module/iftags/preprocess.ts
|
|
9290
|
+
var INNERMOST_IFTAGS_PATTERN = /\[\[\s*iftags\b([^\]]*)\]\]((?:(?!\[\[\s*iftags\b|\[\[\/\s*iftags\s*\]\]).)*)\[\[\/\s*iftags\s*\]\]/gis;
|
|
9291
|
+
function preprocessIftags(source, pageTags) {
|
|
9292
|
+
if (!source.includes("[["))
|
|
9293
|
+
return source;
|
|
9294
|
+
const sentinels = makeUniqueSentinels(source);
|
|
9295
|
+
const { masked, placeholders } = maskRawRegions(source, sentinels);
|
|
9296
|
+
const reduced = reduceIftags(masked, pageTags);
|
|
9297
|
+
return restorePlaceholders(reduced, placeholders, sentinels);
|
|
9298
|
+
}
|
|
9299
|
+
function reduceIftags(source, pageTags) {
|
|
9300
|
+
let current = source;
|
|
9301
|
+
const maxIterations = source.length + 1;
|
|
9302
|
+
const tagSet = pageTags ?? [];
|
|
9303
|
+
for (let i = 0;i < maxIterations; i++) {
|
|
9304
|
+
const depths = pageTags === null ? computeBracketDepths(current) : null;
|
|
9305
|
+
let changed = false;
|
|
9306
|
+
const next = current.replace(INNERMOST_IFTAGS_PATTERN, (match, cond, body, offset) => {
|
|
9307
|
+
if (depths !== null && depths[offset] === 0) {
|
|
9308
|
+
return match;
|
|
9309
|
+
}
|
|
9310
|
+
changed = true;
|
|
9311
|
+
const condition = parseTagCondition(cond);
|
|
9312
|
+
return evaluateTagCondition(condition, tagSet) ? body : "";
|
|
9313
|
+
});
|
|
9314
|
+
if (!changed)
|
|
9315
|
+
return current;
|
|
9316
|
+
current = next;
|
|
9317
|
+
}
|
|
9318
|
+
return current;
|
|
9319
|
+
}
|
|
9320
|
+
|
|
9321
|
+
// packages/parser/src/parser/preprocess/expr.ts
|
|
9322
|
+
import { evaluateExpression, formatExprValue, isTruthy } from "@wdprlib/ast";
|
|
9323
|
+
function preprocessExpr(source) {
|
|
9324
|
+
if (!source.includes("[[#"))
|
|
9325
|
+
return source;
|
|
9326
|
+
const sentinels = makeUniqueSentinels(source);
|
|
9327
|
+
const { masked, placeholders } = maskRawRegions(source, sentinels);
|
|
9328
|
+
const reduced = reduceExpr(masked);
|
|
9329
|
+
return restorePlaceholders(reduced, placeholders, sentinels);
|
|
9330
|
+
}
|
|
9331
|
+
function reduceExpr(source) {
|
|
9332
|
+
let current = source;
|
|
9333
|
+
const maxIterations = source.length + 1;
|
|
9334
|
+
for (let i = 0;i < maxIterations; i++) {
|
|
9335
|
+
const next = expandInnermost(current);
|
|
9336
|
+
if (next === current)
|
|
9337
|
+
return current;
|
|
9338
|
+
current = next;
|
|
9339
|
+
}
|
|
9340
|
+
return current;
|
|
9341
|
+
}
|
|
9342
|
+
function expandInnermost(source) {
|
|
9343
|
+
const depths = computeBracketDepths(source);
|
|
9344
|
+
let result = "";
|
|
9242
9345
|
let i = 0;
|
|
9346
|
+
let replaced = false;
|
|
9243
9347
|
while (i < source.length) {
|
|
9244
|
-
|
|
9245
|
-
|
|
9246
|
-
const
|
|
9247
|
-
if (
|
|
9248
|
-
|
|
9249
|
-
|
|
9250
|
-
|
|
9251
|
-
closePattern.lastIndex = i + openLen;
|
|
9252
|
-
const closeMatch = closePattern.exec(source);
|
|
9253
|
-
if (closeMatch) {
|
|
9254
|
-
const regionEnd = closeMatch.index + closeMatch[0].length;
|
|
9255
|
-
masked += pushPlaceholder(placeholders, source.slice(i, regionEnd), sentinels);
|
|
9256
|
-
i = regionEnd;
|
|
9257
|
-
continue;
|
|
9258
|
-
}
|
|
9259
|
-
if (name === "code") {
|
|
9260
|
-
masked += pushPlaceholder(placeholders, source.slice(i), sentinels);
|
|
9261
|
-
i = source.length;
|
|
9262
|
-
continue;
|
|
9263
|
-
}
|
|
9264
|
-
}
|
|
9265
|
-
}
|
|
9266
|
-
if (source[i] === "@" && source[i + 1] === "<") {
|
|
9267
|
-
const close = source.indexOf(">@", i + 2);
|
|
9268
|
-
const newline = source.indexOf(`
|
|
9269
|
-
`, i + 2);
|
|
9270
|
-
if (close !== -1 && (newline === -1 || close < newline)) {
|
|
9271
|
-
const regionEnd = close + 2;
|
|
9272
|
-
masked += pushPlaceholder(placeholders, source.slice(i, regionEnd), sentinels);
|
|
9273
|
-
i = regionEnd;
|
|
9348
|
+
const kind = matchDirectiveKind(source, i);
|
|
9349
|
+
if (kind !== null && depths[i] > 0) {
|
|
9350
|
+
const match = tryParseInnermostDirective(source, i, kind);
|
|
9351
|
+
if (match !== null) {
|
|
9352
|
+
result += evaluateDirective(kind, match);
|
|
9353
|
+
i = match.end;
|
|
9354
|
+
replaced = true;
|
|
9274
9355
|
continue;
|
|
9275
9356
|
}
|
|
9276
9357
|
}
|
|
9277
|
-
|
|
9278
|
-
|
|
9279
|
-
|
|
9280
|
-
|
|
9281
|
-
|
|
9282
|
-
|
|
9283
|
-
|
|
9284
|
-
|
|
9285
|
-
|
|
9358
|
+
result += source[i];
|
|
9359
|
+
i++;
|
|
9360
|
+
}
|
|
9361
|
+
return replaced ? result : source;
|
|
9362
|
+
}
|
|
9363
|
+
function matchDirectiveKind(source, i) {
|
|
9364
|
+
if (!source.startsWith("[[#", i))
|
|
9365
|
+
return null;
|
|
9366
|
+
if (source.startsWith("ifexpr", i + 3) && !isIdentChar(source[i + 9])) {
|
|
9367
|
+
return "ifexpr";
|
|
9368
|
+
}
|
|
9369
|
+
if (source.startsWith("if", i + 3) && !isIdentChar(source[i + 5])) {
|
|
9370
|
+
return "if";
|
|
9371
|
+
}
|
|
9372
|
+
if (source.startsWith("expr", i + 3) && !isIdentChar(source[i + 7])) {
|
|
9373
|
+
return "expr";
|
|
9374
|
+
}
|
|
9375
|
+
return null;
|
|
9376
|
+
}
|
|
9377
|
+
function tryParseInnermostDirective(source, start, kind) {
|
|
9378
|
+
const keywordLen = kind === "ifexpr" ? 6 : kind === "expr" ? 4 : 2;
|
|
9379
|
+
let pos = start + 3 + keywordLen;
|
|
9380
|
+
while (pos < source.length && isWhitespace(source[pos]))
|
|
9381
|
+
pos++;
|
|
9382
|
+
const headStart = pos;
|
|
9383
|
+
let blockDepth = 0;
|
|
9384
|
+
let linkDepth = 0;
|
|
9385
|
+
const pipes = [];
|
|
9386
|
+
let closeStart = -1;
|
|
9387
|
+
while (pos < source.length) {
|
|
9388
|
+
if (matchDirectiveKind(source, pos) !== null) {
|
|
9389
|
+
return null;
|
|
9390
|
+
}
|
|
9391
|
+
if (source.startsWith("[[[", pos)) {
|
|
9392
|
+
linkDepth++;
|
|
9393
|
+
pos += 3;
|
|
9394
|
+
continue;
|
|
9395
|
+
}
|
|
9396
|
+
if (linkDepth > 0 && source.startsWith("]]]", pos)) {
|
|
9397
|
+
linkDepth--;
|
|
9398
|
+
pos += 3;
|
|
9399
|
+
continue;
|
|
9400
|
+
}
|
|
9401
|
+
if (linkDepth > 0) {
|
|
9402
|
+
pos++;
|
|
9403
|
+
continue;
|
|
9404
|
+
}
|
|
9405
|
+
if (source.startsWith("[[", pos)) {
|
|
9406
|
+
blockDepth++;
|
|
9407
|
+
pos += 2;
|
|
9408
|
+
continue;
|
|
9409
|
+
}
|
|
9410
|
+
if (source.startsWith("]]", pos)) {
|
|
9411
|
+
if (blockDepth === 0) {
|
|
9412
|
+
closeStart = pos;
|
|
9413
|
+
break;
|
|
9286
9414
|
}
|
|
9415
|
+
blockDepth--;
|
|
9416
|
+
pos += 2;
|
|
9417
|
+
continue;
|
|
9287
9418
|
}
|
|
9288
|
-
|
|
9289
|
-
|
|
9419
|
+
if (source[pos] === "|" && blockDepth === 0 && linkDepth === 0) {
|
|
9420
|
+
pipes.push(pos);
|
|
9421
|
+
}
|
|
9422
|
+
pos++;
|
|
9290
9423
|
}
|
|
9291
|
-
|
|
9424
|
+
if (closeStart === -1)
|
|
9425
|
+
return null;
|
|
9426
|
+
const hasPipe = pipes.length > 0;
|
|
9427
|
+
if (!hasPipe && (kind === "if" || kind === "ifexpr"))
|
|
9428
|
+
return null;
|
|
9429
|
+
let head;
|
|
9430
|
+
let thenText = "";
|
|
9431
|
+
let elseText = "";
|
|
9432
|
+
if (!hasPipe) {
|
|
9433
|
+
head = source.slice(headStart, closeStart).trim();
|
|
9434
|
+
} else {
|
|
9435
|
+
head = source.slice(headStart, pipes[0]).trim();
|
|
9436
|
+
if (pipes.length >= 2) {
|
|
9437
|
+
thenText = source.slice(pipes[0] + 1, pipes[1]).trim();
|
|
9438
|
+
elseText = source.slice(pipes[1] + 1, closeStart).trim();
|
|
9439
|
+
} else {
|
|
9440
|
+
thenText = source.slice(pipes[0] + 1, closeStart).trim();
|
|
9441
|
+
}
|
|
9442
|
+
}
|
|
9443
|
+
return {
|
|
9444
|
+
end: closeStart + 2,
|
|
9445
|
+
head,
|
|
9446
|
+
thenText,
|
|
9447
|
+
elseText,
|
|
9448
|
+
hasPipe
|
|
9449
|
+
};
|
|
9292
9450
|
}
|
|
9293
|
-
function
|
|
9294
|
-
|
|
9295
|
-
|
|
9296
|
-
|
|
9451
|
+
function evaluateDirective(kind, m) {
|
|
9452
|
+
if (kind === "expr") {
|
|
9453
|
+
const result2 = evaluateExpression(m.head);
|
|
9454
|
+
if (result2.success)
|
|
9455
|
+
return formatExprValue(result2.value);
|
|
9456
|
+
if (result2.error === "empty expression")
|
|
9457
|
+
return "";
|
|
9458
|
+
return "ERROR";
|
|
9459
|
+
}
|
|
9460
|
+
if (kind === "if") {
|
|
9461
|
+
if (!m.hasPipe)
|
|
9462
|
+
return "";
|
|
9463
|
+
return isTruthy(m.head) ? m.thenText : m.elseText;
|
|
9464
|
+
}
|
|
9465
|
+
if (!m.hasPipe)
|
|
9466
|
+
return "";
|
|
9467
|
+
const result = evaluateExpression(m.head);
|
|
9468
|
+
if (!result.success)
|
|
9469
|
+
return "ERROR";
|
|
9470
|
+
return result.value !== 0 && !Number.isNaN(result.value) ? m.thenText : m.elseText;
|
|
9297
9471
|
}
|
|
9298
|
-
function
|
|
9299
|
-
return
|
|
9472
|
+
function isWhitespace(ch) {
|
|
9473
|
+
return ch === " " || ch === "\t" || ch === `
|
|
9474
|
+
` || ch === "\r";
|
|
9300
9475
|
}
|
|
9301
|
-
function
|
|
9302
|
-
|
|
9303
|
-
|
|
9476
|
+
function isIdentChar(ch) {
|
|
9477
|
+
if (!ch)
|
|
9478
|
+
return false;
|
|
9479
|
+
return /[a-z0-9_-]/i.test(ch);
|
|
9304
9480
|
}
|
|
9305
9481
|
|
|
9306
9482
|
// packages/parser/src/parser/parse.ts
|
|
@@ -9411,7 +9587,8 @@ class Parser {
|
|
|
9411
9587
|
}
|
|
9412
9588
|
}
|
|
9413
9589
|
function parse(source, options) {
|
|
9414
|
-
const
|
|
9590
|
+
const ifProcessed = preprocessExpr(source);
|
|
9591
|
+
const iftagsProcessed = options?.pageTags !== undefined ? preprocessIftags(ifProcessed, options.pageTags) : ifProcessed;
|
|
9415
9592
|
const preprocessed = preprocess(iftagsProcessed);
|
|
9416
9593
|
const tokens = tokenize(preprocessed, { trackPositions: options?.trackPositions });
|
|
9417
9594
|
return new Parser(tokens, options).parse();
|
|
@@ -10383,15 +10560,23 @@ async function resolveIncludesAsync(source, fetcher, options) {
|
|
|
10383
10560
|
return expandIterativeAsync(source, cachedFetcher, maxIterations);
|
|
10384
10561
|
}
|
|
10385
10562
|
var INCLUDE_OPEN_PATTERN = /^\[\[include\s/gim;
|
|
10563
|
+
function hasAttributes(innerSoFar) {
|
|
10564
|
+
if (innerSoFar.includes("|"))
|
|
10565
|
+
return true;
|
|
10566
|
+
const trimmed = innerSoFar.trimStart();
|
|
10567
|
+
const ws = trimmed.search(/\s/);
|
|
10568
|
+
if (ws === -1)
|
|
10569
|
+
return false;
|
|
10570
|
+
return trimmed.slice(ws).trim().length > 0;
|
|
10571
|
+
}
|
|
10386
10572
|
function isRestOfLineBlank(source, pos) {
|
|
10387
10573
|
for (let i = pos;i < source.length; i++) {
|
|
10388
10574
|
const ch = source[i];
|
|
10389
10575
|
if (ch === `
|
|
10390
10576
|
`)
|
|
10391
10577
|
return true;
|
|
10392
|
-
if (ch
|
|
10393
|
-
|
|
10394
|
-
return false;
|
|
10578
|
+
if (ch !== " " && ch !== "\t" && ch !== "\r")
|
|
10579
|
+
return false;
|
|
10395
10580
|
}
|
|
10396
10581
|
return true;
|
|
10397
10582
|
}
|
|
@@ -10425,6 +10610,12 @@ function scanIncludeDirectives(source) {
|
|
|
10425
10610
|
depth--;
|
|
10426
10611
|
i += 2;
|
|
10427
10612
|
if (depth <= 0) {
|
|
10613
|
+
const innerSoFar = source.slice(contentStart, closeStart);
|
|
10614
|
+
if (hasAttributes(innerSoFar)) {
|
|
10615
|
+
while (i < source.length && source[i] === "]") {
|
|
10616
|
+
i++;
|
|
10617
|
+
}
|
|
10618
|
+
}
|
|
10428
10619
|
const onOpenerLine = firstNewline === -1 || closeStart < firstNewline;
|
|
10429
10620
|
if (onOpenerLine || isRestOfLineBlank(source, i)) {
|
|
10430
10621
|
closeEnd = i;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wdprlib/parser",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"description": "Parser for Wikidot markup",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ast",
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
"directory": "packages/parser"
|
|
16
16
|
},
|
|
17
17
|
"files": [
|
|
18
|
-
"dist"
|
|
18
|
+
"dist",
|
|
19
|
+
"src"
|
|
19
20
|
],
|
|
20
21
|
"type": "module",
|
|
21
22
|
"sideEffects": false,
|
|
@@ -24,6 +25,7 @@
|
|
|
24
25
|
"types": "./dist/index.d.ts",
|
|
25
26
|
"exports": {
|
|
26
27
|
".": {
|
|
28
|
+
"bun": "./src/index.ts",
|
|
27
29
|
"import": {
|
|
28
30
|
"types": "./dist/index.d.ts",
|
|
29
31
|
"default": "./dist/index.js"
|
|
@@ -39,6 +41,6 @@
|
|
|
39
41
|
},
|
|
40
42
|
"dependencies": {
|
|
41
43
|
"@braintree/sanitize-url": "^7.1.1",
|
|
42
|
-
"@wdprlib/ast": "2.
|
|
44
|
+
"@wdprlib/ast": "2.1.0"
|
|
43
45
|
}
|
|
44
46
|
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wikidot markup parser.
|
|
3
|
+
*
|
|
4
|
+
* This package converts Wikidot wikitext source into an abstract syntax
|
|
5
|
+
* tree (AST) defined by `@wdprlib/ast`. It also provides module-resolution
|
|
6
|
+
* utilities for dynamic constructs such as `[[module ListPages]]`,
|
|
7
|
+
* `[[module ListUsers]]`, `[[include]]`, and `[[iftags]]`.
|
|
8
|
+
*
|
|
9
|
+
* Typical usage:
|
|
10
|
+
*
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { parse } from "@wdprlib/parser";
|
|
13
|
+
*
|
|
14
|
+
* const { ast, diagnostics } = parse("**bold** and //italic//");
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* For server-side module resolution, see {@link extractDataRequirements},
|
|
18
|
+
* {@link resolveModules}, and {@link resolveIncludes}.
|
|
19
|
+
*
|
|
20
|
+
* @packageDocumentation
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
// Re-export AST types and utilities from @wdprlib/ast
|
|
24
|
+
export type {
|
|
25
|
+
Position,
|
|
26
|
+
Point,
|
|
27
|
+
Version,
|
|
28
|
+
Element,
|
|
29
|
+
SyntaxTree,
|
|
30
|
+
ContainerType,
|
|
31
|
+
ContainerData,
|
|
32
|
+
AttributeMap,
|
|
33
|
+
VariableMap,
|
|
34
|
+
Alignment,
|
|
35
|
+
LinkType,
|
|
36
|
+
LinkLocation,
|
|
37
|
+
LinkLabel,
|
|
38
|
+
PageRef,
|
|
39
|
+
ImageSource,
|
|
40
|
+
FloatAlignment,
|
|
41
|
+
ListType,
|
|
42
|
+
ListItem,
|
|
43
|
+
ListData,
|
|
44
|
+
CodeBlockData,
|
|
45
|
+
TabData,
|
|
46
|
+
TableCell,
|
|
47
|
+
TableRow,
|
|
48
|
+
TableData,
|
|
49
|
+
DefinitionListItem,
|
|
50
|
+
Module,
|
|
51
|
+
CollapsibleData,
|
|
52
|
+
ClearFloat,
|
|
53
|
+
AnchorTarget,
|
|
54
|
+
HeaderType,
|
|
55
|
+
AlignType,
|
|
56
|
+
HeadingLevel,
|
|
57
|
+
Heading,
|
|
58
|
+
DateItem,
|
|
59
|
+
Embed,
|
|
60
|
+
TocEntry,
|
|
61
|
+
// Diagnostics
|
|
62
|
+
Diagnostic,
|
|
63
|
+
DiagnosticSeverity,
|
|
64
|
+
ParseResult,
|
|
65
|
+
} from "@wdprlib/ast";
|
|
66
|
+
export {
|
|
67
|
+
createPoint,
|
|
68
|
+
createPosition,
|
|
69
|
+
text,
|
|
70
|
+
container,
|
|
71
|
+
paragraph,
|
|
72
|
+
bold,
|
|
73
|
+
italics,
|
|
74
|
+
heading,
|
|
75
|
+
lineBreak,
|
|
76
|
+
horizontalRule,
|
|
77
|
+
link,
|
|
78
|
+
list,
|
|
79
|
+
listItemElements,
|
|
80
|
+
listItemSubList,
|
|
81
|
+
} from "@wdprlib/ast";
|
|
82
|
+
|
|
83
|
+
// Wikitext settings (re-exported from @wdprlib/ast)
|
|
84
|
+
export type { WikitextMode, WikitextSettings } from "@wdprlib/ast";
|
|
85
|
+
export { createSettings, DEFAULT_SETTINGS } from "@wdprlib/ast";
|
|
86
|
+
|
|
87
|
+
// Lexer
|
|
88
|
+
export type { TokenType, Token, LexerOptions } from "./lexer";
|
|
89
|
+
export { Lexer, tokenize, createToken } from "./lexer";
|
|
90
|
+
|
|
91
|
+
// Parser
|
|
92
|
+
export type { ParserOptions } from "./parser";
|
|
93
|
+
export { Parser, parse } from "./parser";
|
|
94
|
+
|
|
95
|
+
// Modules (ListPages, ListUsers, IfTags, Include, etc.)
|
|
96
|
+
export type {
|
|
97
|
+
// ListPages query types
|
|
98
|
+
ListPagesQuery,
|
|
99
|
+
ListPagesVariable,
|
|
100
|
+
// Data requirement types
|
|
101
|
+
ListPagesDataRequirement,
|
|
102
|
+
DataRequirements,
|
|
103
|
+
// External data types
|
|
104
|
+
UserInfo,
|
|
105
|
+
PageData,
|
|
106
|
+
SiteContext,
|
|
107
|
+
ListPagesExternalData,
|
|
108
|
+
// Callback types
|
|
109
|
+
ListPagesDataFetcher,
|
|
110
|
+
DataProvider,
|
|
111
|
+
// Template types
|
|
112
|
+
VariableContext,
|
|
113
|
+
CompiledTemplate,
|
|
114
|
+
// Extraction types
|
|
115
|
+
ExtractionResult,
|
|
116
|
+
// Resolution types
|
|
117
|
+
ParseFunction,
|
|
118
|
+
ResolveOptions,
|
|
119
|
+
// Include resolution
|
|
120
|
+
IncludeFetcher,
|
|
121
|
+
AsyncIncludeFetcher,
|
|
122
|
+
ResolveIncludesOptions,
|
|
123
|
+
// ListUsers types
|
|
124
|
+
ListUsersVariable,
|
|
125
|
+
ListUsersUserData,
|
|
126
|
+
ListUsersDataRequirement,
|
|
127
|
+
ListUsersExternalData,
|
|
128
|
+
ListUsersDataFetcher,
|
|
129
|
+
ListUsersVariableContext,
|
|
130
|
+
ListUsersCompiledTemplate,
|
|
131
|
+
// Normalized query types
|
|
132
|
+
NormalizedListPagesQuery,
|
|
133
|
+
NormalizedTags,
|
|
134
|
+
NormalizedCategory,
|
|
135
|
+
NormalizedOrder,
|
|
136
|
+
NormalizedParent,
|
|
137
|
+
NormalizedDateSelector,
|
|
138
|
+
NormalizedNumericSelector,
|
|
139
|
+
} from "./parser/rules/block/module/index";
|
|
140
|
+
export {
|
|
141
|
+
extractDataRequirements,
|
|
142
|
+
resolveModules,
|
|
143
|
+
STYLE_SLOT_PREFIX,
|
|
144
|
+
compileTemplate,
|
|
145
|
+
// Include resolution
|
|
146
|
+
resolveIncludes,
|
|
147
|
+
resolveIncludesAsync,
|
|
148
|
+
// IfTags source-level preprocessing (run between include expansion and parse)
|
|
149
|
+
preprocessIftags,
|
|
150
|
+
// Query normalization (for advanced use cases)
|
|
151
|
+
normalizeQuery,
|
|
152
|
+
parseTags,
|
|
153
|
+
parseCategory,
|
|
154
|
+
parseOrder,
|
|
155
|
+
parseParent,
|
|
156
|
+
parseDateSelector,
|
|
157
|
+
parseNumericSelector,
|
|
158
|
+
// ListUsers
|
|
159
|
+
extractListUsersVariables,
|
|
160
|
+
compileListUsersTemplate,
|
|
161
|
+
isListUsersModule,
|
|
162
|
+
resolveListUsers,
|
|
163
|
+
} from "./parser/rules/block/module/index";
|