Added support for record and tuple syntax. (#10865)

* Added support for record and tuple syntax.

This commit adds support for both the hash #{} and bar {||}
syntaxes to babel-parser, as well as adds the supporting
babel-plugin-syntax-record-and-tuple plugin to enable support
for the syntax. Does not include any transform for records and
tuples.

* typo

* added check to ensure recordAndTuple in babel-parser

* switched to syntaxType option instead of explicit entries for each record and tuple type

* switched to using recordAndTupleSyntaxType for generator options instead of adding to node

* added tests for generator option recordAndTupleSyntaxType

* added test for record and tuple bar syntax with flow typings

* added tests for invalid/missing recordAndTuple syntaxType parser option

* fixed flowcheck errors

* fix merge with class privates in tokenizer

* Update packages/babel-parser/src/types.js

Co-Authored-By: Nicolò Ribaudo <nicolo.ribaudo@gmail.com>

* improved recordAndTuple generator error message, added tests for invalid,missing options

* updated error messages for invalid parser syntaxType option

* updated error message

* added better error messages for when the recordAndTuple syntaxType is doesn't match the syntax used

* updated record and tuple support to use new error message templates

* added recordAndTuple to missing plugin helpers

* Fix linting

Co-authored-by: Nicolò Ribaudo <nicolo.ribaudo@gmail.com>
This commit is contained in:
Rick Button 2020-03-16 18:57:44 -04:00 committed by GitHub
parent e06bf8ffdb
commit 3ce7c2e394
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
69 changed files with 2253 additions and 30 deletions

View File

@ -143,6 +143,12 @@ const pluginNameMap = {
url: "https://git.io/vb4SU",
},
},
recordAndTuple: {
syntax: {
name: "@babel/plugin-syntax-record-and-tuple",
url: "https://git.io/JvKp3",
},
},
throwExpressions: {
syntax: {
name: "@babel/plugin-syntax-throw-expressions",

View File

@ -106,6 +106,69 @@ export function ArrayExpression(node: Object) {
export { ArrayExpression as ArrayPattern };
export function RecordExpression(node: Object) {
const props = node.properties;
let startToken;
let endToken;
if (this.format.recordAndTupleSyntaxType === "bar") {
startToken = "{|";
endToken = "|}";
} else if (this.format.recordAndTupleSyntaxType === "hash") {
startToken = "#{";
endToken = "}";
} else {
throw new Error(
`The "recordAndTupleSyntaxType" generator option must be "bar" or "hash" (${JSON.stringify(
this.format.recordAndTupleSyntaxType,
)} received).`,
);
}
this.token(startToken);
this.printInnerComments(node);
if (props.length) {
this.space();
this.printList(props, node, { indent: true, statement: true });
this.space();
}
this.token(endToken);
}
export function TupleExpression(node: Object) {
const elems = node.elements;
const len = elems.length;
let startToken;
let endToken;
if (this.format.recordAndTupleSyntaxType === "bar") {
startToken = "[|";
endToken = "|]";
} else if (this.format.recordAndTupleSyntaxType === "hash") {
startToken = "#[";
endToken = "]";
} else {
throw new Error(
`${this.format.recordAndTupleSyntaxType} is not a valid recordAndTuple syntax type`,
);
}
this.token(startToken);
this.printInnerComments(node);
for (let i = 0; i < elems.length; i++) {
const elem = elems[i];
if (elem) {
if (i > 0) this.space();
this.print(elem, node);
if (i < len - 1) this.token(",");
}
}
this.token(endToken);
}
export function RegExpLiteral(node: Object) {
this.word(`/${node.pattern}/${node.flags}`);
}

View File

@ -58,6 +58,7 @@ function normalizeOptions(code, opts): Format {
wrap: true,
...opts.jsescOption,
},
recordAndTupleSyntaxType: opts.recordAndTupleSyntaxType,
};
if (format.minified) {

View File

@ -0,0 +1 @@
{| a: 1 |}

View File

@ -0,0 +1,4 @@
{
"plugins": [["recordAndTuple", { "syntaxType": "bar" }]],
"recordAndTupleSyntaxType": "bar"
}

View File

@ -0,0 +1,3 @@
{|
a: 1
|};

View File

@ -0,0 +1 @@
[| 1 |]

View File

@ -0,0 +1,4 @@
{
"plugins": [["recordAndTuple", { "syntaxType": "bar" }]],
"recordAndTupleSyntaxType": "bar"
}

View File

@ -0,0 +1 @@
[|1|];

View File

@ -0,0 +1 @@
#{ a: 1 }

View File

@ -0,0 +1,4 @@
{
"plugins": [["recordAndTuple", { "syntaxType": "hash" }]],
"recordAndTupleSyntaxType": "hash"
}

View File

@ -0,0 +1,3 @@
#{
a: 1
};

View File

@ -0,0 +1 @@
#[ 1 ]

View File

@ -0,0 +1,4 @@
{
"plugins": [["recordAndTuple", { "syntaxType": "hash" }]],
"recordAndTupleSyntaxType": "hash"
}

View File

@ -0,0 +1 @@
#{ a: 1 }

View File

@ -0,0 +1,5 @@
{
"plugins": [["recordAndTuple", { "syntaxType": "hash" }]],
"recordAndTupleSyntaxType": "invalid",
"throws": "The \"recordAndTupleSyntaxType\" generator option must be \"bar\" or \"hash\" (\"invalid\" received)"
}

View File

@ -0,0 +1 @@
#{ a: 1 }

View File

@ -0,0 +1,4 @@
{
"plugins": [["recordAndTuple", { "syntaxType": "hash" }]],
"throws": "The \"recordAndTupleSyntaxType\" generator option must be \"bar\" or \"hash\" (undefined received)"
}

View File

@ -534,22 +534,33 @@ suites.forEach(function(testSuite) {
sourceMaps: task.sourceMap ? true : task.options.sourceMaps,
};
const result = generate(actualAst, options, actualCode);
const run = () => {
return generate(actualAst, options, actualCode);
};
if (options.sourceMaps) {
expect(result.map).toEqual(task.sourceMap);
}
if (
!expected.code &&
result.code &&
fs.statSync(path.dirname(expected.loc)).isDirectory() &&
!process.env.CI
) {
console.log(`New test file created: ${expected.loc}`);
fs.writeFileSync(expected.loc, result.code);
const throwMsg = task.options.throws;
if (throwMsg) {
expect(() => run()).toThrow(
throwMsg === true ? undefined : throwMsg,
);
} else {
expect(result.code).toBe(expected.code);
const result = run();
if (options.sourceMaps) {
expect(result.map).toEqual(task.sourceMap);
}
if (
!expected.code &&
result.code &&
fs.statSync(path.dirname(expected.loc)).isDirectory() &&
!process.env.CI
) {
console.log(`New test file created: ${expected.loc}`);
fs.writeFileSync(expected.loc, result.code);
} else {
expect(result.code).toBe(expected.code);
}
}
}
},

View File

@ -58,6 +58,8 @@ These are the core @babel/parser (babylon) AST node types.
- [ObjectMember](#objectmember)
- [ObjectProperty](#objectproperty)
- [ObjectMethod](#objectmethod)
- [RecordExpression](#recordexpression)
- [TupleExpression](#tupleexpression)
- [FunctionExpression](#functionexpression)
- [Unary operations](#unary-operations)
- [UnaryExpression](#unaryexpression)
@ -719,6 +721,24 @@ interface ObjectMethod <: ObjectMember, Function {
}
```
## RecordExpression
```js
interface RecordExpression <: Expression {
type: "RecordExpression";
properties: [ ObjectProperty | ObjectMethod | SpreadElement ];
}
```
## TupleExpression
```js
interface TupleExpression <: Expression {
type: "TupleExpression";
elements: [ Expression | SpreadElement | null ];
}
```
## FunctionExpression
```js

View File

@ -1026,6 +1026,25 @@ export default class ExpressionParser extends LValParser {
case tt.parenL:
return this.parseParenAndDistinguishExpression(canBeArrow);
case tt.bracketBarL:
case tt.bracketHashL: {
this.expectPlugin("recordAndTuple");
const oldInFSharpPipelineDirectBody = this.state
.inFSharpPipelineDirectBody;
const close =
this.state.type === tt.bracketBarL ? tt.bracketBarR : tt.bracketR;
this.state.inFSharpPipelineDirectBody = false;
node = this.startNode();
this.next();
node.elements = this.parseExprList(
close,
true,
refExpressionErrors,
node,
);
this.state.inFSharpPipelineDirectBody = oldInFSharpPipelineDirectBody;
return this.finishNode(node, "TupleExpression");
}
case tt.bracketL: {
const oldInFSharpPipelineDirectBody = this.state
.inFSharpPipelineDirectBody;
@ -1049,11 +1068,23 @@ export default class ExpressionParser extends LValParser {
this.state.inFSharpPipelineDirectBody = oldInFSharpPipelineDirectBody;
return this.finishNode(node, "ArrayExpression");
}
case tt.braceBarL:
case tt.braceHashL: {
this.expectPlugin("recordAndTuple");
const oldInFSharpPipelineDirectBody = this.state
.inFSharpPipelineDirectBody;
const close =
this.state.type === tt.braceBarL ? tt.braceBarR : tt.braceR;
this.state.inFSharpPipelineDirectBody = false;
const ret = this.parseObj(close, false, true, refExpressionErrors);
this.state.inFSharpPipelineDirectBody = oldInFSharpPipelineDirectBody;
return ret;
}
case tt.braceL: {
const oldInFSharpPipelineDirectBody = this.state
.inFSharpPipelineDirectBody;
this.state.inFSharpPipelineDirectBody = false;
const ret = this.parseObj(false, refExpressionErrors);
const ret = this.parseObj(tt.braceR, false, false, refExpressionErrors);
this.state.inFSharpPipelineDirectBody = oldInFSharpPipelineDirectBody;
return ret;
}
@ -1465,10 +1496,12 @@ export default class ExpressionParser extends LValParser {
return this.finishNode(node, "TemplateLiteral");
}
// Parse an object literal or binding pattern.
// Parse an object literal, binding pattern, or record.
parseObj<T: N.ObjectPattern | N.ObjectExpression>(
close: TokenType,
isPattern: boolean,
isRecord?: ?boolean,
refExpressionErrors?: ?ExpressionErrors,
): T {
const propHash: any = Object.create(null);
@ -1478,12 +1511,12 @@ export default class ExpressionParser extends LValParser {
node.properties = [];
this.next();
while (!this.eat(tt.braceR)) {
while (!this.eat(close)) {
if (first) {
first = false;
} else {
this.expect(tt.comma);
if (this.match(tt.braceR)) {
if (this.match(close)) {
this.addExtra(node, "trailingComma", this.state.lastTokStart);
this.next();
break;
@ -1504,10 +1537,13 @@ export default class ExpressionParser extends LValParser {
node.properties.push(prop);
}
return this.finishNode(
node,
isPattern ? "ObjectPattern" : "ObjectExpression",
);
let type = "ObjectExpression";
if (isPattern) {
type = "ObjectPattern";
} else if (isRecord) {
type = "RecordExpression";
}
return this.finishNode(node, type);
}
isAsyncProp(prop: N.ObjectProperty): boolean {

View File

@ -127,6 +127,12 @@ export const Errors = Object.freeze({
PrimaryTopicRequiresSmartPipeline:
"Primary Topic Reference found but pipelineOperator not passed 'smart' for 'proposal' option.",
PrivateNameRedeclaration: "Duplicate private name #%0",
RecordExpressionBarIncorrectEndSyntaxType:
"Record expressions ending with '|}' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'bar'",
RecordExpressionBarIncorrectStartSyntaxType:
"Record expressions starting with '{|' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'bar'",
RecordExpressionHashIncorrectStartSyntaxType:
"Record expressions starting with '#{' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'hash'",
RestTrailingComma: "Unexpected trailing comma after rest element",
SloppyFunction:
"In non-strict mode code, functions can only be declared at top level, inside a block, or as the body of an if statement",
@ -143,6 +149,12 @@ export const Errors = Object.freeze({
SuperPrivateField: "Private fields can't be accessed on super",
//todo: rephrase this error message as it is too subjective
TrailingDecorator: "You have trailing decorators with no method",
TupleExpressionBarIncorrectEndSyntaxType:
"Tuple expressions ending with '|]' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'bar'",
TupleExpressionBarIncorrectStartSyntaxType:
"Tuple expressions starting with '[|' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'bar'",
TupleExpressionHashIncorrectStartSyntaxType:
"Tuple expressions starting with '#[' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'hash'",
UnexpectedArgumentPlaceholder: "Unexpected argument placeholder",
UnexpectedAwaitAfterPipelineBody:
'Unexpected "await" after pipeline body; await must have parentheses in minimal proposal',

View File

@ -41,7 +41,9 @@ export default class LValParser extends NodeUtils {
refNeedsArrowPos?: ?Pos,
) => Expression;
+parseObj: <T: ObjectPattern | ObjectExpression>(
close: TokenType,
isPattern: boolean,
isRecord?: ?boolean,
refExpressionErrors?: ?ExpressionErrors,
) => T;
*/
@ -253,7 +255,7 @@ export default class LValParser extends NodeUtils {
}
case tt.braceL:
return this.parseObj(true);
return this.parseObj(tt.braceR, true);
}
return this.parseIdentifier();

View File

@ -39,6 +39,7 @@ export function getPluginOption(
}
const PIPELINE_PROPOSALS = ["minimal", "smart", "fsharp"];
const RECORD_AND_TUPLE_SYNTAX_TYPES = ["hash", "bar"];
export function validatePlugins(plugins: PluginList) {
if (hasPlugin(plugins, "decorators")) {
@ -84,6 +85,18 @@ export function validatePlugins(plugins: PluginList) {
PIPELINE_PROPOSALS.map(p => `'${p}'`).join(", "),
);
}
if (
hasPlugin(plugins, "recordAndTuple") &&
!RECORD_AND_TUPLE_SYNTAX_TYPES.includes(
getPluginOption(plugins, "recordAndTuple", "syntaxType"),
)
) {
throw new Error(
"'recordAndTuple' requires 'syntaxType' option whose value should be one of: " +
RECORD_AND_TUPLE_SYNTAX_TYPES.map(p => `'${p}'`).join(", "),
);
}
}
// These plugins are defined using a mixin which extends the parser class.

View File

@ -405,6 +405,28 @@ export default class Tokenizer extends LocationParser {
}
if (
this.hasPlugin("recordAndTuple") &&
(next === charCodes.leftCurlyBrace ||
next === charCodes.leftSquareBracket)
) {
if (this.getPluginOption("recordAndTuple", "syntaxType") !== "hash") {
throw this.raise(
this.state.pos,
next === charCodes.leftCurlyBrace
? Errors.RecordExpressionHashIncorrectStartSyntaxType
: Errors.TupleExpressionHashIncorrectStartSyntaxType,
);
}
if (next === charCodes.leftCurlyBrace) {
// #{
this.finishToken(tt.braceHashL);
} else {
// #[
this.finishToken(tt.bracketHashL);
}
this.state.pos += 2;
} else if (
this.hasPlugin("classPrivateProperties") ||
this.hasPlugin("classPrivateMethods") ||
this.getPluginOption("pipelineOperator", "proposal") === "smart"
@ -453,12 +475,12 @@ export default class Tokenizer extends LocationParser {
readToken_interpreter(): boolean {
if (this.state.pos !== 0 || this.length < 2) return false;
let ch = this.input.charCodeAt(this.state.pos + 1);
if (ch !== charCodes.exclamationMark) return false;
const start = this.state.pos;
this.state.pos += 1;
let ch = this.input.charCodeAt(this.state.pos);
if (ch !== charCodes.exclamationMark) return false;
while (!isNewLine(ch) && ++this.state.pos < this.length) {
ch = this.input.charCodeAt(this.state.pos);
}
@ -514,6 +536,37 @@ export default class Tokenizer extends LocationParser {
this.finishOp(tt.pipeline, 2);
return;
}
// '|}'
if (
this.hasPlugin("recordAndTuple") &&
next === charCodes.rightCurlyBrace
) {
if (this.getPluginOption("recordAndTuple", "syntaxType") !== "bar") {
throw this.raise(
this.state.pos,
Errors.RecordExpressionBarIncorrectEndSyntaxType,
);
}
this.finishOp(tt.braceBarR, 2);
return;
}
// '|]'
if (
this.hasPlugin("recordAndTuple") &&
next === charCodes.rightSquareBracket
) {
if (this.getPluginOption("recordAndTuple", "syntaxType") !== "bar") {
throw this.raise(
this.state.pos,
Errors.TupleExpressionBarIncorrectEndSyntaxType,
);
}
this.finishOp(tt.bracketBarR, 2);
return;
}
}
if (next === charCodes.equalsTo) {
@ -682,16 +735,48 @@ export default class Tokenizer extends LocationParser {
this.finishToken(tt.comma);
return;
case charCodes.leftSquareBracket:
++this.state.pos;
this.finishToken(tt.bracketL);
if (
this.hasPlugin("recordAndTuple") &&
this.input.charCodeAt(this.state.pos + 1) === charCodes.verticalBar
) {
if (this.getPluginOption("recordAndTuple", "syntaxType") !== "bar") {
throw this.raise(
this.state.pos,
Errors.TupleExpressionBarIncorrectStartSyntaxType,
);
}
// [|
this.finishToken(tt.bracketBarL);
this.state.pos += 2;
} else {
++this.state.pos;
this.finishToken(tt.bracketL);
}
return;
case charCodes.rightSquareBracket:
++this.state.pos;
this.finishToken(tt.bracketR);
return;
case charCodes.leftCurlyBrace:
++this.state.pos;
this.finishToken(tt.braceL);
if (
this.hasPlugin("recordAndTuple") &&
this.input.charCodeAt(this.state.pos + 1) === charCodes.verticalBar
) {
if (this.getPluginOption("recordAndTuple", "syntaxType") !== "bar") {
throw this.raise(
this.state.pos,
Errors.RecordExpressionBarIncorrectStartSyntaxType,
);
}
// {|
this.finishToken(tt.braceBarL);
this.state.pos += 2;
} else {
++this.state.pos;
this.finishToken(tt.braceL);
}
return;
case charCodes.rightCurlyBrace:
++this.state.pos;

View File

@ -93,9 +93,13 @@ export const types: { [name: string]: TokenType } = {
// Punctuation token types.
bracketL: new TokenType("[", { beforeExpr, startsExpr }),
bracketHashL: new TokenType("#[", { beforeExpr, startsExpr }),
bracketBarL: new TokenType("[|", { beforeExpr, startsExpr }),
bracketR: new TokenType("]"),
bracketBarR: new TokenType("|]"),
braceL: new TokenType("{", { beforeExpr, startsExpr }),
braceBarL: new TokenType("{|", { beforeExpr, startsExpr }),
braceHashL: new TokenType("#{", { beforeExpr, startsExpr }),
braceR: new TokenType("}"),
braceBarR: new TokenType("|}"),
parenL: new TokenType("(", { beforeExpr, startsExpr }),

View File

@ -389,11 +389,21 @@ export type ArrayExpression = NodeBase & {
elements: $ReadOnlyArray<?(Expression | SpreadElement)>,
};
export type TupleExpression = NodeBase & {
type: "TupleExpression",
elements: $ReadOnlyArray<?(Expression | SpreadElement)>,
};
export type ObjectExpression = NodeBase & {
type: "ObjectExpression",
properties: $ReadOnlyArray<ObjectProperty | ObjectMethod | SpreadElement>,
};
export type RecordExpression = NodeBase & {
type: "RecordExpression",
properties: $ReadOnlyArray<ObjectProperty | ObjectMethod | SpreadElement>,
};
export type ObjectOrClassMember = ClassMethod | ClassProperty | ObjectMember;
export type ObjectMember = ObjectProperty | ObjectMethod;

View File

@ -0,0 +1 @@
var a: {| x: number |} = {| x: 2 |}

View File

@ -0,0 +1,6 @@
{
"plugins": [
["recordAndTuple", { "syntaxType": "bar" }],
["flow"]
]
}

View File

@ -0,0 +1,247 @@
{
"type": "File",
"start": 0,
"end": 35,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 35
}
},
"program": {
"type": "Program",
"start": 0,
"end": 35,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 35
}
},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "VariableDeclaration",
"start": 0,
"end": 35,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 35
}
},
"declarations": [
{
"type": "VariableDeclarator",
"start": 4,
"end": 35,
"loc": {
"start": {
"line": 1,
"column": 4
},
"end": {
"line": 1,
"column": 35
}
},
"id": {
"type": "Identifier",
"start": 4,
"end": 22,
"loc": {
"start": {
"line": 1,
"column": 4
},
"end": {
"line": 1,
"column": 22
},
"identifierName": "a"
},
"name": "a",
"typeAnnotation": {
"type": "TypeAnnotation",
"start": 5,
"end": 22,
"loc": {
"start": {
"line": 1,
"column": 5
},
"end": {
"line": 1,
"column": 22
}
},
"typeAnnotation": {
"type": "ObjectTypeAnnotation",
"start": 7,
"end": 22,
"loc": {
"start": {
"line": 1,
"column": 7
},
"end": {
"line": 1,
"column": 22
}
},
"callProperties": [],
"properties": [
{
"type": "ObjectTypeProperty",
"start": 10,
"end": 19,
"loc": {
"start": {
"line": 1,
"column": 10
},
"end": {
"line": 1,
"column": 19
}
},
"key": {
"type": "Identifier",
"start": 10,
"end": 11,
"loc": {
"start": {
"line": 1,
"column": 10
},
"end": {
"line": 1,
"column": 11
},
"identifierName": "x"
},
"name": "x"
},
"static": false,
"proto": false,
"kind": "init",
"method": false,
"value": {
"type": "NumberTypeAnnotation",
"start": 13,
"end": 19,
"loc": {
"start": {
"line": 1,
"column": 13
},
"end": {
"line": 1,
"column": 19
}
}
},
"variance": null,
"optional": false
}
],
"indexers": [],
"internalSlots": [],
"exact": true,
"inexact": false
}
}
},
"init": {
"type": "RecordExpression",
"start": 25,
"end": 35,
"loc": {
"start": {
"line": 1,
"column": 25
},
"end": {
"line": 1,
"column": 35
}
},
"properties": [
{
"type": "ObjectProperty",
"start": 28,
"end": 32,
"loc": {
"start": {
"line": 1,
"column": 28
},
"end": {
"line": 1,
"column": 32
}
},
"method": false,
"key": {
"type": "Identifier",
"start": 28,
"end": 29,
"loc": {
"start": {
"line": 1,
"column": 28
},
"end": {
"line": 1,
"column": 29
},
"identifierName": "x"
},
"name": "x"
},
"computed": false,
"shorthand": false,
"value": {
"type": "NumericLiteral",
"start": 31,
"end": 32,
"loc": {
"start": {
"line": 1,
"column": 31
},
"end": {
"line": 1,
"column": 32
}
},
"extra": {
"rawValue": 2,
"raw": "2"
},
"value": 2
}
}
]
}
}
],
"kind": "var"
}
],
"directives": []
}
}

View File

@ -0,0 +1,16 @@
{||};
{| a: 1, b: 2, c: 3 |};
{|
a: 1,
b: {|
c: 3,
|},
|};
[||];
[|1, 2, 3|];
[|1, [|2, 3|], 4|];

View File

@ -0,0 +1,3 @@
{
"plugins": [["recordAndTuple", { "syntaxType": "bar" }]]
}

View File

@ -0,0 +1,715 @@
{
"type": "File",
"start": 0,
"end": 112,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 16,
"column": 19
}
},
"program": {
"type": "Program",
"start": 0,
"end": 112,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 16,
"column": 19
}
},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start": 0,
"end": 5,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 5
}
},
"expression": {
"type": "RecordExpression",
"start": 0,
"end": 4,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 4
}
},
"properties": []
}
},
{
"type": "ExpressionStatement",
"start": 7,
"end": 30,
"loc": {
"start": {
"line": 3,
"column": 0
},
"end": {
"line": 3,
"column": 23
}
},
"expression": {
"type": "RecordExpression",
"start": 7,
"end": 29,
"loc": {
"start": {
"line": 3,
"column": 0
},
"end": {
"line": 3,
"column": 22
}
},
"properties": [
{
"type": "ObjectProperty",
"start": 10,
"end": 14,
"loc": {
"start": {
"line": 3,
"column": 3
},
"end": {
"line": 3,
"column": 7
}
},
"method": false,
"key": {
"type": "Identifier",
"start": 10,
"end": 11,
"loc": {
"start": {
"line": 3,
"column": 3
},
"end": {
"line": 3,
"column": 4
},
"identifierName": "a"
},
"name": "a"
},
"computed": false,
"shorthand": false,
"value": {
"type": "NumericLiteral",
"start": 13,
"end": 14,
"loc": {
"start": {
"line": 3,
"column": 6
},
"end": {
"line": 3,
"column": 7
}
},
"extra": {
"rawValue": 1,
"raw": "1"
},
"value": 1
}
},
{
"type": "ObjectProperty",
"start": 16,
"end": 20,
"loc": {
"start": {
"line": 3,
"column": 9
},
"end": {
"line": 3,
"column": 13
}
},
"method": false,
"key": {
"type": "Identifier",
"start": 16,
"end": 17,
"loc": {
"start": {
"line": 3,
"column": 9
},
"end": {
"line": 3,
"column": 10
},
"identifierName": "b"
},
"name": "b"
},
"computed": false,
"shorthand": false,
"value": {
"type": "NumericLiteral",
"start": 19,
"end": 20,
"loc": {
"start": {
"line": 3,
"column": 12
},
"end": {
"line": 3,
"column": 13
}
},
"extra": {
"rawValue": 2,
"raw": "2"
},
"value": 2
}
},
{
"type": "ObjectProperty",
"start": 22,
"end": 26,
"loc": {
"start": {
"line": 3,
"column": 15
},
"end": {
"line": 3,
"column": 19
}
},
"method": false,
"key": {
"type": "Identifier",
"start": 22,
"end": 23,
"loc": {
"start": {
"line": 3,
"column": 15
},
"end": {
"line": 3,
"column": 16
},
"identifierName": "c"
},
"name": "c"
},
"computed": false,
"shorthand": false,
"value": {
"type": "NumericLiteral",
"start": 25,
"end": 26,
"loc": {
"start": {
"line": 3,
"column": 18
},
"end": {
"line": 3,
"column": 19
}
},
"extra": {
"rawValue": 3,
"raw": "3"
},
"value": 3
}
}
]
}
},
{
"type": "ExpressionStatement",
"start": 32,
"end": 70,
"loc": {
"start": {
"line": 5,
"column": 0
},
"end": {
"line": 10,
"column": 3
}
},
"expression": {
"type": "RecordExpression",
"start": 32,
"end": 69,
"loc": {
"start": {
"line": 5,
"column": 0
},
"end": {
"line": 10,
"column": 2
}
},
"properties": [
{
"type": "ObjectProperty",
"start": 37,
"end": 41,
"loc": {
"start": {
"line": 6,
"column": 2
},
"end": {
"line": 6,
"column": 6
}
},
"method": false,
"key": {
"type": "Identifier",
"start": 37,
"end": 38,
"loc": {
"start": {
"line": 6,
"column": 2
},
"end": {
"line": 6,
"column": 3
},
"identifierName": "a"
},
"name": "a"
},
"computed": false,
"shorthand": false,
"value": {
"type": "NumericLiteral",
"start": 40,
"end": 41,
"loc": {
"start": {
"line": 6,
"column": 5
},
"end": {
"line": 6,
"column": 6
}
},
"extra": {
"rawValue": 1,
"raw": "1"
},
"value": 1
}
},
{
"type": "ObjectProperty",
"start": 45,
"end": 65,
"loc": {
"start": {
"line": 7,
"column": 2
},
"end": {
"line": 9,
"column": 4
}
},
"method": false,
"key": {
"type": "Identifier",
"start": 45,
"end": 46,
"loc": {
"start": {
"line": 7,
"column": 2
},
"end": {
"line": 7,
"column": 3
},
"identifierName": "b"
},
"name": "b"
},
"computed": false,
"shorthand": false,
"value": {
"type": "RecordExpression",
"start": 48,
"end": 65,
"loc": {
"start": {
"line": 7,
"column": 5
},
"end": {
"line": 9,
"column": 4
}
},
"properties": [
{
"type": "ObjectProperty",
"start": 55,
"end": 59,
"loc": {
"start": {
"line": 8,
"column": 4
},
"end": {
"line": 8,
"column": 8
}
},
"method": false,
"key": {
"type": "Identifier",
"start": 55,
"end": 56,
"loc": {
"start": {
"line": 8,
"column": 4
},
"end": {
"line": 8,
"column": 5
},
"identifierName": "c"
},
"name": "c"
},
"computed": false,
"shorthand": false,
"value": {
"type": "NumericLiteral",
"start": 58,
"end": 59,
"loc": {
"start": {
"line": 8,
"column": 7
},
"end": {
"line": 8,
"column": 8
}
},
"extra": {
"rawValue": 3,
"raw": "3"
},
"value": 3
}
}
],
"extra": {
"trailingComma": 59
}
}
}
],
"extra": {
"trailingComma": 65
}
}
},
{
"type": "ExpressionStatement",
"start": 72,
"end": 77,
"loc": {
"start": {
"line": 12,
"column": 0
},
"end": {
"line": 12,
"column": 5
}
},
"expression": {
"type": "TupleExpression",
"start": 72,
"end": 76,
"loc": {
"start": {
"line": 12,
"column": 0
},
"end": {
"line": 12,
"column": 4
}
},
"elements": []
}
},
{
"type": "ExpressionStatement",
"start": 79,
"end": 91,
"loc": {
"start": {
"line": 14,
"column": 0
},
"end": {
"line": 14,
"column": 12
}
},
"expression": {
"type": "TupleExpression",
"start": 79,
"end": 90,
"loc": {
"start": {
"line": 14,
"column": 0
},
"end": {
"line": 14,
"column": 11
}
},
"elements": [
{
"type": "NumericLiteral",
"start": 81,
"end": 82,
"loc": {
"start": {
"line": 14,
"column": 2
},
"end": {
"line": 14,
"column": 3
}
},
"extra": {
"rawValue": 1,
"raw": "1"
},
"value": 1
},
{
"type": "NumericLiteral",
"start": 84,
"end": 85,
"loc": {
"start": {
"line": 14,
"column": 5
},
"end": {
"line": 14,
"column": 6
}
},
"extra": {
"rawValue": 2,
"raw": "2"
},
"value": 2
},
{
"type": "NumericLiteral",
"start": 87,
"end": 88,
"loc": {
"start": {
"line": 14,
"column": 8
},
"end": {
"line": 14,
"column": 9
}
},
"extra": {
"rawValue": 3,
"raw": "3"
},
"value": 3
}
]
}
},
{
"type": "ExpressionStatement",
"start": 93,
"end": 112,
"loc": {
"start": {
"line": 16,
"column": 0
},
"end": {
"line": 16,
"column": 19
}
},
"expression": {
"type": "TupleExpression",
"start": 93,
"end": 111,
"loc": {
"start": {
"line": 16,
"column": 0
},
"end": {
"line": 16,
"column": 18
}
},
"elements": [
{
"type": "NumericLiteral",
"start": 95,
"end": 96,
"loc": {
"start": {
"line": 16,
"column": 2
},
"end": {
"line": 16,
"column": 3
}
},
"extra": {
"rawValue": 1,
"raw": "1"
},
"value": 1
},
{
"type": "TupleExpression",
"start": 98,
"end": 106,
"loc": {
"start": {
"line": 16,
"column": 5
},
"end": {
"line": 16,
"column": 13
}
},
"elements": [
{
"type": "NumericLiteral",
"start": 100,
"end": 101,
"loc": {
"start": {
"line": 16,
"column": 7
},
"end": {
"line": 16,
"column": 8
}
},
"extra": {
"rawValue": 2,
"raw": "2"
},
"value": 2
},
{
"type": "NumericLiteral",
"start": 103,
"end": 104,
"loc": {
"start": {
"line": 16,
"column": 10
},
"end": {
"line": 16,
"column": 11
}
},
"extra": {
"rawValue": 3,
"raw": "3"
},
"value": 3
}
]
},
{
"type": "NumericLiteral",
"start": 108,
"end": 109,
"loc": {
"start": {
"line": 16,
"column": 15
},
"end": {
"line": 16,
"column": 16
}
},
"extra": {
"rawValue": 4,
"raw": "4"
},
"value": 4
}
]
}
}
],
"directives": []
}
}

View File

@ -0,0 +1,16 @@
#{};
#{ a: 1, b: 2, c: 3 };
#{
a: 1,
b: #{
c: 3,
},
};
#[];
#[1, 2, 3];
#[1, #[2, 3], 4];

View File

@ -0,0 +1,3 @@
{
"plugins": [["recordAndTuple", { "syntaxType": "hash" }]]
}

View File

@ -0,0 +1,715 @@
{
"type": "File",
"start": 0,
"end": 104,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 16,
"column": 17
}
},
"program": {
"type": "Program",
"start": 0,
"end": 104,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 16,
"column": 17
}
},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start": 0,
"end": 4,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 4
}
},
"expression": {
"type": "RecordExpression",
"start": 0,
"end": 3,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 3
}
},
"properties": []
}
},
{
"type": "ExpressionStatement",
"start": 6,
"end": 28,
"loc": {
"start": {
"line": 3,
"column": 0
},
"end": {
"line": 3,
"column": 22
}
},
"expression": {
"type": "RecordExpression",
"start": 6,
"end": 27,
"loc": {
"start": {
"line": 3,
"column": 0
},
"end": {
"line": 3,
"column": 21
}
},
"properties": [
{
"type": "ObjectProperty",
"start": 9,
"end": 13,
"loc": {
"start": {
"line": 3,
"column": 3
},
"end": {
"line": 3,
"column": 7
}
},
"method": false,
"key": {
"type": "Identifier",
"start": 9,
"end": 10,
"loc": {
"start": {
"line": 3,
"column": 3
},
"end": {
"line": 3,
"column": 4
},
"identifierName": "a"
},
"name": "a"
},
"computed": false,
"shorthand": false,
"value": {
"type": "NumericLiteral",
"start": 12,
"end": 13,
"loc": {
"start": {
"line": 3,
"column": 6
},
"end": {
"line": 3,
"column": 7
}
},
"extra": {
"rawValue": 1,
"raw": "1"
},
"value": 1
}
},
{
"type": "ObjectProperty",
"start": 15,
"end": 19,
"loc": {
"start": {
"line": 3,
"column": 9
},
"end": {
"line": 3,
"column": 13
}
},
"method": false,
"key": {
"type": "Identifier",
"start": 15,
"end": 16,
"loc": {
"start": {
"line": 3,
"column": 9
},
"end": {
"line": 3,
"column": 10
},
"identifierName": "b"
},
"name": "b"
},
"computed": false,
"shorthand": false,
"value": {
"type": "NumericLiteral",
"start": 18,
"end": 19,
"loc": {
"start": {
"line": 3,
"column": 12
},
"end": {
"line": 3,
"column": 13
}
},
"extra": {
"rawValue": 2,
"raw": "2"
},
"value": 2
}
},
{
"type": "ObjectProperty",
"start": 21,
"end": 25,
"loc": {
"start": {
"line": 3,
"column": 15
},
"end": {
"line": 3,
"column": 19
}
},
"method": false,
"key": {
"type": "Identifier",
"start": 21,
"end": 22,
"loc": {
"start": {
"line": 3,
"column": 15
},
"end": {
"line": 3,
"column": 16
},
"identifierName": "c"
},
"name": "c"
},
"computed": false,
"shorthand": false,
"value": {
"type": "NumericLiteral",
"start": 24,
"end": 25,
"loc": {
"start": {
"line": 3,
"column": 18
},
"end": {
"line": 3,
"column": 19
}
},
"extra": {
"rawValue": 3,
"raw": "3"
},
"value": 3
}
}
]
}
},
{
"type": "ExpressionStatement",
"start": 30,
"end": 66,
"loc": {
"start": {
"line": 5,
"column": 0
},
"end": {
"line": 10,
"column": 2
}
},
"expression": {
"type": "RecordExpression",
"start": 30,
"end": 65,
"loc": {
"start": {
"line": 5,
"column": 0
},
"end": {
"line": 10,
"column": 1
}
},
"properties": [
{
"type": "ObjectProperty",
"start": 35,
"end": 39,
"loc": {
"start": {
"line": 6,
"column": 2
},
"end": {
"line": 6,
"column": 6
}
},
"method": false,
"key": {
"type": "Identifier",
"start": 35,
"end": 36,
"loc": {
"start": {
"line": 6,
"column": 2
},
"end": {
"line": 6,
"column": 3
},
"identifierName": "a"
},
"name": "a"
},
"computed": false,
"shorthand": false,
"value": {
"type": "NumericLiteral",
"start": 38,
"end": 39,
"loc": {
"start": {
"line": 6,
"column": 5
},
"end": {
"line": 6,
"column": 6
}
},
"extra": {
"rawValue": 1,
"raw": "1"
},
"value": 1
}
},
{
"type": "ObjectProperty",
"start": 43,
"end": 62,
"loc": {
"start": {
"line": 7,
"column": 2
},
"end": {
"line": 9,
"column": 3
}
},
"method": false,
"key": {
"type": "Identifier",
"start": 43,
"end": 44,
"loc": {
"start": {
"line": 7,
"column": 2
},
"end": {
"line": 7,
"column": 3
},
"identifierName": "b"
},
"name": "b"
},
"computed": false,
"shorthand": false,
"value": {
"type": "RecordExpression",
"start": 46,
"end": 62,
"loc": {
"start": {
"line": 7,
"column": 5
},
"end": {
"line": 9,
"column": 3
}
},
"properties": [
{
"type": "ObjectProperty",
"start": 53,
"end": 57,
"loc": {
"start": {
"line": 8,
"column": 4
},
"end": {
"line": 8,
"column": 8
}
},
"method": false,
"key": {
"type": "Identifier",
"start": 53,
"end": 54,
"loc": {
"start": {
"line": 8,
"column": 4
},
"end": {
"line": 8,
"column": 5
},
"identifierName": "c"
},
"name": "c"
},
"computed": false,
"shorthand": false,
"value": {
"type": "NumericLiteral",
"start": 56,
"end": 57,
"loc": {
"start": {
"line": 8,
"column": 7
},
"end": {
"line": 8,
"column": 8
}
},
"extra": {
"rawValue": 3,
"raw": "3"
},
"value": 3
}
}
],
"extra": {
"trailingComma": 57
}
}
}
],
"extra": {
"trailingComma": 62
}
}
},
{
"type": "ExpressionStatement",
"start": 68,
"end": 72,
"loc": {
"start": {
"line": 12,
"column": 0
},
"end": {
"line": 12,
"column": 4
}
},
"expression": {
"type": "TupleExpression",
"start": 68,
"end": 71,
"loc": {
"start": {
"line": 12,
"column": 0
},
"end": {
"line": 12,
"column": 3
}
},
"elements": []
}
},
{
"type": "ExpressionStatement",
"start": 74,
"end": 85,
"loc": {
"start": {
"line": 14,
"column": 0
},
"end": {
"line": 14,
"column": 11
}
},
"expression": {
"type": "TupleExpression",
"start": 74,
"end": 84,
"loc": {
"start": {
"line": 14,
"column": 0
},
"end": {
"line": 14,
"column": 10
}
},
"elements": [
{
"type": "NumericLiteral",
"start": 76,
"end": 77,
"loc": {
"start": {
"line": 14,
"column": 2
},
"end": {
"line": 14,
"column": 3
}
},
"extra": {
"rawValue": 1,
"raw": "1"
},
"value": 1
},
{
"type": "NumericLiteral",
"start": 79,
"end": 80,
"loc": {
"start": {
"line": 14,
"column": 5
},
"end": {
"line": 14,
"column": 6
}
},
"extra": {
"rawValue": 2,
"raw": "2"
},
"value": 2
},
{
"type": "NumericLiteral",
"start": 82,
"end": 83,
"loc": {
"start": {
"line": 14,
"column": 8
},
"end": {
"line": 14,
"column": 9
}
},
"extra": {
"rawValue": 3,
"raw": "3"
},
"value": 3
}
]
}
},
{
"type": "ExpressionStatement",
"start": 87,
"end": 104,
"loc": {
"start": {
"line": 16,
"column": 0
},
"end": {
"line": 16,
"column": 17
}
},
"expression": {
"type": "TupleExpression",
"start": 87,
"end": 103,
"loc": {
"start": {
"line": 16,
"column": 0
},
"end": {
"line": 16,
"column": 16
}
},
"elements": [
{
"type": "NumericLiteral",
"start": 89,
"end": 90,
"loc": {
"start": {
"line": 16,
"column": 2
},
"end": {
"line": 16,
"column": 3
}
},
"extra": {
"rawValue": 1,
"raw": "1"
},
"value": 1
},
{
"type": "TupleExpression",
"start": 92,
"end": 99,
"loc": {
"start": {
"line": 16,
"column": 5
},
"end": {
"line": 16,
"column": 12
}
},
"elements": [
{
"type": "NumericLiteral",
"start": 94,
"end": 95,
"loc": {
"start": {
"line": 16,
"column": 7
},
"end": {
"line": 16,
"column": 8
}
},
"extra": {
"rawValue": 2,
"raw": "2"
},
"value": 2
},
{
"type": "NumericLiteral",
"start": 97,
"end": 98,
"loc": {
"start": {
"line": 16,
"column": 10
},
"end": {
"line": 16,
"column": 11
}
},
"extra": {
"rawValue": 3,
"raw": "3"
},
"value": 3
}
]
},
{
"type": "NumericLiteral",
"start": 101,
"end": 102,
"loc": {
"start": {
"line": 16,
"column": 14
},
"end": {
"line": 16,
"column": 15
}
},
"extra": {
"rawValue": 4,
"raw": "4"
},
"value": 4
}
]
}
}
],
"directives": []
}
}

View File

@ -0,0 +1,4 @@
{
"plugins": [["recordAndTuple", { "syntaxType": "hash" }]],
"throws": "Record expressions ending with '|}' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'bar' (1:0)"
}

View File

@ -0,0 +1,4 @@
{
"plugins": [["recordAndTuple", { "syntaxType": "hash" }]],
"throws": "Record expressions starting with '{|' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'bar' (1:0)"
}

View File

@ -0,0 +1,4 @@
{
"plugins": [["recordAndTuple", { "syntaxType": "bar" }]],
"throws": "Record expressions starting with '#{' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'hash' (1:0)"
}

View File

@ -0,0 +1,4 @@
{
"plugins": [["recordAndTuple", { "syntaxType": "hash" }]],
"throws": "Tuple expressions ending with '|]' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'bar' (1:0)"
}

View File

@ -0,0 +1,4 @@
{
"plugins": [["recordAndTuple", { "syntaxType": "hash" }]],
"throws": "Tuple expressions starting with '[|' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'bar' (1:0)"
}

View File

@ -0,0 +1,4 @@
{
"plugins": [["recordAndTuple", { "syntaxType": "bar" }]],
"throws": "Tuple expressions starting with '#[' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'hash' (1:0)"
}

View File

@ -0,0 +1,4 @@
{
"plugins": [["recordAndTuple", { "syntaxType": "invalid" }]],
"throws": "'recordAndTuple' requires 'syntaxType' option whose value should be one of: 'hash', 'bar'"
}

View File

@ -0,0 +1,4 @@
{
"plugins": [["recordAndTuple", { "syntaxType": "invalid" }]],
"throws": "'recordAndTuple' requires 'syntaxType' option whose value should be one of: 'hash', 'bar'"
}

View File

@ -0,0 +1,4 @@
{
"plugins": [["recordAndTuple", { "syntaxType": "invalid" }]],
"throws": "'recordAndTuple' requires 'syntaxType' option whose value should be one of: 'hash', 'bar'"
}

View File

@ -0,0 +1,4 @@
{
"plugins": [["recordAndTuple", { "syntaxType": "invalid" }]],
"throws": "'recordAndTuple' requires 'syntaxType' option whose value should be one of: 'hash', 'bar'"
}

View File

@ -0,0 +1,4 @@
{
"plugins": [],
"throws": "Unexpected token (1:1)"
}

View File

@ -0,0 +1,4 @@
{
"plugins": [],
"throws": "Unexpected character '#' (1:0)"
}

View File

@ -0,0 +1,3 @@
src
test
*.log

View File

@ -0,0 +1,19 @@
# @babel/plugin-syntax-record-and-tuple
> Allow parsing of records and tuples.
See our website [@babel/plugin-syntax-record-and-tuple](https://babeljs.io/docs/en/next/babel-plugin-syntax-record-and-tuple.html) for more information.
## Install
Using npm:
```sh
npm install --save-dev @babel/plugin-syntax-record-and-tuple
```
or using yarn:
```sh
yarn add @babel/plugin-syntax-record-and-tuple --dev
```

View File

@ -0,0 +1,23 @@
{
"name": "@babel/plugin-syntax-record-and-tuple",
"version": "7.7.4",
"description": "Allow parsing of records and tuples.",
"repository": "https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-record-and-tuple",
"license": "MIT",
"publishConfig": {
"access": "public"
},
"main": "lib/index.js",
"keywords": [
"babel-plugin"
],
"dependencies": {
"@babel/helper-plugin-utils": "^7.0.0"
},
"peerDependencies": {
"@babel/core": "^7.0.0"
},
"devDependencies": {
"@babel/core": "^7.0.0"
}
}

View File

@ -0,0 +1,18 @@
import { declare } from "@babel/helper-plugin-utils";
export default declare((api, options) => {
api.assertVersion(7);
return {
name: "syntax-record-and-tuple",
manipulateOptions(opts, parserOpts) {
opts.generatorOpts.recordAndTupleSyntaxType = options.syntaxType;
parserOpts.plugins.push([
"recordAndTuple",
{ syntaxType: options.syntaxType },
]);
},
};
});

View File

@ -791,6 +791,12 @@ export function assertPrivateName(node: Object, opts?: Object = {}): void {
export function assertBigIntLiteral(node: Object, opts?: Object = {}): void {
assert("BigIntLiteral", node, opts);
}
export function assertRecordExpression(node: Object, opts?: Object = {}): void {
assert("RecordExpression", node, opts);
}
export function assertTupleExpression(node: Object, opts?: Object = {}): void {
assert("TupleExpression", node, opts);
}
export function assertTSParameterProperty(
node: Object,
opts?: Object = {},

View File

@ -716,6 +716,14 @@ export function BigIntLiteral(...args: Array<any>): Object {
return builder("BigIntLiteral", ...args);
}
export { BigIntLiteral as bigIntLiteral };
export function RecordExpression(...args: Array<any>): Object {
return builder("RecordExpression", ...args);
}
export { RecordExpression as recordExpression };
export function TupleExpression(...args: Array<any>): Object {
return builder("TupleExpression", ...args);
}
export { TupleExpression as tupleExpression };
export function TSParameterProperty(...args: Array<any>): Object {
return builder("TSParameterProperty", ...args);
}

View File

@ -2,6 +2,7 @@
import defineType, {
assertEach,
assertNodeType,
assertNodeOrValueType,
assertValueType,
chain,
} from "./utils";
@ -276,3 +277,34 @@ defineType("BigIntLiteral", {
},
aliases: ["Expression", "Pureish", "Literal", "Immutable"],
});
defineType("RecordExpression", {
visitor: ["properties"],
aliases: ["Expression"],
fields: {
properties: {
validate: chain(
assertValueType("array"),
assertEach(
assertNodeType("ObjectProperty", "ObjectMethod", "SpreadElement"),
),
),
},
},
});
defineType("TupleExpression", {
fields: {
elements: {
validate: chain(
assertValueType("array"),
assertEach(
assertNodeOrValueType("null", "Expression", "SpreadElement"),
),
),
default: [],
},
},
visitor: ["elements"],
aliases: ["Expression"],
});

View File

@ -2531,6 +2531,34 @@ export function isBigIntLiteral(node: ?Object, opts?: Object): boolean {
return false;
}
export function isRecordExpression(node: ?Object, opts?: Object): boolean {
if (!node) return false;
const nodeType = node.type;
if (nodeType === "RecordExpression") {
if (typeof opts === "undefined") {
return true;
} else {
return shallowEqual(node, opts);
}
}
return false;
}
export function isTupleExpression(node: ?Object, opts?: Object): boolean {
if (!node) return false;
const nodeType = node.type;
if (nodeType === "TupleExpression") {
if (typeof opts === "undefined") {
return true;
} else {
return shallowEqual(node, opts);
}
}
return false;
}
export function isTSParameterProperty(node: ?Object, opts?: Object): boolean {
if (!node) return false;
@ -3460,6 +3488,8 @@ export function isExpression(node: ?Object, opts?: Object): boolean {
"Import" === nodeType ||
"DoExpression" === nodeType ||
"BigIntLiteral" === nodeType ||
"RecordExpression" === nodeType ||
"TupleExpression" === nodeType ||
"TSAsExpression" === nodeType ||
"TSTypeAssertion" === nodeType ||
"TSNonNullExpression" === nodeType ||