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:
@@ -23,8 +23,8 @@
|
||||
"eslint": ">=6.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"eslint-scope": "5.0.0",
|
||||
"eslint-visitor-keys": "^1.1.0",
|
||||
"eslint-scope": "5.1.0",
|
||||
"eslint-visitor-keys": "^1.3.0",
|
||||
"semver": "^6.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { types as t, traverse } from "@babel/core";
|
||||
import VISITOR_KEYS from "../visitor-keys";
|
||||
|
||||
function convertNodes(ast, code) {
|
||||
const astTransformVisitor = {
|
||||
@@ -81,21 +82,28 @@ function convertNodes(ast, code) {
|
||||
};
|
||||
const state = { source: code };
|
||||
|
||||
// Monkey patch visitor keys in order to be able to traverse the estree nodes
|
||||
t.VISITOR_KEYS.Property = t.VISITOR_KEYS.ObjectProperty;
|
||||
t.VISITOR_KEYS.MethodDefinition = [
|
||||
"key",
|
||||
"value",
|
||||
"decorators",
|
||||
"returnType",
|
||||
"typeParameters",
|
||||
];
|
||||
const oldExportAllDeclarationKeys = t.VISITOR_KEYS.ExportAllDeclaration;
|
||||
|
||||
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.
|
||||
delete t.VISITOR_KEYS.Property;
|
||||
delete t.VISITOR_KEYS.MethodDefinition;
|
||||
// Make sure we visit `exported` key to remove `identifierName` from loc node
|
||||
t.VISITOR_KEYS.ExportAllDeclaration = t.VISITOR_KEYS.ExportAllDeclaration.concat(
|
||||
"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) {
|
||||
|
||||
@@ -115,7 +115,6 @@ function convertToken(token, source) {
|
||||
type === tt.incDec ||
|
||||
type === tt.colon ||
|
||||
type === tt.question ||
|
||||
type === tt.questionDot ||
|
||||
type === tt.template ||
|
||||
type === tt.backQuote ||
|
||||
type === tt.dollarBraceL ||
|
||||
@@ -173,6 +172,12 @@ function convertToken(token, source) {
|
||||
} else if (type === tt.bigint) {
|
||||
token.type = "Numeric";
|
||||
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;
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import { types as t } from "@babel/core";
|
||||
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(
|
||||
{
|
||||
ChainExpression: ESLINT_VISITOR_KEYS.ChainExpression,
|
||||
ExportAllDeclaration: ESLINT_VISITOR_KEYS.ExportAllDeclaration,
|
||||
Literal: ESLINT_VISITOR_KEYS.Literal,
|
||||
MethodDefinition: ["decorators"].concat(
|
||||
ESLINT_VISITOR_KEYS.MethodDefinition,
|
||||
|
||||
@@ -253,6 +253,10 @@ describe("Babel and Espree", () => {
|
||||
parseAndAssertSame('import "foo";');
|
||||
});
|
||||
|
||||
it("import meta", () => {
|
||||
parseAndAssertSame("const url = import.meta.url");
|
||||
});
|
||||
|
||||
it("export default class declaration", () => {
|
||||
parseAndAssertSame("export default class Foo {}");
|
||||
});
|
||||
@@ -273,15 +277,8 @@ describe("Babel and Espree", () => {
|
||||
parseAndAssertSame('export * from "foo";');
|
||||
});
|
||||
|
||||
// Espree doesn't support `export * as ns` yet
|
||||
it("export * as ns", () => {
|
||||
const code = 'export * as Foo from "foo";';
|
||||
const babylonAST = parseForESLint(code, {
|
||||
eslintVisitorKeys: true,
|
||||
eslintScopeManager: true,
|
||||
babelOptions: BABEL_OPTIONS,
|
||||
}).ast;
|
||||
expect(babylonAST.tokens[1].type).toEqual("Punctuator");
|
||||
parseAndAssertSame('export * as Foo from "foo";');
|
||||
});
|
||||
|
||||
it("export named", () => {
|
||||
@@ -292,26 +289,12 @@ describe("Babel and Espree", () => {
|
||||
parseAndAssertSame("var foo = 1;export { foo as bar };");
|
||||
});
|
||||
|
||||
// Espree doesn't support the optional chaining operator yet
|
||||
it("optional chaining operator (token)", () => {
|
||||
const code = "foo?.bar";
|
||||
const babylonAST = parseForESLint(code, {
|
||||
eslintVisitorKeys: true,
|
||||
eslintScopeManager: true,
|
||||
babelOptions: BABEL_OPTIONS,
|
||||
}).ast;
|
||||
expect(babylonAST.tokens[1].type).toEqual("Punctuator");
|
||||
it("optional chaining operator", () => {
|
||||
parseAndAssertSame("foo?.bar?.().qux()");
|
||||
});
|
||||
|
||||
// Espree doesn't support the nullish coalescing operator yet
|
||||
it("nullish coalescing operator (token)", () => {
|
||||
const code = "foo ?? bar";
|
||||
const babylonAST = parseForESLint(code, {
|
||||
eslintVisitorKeys: true,
|
||||
eslintScopeManager: true,
|
||||
babelOptions: BABEL_OPTIONS,
|
||||
}).ast;
|
||||
expect(babylonAST.tokens[1].type).toEqual("Punctuator");
|
||||
it("nullish coalescing operator", () => {
|
||||
parseAndAssertSame("foo ?? bar");
|
||||
});
|
||||
|
||||
// Espree doesn't support the pipeline operator yet
|
||||
|
||||
@@ -53,7 +53,8 @@ function isOptionalCallExpression(node) {
|
||||
return (
|
||||
!!node &&
|
||||
node.type === "ExpressionStatement" &&
|
||||
node.expression.type === "OptionalCallExpression"
|
||||
node.expression.type === "ChainExpression" &&
|
||||
node.expression.expression.type === "CallExpression"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user