eslint-parser: ES2020 features (#11815)

* chore: update espree test on nullish coalescing

* feat: add optional chaining support

* fix: adapt to estree AST shape

* chore: update lockfile

* add estree optional-chaining test fixtures

* address review comments

* chore: simplify smoke test

* export * support

Co-authored-by: Brian Ng <bng412@gmail.com>
This commit is contained in:
Huáng Jùnliàng 2020-07-29 16:46:29 -04:00 committed by GitHub
parent 059e9124ff
commit d7347fb8bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 690 additions and 60 deletions

View File

@ -23,8 +23,8 @@
"eslint": ">=6.0.0" "eslint": ">=6.0.0"
}, },
"dependencies": { "dependencies": {
"eslint-scope": "5.0.0", "eslint-scope": "5.1.0",
"eslint-visitor-keys": "^1.1.0", "eslint-visitor-keys": "^1.3.0",
"semver": "^6.3.0" "semver": "^6.3.0"
}, },
"devDependencies": { "devDependencies": {

View File

@ -1,4 +1,5 @@
import { types as t, traverse } from "@babel/core"; import { types as t, traverse } from "@babel/core";
import VISITOR_KEYS from "../visitor-keys";
function convertNodes(ast, code) { function convertNodes(ast, code) {
const astTransformVisitor = { const astTransformVisitor = {
@ -81,21 +82,28 @@ function convertNodes(ast, code) {
}; };
const state = { source: code }; const state = { source: code };
// Monkey patch visitor keys in order to be able to traverse the estree nodes const oldExportAllDeclarationKeys = t.VISITOR_KEYS.ExportAllDeclaration;
t.VISITOR_KEYS.Property = t.VISITOR_KEYS.ObjectProperty;
t.VISITOR_KEYS.MethodDefinition = [
"key",
"value",
"decorators",
"returnType",
"typeParameters",
];
traverse(ast, astTransformVisitor, null, state); try {
// Monkey patch visitor keys in order to be able to traverse the estree nodes
t.VISITOR_KEYS.ChainExpression = VISITOR_KEYS.ChainExpression;
t.VISITOR_KEYS.Property = VISITOR_KEYS.Property;
t.VISITOR_KEYS.MethodDefinition = VISITOR_KEYS.MethodDefinition;
// These can be safely deleted because they are not defined in the original visitor keys. // Make sure we visit `exported` key to remove `identifierName` from loc node
delete t.VISITOR_KEYS.Property; t.VISITOR_KEYS.ExportAllDeclaration = t.VISITOR_KEYS.ExportAllDeclaration.concat(
delete t.VISITOR_KEYS.MethodDefinition; "exported",
);
traverse(ast, astTransformVisitor, null, state);
} finally {
// These can be safely deleted because they are not defined in the original visitor keys.
delete t.VISITOR_KEYS.ChainExpression;
delete t.VISITOR_KEYS.MethodDefinition;
delete t.VISITOR_KEYS.Property;
t.VISITOR_KEYS.ExportAllDeclaration = oldExportAllDeclarationKeys;
}
} }
function convertProgramNode(ast) { function convertProgramNode(ast) {

View File

@ -115,7 +115,6 @@ function convertToken(token, source) {
type === tt.incDec || type === tt.incDec ||
type === tt.colon || type === tt.colon ||
type === tt.question || type === tt.question ||
type === tt.questionDot ||
type === tt.template || type === tt.template ||
type === tt.backQuote || type === tt.backQuote ||
type === tt.dollarBraceL || type === tt.dollarBraceL ||
@ -173,6 +172,12 @@ function convertToken(token, source) {
} else if (type === tt.bigint) { } else if (type === tt.bigint) {
token.type = "Numeric"; token.type = "Numeric";
token.value = `${token.value}n`; token.value = `${token.value}n`;
} else if (type === tt.questionDot) {
token.value = type.label;
}
if (typeof token.type !== "string") {
// Acorn does not have rightAssociative
delete token.type.rightAssociative;
} }
return token; return token;

View File

@ -1,10 +1,13 @@
import { types as t } from "@babel/core"; import { types as t } from "@babel/core";
import { KEYS as ESLINT_VISITOR_KEYS } from "eslint-visitor-keys"; import { KEYS as ESLINT_VISITOR_KEYS } from "eslint-visitor-keys";
const { VISITOR_KEYS: BABEL_VISITOR_KEYS } = t; /*eslint no-unused-vars: ["error", { "ignoreRestSiblings": true }]*/
const { ExportAllDeclaration, ...BABEL_VISITOR_KEYS } = t.VISITOR_KEYS;
export default Object.assign( export default Object.assign(
{ {
ChainExpression: ESLINT_VISITOR_KEYS.ChainExpression,
ExportAllDeclaration: ESLINT_VISITOR_KEYS.ExportAllDeclaration,
Literal: ESLINT_VISITOR_KEYS.Literal, Literal: ESLINT_VISITOR_KEYS.Literal,
MethodDefinition: ["decorators"].concat( MethodDefinition: ["decorators"].concat(
ESLINT_VISITOR_KEYS.MethodDefinition, ESLINT_VISITOR_KEYS.MethodDefinition,

View File

@ -253,6 +253,10 @@ describe("Babel and Espree", () => {
parseAndAssertSame('import "foo";'); parseAndAssertSame('import "foo";');
}); });
it("import meta", () => {
parseAndAssertSame("const url = import.meta.url");
});
it("export default class declaration", () => { it("export default class declaration", () => {
parseAndAssertSame("export default class Foo {}"); parseAndAssertSame("export default class Foo {}");
}); });
@ -273,15 +277,8 @@ describe("Babel and Espree", () => {
parseAndAssertSame('export * from "foo";'); parseAndAssertSame('export * from "foo";');
}); });
// Espree doesn't support `export * as ns` yet
it("export * as ns", () => { it("export * as ns", () => {
const code = 'export * as Foo from "foo";'; parseAndAssertSame('export * as Foo from "foo";');
const babylonAST = parseForESLint(code, {
eslintVisitorKeys: true,
eslintScopeManager: true,
babelOptions: BABEL_OPTIONS,
}).ast;
expect(babylonAST.tokens[1].type).toEqual("Punctuator");
}); });
it("export named", () => { it("export named", () => {
@ -292,26 +289,12 @@ describe("Babel and Espree", () => {
parseAndAssertSame("var foo = 1;export { foo as bar };"); parseAndAssertSame("var foo = 1;export { foo as bar };");
}); });
// Espree doesn't support the optional chaining operator yet it("optional chaining operator", () => {
it("optional chaining operator (token)", () => { parseAndAssertSame("foo?.bar?.().qux()");
const code = "foo?.bar";
const babylonAST = parseForESLint(code, {
eslintVisitorKeys: true,
eslintScopeManager: true,
babelOptions: BABEL_OPTIONS,
}).ast;
expect(babylonAST.tokens[1].type).toEqual("Punctuator");
}); });
// Espree doesn't support the nullish coalescing operator yet it("nullish coalescing operator", () => {
it("nullish coalescing operator (token)", () => { parseAndAssertSame("foo ?? bar");
const code = "foo ?? bar";
const babylonAST = parseForESLint(code, {
eslintVisitorKeys: true,
eslintScopeManager: true,
babelOptions: BABEL_OPTIONS,
}).ast;
expect(babylonAST.tokens[1].type).toEqual("Punctuator");
}); });
// Espree doesn't support the pipeline operator yet // Espree doesn't support the pipeline operator yet

View File

@ -53,7 +53,8 @@ function isOptionalCallExpression(node) {
return ( return (
!!node && !!node &&
node.type === "ExpressionStatement" && node.type === "ExpressionStatement" &&
node.expression.type === "OptionalCallExpression" node.expression.type === "ChainExpression" &&
node.expression.expression.type === "CallExpression"
); );
} }

View File

@ -388,8 +388,6 @@ export default (superClass: Class<Parser>): Class<Parser> =>
delete node.arguments; delete node.arguments;
// $FlowIgnore - callee isn't optional in the type definition // $FlowIgnore - callee isn't optional in the type definition
delete node.callee; delete node.callee;
} else if (node.type === "CallExpression") {
(node: N.Node).optional = false;
} }
return node; return node;
@ -431,10 +429,38 @@ export default (superClass: Class<Parser>): Class<Parser> =>
return node; return node;
} }
parseSubscript(...args) { parseSubscript(
const node = super.parseSubscript(...args); base: N.Expression,
startPos: number,
startLoc: Position,
noCalls: ?boolean,
state: N.ParseSubscriptState,
) {
const node = super.parseSubscript(
base,
startPos,
startLoc,
noCalls,
state,
);
if (node.type === "MemberExpression") { if (state.optionalChainMember) {
// https://github.com/estree/estree/blob/master/es2020.md#chainexpression
if (
node.type === "OptionalMemberExpression" ||
node.type === "OptionalCallExpression"
) {
node.type = node.type.substring(8); // strip Optional prefix
}
if (state.stop) {
const chain = this.startNodeAtNode(node);
chain.expression = node;
return this.finishNode(chain, "ChainExpression");
}
} else if (
node.type === "MemberExpression" ||
node.type === "CallExpression"
) {
node.optional = false; node.optional = false;
} }

View File

@ -0,0 +1 @@
(foo?.())()

View File

@ -0,0 +1,41 @@
{
"type": "File",
"start":0,"end":11,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":11}},
"program": {
"type": "Program",
"start":0,"end":11,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":11}},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start":0,"end":11,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":11}},
"expression": {
"type": "CallExpression",
"start":0,"end":11,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":11}},
"callee": {
"type": "ChainExpression",
"start":1,"end":8,"loc":{"start":{"line":1,"column":1},"end":{"line":1,"column":8}},
"expression": {
"type": "CallExpression",
"start":1,"end":8,"loc":{"start":{"line":1,"column":1},"end":{"line":1,"column":8}},
"callee": {
"type": "Identifier",
"start":1,"end":4,"loc":{"start":{"line":1,"column":1},"end":{"line":1,"column":4},"identifierName":"foo"},
"name": "foo"
},
"optional": true,
"arguments": []
},
"extra": {
"parenthesized": true,
"parenStart": 0
}
},
"arguments": [],
"optional": false
}
}
]
}
}

View File

@ -0,0 +1,37 @@
{
"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": "ChainExpression",
"start":0,"end":9,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":9}},
"expression": {
"type": "CallExpression",
"start":0,"end":9,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":9}},
"callee": {
"type": "CallExpression",
"start":0,"end":7,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":7}},
"callee": {
"type": "Identifier",
"start":0,"end":3,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":3},"identifierName":"foo"},
"name": "foo"
},
"optional": true,
"arguments": []
},
"optional": false,
"arguments": []
}
}
}
]
}
}

View File

@ -0,0 +1,42 @@
{
"type": "File",
"start":0,"end":11,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":11}},
"program": {
"type": "Program",
"start":0,"end":11,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":11}},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start":0,"end":11,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":11}},
"expression": {
"type": "ChainExpression",
"start":0,"end":11,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":11}},
"expression": {
"type": "MemberExpression",
"start":0,"end":11,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":11}},
"object": {
"type": "CallExpression",
"start":0,"end":7,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":7}},
"callee": {
"type": "Identifier",
"start":0,"end":3,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":3},"identifierName":"foo"},
"name": "foo"
},
"optional": true,
"arguments": []
},
"property": {
"type": "Identifier",
"start":8,"end":11,"loc":{"start":{"line":1,"column":8},"end":{"line":1,"column":11},"identifierName":"bar"},
"name": "bar"
},
"computed": false,
"optional": false
}
}
}
]
}
}

View File

@ -0,0 +1 @@
(foo?.()).bar

View File

@ -0,0 +1,46 @@
{
"type": "File",
"start":0,"end":13,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":13}},
"program": {
"type": "Program",
"start":0,"end":13,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":13}},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start":0,"end":13,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":13}},
"expression": {
"type": "MemberExpression",
"start":0,"end":13,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":13}},
"object": {
"type": "ChainExpression",
"start":1,"end":8,"loc":{"start":{"line":1,"column":1},"end":{"line":1,"column":8}},
"expression": {
"type": "CallExpression",
"start":1,"end":8,"loc":{"start":{"line":1,"column":1},"end":{"line":1,"column":8}},
"callee": {
"type": "Identifier",
"start":1,"end":4,"loc":{"start":{"line":1,"column":1},"end":{"line":1,"column":4},"identifierName":"foo"},
"name": "foo"
},
"optional": true,
"arguments": []
},
"extra": {
"parenthesized": true,
"parenStart": 0
}
},
"property": {
"type": "Identifier",
"start":10,"end":13,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":13},"identifierName":"bar"},
"name": "bar"
},
"computed": false,
"optional": false
}
}
]
}
}

View File

@ -0,0 +1,37 @@
{
"type": "File",
"start":0,"end":11,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":11}},
"program": {
"type": "Program",
"start":0,"end":11,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":11}},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start":0,"end":11,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":11}},
"expression": {
"type": "ChainExpression",
"start":0,"end":11,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":11}},
"expression": {
"type": "CallExpression",
"start":0,"end":11,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":11}},
"callee": {
"type": "CallExpression",
"start":0,"end":7,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":7}},
"callee": {
"type": "Identifier",
"start":0,"end":3,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":3},"identifierName":"foo"},
"name": "foo"
},
"optional": true,
"arguments": []
},
"optional": true,
"arguments": []
}
}
}
]
}
}

View File

@ -0,0 +1,42 @@
{
"type": "File",
"start":0,"end":12,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":12}},
"program": {
"type": "Program",
"start":0,"end":12,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":12}},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start":0,"end":12,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":12}},
"expression": {
"type": "ChainExpression",
"start":0,"end":12,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":12}},
"expression": {
"type": "MemberExpression",
"start":0,"end":12,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":12}},
"object": {
"type": "CallExpression",
"start":0,"end":7,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":7}},
"callee": {
"type": "Identifier",
"start":0,"end":3,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":3},"identifierName":"foo"},
"name": "foo"
},
"optional": true,
"arguments": []
},
"property": {
"type": "Identifier",
"start":9,"end":12,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":12},"identifierName":"bar"},
"name": "bar"
},
"computed": false,
"optional": true
}
}
}
]
}
}

View File

@ -0,0 +1 @@
foo?.()

View File

@ -0,0 +1,31 @@
{
"type": "File",
"start":0,"end":7,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":7}},
"program": {
"type": "Program",
"start":0,"end":7,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":7}},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start":0,"end":7,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":7}},
"expression": {
"type": "ChainExpression",
"start":0,"end":7,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":7}},
"expression": {
"type": "CallExpression",
"start":0,"end":7,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":7}},
"callee": {
"type": "Identifier",
"start":0,"end":3,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":3},"identifierName":"foo"},
"name": "foo"
},
"optional": true,
"arguments": []
}
}
}
]
}
}

View File

@ -0,0 +1 @@
(foo?.bar)()

View File

@ -0,0 +1,46 @@
{
"type": "File",
"start":0,"end":12,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":12}},
"program": {
"type": "Program",
"start":0,"end":12,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":12}},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start":0,"end":12,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":12}},
"expression": {
"type": "CallExpression",
"start":0,"end":12,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":12}},
"callee": {
"type": "ChainExpression",
"start":1,"end":9,"loc":{"start":{"line":1,"column":1},"end":{"line":1,"column":9}},
"expression": {
"type": "MemberExpression",
"start":1,"end":9,"loc":{"start":{"line":1,"column":1},"end":{"line":1,"column":9}},
"object": {
"type": "Identifier",
"start":1,"end":4,"loc":{"start":{"line":1,"column":1},"end":{"line":1,"column":4},"identifierName":"foo"},
"name": "foo"
},
"property": {
"type": "Identifier",
"start":6,"end":9,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":9},"identifierName":"bar"},
"name": "bar"
},
"computed": false,
"optional": true
},
"extra": {
"parenthesized": true,
"parenStart": 0
}
},
"arguments": [],
"optional": false
}
}
]
}
}

View File

@ -0,0 +1,42 @@
{
"type": "File",
"start":0,"end":10,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":10}},
"program": {
"type": "Program",
"start":0,"end":10,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":10}},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start":0,"end":10,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":10}},
"expression": {
"type": "ChainExpression",
"start":0,"end":10,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":10}},
"expression": {
"type": "CallExpression",
"start":0,"end":10,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":10}},
"callee": {
"type": "MemberExpression",
"start":0,"end":8,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":8}},
"object": {
"type": "Identifier",
"start":0,"end":3,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":3},"identifierName":"foo"},
"name": "foo"
},
"property": {
"type": "Identifier",
"start":5,"end":8,"loc":{"start":{"line":1,"column":5},"end":{"line":1,"column":8},"identifierName":"bar"},
"name": "bar"
},
"computed": false,
"optional": true
},
"optional": false,
"arguments": []
}
}
}
]
}
}

View File

@ -0,0 +1,47 @@
{
"type": "File",
"start":0,"end":12,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":12}},
"program": {
"type": "Program",
"start":0,"end":12,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":12}},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start":0,"end":12,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":12}},
"expression": {
"type": "ChainExpression",
"start":0,"end":12,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":12}},
"expression": {
"type": "MemberExpression",
"start":0,"end":12,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":12}},
"object": {
"type": "MemberExpression",
"start":0,"end":8,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":8}},
"object": {
"type": "Identifier",
"start":0,"end":3,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":3},"identifierName":"foo"},
"name": "foo"
},
"property": {
"type": "Identifier",
"start":5,"end":8,"loc":{"start":{"line":1,"column":5},"end":{"line":1,"column":8},"identifierName":"bar"},
"name": "bar"
},
"computed": false,
"optional": true
},
"property": {
"type": "Identifier",
"start":9,"end":12,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":12},"identifierName":"qux"},
"name": "qux"
},
"computed": false,
"optional": false
}
}
}
]
}
}

View File

@ -0,0 +1 @@
(foo?.bar).qux

View File

@ -0,0 +1,51 @@
{
"type": "File",
"start":0,"end":14,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":14}},
"program": {
"type": "Program",
"start":0,"end":14,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":14}},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start":0,"end":14,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":14}},
"expression": {
"type": "MemberExpression",
"start":0,"end":14,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":14}},
"object": {
"type": "ChainExpression",
"start":1,"end":9,"loc":{"start":{"line":1,"column":1},"end":{"line":1,"column":9}},
"expression": {
"type": "MemberExpression",
"start":1,"end":9,"loc":{"start":{"line":1,"column":1},"end":{"line":1,"column":9}},
"object": {
"type": "Identifier",
"start":1,"end":4,"loc":{"start":{"line":1,"column":1},"end":{"line":1,"column":4},"identifierName":"foo"},
"name": "foo"
},
"property": {
"type": "Identifier",
"start":6,"end":9,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":9},"identifierName":"bar"},
"name": "bar"
},
"computed": false,
"optional": true
},
"extra": {
"parenthesized": true,
"parenStart": 0
}
},
"property": {
"type": "Identifier",
"start":11,"end":14,"loc":{"start":{"line":1,"column":11},"end":{"line":1,"column":14},"identifierName":"qux"},
"name": "qux"
},
"computed": false,
"optional": false
}
}
]
}
}

View File

@ -0,0 +1,42 @@
{
"type": "File",
"start":0,"end":12,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":12}},
"program": {
"type": "Program",
"start":0,"end":12,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":12}},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start":0,"end":12,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":12}},
"expression": {
"type": "ChainExpression",
"start":0,"end":12,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":12}},
"expression": {
"type": "CallExpression",
"start":0,"end":12,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":12}},
"callee": {
"type": "MemberExpression",
"start":0,"end":8,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":8}},
"object": {
"type": "Identifier",
"start":0,"end":3,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":3},"identifierName":"foo"},
"name": "foo"
},
"property": {
"type": "Identifier",
"start":5,"end":8,"loc":{"start":{"line":1,"column":5},"end":{"line":1,"column":8},"identifierName":"bar"},
"name": "bar"
},
"computed": false,
"optional": true
},
"optional": true,
"arguments": []
}
}
}
]
}
}

View File

@ -0,0 +1,47 @@
{
"type": "File",
"start":0,"end":13,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":13}},
"program": {
"type": "Program",
"start":0,"end":13,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":13}},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start":0,"end":13,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":13}},
"expression": {
"type": "ChainExpression",
"start":0,"end":13,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":13}},
"expression": {
"type": "MemberExpression",
"start":0,"end":13,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":13}},
"object": {
"type": "MemberExpression",
"start":0,"end":8,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":8}},
"object": {
"type": "Identifier",
"start":0,"end":3,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":3},"identifierName":"foo"},
"name": "foo"
},
"property": {
"type": "Identifier",
"start":5,"end":8,"loc":{"start":{"line":1,"column":5},"end":{"line":1,"column":8},"identifierName":"bar"},
"name": "bar"
},
"computed": false,
"optional": true
},
"property": {
"type": "Identifier",
"start":10,"end":13,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":13},"identifierName":"qux"},
"name": "qux"
},
"computed": false,
"optional": true
}
}
}
]
}
}

View File

@ -0,0 +1 @@
foo?.bar

View File

@ -0,0 +1,36 @@
{
"type": "File",
"start":0,"end":8,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":8}},
"program": {
"type": "Program",
"start":0,"end":8,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":8}},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start":0,"end":8,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":8}},
"expression": {
"type": "ChainExpression",
"start":0,"end":8,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":8}},
"expression": {
"type": "MemberExpression",
"start":0,"end":8,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":8}},
"object": {
"type": "Identifier",
"start":0,"end":3,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":3},"identifierName":"foo"},
"name": "foo"
},
"property": {
"type": "Identifier",
"start":5,"end":8,"loc":{"start":{"line":1,"column":5},"end":{"line":1,"column":8},"identifierName":"bar"},
"name": "bar"
},
"computed": false,
"optional": true
}
}
}
]
}
}

View File

@ -2120,12 +2120,7 @@ acorn@^6.0.1:
resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474" resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474"
integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA== integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==
acorn@^7.0.0, acorn@^7.1.0: acorn@^7.0.0, acorn@^7.1.0, acorn@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.1.tgz#e35668de0b402f359de515c5482a1ab9f89a69bf"
integrity sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==
acorn@^7.1.1:
version "7.3.1" version "7.3.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.3.1.tgz#85010754db53c3fbaf3b9ea3e083aa5c5d147ffd" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.3.1.tgz#85010754db53c3fbaf3b9ea3e083aa5c5d147ffd"
integrity sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA== integrity sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA==
@ -4365,7 +4360,7 @@ eslint-plugin-prettier@^3.1.2:
dependencies: dependencies:
prettier-linter-helpers "^1.0.0" prettier-linter-helpers "^1.0.0"
eslint-scope@5.0.0, eslint-scope@^5.0.0: eslint-scope@5.0.0:
version "5.0.0" version "5.0.0"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.0.0.tgz#e87c8887c73e8d1ec84f1ca591645c358bfc8fb9" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.0.0.tgz#e87c8887c73e8d1ec84f1ca591645c358bfc8fb9"
integrity sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw== integrity sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==
@ -4373,6 +4368,14 @@ eslint-scope@5.0.0, eslint-scope@^5.0.0:
esrecurse "^4.1.0" esrecurse "^4.1.0"
estraverse "^4.1.1" estraverse "^4.1.1"
eslint-scope@5.1.0, eslint-scope@^5.0.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.0.tgz#d0f971dfe59c69e0cada684b23d49dbf82600ce5"
integrity sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==
dependencies:
esrecurse "^4.1.0"
estraverse "^4.1.1"
eslint-utils@^1.4.3: eslint-utils@^1.4.3:
version "1.4.3" version "1.4.3"
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f"
@ -4380,10 +4383,10 @@ eslint-utils@^1.4.3:
dependencies: dependencies:
eslint-visitor-keys "^1.1.0" eslint-visitor-keys "^1.1.0"
eslint-visitor-keys@^1.1.0: eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0:
version "1.1.0" version "1.3.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e"
integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==
eslint@^6.8.0: eslint@^6.8.0:
version "6.8.0" version "6.8.0"