Skip to content

Commit

Permalink
update parser to new estree
Browse files Browse the repository at this point in the history
  • Loading branch information
bradzacher committed Jul 19, 2020
1 parent 2c90d9f commit 56e3fd3
Show file tree
Hide file tree
Showing 16 changed files with 3,583 additions and 2,521 deletions.
3 changes: 1 addition & 2 deletions packages/types/src/ast-node-types.ts
Expand Up @@ -10,6 +10,7 @@ enum AST_NODE_TYPES {
BreakStatement = 'BreakStatement',
CallExpression = 'CallExpression',
CatchClause = 'CatchClause',
ChainExpression = 'ChainExpression',
ClassBody = 'ClassBody',
ClassDeclaration = 'ClassDeclaration',
ClassExpression = 'ClassExpression',
Expand Down Expand Up @@ -61,8 +62,6 @@ enum AST_NODE_TYPES {
NewExpression = 'NewExpression',
ObjectExpression = 'ObjectExpression',
ObjectPattern = 'ObjectPattern',
OptionalCallExpression = 'OptionalCallExpression',
OptionalMemberExpression = 'OptionalMemberExpression',
Program = 'Program',
Property = 'Property',
RestElement = 'RestElement',
Expand Down
35 changes: 8 additions & 27 deletions packages/types/src/ts-estree.ts
Expand Up @@ -151,6 +151,7 @@ export type Node =
| BreakStatement
| CallExpression
| CatchClause
| ChainExpression
| ClassBody
| ClassDeclaration
| ClassExpression
Expand Down Expand Up @@ -201,8 +202,6 @@ export type Node =
| NewExpression
| ObjectExpression
| ObjectPattern
| OptionalCallExpression
| OptionalMemberExpression
| Program
| Property
| RestElement
Expand Down Expand Up @@ -308,6 +307,7 @@ export type Node =
export type Accessibility = 'public' | 'protected' | 'private';
export type BindingPattern = ArrayPattern | ObjectPattern;
export type BindingName = BindingPattern | Identifier;
export type ChainElement = CallExpression | MemberExpression;
export type ClassElement =
| ClassProperty
| MethodDefinition
Expand Down Expand Up @@ -353,6 +353,7 @@ export type Expression =
| ArrowFunctionExpression
| AssignmentExpression
| BinaryExpression
| ChainExpression
| ConditionalExpression
| ImportExpression
| JSXClosingElement
Expand Down Expand Up @@ -393,8 +394,6 @@ export type LeftHandSideExpression =
| FunctionExpression
| LiteralExpression
| MemberExpression
| OptionalCallExpression
| OptionalMemberExpression
| PrimaryExpression
| TaggedTemplateExpression
| TSNonNullExpression
Expand Down Expand Up @@ -429,9 +428,6 @@ export type ObjectLiteralElementLike =
| Property
| SpreadElement
| TSAbstractMethodDefinition;
export type OptionalMemberExpression =
| OptionalMemberExpressionComputedName
| OptionalMemberExpressionNonComputedName;
export type Parameter =
| ArrayPattern
| AssignmentPattern
Expand Down Expand Up @@ -822,9 +818,13 @@ export interface BreakStatement extends BaseNode {
label: Identifier | null;
}

export interface ChainExpression extends BaseNode {
type: AST_NODE_TYPES.ChainExpression;
expression: ChainElement;
}

export interface CallExpression extends CallExpressionBase {
type: AST_NODE_TYPES.CallExpression;
optional: false;
}

export interface CatchClause extends BaseNode {
Expand Down Expand Up @@ -1086,13 +1086,11 @@ export interface LogicalExpression extends BinaryExpressionBase {
export interface MemberExpressionComputedName
extends MemberExpressionComputedNameBase {
type: AST_NODE_TYPES.MemberExpression;
optional: false;
}

export interface MemberExpressionNonComputedName
extends MemberExpressionNonComputedNameBase {
type: AST_NODE_TYPES.MemberExpression;
optional: false;
}

export interface MetaProperty extends BaseNode {
Expand Down Expand Up @@ -1141,23 +1139,6 @@ export interface ObjectPattern extends BaseNode {
decorators?: Decorator[];
}

export interface OptionalCallExpression extends CallExpressionBase {
type: AST_NODE_TYPES.OptionalCallExpression;
optional: boolean;
}

export interface OptionalMemberExpressionComputedName
extends MemberExpressionComputedNameBase {
type: AST_NODE_TYPES.OptionalMemberExpression;
optional: boolean;
}

export interface OptionalMemberExpressionNonComputedName
extends MemberExpressionNonComputedNameBase {
type: AST_NODE_TYPES.OptionalMemberExpression;
optional: boolean;
}

export interface Program extends BaseNode {
type: AST_NODE_TYPES.Program;
body: Statement[];
Expand Down
124 changes: 60 additions & 64 deletions packages/typescript-estree/src/convert.ts
Expand Up @@ -21,6 +21,7 @@ import {
isOptional,
TSError,
unescapeStringLiteralText,
isChainExpression,
} from './node-utils';
import { ParserWeakMap, ParserWeakMapESTreeToTSNode } from './parser-options';
import {
Expand Down Expand Up @@ -399,6 +400,38 @@ export class Converter {
});
}

private convertChainExpression(
node: TSESTree.ChainElement,
tsNode:
| ts.PropertyAccessExpression
| ts.ElementAccessExpression
| ts.CallExpression,
): TSESTree.ChainExpression | TSESTree.ChainElement {
let child = (node.type === AST_NODE_TYPES.MemberExpression
? node.object
: node.callee) as TSESTree.Node;
const isChildOptional = isChildOptionalChain(tsNode, child);

if (!isChildOptional && !node.optional) {
return node;
}

if (isChainExpression(child)) {
// unwrap the chain expression child
child = child.expression;
if (node.type === AST_NODE_TYPES.MemberExpression) {
node.object = child;
} else {
node.callee = child;
}
}

return this.createNode<TSESTree.ChainExpression>(tsNode, {
type: AST_NODE_TYPES.ChainExpression,
expression: node,
});
}

/**
* For nodes that are copied directly from the TypeScript AST into
* ESTree mostly as-is. The only difference is the addition of a type
Expand Down Expand Up @@ -1771,55 +1804,31 @@ export class Converter {
const property = this.convertChild(node.name);
const computed = false;

const isLocallyOptional = node.questionDotToken !== undefined;
// the optional expression should propagate up the member expression tree
const isChildOptional = isChildOptionalChain(node, object);

if (isLocallyOptional || isChildOptional) {
return this.createNode<TSESTree.OptionalMemberExpression>(node, {
type: AST_NODE_TYPES.OptionalMemberExpression,
object,
property,
computed,
optional: isLocallyOptional,
});
} else {
return this.createNode<TSESTree.MemberExpression>(node, {
type: AST_NODE_TYPES.MemberExpression,
object,
property,
computed,
optional: false,
});
}
const result = this.createNode<TSESTree.MemberExpression>(node, {
type: AST_NODE_TYPES.MemberExpression,
object,
property,
computed,
optional: node.questionDotToken !== undefined,
});

return this.convertChainExpression(result, node);
}

case SyntaxKind.ElementAccessExpression: {
const object = this.convertChild(node.expression);
const property = this.convertChild(node.argumentExpression);
const computed = true;

const isLocallyOptional = node.questionDotToken !== undefined;
// the optional expression should propagate up the member expression tree
const isChildOptional = isChildOptionalChain(node, object);

if (isLocallyOptional || isChildOptional) {
return this.createNode<TSESTree.OptionalMemberExpression>(node, {
type: AST_NODE_TYPES.OptionalMemberExpression,
object,
property,
computed,
optional: isLocallyOptional,
});
} else {
return this.createNode<TSESTree.MemberExpression>(node, {
type: AST_NODE_TYPES.MemberExpression,
object,
property,
computed,
optional: false,
});
}
const result = this.createNode<TSESTree.MemberExpression>(node, {
type: AST_NODE_TYPES.MemberExpression,
object,
property,
computed,
optional: node.questionDotToken !== undefined,
});

return this.convertChainExpression(result, node);
}

case SyntaxKind.CallExpression: {
Expand All @@ -1839,35 +1848,22 @@ export class Converter {

const callee = this.convertChild(node.expression);
const args = node.arguments.map(el => this.convertChild(el));
let result;

const isLocallyOptional = node.questionDotToken !== undefined;
// the optional expression should propagate up the member expression tree
const isChildOptional = isChildOptionalChain(node, callee);

if (isLocallyOptional || isChildOptional) {
result = this.createNode<TSESTree.OptionalCallExpression>(node, {
type: AST_NODE_TYPES.OptionalCallExpression,
callee,
arguments: args,
optional: isLocallyOptional,
});
} else {
result = this.createNode<TSESTree.CallExpression>(node, {
type: AST_NODE_TYPES.CallExpression,
callee,
arguments: args,
optional: false,
});
}

const result = this.createNode<TSESTree.CallExpression>(node, {
type: AST_NODE_TYPES.CallExpression,
callee,
arguments: args,
optional: node.questionDotToken !== undefined,
});

if (node.typeArguments) {
result.typeParameters = this.convertTypeArgumentsToTypeParameters(
node.typeArguments,
node,
);
}
return result;

return this.convertChainExpression(result, node);
}

case SyntaxKind.NewExpression: {
Expand Down
17 changes: 7 additions & 10 deletions packages/typescript-estree/src/node-utils.ts
Expand Up @@ -443,13 +443,10 @@ export function isOptional(node: {
/**
* Returns true if the node is an optional chain node
*/
export function isOptionalChain(
export function isChainExpression(
node: TSESTree.Node,
): node is TSESTree.OptionalCallExpression | TSESTree.OptionalMemberExpression {
return (
node.type === AST_NODE_TYPES.OptionalCallExpression ||
node.type == AST_NODE_TYPES.OptionalMemberExpression
);
): node is TSESTree.ChainExpression {
return node.type === AST_NODE_TYPES.ChainExpression;
}

/**
Expand All @@ -467,10 +464,10 @@ export function isChildOptionalChain(
| ts.PropertyAccessExpression
| ts.ElementAccessExpression
| ts.CallExpression,
object: TSESTree.LeftHandSideExpression,
child: TSESTree.Node,
): boolean {
if (
isOptionalChain(object) &&
isChainExpression(child) &&
// (x?.y).z is semantically different, and as such .z is no longer optional
node.expression.kind !== ts.SyntaxKind.ParenthesizedExpression
) {
Expand All @@ -486,8 +483,8 @@ export function isChildOptionalChain(
// Post-3.9, `x?.y!.z` means `x?.y!.z` - i.e. it just asserts that the property `y` is non-null, not the result of `x?.y`

if (
object.type !== AST_NODE_TYPES.TSNonNullExpression ||
!isOptionalChain(object.expression)
child.type !== AST_NODE_TYPES.TSNonNullExpression ||
!isChainExpression(child.expression)
) {
return false;
}
Expand Down
Expand Up @@ -20,6 +20,10 @@ export interface EstreeToTsNodeTypes {
[AST_NODE_TYPES.BreakStatement]: ts.BreakStatement;
[AST_NODE_TYPES.CallExpression]: ts.CallExpression;
[AST_NODE_TYPES.CatchClause]: ts.CatchClause;
[AST_NODE_TYPES.ChainExpression]:
| ts.CallExpression
| ts.PropertyAccessExpression
| ts.ElementAccessExpression;
[AST_NODE_TYPES.ClassBody]: ts.ClassDeclaration | ts.ClassExpression;
[AST_NODE_TYPES.ClassDeclaration]: ts.ClassDeclaration;
[AST_NODE_TYPES.ClassExpression]: ts.ClassExpression;
Expand Down Expand Up @@ -114,10 +118,6 @@ export interface EstreeToTsNodeTypes {
[AST_NODE_TYPES.ObjectPattern]:
| ts.ObjectLiteralExpression
| ts.ObjectBindingPattern;
[AST_NODE_TYPES.OptionalCallExpression]: ts.CallExpression;
[AST_NODE_TYPES.OptionalMemberExpression]:
| ts.PropertyAccessExpression
| ts.ElementAccessExpression;
[AST_NODE_TYPES.Program]: ts.SourceFile;
[AST_NODE_TYPES.Property]:
| ts.PropertyAssignment
Expand Down
18 changes: 18 additions & 0 deletions packages/typescript-estree/tests/ast-alignment/fixtures-to-test.ts
Expand Up @@ -424,6 +424,18 @@ tester.addFixturePatternConfig('typescript/basics', {
*/
'catch-clause-with-annotation',
'catch-clause-with-invalid-annotation',
/**
* Optional chain - babel doesn't yet support the new ESTree representation
*/
'optional-chain',
'optional-chain-with-parens',
'optional-chain-with-non-null-assertion',
'optional-chain-element-access',
'optional-chain-element-access-with-parens',
'optional-chain-element-access-with-non-null-assertion',
'optional-chain-call',
'optional-chain-call-with-parens',
'optional-chain-call-with-non-null-assertion',
],
ignoreSourceType: [
/**
Expand Down Expand Up @@ -468,6 +480,12 @@ tester.addFixturePatternConfig('typescript/decorators/property-decorators', {

tester.addFixturePatternConfig('typescript/expressions', {
fileType: 'ts',
ignore: [
/**
* Optional chain - babel doesn't yet support the new ESTree representation
*/
'optional-call-expression-type-arguments',
],
});

tester.addFixturePatternConfig('typescript/errorRecovery', {
Expand Down

0 comments on commit 56e3fd3

Please sign in to comment.