@wdprlib/render 1.4.0 → 2.1.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 +126 -393
- package/dist/index.js +117 -384
- package/package.json +5 -3
- package/src/context.ts +422 -0
- package/src/elements/bibliography.ts +123 -0
- package/src/elements/clear-float.ts +27 -0
- package/src/elements/code.ts +49 -0
- package/src/elements/collapsible.ts +105 -0
- package/src/elements/color.ts +32 -0
- package/src/elements/container.ts +302 -0
- package/src/elements/date.ts +59 -0
- package/src/elements/embed-block.ts +327 -0
- package/src/elements/embed.ts +166 -0
- package/src/elements/expr.ts +102 -0
- package/src/elements/footnote.ts +76 -0
- package/src/elements/html.ts +79 -0
- package/src/elements/iframe.ts +44 -0
- package/src/elements/iftags.ts +118 -0
- package/src/elements/image.ts +154 -0
- package/src/elements/include.ts +43 -0
- package/src/elements/index.ts +35 -0
- package/src/elements/line-break.ts +22 -0
- package/src/elements/link.ts +201 -0
- package/src/elements/list.ts +241 -0
- package/src/elements/math.ts +177 -0
- package/src/elements/module/backlinks.ts +28 -0
- package/src/elements/module/categories.ts +27 -0
- package/src/elements/module/index.ts +67 -0
- package/src/elements/module/join.ts +33 -0
- package/src/elements/module/listpages.ts +27 -0
- package/src/elements/module/listusers.ts +27 -0
- package/src/elements/module/page-tree.ts +27 -0
- package/src/elements/module/rate.ts +44 -0
- package/src/elements/tab-view.ts +75 -0
- package/src/elements/table.ts +101 -0
- package/src/elements/text.ts +57 -0
- package/src/elements/toc.ts +147 -0
- package/src/elements/user.ts +79 -0
- package/src/escape.ts +829 -0
- package/src/hash.ts +62 -0
- package/src/index.ts +26 -0
- package/src/libs/highlighter/engine.ts +352 -0
- package/src/libs/highlighter/index.ts +70 -0
- package/src/libs/highlighter/languages/cpp.ts +345 -0
- package/src/libs/highlighter/languages/css.ts +104 -0
- package/src/libs/highlighter/languages/diff.ts +154 -0
- package/src/libs/highlighter/languages/dtd.ts +99 -0
- package/src/libs/highlighter/languages/html.ts +59 -0
- package/src/libs/highlighter/languages/java.ts +251 -0
- package/src/libs/highlighter/languages/javascript.ts +213 -0
- package/src/libs/highlighter/languages/php.ts +433 -0
- package/src/libs/highlighter/languages/python.ts +308 -0
- package/src/libs/highlighter/languages/ruby.ts +360 -0
- package/src/libs/highlighter/languages/sql.ts +125 -0
- package/src/libs/highlighter/languages/xml.ts +68 -0
- package/src/libs/highlighter/types.ts +44 -0
- package/src/render.ts +231 -0
- package/src/types.ts +140 -0
package/dist/index.cjs
CHANGED
|
@@ -44,14 +44,14 @@ var __export = (target, all) => {
|
|
|
44
44
|
var exports_src = {};
|
|
45
45
|
__export(exports_src, {
|
|
46
46
|
renderToHtml: () => renderToHtml,
|
|
47
|
-
createSettings: () =>
|
|
48
|
-
DEFAULT_SETTINGS: () =>
|
|
47
|
+
createSettings: () => import_ast5.createSettings,
|
|
48
|
+
DEFAULT_SETTINGS: () => import_ast5.DEFAULT_SETTINGS,
|
|
49
49
|
DEFAULT_EMBED_ALLOWLIST: () => DEFAULT_EMBED_ALLOWLIST
|
|
50
50
|
});
|
|
51
51
|
module.exports = __toCommonJS(exports_src);
|
|
52
52
|
|
|
53
53
|
// packages/render/src/render.ts
|
|
54
|
-
var
|
|
54
|
+
var import_ast4 = require("@wdprlib/ast");
|
|
55
55
|
|
|
56
56
|
// packages/render/src/context.ts
|
|
57
57
|
var import_ast = require("@wdprlib/ast");
|
|
@@ -356,10 +356,76 @@ function normalizeCssValue(value) {
|
|
|
356
356
|
result = result.replace(/[\s\u0000-\u001f\u007f-\u009f]/g, "");
|
|
357
357
|
return result.toLowerCase();
|
|
358
358
|
}
|
|
359
|
+
function isUrlAllowed(rawUrl) {
|
|
360
|
+
let url = rawUrl;
|
|
361
|
+
if (url.length >= 2) {
|
|
362
|
+
const first = url[0];
|
|
363
|
+
const last = url[url.length - 1];
|
|
364
|
+
if (first === '"' && last === '"' || first === "'" && last === "'") {
|
|
365
|
+
url = url.slice(1, -1);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
if (url === "")
|
|
369
|
+
return true;
|
|
370
|
+
if (url.startsWith("#"))
|
|
371
|
+
return true;
|
|
372
|
+
if (url.startsWith("./") || url.startsWith("../"))
|
|
373
|
+
return true;
|
|
374
|
+
if (url.startsWith("//"))
|
|
375
|
+
return true;
|
|
376
|
+
if (url.startsWith("/"))
|
|
377
|
+
return true;
|
|
378
|
+
if (url.startsWith("http://") || url.startsWith("https://"))
|
|
379
|
+
return true;
|
|
380
|
+
if (url.startsWith("data:image/")) {
|
|
381
|
+
const after = url.slice("data:image/".length);
|
|
382
|
+
const sep = Math.min(after.indexOf(";") === -1 ? after.length : after.indexOf(";"), after.indexOf(",") === -1 ? after.length : after.indexOf(","));
|
|
383
|
+
const mime = after.slice(0, sep);
|
|
384
|
+
if (mime === "png" || mime === "jpeg" || mime === "jpg" || mime === "gif" || mime === "webp") {
|
|
385
|
+
return true;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
return false;
|
|
389
|
+
}
|
|
390
|
+
function* iterateUrls(normalized) {
|
|
391
|
+
let searchPos = 0;
|
|
392
|
+
while (searchPos < normalized.length) {
|
|
393
|
+
const idx = normalized.indexOf("url(", searchPos);
|
|
394
|
+
if (idx === -1)
|
|
395
|
+
return;
|
|
396
|
+
let depth = 1;
|
|
397
|
+
let quoteChar = null;
|
|
398
|
+
let i = idx + 4;
|
|
399
|
+
while (i < normalized.length && depth > 0) {
|
|
400
|
+
const ch = normalized[i];
|
|
401
|
+
if (quoteChar !== null) {
|
|
402
|
+
if (ch === quoteChar)
|
|
403
|
+
quoteChar = null;
|
|
404
|
+
} else if (ch === '"' || ch === "'") {
|
|
405
|
+
quoteChar = ch;
|
|
406
|
+
} else if (ch === "(") {
|
|
407
|
+
depth++;
|
|
408
|
+
} else if (ch === ")") {
|
|
409
|
+
depth--;
|
|
410
|
+
}
|
|
411
|
+
i++;
|
|
412
|
+
}
|
|
413
|
+
if (depth > 0) {
|
|
414
|
+
yield { inner: normalized.slice(idx + 4), malformed: true };
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
yield { inner: normalized.slice(idx + 4, i - 1), malformed: false };
|
|
418
|
+
searchPos = i;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
359
421
|
function isDangerousCssValue(value) {
|
|
360
422
|
const normalized = normalizeCssValue(value);
|
|
361
|
-
|
|
362
|
-
|
|
423
|
+
for (const { inner, malformed } of iterateUrls(normalized)) {
|
|
424
|
+
if (malformed)
|
|
425
|
+
return true;
|
|
426
|
+
if (!isUrlAllowed(inner))
|
|
427
|
+
return true;
|
|
428
|
+
}
|
|
363
429
|
if (normalized.includes("expression("))
|
|
364
430
|
return true;
|
|
365
431
|
if (normalized.includes("-moz-binding"))
|
|
@@ -370,21 +436,61 @@ function isDangerousCssValue(value) {
|
|
|
370
436
|
return true;
|
|
371
437
|
return false;
|
|
372
438
|
}
|
|
439
|
+
function splitDeclarations(style) {
|
|
440
|
+
const out = [];
|
|
441
|
+
let buf = "";
|
|
442
|
+
let parenDepth = 0;
|
|
443
|
+
let quoteChar = null;
|
|
444
|
+
for (const ch of style) {
|
|
445
|
+
if (quoteChar !== null) {
|
|
446
|
+
buf += ch;
|
|
447
|
+
if (ch === quoteChar)
|
|
448
|
+
quoteChar = null;
|
|
449
|
+
continue;
|
|
450
|
+
}
|
|
451
|
+
if (ch === '"' || ch === "'") {
|
|
452
|
+
quoteChar = ch;
|
|
453
|
+
buf += ch;
|
|
454
|
+
continue;
|
|
455
|
+
}
|
|
456
|
+
if (ch === "(") {
|
|
457
|
+
parenDepth++;
|
|
458
|
+
buf += ch;
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
461
|
+
if (ch === ")") {
|
|
462
|
+
if (parenDepth > 0)
|
|
463
|
+
parenDepth--;
|
|
464
|
+
buf += ch;
|
|
465
|
+
continue;
|
|
466
|
+
}
|
|
467
|
+
if (ch === ";" && parenDepth === 0) {
|
|
468
|
+
out.push(buf);
|
|
469
|
+
buf = "";
|
|
470
|
+
continue;
|
|
471
|
+
}
|
|
472
|
+
buf += ch;
|
|
473
|
+
}
|
|
474
|
+
if (buf.length > 0)
|
|
475
|
+
out.push(buf);
|
|
476
|
+
return out;
|
|
477
|
+
}
|
|
373
478
|
function sanitizeStyleValue(style) {
|
|
374
479
|
const endsWithSemicolon = style.trimEnd().endsWith(";");
|
|
375
|
-
const declarations = style
|
|
480
|
+
const declarations = splitDeclarations(style).map((d) => d.trim()).filter(Boolean);
|
|
376
481
|
const safe = [];
|
|
377
482
|
for (const decl of declarations) {
|
|
378
483
|
const colonIdx = decl.indexOf(":");
|
|
379
484
|
if (colonIdx === -1)
|
|
380
485
|
continue;
|
|
381
|
-
const property = decl.slice(0, colonIdx).trim()
|
|
486
|
+
const property = decl.slice(0, colonIdx).trim();
|
|
382
487
|
const value = decl.slice(colonIdx + 1).trim();
|
|
383
488
|
if (isDangerousCssValue(value))
|
|
384
489
|
continue;
|
|
385
|
-
|
|
490
|
+
const normalisedProperty = normalizeCssValue(property);
|
|
491
|
+
if (normalisedProperty.startsWith("-moz-binding"))
|
|
386
492
|
continue;
|
|
387
|
-
if (
|
|
493
|
+
if (normalisedProperty === "behavior")
|
|
388
494
|
continue;
|
|
389
495
|
safe.push(decl);
|
|
390
496
|
}
|
|
@@ -4610,6 +4716,9 @@ function generateDefaultUrl(pageName, contents) {
|
|
|
4610
4716
|
return path;
|
|
4611
4717
|
}
|
|
4612
4718
|
function renderHtmlBlock(ctx, data) {
|
|
4719
|
+
if (ctx.settings.allowHtmlBlocks === false) {
|
|
4720
|
+
return;
|
|
4721
|
+
}
|
|
4613
4722
|
const index = ctx.nextHtmlBlockIndex();
|
|
4614
4723
|
const pageName = ctx.page?.pageName ?? "";
|
|
4615
4724
|
const callbackUrl = ctx.options.resolvers?.htmlBlockUrl?.(index);
|
|
@@ -4712,392 +4821,22 @@ function formatDate(date, format) {
|
|
|
4712
4821
|
return format.replace(/%Y/g, String(date.getFullYear())).replace(/%m/g, String(date.getMonth() + 1).padStart(2, "0")).replace(/%d/g, String(date.getDate()).padStart(2, "0")).replace(/%H/g, String(date.getHours()).padStart(2, "0")).replace(/%M/g, String(date.getMinutes()).padStart(2, "0")).replace(/%S/g, String(date.getSeconds()).padStart(2, "0"));
|
|
4713
4822
|
}
|
|
4714
4823
|
|
|
4715
|
-
// packages/render/src/utils/expr-eval.ts
|
|
4716
|
-
var FALSE_VALUES = new Set(["false", "null", "", "0"]);
|
|
4717
|
-
function isTruthy(value) {
|
|
4718
|
-
return !FALSE_VALUES.has(value.toLowerCase().trim());
|
|
4719
|
-
}
|
|
4720
|
-
var MAX_EXPRESSION_LENGTH = 256;
|
|
4721
|
-
function isTruthyNum(n) {
|
|
4722
|
-
return n !== 0 && !Number.isNaN(n);
|
|
4723
|
-
}
|
|
4724
|
-
function evaluateExpression(expr) {
|
|
4725
|
-
try {
|
|
4726
|
-
if (expr.length > MAX_EXPRESSION_LENGTH) {
|
|
4727
|
-
return { success: false, error: "expression too long" };
|
|
4728
|
-
}
|
|
4729
|
-
if (expr.trim() === "") {
|
|
4730
|
-
return { success: false, error: "empty expression" };
|
|
4731
|
-
}
|
|
4732
|
-
const tokens = tokenize2(expr);
|
|
4733
|
-
if (tokens.length <= 1) {
|
|
4734
|
-
return { success: false, error: "empty expression" };
|
|
4735
|
-
}
|
|
4736
|
-
const parser = new ExprParser(tokens);
|
|
4737
|
-
const result = parser.parse();
|
|
4738
|
-
if (!Number.isFinite(result)) {
|
|
4739
|
-
return { success: false, error: "division by zero" };
|
|
4740
|
-
}
|
|
4741
|
-
return { success: true, value: result };
|
|
4742
|
-
} catch (e) {
|
|
4743
|
-
const msg = e instanceof Error ? e.message : "unknown error";
|
|
4744
|
-
return { success: false, error: msg };
|
|
4745
|
-
}
|
|
4746
|
-
}
|
|
4747
|
-
function tokenize2(expr) {
|
|
4748
|
-
const tokens = [];
|
|
4749
|
-
let i = 0;
|
|
4750
|
-
while (i < expr.length) {
|
|
4751
|
-
const ch = expr[i];
|
|
4752
|
-
if (/\s/.test(ch)) {
|
|
4753
|
-
i++;
|
|
4754
|
-
continue;
|
|
4755
|
-
}
|
|
4756
|
-
if (/\d/.test(ch) || ch === "." && /\d/.test(expr[i + 1] ?? "")) {
|
|
4757
|
-
let numStr = "";
|
|
4758
|
-
let hasDot = false;
|
|
4759
|
-
while (i < expr.length) {
|
|
4760
|
-
const c = expr[i];
|
|
4761
|
-
if (c === ".") {
|
|
4762
|
-
if (hasDot)
|
|
4763
|
-
break;
|
|
4764
|
-
hasDot = true;
|
|
4765
|
-
} else if (!/\d/.test(c)) {
|
|
4766
|
-
break;
|
|
4767
|
-
}
|
|
4768
|
-
numStr += c;
|
|
4769
|
-
i++;
|
|
4770
|
-
}
|
|
4771
|
-
const num = parseFloat(numStr);
|
|
4772
|
-
if (!Number.isFinite(num)) {
|
|
4773
|
-
throw new Error("Invalid number");
|
|
4774
|
-
}
|
|
4775
|
-
tokens.push({ kind: "NUMBER", value: num });
|
|
4776
|
-
continue;
|
|
4777
|
-
}
|
|
4778
|
-
if (/[a-zA-Z_]/.test(ch)) {
|
|
4779
|
-
let id = "";
|
|
4780
|
-
while (i < expr.length) {
|
|
4781
|
-
const c = expr[i];
|
|
4782
|
-
if (!/[a-zA-Z0-9_]/.test(c))
|
|
4783
|
-
break;
|
|
4784
|
-
id += c;
|
|
4785
|
-
i++;
|
|
4786
|
-
}
|
|
4787
|
-
tokens.push({ kind: "IDENTIFIER", value: id.toLowerCase() });
|
|
4788
|
-
continue;
|
|
4789
|
-
}
|
|
4790
|
-
if (ch === "<" && expr[i + 1] === "=") {
|
|
4791
|
-
tokens.push({ kind: "LE", value: "<=" });
|
|
4792
|
-
i += 2;
|
|
4793
|
-
continue;
|
|
4794
|
-
}
|
|
4795
|
-
if (ch === ">" && expr[i + 1] === "=") {
|
|
4796
|
-
tokens.push({ kind: "GE", value: ">=" });
|
|
4797
|
-
i += 2;
|
|
4798
|
-
continue;
|
|
4799
|
-
}
|
|
4800
|
-
if (ch === "!" && expr[i + 1] === "=") {
|
|
4801
|
-
tokens.push({ kind: "NE", value: "!=" });
|
|
4802
|
-
i += 2;
|
|
4803
|
-
continue;
|
|
4804
|
-
}
|
|
4805
|
-
if (ch === "<" && expr[i + 1] === ">") {
|
|
4806
|
-
tokens.push({ kind: "NE", value: "<>" });
|
|
4807
|
-
i += 2;
|
|
4808
|
-
continue;
|
|
4809
|
-
}
|
|
4810
|
-
switch (ch) {
|
|
4811
|
-
case "+":
|
|
4812
|
-
tokens.push({ kind: "PLUS", value: "+" });
|
|
4813
|
-
break;
|
|
4814
|
-
case "-":
|
|
4815
|
-
tokens.push({ kind: "MINUS", value: "-" });
|
|
4816
|
-
break;
|
|
4817
|
-
case "*":
|
|
4818
|
-
tokens.push({ kind: "STAR", value: "*" });
|
|
4819
|
-
break;
|
|
4820
|
-
case "/":
|
|
4821
|
-
tokens.push({ kind: "SLASH", value: "/" });
|
|
4822
|
-
break;
|
|
4823
|
-
case "%":
|
|
4824
|
-
tokens.push({ kind: "PERCENT", value: "%" });
|
|
4825
|
-
break;
|
|
4826
|
-
case "^":
|
|
4827
|
-
tokens.push({ kind: "CARET", value: "^" });
|
|
4828
|
-
break;
|
|
4829
|
-
case "(":
|
|
4830
|
-
tokens.push({ kind: "LPAREN", value: "(" });
|
|
4831
|
-
break;
|
|
4832
|
-
case ")":
|
|
4833
|
-
tokens.push({ kind: "RPAREN", value: ")" });
|
|
4834
|
-
break;
|
|
4835
|
-
case ",":
|
|
4836
|
-
tokens.push({ kind: "COMMA", value: "," });
|
|
4837
|
-
break;
|
|
4838
|
-
case "<":
|
|
4839
|
-
tokens.push({ kind: "LT", value: "<" });
|
|
4840
|
-
break;
|
|
4841
|
-
case ">":
|
|
4842
|
-
tokens.push({ kind: "GT", value: ">" });
|
|
4843
|
-
break;
|
|
4844
|
-
case "=":
|
|
4845
|
-
tokens.push({ kind: "EQ", value: "=" });
|
|
4846
|
-
break;
|
|
4847
|
-
default:
|
|
4848
|
-
throw new Error(`Unknown character: ${ch}`);
|
|
4849
|
-
}
|
|
4850
|
-
i++;
|
|
4851
|
-
}
|
|
4852
|
-
tokens.push({ kind: "EOF", value: "" });
|
|
4853
|
-
return tokens;
|
|
4854
|
-
}
|
|
4855
|
-
|
|
4856
|
-
class ExprParser {
|
|
4857
|
-
tokens;
|
|
4858
|
-
pos = 0;
|
|
4859
|
-
constructor(tokens) {
|
|
4860
|
-
this.tokens = tokens;
|
|
4861
|
-
}
|
|
4862
|
-
parse() {
|
|
4863
|
-
const result = this.parseOr();
|
|
4864
|
-
if (this.current().kind !== "EOF") {
|
|
4865
|
-
throw new Error("too many values in the stack");
|
|
4866
|
-
}
|
|
4867
|
-
return result;
|
|
4868
|
-
}
|
|
4869
|
-
current() {
|
|
4870
|
-
return this.tokens[this.pos] ?? { kind: "EOF", value: "" };
|
|
4871
|
-
}
|
|
4872
|
-
advance() {
|
|
4873
|
-
const token = this.current();
|
|
4874
|
-
this.pos++;
|
|
4875
|
-
return token;
|
|
4876
|
-
}
|
|
4877
|
-
parseOr() {
|
|
4878
|
-
let left = this.parseAnd();
|
|
4879
|
-
while (this.current().kind === "IDENTIFIER" && this.current().value === "or") {
|
|
4880
|
-
this.advance();
|
|
4881
|
-
const right = this.parseAnd();
|
|
4882
|
-
left = isTruthyNum(left) || isTruthyNum(right) ? 1 : 0;
|
|
4883
|
-
}
|
|
4884
|
-
return left;
|
|
4885
|
-
}
|
|
4886
|
-
parseAnd() {
|
|
4887
|
-
let left = this.parseNot();
|
|
4888
|
-
while (this.current().kind === "IDENTIFIER" && this.current().value === "and") {
|
|
4889
|
-
this.advance();
|
|
4890
|
-
const right = this.parseNot();
|
|
4891
|
-
left = isTruthyNum(left) && isTruthyNum(right) ? 1 : 0;
|
|
4892
|
-
}
|
|
4893
|
-
return left;
|
|
4894
|
-
}
|
|
4895
|
-
parseNot() {
|
|
4896
|
-
if (this.current().kind === "IDENTIFIER" && this.current().value === "not") {
|
|
4897
|
-
this.advance();
|
|
4898
|
-
const value = this.parseNot();
|
|
4899
|
-
return isTruthyNum(value) ? 0 : 1;
|
|
4900
|
-
}
|
|
4901
|
-
return this.parseComparison();
|
|
4902
|
-
}
|
|
4903
|
-
parseComparison() {
|
|
4904
|
-
let left = this.parseAddition();
|
|
4905
|
-
const kind = this.current().kind;
|
|
4906
|
-
if (kind === "LT" || kind === "GT" || kind === "LE" || kind === "GE" || kind === "EQ" || kind === "NE") {
|
|
4907
|
-
this.advance();
|
|
4908
|
-
const right = this.parseAddition();
|
|
4909
|
-
switch (kind) {
|
|
4910
|
-
case "LT":
|
|
4911
|
-
return left < right ? 1 : 0;
|
|
4912
|
-
case "GT":
|
|
4913
|
-
return left > right ? 1 : 0;
|
|
4914
|
-
case "LE":
|
|
4915
|
-
return left <= right ? 1 : 0;
|
|
4916
|
-
case "GE":
|
|
4917
|
-
return left >= right ? 1 : 0;
|
|
4918
|
-
case "EQ":
|
|
4919
|
-
return left === right ? 1 : 0;
|
|
4920
|
-
case "NE":
|
|
4921
|
-
return left !== right ? 1 : 0;
|
|
4922
|
-
}
|
|
4923
|
-
}
|
|
4924
|
-
return left;
|
|
4925
|
-
}
|
|
4926
|
-
parseAddition() {
|
|
4927
|
-
let left = this.parseMultiplication();
|
|
4928
|
-
while (true) {
|
|
4929
|
-
const kind = this.current().kind;
|
|
4930
|
-
if (kind === "PLUS") {
|
|
4931
|
-
this.advance();
|
|
4932
|
-
left = left + this.parseMultiplication();
|
|
4933
|
-
} else if (kind === "MINUS") {
|
|
4934
|
-
this.advance();
|
|
4935
|
-
left = left - this.parseMultiplication();
|
|
4936
|
-
} else {
|
|
4937
|
-
break;
|
|
4938
|
-
}
|
|
4939
|
-
}
|
|
4940
|
-
return left;
|
|
4941
|
-
}
|
|
4942
|
-
parseMultiplication() {
|
|
4943
|
-
let left = this.parsePower();
|
|
4944
|
-
while (true) {
|
|
4945
|
-
const kind = this.current().kind;
|
|
4946
|
-
if (kind === "STAR") {
|
|
4947
|
-
this.advance();
|
|
4948
|
-
left = left * this.parsePower();
|
|
4949
|
-
} else if (kind === "SLASH") {
|
|
4950
|
-
this.advance();
|
|
4951
|
-
left = left / this.parsePower();
|
|
4952
|
-
} else if (kind === "PERCENT") {
|
|
4953
|
-
this.advance();
|
|
4954
|
-
left = left % this.parsePower();
|
|
4955
|
-
} else {
|
|
4956
|
-
break;
|
|
4957
|
-
}
|
|
4958
|
-
}
|
|
4959
|
-
return left;
|
|
4960
|
-
}
|
|
4961
|
-
parsePower() {
|
|
4962
|
-
const left = this.parseUnary();
|
|
4963
|
-
if (this.current().kind === "CARET") {
|
|
4964
|
-
this.advance();
|
|
4965
|
-
const right = this.parsePower();
|
|
4966
|
-
return Math.pow(left, right);
|
|
4967
|
-
}
|
|
4968
|
-
return left;
|
|
4969
|
-
}
|
|
4970
|
-
parseUnary() {
|
|
4971
|
-
const kind = this.current().kind;
|
|
4972
|
-
if (kind === "MINUS") {
|
|
4973
|
-
this.advance();
|
|
4974
|
-
return -this.parseUnary();
|
|
4975
|
-
}
|
|
4976
|
-
if (kind === "PLUS") {
|
|
4977
|
-
this.advance();
|
|
4978
|
-
return +this.parseUnary();
|
|
4979
|
-
}
|
|
4980
|
-
return this.parsePrimary();
|
|
4981
|
-
}
|
|
4982
|
-
parsePrimary() {
|
|
4983
|
-
const token = this.current();
|
|
4984
|
-
if (token.kind === "NUMBER") {
|
|
4985
|
-
this.advance();
|
|
4986
|
-
return token.value;
|
|
4987
|
-
}
|
|
4988
|
-
if (token.kind === "LPAREN") {
|
|
4989
|
-
this.advance();
|
|
4990
|
-
const value = this.parseOr();
|
|
4991
|
-
if (this.current().kind !== "RPAREN") {
|
|
4992
|
-
throw new Error("Expected )");
|
|
4993
|
-
}
|
|
4994
|
-
this.advance();
|
|
4995
|
-
return value;
|
|
4996
|
-
}
|
|
4997
|
-
if (token.kind === "IDENTIFIER") {
|
|
4998
|
-
const name = token.value;
|
|
4999
|
-
this.advance();
|
|
5000
|
-
if (this.current().kind === "LPAREN") {
|
|
5001
|
-
return this.parseFunctionCall(name);
|
|
5002
|
-
}
|
|
5003
|
-
throw new Error(`undefined constant "${name}"`);
|
|
5004
|
-
}
|
|
5005
|
-
throw new Error("Expected expression");
|
|
5006
|
-
}
|
|
5007
|
-
parseFunctionCall(name) {
|
|
5008
|
-
if (this.current().kind !== "LPAREN") {
|
|
5009
|
-
throw new Error("Expected (");
|
|
5010
|
-
}
|
|
5011
|
-
this.advance();
|
|
5012
|
-
const args = [];
|
|
5013
|
-
if (this.current().kind !== "RPAREN") {
|
|
5014
|
-
args.push(this.parseOr());
|
|
5015
|
-
while (this.current().kind === "COMMA") {
|
|
5016
|
-
this.advance();
|
|
5017
|
-
args.push(this.parseOr());
|
|
5018
|
-
}
|
|
5019
|
-
}
|
|
5020
|
-
if (this.current().kind !== "RPAREN") {
|
|
5021
|
-
throw new Error("Expected )");
|
|
5022
|
-
}
|
|
5023
|
-
this.advance();
|
|
5024
|
-
return this.callFunction(name, args);
|
|
5025
|
-
}
|
|
5026
|
-
callFunction(name, args) {
|
|
5027
|
-
switch (name) {
|
|
5028
|
-
case "abs":
|
|
5029
|
-
this.checkArgs(name, args, 1);
|
|
5030
|
-
return Math.abs(args[0]);
|
|
5031
|
-
case "min":
|
|
5032
|
-
this.checkArgsMin(name, args, 1);
|
|
5033
|
-
return Math.min(...args);
|
|
5034
|
-
case "max":
|
|
5035
|
-
this.checkArgsMin(name, args, 1);
|
|
5036
|
-
return Math.max(...args);
|
|
5037
|
-
case "floor":
|
|
5038
|
-
this.checkArgs(name, args, 1);
|
|
5039
|
-
return Math.floor(args[0]);
|
|
5040
|
-
case "ceil":
|
|
5041
|
-
this.checkArgs(name, args, 1);
|
|
5042
|
-
return Math.ceil(args[0]);
|
|
5043
|
-
case "round":
|
|
5044
|
-
this.checkArgs(name, args, 1);
|
|
5045
|
-
return Math.round(args[0]);
|
|
5046
|
-
case "sqrt":
|
|
5047
|
-
this.checkArgs(name, args, 1);
|
|
5048
|
-
return Math.sqrt(args[0]);
|
|
5049
|
-
case "sin":
|
|
5050
|
-
this.checkArgs(name, args, 1);
|
|
5051
|
-
return Math.sin(args[0]);
|
|
5052
|
-
case "cos":
|
|
5053
|
-
this.checkArgs(name, args, 1);
|
|
5054
|
-
return Math.cos(args[0]);
|
|
5055
|
-
case "tan":
|
|
5056
|
-
this.checkArgs(name, args, 1);
|
|
5057
|
-
return Math.tan(args[0]);
|
|
5058
|
-
case "ln":
|
|
5059
|
-
this.checkArgs(name, args, 1);
|
|
5060
|
-
return Math.log(args[0]);
|
|
5061
|
-
case "log":
|
|
5062
|
-
this.checkArgs(name, args, 1);
|
|
5063
|
-
return Math.log10(args[0]);
|
|
5064
|
-
case "exp":
|
|
5065
|
-
this.checkArgs(name, args, 1);
|
|
5066
|
-
return Math.exp(args[0]);
|
|
5067
|
-
case "pow":
|
|
5068
|
-
this.checkArgs(name, args, 2);
|
|
5069
|
-
return Math.pow(args[0], args[1]);
|
|
5070
|
-
default:
|
|
5071
|
-
throw new Error(`undefined function "${name}"`);
|
|
5072
|
-
}
|
|
5073
|
-
}
|
|
5074
|
-
checkArgs(name, args, expected) {
|
|
5075
|
-
if (args.length !== expected) {
|
|
5076
|
-
throw new Error(`${name}() expects ${expected} argument(s), got ${args.length}`);
|
|
5077
|
-
}
|
|
5078
|
-
}
|
|
5079
|
-
checkArgsMin(name, args, min) {
|
|
5080
|
-
if (args.length < min) {
|
|
5081
|
-
throw new Error(`${name}() expects at least ${min} argument(s), got ${args.length}`);
|
|
5082
|
-
}
|
|
5083
|
-
}
|
|
5084
|
-
}
|
|
5085
|
-
|
|
5086
4824
|
// packages/render/src/elements/expr.ts
|
|
4825
|
+
var import_ast3 = require("@wdprlib/ast");
|
|
5087
4826
|
function renderExpr(ctx, data) {
|
|
5088
|
-
const result = evaluateExpression(data.expression);
|
|
4827
|
+
const result = import_ast3.evaluateExpression(data.expression);
|
|
5089
4828
|
if (result.success) {
|
|
5090
|
-
ctx.pushEscaped(
|
|
4829
|
+
ctx.pushEscaped(import_ast3.formatExprValue(result.value));
|
|
5091
4830
|
} else if (result.error !== "empty expression") {
|
|
5092
4831
|
ctx.pushEscaped(`run-time error: ${result.error}`);
|
|
5093
4832
|
}
|
|
5094
4833
|
}
|
|
5095
4834
|
function renderIf(ctx, data) {
|
|
5096
|
-
const elements = isTruthy(data.condition) ? data.then : data.else;
|
|
4835
|
+
const elements = import_ast3.isTruthy(data.condition) ? data.then : data.else;
|
|
5097
4836
|
renderBranchElements(ctx, elements);
|
|
5098
4837
|
}
|
|
5099
4838
|
function renderIfExpr(ctx, data) {
|
|
5100
|
-
const result = evaluateExpression(data.expression);
|
|
4839
|
+
const result = import_ast3.evaluateExpression(data.expression);
|
|
5101
4840
|
if (!result.success) {
|
|
5102
4841
|
ctx.pushEscaped(`run-time error: ${result.error}`);
|
|
5103
4842
|
return;
|
|
@@ -5117,12 +4856,6 @@ function renderBranchElements(ctx, elements) {
|
|
|
5117
4856
|
}
|
|
5118
4857
|
renderElements(ctx, elements.slice(0, lastIdx + 1));
|
|
5119
4858
|
}
|
|
5120
|
-
function formatNumber(n) {
|
|
5121
|
-
if (Number.isInteger(n)) {
|
|
5122
|
-
return String(n);
|
|
5123
|
-
}
|
|
5124
|
-
return n.toFixed(6).replace(/\.?0+$/, "");
|
|
5125
|
-
}
|
|
5126
4859
|
|
|
5127
4860
|
// packages/render/src/render.ts
|
|
5128
4861
|
function renderToHtml(tree, options = {}) {
|
|
@@ -5130,8 +4863,8 @@ function renderToHtml(tree, options = {}) {
|
|
|
5130
4863
|
renderElements(ctx, tree.elements);
|
|
5131
4864
|
if (ctx.settings.allowStyleElements && tree.styles?.length) {
|
|
5132
4865
|
for (const style of tree.styles) {
|
|
5133
|
-
if (style.startsWith(
|
|
5134
|
-
const slotId = parseInt(style.slice(
|
|
4866
|
+
if (style.startsWith(import_ast4.STYLE_SLOT_PREFIX)) {
|
|
4867
|
+
const slotId = parseInt(style.slice(import_ast4.STYLE_SLOT_PREFIX.length), 10);
|
|
5135
4868
|
for (const css of ctx.getStyleSlotContents(slotId)) {
|
|
5136
4869
|
ctx.push(`<style>${escapeStyleContent(css)}</style>`);
|
|
5137
4870
|
}
|
|
@@ -5288,4 +5021,4 @@ function renderElement(ctx, element) {
|
|
|
5288
5021
|
}
|
|
5289
5022
|
|
|
5290
5023
|
// packages/render/src/index.ts
|
|
5291
|
-
var
|
|
5024
|
+
var import_ast5 = require("@wdprlib/ast");
|