babel-plugin-jsx-dom-expressions 0.40.10 → 0.40.14
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/index.js +168 -30
- package/package.json +2 -2
package/index.js
CHANGED
|
@@ -321,6 +321,49 @@ const SVGElements = /*#__PURE__*/new Set([
|
|
|
321
321
|
"vkern"]);
|
|
322
322
|
|
|
323
323
|
|
|
324
|
+
const MathMLElements = /*#__PURE__*/new Set([
|
|
325
|
+
"annotation",
|
|
326
|
+
"annotation-xml",
|
|
327
|
+
"maction",
|
|
328
|
+
"math",
|
|
329
|
+
"menclose",
|
|
330
|
+
"merror",
|
|
331
|
+
"mfenced",
|
|
332
|
+
"mfrac",
|
|
333
|
+
"mi",
|
|
334
|
+
"mmultiscripts",
|
|
335
|
+
"mn",
|
|
336
|
+
"mo",
|
|
337
|
+
"mover",
|
|
338
|
+
"mpadded",
|
|
339
|
+
"mphantom",
|
|
340
|
+
"mprescripts",
|
|
341
|
+
"mroot",
|
|
342
|
+
"mrow",
|
|
343
|
+
"ms",
|
|
344
|
+
"mspace",
|
|
345
|
+
"msqrt",
|
|
346
|
+
"mstyle",
|
|
347
|
+
"msub",
|
|
348
|
+
"msubsup",
|
|
349
|
+
"msup",
|
|
350
|
+
"mtable",
|
|
351
|
+
"mtd",
|
|
352
|
+
"mtext",
|
|
353
|
+
"mtr",
|
|
354
|
+
"munder",
|
|
355
|
+
"munderover",
|
|
356
|
+
"semantics"]);
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
const MathMLTextIntegrationPoints = /*#__PURE__*/new Set([
|
|
360
|
+
"mi",
|
|
361
|
+
"mo",
|
|
362
|
+
"mn",
|
|
363
|
+
"ms",
|
|
364
|
+
"mtext"]);
|
|
365
|
+
|
|
366
|
+
|
|
324
367
|
const SVGNamespace = {
|
|
325
368
|
xlink: "http://www.w3.org/1999/xlink",
|
|
326
369
|
xml: "http://www.w3.org/XML/1998/namespace"
|
|
@@ -409,6 +452,58 @@ function isComponent(tagName) {
|
|
|
409
452
|
|
|
410
453
|
}
|
|
411
454
|
|
|
455
|
+
// <annotation-xml> is a MathML HTML integration point only when its encoding
|
|
456
|
+
// is text/html or application/xhtml+xml
|
|
457
|
+
function isHTMLEncodingAnnotationXML(node) {
|
|
458
|
+
const encoding = node.openingElement.attributes.find(
|
|
459
|
+
(attr) => t__namespace.isJSXAttribute(attr) && t__namespace.isJSXIdentifier(attr.name) && attr.name.name === "encoding");
|
|
460
|
+
|
|
461
|
+
return (
|
|
462
|
+
t__namespace.isStringLiteral(encoding?.value) &&
|
|
463
|
+
/^(?:text\/html|application\/xhtml\+xml)$/i.test(encoding.value.value));
|
|
464
|
+
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// <script> and <style> are only raw text in HTML. Inside SVG or MathML the
|
|
468
|
+
// parser decodes entities and treats `<` as markup, so their children still
|
|
469
|
+
// need escaping. Integration points (<foreignObject> in SVG; the MathML text
|
|
470
|
+
// integration points and <annotation-xml> with an HTML encoding in MathML)
|
|
471
|
+
// switch their content back to HTML parsing.
|
|
472
|
+
function isRawTextElement(path) {
|
|
473
|
+
const tagName = getTagName(path.node);
|
|
474
|
+
if (tagName !== "script" && tagName !== "style") return false;
|
|
475
|
+
const ancestors = [];
|
|
476
|
+
let parent = path.parentPath;
|
|
477
|
+
while (t__namespace.isJSXElement(parent.node)) {
|
|
478
|
+
if (isComponent(getTagName(parent.node))) break;
|
|
479
|
+
ancestors.push(parent.node);
|
|
480
|
+
parent = parent.parentPath;
|
|
481
|
+
}
|
|
482
|
+
const rootTag = ancestors.length ? getTagName(ancestors[ancestors.length - 1]) : undefined;
|
|
483
|
+
// a top-level SVG element is parsed inside an <svg> wrapper and a top-level
|
|
484
|
+
// MathML element inside a MathML template
|
|
485
|
+
let namespace = SVGElements.has(rootTag) ?
|
|
486
|
+
"svg" :
|
|
487
|
+
MathMLElements.has(rootTag) ?
|
|
488
|
+
"math" :
|
|
489
|
+
"html";
|
|
490
|
+
for (let i = ancestors.length - 1; i >= 0; i--) {
|
|
491
|
+
const parentTag = getTagName(ancestors[i]);
|
|
492
|
+
if (namespace === "html") {
|
|
493
|
+
if (parentTag === "svg") namespace = "svg";else
|
|
494
|
+
if (parentTag === "math") namespace = "math";
|
|
495
|
+
} else if (namespace === "svg") {
|
|
496
|
+
if (parentTag === "foreignObject") namespace = "html";
|
|
497
|
+
} else if (
|
|
498
|
+
MathMLTextIntegrationPoints.has(parentTag) ||
|
|
499
|
+
parentTag === "annotation-xml" && isHTMLEncodingAnnotationXML(ancestors[i]))
|
|
500
|
+
{
|
|
501
|
+
namespace = "html";
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
return namespace === "html";
|
|
505
|
+
}
|
|
506
|
+
|
|
412
507
|
function hasStaticMarker(object, path) {
|
|
413
508
|
if (!object) return false;
|
|
414
509
|
if (
|
|
@@ -1901,6 +1996,7 @@ function findLastElement(children, hydratable) {
|
|
|
1901
1996
|
function transformChildren$2(path, results, config) {
|
|
1902
1997
|
let tempPath = results.id && results.id.name,
|
|
1903
1998
|
tagName = getTagName(path.node),
|
|
1999
|
+
doNotEscape = isRawTextElement(path),
|
|
1904
2000
|
nextPlaceholder,
|
|
1905
2001
|
childPostExprs = [],
|
|
1906
2002
|
i = 0;
|
|
@@ -1913,6 +2009,7 @@ function transformChildren$2(path, results, config) {
|
|
|
1913
2009
|
|
|
1914
2010
|
}
|
|
1915
2011
|
const transformed = transformNode(child, {
|
|
2012
|
+
doNotEscape,
|
|
1916
2013
|
toBeClosed: results.toBeClosed,
|
|
1917
2014
|
lastElement: index === lastElement,
|
|
1918
2015
|
skipId: !results.id || !detectExpressions(filteredChildren, index, config)
|
|
@@ -2542,7 +2639,7 @@ function transformElement$2(path, info) {
|
|
|
2542
2639
|
|
|
2543
2640
|
const config = getConfig(path);
|
|
2544
2641
|
const tagName = getTagName(path.node);
|
|
2545
|
-
if (
|
|
2642
|
+
if (isRawTextElement(path)) path.doNotEscape = true;
|
|
2546
2643
|
|
|
2547
2644
|
// contains spread attributes
|
|
2548
2645
|
if (path.node.openingElement.attributes.some((a) => t__namespace.isJSXSpreadAttribute(a)))
|
|
@@ -2625,26 +2722,38 @@ function setAttr$1(attribute, results, name, value, isSVG) {
|
|
|
2625
2722
|
}
|
|
2626
2723
|
}
|
|
2627
2724
|
|
|
2628
|
-
|
|
2725
|
+
/**
|
|
2726
|
+
* How `escapeExpression` treats a string literal it reaches.
|
|
2727
|
+
* - `undefined`: the hole itself. The caller escapes a literal when it
|
|
2728
|
+
* inlines it into the template, so it stays as written here.
|
|
2729
|
+
* - `"escape"`: a position whose value the runtime writes as is.
|
|
2730
|
+
* - `"keep"`: inside a function value in an attribute. `ssrAttribute`
|
|
2731
|
+
* stringifies the function's source, so literals stay as written.
|
|
2732
|
+
*/
|
|
2733
|
+
function escapeExpression(path, expression, attr, literals) {
|
|
2734
|
+
if (!expression) return expression;
|
|
2735
|
+
// A literal in a branch is the hole's value, which `ssr` and
|
|
2736
|
+
// `ssrAttribute` write as is, so branches escape literals.
|
|
2737
|
+
const branch = literals === "keep" ? "keep" : "escape";
|
|
2738
|
+
// A function's returns escape like branches, except for a function value in
|
|
2739
|
+
// an attribute: `ssrAttribute` stringifies its source, so its literals stay
|
|
2740
|
+
// as written at every depth.
|
|
2741
|
+
const returns = literals === undefined && attr ? "keep" : branch;
|
|
2629
2742
|
if (
|
|
2630
2743
|
t__namespace.isStringLiteral(expression) ||
|
|
2631
2744
|
t__namespace.isNumericLiteral(expression) ||
|
|
2632
2745
|
t__namespace.isTemplateLiteral(expression) && expression.expressions.length === 0)
|
|
2633
2746
|
{
|
|
2634
|
-
if (
|
|
2747
|
+
if (literals === "escape") {
|
|
2635
2748
|
if (t__namespace.isStringLiteral(expression)) return t__namespace.stringLiteral(escapeHTML(expression.value, attr));else
|
|
2636
2749
|
if (t__namespace.isTemplateLiteral(expression))
|
|
2637
|
-
return t__namespace.stringLiteral(
|
|
2750
|
+
return t__namespace.stringLiteral(
|
|
2751
|
+
escapeHTML(expression.quasis[0].value.cooked ?? expression.quasis[0].value.raw, attr));
|
|
2752
|
+
|
|
2638
2753
|
}
|
|
2639
2754
|
return expression;
|
|
2640
2755
|
} else if (t__namespace.isFunction(expression)) {
|
|
2641
|
-
|
|
2642
|
-
expression.body.body = expression.body.body.map((e) => {
|
|
2643
|
-
if (t__namespace.isReturnStatement(e))
|
|
2644
|
-
e.argument = escapeExpression(path, e.argument, attr, escapeLiterals);
|
|
2645
|
-
return e;
|
|
2646
|
-
});
|
|
2647
|
-
} else expression.body = escapeExpression(path, expression.body, attr, escapeLiterals);
|
|
2756
|
+
escapeFunctionResult(path, expression, attr, returns);
|
|
2648
2757
|
return expression;
|
|
2649
2758
|
} else if (t__namespace.isTemplateLiteral(expression)) {
|
|
2650
2759
|
// Interpolations are escaped recursively. The static quasis are not —
|
|
@@ -2652,35 +2761,30 @@ function escapeExpression(path, expression, attr, escapeLiterals) {
|
|
|
2652
2761
|
// attr="...", which HTML parses as attribute injection.
|
|
2653
2762
|
if (attr) escapeTemplateQuasis(expression, true);
|
|
2654
2763
|
expression.expressions = expression.expressions.map((e) =>
|
|
2655
|
-
escapeExpression(path, e, attr,
|
|
2764
|
+
escapeExpression(path, e, attr, literals));
|
|
2656
2765
|
|
|
2657
2766
|
return expression;
|
|
2658
2767
|
} else if (t__namespace.isUnaryExpression(expression)) {
|
|
2659
2768
|
return expression;
|
|
2660
2769
|
} else if (t__namespace.isBinaryExpression(expression)) {
|
|
2661
|
-
expression.left = escapeExpression(path, expression.left, attr,
|
|
2662
|
-
expression.right = escapeExpression(path, expression.right, attr,
|
|
2770
|
+
expression.left = escapeExpression(path, expression.left, attr, literals);
|
|
2771
|
+
expression.right = escapeExpression(path, expression.right, attr, literals);
|
|
2663
2772
|
return expression;
|
|
2664
2773
|
} else if (t__namespace.isConditionalExpression(expression)) {
|
|
2665
|
-
expression.consequent = escapeExpression(path, expression.consequent, attr,
|
|
2666
|
-
expression.alternate = escapeExpression(path, expression.alternate, attr,
|
|
2774
|
+
expression.consequent = escapeExpression(path, expression.consequent, attr, branch);
|
|
2775
|
+
expression.alternate = escapeExpression(path, expression.alternate, attr, branch);
|
|
2667
2776
|
return expression;
|
|
2668
2777
|
} else if (t__namespace.isLogicalExpression(expression)) {
|
|
2669
2778
|
// Preserve the old short-circuit shape for && while still escaping the
|
|
2670
2779
|
// selected result of || and ?? as a whole.
|
|
2671
2780
|
if (expression.operator === "&&") {
|
|
2672
|
-
expression.right = escapeExpression(path, expression.right, attr,
|
|
2781
|
+
expression.right = escapeExpression(path, expression.right, attr, branch);
|
|
2673
2782
|
return expression;
|
|
2674
2783
|
}
|
|
2675
2784
|
} else if (t__namespace.isCallExpression(expression) && t__namespace.isFunction(expression.callee)) {
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
e.argument = escapeExpression(path, e.argument, attr, escapeLiterals);
|
|
2680
|
-
return e;
|
|
2681
|
-
});
|
|
2682
|
-
} else
|
|
2683
|
-
expression.callee.body = escapeExpression(path, expression.callee.body, attr, escapeLiterals);
|
|
2785
|
+
// The call's result is the hole's value, so its returns escape like
|
|
2786
|
+
// branches.
|
|
2787
|
+
escapeFunctionResult(path, expression.callee, attr, branch);
|
|
2684
2788
|
return expression;
|
|
2685
2789
|
} else if (t__namespace.isJSXElement(expression) && !isComponent(getTagName(expression))) {
|
|
2686
2790
|
expression.wontEscape = true;
|
|
@@ -2693,6 +2797,37 @@ function escapeExpression(path, expression, attr, escapeLiterals) {
|
|
|
2693
2797
|
|
|
2694
2798
|
}
|
|
2695
2799
|
|
|
2800
|
+
/** Escapes a function's expression body or its `return` arguments. */
|
|
2801
|
+
function escapeFunctionResult(path, fn, attr, literals) {
|
|
2802
|
+
if (t__namespace.isBlockStatement(fn.body)) escapeReturns(path, fn.body, attr, literals);else
|
|
2803
|
+
fn.body = escapeExpression(path, fn.body, attr, literals);
|
|
2804
|
+
}
|
|
2805
|
+
|
|
2806
|
+
/**
|
|
2807
|
+
* Escapes the `return` arguments in a statement at any depth, without
|
|
2808
|
+
* entering nested functions or classes.
|
|
2809
|
+
*/
|
|
2810
|
+
function escapeReturns(path, statement, attr, literals) {
|
|
2811
|
+
if (!statement) return;
|
|
2812
|
+
if (t__namespace.isReturnStatement(statement)) {
|
|
2813
|
+
statement.argument = escapeExpression(path, statement.argument, attr, literals);
|
|
2814
|
+
} else if (t__namespace.isBlockStatement(statement)) {
|
|
2815
|
+
for (const child of statement.body) escapeReturns(path, child, attr, literals);
|
|
2816
|
+
} else if (t__namespace.isIfStatement(statement)) {
|
|
2817
|
+
escapeReturns(path, statement.consequent, attr, literals);
|
|
2818
|
+
escapeReturns(path, statement.alternate, attr, literals);
|
|
2819
|
+
} else if (t__namespace.isSwitchStatement(statement)) {
|
|
2820
|
+
for (const switchCase of statement.cases)
|
|
2821
|
+
for (const child of switchCase.consequent) escapeReturns(path, child, attr, literals);
|
|
2822
|
+
} else if (t__namespace.isTryStatement(statement)) {
|
|
2823
|
+
escapeReturns(path, statement.block, attr, literals);
|
|
2824
|
+
escapeReturns(path, statement.handler && statement.handler.body, attr, literals);
|
|
2825
|
+
escapeReturns(path, statement.finalizer, attr, literals);
|
|
2826
|
+
} else if (t__namespace.isLoop(statement) || t__namespace.isLabeledStatement(statement) || t__namespace.isWithStatement(statement)) {
|
|
2827
|
+
escapeReturns(path, statement.body, attr, literals);
|
|
2828
|
+
}
|
|
2829
|
+
}
|
|
2830
|
+
|
|
2696
2831
|
function escapeTemplateQuasis(expression, attr) {
|
|
2697
2832
|
for (const quasi of expression.quasis) {
|
|
2698
2833
|
const src = quasi.value.cooked != null ? quasi.value.cooked : quasi.value.raw;
|
|
@@ -2841,8 +2976,11 @@ function transformAttributes$1(path, results, info) {
|
|
|
2841
2976
|
let doEscape = true;
|
|
2842
2977
|
|
|
2843
2978
|
if (key.startsWith("attr:")) key = key.replace("attr:", "");
|
|
2844
|
-
|
|
2845
|
-
|
|
2979
|
+
// preservesPitch is a boolean property, but not an HTML boolean attribute.
|
|
2980
|
+
const isBooleanAttribute =
|
|
2981
|
+
key !== "preservesPitch" && BooleanAttributes.has(toAttribute(key, isSVG));
|
|
2982
|
+
if (isBooleanAttribute || key.startsWith("bool:")) {
|
|
2983
|
+
key = toAttribute(key.replace("bool:", ""), isSVG);
|
|
2846
2984
|
results.template.push("");
|
|
2847
2985
|
const fn = t__namespace.callExpression(registerImportMethod(attribute, "ssrAttribute"), [
|
|
2848
2986
|
t__namespace.stringLiteral(key),
|
|
@@ -2865,14 +3003,14 @@ function transformAttributes$1(path, results, info) {
|
|
|
2865
3003
|
if (p.computed) {
|
|
2866
3004
|
return t__namespace.callExpression(registerImportMethod(path, "ssrStyleProperty"), [
|
|
2867
3005
|
t__namespace.binaryExpression("+", p.key, t__namespace.stringLiteral(":")),
|
|
2868
|
-
escapeExpression(path, p.value, true,
|
|
3006
|
+
escapeExpression(path, p.value, true, "escape")]);
|
|
2869
3007
|
|
|
2870
3008
|
}
|
|
2871
3009
|
return t__namespace.callExpression(registerImportMethod(path, "ssrStyleProperty"), [
|
|
2872
3010
|
t__namespace.stringLiteral(
|
|
2873
3011
|
(i ? ";" : "") + (t__namespace.isIdentifier(p.key) ? p.key.name : p.key.value) + ":"),
|
|
2874
3012
|
|
|
2875
|
-
escapeExpression(path, p.value, true,
|
|
3013
|
+
escapeExpression(path, p.value, true, "escape")]);
|
|
2876
3014
|
|
|
2877
3015
|
});
|
|
2878
3016
|
|
|
@@ -4068,7 +4206,7 @@ function transformNode(path, info = {}) {
|
|
|
4068
4206
|
info.doNotEscape ?
|
|
4069
4207
|
staticValue.toString() :
|
|
4070
4208
|
escapeHTML(staticValue.toString()) :
|
|
4071
|
-
trimWhitespace(node.extra.raw);
|
|
4209
|
+
trimWhitespace(info.doNotEscape ? node.value : node.extra.raw);
|
|
4072
4210
|
if (!text.length) return null;
|
|
4073
4211
|
const results = {
|
|
4074
4212
|
template: text,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "babel-plugin-jsx-dom-expressions",
|
|
3
3
|
"description": "A JSX to DOM plugin that wraps expressions for fine grained change detection",
|
|
4
|
-
"version": "0.40.
|
|
4
|
+
"version": "0.40.14",
|
|
5
5
|
"author": "Ryan Carniato",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -33,5 +33,5 @@
|
|
|
33
33
|
"@rollup/plugin-babel": "6.0.3",
|
|
34
34
|
"@types/babel__core": "^7.20.5"
|
|
35
35
|
},
|
|
36
|
-
"gitHead": "
|
|
36
|
+
"gitHead": "f6fecdf9e455d03cfa90aaba0323ea3d4686ada6"
|
|
37
37
|
}
|