JSX: Allow for one level of nested curly braces inside tag attribute value. Fix #1335
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
diff --git a/components/prism-jsx.js b/components/prism-jsx.js
index 4b59cfb..b4530a2 100644
--- a/components/prism-jsx.js
+++ b/components/prism-jsx.js
@@ -3,7 +3,7 @@
var javascript = Prism.util.clone(Prism.languages.javascript);
Prism.languages.jsx = Prism.languages.extend('markup', javascript);
-Prism.languages.jsx.tag.pattern= /<\/?[\w.:-]+\s*(?:\s+(?:[\w.:-]+(?:=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+|(?:\{\{?[^}]*\}?\})))?|\{\.{3}[a-z_$][\w$]*(?:\.[a-z_$][\w$]*)*\}))*\s*\/?>/i;
+Prism.languages.jsx.tag.pattern= /<\/?[\w.:-]+\s*(?:\s+(?:[\w.:-]+(?:=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s{'">=]+|\{(?:\{[^}]+\}|[^{}])+\}))?|\{\.{3}[a-z_$][\w$]*(?:\.[a-z_$][\w$]*)*\}))*\s*\/?>/i;
Prism.languages.jsx.tag.inside['attr-value'].pattern = /=(?!\{)(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">]+)/i;
diff --git a/components/prism-jsx.min.js b/components/prism-jsx.min.js
index 7f696af..0704816 100644
--- a/components/prism-jsx.min.js
+++ b/components/prism-jsx.min.js
@@ -1 +1 @@
-!function(a){var e=a.util.clone(a.languages.javascript);a.languages.jsx=a.languages.extend("markup",e),a.languages.jsx.tag.pattern=/<\/?[\w.:-]+\s*(?:\s+(?:[\w.:-]+(?:=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+|(?:\{\{?[^}]*\}?\})))?|\{\.{3}[a-z_$][\w$]*(?:\.[a-z_$][\w$]*)*\}))*\s*\/?>/i,a.languages.jsx.tag.inside["attr-value"].pattern=/=(?!\{)(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">]+)/i,a.languages.insertBefore("inside","attr-name",{spread:{pattern:/\{\.{3}[a-z_$][\w$]*(?:\.[a-z_$][\w$]*)*\}/,inside:{punctuation:/\.{3}|[{}.]/,"attr-value":/\w+/}}},a.languages.jsx.tag);var s=a.util.clone(a.languages.jsx);delete s.punctuation,s=a.languages.insertBefore("jsx","operator",{punctuation:/=(?={)|[{}[\];(),.:]/},{jsx:s}),a.languages.insertBefore("inside","attr-value",{script:{pattern:/=(\{(?:\{[^}]*\}|[^}])+\})/i,inside:s,alias:"language-javascript"}},a.languages.jsx.tag)}(Prism);
\ No newline at end of file
+!function(a){var e=a.util.clone(a.languages.javascript);a.languages.jsx=a.languages.extend("markup",e),a.languages.jsx.tag.pattern=/<\/?[\w.:-]+\s*(?:\s+(?:[\w.:-]+(?:=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s{'">=]+|\{(?:\{[^}]+\}|[^{}])+\}))?|\{\.{3}[a-z_$][\w$]*(?:\.[a-z_$][\w$]*)*\}))*\s*\/?>/i,a.languages.jsx.tag.inside["attr-value"].pattern=/=(?!\{)(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">]+)/i,a.languages.insertBefore("inside","attr-name",{spread:{pattern:/\{\.{3}[a-z_$][\w$]*(?:\.[a-z_$][\w$]*)*\}/,inside:{punctuation:/\.{3}|[{}.]/,"attr-value":/\w+/}}},a.languages.jsx.tag);var s=a.util.clone(a.languages.jsx);delete s.punctuation,s=a.languages.insertBefore("jsx","operator",{punctuation:/=(?={)|[{}[\];(),.:]/},{jsx:s}),a.languages.insertBefore("inside","attr-value",{script:{pattern:/=(\{(?:\{[^}]*\}|[^}])+\})/i,inside:s,alias:"language-javascript"}},a.languages.jsx.tag)}(Prism);
\ No newline at end of file
diff --git a/tests/languages/jsx/issue1335.test b/tests/languages/jsx/issue1335.test
new file mode 100644
index 0000000..9de5749
--- /dev/null
+++ b/tests/languages/jsx/issue1335.test
@@ -0,0 +1,124 @@
+<Button onClick={(e) => this.setState({clicked: true})} />
+<Component
+ data={[
+ {id: 0, name: 'Joe'},
+ {id: 1, name: 'Sue'},
+ ]}
+/>
+<Component title={`${name}`} />
+<Component title={`${name}'s page`} />
+
+----------------------------------------------------
+
+[
+ ["tag", [
+ ["tag", [
+ ["punctuation", "<"],
+ "Button"
+ ]],
+ ["attr-name", ["onClick"]],
+ ["script", [
+ ["punctuation", "="],
+ ["punctuation", "{"],
+ ["punctuation", "("],
+ "e",
+ ["punctuation", ")"],
+ ["operator", "=>"],
+ ["keyword", "this"],
+ ["punctuation", "."],
+ ["function", "setState"],
+ ["punctuation", "("],
+ ["punctuation", "{"],
+ "clicked",
+ ["punctuation", ":"],
+ ["boolean", "true"],
+ ["punctuation", "}"],
+ ["punctuation", ")"],
+ ["punctuation", "}"]
+ ]],
+ ["punctuation", "/>"]
+ ]],
+ ["tag", [
+ ["tag", [
+ ["punctuation", "<"],
+ "Component"
+ ]],
+ ["attr-name", ["data"]],
+ ["script", [
+ ["punctuation", "="],
+ ["punctuation", "{"],
+ ["punctuation", "["],
+ ["punctuation", "{"],
+ "id",
+ ["punctuation", ":"],
+ ["number", "0"],
+ ["punctuation", ","],
+ " name",
+ ["punctuation", ":"],
+ ["string", "'Joe'"],
+ ["punctuation", "}"],
+ ["punctuation", ","],
+ ["punctuation", "{"],
+ "id",
+ ["punctuation", ":"],
+ ["number", "1"],
+ ["punctuation", ","],
+ " name",
+ ["punctuation", ":"],
+ ["string", "'Sue'"],
+ ["punctuation", "}"],
+ ["punctuation", ","],
+ ["punctuation", "]"],
+ ["punctuation", "}"]
+ ]],
+ ["punctuation", "/>"]
+ ]],
+ ["tag", [
+ ["tag", [
+ ["punctuation", "<"],
+ "Component"
+ ]],
+ ["attr-name", ["title"]],
+ ["script", [
+ ["punctuation", "="],
+ ["punctuation", "{"],
+ ["template-string", [
+ ["string", "`"],
+ ["interpolation", [
+ ["interpolation-punctuation", "${"],
+ "name",
+ ["interpolation-punctuation", "}"]
+ ]],
+ ["string", "`"]
+ ]],
+ ["punctuation", "}"]
+ ]],
+ ["punctuation", "/>"]
+ ]],
+ ["tag", [
+ ["tag", [
+ ["punctuation", "<"],
+ "Component"
+ ]],
+ ["attr-name", ["title"]],
+ ["script", [
+ ["punctuation", "="],
+ ["punctuation", "{"],
+ ["template-string", [
+ ["string", "`"],
+ ["interpolation", [
+ ["interpolation-punctuation", "${"],
+ "name",
+ ["interpolation-punctuation", "}"]
+ ]],
+ ["string", "'s page`"]
+ ]],
+ ["punctuation", "}"]
+ ]],
+ ["punctuation", "/>"]
+ ]]
+]
+
+----------------------------------------------------
+
+Handles nested pairs of curly braces inside tag attribute. See #1335
\ No newline at end of file