Fix several edge cases with context expression state (#8972)

* Fix several edge cases with context expression state

* Fix review comments

* Remove unused field
This commit is contained in:
Daniel Tschinder 2018-11-06 19:37:24 -08:00 committed by GitHub
parent afe67a7035
commit 5d5cd8612f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 1986 additions and 37 deletions

View File

@ -23,6 +23,7 @@ import * as N from "../types";
import LValParser from "./lval";
import { reservedWords } from "../util/identifier";
import type { Pos, Position } from "../util/location";
import * as charCodes from "charcodes";
export default class ExpressionParser extends LValParser {
// Forward-declaration: defined in statement.js
@ -718,6 +719,10 @@ export default class ExpressionParser extends LValParser {
// or `{}`.
parseExprAtom(refShorthandDefaultPos?: ?Pos): N.Expression {
// If a division operator appears in an expression position, the
// tokenizer got confused, and we force it to read a regexp instead.
if (this.state.type === tt.slash) this.readRegexp();
const canBeArrow = this.state.potentialArrowAt === this.state.start;
let node;
@ -964,7 +969,16 @@ export default class ExpressionParser extends LValParser {
parseFunctionExpression(): N.FunctionExpression | N.MetaProperty {
const node = this.startNode();
const meta = this.parseIdentifier(true);
// We do not do parseIdentifier here because when parseFunctionExpression
// is called we already know that the current token is a "name" with the value "function"
// This will improve perf a tiny little bit as we do not do validation but more importantly
// here is that parseIdentifier will remove an item from the expression stack
// if "function" or "class" is parsed as identifier (in objects e.g.), which should not happen here.
let meta = this.startNode();
this.next();
meta = this.createIdentifier(meta, "function");
if (this.state.inGenerator && this.eat(tt.dot)) {
return this.parseMetaProperty(node, meta, "sent");
}
@ -1863,8 +1877,14 @@ export default class ExpressionParser extends LValParser {
parseIdentifier(liberal?: boolean): N.Identifier {
const node = this.startNode();
const name = this.parseIdentifierName(node.start, liberal);
return this.createIdentifier(node, name);
}
createIdentifier(node: N.Identifier, name: string): N.Identifier {
node.name = name;
node.loc.identifierName = name;
return this.finishNode(node, "Identifier");
}
@ -1884,6 +1904,19 @@ export default class ExpressionParser extends LValParser {
name = this.state.value;
} else if (this.state.type.keyword) {
name = this.state.type.keyword;
// `class` and `function` keywords push new context into this.context.
// But there is no chance to pop the context if the keyword is consumed
// as an identifier such as a property name.
// If the previous token is a dot, this does not apply because the
// context-managing code already ignored the keyword
if (
(name === "class" || name === "function") &&
(this.state.lastTokEnd !== this.state.lastTokStart + 1 ||
this.input.charCodeAt(this.state.lastTokStart) !== charCodes.dot)
) {
this.state.context.pop();
}
} else {
throw this.unexpected();
}

View File

@ -6,6 +6,7 @@ import * as N from "../types";
import type { Options } from "../options";
import type { Pos, Position } from "../util/location";
import type State from "../tokenizer/state";
import { types as tc } from "../tokenizer/context";
import * as charCodes from "charcodes";
import { isIteratorStart } from "../util/identifier";
@ -2392,7 +2393,10 @@ export default (superClass: Class<Parser>): Class<Parser> =>
refNeedsArrowPos?: ?Pos,
): N.Expression {
let jsxError = null;
if (tt.jsxTagStart && this.match(tt.jsxTagStart)) {
if (
this.hasPlugin("jsx") &&
(this.match(tt.jsxTagStart) || this.isRelational("<"))
) {
const state = this.state.clone();
try {
return super.parseMaybeAssign(
@ -2408,7 +2412,10 @@ export default (superClass: Class<Parser>): Class<Parser> =>
// Remove `tc.j_expr` and `tc.j_oTag` from context added
// by parsing `jsxTagStart` to stop the JSX plugin from
// messing with the tokens
this.state.context.length -= 2;
const cLength = this.state.context.length;
if (this.state.context[cLength - 1] === tc.j_oTag) {
this.state.context.length -= 2;
}
jsxError = err;
} else {

View File

@ -506,6 +506,15 @@ export default (superClass: Class<Parser>): Class<Parser> =>
return this.parseLiteral(this.state.value, "JSXText");
} else if (this.match(tt.jsxTagStart)) {
return this.jsxParseElement();
} else if (
this.isRelational("<") &&
this.state.input.charCodeAt(this.state.pos) !==
charCodes.exclamationMark
) {
// In case we encounter an lt token here it will always be the start of
// jsx as the lt sign is not allowed in places that expect an expression
this.finishToken(tt.jsxTagStart);
return this.jsxParseElement();
} else {
return super.parseExprAtom(refShortHandDefaultPos);
}
@ -538,7 +547,12 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
}
if (code === charCodes.lessThan && this.state.exprAllowed) {
if (
code === charCodes.lessThan &&
this.state.exprAllowed &&
this.state.input.charCodeAt(this.state.pos + 1) !==
charCodes.exclamationMark
) {
++this.state.pos;
return this.finishToken(tt.jsxTagStart);
}

View File

@ -12,7 +12,7 @@ export class TokContext {
token: string,
isExpr?: boolean,
preserveSpace?: boolean,
override?: Function, // Takes a Tokenizer as a this-parameter, and returns void.
override?: ?Function, // Takes a Tokenizer as a this-parameter, and returns void.
) {
this.token = token;
this.isExpr = !!isExpr;
@ -31,11 +31,12 @@ export const types: {
} = {
braceStatement: new TokContext("{", false),
braceExpression: new TokContext("{", true),
templateQuasi: new TokContext("${", true),
templateQuasi: new TokContext("${", false),
parenStatement: new TokContext("(", false),
parenExpression: new TokContext("(", true),
template: new TokContext("`", true, true, p => p.readTmplToken()),
functionExpression: new TokContext("function", true),
functionStatement: new TokContext("function", false),
};
// Token-specific context update code
@ -46,33 +47,26 @@ tt.parenR.updateContext = tt.braceR.updateContext = function() {
return;
}
const out = this.state.context.pop();
if (
out === types.braceStatement &&
this.curContext() === types.functionExpression
) {
this.state.context.pop();
this.state.exprAllowed = false;
} else if (out === types.templateQuasi) {
this.state.exprAllowed = true;
} else {
this.state.exprAllowed = !out.isExpr;
let out = this.state.context.pop();
if (out === types.braceStatement && this.curContext().token === "function") {
out = this.state.context.pop();
}
this.state.exprAllowed = !out.isExpr;
};
tt.name.updateContext = function(prevType) {
if (this.state.value === "of" && this.curContext() === types.parenStatement) {
this.state.exprAllowed = !prevType.beforeExpr;
return;
}
this.state.exprAllowed = false;
if (prevType === tt._let || prevType === tt._const || prevType === tt._var) {
if (lineBreak.test(this.input.slice(this.state.end))) {
this.state.exprAllowed = true;
let allowed = false;
if (prevType !== tt.dot) {
if (
(this.state.value === "of" && !this.state.exprAllowed) ||
(this.state.value === "yield" && this.state.inGenerator)
) {
allowed = true;
}
}
this.state.exprAllowed = allowed;
if (this.state.isIterator) {
this.state.isIterator = false;
}
@ -107,8 +101,22 @@ tt.incDec.updateContext = function() {
};
tt._function.updateContext = tt._class.updateContext = function(prevType) {
if (this.state.exprAllowed && !this.braceIsBlock(prevType)) {
if (
prevType.beforeExpr &&
prevType !== tt.semi &&
prevType !== tt._else &&
!(
prevType === tt._return &&
lineBreak.test(this.input.slice(this.state.lastTokEnd, this.state.start))
) &&
!(
(prevType === tt.colon || prevType === tt.braceL) &&
this.curContext() === types.b_stat
)
) {
this.state.context.push(types.functionExpression);
} else {
this.state.context.push(types.functionStatement);
}
this.state.exprAllowed = false;

View File

@ -1324,14 +1324,25 @@ export default class Tokenizer extends LocationParser {
}
braceIsBlock(prevType: TokenType): boolean {
if (prevType === tt.colon) {
const parent = this.curContext();
if (parent === ct.braceStatement || parent === ct.braceExpression) {
return !parent.isExpr;
}
const parent = this.curContext();
if (parent === ct.functionExpression || parent === ct.functionStatement) {
return true;
}
if (
prevType === tt.colon &&
(parent === ct.braceStatement || parent === ct.braceExpression)
) {
return !parent.isExpr;
}
if (prevType === tt._return) {
// The check for `tt.name && exprAllowed` detects whether we are
// after a `yield` or `of` construct. See the `updateContext` for
// `tt.name`.
if (
prevType === tt._return ||
prevType === tt._yield ||
(prevType === tt.name && this.state.exprAllowed)
) {
return lineBreak.test(
this.input.slice(this.state.lastTokEnd, this.state.start),
);
@ -1341,13 +1352,22 @@ export default class Tokenizer extends LocationParser {
prevType === tt._else ||
prevType === tt.semi ||
prevType === tt.eof ||
prevType === tt.parenR
prevType === tt.parenR ||
prevType === tt.arrow
) {
return true;
}
if (prevType === tt.braceL) {
return this.curContext() === ct.braceStatement;
return parent === ct.braceStatement;
}
if (
prevType === tt._var ||
prevType === tt._let ||
prevType === tt._const
) {
return false;
}
if (prevType === tt.relational) {

View File

@ -174,7 +174,7 @@ export const keywords = {
new: new KeywordTokenType("new", { beforeExpr, startsExpr }),
this: new KeywordTokenType("this", { startsExpr }),
super: new KeywordTokenType("super", { startsExpr }),
class: new KeywordTokenType("class"),
class: new KeywordTokenType("class", { startsExpr }),
extends: new KeywordTokenType("extends", { beforeExpr }),
export: new KeywordTokenType("export"),
import: new KeywordTokenType("import", { startsExpr }),

View File

@ -0,0 +1 @@
for (const {a} of /b/) {}

View File

@ -0,0 +1,194 @@
{
"type": "File",
"start": 0,
"end": 25,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 25
}
},
"program": {
"type": "Program",
"start": 0,
"end": 25,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 25
}
},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ForOfStatement",
"start": 0,
"end": 25,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 25
}
},
"await": false,
"left": {
"type": "VariableDeclaration",
"start": 5,
"end": 14,
"loc": {
"start": {
"line": 1,
"column": 5
},
"end": {
"line": 1,
"column": 14
}
},
"declarations": [
{
"type": "VariableDeclarator",
"start": 11,
"end": 14,
"loc": {
"start": {
"line": 1,
"column": 11
},
"end": {
"line": 1,
"column": 14
}
},
"id": {
"type": "ObjectPattern",
"start": 11,
"end": 14,
"loc": {
"start": {
"line": 1,
"column": 11
},
"end": {
"line": 1,
"column": 14
}
},
"properties": [
{
"type": "ObjectProperty",
"start": 12,
"end": 13,
"loc": {
"start": {
"line": 1,
"column": 12
},
"end": {
"line": 1,
"column": 13
}
},
"method": false,
"key": {
"type": "Identifier",
"start": 12,
"end": 13,
"loc": {
"start": {
"line": 1,
"column": 12
},
"end": {
"line": 1,
"column": 13
},
"identifierName": "a"
},
"name": "a"
},
"computed": false,
"shorthand": true,
"value": {
"type": "Identifier",
"start": 12,
"end": 13,
"loc": {
"start": {
"line": 1,
"column": 12
},
"end": {
"line": 1,
"column": 13
},
"identifierName": "a"
},
"name": "a"
},
"extra": {
"shorthand": true
}
}
]
},
"init": null
}
],
"kind": "const"
},
"right": {
"type": "RegExpLiteral",
"start": 18,
"end": 21,
"loc": {
"start": {
"line": 1,
"column": 18
},
"end": {
"line": 1,
"column": 21
}
},
"extra": {
"raw": "/b/"
},
"pattern": "b",
"flags": ""
},
"body": {
"type": "BlockStatement",
"start": 23,
"end": 25,
"loc": {
"start": {
"line": 1,
"column": 23
},
"end": {
"line": 1,
"column": 25
}
},
"body": [],
"directives": []
}
}
],
"directives": []
}
}

View File

@ -0,0 +1 @@
for (let {a} of /b/) {}

View File

@ -0,0 +1,194 @@
{
"type": "File",
"start": 0,
"end": 23,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 23
}
},
"program": {
"type": "Program",
"start": 0,
"end": 23,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 23
}
},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ForOfStatement",
"start": 0,
"end": 23,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 23
}
},
"await": false,
"left": {
"type": "VariableDeclaration",
"start": 5,
"end": 12,
"loc": {
"start": {
"line": 1,
"column": 5
},
"end": {
"line": 1,
"column": 12
}
},
"declarations": [
{
"type": "VariableDeclarator",
"start": 9,
"end": 12,
"loc": {
"start": {
"line": 1,
"column": 9
},
"end": {
"line": 1,
"column": 12
}
},
"id": {
"type": "ObjectPattern",
"start": 9,
"end": 12,
"loc": {
"start": {
"line": 1,
"column": 9
},
"end": {
"line": 1,
"column": 12
}
},
"properties": [
{
"type": "ObjectProperty",
"start": 10,
"end": 11,
"loc": {
"start": {
"line": 1,
"column": 10
},
"end": {
"line": 1,
"column": 11
}
},
"method": false,
"key": {
"type": "Identifier",
"start": 10,
"end": 11,
"loc": {
"start": {
"line": 1,
"column": 10
},
"end": {
"line": 1,
"column": 11
},
"identifierName": "a"
},
"name": "a"
},
"computed": false,
"shorthand": true,
"value": {
"type": "Identifier",
"start": 10,
"end": 11,
"loc": {
"start": {
"line": 1,
"column": 10
},
"end": {
"line": 1,
"column": 11
},
"identifierName": "a"
},
"name": "a"
},
"extra": {
"shorthand": true
}
}
]
},
"init": null
}
],
"kind": "let"
},
"right": {
"type": "RegExpLiteral",
"start": 16,
"end": 19,
"loc": {
"start": {
"line": 1,
"column": 16
},
"end": {
"line": 1,
"column": 19
}
},
"extra": {
"raw": "/b/"
},
"pattern": "b",
"flags": ""
},
"body": {
"type": "BlockStatement",
"start": 21,
"end": 23,
"loc": {
"start": {
"line": 1,
"column": 21
},
"end": {
"line": 1,
"column": 23
}
},
"body": [],
"directives": []
}
}
],
"directives": []
}
}

View File

@ -0,0 +1 @@
for (var {a} of /b/) {}

View File

@ -0,0 +1,194 @@
{
"type": "File",
"start": 0,
"end": 23,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 23
}
},
"program": {
"type": "Program",
"start": 0,
"end": 23,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 23
}
},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ForOfStatement",
"start": 0,
"end": 23,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 23
}
},
"await": false,
"left": {
"type": "VariableDeclaration",
"start": 5,
"end": 12,
"loc": {
"start": {
"line": 1,
"column": 5
},
"end": {
"line": 1,
"column": 12
}
},
"declarations": [
{
"type": "VariableDeclarator",
"start": 9,
"end": 12,
"loc": {
"start": {
"line": 1,
"column": 9
},
"end": {
"line": 1,
"column": 12
}
},
"id": {
"type": "ObjectPattern",
"start": 9,
"end": 12,
"loc": {
"start": {
"line": 1,
"column": 9
},
"end": {
"line": 1,
"column": 12
}
},
"properties": [
{
"type": "ObjectProperty",
"start": 10,
"end": 11,
"loc": {
"start": {
"line": 1,
"column": 10
},
"end": {
"line": 1,
"column": 11
}
},
"method": false,
"key": {
"type": "Identifier",
"start": 10,
"end": 11,
"loc": {
"start": {
"line": 1,
"column": 10
},
"end": {
"line": 1,
"column": 11
},
"identifierName": "a"
},
"name": "a"
},
"computed": false,
"shorthand": true,
"value": {
"type": "Identifier",
"start": 10,
"end": 11,
"loc": {
"start": {
"line": 1,
"column": 10
},
"end": {
"line": 1,
"column": 11
},
"identifierName": "a"
},
"name": "a"
},
"extra": {
"shorthand": true
}
}
]
},
"init": null
}
],
"kind": "var"
},
"right": {
"type": "RegExpLiteral",
"start": 16,
"end": 19,
"loc": {
"start": {
"line": 1,
"column": 16
},
"end": {
"line": 1,
"column": 19
}
},
"extra": {
"raw": "/b/"
},
"pattern": "b",
"flags": ""
},
"body": {
"type": "BlockStatement",
"start": 21,
"end": 23,
"loc": {
"start": {
"line": 1,
"column": 21
},
"end": {
"line": 1,
"column": 23
}
},
"body": [],
"directives": []
}
}
],
"directives": []
}
}

View File

@ -0,0 +1,3 @@
function *f() { yield
{}/1/g
}

View File

@ -0,0 +1,172 @@
{
"type": "File",
"start": 0,
"end": 30,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 3,
"column": 1
}
},
"program": {
"type": "Program",
"start": 0,
"end": 30,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 3,
"column": 1
}
},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "FunctionDeclaration",
"start": 0,
"end": 30,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 3,
"column": 1
}
},
"id": {
"type": "Identifier",
"start": 10,
"end": 11,
"loc": {
"start": {
"line": 1,
"column": 10
},
"end": {
"line": 1,
"column": 11
},
"identifierName": "f"
},
"name": "f"
},
"generator": true,
"async": false,
"params": [],
"body": {
"type": "BlockStatement",
"start": 14,
"end": 30,
"loc": {
"start": {
"line": 1,
"column": 14
},
"end": {
"line": 3,
"column": 1
}
},
"body": [
{
"type": "ExpressionStatement",
"start": 16,
"end": 21,
"loc": {
"start": {
"line": 1,
"column": 16
},
"end": {
"line": 1,
"column": 21
}
},
"expression": {
"type": "YieldExpression",
"start": 16,
"end": 21,
"loc": {
"start": {
"line": 1,
"column": 16
},
"end": {
"line": 1,
"column": 21
}
},
"delegate": false,
"argument": null
}
},
{
"type": "BlockStatement",
"start": 22,
"end": 24,
"loc": {
"start": {
"line": 2,
"column": 0
},
"end": {
"line": 2,
"column": 2
}
},
"body": [],
"directives": []
},
{
"type": "ExpressionStatement",
"start": 24,
"end": 28,
"loc": {
"start": {
"line": 2,
"column": 2
},
"end": {
"line": 2,
"column": 6
}
},
"expression": {
"type": "RegExpLiteral",
"start": 24,
"end": 28,
"loc": {
"start": {
"line": 2,
"column": 2
},
"end": {
"line": 2,
"column": 6
}
},
"extra": {
"raw": "/1/g"
},
"pattern": "1",
"flags": "g"
}
}
],
"directives": []
}
}
],
"directives": []
}
}

View File

@ -0,0 +1 @@
function* bar() { yield class {} }

View File

@ -0,0 +1,152 @@
{
"type": "File",
"start": 0,
"end": 34,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 34
}
},
"program": {
"type": "Program",
"start": 0,
"end": 34,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 34
}
},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "FunctionDeclaration",
"start": 0,
"end": 34,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 34
}
},
"id": {
"type": "Identifier",
"start": 10,
"end": 13,
"loc": {
"start": {
"line": 1,
"column": 10
},
"end": {
"line": 1,
"column": 13
},
"identifierName": "bar"
},
"name": "bar"
},
"generator": true,
"async": false,
"params": [],
"body": {
"type": "BlockStatement",
"start": 16,
"end": 34,
"loc": {
"start": {
"line": 1,
"column": 16
},
"end": {
"line": 1,
"column": 34
}
},
"body": [
{
"type": "ExpressionStatement",
"start": 18,
"end": 32,
"loc": {
"start": {
"line": 1,
"column": 18
},
"end": {
"line": 1,
"column": 32
}
},
"expression": {
"type": "YieldExpression",
"start": 18,
"end": 32,
"loc": {
"start": {
"line": 1,
"column": 18
},
"end": {
"line": 1,
"column": 32
}
},
"delegate": false,
"argument": {
"type": "ClassExpression",
"start": 24,
"end": 32,
"loc": {
"start": {
"line": 1,
"column": 24
},
"end": {
"line": 1,
"column": 32
}
},
"id": null,
"superClass": null,
"body": {
"type": "ClassBody",
"start": 30,
"end": 32,
"loc": {
"start": {
"line": 1,
"column": 30
},
"end": {
"line": 1,
"column": 32
}
},
"body": []
}
}
}
}
],
"directives": []
}
}
],
"directives": []
}
}

View File

@ -0,0 +1 @@
<!--a

View File

@ -0,0 +1,4 @@
{
"sourceType": "script",
"plugins": ["jsx", "flow"]
}

View File

@ -0,0 +1,70 @@
{
"type": "File",
"start": 0,
"end": 5,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 5
}
},
"program": {
"type": "Program",
"start": 0,
"end": 5,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 5
}
},
"sourceType": "script",
"interpreter": null,
"body": [],
"directives": [],
"innerComments": [
{
"type": "CommentLine",
"value": "a",
"start": 0,
"end": 5,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 5
}
}
}
]
},
"comments": [
{
"type": "CommentLine",
"value": "a",
"start": 0,
"end": 5,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 5
}
}
}
]
}

View File

@ -0,0 +1,6 @@
<>
<Select prop={{ function: 'test' }} />
<Select prop={{ class: 'test' }} />
<Select prop={{ delete: 'test' }} />
<Select prop={{ enum: 'test' }} />
</>

View File

@ -0,0 +1,873 @@
{
"type": "File",
"start": 0,
"end": 153,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 6,
"column": 3
}
},
"program": {
"type": "Program",
"start": 0,
"end": 153,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 6,
"column": 3
}
},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start": 0,
"end": 153,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 6,
"column": 3
}
},
"expression": {
"type": "JSXFragment",
"start": 0,
"end": 153,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 6,
"column": 3
}
},
"openingFragment": {
"type": "JSXOpeningFragment",
"start": 0,
"end": 2,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 2
}
}
},
"closingFragment": {
"type": "JSXClosingFragment",
"start": 150,
"end": 153,
"loc": {
"start": {
"line": 6,
"column": 0
},
"end": {
"line": 6,
"column": 3
}
}
},
"children": [
{
"type": "JSXText",
"start": 2,
"end": 3,
"loc": {
"start": {
"line": 1,
"column": 2
},
"end": {
"line": 2,
"column": 0
}
},
"extra": {
"rawValue": "\n",
"raw": "\n"
},
"value": "\n"
},
{
"type": "JSXElement",
"start": 3,
"end": 41,
"loc": {
"start": {
"line": 2,
"column": 0
},
"end": {
"line": 2,
"column": 38
}
},
"openingElement": {
"type": "JSXOpeningElement",
"start": 3,
"end": 41,
"loc": {
"start": {
"line": 2,
"column": 0
},
"end": {
"line": 2,
"column": 38
}
},
"name": {
"type": "JSXIdentifier",
"start": 4,
"end": 10,
"loc": {
"start": {
"line": 2,
"column": 1
},
"end": {
"line": 2,
"column": 7
}
},
"name": "Select"
},
"attributes": [
{
"type": "JSXAttribute",
"start": 11,
"end": 38,
"loc": {
"start": {
"line": 2,
"column": 8
},
"end": {
"line": 2,
"column": 35
}
},
"name": {
"type": "JSXIdentifier",
"start": 11,
"end": 15,
"loc": {
"start": {
"line": 2,
"column": 8
},
"end": {
"line": 2,
"column": 12
}
},
"name": "prop"
},
"value": {
"type": "JSXExpressionContainer",
"start": 16,
"end": 38,
"loc": {
"start": {
"line": 2,
"column": 13
},
"end": {
"line": 2,
"column": 35
}
},
"expression": {
"type": "ObjectExpression",
"start": 17,
"end": 37,
"loc": {
"start": {
"line": 2,
"column": 14
},
"end": {
"line": 2,
"column": 34
}
},
"properties": [
{
"type": "ObjectProperty",
"start": 19,
"end": 35,
"loc": {
"start": {
"line": 2,
"column": 16
},
"end": {
"line": 2,
"column": 32
}
},
"method": false,
"key": {
"type": "Identifier",
"start": 19,
"end": 27,
"loc": {
"start": {
"line": 2,
"column": 16
},
"end": {
"line": 2,
"column": 24
},
"identifierName": "function"
},
"name": "function"
},
"computed": false,
"shorthand": false,
"value": {
"type": "StringLiteral",
"start": 29,
"end": 35,
"loc": {
"start": {
"line": 2,
"column": 26
},
"end": {
"line": 2,
"column": 32
}
},
"extra": {
"rawValue": "test",
"raw": "'test'"
},
"value": "test"
}
}
]
}
}
}
],
"selfClosing": true
},
"closingElement": null,
"children": []
},
{
"type": "JSXText",
"start": 41,
"end": 42,
"loc": {
"start": {
"line": 2,
"column": 38
},
"end": {
"line": 3,
"column": 0
}
},
"extra": {
"rawValue": "\n",
"raw": "\n"
},
"value": "\n"
},
{
"type": "JSXElement",
"start": 42,
"end": 77,
"loc": {
"start": {
"line": 3,
"column": 0
},
"end": {
"line": 3,
"column": 35
}
},
"openingElement": {
"type": "JSXOpeningElement",
"start": 42,
"end": 77,
"loc": {
"start": {
"line": 3,
"column": 0
},
"end": {
"line": 3,
"column": 35
}
},
"name": {
"type": "JSXIdentifier",
"start": 43,
"end": 49,
"loc": {
"start": {
"line": 3,
"column": 1
},
"end": {
"line": 3,
"column": 7
}
},
"name": "Select"
},
"attributes": [
{
"type": "JSXAttribute",
"start": 50,
"end": 74,
"loc": {
"start": {
"line": 3,
"column": 8
},
"end": {
"line": 3,
"column": 32
}
},
"name": {
"type": "JSXIdentifier",
"start": 50,
"end": 54,
"loc": {
"start": {
"line": 3,
"column": 8
},
"end": {
"line": 3,
"column": 12
}
},
"name": "prop"
},
"value": {
"type": "JSXExpressionContainer",
"start": 55,
"end": 74,
"loc": {
"start": {
"line": 3,
"column": 13
},
"end": {
"line": 3,
"column": 32
}
},
"expression": {
"type": "ObjectExpression",
"start": 56,
"end": 73,
"loc": {
"start": {
"line": 3,
"column": 14
},
"end": {
"line": 3,
"column": 31
}
},
"properties": [
{
"type": "ObjectProperty",
"start": 58,
"end": 71,
"loc": {
"start": {
"line": 3,
"column": 16
},
"end": {
"line": 3,
"column": 29
}
},
"method": false,
"key": {
"type": "Identifier",
"start": 58,
"end": 63,
"loc": {
"start": {
"line": 3,
"column": 16
},
"end": {
"line": 3,
"column": 21
},
"identifierName": "class"
},
"name": "class"
},
"computed": false,
"shorthand": false,
"value": {
"type": "StringLiteral",
"start": 65,
"end": 71,
"loc": {
"start": {
"line": 3,
"column": 23
},
"end": {
"line": 3,
"column": 29
}
},
"extra": {
"rawValue": "test",
"raw": "'test'"
},
"value": "test"
}
}
]
}
}
}
],
"selfClosing": true
},
"closingElement": null,
"children": []
},
{
"type": "JSXText",
"start": 77,
"end": 78,
"loc": {
"start": {
"line": 3,
"column": 35
},
"end": {
"line": 4,
"column": 0
}
},
"extra": {
"rawValue": "\n",
"raw": "\n"
},
"value": "\n"
},
{
"type": "JSXElement",
"start": 78,
"end": 114,
"loc": {
"start": {
"line": 4,
"column": 0
},
"end": {
"line": 4,
"column": 36
}
},
"openingElement": {
"type": "JSXOpeningElement",
"start": 78,
"end": 114,
"loc": {
"start": {
"line": 4,
"column": 0
},
"end": {
"line": 4,
"column": 36
}
},
"name": {
"type": "JSXIdentifier",
"start": 79,
"end": 85,
"loc": {
"start": {
"line": 4,
"column": 1
},
"end": {
"line": 4,
"column": 7
}
},
"name": "Select"
},
"attributes": [
{
"type": "JSXAttribute",
"start": 86,
"end": 111,
"loc": {
"start": {
"line": 4,
"column": 8
},
"end": {
"line": 4,
"column": 33
}
},
"name": {
"type": "JSXIdentifier",
"start": 86,
"end": 90,
"loc": {
"start": {
"line": 4,
"column": 8
},
"end": {
"line": 4,
"column": 12
}
},
"name": "prop"
},
"value": {
"type": "JSXExpressionContainer",
"start": 91,
"end": 111,
"loc": {
"start": {
"line": 4,
"column": 13
},
"end": {
"line": 4,
"column": 33
}
},
"expression": {
"type": "ObjectExpression",
"start": 92,
"end": 110,
"loc": {
"start": {
"line": 4,
"column": 14
},
"end": {
"line": 4,
"column": 32
}
},
"properties": [
{
"type": "ObjectProperty",
"start": 94,
"end": 108,
"loc": {
"start": {
"line": 4,
"column": 16
},
"end": {
"line": 4,
"column": 30
}
},
"method": false,
"key": {
"type": "Identifier",
"start": 94,
"end": 100,
"loc": {
"start": {
"line": 4,
"column": 16
},
"end": {
"line": 4,
"column": 22
},
"identifierName": "delete"
},
"name": "delete"
},
"computed": false,
"shorthand": false,
"value": {
"type": "StringLiteral",
"start": 102,
"end": 108,
"loc": {
"start": {
"line": 4,
"column": 24
},
"end": {
"line": 4,
"column": 30
}
},
"extra": {
"rawValue": "test",
"raw": "'test'"
},
"value": "test"
}
}
]
}
}
}
],
"selfClosing": true
},
"closingElement": null,
"children": []
},
{
"type": "JSXText",
"start": 114,
"end": 115,
"loc": {
"start": {
"line": 4,
"column": 36
},
"end": {
"line": 5,
"column": 0
}
},
"extra": {
"rawValue": "\n",
"raw": "\n"
},
"value": "\n"
},
{
"type": "JSXElement",
"start": 115,
"end": 149,
"loc": {
"start": {
"line": 5,
"column": 0
},
"end": {
"line": 5,
"column": 34
}
},
"openingElement": {
"type": "JSXOpeningElement",
"start": 115,
"end": 149,
"loc": {
"start": {
"line": 5,
"column": 0
},
"end": {
"line": 5,
"column": 34
}
},
"name": {
"type": "JSXIdentifier",
"start": 116,
"end": 122,
"loc": {
"start": {
"line": 5,
"column": 1
},
"end": {
"line": 5,
"column": 7
}
},
"name": "Select"
},
"attributes": [
{
"type": "JSXAttribute",
"start": 123,
"end": 146,
"loc": {
"start": {
"line": 5,
"column": 8
},
"end": {
"line": 5,
"column": 31
}
},
"name": {
"type": "JSXIdentifier",
"start": 123,
"end": 127,
"loc": {
"start": {
"line": 5,
"column": 8
},
"end": {
"line": 5,
"column": 12
}
},
"name": "prop"
},
"value": {
"type": "JSXExpressionContainer",
"start": 128,
"end": 146,
"loc": {
"start": {
"line": 5,
"column": 13
},
"end": {
"line": 5,
"column": 31
}
},
"expression": {
"type": "ObjectExpression",
"start": 129,
"end": 145,
"loc": {
"start": {
"line": 5,
"column": 14
},
"end": {
"line": 5,
"column": 30
}
},
"properties": [
{
"type": "ObjectProperty",
"start": 131,
"end": 143,
"loc": {
"start": {
"line": 5,
"column": 16
},
"end": {
"line": 5,
"column": 28
}
},
"method": false,
"key": {
"type": "Identifier",
"start": 131,
"end": 135,
"loc": {
"start": {
"line": 5,
"column": 16
},
"end": {
"line": 5,
"column": 20
},
"identifierName": "enum"
},
"name": "enum"
},
"computed": false,
"shorthand": false,
"value": {
"type": "StringLiteral",
"start": 137,
"end": 143,
"loc": {
"start": {
"line": 5,
"column": 22
},
"end": {
"line": 5,
"column": 28
}
},
"extra": {
"rawValue": "test",
"raw": "'test'"
},
"value": "test"
}
}
]
}
}
}
],
"selfClosing": true
},
"closingElement": null,
"children": []
},
{
"type": "JSXText",
"start": 149,
"end": 150,
"loc": {
"start": {
"line": 5,
"column": 34
},
"end": {
"line": 6,
"column": 0
}
},
"extra": {
"rawValue": "\n",
"raw": "\n"
},
"value": "\n"
}
]
}
}
],
"directives": []
}
}