diff --git a/packages/babel-parser/src/tokenizer/context.js b/packages/babel-parser/src/tokenizer/context.js
index 101ac725969a..8508e69bdd69 100644
--- a/packages/babel-parser/src/tokenizer/context.js
+++ b/packages/babel-parser/src/tokenizer/context.js
@@ -31,6 +31,7 @@ export const types: {
} = {
braceStatement: new TokContext("{", false),
braceExpression: new TokContext("{", true),
+ recordExpression: new TokContext("#{", true),
templateQuasi: new TokContext("${", false),
parenStatement: new TokContext("(", false),
parenExpression: new TokContext("(", true),
@@ -140,3 +141,9 @@ tt.backQuote.updateContext = function () {
tt.star.updateContext = function () {
this.state.exprAllowed = false;
};
+
+// we don't need to update context for tt.braceBarL because we do not pop context for tt.braceBarR
+tt.braceHashL.updateContext = function () {
+ this.state.context.push(types.recordExpression);
+ this.state.exprAllowed = true; /* tt.braceHashL.beforeExpr */
+};
diff --git a/packages/babel-parser/test/fixtures/experimental/record-and-tuple/as-jsx-attribute-value-bar/input.js b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/as-jsx-attribute-value-bar/input.js
new file mode 100644
index 000000000000..f325f9eb9a5d
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/as-jsx-attribute-value-bar/input.js
@@ -0,0 +1 @@
+
diff --git a/packages/babel-parser/test/fixtures/experimental/record-and-tuple/as-jsx-attribute-value-bar/options.json b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/as-jsx-attribute-value-bar/options.json
new file mode 100644
index 000000000000..663c67344986
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/as-jsx-attribute-value-bar/options.json
@@ -0,0 +1,3 @@
+{
+ "plugins": ["jsx", "flow", ["recordAndTuple", { "syntaxType": "bar" }]]
+}
diff --git a/packages/babel-parser/test/fixtures/experimental/record-and-tuple/as-jsx-attribute-value-bar/output.json b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/as-jsx-attribute-value-bar/output.json
new file mode 100644
index 000000000000..dac25261bdb0
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/as-jsx-attribute-value-bar/output.json
@@ -0,0 +1,83 @@
+{
+ "type": "File",
+ "start":0,"end":37,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":37}},
+ "program": {
+ "type": "Program",
+ "start":0,"end":37,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":37}},
+ "sourceType": "script",
+ "interpreter": null,
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "start":0,"end":37,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":37}},
+ "expression": {
+ "type": "JSXElement",
+ "start":0,"end":37,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":37}},
+ "openingElement": {
+ "type": "JSXOpeningElement",
+ "start":0,"end":30,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":30}},
+ "name": {
+ "type": "JSXIdentifier",
+ "start":1,"end":5,"loc":{"start":{"line":1,"column":1},"end":{"line":1,"column":5}},
+ "name": "Card"
+ },
+ "attributes": [
+ {
+ "type": "JSXAttribute",
+ "start":6,"end":29,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":29}},
+ "name": {
+ "type": "JSXIdentifier",
+ "start":6,"end":10,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":10}},
+ "name": "card"
+ },
+ "value": {
+ "type": "JSXExpressionContainer",
+ "start":11,"end":29,"loc":{"start":{"line":1,"column":11},"end":{"line":1,"column":29}},
+ "expression": {
+ "type": "RecordExpression",
+ "start":12,"end":28,"loc":{"start":{"line":1,"column":12},"end":{"line":1,"column":28}},
+ "properties": [
+ {
+ "type": "ObjectProperty",
+ "start":14,"end":26,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":26}},
+ "method": false,
+ "key": {
+ "type": "Identifier",
+ "start":14,"end":19,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":19},"identifierName":"title"},
+ "name": "title"
+ },
+ "computed": false,
+ "shorthand": false,
+ "value": {
+ "type": "StringLiteral",
+ "start":21,"end":26,"loc":{"start":{"line":1,"column":21},"end":{"line":1,"column":26}},
+ "extra": {
+ "rawValue": "foo",
+ "raw": "\"foo\""
+ },
+ "value": "foo"
+ }
+ }
+ ]
+ }
+ }
+ }
+ ],
+ "selfClosing": false
+ },
+ "closingElement": {
+ "type": "JSXClosingElement",
+ "start":30,"end":37,"loc":{"start":{"line":1,"column":30},"end":{"line":1,"column":37}},
+ "name": {
+ "type": "JSXIdentifier",
+ "start":32,"end":36,"loc":{"start":{"line":1,"column":32},"end":{"line":1,"column":36}},
+ "name": "Card"
+ }
+ },
+ "children": []
+ }
+ }
+ ],
+ "directives": []
+ }
+}
\ No newline at end of file
diff --git a/packages/babel-parser/test/fixtures/experimental/record-and-tuple/as-jsx-attribute-value-hash/input.js b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/as-jsx-attribute-value-hash/input.js
new file mode 100644
index 000000000000..387feb4a9ef9
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/as-jsx-attribute-value-hash/input.js
@@ -0,0 +1 @@
+
diff --git a/packages/babel-parser/test/fixtures/experimental/record-and-tuple/as-jsx-attribute-value-hash/options.json b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/as-jsx-attribute-value-hash/options.json
new file mode 100644
index 000000000000..625b0abffbc0
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/as-jsx-attribute-value-hash/options.json
@@ -0,0 +1,3 @@
+{
+ "plugins": ["jsx", "flow", ["recordAndTuple", { "syntaxType": "hash" }]]
+}
diff --git a/packages/babel-parser/test/fixtures/experimental/record-and-tuple/as-jsx-attribute-value-hash/output.json b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/as-jsx-attribute-value-hash/output.json
new file mode 100644
index 000000000000..4d775dacb9c5
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/as-jsx-attribute-value-hash/output.json
@@ -0,0 +1,83 @@
+{
+ "type": "File",
+ "start":0,"end":36,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":36}},
+ "program": {
+ "type": "Program",
+ "start":0,"end":36,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":36}},
+ "sourceType": "script",
+ "interpreter": null,
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "start":0,"end":36,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":36}},
+ "expression": {
+ "type": "JSXElement",
+ "start":0,"end":36,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":36}},
+ "openingElement": {
+ "type": "JSXOpeningElement",
+ "start":0,"end":29,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":29}},
+ "name": {
+ "type": "JSXIdentifier",
+ "start":1,"end":5,"loc":{"start":{"line":1,"column":1},"end":{"line":1,"column":5}},
+ "name": "Card"
+ },
+ "attributes": [
+ {
+ "type": "JSXAttribute",
+ "start":6,"end":28,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":28}},
+ "name": {
+ "type": "JSXIdentifier",
+ "start":6,"end":10,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":10}},
+ "name": "card"
+ },
+ "value": {
+ "type": "JSXExpressionContainer",
+ "start":11,"end":28,"loc":{"start":{"line":1,"column":11},"end":{"line":1,"column":28}},
+ "expression": {
+ "type": "RecordExpression",
+ "start":12,"end":27,"loc":{"start":{"line":1,"column":12},"end":{"line":1,"column":27}},
+ "properties": [
+ {
+ "type": "ObjectProperty",
+ "start":14,"end":26,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":26}},
+ "method": false,
+ "key": {
+ "type": "Identifier",
+ "start":14,"end":19,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":19},"identifierName":"title"},
+ "name": "title"
+ },
+ "computed": false,
+ "shorthand": false,
+ "value": {
+ "type": "StringLiteral",
+ "start":21,"end":26,"loc":{"start":{"line":1,"column":21},"end":{"line":1,"column":26}},
+ "extra": {
+ "rawValue": "foo",
+ "raw": "\"foo\""
+ },
+ "value": "foo"
+ }
+ }
+ ]
+ }
+ }
+ }
+ ],
+ "selfClosing": false
+ },
+ "closingElement": {
+ "type": "JSXClosingElement",
+ "start":29,"end":36,"loc":{"start":{"line":1,"column":29},"end":{"line":1,"column":36}},
+ "name": {
+ "type": "JSXIdentifier",
+ "start":31,"end":35,"loc":{"start":{"line":1,"column":31},"end":{"line":1,"column":35}},
+ "name": "Card"
+ }
+ },
+ "children": []
+ }
+ }
+ ],
+ "directives": []
+ }
+}
\ No newline at end of file
diff --git a/packages/babel-parser/test/fixtures/experimental/record-and-tuple/disambiguate-regex-hash/input.js b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/disambiguate-regex-hash/input.js
new file mode 100644
index 000000000000..605ff6ffa946
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/disambiguate-regex-hash/input.js
@@ -0,0 +1 @@
+(#{})/foo
diff --git a/packages/babel-parser/test/fixtures/experimental/record-and-tuple/disambiguate-regex-hash/options.json b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/disambiguate-regex-hash/options.json
new file mode 100644
index 000000000000..625b0abffbc0
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/disambiguate-regex-hash/options.json
@@ -0,0 +1,3 @@
+{
+ "plugins": ["jsx", "flow", ["recordAndTuple", { "syntaxType": "hash" }]]
+}
diff --git a/packages/babel-parser/test/fixtures/experimental/record-and-tuple/disambiguate-regex-hash/output.json b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/disambiguate-regex-hash/output.json
new file mode 100644
index 000000000000..0b986267cd22
--- /dev/null
+++ b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/disambiguate-regex-hash/output.json
@@ -0,0 +1,36 @@
+{
+ "type": "File",
+ "start":0,"end":9,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":9}},
+ "program": {
+ "type": "Program",
+ "start":0,"end":9,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":9}},
+ "sourceType": "script",
+ "interpreter": null,
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "start":0,"end":9,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":9}},
+ "expression": {
+ "type": "BinaryExpression",
+ "start":0,"end":9,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":9}},
+ "left": {
+ "type": "RecordExpression",
+ "start":1,"end":4,"loc":{"start":{"line":1,"column":1},"end":{"line":1,"column":4}},
+ "properties": [],
+ "extra": {
+ "parenthesized": true,
+ "parenStart": 0
+ }
+ },
+ "operator": "/",
+ "right": {
+ "type": "Identifier",
+ "start":6,"end":9,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":9},"identifierName":"foo"},
+ "name": "foo"
+ }
+ }
+ }
+ ],
+ "directives": []
+ }
+}
\ No newline at end of file