diff --git a/web-infras/common/src/ast.ts b/web-infras/common/src/ast.ts index 3a5e961f..9a2f64fc 100644 --- a/web-infras/common/src/ast.ts +++ b/web-infras/common/src/ast.ts @@ -35,6 +35,8 @@ export interface MethodDefinition extends ModuleItem { key: PropertyName | PrivateName; body: FunctionBody; params: Array; + typeParameters: TSTypeParameterDeclaration | undefined; + returnType: TSTypeAnnotation | undefined; type: "constructor" | "method" | "get" | "set"; computed: boolean; generator: boolean; @@ -141,6 +143,8 @@ export interface ThisExpression extends ExpressionModuleItem { export interface Identifier extends ExpressionModuleItem { kind: SyntaxKinds.Identifier; name: string; + typeAnnotation: TSTypeAnnotation | undefined; + optional: boolean | undefined; } export interface PrivateName extends ExpressionModuleItem { kind: SyntaxKinds.PrivateName; @@ -265,6 +269,8 @@ export interface ArrorFunctionExpression extends ExpressionModuleItem { expressionBody: boolean; async: boolean; arguments: Array; + typeParameters: TSTypeParameterDeclaration | undefined; + returnType: TSTypeAnnotation | undefined; body: Expression | FunctionBody; } export interface MetaProperty extends ExpressionModuleItem { @@ -280,6 +286,7 @@ export interface NewExpression extends ExpressionModuleItem { kind: SyntaxKinds.NewExpression; callee: Expression; arguments: Array; + typeArguments: TSTypeParameterInstantiation | undefined; } export interface MemberExpression extends ExpressionModuleItem { kind: SyntaxKinds.MemberExpression; @@ -292,6 +299,7 @@ export interface CallExpression extends ExpressionModuleItem { kind: SyntaxKinds.CallExpression; callee: Expression; arguments: Array; + typeArguments: TSTypeParameterInstantiation | undefined; optional: boolean; } export interface TaggedTemplateExpression extends ExpressionModuleItem { @@ -342,6 +350,35 @@ export interface SequenceExpression extends ExpressionModuleItem { exprs: Array; } +export interface TSInstantiationExpression extends ExpressionModuleItem { + kind: SyntaxKinds.TSInstantiationExpression; + typeArguments: TSTypeParameterInstantiation; + expression: Expression; +} + +export interface TSTypeAssertionExpression extends ExpressionModuleItem { + kind: SyntaxKinds.TSTypeAssertionExpression; + expression: Expression; + typeAnnotation: TSTypeNode; +} + +export interface TSAsExpression extends ExpressionModuleItem { + kind: SyntaxKinds.TSAsExpression; + expression: Expression; + typeAnnotation: TSTypeNode; +} + +export interface TSSatisfiesExpression extends ExpressionModuleItem { + kind: SyntaxKinds.TSSatisfiesExpression; + expression: Expression; + typeAnnotation: TSTypeNode; +} + +export interface TSNonNullExpression extends ExpressionModuleItem { + kind: SyntaxKinds.TSNonNullExpression; + expression: Expression; +} + export type Expression = // jsx element | JSXElement @@ -382,7 +419,13 @@ export type Expression = | ConditionalExpression | YieldExpression | AssigmentExpression - | SequenceExpression; + | SequenceExpression + // TS expression + | TSInstantiationExpression + | TSTypeAssertionExpression + | TSAsExpression + | TSSatisfiesExpression + | TSNonNullExpression; export interface ExpressionStatement extends ModuleItem { kind: SyntaxKinds.ExpressionStatement; expr: Expression; @@ -395,6 +438,8 @@ export interface ExpressionStatement extends ModuleItem { export interface ObjectPattern extends ModuleItem { kind: SyntaxKinds.ObjectPattern; properties: Array; + typeAnnotation: TSTypeAnnotation | undefined; + optional: boolean | undefined; } export interface ObjectPatternProperty extends ModuleItem { kind: SyntaxKinds.ObjectPatternProperty; @@ -406,15 +451,21 @@ export interface ObjectPatternProperty extends ModuleItem { export interface ArrayPattern extends ModuleItem { kind: SyntaxKinds.ArrayPattern; elements: Array; + typeAnnotation: TSTypeAnnotation | undefined; + optional: boolean | undefined; } export interface AssignmentPattern extends ModuleItem { kind: SyntaxKinds.AssignmentPattern; left: Pattern; right: Expression; + typeAnnotation: TSTypeAnnotation | undefined; + optional: boolean | undefined; } export interface RestElement extends ModuleItem { kind: SyntaxKinds.RestElement; argument: Pattern; + typeAnnotation: TSTypeAnnotation | undefined; + optional: boolean | undefined; } export type Pattern = @@ -423,7 +474,11 @@ export type Pattern = | ObjectPattern | ArrayPattern | Identifier - | MemberExpression; + | MemberExpression + | TSAsExpression + | TSTypeAssertionExpression + | TSSatisfiesExpression + | TSNonNullExpression; /** ========================== * Statement @@ -516,6 +571,8 @@ export interface ForOfStatement extends ModuleItem { await: boolean; body: Statement; } +// TODO. better Type +// type ForOfInStatementLeft = VariableDeclaration | Pattern | TSAsExpression | TSTypeAssertionExpression; export interface ForInStatement extends ModuleItem { kind: SyntaxKinds.ForInStatement; left: Expression | VariableDeclaration; @@ -560,6 +617,8 @@ export interface VariableDeclarator extends ModuleItem { export interface Function extends Omit { name: Identifier | null; params: Array; + typeParameters: TSTypeParameterDeclaration | undefined; + returnType: TSTypeAnnotation | undefined; body: FunctionBody; generator: boolean; async: boolean; @@ -595,7 +654,7 @@ export interface ClassMethodDefinition extends Omit { decorators: Decorator[] | null; } export interface ClassConstructor - extends Omit { + extends Omit { kind: SyntaxKinds.ClassConstructor; key: Identifier; } @@ -622,7 +681,9 @@ export interface Decorator extends ModuleItem { kind: SyntaxKinds.Decorator; expression: Expression; } -export type Declaration = FunctionDeclaration | VariableDeclaration | ClassDeclaration; +export type Declaration = FunctionDeclaration | VariableDeclaration | ClassDeclaration | TSDeclaration; + +type TSDeclaration = TSTypeAliasDeclaration | TSInterfaceDeclaration | TSEnumDeclaration | TSDeclareFunction; /** ========================================== * Import Declaration @@ -665,7 +726,13 @@ export interface ExportSpecifier extends ModuleItem { } export interface ExportDefaultDeclaration extends ModuleItem { kind: SyntaxKinds.ExportDefaultDeclaration; - declaration: FunctionDeclaration | FunctionExpression | ClassDeclaration | ClassExpression | Expression; + declaration: + | FunctionDeclaration + | FunctionExpression + | ClassDeclaration + | ClassExpression + | Expression + | TSDeclaration; } export interface ExportAllDeclaration extends ModuleItem { kind: SyntaxKinds.ExportAllDeclaration; @@ -684,6 +751,237 @@ export interface ImportAttribute extends ModuleItem { value: StringLiteral; } +/** ======================================== + * TypeScript AST + * reference from typescript-eslint AST spec + * to create estree based AST for TypeScript. + * ========================================= + */ +export type TSTypeNode = + | TSConditionalType + | TSUnionType + | TSIntersectionType + | TSTypeOperator + | TSArrayType + | TSIndexedAccessType + | TSTypeQuery + | TSLiteralType + | TSConstrcutorType + | TSInterfaceDeclaration + | TSTypeAliasDeclaration + | TSFunctionType + | TSTypeLiteral + | TSTupleType + | TSTypePredicate + | TSTypeReference + | TSStringKeyword + | TSNumberKeyword + | TSBigIntKeyword + | TSBooleanKeyword + | TSNullKeyword + | TSUndefinedKeyword + | TSSymbolKeyword + | TSAnyKeyword + | TSNeverKeyword + | TSUnknowKeyword + | TSVoidKeyword; + +// ======== TS Comnputed Type +export interface TSConditionalType extends ModuleItem { + kind: SyntaxKinds.TSConditionalType; + checkType: TSTypeNode; + extendType: TSTypeNode; + trueType: TSTypeNode; + falseType: TSTypeNode; +} +export interface TSUnionType extends ModuleItem { + kind: SyntaxKinds.TSUnionType; + types: Array; +} +export interface TSIntersectionType extends ModuleItem { + kind: SyntaxKinds.TSIntersectionType; + types: Array; +} +export interface TSTypeOperator extends ModuleItem { + kind: SyntaxKinds.TSTypeOperator; + operator: "keyof" | "unique" | "readonly"; + typeAnnotation: TSTypeNode; +} +export interface TSArrayType extends ModuleItem { + kind: SyntaxKinds.TSArrayType; + elementType: TSTypeNode; +} +export interface TSIndexedAccessType extends ModuleItem { + kind: SyntaxKinds.TSIndexedAccessType; + indexedType: TSTypeNode; + objectType: TSTypeNode; +} +// ======= TS High Level Basic Type + +// ======= TS Type-Param +export interface TSTypeParameterDeclaration extends ModuleItem { + kind: SyntaxKinds.TSTypeParameterDeclaration; + params: Array; +} + +export interface TSTypeParameter extends ModuleItem { + kind: SyntaxKinds.TSTypeParameter; + constraint: TSTypeNode | undefined; + default: TSTypeNode | undefined; + name: Identifier; +} + +export interface TSTypeParameterInstantiation extends ModuleItem { + kind: SyntaxKinds.TSTypeParameterInstantiation; + params: Array; +} +// ===== TS Basic Type +export interface TSFunctionType extends TSFunctionSignatureBase { + kind: SyntaxKinds.TSFunctionType; +} +export interface TSDeclareFunction extends Omit, ModuleItem { + kind: SyntaxKinds.TSDeclareFunction; +} +export interface TSConstrcutorType extends TSFunctionSignatureBase { + kind: SyntaxKinds.TSConstructorType; +} +export interface TSEnumDeclaration extends ModuleItem { + id: Identifier; + kind: SyntaxKinds.TSEnumDeclaration; + body: TSEnumBody; +} + +export interface TSEnumBody extends ModuleItem { + kind: SyntaxKinds.TSEnumBody; + members: Array; +} +export interface TSEnumMember extends ModuleItem { + kind: SyntaxKinds.TSEnumMember; + computed: boolean; + id: Identifier; + init: Expression | undefined; +} + +export interface TSTypeAliasDeclaration extends ModuleItem { + kind: SyntaxKinds.TSTypeAliasDeclaration; + name: Identifier; + typeAnnotation: TSTypeNode; + typeParameters: TSTypeParameterDeclaration | undefined; +} +export interface TSInterfaceDeclaration extends ModuleItem { + kind: SyntaxKinds.TSInterfaceDeclaration; + name: Identifier; + body: TSInterfaceBody; + typeParameters: TSTypeParameterDeclaration | undefined; + extends: Array; +} +export interface TSInterfaceHeritage extends ModuleItem { + typeName: TSEntityName; + typeArguments: TSTypeParameterInstantiation | undefined; +} +export interface TSInterfaceBody extends ModuleItem { + kind: SyntaxKinds.TSInterfaceBody; + body: TSTypeElement[]; +} +export type TSParameter = Identifier | ObjectPattern | AssignmentPattern | ArrayPattern | RestElement; +export interface TSTypeAnnotation extends ModuleItem { + kind: SyntaxKinds.TSTypeAnnotation; + typeAnnotation: TSTypeNode; +} +export interface TSTypePredicate extends ModuleItem { + kind: SyntaxKinds.TSTypePredicate; + parameterName: Identifier; + asserts: boolean; + typeAnnotation: TSTypeAnnotation | undefined; +} +export interface TSFunctionSignatureBase extends ModuleItem { + returnType: TSTypeAnnotation | undefined; + parameters: Array; + typeParameters: TSTypeParameterDeclaration | undefined; +} +export interface TSTypeLiteral extends ModuleItem { + members: Array; +} +export type TSTypeElement = + | TSCallSignatureDeclaration + | TSConstructSignatureDeclaration + // | TSIndexSignature + | TSMethodSignature + | TSPropertySignature; +export interface TSPropertySignature extends ModuleItem { + kind: SyntaxKinds.TSPropertySignature; + key: PropertyName; + computed: boolean; + optional: boolean; + typeAnnotation: TSTypeAnnotation | undefined; +} +export interface TSCallSignatureDeclaration extends TSFunctionSignatureBase { + kind: SyntaxKinds.TSCallSignatureDeclaration; +} +export interface TSConstructSignatureDeclaration extends TSFunctionSignatureBase { + kind: SyntaxKinds.TSConstructSignatureDeclaration; +} +export interface TSMethodSignature extends TSFunctionSignatureBase { + kind: SyntaxKinds.TSMethodSignature; + key: PropertyName; + computed: boolean; + optional: boolean; +} +export interface TSTypeQuery extends ModuleItem { + kind: SyntaxKinds.TSTypeQuery; + exprName: TSEntityName; +} +export interface TSTupleType extends ModuleItem { + kind: SyntaxKinds.TSTupleType; + elementTypes: Array; +} +export interface TSLiteralType extends ModuleItem { + kind: SyntaxKinds.TSLiteralType; + literal: StringLiteral | NumberLiteral | BoolLiteral | NullLiteral | UndefinbedLiteral; +} +export interface TSTypeReference extends ModuleItem { + typeName: TSEntityName; + typeArguments: TSTypeParameterInstantiation | undefined; +} +export interface TSQualifiedName extends ModuleItem { + kind: SyntaxKinds.TSQualifiedName; + left: TSEntityName; + right: Identifier; +} +export type TSEntityName = Identifier | TSQualifiedName; +export interface TSStringKeyword extends ModuleItem { + kind: SyntaxKinds.TSStringKeyword; +} +export interface TSNumberKeyword extends ModuleItem { + kind: SyntaxKinds.TSNumberKeyword; +} +export interface TSBigIntKeyword extends ModuleItem { + kind: SyntaxKinds.TSBigIntKeyword; +} +export interface TSBooleanKeyword extends ModuleItem { + kind: SyntaxKinds.TSBooleanKeyword; +} +export interface TSNullKeyword extends ModuleItem { + kind: SyntaxKinds.TSNullKeyword; +} +export interface TSUndefinedKeyword extends ModuleItem { + kind: SyntaxKinds.TSUndefinedKeyword; +} +export interface TSSymbolKeyword extends ModuleItem { + kind: SyntaxKinds.TSSymbolKeyword; +} +export interface TSAnyKeyword extends ModuleItem { + kind: SyntaxKinds.TSAnyKeyword; +} +export interface TSNeverKeyword extends ModuleItem { + kind: SyntaxKinds.TSNeverKeyword; +} +export interface TSUnknowKeyword extends ModuleItem { + kind: SyntaxKinds.TSUnknowKeyword; +} +export interface TSVoidKeyword extends ModuleItem { + kind: SyntaxKinds.TSVoidKeyword; +} /** ======================================== * Helper * ========================================= diff --git a/web-infras/common/src/factory.ts b/web-infras/common/src/factory.ts index be4cb057..6d71118f 100644 --- a/web-infras/common/src/factory.ts +++ b/web-infras/common/src/factory.ts @@ -3,10 +3,18 @@ import * as AST from "./ast"; import { SyntaxKinds } from "./kind"; import { AssigmentOperatorKinds, BinaryOperatorKinds, UnaryOperatorKinds, UpdateOperatorKinds } from "./kind"; -export function createIdentifier(name: string, start: SourcePosition, end: SourcePosition): AST.Identifier { +export function createIdentifier( + name: string, + start: SourcePosition, + end: SourcePosition, + typeAnnotation: AST.TSTypeAnnotation | undefined, + optional: boolean | undefined, +): AST.Identifier { return { kind: SyntaxKinds.Identifier, name, + typeAnnotation, + optional, start, end, }; @@ -269,6 +277,8 @@ export function createObjectMethodDefintion( key: AST.ObjectMethodDefinition["key"], body: AST.ObjectMethodDefinition["body"], params: AST.ObjectMethodDefinition["params"], + typeParameters: AST.ObjectMethodDefinition["typeParameters"], + returnType: AST.ObjectMethodDefinition["returnType"], async: AST.ObjectMethodDefinition["async"], generator: AST.ObjectMethodDefinition["generator"], computed: AST.ObjectMethodDefinition["computed"], @@ -282,6 +292,8 @@ export function createObjectMethodDefintion( computed, key, params, + typeParameters, + returnType, body, start, end, @@ -291,6 +303,8 @@ export function createObjectAccessor( key: AST.ObjectAccessor["key"], body: AST.ObjectAccessor["body"], params: AST.ObjectAccessor["params"], + typeParameters: AST.ObjectAccessor["typeParameters"], + returnType: AST.ObjectAccessor["returnType"], type: AST.ObjectAccessor["type"], computed: AST.ObjectAccessor["computed"], start: SourcePosition, @@ -300,6 +314,8 @@ export function createObjectAccessor( kind: SyntaxKinds.ObjectAccessor, key, params, + typeParameters, + returnType, body, type, computed, @@ -372,6 +388,7 @@ export function createChainExpression( export function createCallExpression( callee: AST.Expression, calleeArguments: Array, + typeArguments: AST.CallExpression["typeArguments"], optional: boolean, start: SourcePosition, end: SourcePosition, @@ -380,6 +397,7 @@ export function createCallExpression( kind: SyntaxKinds.CallExpression, optional, callee, + typeArguments, arguments: calleeArguments, start, end, @@ -388,6 +406,7 @@ export function createCallExpression( export function createNewExpression( callee: AST.Expression, calleeArguments: Array, + typeArguments: AST.NewExpression["typeArguments"], start: SourcePosition, end: SourcePosition, ): AST.NewExpression { @@ -395,6 +414,7 @@ export function createNewExpression( kind: SyntaxKinds.NewExpression, callee, arguments: calleeArguments, + typeArguments, start, end, }; @@ -477,6 +497,8 @@ export function createArrowExpression( isExpression: boolean, body: AST.Expression | AST.FunctionBody, calleeArguments: AST.ArrorFunctionExpression["arguments"], + typeParameters: AST.ArrorFunctionExpression["typeParameters"], + returnType: AST.ArrorFunctionExpression["returnType"], async: boolean, start: SourcePosition, end: SourcePosition, @@ -486,6 +508,8 @@ export function createArrowExpression( expressionBody: isExpression, async, arguments: calleeArguments, + typeParameters, + returnType, body, start, end, @@ -593,6 +617,8 @@ export function createFunction( name: AST.Function["name"], body: AST.Function["body"], params: AST.Function["params"], + typeParameters: AST.Function["typeParameters"], + returnType: AST.Function["returnType"], generator: AST.Function["generator"], async: AST.Function["async"], start: SourcePosition, @@ -604,6 +630,8 @@ export function createFunction( async, body, params, + typeParameters, + returnType, start, end, }; @@ -709,6 +737,8 @@ export function createClassMethodDefintion( key: AST.ClassMethodDefinition["key"], body: AST.ClassMethodDefinition["body"], params: AST.ClassMethodDefinition["params"], + typeParameters: AST.ClassMethodDefinition["typeParameters"], + returnType: AST.ClassMethodDefinition["returnType"], async: AST.ClassMethodDefinition["async"], generator: AST.ClassMethodDefinition["generator"], computed: AST.ClassMethodDefinition["computed"], @@ -725,6 +755,8 @@ export function createClassMethodDefintion( static: isStatic, key, params, + typeParameters, + returnType, body, decorators, start, @@ -735,6 +767,7 @@ export function createClassConstructor( key: AST.ClassConstructor["key"], body: AST.ClassConstructor["body"], params: AST.ClassConstructor["params"], + returnType: AST.ClassConstructor["returnType"], start: SourcePosition, end: SourcePosition, ): AST.ClassConstructor { @@ -743,6 +776,7 @@ export function createClassConstructor( key, body, params, + returnType, start, end, }; @@ -751,6 +785,8 @@ export function createClassAccessor( key: AST.ClassAccessor["key"], body: AST.ClassAccessor["body"], params: AST.ClassAccessor["params"], + typeParameters: AST.ClassAccessor["typeParameters"], + returnType: AST.ClassAccessor["returnType"], type: AST.ClassAccessor["type"], computed: AST.ClassAccessor["computed"], decorators: AST.Class["decorators"], @@ -761,6 +797,8 @@ export function createClassAccessor( kind: SyntaxKinds.ClassAccessor, key, params, + typeParameters, + returnType, body, type, computed, @@ -1080,6 +1118,8 @@ export function createForOfStatement( export function createAssignmentPattern( left: AST.AssignmentPattern["left"], right: AST.AssignmentPattern["right"], + typeAnnotation: AST.AssignmentPattern["typeAnnotation"], + optional: AST.AssignmentPattern["optional"], start: SourcePosition, end: SourcePosition, ): AST.AssignmentPattern { @@ -1087,12 +1127,16 @@ export function createAssignmentPattern( kind: SyntaxKinds.AssignmentPattern, left, right, + typeAnnotation, + optional, start, end, }; } export function createArrayPattern( elements: AST.ArrayPattern["elements"], + typeAnnotation: AST.ArrayPattern["typeAnnotation"], + optional: AST.ArrayPattern["optional"], start: SourcePosition, end: SourcePosition, ): AST.ArrayPattern { @@ -1100,17 +1144,23 @@ export function createArrayPattern( kind: SyntaxKinds.ArrayPattern, elements, start, + typeAnnotation, + optional, end, }; } export function createObjectPattern( properties: AST.ObjectPattern["properties"], + typeAnnotation: AST.ObjectPattern["typeAnnotation"], + optional: AST.ObjectPattern["optional"], start: SourcePosition, end: SourcePosition, ): AST.ObjectPattern { return { kind: SyntaxKinds.ObjectPattern, properties, + typeAnnotation, + optional, start, end, }; @@ -1135,12 +1185,16 @@ export function createObjectPatternProperty( } export function createRestElement( argument: AST.RestElement["argument"], + typeAnnotation: AST.RestElement["typeAnnotation"], + optional: AST.RestElement["optional"], start: SourcePosition, end: SourcePosition, ): AST.RestElement { return { kind: SyntaxKinds.RestElement, argument, + typeAnnotation, + optional, start, end, }; @@ -1465,3 +1519,636 @@ export function createJSXClosingFragment(start: SourcePosition, end: SourcePosit end, }; } + +export function createTSStringKeyword(start: SourcePosition, end: SourcePosition): AST.TSStringKeyword { + return { + kind: SyntaxKinds.TSStringKeyword, + start, + end, + }; +} + +export function createTSNumberKeyword(start: SourcePosition, end: SourcePosition): AST.TSNumberKeyword { + return { + kind: SyntaxKinds.TSNumberKeyword, + start, + end, + }; +} + +export function createTSBigintKeyword(start: SourcePosition, end: SourcePosition): AST.TSBigIntKeyword { + return { + kind: SyntaxKinds.TSBigIntKeyword, + start, + end, + }; +} + +export function createTSBoolKeyword(start: SourcePosition, end: SourcePosition): AST.TSBooleanKeyword { + return { + kind: SyntaxKinds.TSBooleanKeyword, + start, + end, + }; +} + +export function createTSNullKeyword(start: SourcePosition, end: SourcePosition): AST.TSNullKeyword { + return { + kind: SyntaxKinds.TSNullKeyword, + start, + end, + }; +} + +export function createTSUndefinedKeyword(start: SourcePosition, end: SourcePosition): AST.TSUndefinedKeyword { + return { + kind: SyntaxKinds.TSUndefinedKeyword, + start, + end, + }; +} + +export function createTSSymbolKeyword(start: SourcePosition, end: SourcePosition): AST.TSSymbolKeyword { + return { + kind: SyntaxKinds.TSSymbolKeyword, + start, + end, + }; +} + +export function createTSAnyKeyword(start: SourcePosition, end: SourcePosition): AST.TSAnyKeyword { + return { + kind: SyntaxKinds.TSAnyKeyword, + start, + end, + }; +} + +export function createTSNeverKeyword(start: SourcePosition, end: SourcePosition): AST.TSUndefinedKeyword { + return { + kind: SyntaxKinds.TSUndefinedKeyword, + start, + end, + }; +} + +export function createTSUnknowKeyword(start: SourcePosition, end: SourcePosition): AST.TSUnknowKeyword { + return { + kind: SyntaxKinds.TSUnknowKeyword, + start, + end, + }; +} + +export function createTSTypeAnnotation( + typeAnnotation: AST.TSTypeNode, + start: SourcePosition, + end: SourcePosition, +): AST.TSTypeAnnotation { + return { + kind: SyntaxKinds.TSTypeAnnotation, + typeAnnotation, + start, + end, + }; +} + +export function createTSTypePredicate( + parameterName: AST.TSTypePredicate["parameterName"], + asserts: AST.TSTypePredicate["asserts"], + typeAnnotation: AST.TSTypePredicate["typeAnnotation"], + start: SourcePosition, + end: SourcePosition, +): AST.TSTypePredicate { + return { + kind: SyntaxKinds.TSTypePredicate, + parameterName, + asserts, + typeAnnotation, + start, + end, + }; +} + +export function createTSCallSignatureDeclaration( + parameters: AST.TSCallSignatureDeclaration["parameters"], + returnType: AST.TSCallSignatureDeclaration["returnType"], + typeParameters: AST.TSCallSignatureDeclaration["typeParameters"], + start: SourcePosition, + end: SourcePosition, +): AST.TSCallSignatureDeclaration { + return { + kind: SyntaxKinds.TSCallSignatureDeclaration, + parameters, + returnType, + typeParameters, + start, + end, + }; +} + +export function createTSConstructSignatureDeclaration( + parameters: AST.TSConstructSignatureDeclaration["parameters"], + returnType: AST.TSConstructSignatureDeclaration["returnType"], + typeParameters: AST.TSConstructSignatureDeclaration["typeParameters"], + start: SourcePosition, + end: SourcePosition, +): AST.TSConstructSignatureDeclaration { + return { + kind: SyntaxKinds.TSConstructSignatureDeclaration, + parameters, + returnType, + typeParameters, + start, + end, + }; +} + +export function createTSPropertySignature( + key: AST.TSPropertySignature["key"], + computed: AST.TSPropertySignature["computed"], + optional: AST.TSPropertySignature["optional"], + typeAnnotation: AST.TSPropertySignature["typeAnnotation"], + start: SourcePosition, + end: SourcePosition, +): AST.TSPropertySignature { + return { + kind: SyntaxKinds.TSPropertySignature, + key, + computed, + optional, + typeAnnotation, + start, + end, + }; +} + +export function createTSMethodSignature( + key: AST.TSMethodSignature["key"], + computed: AST.TSMethodSignature["computed"], + optional: AST.TSMethodSignature["optional"], + parameters: AST.TSMethodSignature["parameters"], + returnType: AST.TSMethodSignature["returnType"], + typeParameters: AST.TSMethodSignature["typeParameters"], + start: SourcePosition, + end: SourcePosition, +): AST.TSMethodSignature { + return { + kind: SyntaxKinds.TSMethodSignature, + key, + computed, + optional, + parameters, + returnType, + typeParameters, + start, + end, + }; +} + +export function createTSTypeReference( + typeName: AST.TSEntityName, + typeArguments: AST.TSTypeReference["typeArguments"], + start: SourcePosition, + end: SourcePosition, +): AST.TSTypeReference { + return { + kind: SyntaxKinds.TSTypeReference, + typeName, + typeArguments, + start, + end, + }; +} + +export function createTSQualifiedName( + left: AST.TSEntityName, + right: AST.Identifier, + start: SourcePosition, + end: SourcePosition, +): AST.TSQualifiedName { + return { + kind: SyntaxKinds.TSQualifiedName, + left, + right, + start, + end, + }; +} + +export function createTSTypeAliasDeclaration( + name: AST.TSTypeAliasDeclaration["name"], + typeAnnotation: AST.TSTypeAliasDeclaration["typeAnnotation"], + typeParameters: AST.TSTypeAliasDeclaration["typeParameters"], + start: SourcePosition, + end: SourcePosition, +): AST.TSTypeAliasDeclaration { + return { + kind: SyntaxKinds.TSTypeAliasDeclaration, + name, + typeAnnotation, + typeParameters, + start, + end, + }; +} + +export function createTSInterfaceBody( + body: AST.TSInterfaceBody["body"], + start: SourcePosition, + end: SourcePosition, +): AST.TSInterfaceBody { + return { + kind: SyntaxKinds.TSInterfaceBody, + body, + start, + end, + }; +} + +export function createTSInterface( + name: AST.TSInterfaceDeclaration["name"], + typeParameters: AST.TSInterfaceDeclaration["typeParameters"], + extendsTypes: AST.TSInterfaceDeclaration["extends"], + body: AST.TSInterfaceDeclaration["body"], + start: SourcePosition, + end: SourcePosition, +): AST.TSInterfaceDeclaration { + return { + kind: SyntaxKinds.TSInterfaceDeclaration, + name, + typeParameters, + extends: extendsTypes, + body, + start, + end, + }; +} + +export function createTSInterfaceHeritage( + typeName: AST.TSEntityName, + typeArguments: AST.TSTypeReference["typeArguments"], + start: SourcePosition, + end: SourcePosition, +): AST.TSInterfaceHeritage { + return { + kind: SyntaxKinds.TSInterfaceHeritage, + typeName, + typeArguments, + start, + end, + }; +} + +export function createTSTypeParameterInstantiation( + params: Array, + start: SourcePosition, + end: SourcePosition, +): AST.TSTypeParameterInstantiation { + return { + kind: SyntaxKinds.TSTypeParameterInstantiation, + params, + start, + end, + }; +} + +export function createTSTypeParameterDeclaration( + params: Array, + start: SourcePosition, + end: SourcePosition, +): AST.TSTypeParameterDeclaration { + return { + kind: SyntaxKinds.TSTypeParameterDeclaration, + params, + start, + end, + }; +} + +export function createTSTypeParameter( + constraint: AST.TSTypeNode | undefined, + defaultType: AST.TSTypeNode | undefined, + name: AST.Identifier, + start: SourcePosition, + end: SourcePosition, +): AST.TSTypeParameter { + return { + kind: SyntaxKinds.TSTypeParameter, + constraint, + default: defaultType, + name, + start, + end, + }; +} + +export function createTSConditionType( + checkType: AST.TSConditionalType["checkType"], + extendType: AST.TSConditionalType["extendType"], + trueType: AST.TSConditionalType["trueType"], + falseType: AST.TSConditionalType["falseType"], + start: SourcePosition, + end: SourcePosition, +): AST.TSConditionalType { + return { + kind: SyntaxKinds.TSConditionalType, + checkType, + extendType, + trueType, + falseType, + start, + end, + }; +} + +export function createTSUnionType( + types: Array, + start: SourcePosition, + end: SourcePosition, +): AST.TSUnionType { + return { + kind: SyntaxKinds.TSUnionType, + types, + start, + end, + }; +} + +export function createTSIntersectionType( + types: Array, + start: SourcePosition, + end: SourcePosition, +): AST.TSIntersectionType { + return { + kind: SyntaxKinds.TSIntersectionType, + types, + start, + end, + }; +} + +export function createTSTypeQuery( + exprName: AST.TSTypeQuery["exprName"], + start: SourcePosition, + end: SourcePosition, +): AST.TSTypeQuery { + return { + kind: SyntaxKinds.TSTypeQuery, + exprName, + start, + end, + }; +} + +export function createTSTypeOperator( + typeAnnotation: AST.TSTypeOperator["typeAnnotation"], + operator: AST.TSTypeOperator["operator"], + start: SourcePosition, + end: SourcePosition, +): AST.TSTypeOperator { + return { + kind: SyntaxKinds.TSTypeOperator, + typeAnnotation, + operator, + start, + end, + }; +} + +export function createTSArrayType( + elementType: AST.TSArrayType["elementType"], + start: SourcePosition, + end: SourcePosition, +): AST.TSArrayType { + return { + kind: SyntaxKinds.TSArrayType, + elementType, + start, + end, + }; +} + +export function createTSIndexedAccessType( + indexedType: AST.TSIndexedAccessType["indexedType"], + objectType: AST.TSIndexedAccessType["objectType"], + start: SourcePosition, + end: SourcePosition, +): AST.TSIndexedAccessType { + return { + kind: SyntaxKinds.TSIndexedAccessType, + indexedType, + objectType, + start, + end, + }; +} + +export function createTSFunctionType( + returnType: AST.TSFunctionType["returnType"], + parameters: AST.TSFunctionType["parameters"], + typeParameters: AST.TSFunctionType["typeParameters"], + start: SourcePosition, + end: SourcePosition, +): AST.TSFunctionType { + return { + kind: SyntaxKinds.TSFunctionType, + returnType, + parameters, + typeParameters, + start, + end, + }; +} + +export function createTSConstrcutorType( + returnType: AST.TSConstrcutorType["returnType"], + parameters: AST.TSConstrcutorType["parameters"], + typeParameters: AST.TSConstrcutorType["typeParameters"], + start: SourcePosition, + end: SourcePosition, +): AST.TSConstrcutorType { + return { + kind: SyntaxKinds.TSConstructorType, + returnType, + parameters, + typeParameters, + start, + end, + }; +} + +export function createTSTupleType( + elementTypes: AST.TSTupleType["elementTypes"], + start: SourcePosition, + end: SourcePosition, +): AST.TSTupleType { + return { + kind: SyntaxKinds.TSTupleType, + elementTypes, + start, + end, + }; +} + +export function createTSLiteralType( + literal: AST.TSLiteralType["literal"], + start: SourcePosition, + end: SourcePosition, +): AST.TSLiteralType { + return { + kind: SyntaxKinds.TSLiteralType, + literal, + start, + end, + }; +} + +export function createTSVoidKeyword(start: SourcePosition, end: SourcePosition): AST.TSVoidKeyword { + return { + kind: SyntaxKinds.TSVoidKeyword, + start, + end, + }; +} + +export function createTSInstantiationExpression( + expression: AST.TSInstantiationExpression["expression"], + typeArguments: AST.TSInstantiationExpression["typeArguments"], + start: SourcePosition, + end: SourcePosition, +): AST.TSInstantiationExpression { + return { + kind: SyntaxKinds.TSInstantiationExpression, + expression, + typeArguments, + start, + end, + }; +} + +export function createTSTypeAssertionExpression( + expression: AST.TSTypeAssertionExpression["expression"], + typeAnnotation: AST.TSTypeAssertionExpression["typeAnnotation"], + start: SourcePosition, + end: SourcePosition, +): AST.TSTypeAssertionExpression { + return { + kind: SyntaxKinds.TSTypeAssertionExpression, + expression, + typeAnnotation, + start, + end, + }; +} + +export function createTSAsExpression( + expression: AST.TSAsExpression["expression"], + typeAnnotation: AST.TSAsExpression["typeAnnotation"], + start: SourcePosition, + end: SourcePosition, +): AST.TSAsExpression { + return { + kind: SyntaxKinds.TSAsExpression, + expression, + typeAnnotation, + start, + end, + }; +} + +export function createTSSatisfiesExpression( + expression: AST.TSSatisfiesExpression["expression"], + typeAnnotation: AST.TSSatisfiesExpression["typeAnnotation"], + start: SourcePosition, + end: SourcePosition, +): AST.TSSatisfiesExpression { + return { + kind: SyntaxKinds.TSSatisfiesExpression, + expression, + typeAnnotation, + start, + end, + }; +} + +export function createTSNonNullExpression( + expression: AST.TSNonNullExpression["expression"], + start: SourcePosition, + end: SourcePosition, +): AST.TSNonNullExpression { + return { + kind: SyntaxKinds.TSNonNullExpression, + expression, + start, + end, + }; +} + +export function createTSEnumDeclaration( + id: AST.TSEnumDeclaration["id"], + body: AST.TSEnumDeclaration["body"], + start: SourcePosition, + end: SourcePosition, +): AST.TSEnumDeclaration { + return { + kind: SyntaxKinds.TSEnumDeclaration, + id, + body, + start, + end, + }; +} + +export function createTSEnumBody( + members: AST.TSEnumBody["members"], + start: SourcePosition, + end: SourcePosition, +): AST.TSEnumBody { + return { + kind: SyntaxKinds.TSEnumBody, + members, + start, + end, + }; +} + +export function createTSEnumMember( + id: AST.TSEnumMember["id"], + computed: AST.TSEnumMember["computed"], + init: AST.TSEnumMember["init"], + start: SourcePosition, + end: SourcePosition, +): AST.TSEnumMember { + return { + kind: SyntaxKinds.TSEnumMember, + computed, + id, + init, + start, + end, + }; +} + +export function createTSDeclarFunction( + name: AST.TSDeclareFunction["name"], + returnType: AST.TSDeclareFunction["returnType"], + params: AST.TSDeclareFunction["params"], + typeParameters: AST.TSDeclareFunction["typeParameters"], + generator: AST.TSDeclareFunction["generator"], + async: AST.TSDeclareFunction["async"], + start: SourcePosition, + end: SourcePosition, +): AST.TSDeclareFunction { + return { + kind: SyntaxKinds.TSDeclareFunction, + name, + params, + returnType, + typeParameters, + generator, + async, + start, + end, + }; +} diff --git a/web-infras/common/src/kind.ts b/web-infras/common/src/kind.ts index c93d9b7c..034bb5ce 100644 --- a/web-infras/common/src/kind.ts +++ b/web-infras/common/src/kind.ts @@ -245,6 +245,67 @@ export enum SyntaxKinds { JSXExpressionContainer, JSXSelfClosedToken, // token for `/>` JSXCloseTagStart, // token for ` = { [SyntaxKinds.ColonPunctuator]: ":", // : [SyntaxKinds.HashTagPunctuator]: "#", // # [SyntaxKinds.AtPunctuator]: "@", // @ + // ========== Template =========== [SyntaxKinds.TemplateHead]: "TemplateHead", [SyntaxKinds.TemplateTail]: "TemplateTail", @@ -679,6 +741,58 @@ export const SytaxKindsMapLexicalLiteral: Record = { [SyntaxKinds.JSXExpressionContainer]: "JSXExpressionContainer", [SyntaxKinds.JSXCloseTagStart]: "JSXClosedTagStart", [SyntaxKinds.JSXSelfClosedToken]: "JSXSelfClosedToken", + // ====== TypeScript Computed Type + [SyntaxKinds.TSConditionalType]: "TSConditionalType", + [SyntaxKinds.TSUnionType]: "TSUnionType", + [SyntaxKinds.TSIntersectionType]: "TSIntersectionType", + [SyntaxKinds.TSTypeOperator]: "TSTypeOperator", + [SyntaxKinds.TSArrayType]: "TSArrayType", + [SyntaxKinds.TSIndexedAccessType]: "TSIndexedAccessType", + [SyntaxKinds.TSTypeAliasDeclaration]: "TSTypeAliasDeclaration", + [SyntaxKinds.TSInterfaceDeclaration]: "TSInterfaceDeclaration", + // ====== TypeScript High Basic Type + [SyntaxKinds.TSFunctionType]: "TSFunctionType", + [SyntaxKinds.TSConstructorType]: "TSConstructorType", + // ====== TypeScript Type Param + [SyntaxKinds.TSTypeParameterInstantiation]: "TSTypeParameterInstantiation", + [SyntaxKinds.TSTypeParameterDeclaration]: "TSTypeParameterDeclaration", + [SyntaxKinds.TSTypeParameter]: "TSTypeParameter", + // ====== TypeScript Basic Type + [SyntaxKinds.TSTypeLiteral]: "TSTypeLiteral", + [SyntaxKinds.TSCallSignatureDeclaration]: "TSCallSignatureDeclaration", + [SyntaxKinds.TSConstructSignatureDeclaration]: "TSConstructSignatureDeclaration", + [SyntaxKinds.TSIndexSignature]: "TSIndexSignature", + [SyntaxKinds.TSPropertySignature]: "TSPropertySignature", + [SyntaxKinds.TSMethodSignature]: "TSMethodSignature", + [SyntaxKinds.TSQualifiedName]: "TSQualifiedName", + [SyntaxKinds.TSTypePredicate]: "TSTypePredicate", + [SyntaxKinds.TSTypeAnnotation]: "TSTypeAnnotation", + [SyntaxKinds.TSTypeReference]: "TSTypeReference", + [SyntaxKinds.TSStringKeyword]: "TSStringKeyword", + [SyntaxKinds.TSNumberKeyword]: "TSNumberKeyword", + [SyntaxKinds.TSBigIntKeyword]: "TSBigIntKeyword", + [SyntaxKinds.TSBooleanKeyword]: "TSBooleanKeyword", + [SyntaxKinds.TSNullKeyword]: "TSNullKeyword", + [SyntaxKinds.TSUndefinedKeyword]: "TSUndefinedKeyword", + [SyntaxKinds.TSSymbolKeyword]: "TSSymbolKeyword", + [SyntaxKinds.TSAnyKeyword]: "TSAnyKeyword", + [SyntaxKinds.TSNeverKeyword]: "TSNeverKeyword", + [SyntaxKinds.TSUnknowKeyword]: "TSUnknowKeyword", + [SyntaxKinds.TSTypeQuery]: "TSTypeQuery", + [SyntaxKinds.TSInterfaceBody]: "TSInterfaceBody", + [SyntaxKinds.TSTupleType]: "TSTupleType", + [SyntaxKinds.TSLiteralType]: "TSLiteralType", + [SyntaxKinds.TSVoidKeyword]: "TSVoidKeyword", + [SyntaxKinds.TSInstantiationExpression]: "TSInstantiationExpression", + [SyntaxKinds.TSInterfaceHeritage]: "TSInterfaceHeritage", + [SyntaxKinds.TSTypeAssertionExpression]: "TSTypeAssertionExpression", + [SyntaxKinds.TSAsExpression]: "TSAsExpression", + [SyntaxKinds.TSSatisfiesExpression]: "TSSatisfiesExpression", + [SyntaxKinds.TSNonNullExpression]: "TSNonNullExpression", + [SyntaxKinds.TSEnumDeclaration]: "TSEnumDeclaration", + [SyntaxKinds.TSEnumBody]: "TSEnumBody", + [SyntaxKinds.TSEnumMember]: "TSEnumMember", + [SyntaxKinds.TSDeclareFunction]: "TSDeclareFunction", }; /** =================================== * Union SytaxKinds diff --git a/web-infras/common/src/visitor.ts b/web-infras/common/src/visitor.ts index b17fe7bb..aac40f6b 100644 --- a/web-infras/common/src/visitor.ts +++ b/web-infras/common/src/visitor.ts @@ -104,6 +104,50 @@ import { JSXOpeningFragment, Decorator, ClassAccessorProperty, + TSTypeAliasDeclaration, + TSInterfaceDeclaration, + TSTypeLiteral, + TSCallSignatureDeclaration, + TSConstructSignatureDeclaration, + TSPropertySignature, + TSMethodSignature, + TSQualifiedName, + TSTypePredicate, + TSTypeAnnotation, + TSTypeReference, + TSStringKeyword, + TSNumberKeyword, + TSBigIntKeyword, + TSBooleanKeyword, + TSTypeParameter, + TSTypeParameterDeclaration, + TSTypeParameterInstantiation, + TSInterfaceBody, + TSFunctionType, + TSUnknowKeyword, + TSNeverKeyword, + TSAnyKeyword, + TSSymbolKeyword, + TSUndefinedKeyword, + TSNullKeyword, + TSConstrcutorType, + TSConditionalType, + TSIntersectionType, + TSArrayType, + TSTypeOperator, + TSIndexedAccessType, + TSUnionType, + TSInstantiationExpression, + TSVoidKeyword, + TSInterfaceHeritage, + TSTypeAssertionExpression, + TSAsExpression, + TSSatisfiesExpression, + TSNonNullExpression, + TSEnumDeclaration, + TSEnumBody, + TSEnumMember, + TSDeclareFunction, } from "./ast"; import { SyntaxKinds } from "./kind"; @@ -217,6 +261,54 @@ export type Visitor = { [SyntaxKinds.JSXFragment]?: (node: JSXFragment, visitor: Visitor) => void; [SyntaxKinds.JSXOpeningFragment]?: (node: JSXOpeningFragment, visitor: Visitor) => void; [SyntaxKinds.JSXClosingFragment]?: (node: JSXClosingFragment, visitor: Visitor) => void; + [SyntaxKinds.TSConditionalType]?: (node: TSConditionalType, visitor: Visitor) => void; + [SyntaxKinds.TSUnionType]?: (node: TSUnionType, visitor: Visitor) => void; + [SyntaxKinds.TSIntersectionType]?: (node: TSIntersectionType, visitor: Visitor) => void; + [SyntaxKinds.TSArrayType]?: (node: TSArrayType, visitor: Visitor) => void; + [SyntaxKinds.TSTypeOperator]?: (node: TSTypeOperator, visitor: Visitor) => void; + [SyntaxKinds.TSArrayType]?: (node: TSArrayType, visitor: Visitor) => void; + [SyntaxKinds.TSIndexedAccessType]?: (node: TSIndexedAccessType, visitor: Visitor) => void; + [SyntaxKinds.TSFunctionType]?: (node: TSFunctionType, visitor: Visitor) => void; + [SyntaxKinds.TSConstructorType]?: (node: TSConstrcutorType, visitor: Visitor) => void; + [SyntaxKinds.TSTypeAliasDeclaration]?: (node: TSTypeAliasDeclaration, visitor: Visitor) => void; + [SyntaxKinds.TSInterfaceDeclaration]?: (node: TSInterfaceDeclaration, visitor: Visitor) => void; + [SyntaxKinds.TSInterfaceBody]?: (node: TSInterfaceBody, visitor: Visitor) => void; + [SyntaxKinds.TSTypeLiteral]?: (node: TSTypeLiteral, visitor: Visitor) => void; + [SyntaxKinds.TSCallSignatureDeclaration]?: (node: TSCallSignatureDeclaration, visitor: Visitor) => void; + [SyntaxKinds.TSConstructSignatureDeclaration]?: ( + node: TSConstructSignatureDeclaration, + visitor: Visitor, + ) => void; + [SyntaxKinds.TSTypeParameterInstantiation]?: (node: TSTypeParameterInstantiation, visitor: Visitor) => void; + [SyntaxKinds.TSTypeParameterDeclaration]?: (node: TSTypeParameterDeclaration, visitor: Visitor) => void; + [SyntaxKinds.TSTypeParameter]?: (node: TSTypeParameter, visitor: Visitor) => void; + [SyntaxKinds.TSPropertySignature]?: (node: TSPropertySignature, visitor: Visitor) => void; + [SyntaxKinds.TSMethodSignature]?: (node: TSMethodSignature, visitor: Visitor) => void; + [SyntaxKinds.TSQualifiedName]?: (node: TSQualifiedName, visitor: Visitor) => void; + [SyntaxKinds.TSTypePredicate]?: (node: TSTypePredicate, visitor: Visitor) => void; + [SyntaxKinds.TSTypeAnnotation]?: (node: TSTypeAnnotation, visitor: Visitor) => void; + [SyntaxKinds.TSTypeReference]?: (node: TSTypeReference, visitor: Visitor) => void; + [SyntaxKinds.TSStringKeyword]?: (node: TSStringKeyword, visitor: Visitor) => void; + [SyntaxKinds.TSNumberKeyword]?: (node: TSNumberKeyword, visitor: Visitor) => void; + [SyntaxKinds.TSBigIntKeyword]?: (node: TSBigIntKeyword, visitor: Visitor) => void; + [SyntaxKinds.TSBooleanKeyword]?: (node: TSBooleanKeyword, visitor: Visitor) => void; + [SyntaxKinds.TSNullKeyword]?: (node: TSNullKeyword, visitor: Visitor) => void; + [SyntaxKinds.TSUndefinedKeyword]?: (node: TSUndefinedKeyword, visitor: Visitor) => void; + [SyntaxKinds.TSSymbolKeyword]?: (node: TSSymbolKeyword, visitor: Visitor) => void; + [SyntaxKinds.TSAnyKeyword]?: (node: TSAnyKeyword, visitor: Visitor) => void; + [SyntaxKinds.TSNeverKeyword]?: (node: TSNeverKeyword, visitor: Visitor) => void; + [SyntaxKinds.TSUnknowKeyword]?: (node: TSUnknowKeyword, visitor: Visitor) => void; + [SyntaxKinds.TSVoidKeyword]?: (node: TSVoidKeyword, visitor: Visitor) => void; + [SyntaxKinds.TSInstantiationExpression]?: (node: TSInstantiationExpression, visitor: Visitor) => void; + [SyntaxKinds.TSInterfaceHeritage]?: (node: TSInterfaceHeritage, visitor: Visitor) => void; + [SyntaxKinds.TSTypeAssertionExpression]?: (node: TSTypeAssertionExpression, visitor: Visitor) => void; + [SyntaxKinds.TSAsExpression]?: (node: TSAsExpression, visitor: Visitor) => void; + [SyntaxKinds.TSSatisfiesExpression]?: (node: TSSatisfiesExpression, visitor: Visitor) => void; + [SyntaxKinds.TSNonNullExpression]?: (node: TSNonNullExpression, visitor: Visitor) => void; + [SyntaxKinds.TSEnumDeclaration]?: (node: TSEnumDeclaration, visitor: Visitor) => void; + [SyntaxKinds.TSEnumBody]?: (node: TSEnumBody, visitor: Visitor) => void; + [SyntaxKinds.TSEnumMember]?: (node: TSEnumMember, visitor: Visitor) => void; + [SyntaxKinds.TSDeclareFunction]?: (node: TSDeclareFunction, visitor: Visitor) => void; }; export const PropagationtVisitorTable: Visitor = { @@ -241,7 +333,9 @@ export const PropagationtVisitorTable: Visitor = { [SyntaxKinds.BinaryBigIntegerLiteral]: function (_node: BinaryIntegerLiteral, _visitor: Visitor) {}, [SyntaxKinds.OctalBigIntegerLiteral]: function (_node: OctalBigIntegerLiteral, _visitor: Visitor) {}, [SyntaxKinds.HexBigIntegerLiteral]: function (_node: HexBigIntegerLiteral, _visitor: Visitor) {}, - [SyntaxKinds.Identifier]: function bindIdentifier(_node: Identifier, _visitor: Visitor) {}, + [SyntaxKinds.Identifier]: function bindIdentifier(node: Identifier, visitor: Visitor) { + visitNode(node.typeAnnotation, visitor); + }, [SyntaxKinds.Super]: function bindSuper(_node: Super, _visitor: Visitor) {}, [SyntaxKinds.Import]: function bindImport(_node: Import, _visitor: Visitor) {}, [SyntaxKinds.ThisExpression]: function bindThisExpression(_node: ThisExpression, _visitor: Visitor) {}, @@ -263,12 +357,16 @@ export const PropagationtVisitorTable: Visitor = { visitor: Visitor, ) { visitNode(node.key, visitor); + visitNode(node.typeParameters, visitor); visitNodes(node.params, visitor); + visitNode(node.returnType, visitor); visitNode(node.body, visitor); }, [SyntaxKinds.ObjectAccessor]: function bindObjectAccessor(node: ObjectAccessor, visitor: Visitor) { visitNode(node.key, visitor); + visitNode(node.typeParameters, visitor); visitNodes(node.params, visitor); + visitNode(node.returnType, visitor); visitNode(node.body, visitor); }, [SyntaxKinds.SpreadElement]: function bindSpreadElement(node: SpreadElement, visitor: Visitor) { @@ -287,15 +385,19 @@ export const PropagationtVisitorTable: Visitor = { visitor: Visitor, ) { visitNode(node.name, visitor); + visitNode(node.typeParameters, visitor); visitNodes(node.params, visitor); + visitNode(node.returnType, visitor); visitNode(node.body, visitor); }, [SyntaxKinds.ArrowFunctionExpression]: function bindArrowFunctionExpression( node: ArrorFunctionExpression, visitor: Visitor, ) { - visitNode(node.body, visitor); + visitNode(node.typeParameters, visitor); visitNodes(node.arguments, visitor); + visitNode(node.returnType, visitor); + visitNode(node.body, visitor); }, [SyntaxKinds.MetaProperty]: function bindMetaProperty(node: MetaProperty, visitor: Visitor) { visitNode(node.meta, visitor); @@ -306,6 +408,7 @@ export const PropagationtVisitorTable: Visitor = { }, [SyntaxKinds.NewExpression]: function bindNewExpression(node: NewExpression, visitor: Visitor) { visitNode(node.callee, visitor); + visitNode(node.typeArguments, visitor); visitNodes(node.arguments, visitor); }, [SyntaxKinds.MemberExpression]: function bindMemberExpression(node: MemberExpression, visitor: Visitor) { @@ -315,6 +418,7 @@ export const PropagationtVisitorTable: Visitor = { [SyntaxKinds.CallExpression]: function bindCallExpression(node: CallExpression, visitor: Visitor) { visitNode(node.callee, visitor); visitNodes(node.arguments, visitor); + visitNode(node.typeArguments, visitor); }, [SyntaxKinds.TaggedTemplateExpression]: function bindTaggTemplateExpression( node: TaggedTemplateExpression, @@ -368,6 +472,7 @@ export const PropagationtVisitorTable: Visitor = { }, [SyntaxKinds.ObjectPattern]: function bindObjectPattern(node: ObjectPattern, visitor: Visitor) { visitNodes(node.properties, visitor); + visitNode(node.typeAnnotation, visitor); }, [SyntaxKinds.ObjectPatternProperty]: function bindObjectPatternProperty( node: ObjectPatternProperty, @@ -378,13 +483,16 @@ export const PropagationtVisitorTable: Visitor = { }, [SyntaxKinds.ArrayPattern]: function bindArrayPattern(node: ArrayPattern, visitor: Visitor) { visitNodes(node.elements, visitor); + visitNode(node.typeAnnotation, visitor); }, [SyntaxKinds.AssignmentPattern]: function bindAssigmentPattern(node: AssignmentPattern, visitor: Visitor) { visitNode(node.left, visitor); visitNode(node.right, visitor); + visitNode(node.typeAnnotation, visitor); }, [SyntaxKinds.RestElement]: function bindRestElement(node: RestElement, visitor: Visitor) { visitNode(node.argument, visitor); + visitNode(node.typeAnnotation, visitor); }, [SyntaxKinds.IfStatement]: function bindIfStatement(node: IfStatement, visitor: Visitor) { visitNode(node.test, visitor); @@ -481,7 +589,9 @@ export const PropagationtVisitorTable: Visitor = { visitor: Visitor, ) { visitNode(node.name, visitor); + visitNode(node.typeParameters, visitor); visitNodes(node.params, visitor); + visitNode(node.returnType, visitor); visitNode(node.body, visitor); }, [SyntaxKinds.ClassBody]: function bindClassBody(node: ClassBody, visitor: Visitor) { @@ -502,18 +612,23 @@ export const PropagationtVisitorTable: Visitor = { visitor: Visitor, ) { visitNode(node.key, visitor); + visitNode(node.typeParameters, visitor); visitNodes(node.params, visitor); + visitNode(node.returnType, visitor); visitNode(node.body, visitor); visitNodes(node.decorators, visitor); }, [SyntaxKinds.ClassConstructor]: function bindClassConstructor(node: ClassConstructor, visitor: Visitor) { visitNode(node.key, visitor); visitNodes(node.params, visitor); + visitNode(node.returnType, visitor); visitNode(node.body, visitor); }, [SyntaxKinds.ClassAccessor]: function bindClassAccessor(node: ClassAccessor, visitor: Visitor) { visitNode(node.key, visitor); + visitNode(node.typeParameters, visitor); visitNodes(node.params, visitor); + visitNode(node.returnType, visitor); visitNode(node.body, visitor); visitNodes(node.decorators, visitor); }, @@ -618,6 +733,154 @@ export const PropagationtVisitorTable: Visitor = { }, [SyntaxKinds.JSXOpeningFragment]: function (_node: JSXOpeningFragment, _visitor: Visitor) {}, [SyntaxKinds.JSXClosingFragment]: function (_node: JSXClosingFragment, _visitor: Visitor) {}, + [SyntaxKinds.TSConditionalType]: function (node: TSConditionalType, visitor: Visitor) { + visitNode(node.checkType, visitor); + visitNode(node.extendType, visitor); + visitNode(node.trueType, visitor); + visitNode(node.falseType, visitor); + }, + [SyntaxKinds.TSUnionType]: function (node: TSUnionType, visitor: Visitor) { + visitNodes(node.types, visitor); + }, + [SyntaxKinds.TSIntersectionType]: function (node: TSIntersectionType, visitor: Visitor) { + visitNodes(node.types, visitor); + }, + [SyntaxKinds.TSArrayType]: function (node: TSArrayType, visitor: Visitor) { + visitNode(node.elementType, visitor); + }, + [SyntaxKinds.TSTypeOperator]: function (node: TSTypeOperator, visitor: Visitor) { + visitNode(node.typeAnnotation, visitor); + }, + [SyntaxKinds.TSIndexedAccessType]: function (node: TSIndexedAccessType, visitor: Visitor) { + visitNode(node.indexedType, visitor); + visitNode(node.objectType, visitor); + }, + [SyntaxKinds.TSFunctionType]: function (node: TSFunctionType, visitor: Visitor) { + visitNode(node.typeParameters, visitor); + visitNodes(node.parameters, visitor); + visitNode(node.returnType, visitor); + }, + [SyntaxKinds.TSConstructorType]: function (node: TSConstrcutorType, visitor: Visitor) { + visitNode(node.typeParameters, visitor); + visitNodes(node.parameters, visitor); + visitNode(node.returnType, visitor); + }, + [SyntaxKinds.TSTypeAliasDeclaration]: function (node: TSTypeAliasDeclaration, visitor: Visitor) { + visitNode(node.typeAnnotation, visitor); + visitNode(node.typeParameters, visitor); + }, + [SyntaxKinds.TSInterfaceDeclaration]: function (node: TSInterfaceDeclaration, visitor: Visitor) { + visitNode(node.body, visitor); + visitNode(node.typeParameters, visitor); + visitNodes(node.extends, visitor); + }, + [SyntaxKinds.TSTypeLiteral]: function (node: TSTypeLiteral, visitor: Visitor) { + visitNodes(node.members, visitor); + }, + [SyntaxKinds.TSCallSignatureDeclaration]: function (node: TSCallSignatureDeclaration, visitor: Visitor) { + visitNodes(node.parameters, visitor); + visitNode(node.returnType, visitor); + }, + [SyntaxKinds.TSConstructSignatureDeclaration]: function ( + node: TSConstructSignatureDeclaration, + visitor: Visitor, + ) { + visitNodes(node.parameters, visitor); + visitNode(node.returnType, visitor); + }, + [SyntaxKinds.TSPropertySignature]: function (node: TSPropertySignature, visitor: Visitor) { + visitNode(node.key, visitor); + visitNode(node.typeAnnotation, visitor); + }, + [SyntaxKinds.TSMethodSignature]: function (node: TSMethodSignature, visitor: Visitor) { + visitNode(node.key, visitor); + visitNode(node.typeParameters, visitor); + visitNodes(node.parameters, visitor); + visitNode(node.returnType, visitor); + }, + [SyntaxKinds.TSQualifiedName]: function (node: TSQualifiedName, visitor: Visitor) { + visitNode(node.left, visitor); + visitNode(node.right, visitor); + }, + [SyntaxKinds.TSTypePredicate]: function (node: TSTypePredicate, visitor: Visitor) { + visitNode(node.parameterName, visitor); + visitNode(node.typeAnnotation, visitor); + }, + [SyntaxKinds.TSTypeAnnotation]: function (node: TSTypeAnnotation, visitor: Visitor) { + visitNode(node.typeAnnotation, visitor); + }, + [SyntaxKinds.TSTypeReference]: function (node: TSTypeReference, visitor: Visitor) { + visitNode(node.typeArguments, visitor); + visitNode(node.typeName, visitor); + }, + [SyntaxKinds.TSInstantiationExpression]: function (node: TSInstantiationExpression, visitor: Visitor) { + visitNode(node.expression, visitor); + visitNode(node.typeArguments, visitor); + }, + [SyntaxKinds.TSStringKeyword]: function (_node: TSStringKeyword, _visitor: Visitor) {}, + [SyntaxKinds.TSNumberKeyword]: function (_node: TSNumberKeyword, _visitor: Visitor) {}, + [SyntaxKinds.TSBigIntKeyword]: function (_node: TSBigIntKeyword, _visitor: Visitor) {}, + [SyntaxKinds.TSBooleanKeyword]: function (_node: TSBooleanKeyword, _visitor: Visitor) {}, + [SyntaxKinds.TSNullKeyword]: function (_node: TSNullKeyword, _visitor: Visitor) {}, + [SyntaxKinds.TSUndefinedKeyword]: function (_node: TSUndefinedKeyword, _visitor: Visitor) {}, + [SyntaxKinds.TSSymbolKeyword]: function (_node: TSSymbolKeyword, _visitor: Visitor) {}, + [SyntaxKinds.TSAnyKeyword]: function (_node: TSAnyKeyword, _visitor: Visitor) {}, + [SyntaxKinds.TSNeverKeyword]: function (_node: TSNeverKeyword, _visitor: Visitor) {}, + [SyntaxKinds.TSUnknowKeyword]: function (_node: TSUnknowKeyword, _visitor: Visitor) {}, + [SyntaxKinds.TSVoidKeyword]: function (_node: TSVoidKeyword, _visitor: Visitor) {}, + [SyntaxKinds.TSInterfaceBody]: function (node: TSInterfaceBody, visitor: Visitor) { + visitNodes(node.body, visitor); + }, + [SyntaxKinds.TSTypeParameterInstantiation]: function ( + node: TSTypeParameterInstantiation, + visitor: Visitor, + ) { + visitNodes(node.params, visitor); + }, + [SyntaxKinds.TSTypeParameterDeclaration]: function (node: TSTypeParameterDeclaration, visitor: Visitor) { + visitNodes(node.params, visitor); + }, + [SyntaxKinds.TSTypeParameter]: function (node: TSTypeParameter, visitor: Visitor) { + visitNode(node.name, visitor); + visitNode(node.constraint, visitor); + visitNode(node.default, visitor); + }, + [SyntaxKinds.TSInterfaceHeritage]: function (node: TSInterfaceHeritage, visitor: Visitor) { + visitNode(node.typeName, visitor); + visitNode(node.typeArguments, visitor); + }, + [SyntaxKinds.TSTypeAssertionExpression]: function (node: TSTypeAssertionExpression, visitor: Visitor) { + visitNode(node.expression, visitor); + visitNode(node.typeAnnotation, visitor); + }, + [SyntaxKinds.TSAsExpression]: function (node: TSAsExpression, visitor: Visitor) { + visitNode(node.expression, visitor); + visitNode(node.typeAnnotation, visitor); + }, + [SyntaxKinds.TSSatisfiesExpression]: function (node: TSSatisfiesExpression, visitor: Visitor) { + visitNode(node.expression, visitor); + visitNode(node.typeAnnotation, visitor); + }, + [SyntaxKinds.TSNonNullExpression]: function (node: TSNonNullExpression, visitor: Visitor) { + visitNode(node.expression, visitor); + }, + [SyntaxKinds.TSEnumDeclaration]: function (node: TSEnumDeclaration, visitor: Visitor) { + visitNode(node.id, visitor); + visitNode(node.body, visitor); + }, + [SyntaxKinds.TSEnumBody]: function (node: TSEnumBody, visitor: Visitor) { + visitNodes(node.members, visitor); + }, + [SyntaxKinds.TSEnumMember]: function (node: TSEnumMember, visitor: Visitor) { + visitNode(node.init, visitor); + visitNode(node.id, visitor); + }, + [SyntaxKinds.TSDeclareFunction]: function (node: TSDeclareFunction, visitor: Visitor) { + visitNode(node.name, visitor); + visitNodes(node.params, visitor); + visitNode(node.typeParameters, visitor); + visitNode(node.returnType, visitor); + }, }; export function visitNode(node: T | null | undefined, visitor: Visitor) { diff --git a/web-infras/parser/.gitignore b/web-infras/parser/.gitignore index ce4b03d3..528c182d 100644 --- a/web-infras/parser/.gitignore +++ b/web-infras/parser/.gitignore @@ -1,5 +1,6 @@ ## For develop generate file test.js +test.ts test1.js jquery.format.js dist \ No newline at end of file diff --git a/web-infras/parser/src/dev.ts b/web-infras/parser/src/dev.ts index 60fa3c13..4eed06f4 100644 --- a/web-infras/parser/src/dev.ts +++ b/web-infras/parser/src/dev.ts @@ -4,7 +4,8 @@ import { parse } from "@/src/index"; import { transformSyntaxKindToLiteral } from "../tests/parserRunner/helpers/transform"; import fs from "fs"; import path from "path"; -const code = fs.readFileSync(path.join(__dirname, "test.js")).toString(); +// import { ParserPlugin } from "./parser/config"; +const code = fs.readFileSync(path.join(__dirname, "test.ts")).toString(); // console.log(code); // const writePath = path.join(__dirname, "test.json"); @@ -49,8 +50,10 @@ function printLexer(code: string) { ); } function printParser(code: string) { - const ast = parse(code, { sourceType: "script", plugins: ["jsx"] }); + const ast = parse(code, { sourceType: "module", plugins: [] }); transformSyntaxKindToLiteral(ast); + const astJsonString = JSON.stringify(ast, null, 4); + fs.writeFileSync("./test.json", astJsonString); console.log(JSON.stringify(ast, null, 4)); return 0; } diff --git a/web-infras/parser/src/errorHandler/index.ts b/web-infras/parser/src/errorHandler/index.ts index 93af0dba..78e79275 100644 --- a/web-infras/parser/src/errorHandler/index.ts +++ b/web-infras/parser/src/errorHandler/index.ts @@ -6,7 +6,7 @@ import { SourcePosition } from "web-infra-common"; import { SyntaxError, SyntaxErrorHandler } from "./type"; export function createErrorHandler(code: string): SyntaxErrorHandler { - const errors: Array = []; + let errors: Array = []; function pushSyntaxErrors(...syntaxErrors: Array) { errors.push(...syntaxErrors); } @@ -46,9 +46,17 @@ export function createErrorHandler(code: string): SyntaxErrorHandler { .map(() => " ") .join(""); } + function markAsTry() { + return errors.length; + } + function restoreTryFail(index: number) { + errors = errors.slice(0, index); + } return { pushSyntaxErrors, haveError, formatErrorString, + markAsTry, + restoreTryFail, }; } diff --git a/web-infras/parser/src/errorHandler/type.ts b/web-infras/parser/src/errorHandler/type.ts index 254dc6ba..358a19fd 100644 --- a/web-infras/parser/src/errorHandler/type.ts +++ b/web-infras/parser/src/errorHandler/type.ts @@ -8,4 +8,6 @@ export type SyntaxErrorHandler = { pushSyntaxErrors: (...syntaxErrors: Array) => void; haveError: () => boolean; formatErrorString: () => string; + markAsTry(): number; + restoreTryFail(index: number): void; }; diff --git a/web-infras/parser/src/index.ts b/web-infras/parser/src/index.ts index 11fb689f..5a7c97b3 100644 --- a/web-infras/parser/src/index.ts +++ b/web-infras/parser/src/index.ts @@ -1,4 +1,4 @@ -import { createParser } from "@/src/parser"; +import { Parser } from "@/src/parser"; import { createLexer } from "@/src/lexer"; import { Token } from "@/src/lexer/type"; import { SyntaxKinds } from "web-infra-common"; @@ -7,8 +7,8 @@ import { createErrorHandler } from "./errorHandler"; export function parse(code: string, config?: ParserUserConfig) { const errorHandler = createErrorHandler(code); - const parser = createParser(code, errorHandler, config); - const program = parser.parse(); + const parser = new Parser(code, errorHandler, config); + const program = parser.parseProgram(); if (errorHandler.haveError()) { throw new Error(errorHandler.formatErrorString()); } diff --git a/web-infras/parser/src/lexer/lexer.ts b/web-infras/parser/src/lexer/lexer.ts index 9fc6e2e4..c15e831c 100644 --- a/web-infras/parser/src/lexer/lexer.ts +++ b/web-infras/parser/src/lexer/lexer.ts @@ -5,6 +5,8 @@ import { createLexerContext, cloneLexerContext, cloneLexerState, + LexerState, + LexerContext, } from "./type"; import { isCodePointLineTerminate, @@ -21,6 +23,8 @@ const KeywordLiteralSet = new Set([ ...LexicalLiteral.UndefinbedLiteral, ]); +export type Lexer = ReturnType; + export function createLexer(code: string) { /** * state and context for lexer, @@ -34,6 +38,23 @@ export function createLexer(code: string) { * Public API of Lexer * =========================================================== */ + /** + * fork state and context of lexer, used by parser to try parse + * some syntax. + * @returns {[LexerState, LexerContext]} + */ + function forkState(): [LexerState, LexerContext] { + return [cloneLexerState(state), cloneLexerContext(context)]; + } + /** + * Restore lexer state and context, used by parser when failed on try parse + * @param restoreState + * @param restoreContext + */ + function restoreState(restoreState: LexerState, restoreContext: LexerContext) { + state = restoreState; + context = restoreContext; + } /** * Public Api for getting change line flag of current token. * @returns {boolean} @@ -324,6 +345,73 @@ export function createLexer(code: string) { } return getSliceStringFromCode(startIndex, getCurrentIndex()); } + /** + * + * @returns + */ + function reLexGtRelateToken(allowAssign: boolean) { + switch (state.token.kind) { + // `>=` to `>`, `=` + case SyntaxKinds.GeqtOperator: { + if (!allowAssign) return; + state.cursor.pos -= 2; + startToken(); + eatChar(); + finishToken(SyntaxKinds.GtOperator); + return; + } + // `>>` to `>`, `>` + case SyntaxKinds.BitwiseRightShiftOperator: { + state.cursor.pos -= 2; + startToken(); + eatChar(); + finishToken(SyntaxKinds.GtOperator); + return; + } + // `>>>` to `>`, `>>` + case SyntaxKinds.BitwiseRightShiftFillOperator: { + state.cursor.pos -= 3; + startToken(); + eatChar(); + finishToken(SyntaxKinds.GtOperator); + return; + } + // `>>=` to `>`, `>=` + // case SyntaxKinds.BitwiseRightShiftAssginOperator: { + // state.cursor.pos -= 3; + // startToken(); + // eatChar(); + // finishToken(SyntaxKinds.GtOperator); + // return; + // } + // `>>>=`, to `>`, `>>=` + // case SyntaxKinds.BitwiseRightShiftFillAssginOperator: { + // state.cursor.pos -= 4; + // startToken(); + // eatChar(); + // finishToken(SyntaxKinds.GtOperator); + // return; + // } + default: { + return; + } + } + } + function reLexLtRelateToken() { + switch (state.token.kind) { + // `<<` to `<`, `<` + case SyntaxKinds.BitwiseLeftShiftOperator: { + state.cursor.pos -= 2; + startToken(); + eatChar(); + finishToken(SyntaxKinds.LtOperator); + return; + } + default: { + return; + } + } + } /** * Public API for sync the strict mode context with parser. * @param {boolean} strictMode @@ -351,6 +439,11 @@ export function createLexer(code: string) { setJSXGtContext, // only used by strict mode setStrictModeContext, + // only used by TS + reLexGtRelateToken, + reLexLtRelateToken, + forkState, + restoreState, }; /** =========================================================== * Private API for Lexer diff --git a/web-infras/parser/src/parser/config.ts b/web-infras/parser/src/parser/config.ts index d502e93d..12e9024c 100644 --- a/web-infras/parser/src/parser/config.ts +++ b/web-infras/parser/src/parser/config.ts @@ -7,12 +7,20 @@ export type ParserConfig = { allowAwaitOutsideFunction: boolean; allowNewTargetOutsideFunction: boolean; allowUndeclaredExports: boolean; - plugins: Array; + plugins: Array; // errorRecovery: boolean; // createImportExpressions: boolean; // allowSuperOutsideMethod: boolean; }; export type ParserUserConfig = Partial; + +export enum ParserPlugin { + TypeScript = "typescript", + JSX = "jsx", + ImportAssertions = "importAssertions", + ImportAttribute = "importAttributes", +} + const defaultConfig: ParserConfig = { sourceType: "script", allowReturnOutsideFunction: false, @@ -21,6 +29,7 @@ const defaultConfig: ParserConfig = { allowUndeclaredExports: false, plugins: [], }; + export function getConfigFromUserInput(config?: ParserUserConfig): ParserConfig { return { ...defaultConfig, diff --git a/web-infras/parser/src/parser/context.ts b/web-infras/parser/src/parser/context.ts new file mode 100644 index 00000000..12d790c6 --- /dev/null +++ b/web-infras/parser/src/parser/context.ts @@ -0,0 +1,750 @@ +import { + ModuleItem, + PropertyName, + SyntaxKinds, + SourcePosition, + SytaxKindsMapLexicalLiteral, + Decorator, +} from "web-infra-common"; +import { ExpectToken } from "./type"; +import { ErrorMessageMap } from "./error"; +import { ParserPlugin } from "./config"; +import { LookaheadToken } from "../lexer/type"; +import { AsyncArrowExpressionScope } from "./scope/arrowExprScope"; +import { StrictModeScope } from "./scope/strictModeScope"; +import { ExpressionScopeKind } from "./scope/type"; +import { ExportContext, PrivateNameDefKind } from "./scope/lexicalScope"; +import { FunctionSymbolScope, NonFunctionalSymbolType, SymbolType } from "./scope/symbolScope"; +import type { Parser } from "@/src/parser"; + +export interface Context { + maybeArrowStart: number; + isInType: boolean; + inOperatorStack: Array; + propertiesInitSet: Set; + propertiesProtoDuplicateSet: Set; + lastTokenIndexOfIfStmt: number; + cache: { + decorators: Decorator[] | null; + }; +} +/** + * Create context for parser + * @returns {Context} + */ +export function createContext(): Context { + return { + maybeArrowStart: -1, + isInType: false, + inOperatorStack: [], + propertiesInitSet: new Set(), + propertiesProtoDuplicateSet: new Set(), + lastTokenIndexOfIfStmt: -1, + cache: { + decorators: null, + }, + }; +} +/** + * Private API for parser, helper to require some plugin + */ +export function requirePlugin(this: Parser, ...plugins: Array): boolean { + for (const plugin of plugins) { + if (!this.config.plugins.includes(plugin)) { + return false; + } + } + return true; +} +/** + * Private API for parser, move to next token, skip comment and + * block comment token. + * @returns {SyntaxKinds} + */ +export function nextToken(this: Parser): SyntaxKinds { + this.lexer.nextToken(); + const token = this.lexer.getTokenKind(); + if (token === SyntaxKinds.Comment || token == SyntaxKinds.BlockComment) { + return this.nextToken(); + } + return token; +} +/** + * Private API for parser, get current token kind, skip comment + * and block comment token + * @returns {SyntaxKinds} + */ +export function getToken(this: Parser): SyntaxKinds { + const token = this.lexer.getTokenKind(); + if (token === SyntaxKinds.Comment || token == SyntaxKinds.BlockComment) { + return this.nextToken(); + } + return token; +} +/** + * Private API for parser, get current token's string value. + * @returns {string} + */ +export function getSourceValue(this: Parser): string { + return this.lexer.getSourceValue(); +} +/** + * Private API for parser, just wrapper of this.lexer, get start + * position of current token. + * @return {SourcePosition} + */ +export function getStartPosition(this: Parser): SourcePosition { + return this.lexer.getStartPosition(); +} +/** + * Private API for parser, just wrapper of this.lexer, get end + * position of current token. + * @return {SourcePosition} + */ +export function getEndPosition(this: Parser): SourcePosition { + return this.lexer.getEndPosition(); +} +/** + * Private API for parser, just wrapper of this.lexer, get end + * position of last token. + * @returns {SourcePosition} + */ +export function getLastTokenEndPositon(this: Parser): SourcePosition { + return this.lexer.getLastTokenEndPositon(); +} +/** + * Private API for parser, just wrapper of lookahead method + * of this.lexer. + * @returns + */ +export function lookahead(this: Parser): LookaheadToken { + return this.lexer.lookahead(); +} +/** + * Private API for parser, just wrapper of this.lexer method. + * @returns + */ +export function readRegex(this: Parser) { + return this.lexer.readRegex(); +} +/** + * Private API for parser, just wrapper of this.lexer method, check + * is a line terminator in the range of last token end and start + * of current token. + * @returns {boolean} + */ +export function getLineTerminatorFlag(this: Parser): boolean { + return this.lexer.getLineTerminatorFlag(); +} +/** + * Private API for parser, just wrapper of this.lexer methid, check + * is current token contain a unicode esc. + */ +export function getEscFlag(this: Parser): boolean { + return this.lexer.getEscFlag(); +} +/** + * Private API for parser, is current token kind match the + * given token kind ? + * @param {SyntaxKinds | Array} kind + * @returns {boolean} + */ +export function match(this: Parser, kind: SyntaxKinds | Array): boolean { + const currentToken = this.getToken(); + if (Array.isArray(kind)) { + const tokenSet = new Set(kind); + return tokenSet.has(currentToken); + } + return currentToken === kind; +} +/** + * Private API for check if current identifier is a given value, + * used when we need to detect a contextual keyword (like `async`). + * @param {string} value + * @returns {boolean} + */ +export function isContextKeyword(this: Parser, value: string): boolean { + if ( + this.getSourceValue() === value && + this.getToken() === SyntaxKinds.Identifier && + !this.lexer.getEscFlag() + ) { + return true; + } + return false; +} +/** + * Private API for parser, expect current token is one of given token(s), + * it not, it will create a unexpect error, if is one of given token, it will + * eat token and return `value`, `start`, `end` of token + * @param kind + * @param message + * @returns {ExpectToken} + */ +export function expect(this: Parser, kind: SyntaxKinds | Array): ExpectToken { + if (this.match(kind)) { + const metaData = { + value: this.getSourceValue(), + start: this.getStartPosition(), + end: this.getEndPosition(), + }; + this.nextToken(); + return metaData; + } + throw this.createUnexpectError(); +} +/** + * Private API for parser, expect current token is one of given token(s), + * it not, it will create a unexpect error, if is one of given token, it + * will NOT eat token. + * @param kind + * @param message + * @returns {void} + */ +export function expectButNotEat(this: Parser, kind: SyntaxKinds | Array): void { + if (this.match(kind)) { + return; + } + throw this.createUnexpectError(); +} +/** + * Private API for `shouldInsertSemi` and `isSoftInsertSemi`, + * test is there a semi or equal syntax, return three state + * - `SemiExisted`: there is a semi token. + * - `SemiInsertAble`: there is a equal to semi syntax. + * - `SemiNotExisted`: there is no semi or equal syntax, + * @returns + */ +export function isSemiInsertable(this: Parser) { + if (this.match(SyntaxKinds.SemiPunctuator)) { + return "SemiExisted"; + } + if (this.match([SyntaxKinds.BracesRightPunctuator, SyntaxKinds.EOFToken])) { + return "SemiInsertAble"; + } + if (this.getLineTerminatorFlag()) { + return "SemiInsertAble"; + } + return "SemiNotExisted"; +} +/** + * Private API for most of insert semi check, if semi exist, eat token, + * pass if equal syntax exist, throw error if not existed semi or equal + * syntax. + * @returns + */ +export function shouldInsertSemi(this: Parser) { + const semiState = this.isSemiInsertable(); + switch (semiState) { + case "SemiExisted": + this.nextToken(); + return; + case "SemiInsertAble": + return; + case "SemiNotExisted": + // recoverable error + this.raiseError(ErrorMessageMap.missing_semicolon, this.getStartPosition()); + } +} +/** + * Private API for insert semi for three edge case + * - `DoWhileStatement` + * - `ReturnStatement` + * - `YeildExpression` + * @param {boolean} shouldEat - false whem used in yield expression. + * @returns + */ +export function isSoftInsertSemi(this: Parser, shouldEat: boolean = true) { + const semiState = this.isSemiInsertable(); + switch (semiState) { + case "SemiExisted": + if (shouldEat) { + this.nextToken(); + } + return true; + case "SemiInsertAble": + return true; + case "SemiNotExisted": + return false; + } +} +/** + * Create a Message error from parser's error map. + * @param {string} messsage + */ +export function createMessageError(this: Parser, messsage: string, position?: SourcePosition) { + if (position === undefined) position = this.getStartPosition(); + + return new Error(`[Syntax Error]: ${messsage} (${position.row}, ${position.col})`); +} +/** + * Create a error object with message tell developer that get a + * unexpect token. + * @returns {Error} + */ +export function createUnexpectError(this: Parser): Error { + const startPos = this.getStartPosition(); + return new Error( + `[Syntax Error]: Unexpect token ${SytaxKindsMapLexicalLiteral[this.getToken()]}(${startPos.row}, ${startPos.col}).`, + ); +} +/** + * Given that this parser is recurive decent parser, some + * export function must call with some start token, if export function call + * with unexecpt start token, it should throw this error. + * @param {Array} startTokens + * @returns {Error} + */ +export function createUnreachError(this: Parser, startTokens: Array = []): Error { + const start = this.getStartPosition(); + let message = `[Unreach Zone]: this piece of code should not be reach (${start.row}, ${start.col}), have a unexpect token ${this.getToken()} (${this.getSourceValue()}).`; + if (startTokens.length !== 0) { + message += " it should call with start token["; + for (const token of startTokens) { + message += `${token}, `; + } + message += "]"; + } + message += ", please report to developer."; + return new Error(message); +} +export function disAllowInOperaotr(this: Parser, parseCallback: () => T): T { + this.context.inOperatorStack.push(false); + const result = parseCallback(); + this.context.inOperatorStack.pop(); + return result; +} +/** + * Private API for parse api for expression, in ECMAscript, there is + * a syntax tranlation for in operator production rule. + * @param parseCallback + * @returns + */ +export function allowInOperaotr(this: Parser, parseCallback: () => T) { + this.context.inOperatorStack.push(true); + const result = parseCallback(); + this.context.inOperatorStack.pop(); + return result; +} +/** =========================================================== + * Private API for other Parser API, just wrapper of recorder + * =========================================================== + */ + +/** + * please reference to recorder api + */ +export function enterFunctionScope(this: Parser, isAsync: boolean = false, isGenerator: boolean = false) { + this.asyncArrowExprScopeRecorder.enterFunctionScope(); + this.strictModeScopeRecorder.enterRHSStrictModeScope(); + this.symbolScopeRecorder.enterFunctionSymbolScope(); + this.lexicalScopeRecorder.enterFunctionLexicalScope(isAsync, isGenerator); + this.lexer.setStrictModeContext(this.isInStrictMode()); +} +export function exitFunctionScope(this: Parser, focusCheck: boolean) { + const isNonSimpleParam = !this.isCurrentFunctionParameterListSimple(); + const isStrict = this.isInStrictMode(); + const symbolScope = this.symbolScopeRecorder.exitSymbolScope()!; + if (isNonSimpleParam || isStrict || focusCheck) { + const functionSymbolScope = symbolScope as FunctionSymbolScope; + for (const symPos of functionSymbolScope.duplicateParams) { + this.raiseError(ErrorMessageMap.duplicate_param, symPos); + } + } + this.asyncArrowExprScopeRecorder.exitAsyncArrowExpressionScope(); + this.strictModeScopeRecorder.exitStrictModeScope(); + this.lexicalScopeRecorder.exitFunctionLexicalScope(); + this.lexer.setStrictModeContext(this.isInStrictMode()); +} +export function enterProgram(this: Parser) { + this.symbolScopeRecorder.enterProgramSymbolScope(); + this.lexicalScopeRecorder.enterProgramLexicalScope( + this.config.allowAwaitOutsideFunction || false, + this.config.sourceType === "module", + ); + this.lexer.setStrictModeContext(this.config.sourceType === "module"); +} +export function exitProgram(this: Parser) { + if (!this.config.allowUndeclaredExports) { + for (const pos of this.symbolScopeRecorder.getProgramContainUndefSymbol()) { + this.raiseError(ErrorMessageMap.babel_error_export_is_not_defined, pos); + } + } + this.symbolScopeRecorder.exitSymbolScope(); + this.lexicalScopeRecorder.exitProgramLexicalScope(); + this.lexer.setStrictModeContext(false); +} +export function enterBlockScope(this: Parser) { + this.lexicalScopeRecorder.enterBlockLexicalScope(false); + this.symbolScopeRecorder.enterBlockSymbolScope(); +} +export function exitBlockScope(this: Parser) { + this.lexicalScopeRecorder.exitBlockLexicalScope(); + this.symbolScopeRecorder.exitSymbolScope(); +} +export function enterCatchBlockScope(this: Parser) { + this.lexicalScopeRecorder.enterBlockLexicalScope(true); + this.symbolScopeRecorder.enterFunctionSymbolScope(); +} +export function exitCatchBlockScope(this: Parser) { + this.lexicalScopeRecorder.exitBlockLexicalScope(); + this.symbolScopeRecorder.exitSymbolScope(); +} +export function parseAsLoop(this: Parser, callback: () => T): T { + this.lexicalScopeRecorder.enterVirtualBlockScope("Loop"); + const result = callback(); + this.lexicalScopeRecorder.exitVirtualBlockScope(); + return result; +} +export function parseAsSwitch(this: Parser, callback: () => T): T { + this.lexicalScopeRecorder.enterVirtualBlockScope("Switch"); + const result = callback(); + this.lexicalScopeRecorder.exitVirtualBlockScope(); + return result; +} +export function recordScope(this: Parser, kind: ExpressionScopeKind, position: SourcePosition) { + this.strictModeScopeRecorder.record(kind, position); + this.asyncArrowExprScopeRecorder.record(kind, position); +} +export function enterArrowFunctionBodyScope(this: Parser, isAsync: boolean = false) { + this.lexicalScopeRecorder.enterArrowFunctionBodyScope(isAsync); + this.symbolScopeRecorder.enterFunctionSymbolScope(); +} +export function exitArrowFunctionBodyScope(this: Parser) { + const symbolScope = this.symbolScopeRecorder.exitSymbolScope()!; + const functionSymbolScope = symbolScope as FunctionSymbolScope; + for (const symPos of functionSymbolScope.duplicateParams) { + this.raiseError(ErrorMessageMap.duplicate_param, symPos); + } + this.lexicalScopeRecorder.exitArrowFunctionBodyScope(); +} +export function parseWithArrowExpressionScope( + this: Parser, + callback: () => T, +): [T, AsyncArrowExpressionScope] { + this.asyncArrowExprScopeRecorder.enterAsyncArrowExpressionScope(); + const result = callback(); + const scope = this.asyncArrowExprScopeRecorder.getCurrentAsyncArrowExpressionScope()!; + this.asyncArrowExprScopeRecorder.exitAsyncArrowExpressionScope(); + return [result, scope]; +} +export function parseWithCatpureLayer(this: Parser, callback: () => T): [T, StrictModeScope] { + this.strictModeScopeRecorder.enterCatpureStrictModeScope(); + const result = callback(); + const scope = this.strictModeScopeRecorder.getCurrentStrictModeScope(); + this.strictModeScopeRecorder.exitStrictModeScope(); + return [result, scope]; +} +export function parseWithLHSLayer(this: Parser, callback: () => T): T { + this.strictModeScopeRecorder.enterLHSStrictModeScope(); + const result = callback(); + this.strictModeScopeRecorder.exitStrictModeScope(); + return result; +} +export function parseWithLHSLayerReturnScope(this: Parser, callback: () => T): [T, StrictModeScope] { + this.strictModeScopeRecorder.enterLHSStrictModeScope(); + const result = callback(); + const scope = this.strictModeScopeRecorder.getCurrentStrictModeScope(); + this.strictModeScopeRecorder.exitStrictModeScope(); + return [result, scope]; +} +export function parseWithRHSLayer(this: Parser, callback: () => T): T { + this.strictModeScopeRecorder.enterRHSStrictModeScope(); + const result = callback(); + this.strictModeScopeRecorder.exitStrictModeScope(); + return result; +} +export function checkStrictModeScopeError(this: Parser, scope: StrictModeScope) { + if (this.isInStrictMode() && this.strictModeScopeRecorder.isStrictModeScopeViolateStrictMode(scope)) { + if (scope.kind !== "RHSLayer") { + for (const pos of scope.argumentsIdentifier) { + this.raiseError(ErrorMessageMap.syntax_error_bad_strict_arguments_eval, pos); + } + for (const pos of scope.evalIdentifier) { + this.raiseError(ErrorMessageMap.syntax_error_bad_strict_arguments_eval, pos); + } + for (const pos of scope.letIdentifier) { + this.raiseError(ErrorMessageMap.unexpect_keyword_in_stric_mode, pos); + } + for (const pos of scope.yieldIdentifier) { + this.raiseError(ErrorMessageMap.unexpect_keyword_in_stric_mode, pos); + } + for (const pos of scope.preservedWordIdentifier) { + this.raiseError(ErrorMessageMap.unexpect_keyword_in_stric_mode, pos); + } + } + } +} +export function checkAsyncArrowExprScopeError(this: Parser, scope: AsyncArrowExpressionScope) { + if (this.asyncArrowExprScopeRecorder.isAsyncArrowExpressionScopeHaveError(scope)) { + for (const pos of scope.awaitExpressionInParameter) { + this.raiseError(ErrorMessageMap.extra_error_await_expression_can_not_used_in_parameter_list, pos); + } + for (const pos of scope.yieldExpressionInParameter) { + this.raiseError(ErrorMessageMap.extra_error_yield_expression_can_not_used_in_parameter_list, pos); + } + for (const pos of scope.awaitIdentifier) { + this.raiseError( + ErrorMessageMap.babel_error_can_not_use_await_as_identifier_inside_an_async_function, + pos, + ); + } + } +} +export function enterFunctionParameter(this: Parser) { + this.lexicalScopeRecorder.enterFunctionLexicalScopeParamemter(); +} +export function existFunctionParameter(this: Parser) { + this.lexicalScopeRecorder.exitFunctionLexicalScopeParamemter(); +} +export function setCurrentFunctionContextAsGenerator(this: Parser) { + this.lexicalScopeRecorder.setCurrentFunctionLexicalScopeAsGenerator(); +} +export function setCurrentFunctionContextAsStrictMode(this: Parser) { + this.lexicalScopeRecorder.setCurrentFunctionLexicalScopeAsStrictMode(); + this.lexer.setStrictModeContext(true); +} +/** + * Private API for `For-In` parsering problem. + * @returns {boolean} + */ +export function getCurrentInOperatorStack(this: Parser): boolean { + if (this.context.inOperatorStack.length === 0) { + return false; + } + return this.context.inOperatorStack[this.context.inOperatorStack.length - 1]; +} +export function isTopLevel(this: Parser): boolean { + return this.lexicalScopeRecorder.isInTopLevel(); +} +export function isCurrentScopeParseAwaitAsExpression(this: Parser): boolean { + return this.lexicalScopeRecorder.canAwaitParseAsExpression(); +} +export function isCurrentScopeParseYieldAsExpression(this: Parser): boolean { + return this.lexicalScopeRecorder.canYieldParseAsExpression(); +} +export function isInParameter(this: Parser): boolean { + return this.lexicalScopeRecorder.isInParameter(); +} +export function setCurrentFunctionParameterListAsNonSimple(this: Parser) { + return this.lexicalScopeRecorder.setCurrentFunctionLexicalScopeParameterAsNonSimple(); +} +export function isCurrentFunctionParameterListSimple(this: Parser): boolean { + return this.lexicalScopeRecorder.isCurrentFunctionLexicalScopeParameterSimple(); +} +export function isParentFunctionAsync(this: Parser): boolean { + return this.lexicalScopeRecorder.isParentFunctionAsync(); +} +export function isParentFunctionGenerator(this: Parser): boolean { + return this.lexicalScopeRecorder.isParentFunctionGenerator(); +} +export function enterClassScope(this: Parser, isExtend: boolean = false) { + this.lexicalScopeRecorder.enterClassLexicalScope(isExtend); + this.asyncArrowExprScopeRecorder.enterAsyncArrowExpressionScope(); + this.symbolScopeRecorder.enterClassSymbolScope(); +} +export function existClassScope(this: Parser) { + const duplicateSet = this.symbolScopeRecorder.isDuplicatePrivateName(); + if (duplicateSet) { + for (const pos of duplicateSet.values()) { + this.raiseError(ErrorMessageMap.babel_error_private_name_duplicate, pos); + } + } + const undefSet = this.symbolScopeRecorder.isUndeinfedPrivateName(); + if (undefSet) { + for (const pos of undefSet.values()) { + this.raiseError(ErrorMessageMap.babel_error_private_name_undeinfed, pos); + } + } + this.lexicalScopeRecorder.exitClassLexicalScope(); + this.symbolScopeRecorder.exitClassSymbolScope(); + this.asyncArrowExprScopeRecorder.exitAsyncArrowExpressionScope(); +} +export function isInClassScope(this: Parser): boolean { + return this.lexicalScopeRecorder.isInClassScope(); +} +export function isCurrentClassExtend(this: Parser): boolean { + return this.lexicalScopeRecorder.isCurrentClassExtend(); +} +export function usePrivateName( + this: Parser, + name: string, + position: SourcePosition, + type: PrivateNameDefKind = "other", +) { + return this.symbolScopeRecorder.usePrivateName(name, position, type); +} +export function defPrivateName( + this: Parser, + name: string, + position: SourcePosition, + type: PrivateNameDefKind = "other", +) { + return this.symbolScopeRecorder.defPrivateName(name, position, type); +} +export function enterDelete(this: Parser) { + this.lexicalScopeRecorder.enterDelete(); +} +export function exitDelete(this: Parser) { + this.lexicalScopeRecorder.exitDelete(); +} +export function isInDelete(this: Parser) { + return this.lexicalScopeRecorder.isCurrentInDelete(); +} +export function isInStrictMode(this: Parser): boolean { + return this.lexicalScopeRecorder.isInStrictMode(); +} +export function isDirectToFunctionContext(this: Parser): boolean { + return this.lexicalScopeRecorder.isDirectToFunctionContext(); +} +export function isDirectToClassScope(this: Parser): boolean { + return this.lexicalScopeRecorder.isDirectToClassScope(); +} +export function isReturnValidate(this: Parser): boolean { + return this.config.allowReturnOutsideFunction || this.lexicalScopeRecorder.isReturnValidate(); +} +export function isBreakValidate(this: Parser): boolean { + return this.lexicalScopeRecorder.isBreakValidate(); +} +export function isContinueValidate(this: Parser): boolean { + return this.lexicalScopeRecorder.isContinueValidate(); +} +export function canLabelReach(this: Parser, name: string): boolean { + return this.lexicalScopeRecorder.canLabelReach(name); +} +export function isEncloseInFunction(this: Parser): boolean { + return this.lexicalScopeRecorder.isEncloseInFunction(); +} +export function isInPropertyName(this: Parser): boolean { + return this.lexicalScopeRecorder.isInPropertyName(); +} +export function setExportContext(this: Parser, context: ExportContext) { + this.lexicalScopeRecorder.setExportContext(context); +} +export function getExportContext(this: Parser): ExportContext { + return this.lexicalScopeRecorder.getExportContext(); +} +export function takeCacheDecorator(this: Parser) { + const list = this.context.cache.decorators; + this.context.cache.decorators = null; + return list; +} +export function mergeDecoratorList(input1: Decorator[] | null, input2: Decorator[] | null) { + const list = [...(input1 || []), ...(input2 || [])]; + if (list.length === 0) { + return null; + } + return list; +} +/** + * + * @param name + * @param position + * @returns + */ +export function declarateNonFunctionalSymbol(this: Parser, name: string, position: SourcePosition) { + if (this.context.isInType) return; + if (this.isInParameter()) { + this.symbolScopeRecorder.declarateParam(name, position); + return; + } + if (!this.symbolScopeRecorder.declarateNonFunctionalSymbol(name)) { + this.raiseError(ErrorMessageMap.v8_error_duplicate_identifier, position); + } + const isExportAlreadyExist = this.declarateExportSymbolIfInContext(name, position); + if (isExportAlreadyExist) { + this.raiseError(ErrorMessageMap.v8_error_duplicate_identifier, isExportAlreadyExist); + } + return; +} +/** + * + * @param name + * @param generator + * @param position + * @returns + */ +export function delcarateFcuntionSymbol( + this: Parser, + name: string, + generator: boolean, + position: SourcePosition, +) { + if (this.context.isInType) return; + const duplicateType = this.symbolScopeRecorder.declarateFuncrtionSymbol(name, generator); + if (duplicateType) { + if ( + (!generator && + ((duplicateType === SymbolType.Function && this.config.sourceType === "module") || + duplicateType === SymbolType.GenFunction)) || + (generator && + ((duplicateType === SymbolType.GenFunction && this.config.sourceType === "module") || + duplicateType === SymbolType.Function)) || + (duplicateType === SymbolType.Var && this.lexicalScopeRecorder.isInCatch()) || + duplicateType === SymbolType.Let || + duplicateType === SymbolType.Const + ) { + this.raiseError(ErrorMessageMap.v8_error_duplicate_identifier, position); + } + } + const isExportAlreadyExist = this.declarateExportSymbolIfInContext(name, position); + if (isExportAlreadyExist) { + this.raiseError(ErrorMessageMap.v8_error_duplicate_identifier, isExportAlreadyExist); + } + return; +} +export function declarateLetSymbol(this: Parser, name: string, position: SourcePosition) { + if (this.context.isInType) return; + if (!this.symbolScopeRecorder.declarateLetSymbol(name)) { + this.raiseError(ErrorMessageMap.v8_error_duplicate_identifier, position); + } + const isExportAlreadyExist = this.declarateExportSymbolIfInContext(name, position); + if (isExportAlreadyExist) { + this.raiseError(ErrorMessageMap.v8_error_duplicate_identifier, isExportAlreadyExist); + } +} +export function declarateParam(this: Parser, name: string, position: SourcePosition) { + if (this.context.isInType) return; + this.symbolScopeRecorder.declarateParam(name, position); + this.declarateExportSymbolIfInContext(name, position); + return; +} +export function declarateExportSymbolIfInContext(this: Parser, name: string, position: SourcePosition) { + if (this.context.isInType) return; + switch (this.getExportContext()) { + case ExportContext.NotInExport: + return null; + case ExportContext.InExport: { + this.setExportContext(ExportContext.NotInExport); + return this.declarateExportSymbol(name, position); + } + case ExportContext.InExportBinding: { + return this.declarateExportSymbol(name, position); + } + } +} +export function declarateExportSymbol(this: Parser, name: string, position: SourcePosition) { + if (this.context.isInType) return; + return this.symbolScopeRecorder.declarateExportSymbol(name, position); +} +export function isVariableDeclarated(this: Parser, name: string) { + return this.symbolScopeRecorder.isVariableDeclarated(name); +} +export function getSymbolType(this: Parser) { + return this.symbolScopeRecorder.getSymbolType() as NonFunctionalSymbolType; +} +export function setSymbolType(this: Parser, symbolType: NonFunctionalSymbolType) { + this.symbolScopeRecorder.setSymbolType(symbolType); +} +/** + * Raise a error, if config recoverable set to false, it will throw a error and + * cause stack unwidning. + * @param message + * @param position + */ +export function raiseError(this: Parser, message: string, position: SourcePosition) { + this.errorHandler.pushSyntaxErrors({ + message, + position, + }); +} diff --git a/web-infras/parser/src/parser/index.ts b/web-infras/parser/src/parser/index.ts index 5c58fd8f..174589ec 100644 --- a/web-infras/parser/src/parser/index.ts +++ b/web-infras/parser/src/parser/index.ts @@ -1 +1,72 @@ -export * from "./parser"; +import { createLexer, type Lexer } from "@/src/lexer"; +import type { Context } from "./context"; +import { + createAsyncArrowExpressionScopeRecorder, + type AsyncArrowExpressionScopeRecorder, +} from "./scope/arrowExprScope"; +import { createStrictModeScopeRecorder, type StrictModeScopeRecorder } from "./scope/strictModeScope"; +import { createLexicalScopeRecorder, type LexicalScopeRecorder } from "./scope/lexicalScope"; +import { createSymbolScopeRecorder, type SymbolScopeRecorder } from "./scope/symbolScope"; +import { getConfigFromUserInput, ParserUserConfig, type ParserConfig } from "./config"; +import type { SyntaxErrorHandler } from "../errorHandler/type"; + +import * as ContextImpl from "./context"; +import * as JSImpl from "./js"; +import * as TSImpl from "./ts"; +import * as JSXImpl from "./jsx"; + +type ContextImplType = typeof ContextImpl; +type JSImplType = typeof JSImpl; +type TSImplType = typeof TSImpl; +type JSXImplType = typeof JSXImpl; + +export class Parser { + lexer: Lexer; + context: Context; + config: ParserConfig; + // recorder + strictModeScopeRecorder: StrictModeScopeRecorder; + asyncArrowExprScopeRecorder: AsyncArrowExpressionScopeRecorder; + lexicalScopeRecorder: LexicalScopeRecorder; + symbolScopeRecorder: SymbolScopeRecorder; + // error + errorHandler: SyntaxErrorHandler; + constructor(code: string, errorHandler: SyntaxErrorHandler, config?: ParserUserConfig) { + this.lexer = createLexer(code); + this.context = ContextImpl.createContext(); + this.config = getConfigFromUserInput(config); + this.strictModeScopeRecorder = createStrictModeScopeRecorder(); + this.asyncArrowExprScopeRecorder = createAsyncArrowExpressionScopeRecorder(); + this.lexicalScopeRecorder = createLexicalScopeRecorder(); + this.symbolScopeRecorder = createSymbolScopeRecorder(); + this.errorHandler = errorHandler; + } +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function bindingParserMethod(methods: any) { + Object.entries(methods).forEach(([name, method]) => { + // @ts-expect-error implement in JS prototype + Parser.prototype[name] = method; + }); +} + +bindingParserMethod(ContextImpl); +bindingParserMethod(JSImpl); +bindingParserMethod(TSImpl); +bindingParserMethod(JSXImpl); + +declare module "./index" { + interface Parser extends ContextImplType, JSImplType, TSImplType, JSXImplType { + lexer: Lexer; + context: Context; + config: ParserConfig; + // recorder + strictModeScopeRecorder: StrictModeScopeRecorder; + asyncArrowExprScopeRecorder: AsyncArrowExpressionScopeRecorder; + lexicalScopeRecorder: LexicalScopeRecorder; + symbolScopeRecorder: SymbolScopeRecorder; + // error + errorHandler: SyntaxErrorHandler; + } +} diff --git a/web-infras/parser/src/parser/js/const.ts b/web-infras/parser/src/parser/js/const.ts new file mode 100644 index 00000000..d3f2b64e --- /dev/null +++ b/web-infras/parser/src/parser/js/const.ts @@ -0,0 +1,22 @@ +import { Keywords, LexicalLiteral, SourcePosition, SyntaxKinds } from "web-infra-common"; + +export const IdentiferWithKeyworArray = [SyntaxKinds.Identifier, ...Keywords]; +export const PreserveWordSet = new Set(LexicalLiteral.preserveword); +export const BindingIdentifierSyntaxKindArray = [ + SyntaxKinds.Identifier, + SyntaxKinds.AwaitKeyword, + SyntaxKinds.YieldKeyword, + SyntaxKinds.LetKeyword, +]; +export const KeywordSet = new Set([ + ...LexicalLiteral.keywords, + ...LexicalLiteral.BooleanLiteral, + ...LexicalLiteral.NullLiteral, + ...LexicalLiteral.UndefinbedLiteral, +]); + +export interface ASTArrayWithMetaData { + nodes: Array; + start: SourcePosition; + end: SourcePosition; +} diff --git a/web-infras/parser/src/parser/js/declaration.ts b/web-infras/parser/src/parser/js/declaration.ts new file mode 100644 index 00000000..24f8f16b --- /dev/null +++ b/web-infras/parser/src/parser/js/declaration.ts @@ -0,0 +1,819 @@ +/** ================================================================= + * Parse Delcarations + * entry point reference: https://tc39.es/ecma262/#prod-Declaration + * ================================================================== + */ +import { Parser } from "@/src/parser"; +import { + Function as FunctionAST, + VariableDeclaration, + SyntaxKinds, + VariableDeclarator, + isIdentifer, + TSParameter, + Factory, + cloneSourcePosition, + FunctionDeclaration, + TSDeclareFunction, + Identifier, + FunctionBody, + StatementListItem, + Pattern, + Decorator, + Expression, + ClassDeclaration, + Class, + ClassBody, + ClassElement, + ClassMethodDefinition, + PropertyName, + PrivateName, + Keywords, + isPrivateName, + isStringLiteral, + Declaration, +} from "web-infra-common"; +import { ErrorMessageMap } from "@/src/parser/error"; +import { ExportContext } from "@/src/parser/scope/lexicalScope"; +import { StrictModeScope } from "@/src/parser/scope/strictModeScope"; +import { SymbolType } from "@/src/parser/scope/symbolScope"; +import { BindingIdentifierSyntaxKindArray, PreserveWordSet } from "@/src/parser/type"; +/** + * Parse Declaration + * + * ``` + * Declaration := ('let' | 'const') BindingLst + * := FunctionDeclaration + * := FunctionGeneratorDeclaration + * := 'async' FunctionDeclaration + * := 'async' FunctionGeneratorDeclaration + * := ClassDeclaration + * ``` + * when call parseDeclaration, please make sure currentToken is + * - `let` or `const` keyword + * - `function` keyword + * - `class` keyword + * - `async` with `function` keyword + * + * ref: https://tc39.es/ecma262/#prod-Declaration + * @returns + */ +export function parseDeclaration(this: Parser): Declaration { + const token = this.getToken(); + switch (token) { + // async function declaration + case SyntaxKinds.Identifier: + case SyntaxKinds.EnumKeyword: { + const declar = this.tryParseDeclarationWithIdentifierStart(); + if (!declar) { + throw this.createUnexpectError(); + } + return declar; + } + // function delcaration + case SyntaxKinds.FunctionKeyword: + return this.parseFunctionDeclaration(false, false); + case SyntaxKinds.ConstKeyword: + case SyntaxKinds.LetKeyword: + return this.parseVariableDeclaration(); + case SyntaxKinds.AtPunctuator: + return this.parseClassDeclaration(this.parseDecoratorList()); + case SyntaxKinds.ClassKeyword: + return this.parseClassDeclaration(null); + default: + throw this.createUnexpectError(); + } +} +export function tryParseDeclarationWithIdentifierStart(this: Parser): Declaration | undefined { + if (this.getEscFlag()) { + return; + } + if (this.match(SyntaxKinds.EnumKeyword)) { + return this.parseTSEnumDeclaration(); + } + const { kind: lookaheadToken, lineTerminatorFlag } = this.lookahead(); + const sourceValue = this.getSourceValue(); + switch (sourceValue) { + case "async": { + if (!(lookaheadToken === SyntaxKinds.FunctionKeyword && !lineTerminatorFlag)) { + return; + } + this.nextToken(); + if (this.getLineTerminatorFlag()) { + this.raiseError(ErrorMessageMap.missing_semicolon, this.getStartPosition()); + } + return this.parseFunctionDeclaration(true, false); + } + case "type": { + if (!(lookaheadToken === SyntaxKinds.Identifier && !lineTerminatorFlag)) { + return; + } + return this.parseTSTypeAlias(); + } + case "interface": { + if (!(lookaheadToken === SyntaxKinds.Identifier && !lineTerminatorFlag)) { + return; + } + return this.parseTSInterfaceDeclaration(); + } + default: { + return; + } + } +} +/** + * Parse VariableStatement and LexicalBindingDeclaration. + * + * when in for-in statement, variable declaration do not need semi for + * ending, in binding pattern of for-in statement, variable declaration + * maybe do not need init.(for-in, for-of do not need, but for still need) + * + * Anthoer side, let can be identifier in VariableStatement. and parsrIdentifier + * function would always parse let as identifier if not in strict mode. so we need + * to implement custom function for check is identifier or value of pattern is let + * when in LexicalBindingDeclaration + * ``` + * VariableStatement := 'var' VariableDeclarationList + * LexicalBidningDeclaration := '(let | const)' LexicalBinding + * VariableDeclarationList := BindingIdentidier initalizer + * := BindingPattern initalizer + * LexicalBinding := BindingIdentidier initalizer + * := BindingPattern initalizer + * ``` + * @returns {VariableDeclaration} + */ +export function parseVariableDeclaration(this: Parser, inForInit: boolean = false): VariableDeclaration { + const variableKind = this.match(SyntaxKinds.VarKeyword) ? "var" : "lexical"; + const { start: keywordStart, value: variant } = this.expect([ + SyntaxKinds.VarKeyword, + SyntaxKinds.ConstKeyword, + SyntaxKinds.LetKeyword, + ]); + let shouldStop = false, + isStart = true; + const declarations: Array = []; + const lastSymbolKind = this.getSymbolType(); + this.setSymbolType( + variant === "var" ? SymbolType.Var : variant === "const" ? SymbolType.Const : SymbolType.Let, + ); + if (this.getExportContext() === ExportContext.InExport) { + this.setExportContext(ExportContext.InExportBinding); + } + while (!shouldStop) { + if (isStart) { + isStart = false; + } else { + if (!this.match(SyntaxKinds.CommaToken)) { + shouldStop = true; + continue; + } + this.nextToken(); + } + // eslint-disable-next-line prefer-const + let [id, scope] = this.parseWithCatpureLayer(() => this.parseBindingElement(false)); + const isBindingPattern = !isIdentifer(id); + if (variableKind === "lexical" && scope.kind !== "RHSLayer" && scope.letIdentifier.length > 0) { + throw new Error("TODO ERROR: Better"); + } + id = this.parseFunctionParamType(id as TSParameter, false); + // custom logical for check is lexical binding have let identifier ? + if ( + // variable declarations binding pattern but but have init. + (isBindingPattern || variant === "const") && + !this.match(SyntaxKinds.AssginOperator) && + // variable declaration in for statement can existed with `of`, `in` operator + !inForInit + ) { + // recoverable error + this.raiseError(ErrorMessageMap.syntax_error_missing_init_in_const_declaration, id.start); + } + if (this.match(SyntaxKinds.AssginOperator)) { + this.nextToken(); + const init = this.parseAssignmentExpressionInheritIn(); + declarations.push( + Factory.createVariableDeclarator( + id, + init, + cloneSourcePosition(id.start), + cloneSourcePosition(init.end), + ), + ); + continue; + } + declarations.push( + Factory.createVariableDeclarator(id, null, cloneSourcePosition(id.start), cloneSourcePosition(id.end)), + ); + } + this.setSymbolType(lastSymbolKind); + this.setExportContext(ExportContext.NotInExport); + if (!inForInit) { + this.shouldInsertSemi(); + } + return Factory.createVariableDeclaration( + declarations, + variant as VariableDeclaration["variant"], + keywordStart, + declarations[declarations.length - 1].end, + ); +} +export function parseFunctionDeclaration( + this: Parser, + isAsync: boolean, + isDefault: boolean, +): FunctionDeclaration | TSDeclareFunction { + this.enterFunctionScope(isAsync); + const { start } = this.expect(SyntaxKinds.FunctionKeyword); + let generator = false; + if (this.match(SyntaxKinds.MultiplyOperator)) { + generator = true; + this.setCurrentFunctionContextAsGenerator(); + this.nextToken(); + } + const [[name, typeParameters, params], scope] = this.parseWithCatpureLayer(() => { + const name = this.parseFunctionName(isDefault); + if (!name && !isDefault) { + // recoverable error + this.raiseError( + ErrorMessageMap.syntax_error_function_statement_requires_a_name, + this.getStartPosition(), + ); + } + const typeParameters = this.tryParseTSTypeParameterDeclaration(false); + const params = this.parseFunctionParam(); + return [name, typeParameters, params]; + }); + const returnType = this.tryParseTSReturnTypeOrTypePredicate(SyntaxKinds.ColonPunctuator); + if (this.match(SyntaxKinds.BracesLeftPunctuator)) { + const body = this.parseFunctionBody(); + this.postStaticSematicEarlyErrorForStrictModeOfFunction(name, scope); + const func = Factory.createFunction( + name, + body, + params, + typeParameters, + returnType, + generator, + this.isCurrentScopeParseAwaitAsExpression(), + start, + cloneSourcePosition(body.end), + ); + this.exitFunctionScope(false); + // for function declaration, symbol should declar in parent scope. + if (name) { + this.delcarateFcuntionSymbol(name.name, func.generator, func.start); + } + return Factory.transFormFunctionToFunctionDeclaration(func); + } else { + const funcDeclar = Factory.createTSDeclarFunction( + name, + returnType, + params, + typeParameters, + generator, + this.isCurrentScopeParseAwaitAsExpression(), + start, + this.getLastTokenEndPositon(), + ); + this.shouldInsertSemi(); + this.exitFunctionScope(false); + return funcDeclar; + } +} +/** + * Parse function maybe call by parseFunctionDeclaration and parseFunctionExpression, + * first different of those two function is that function-declaration can not have null + * name. + * @returns {FunctionAST} + */ +export function parseFunction(this: Parser, isExpression: boolean): FunctionAST { + const { start } = this.expect(SyntaxKinds.FunctionKeyword); + let generator = false; + if (this.match(SyntaxKinds.MultiplyOperator)) { + generator = true; + this.setCurrentFunctionContextAsGenerator(); + this.nextToken(); + } + const [[name, typeParameters, params], scope] = this.parseWithCatpureLayer(() => { + const name = this.parseFunctionName(isExpression); + if (!name && !isExpression) { + // recoverable error + this.raiseError( + ErrorMessageMap.syntax_error_function_statement_requires_a_name, + this.getStartPosition(), + ); + } + const typeParameters = this.tryParseTSTypeParameterDeclaration(false); + const params = this.parseFunctionParam(); + return [name, typeParameters, params]; + }); + const returnType = this.tryParseTSReturnTypeOrTypePredicate(SyntaxKinds.ColonPunctuator); + const body = this.parseFunctionBody(); + this.postStaticSematicEarlyErrorForStrictModeOfFunction(name, scope); + return Factory.createFunction( + name, + body, + params, + typeParameters, + returnType, + generator, + this.isCurrentScopeParseAwaitAsExpression(), + start, + cloneSourcePosition(body.end), + ); +} +/** + * Because we "use strict" directive is in function body, we will not sure + * if this function contain stric directive or not until we enter the function body. + * as the result, we need to check function name and function paramemter's name after + * parseFunctionBody. + * @param name + * @param params + */ +export function postStaticSematicEarlyErrorForStrictModeOfFunction( + this: Parser, + name: Identifier | null, + scope: StrictModeScope, +) { + if (this.isInStrictMode()) { + this.checkStrictModeScopeError(scope); + if (name) { + if ( + name.name === "arugments" || + name.name === "eval" || + name.name === "yield" || + name.name === "let" || + PreserveWordSet.has(name.name) + ) { + this.raiseError(ErrorMessageMap.unexpect_keyword_in_stric_mode, name.start); + } + } + } +} +/** + * When parse name of function, can not just call parseIdentifier, because function name + * maybe await or yield, and function name's context rule is different from identifier in + * scope (function body). so there we need to implement special logical for parse function + * name. and you need to note that name of function expression and name of function delcaration + * have different context rule for parse function name. + * @param {boolean} optionalName + * @returns {Identifier | null} + */ +export function parseFunctionName(this: Parser, optionalName: boolean): Identifier | null { + return this.parseWithLHSLayer(() => { + let name: Identifier | null = null; + // there we do not just using parseIdentifier function as the reason above + // let can be function name as other place + if (this.match([SyntaxKinds.Identifier, SyntaxKinds.LetKeyword])) { + name = this.parseIdentifierReference(); + } else { + if (this.match(SyntaxKinds.AwaitKeyword)) { + // for function expression, can await treat as function name is dep on current scope. + if (optionalName && this.isCurrentScopeParseAwaitAsExpression()) { + this.raiseError( + ErrorMessageMap.babel_error_can_not_use_await_as_identifier_inside_an_async_function, + this.getStartPosition(), + ); + } + // for function declaration, can await treat as function name is dep on parent scope. + if (!optionalName && this.isParentFunctionAsync()) { + this.raiseError( + ErrorMessageMap.babel_error_can_not_use_await_as_identifier_inside_an_async_function, + this.getStartPosition(), + ); + } + if (this.config.sourceType === "module") { + this.raiseError( + ErrorMessageMap.babel_error_can_not_use_await_as_identifier_inside_an_async_function, + this.getStartPosition(), + ); + } + name = this.parseIdentifierName(); + } else if (this.match(SyntaxKinds.YieldKeyword)) { + // for function expression, can yield treat as function name is dep on current scope. + if (optionalName && this.isCurrentScopeParseYieldAsExpression()) { + this.raiseError(ErrorMessageMap.babel_error_invalid_yield, this.getStartPosition()); + } + // for function declaration, can yield treat as function name is dep on parent scope. + if (!optionalName && this.isParentFunctionGenerator()) { + this.raiseError(ErrorMessageMap.babel_error_invalid_yield, this.getStartPosition()); + } + // if in strict mode, yield can not be function name. + if (this.isInStrictMode()) { + this.raiseError(ErrorMessageMap.babel_error_invalid_yield, this.getStartPosition()); + } + name = this.parseIdentifierName(); + } + } + return name; + }); +} +/** + * Parse Function Body + * ``` + * FunctionBody := '{' StatementList '}' + * StatementList := StatementList StatementListItem + * := StatementListItem + * ``` + * @return {FunctionBody} + */ +export function parseFunctionBody(this: Parser): FunctionBody { + const { start } = this.expect(SyntaxKinds.BracesLeftPunctuator); + const body: Array = []; + while (!this.match(SyntaxKinds.BracesRightPunctuator) && !this.match(SyntaxKinds.EOFToken)) { + body.push(this.parseStatementListItem()); + } + const { end } = this.expect(SyntaxKinds.BracesRightPunctuator); + return Factory.createFunctionBody(body, start, end); +} +/** + * Parse Function Params, parameter list is a spcial place for await and yield, + * function parameter list is in current function scope, so await and yield would + * parse as expression, but parameter list can not call await and yield expression. + * + * Anthoer thing is that trailing comma of restElement is error, multi restElement is + * error for function param list. + * ``` + * FunctionParams := '(' FunctionParamsList ')' + * := '(' FunctionParamsList ',' ')' + * := '(' FunctionPramsList ',' RestElement ')' + * := '(' RestElement ')' + * FunctiinParamList := FunctionParamList ',' FunctionParam + * := FunctionParam + * FunctionParam := BindingElement + * ``` + */ +export function parseFunctionParam(this: Parser): Array { + this.expect(SyntaxKinds.ParenthesesLeftPunctuator); + this.enterFunctionParameter(); + let isStart = true; + let isEndWithRest = false; + const params: Array = []; + while (!this.match(SyntaxKinds.ParenthesesRightPunctuator)) { + if (isStart) { + if (this.match(SyntaxKinds.CommaToken)) { + // recoverable error + this.raiseError(ErrorMessageMap.extra_error_unexpect_trailing_comma, this.getStartPosition()); + this.nextToken(); + } + isStart = false; + } else { + this.expect(SyntaxKinds.CommaToken); + } + if (this.match(SyntaxKinds.ParenthesesRightPunctuator)) { + continue; + } + // parse SpreadElement (identifer, Object, Array) + let param: Pattern; + if (this.match(SyntaxKinds.SpreadOperator)) { + isEndWithRest = true; + param = this.parseRestElement(true); + param = this.parseFunctionParamType(param as TSParameter, true); + params.push(param); + break; + } else { + param = this.parseBindingElement(); + param = this.parseFunctionParamType(param as TSParameter, true); + params.push(param); + } + } + if (!this.match(SyntaxKinds.ParenthesesRightPunctuator)) { + if (isEndWithRest && this.match(SyntaxKinds.CommaToken)) { + // recoverable error + this.raiseError( + ErrorMessageMap.babel_error_unexpected_trailing_comma_after_rest_element, + this.getStartPosition(), + ); + this.nextToken(); + } + throw this.createUnexpectError(); + } + this.nextToken(); + this.setContextIfParamsIsSimpleParameterList(params); + this.existFunctionParameter(); + return params; +} +/** + * Helper function for check if parameter list is simple + * parameter list or not, if is simple parameter, set + * the context. + * @param {Array} params + * @returns + */ +export function setContextIfParamsIsSimpleParameterList(this: Parser, params: Array) { + for (const param of params) { + if (!isIdentifer(param)) { + this.setCurrentFunctionParameterListAsNonSimple(); + return; + } + } +} +export function parseDecoratorListToCache(this: Parser) { + const decoratorList = this.parseDecoratorList(); + this.context.cache.decorators = decoratorList; +} +export function parseDecoratorList(this: Parser): [Decorator] { + const decoratorList: [Decorator] = [this.parseDecorator()]; + while (this.match(SyntaxKinds.AtPunctuator)) { + decoratorList.push(this.parseDecorator()); + } + if ( + this.match(SyntaxKinds.ClassKeyword) || + (this.match(SyntaxKinds.ExportKeyword) && this.config.sourceType === "module") || + this.isInClassScope() + ) { + return decoratorList; + } + this.raiseError( + ErrorMessageMap.babel_error_leading_decorators_must_be_attached_to_a_class_declaration, + decoratorList[0].start, + ); + return decoratorList; +} +export function parseDecorator(this: Parser): Decorator { + const { start } = this.expect(SyntaxKinds.AtPunctuator); + switch (this.getToken()) { + case SyntaxKinds.ParenthesesLeftPunctuator: { + this.nextToken(); + const expr = this.parseExpressionAllowIn(); + this.expect(SyntaxKinds.ParenthesesRightPunctuator); + return Factory.createDecorator(expr, start, expr.end); + } + default: { + let expr: Expression = this.parseIdentifierName(); + while (this.match(SyntaxKinds.DotOperator)) { + this.nextToken(); + const property = this.match(SyntaxKinds.PrivateName) + ? this.parsePrivateName() + : this.parseIdentifierName(); + expr = Factory.createMemberExpression( + false, + property, + expr, + false, + cloneSourcePosition(expr.start), + cloneSourcePosition(property.end), + ); + } + if ( + this.match(SyntaxKinds.LtOperator) || + this.match(SyntaxKinds.BitwiseLeftShiftOperator) || + this.match(SyntaxKinds.ParenthesesLeftPunctuator) + ) { + const typeArguments = this.tryParseTSTypeParameterInstantiation(false); + const { nodes, end } = this.parseArguments(); + const callExpr = Factory.createCallExpression( + expr, + nodes, + typeArguments, + false, + cloneSourcePosition(expr.start), + end, + ); + return Factory.createDecorator(callExpr, start, cloneSourcePosition(callExpr.end)); + } + return Factory.createDecorator(expr, start, expr.end); + } + } +} + +/** + * + */ +export function parseClassDeclaration(this: Parser, decoratorList: Decorator[] | null): ClassDeclaration { + this.expectButNotEat(SyntaxKinds.ClassKeyword); + decoratorList = decoratorList || this.takeCacheDecorator(); + const classDelcar = this.parseClass(decoratorList); + if (classDelcar.id === null) { + this.raiseError(ErrorMessageMap.babel_error_a_class_name_is_required, classDelcar.start); + } + return Factory.transFormClassToClassDeclaration(classDelcar); +} +/** + * Parse Class + * ``` + * Class := 'class' identifer ('extends' LeftHandSideExpression) ClassBody + * ``` + * @returns {Class} + */ +export function parseClass(this: Parser, decoratorList: Decorator[] | null): Class { + const { start } = this.expect(SyntaxKinds.ClassKeyword); + let name: Identifier | null = null; + if (this.match(BindingIdentifierSyntaxKindArray)) { + name = this.parseIdentifierReference(); + this.declarateLetSymbol(name.name, name.start); + } + let superClass: Expression | null = null; + if (this.match(SyntaxKinds.ExtendsKeyword)) { + this.enterClassScope(true); + this.nextToken(); + superClass = this.parseLeftHandSideExpression(); + } else { + this.enterClassScope(false); + } + const body = this.parseClassBody(); + this.existClassScope(); + return Factory.createClass(name, superClass, body, decoratorList, start, cloneSourcePosition(body.end)); +} +/** + * Parse ClassBody + * ``` + * ClassBody := '{' [ClassElement] '}' + * ``` + * @return {ClassBody} + */ +export function parseClassBody(this: Parser): ClassBody { + const { start } = this.expect(SyntaxKinds.BracesLeftPunctuator); + const classbody: ClassBody["body"] = []; + while (!this.match(SyntaxKinds.BracesRightPunctuator) && !this.match(SyntaxKinds.EOFToken)) { + if (this.match(SyntaxKinds.SemiPunctuator)) { + this.nextToken(); + continue; + } + classbody.push(this.parseClassElement()); + } + const { end } = this.expect(SyntaxKinds.BracesRightPunctuator); + return Factory.createClassBody(classbody, cloneSourcePosition(start), cloneSourcePosition(end)); +} +/** + * Parse ClassElement + * ``` + * ClassElement := MethodDefinition + * := 'static' MethodDefinition + * := FieldDefintion ; + * := 'static' FieldDefintion ; + * := ClassStaticBlock + * := ; (this production rule handle by caller) + * FieldDefintion := ClassElementName ('=' AssignmentExpression)? + * ``` + * - frist, parse 'static' keyword if possible, next follow cases + * 1. start with some method modifier like 'set', 'get', 'async', '*' must be methodDefintion + * 2. start with '{', must be static block + * - then parse ClassElement + * 1. if next token is '(', must be MethodDefintion, + * 2. else this only case is FieldDefinition with init or not. + * @returns {ClassElement} + */ +export function parseClassElement(this: Parser): ClassElement { + let decorators: Decorator[] | null = null; + if (this.match(SyntaxKinds.AtPunctuator)) { + decorators = this.parseDecoratorList(); + } else { + decorators = this.takeCacheDecorator(); + } + // parse static modifier + const isStatic = this.checkIsMethodStartWithStaticModifier(); + if (this.checkIsMethodStartWithModifier()) { + return this.parseMethodDefintion(true, undefined, isStatic, decorators) as ClassMethodDefinition; + } + if (this.match(SyntaxKinds.BracesLeftPunctuator) && isStatic) { + if (decorators) { + this.raiseError( + ErrorMessageMap.babel_error_decorators_can_not_be_used_with_a_static_block, + decorators[0].start, + ); + } + const { start } = this.expect(SyntaxKinds.BracesLeftPunctuator); + this.symbolScopeRecorder.enterFunctionSymbolScope(); + const body: Array = []; + while (!this.match(SyntaxKinds.BracesRightPunctuator) && !this.match(SyntaxKinds.EOFToken)) { + body.push(this.parseStatementListItem()); + } + this.symbolScopeRecorder.exitSymbolScope(); + const { end } = this.expect(SyntaxKinds.BracesRightPunctuator); + return Factory.createClassStaticBlock(body, start, end); + } + let accessor = false; + if (this.isContextKeyword("accessor")) { + const { kind, lineTerminatorFlag } = this.lookahead(); + if (kind === SyntaxKinds.Identifier && !lineTerminatorFlag) { + this.nextToken(); + accessor = true; + } + } + // parse ClassElementName + const isComputedRef = { isComputed: false }; + let key: PropertyName | PrivateName | undefined; + if (this.match(SyntaxKinds.PrivateName)) { + key = this.parsePrivateName(); + this.defPrivateName(key.name, key.start); + } else { + key = this.parsePropertyName(isComputedRef); + } + if (this.match(SyntaxKinds.ParenthesesLeftPunctuator)) { + return this.parseMethodDefintion( + true, + [key, isComputedRef.isComputed], + isStatic, + decorators, + ) as ClassMethodDefinition; + } + this.staticSematicForClassPropertyName(key, isComputedRef.isComputed, isStatic); + let propertyValue = undefined, + shorted = true; + if (this.match([SyntaxKinds.AssginOperator])) { + this.nextToken(); + shorted = false; + const [value, scope] = this.parseWithCatpureLayer(() => this.parseAssignmentExpressionAllowIn()); + propertyValue = value; + this.staticSematicForClassPropertyValue(scope); + } + this.shouldInsertSemi(); + if (accessor) { + return Factory.createClassAccessorProperty( + key, + propertyValue, + isComputedRef.isComputed, + isStatic, + shorted, + decorators, + cloneSourcePosition(key.start), + cloneSourcePosition(key.end), + ); + } + return Factory.createClassProperty( + key, + propertyValue, + isComputedRef.isComputed, + isStatic, + shorted, + decorators, + cloneSourcePosition(key.start), + cloneSourcePosition(key.end), + ); +} +export function checkIsMethodStartWithStaticModifier(this: Parser) { + const { kind } = this.lookahead(); + if (this.isContextKeyword("static")) { + switch (kind) { + // static + // static get/set/async + // static { + // static [] + // static * + case SyntaxKinds.Identifier: + case SyntaxKinds.PrivateName: + case SyntaxKinds.StringLiteral: + case SyntaxKinds.BracesLeftPunctuator: + case SyntaxKinds.BracketLeftPunctuator: + case SyntaxKinds.MultiplyOperator: + this.nextToken(); + return true; + default: + // static for/if ...etc + if (Keywords.find((kw) => kw === kind)) return true; + return false; + } + } + return false; +} +/** + * For a class scope, it must be strict mode, so argument identifier can + * @param {StrictModeScope} scope + * @returns + */ +export function staticSematicForClassPropertyValue(this: Parser, scope: StrictModeScope) { + if (scope.kind !== "CatpureLayer") { + return; + } + for (const pos of scope.argumentsIdentifier) { + this.raiseError(ErrorMessageMap.syntax_error_bad_strict_arguments_eval, pos); + } +} +/** + * Check sematic for class property name. + * - `constructor` can not used as property name + * - `prototype` can not be a static property + * @param {PropertyName | PrivateName} propertyName + * @param isComputed + * @param {boolean} isStatic + * @returns + */ +export function staticSematicForClassPropertyName( + this: Parser, + propertyName: PropertyName | PrivateName, + isComputed: boolean, + isStatic: boolean, +) { + if (isComputed) return; + let value; + if (isPrivateName(propertyName) || isIdentifer(propertyName)) { + value = propertyName.name; + } else if (isStringLiteral(propertyName)) { + value = propertyName.value; + } + if (value) { + if (value === "constructor") { + // recoverable error + this.raiseError( + ErrorMessageMap.babel_error_classe_may_not_have_a_field_named_constructor, + propertyName.start, + ); + } + if (value === "prototype" && isStatic) { + this.raiseError( + ErrorMessageMap.v8_error_class_may_not_have_static_property_named_prototype, + propertyName.start, + ); + } + } +} diff --git a/web-infras/parser/src/parser/js/expression.ts b/web-infras/parser/src/parser/js/expression.ts new file mode 100644 index 00000000..08b31d27 --- /dev/null +++ b/web-infras/parser/src/parser/js/expression.ts @@ -0,0 +1,1276 @@ +import { + Expression, + SyntaxKinds, + Factory, + cloneSourcePosition, + AssigmentOperators, + Pattern, + AssigmentOperatorKinds, + YieldExpression, + isArrowFunctionExpression, + isPrivateName, + BinaryOperatorKinds, + isUnaryExpression, + isAwaitExpression, + UnaryOperators, + UnaryOperatorKinds, + UnaryExpression, + isIdentifer, + UpdateOperators, + UpdateOperatorKinds, + TSTypeParameterInstantiation, + ModuleItem, + TSTypeAnnotation, + PrivateName, + ExpressionStatement, + isClassExpression, + isFunctionExpression, + isStringLiteral, +} from "web-infra-common"; +import { Parser } from "@/src/parser"; +import { ParserPlugin } from "@/src/parser/config"; +import { ErrorMessageMap } from "@/src/parser/error"; +import { ExpressionScopeKind } from "@/src/parser/scope/type"; +import { ASTArrayWithMetaData } from "@/src/parser/type"; + +interface LefthansSideParseState { + shouldStop: boolean; + hasOptional: boolean; + optional: boolean; + abortLastTime: boolean; +} +/** ==================================================================== + * Parse Expression + * entry point reference : https://tc39.es/ecma262/#sec-comma-operator + * ===================================================================== + */ + +/** + * Entry function for parse a expression statement. + * @returns {ExpressionStatement} + */ +export function parseExpressionStatement(this: Parser): ExpressionStatement { + this.preStaticSematicEarlyErrorForExpressionStatement(); + const lastTokenIndex = this.lexer.getLastTokenEndPositon().index; + const expr = this.parseExpressionAllowIn(); + this.checkStrictMode(expr); + this.postStaticSematicEarlyErrorForExpressionStatement(expr, lastTokenIndex); + this.shouldInsertSemi(); + return Factory.createExpressionStatement( + expr, + cloneSourcePosition(expr.start), + cloneSourcePosition(expr.end), + ); +} +/** + * Implement part of NOTE section in 14.5 + */ +export function preStaticSematicEarlyErrorForExpressionStatement(this: Parser) { + if (this.match(SyntaxKinds.LetKeyword)) { + const { kind, lineTerminatorFlag } = this.lookahead(); + if ( + kind === SyntaxKinds.BracketLeftPunctuator || + (!lineTerminatorFlag && (kind === SyntaxKinds.BracesLeftPunctuator || kind === SyntaxKinds.Identifier)) + ) { + this.raiseError( + ErrorMessageMap.v8_error_lexical_declaration_cannot_appear_in_a_single_statement_context, + this.getStartPosition(), + ); + } + } +} +/** + * Implement part of NOTE section in 14.5 + */ +export function postStaticSematicEarlyErrorForExpressionStatement( + this: Parser, + expr: Expression, + lastTokenIndex: number, +) { + if (!expr.parentheses) { + if (isClassExpression(expr)) { + this.raiseError(ErrorMessageMap.syntax_error_functions_declare_non_strict_mode, expr.start); + return; + } + if (isFunctionExpression(expr)) { + if (expr.async) { + this.raiseError(ErrorMessageMap.syntax_error_async_function_declare, expr.start); + } + if (expr.generator) { + this.raiseError(ErrorMessageMap.syntax_error_generator_function_declare, expr.start); + } + if (this.isInStrictMode()) { + this.raiseError(ErrorMessageMap.syntax_error_functions_declare_strict_mode, expr.start); + } else { + if (lastTokenIndex !== this.context.lastTokenIndexOfIfStmt) { + this.raiseError(ErrorMessageMap.syntax_error_functions_declare_non_strict_mode, expr.start); + } + } + } + } +} +/** + * Helper function for checking `use strict` directive, according to + * ECMA spec, `use strict` directive is a `ExpressionStatement` in + * which value is `use strict`, and this function is doing the same + * thing as spec required. + * + * NOTE: this function would perform side effect to parse context + * + * ref: https://tc39.es/ecma262/#use-strict-directive + * @param {Expression} expr + */ +export function checkStrictMode(this: Parser, expr: Expression) { + if (isStringLiteral(expr)) { + if (expr.value === "use strict" && !expr.parentheses) { + if (this.isDirectToFunctionContext()) { + if (!this.isCurrentFunctionParameterListSimple()) { + // recoverable error + this.raiseError( + ErrorMessageMap.syntax_error_use_strict_not_allowed_in_function_with_non_simple_parameters, + expr.start, + ); + } + this.setCurrentFunctionContextAsStrictMode(); + } + } + } +} +/** + * Private Parse API, parse Expression. + * ``` + * Expression: + * AssignmentExpression + * Expression, AssignmentExpression + * ``` + * Since Expression have in operator syntax action, so there we split parseExpression + * into three kind of function. + * - `parseExpressionAllowIn`: equal to production rule with parameter `Expression[+In]` + * - `parseExpressionDisallowIn`: equal to production rule with parameter `Expression[~In]` + * - `parseExpressionInheritIn`: equal to production rule with parameter `Expression[?in]` + * @returns {Expression} + */ +export function parseExpressionAllowIn(this: Parser): Expression { + return this.allowInOperaotr(() => this.parseExpressionInheritIn()); +} +/** + * Private Parse API, parse Expression. + * - allow disallow in operator syntax transition action. + * - for more detail, please refer to `parseExpressionAllowIn`. + * @returns {Expression} + */ +export function parseExpressionDisallowIn(this: Parser): Expression { + return this.disAllowInOperaotr(() => this.parseExpressionInheritIn()); +} +/** + * Private Parse API, parse Expression. + * - inherit in operator syntax transition action. + * - for more detail, please refer to `parseExpressionAllowIn`. + * @returns {Expression} + */ +export function parseExpressionInheritIn(this: Parser): Expression { + const exprs = [this.parseAssignmentExpressionInheritIn()]; + while (this.match(SyntaxKinds.CommaToken)) { + this.nextToken(); + exprs.push(this.parseAssignmentExpressionInheritIn()); + } + if (exprs.length === 1) { + return exprs[0]; + } + return Factory.createSequenceExpression( + exprs, + cloneSourcePosition(exprs[0].start), + cloneSourcePosition(exprs[exprs.length - 1].end), + ); +} +/** + * Private Parse API, parse AssignmentExpression + * + * Since AssignmentExpression usually is a entry point of in operator syntax action. just like + * parseExpression, there we split function into three kind: + * - `parseAssignmentExpressionAllowIn`: equals to production rule with parameter + * - `parseAssignmentExpressionInhertIn`: equals to production rule with parameter + * - It since that disallow is not show in current spec, so ignore it. + * @returns {Expression} + */ +export function parseAssignmentExpressionAllowIn(this: Parser): Expression { + return this.allowInOperaotr(() => this.parseAssignmentExpressionInheritIn()); +} +/** + * Private Parse API, parse AssignmentExpression + * - inherit in operator syntax transition action. + * - for more detail, please refer to `parseAssignmentExpressionAllowIn`. + * @returns {Expression} + */ +export function parseAssignmentExpressionInheritIn(this: Parser): Expression { + if ( + this.match([ + SyntaxKinds.ParenthesesLeftPunctuator, + SyntaxKinds.Identifier, + SyntaxKinds.LetKeyword, + SyntaxKinds.YieldKeyword, + SyntaxKinds.AwaitKeyword, + ]) + ) { + this.context.maybeArrowStart = this.getStartPosition().index; + } + if (this.match(SyntaxKinds.YieldKeyword) && this.isCurrentScopeParseYieldAsExpression()) { + return this.parseYieldExpression(); + } + if ( + !this.requirePlugin(ParserPlugin.JSX) && + this.requirePlugin(ParserPlugin.TypeScript) && + (this.match(SyntaxKinds.LtOperator) || this.match(SyntaxKinds.BitwiseLeftShiftOperator)) + ) { + const expr = this.parseTSGenericArrowFunctionExpression(); + if (expr) return expr; + } + const [leftExpr, scope] = this.parseWithCatpureLayer(() => this.parseConditionalExpression()); + if (!this.match(AssigmentOperators)) { + return leftExpr; + } + const left = this.exprToPattern(leftExpr, false); + this.checkStrictModeScopeError(scope); + const operator = this.getToken(); + if (operator !== SyntaxKinds.AssginOperator) { + this.checkExpressionAsLeftValue(left); + } + this.nextToken(); + const right = this.parseAssignmentExpressionInheritIn(); + return Factory.createAssignmentExpression( + left as Pattern, + right, + operator as AssigmentOperatorKinds, + cloneSourcePosition(left.start), + cloneSourcePosition(right.end), + ); +} +/** + * Helper function for any parse API that need to parse Arrow function. + * From production rule in `AssignmentExpression`, `ArrowFunctionExpression` and + * `AsyncArrowFunctionExpression` is same level of `ConditionalExpression`, but we + * parse ArrowFunction in the bottom of parse recursion(parsePrimary), so we should + * mark context there to make parseArrowFunction only parse when context is mark. + * @returns {boolean} + */ +export function canParseAsArrowFunction(this: Parser): boolean { + return this.getStartPosition().index === this.context.maybeArrowStart; +} +/** + * Parse Yield Expression, when current function scope is generator, yield would + * seems as keyword of yield expression, but even if in generator function scope, + * function parameter can call yield expression, so this function would check is + * current place is in function paramter or not. if yield expression shows in + * parameter list, it would throw error. + * ``` + * YieldExpression := 'yield' + * := 'yield' AssignmentExpression + * := 'yield' '*' AssignmentExpression + * ``` + * @returns {YieldExpression} + */ +export function parseYieldExpression(this: Parser): YieldExpression { + const { start } = this.expect(SyntaxKinds.YieldKeyword); + let delegate = false; + if (this.match(SyntaxKinds.MultiplyOperator)) { + if (!this.getLineTerminatorFlag()) { + this.nextToken(); + delegate = true; + } + } + const isLineDterminator = this.getLineTerminatorFlag(); + let argument: Expression | null = null; + if (!this.isSoftInsertSemi(false) && this.checkIsFollowByExpreesion()) { + if (delegate || (!delegate && !isLineDterminator)) { + argument = this.parseAssignmentExpressionInheritIn(); + } + } + if (delegate && !argument) { + this.raiseError( + ErrorMessageMap.extra_error_yield_deletgate_can_must_be_followed_by_assignment_expression, + this.getStartPosition(), + ); + } + if (this.isInParameter()) { + this.raiseError(ErrorMessageMap.extra_error_yield_expression_can_not_used_in_parameter_list, start); + } + this.recordScope(ExpressionScopeKind.YieldExpressionInParameter, start); + return Factory.createYieldExpression( + argument, + delegate, + start, + cloneSourcePosition(argument ? argument.end : start), + ); +} +export function checkIsFollowByExpreesion(this: Parser) { + switch (this.getToken()) { + case SyntaxKinds.ColonPunctuator: + case SyntaxKinds.ParenthesesRightPunctuator: + case SyntaxKinds.BracketRightPunctuator: + case SyntaxKinds.CommaToken: + return false; + default: + return true; + } +} +export function parseConditionalExpression(this: Parser): Expression { + const test = this.parseBinaryExpression(); + if (this.shouldEarlyReturn(test)) { + return test; + } + // for `arrow function` param, will first + if (!this.match(SyntaxKinds.QustionOperator)) { + return test; + } + if (this.requirePlugin(ParserPlugin.TypeScript)) { + const { kind } = this.lookahead(); + if (kind === SyntaxKinds.ColonPunctuator || kind === SyntaxKinds.ParenthesesRightPunctuator) { + return test; + } + } + this.nextToken(); + const conseq = this.parseAssignmentExpressionAllowIn(); + this.expect(SyntaxKinds.ColonPunctuator); + const alter = this.parseAssignmentExpressionInheritIn(); + return Factory.createConditionalExpression( + test, + conseq, + alter, + cloneSourcePosition(test.start), + cloneSourcePosition(alter.end), + ); +} +/** + * Private Parse Helper API for parse arrow function. + * @param {Expression} expr + * @returns + */ +export function shouldEarlyReturn(this: Parser, expr: Expression) { + return isArrowFunctionExpression(expr) && !expr.parentheses; +} +/** + * Using Operator-precedence parser algorithm is used for parse binary expressiom + * with precedence order. and this is entry function for parseBinaryExpression. + * @returns {Expression} + */ +export function parseBinaryExpression(this: Parser): Expression { + let atom = this.parseUnaryOrPrivateName(); + if (this.shouldEarlyReturn(atom)) { + return atom; + } + atom = this.parseBinaryOps(atom); + if (isPrivateName(atom)) { + this.raiseError(ErrorMessageMap.babel_error_private_name_wrong_used, atom.start); + } + return atom; +} +/** + * Return the precedence order by given binary operator. + * this function should only used by parseBinaryOps + * @param {SyntaxKinds} kind Binary Operator + * @returns {number} + */ +export function getBinaryPrecedence(this: Parser, kind: SyntaxKinds): number { + switch (kind) { + case SyntaxKinds.NullishOperator: + case SyntaxKinds.LogicalOROperator: + return 4; + case SyntaxKinds.LogicalANDOperator: + return 5; + case SyntaxKinds.BitwiseOROperator: + return 6; + case SyntaxKinds.BitwiseXOROperator: + return 7; + case SyntaxKinds.BitwiseANDOperator: + return 8; + case SyntaxKinds.StrictEqOperator: + case SyntaxKinds.StrictNotEqOperator: + case SyntaxKinds.EqOperator: + case SyntaxKinds.NotEqOperator: + return 9; + case SyntaxKinds.InKeyword: + case SyntaxKinds.InstanceofKeyword: + case SyntaxKinds.GtOperator: + case SyntaxKinds.GeqtOperator: + case SyntaxKinds.LeqtOperator: + case SyntaxKinds.LtOperator: + if (kind === SyntaxKinds.InKeyword && !this.getCurrentInOperatorStack()) { + return -1; + } + return 10; + case SyntaxKinds.BitwiseLeftShiftOperator: + case SyntaxKinds.BitwiseRightShiftOperator: + case SyntaxKinds.BitwiseRightShiftFillOperator: + return 11; + case SyntaxKinds.PlusOperator: + case SyntaxKinds.MinusOperator: + return 12; + case SyntaxKinds.ModOperator: + case SyntaxKinds.DivideOperator: + case SyntaxKinds.MultiplyOperator: + return 13; + case SyntaxKinds.ExponOperator: + return 14; + default: + return -1; + } +} +export function isBinaryOps(this: Parser, kind: SyntaxKinds) { + return this.getBinaryPrecedence(kind) > 0; +} +/** + * Bottom up recurive function for parse binary operator and next + * expression. + * @param {Expression} left + * @param {number} lastPre + * @returns {Expression} + */ +export function parseBinaryOps(this: Parser, left: Expression, lastPre: number = 0): Expression { + // eslint-disable-next-line no-constant-condition + while (1) { + // TS handle + if ( + this.requirePlugin(ParserPlugin.TypeScript) && + (this.isContextKeyword("as") || this.isContextKeyword("satisfies")) + ) { + const isSatisfies = this.isContextKeyword("satisfies"); + this.nextToken(); + const typeNode = this.parseTSTypeNode(); + if (isSatisfies) { + left = Factory.createTSSatisfiesExpression( + left, + typeNode, + cloneSourcePosition(left.start), + this.getLastTokenEndPositon(), + ); + } else { + left = Factory.createTSAsExpression( + left, + typeNode, + cloneSourcePosition(left.start), + this.getLastTokenEndPositon(), + ); + } + continue; + } + const currentOp = this.getToken(); + if (!this.isBinaryOps(currentOp) || this.getBinaryPrecedence(currentOp) < lastPre) { + break; + } + this.nextToken(); + let right = this.parseUnaryOrPrivateName(); + const nextOp = this.getToken(); + if (this.isBinaryOps(nextOp) && this.getBinaryPrecedence(nextOp) > this.getBinaryPrecedence(currentOp)) { + right = this.parseBinaryOps(right, this.getBinaryPrecedence(nextOp)); + } + this.staticSematicForBinaryExpr(currentOp, nextOp, left, right); + left = Factory.createBinaryExpression( + left, + right, + currentOp as BinaryOperatorKinds, + cloneSourcePosition(left.start), + cloneSourcePosition(right.end), + ); + } + return left; +} +export function staticSematicForBinaryExpr( + this: Parser, + currentOps: SyntaxKinds, + nextOps: SyntaxKinds, + left: Expression, + right: Expression, +) { + if (isPrivateName(right) || (isPrivateName(left) && currentOps !== SyntaxKinds.InKeyword)) { + // recoverable error + this.raiseError(ErrorMessageMap.babel_error_private_name_wrong_used, left.start); + } + if (left.parentheses) { + return; + } + if (currentOps === SyntaxKinds.ExponOperator) { + if (isUnaryExpression(left) || isAwaitExpression(left)) { + // recoverable error + this.raiseError(ErrorMessageMap.v8_error_expont_operator_need_parans, left.start); + } + } + // if currentOp is nullish, next is logical or not + // if current Ops is logical, check next is nullish or not + if ( + currentOps === SyntaxKinds.NullishOperator && + (nextOps === SyntaxKinds.LogicalANDOperator || nextOps === SyntaxKinds.LogicalOROperator) + ) { + // recoverable error + this.raiseError(ErrorMessageMap.v8_error_nullish_require_parans, left.end); + } + if ( + nextOps === SyntaxKinds.NullishOperator && + (currentOps === SyntaxKinds.LogicalANDOperator || currentOps === SyntaxKinds.LogicalOROperator) + ) { + // recoverable error + this.raiseError(ErrorMessageMap.v8_error_nullish_require_parans, left.end); + } +} +export function parseUnaryOrPrivateName(this: Parser): Expression { + if (this.match(SyntaxKinds.PrivateName)) { + const privateName = this.parsePrivateName(); + this.usePrivateName(privateName.name, privateName.start); + return privateName; + } + if ( + (this.match(SyntaxKinds.LtOperator) || this.match(SyntaxKinds.BitwiseLeftShiftOperator)) && + !this.requirePlugin(ParserPlugin.JSX) + ) { + const start = this.getStartPosition(); + const typeArguments = this.parseTSTypeParameterInstantiation(false); + const expression = this.parseUnaryExpression(); + return Factory.createTSTypeAssertionExpression( + expression, + typeArguments.params[0], + start, + this.getLastTokenEndPositon(), + ); + } + return this.parseUnaryExpression(); +} +export function parseUnaryExpression(this: Parser): Expression { + if (this.match(UnaryOperators)) { + const operator = this.getToken() as UnaryOperatorKinds; + const isDelete = operator === SyntaxKinds.DeleteKeyword; + const start = this.getStartPosition(); + this.nextToken(); + let argument; + if (isDelete) { + this.enterDelete(); + argument = this.parseUnaryExpression(); + this.exitDelete(); + } else { + argument = this.parseUnaryExpression(); + } + const unaryExpr = Factory.createUnaryExpression( + argument, + operator, + start, + cloneSourcePosition(argument.end), + ); + this.staticSematicEarlyErrorForUnaryExpression(unaryExpr); + return unaryExpr; + } + if (this.match(SyntaxKinds.AwaitKeyword) && this.isCurrentScopeParseAwaitAsExpression()) { + return this.parseAwaitExpression(); + } + return this.parseUpdateExpression(); +} +// 13.5.1.1 +export function staticSematicEarlyErrorForUnaryExpression(this: Parser, expr: UnaryExpression) { + if (this.isInStrictMode() && expr.operator === SyntaxKinds.DeleteKeyword && isIdentifer(expr.argument)) { + this.raiseError( + ErrorMessageMap.syntax_error_applying_the_delete_operator_to_an_unqualified_name_is_deprecated, + expr.start, + ); + } +} +export function parseAwaitExpression(this: Parser) { + if (this.isInParameter()) { + this.raiseError( + ErrorMessageMap.extra_error_await_expression_can_not_used_in_parameter_list, + this.getStartPosition(), + ); + } + const start = this.getStartPosition(); + this.nextToken(); + this.recordScope(ExpressionScopeKind.AwaitExpressionImParameter, start); + const argu = this.parseUnaryExpression(); + return Factory.createAwaitExpression(argu, start, cloneSourcePosition(argu.end)); +} +export function parseUpdateExpression(this: Parser): Expression { + if (this.match(UpdateOperators)) { + const operator = this.getToken() as UpdateOperatorKinds; + const start = this.getStartPosition(); + this.nextToken(); + const argument = this.parseWithLHSLayer(() => this.parseLeftHandSideExpression()); + this.checkExpressionAsLeftValue(argument); + return Factory.createUpdateExpression(argument, operator, true, start, cloneSourcePosition(argument.end)); + } + const [argument, scope] = this.parseWithCatpureLayer(() => this.parseLeftHandSideExpression()); + if (this.match(UpdateOperators) && !this.getLineTerminatorFlag()) { + this.checkStrictModeScopeError(scope); + this.checkExpressionAsLeftValue(argument); + const operator = this.getToken() as UpdateOperatorKinds; + const end = this.getEndPosition(); + this.nextToken(); + return Factory.createUpdateExpression( + argument, + operator, + false, + cloneSourcePosition(argument.start), + end, + ); + } + return argument; +} +/** + * Parse Left hand side Expression. This syntax is reference babel function, which is simplify original syntax of TS39, + * 'this' and super 'super' would be meanful when apper at start of atoms, which can be handle by parseAtoms. NewExpression + * is a spacial case , because it can not using optionalChain, so i handle it into a atom. + * ``` + * LeftHandSideExpression := Atoms '?.' CallExpression + * := Atoms '?.' MemberExpression + * := Atoms TagTemplateExpression + * ``` + * @returns {Expression} + */ +export function parseLeftHandSideExpression(this: Parser): Expression { + let base = this.parsePrimaryExpression(); + if (this.shouldEarlyReturn(base)) { + return base; + } + const state: LefthansSideParseState = { + shouldStop: false, + hasOptional: false, + optional: false, + abortLastTime: false, + }; + while (!state.shouldStop) { + state.optional = false; + if ( + this.requirePlugin(ParserPlugin.TypeScript) && + !this.getLineTerminatorFlag() && + this.match(SyntaxKinds.LogicalNOTOperator) + ) { + this.nextToken(); + base = Factory.createTSNonNullExpression( + base, + cloneSourcePosition(base.start), + this.getLastTokenEndPositon(), + ); + continue; + } + if (state.abortLastTime) { + base = this.parseLeftHandSideExpressionWithoutTypeArguments(base, state); + } else { + base = this.parseLeftHandSideExpressionWithTypeArguments(base, state); + } + } + if (state.abortLastTime && state.hasOptional) { + throw this.createUnexpectError(); + } + if (state.hasOptional) { + return Factory.createChainExpression( + base, + cloneSourcePosition(base.start), + cloneSourcePosition(base.end), + ); + } + return base; +} +export function parseLeftHandSideExpressionWithTypeArguments( + this: Parser, + base: Expression, + state: LefthansSideParseState, +) { + this.parseQuestionDotOfLeftHandSideExpression(state); + const result = this.parseTypeArgumentsOfLeftHandSideExpression(state); + const [typeArguments, abort] = result; + if (this.match(SyntaxKinds.ParenthesesLeftPunctuator)) { + // callexpression + base = this.parseCallExpression(base, state.optional, typeArguments); + } else if (this.match([SyntaxKinds.DotOperator, SyntaxKinds.BracketLeftPunctuator]) || state.optional) { + // memberexpression + if (typeArguments) { + abort(); + } else { + base = this.parseMemberExpression(base, state.optional); + } + } else if (this.match(SyntaxKinds.TemplateHead) || this.match(SyntaxKinds.TemplateNoSubstitution)) { + // tag template expressuin + if (state.hasOptional) { + // recoverable error + this.raiseError( + ErrorMessageMap.syntax_error_tag_template_expression_can_not_use_option_chain, + this.getStartPosition(), + ); + } + base = this.parseTagTemplateExpression(base); + } else { + if (typeArguments) { + const currentToken = this.getToken(); + if ( + currentToken === SyntaxKinds.GtOperator || + currentToken === SyntaxKinds.BitwiseRightShiftOperator || + (currentToken !== SyntaxKinds.ParenthesesLeftPunctuator && + this.canStartExpression() && + !this.getLineTerminatorFlag()) + ) { + abort(); + } else { + // base == TSInstanitExpr + base = Factory.createTSInstantiationExpression( + base, + typeArguments, + cloneSourcePosition(base.start), + this.getLastTokenEndPositon(), + ); + if ( + this.match(SyntaxKinds.DotOperator) || + (this.match(SyntaxKinds.QustionDotOperator) && + this.lookahead().kind !== SyntaxKinds.ParenthesesLeftPunctuator) + ) { + // TODO: should error + } + } + } else { + state.shouldStop = true; + } + } + return base; +} +export function parseLeftHandSideExpressionWithoutTypeArguments( + this: Parser, + base: Expression, + state: LefthansSideParseState, +) { + this.parseQuestionDotOfLeftHandSideExpression(state); + if (this.match(SyntaxKinds.ParenthesesLeftPunctuator)) { + // callexpression + state.abortLastTime = false; + base = this.parseCallExpression(base, state.optional, undefined); + } else if (this.match([SyntaxKinds.DotOperator, SyntaxKinds.BracketLeftPunctuator]) || state.optional) { + // memberexpression + state.abortLastTime = false; + base = this.parseMemberExpression(base, state.optional); + } else if (this.match(SyntaxKinds.TemplateHead) || this.match(SyntaxKinds.TemplateNoSubstitution)) { + // tag template expressuin + if (state.hasOptional) { + // recoverable error + this.raiseError( + ErrorMessageMap.syntax_error_tag_template_expression_can_not_use_option_chain, + this.getStartPosition(), + ); + } + state.abortLastTime = false; + base = this.parseTagTemplateExpression(base); + } else { + state.shouldStop = true; + } + return base; +} +export function parseQuestionDotOfLeftHandSideExpression(this: Parser, state: LefthansSideParseState) { + if (this.match(SyntaxKinds.QustionDotOperator)) { + state.optional = true; + state.hasOptional = true; + this.nextToken(); + } +} +export function parseTypeArgumentsOfLeftHandSideExpression( + this: Parser, + state: LefthansSideParseState, +): [TSTypeParameterInstantiation | undefined, () => void] { + let typeArguments: TSTypeParameterInstantiation | undefined = undefined; + let abort = () => {}; + if (this.match(SyntaxKinds.LtOperator) || this.match(SyntaxKinds.BitwiseLeftShiftOperator)) { + const result = this.tryParse(() => { + return this.tryParseTSTypeParameterInstantiation(false); + }); + if (result) { + typeArguments = result?.[0]; + abort = () => { + this.lexer.restoreState(result[1], result[2]); + this.errorHandler.restoreTryFail(result[3]); + state.abortLastTime = true; + }; + return [typeArguments, abort]; + } + //return undefined; + } + return [typeArguments, abort]; +} +/** + * Check is a assignable left value + * @param expression + * @returns + */ +export function checkExpressionAsLeftValue(this: Parser, expression: ModuleItem) { + if (this.isAssignable(expression)) { + return; + } + this.raiseError(ErrorMessageMap.invalid_left_value, expression.start); +} +/** + * Parse CallExpression + * ``` + * CallExpresion := GivenBase(base, optional) '(' Arguments ')' + * ``` + * @param {Expression} callee base expression + * @param {boolean} optional is this call optional ? + * @returns {Expression} + */ +export function parseCallExpression( + this: Parser, + callee: Expression, + optional: boolean, + typeParameter: TSTypeParameterInstantiation | undefined, +): Expression { + this.expectButNotEat([SyntaxKinds.ParenthesesLeftPunctuator]); + const { nodes, end } = this.parseArguments(); + return Factory.createCallExpression( + callee, + nodes, + typeParameter, + optional, + cloneSourcePosition(callee.start), + end, + ); +} +/** + * // TODO: remove possble dep of arrow function paramemter need to call this function. + * + * Parse Arguments, used by call expression, and arrow function paramemter. + * ``` + * Arguments := '(' ArgumentList ')' + * ArgumentList := ArgumentList AssigmentExpression + * := ArgumentList SpreadElement + * := AssignmentExpression + * := SpreadElement + * ``` + */ +export function parseArguments(this: Parser) { + return this.parseArgumentsBase(false); +} +export function parseArgumentsWithType(this: Parser) { + return this.parseArgumentsBase(true); +} +export function parseArgumentsBase( + this: Parser, + acceptType: boolean, +): ASTArrayWithMetaData & { + trailingComma: boolean; + typeAnnotations: Array<[TSTypeAnnotation | undefined, boolean]> | undefined; +} { + const { start } = this.expect(SyntaxKinds.ParenthesesLeftPunctuator); + let isStart = true; + // TODO: refactor logic to remove shoulStop + const callerArguments: Array = []; + const typeAnnotations: Array<[TSTypeAnnotation | undefined, boolean]> = []; + let trailingComma = false; + while (!this.match(SyntaxKinds.ParenthesesRightPunctuator) && !this.match(SyntaxKinds.EOFToken)) { + if (isStart) { + isStart = false; + if (this.match(SyntaxKinds.CommaToken)) { + // trailing comma + this.raiseError(ErrorMessageMap.extra_error_unexpect_trailing_comma, this.getStartPosition()); + this.nextToken(); + } + } else { + trailingComma = true; + this.expect(SyntaxKinds.CommaToken); + } + // case 1: ',' following by ')' + if (this.match(SyntaxKinds.ParenthesesRightPunctuator)) { + break; + } + trailingComma = false; + // case 2: ',' following by SpreadElement, maybe follwed by ',' + if (this.match(SyntaxKinds.SpreadOperator)) { + const spreadElementStart = this.getStartPosition(); + this.nextToken(); + let argu: Expression = Factory.createSpreadElement( + this.parseAssignmentExpressionAllowIn(), + spreadElementStart, + this.getLastTokenEndPositon(), + ); + if (acceptType) { + typeAnnotations.push(this.parsePossibleArugmentType()); + argu = this.parsePossibleArugmentDefaultValue(argu); + } + callerArguments.push(argu); + continue; + } + // case 3 : ',' AssigmentExpression + let argu = this.parseAssignmentExpressionAllowIn(); + if (acceptType) { + typeAnnotations.push(this.parsePossibleArugmentType()); + argu = this.parsePossibleArugmentDefaultValue(argu); + } + callerArguments.push(argu); + } + const { end } = this.expect(SyntaxKinds.ParenthesesRightPunctuator); + return { + end, + start, + nodes: callerArguments, + typeAnnotations: typeAnnotations.length === 0 ? undefined : typeAnnotations, + trailingComma, + }; +} + +/** + * Parse with base, this different between parseLeftHandSideExpression is + * that parseMemberExpression would only eat a `atom` of chain of expression. + * ``` + * MemberExpression := GivenBase(base ,optional) '.' IdentiferWithKeyword + * := GivenBase(base, optional) '[' Expreession ']' + * := GivenBase(base, optional) IdentiferWithKeyword + * // for last condition, optional prope must be True + * ``` + * @param {Expression} base base expression + * @param {boolean} optional is base expression contain a optional + * @returns {Expression} + */ +export function parseMemberExpression(this: Parser, base: Expression, optional: boolean): Expression { + if (!this.match(SyntaxKinds.DotOperator) && !this.match(SyntaxKinds.BracketLeftPunctuator) && !optional) { + throw this.createUnreachError([SyntaxKinds.DotOperator, SyntaxKinds.BracketLeftPunctuator]); + } + // if start with dot, must be a access property, can not with optional. + // because optional means that last token is `?.` + if (this.match(SyntaxKinds.DotOperator) && !optional) { + this.expect(SyntaxKinds.DotOperator); + const property = this.parseMemberExpressionProperty(); + + return Factory.createMemberExpression( + false, + base, + property, + optional, + cloneSourcePosition(base.start), + cloneSourcePosition(property.end), + ); + } + // if start with `[`, must be computed property access. + else if (this.match(SyntaxKinds.BracketLeftPunctuator)) { + this.expect(SyntaxKinds.BracketLeftPunctuator); + const property = this.parseExpressionAllowIn(); + const { end } = this.expect(SyntaxKinds.BracketRightPunctuator); + return Factory.createMemberExpression( + true, + base, + property, + optional, + cloneSourcePosition(base.start), + end, + ); + } else { + // because parseLeftHandSideExpression would eat optional mark (QustionDotToken) frist, so maybe there + // is not dot or `[` for start a member expression, so we can check optional is + const property = this.parseMemberExpressionProperty(); + return Factory.createMemberExpression( + false, + base, + property, + optional, + cloneSourcePosition(base.start), + cloneSourcePosition(property.end), + ); + } +} +export function parseMemberExpressionProperty(this: Parser) { + let property: Expression | PrivateName; + if (this.match(SyntaxKinds.PrivateName)) { + property = this.parsePrivateName(); + this.usePrivateName(property.name, property.start); + if (this.isInDelete()) { + this.raiseError( + ErrorMessageMap.syntax_error_applying_the_delete_operator_to_an_unqualified_name_is_deprecated, + property.start, + ); + } + } else { + property = this.parseIdentifierName(); + } + return property; +} +export function parseTagTemplateExpression(this: Parser, base: Expression) { + const quasi = this.parseTemplateLiteral(true); + return Factory.createTagTemplateExpression( + base, + quasi, + cloneSourcePosition(base.end), + cloneSourcePosition(quasi.end), + ); +} +export function parsePrimaryExpression(this: Parser): Expression { + switch (this.getToken()) { + case SyntaxKinds.LtOperator: + return this.parseJSXElementOrJSXFragment(false); + case SyntaxKinds.DivideOperator: + case SyntaxKinds.DivideAssignOperator: + return this.parseRegexLiteral(); + case SyntaxKinds.NullKeyword: + return this.parseNullLiteral(); + case SyntaxKinds.UndefinedKeyword: + return this.parseUndefinedLiteral(); + case SyntaxKinds.TrueKeyword: + case SyntaxKinds.FalseKeyword: + return this.parseBoolLiteral(); + case SyntaxKinds.DecimalLiteral: + return this.parseDecimalLiteral(); + case SyntaxKinds.DecimalBigIntegerLiteral: + return this.parseDecimalBigIntegerLiteral(); + case SyntaxKinds.NonOctalDecimalLiteral: + return this.parseNonOctalDecimalLiteral(); + case SyntaxKinds.BinaryIntegerLiteral: + return this.parseBinaryIntegerLiteral(); + case SyntaxKinds.BinaryBigIntegerLiteral: + return this.parseBinaryBigIntegerLiteral(); + case SyntaxKinds.OctalIntegerLiteral: + return this.parseOctalIntegerLiteral(); + case SyntaxKinds.OctalBigIntegerLiteral: + return this.parseOctalBigIntegerLiteral(); + case SyntaxKinds.HexIntegerLiteral: + return this.parseHexIntegerLiteral(); + case SyntaxKinds.HexBigIntegerLiteral: + return this.parseHexBigIntegerLiteral(); + case SyntaxKinds.LegacyOctalIntegerLiteral: + return this.parseLegacyOctalIntegerLiteral(); + case SyntaxKinds.StringLiteral: + return this.parseStringLiteral(); + case SyntaxKinds.TemplateHead: + case SyntaxKinds.TemplateNoSubstitution: + return this.parseTemplateLiteral(false); + case SyntaxKinds.ImportKeyword: { + const { kind } = this.lookahead(); + if (kind === SyntaxKinds.DotOperator) return this.parseImportMeta(); + if (kind === SyntaxKinds.ParenthesesLeftPunctuator) { + return this.parseImportCall(); + } + throw this.createUnexpectError(); + } + case SyntaxKinds.NewKeyword: { + const { kind } = this.lookahead(); + if (kind === SyntaxKinds.DotOperator) { + return this.parseNewTarget(); + } + return this.parseNewExpression(); + } + case SyntaxKinds.SuperKeyword: + return this.parseSuper(); + case SyntaxKinds.ThisKeyword: + return this.parseThisExpression(); + case SyntaxKinds.BracesLeftPunctuator: + return this.parseObjectExpression(); + case SyntaxKinds.BracketLeftPunctuator: + return this.parseArrayExpression(); + case SyntaxKinds.FunctionKeyword: + return this.parseFunctionExpression(false); + case SyntaxKinds.AtPunctuator: { + return this.parseClassExpression(this.parseDecoratorList()); + } + case SyntaxKinds.ClassKeyword: + return this.parseClassExpression(null); + case SyntaxKinds.ParenthesesLeftPunctuator: + return this.parseCoverExpressionORArrowFunction(); + // TODO: consider wrap as function or default case ? + case SyntaxKinds.PrivateName: + // recoverable error + this.raiseError(ErrorMessageMap.babel_error_private_name_wrong_used, this.getStartPosition()); + return this.parsePrivateName(); + // return parsePrivateName(); + case SyntaxKinds.Identifier: + case SyntaxKinds.LetKeyword: + case SyntaxKinds.AwaitKeyword: + case SyntaxKinds.YieldKeyword: { + const { kind, lineTerminatorFlag: flag } = this.lookahead(); + // case 0: identifier `=>` ... + if (kind === SyntaxKinds.ArrowOperator && this.canParseAsArrowFunction()) { + const [[argus, strictModeScope], arrowExprScope] = this.parseWithArrowExpressionScope(() => + this.parseWithLHSLayerReturnScope(() => [this.parseIdentifierReference()]), + ); + if (this.getLineTerminatorFlag()) { + this.raiseError( + ErrorMessageMap.extra_error_no_line_break_is_allowed_before_arrow, + this.getStartPosition(), + ); + } + this.enterArrowFunctionBodyScope(); + const arrowExpr = this.parseArrowFunctionExpression( + { + nodes: argus, + start: argus[0].start, + end: argus[0].end, + trailingComma: false, + typeAnnotations: undefined, + }, + undefined, + strictModeScope, + arrowExprScope, + ); + this.exitArrowFunctionBodyScope(); + return arrowExpr; + } + if (this.getSourceValue() === "async") { + // case 1: `async` `function` ==> must be async function () {} + if (kind === SyntaxKinds.FunctionKeyword && !this.getEscFlag()) { + const { value, start, end } = this.expect(SyntaxKinds.Identifier); + if (this.getLineTerminatorFlag()) { + return Factory.createIdentifier(value, start, end, undefined, undefined); + } + return this.parseFunctionExpression(true); + } + if (this.canParseAsArrowFunction()) { + // case 2 `async` `(` + // There might be two case : + // 1.frist case is there are line change after async, which make this case into + // call expression + // 2.second case is not change line after async, making it become async arrow + // function. + // -------------------------- + if (kind === SyntaxKinds.ParenthesesLeftPunctuator) { + const containEsc = this.getEscFlag(); + const id = this.parseIdentifierReference(); // async + // TODO: better accept type param or argument to create async arrow or async call. + const [[meta, strictModeScope], arrowExprScope] = this.parseWithArrowExpressionScope(() => + this.parseWithCatpureLayer(() => this.parseArgumentsWithType()), + ); + if ( + flag || + (!this.match(SyntaxKinds.ArrowOperator) && + !(this.match(SyntaxKinds.ColonPunctuator) && this.requirePlugin(ParserPlugin.TypeScript))) + ) { + return Factory.createCallExpression( + id, + meta.nodes, + undefined, + false, + cloneSourcePosition(id.start), + meta.end, + ); + } + if (containEsc) { + this.raiseError(ErrorMessageMap.invalid_esc_char_in_keyword, id.start); + } + const returnType = this.tryParseTSReturnTypeOrTypePredicate(SyntaxKinds.ColonPunctuator); + this.enterArrowFunctionBodyScope(true); + const arrowFunExpr = this.parseArrowFunctionExpression( + meta, + undefined, + strictModeScope, + arrowExprScope, + ); + this.exitArrowFunctionBodyScope(); + arrowFunExpr.returnType = returnType; + return arrowFunExpr; + } + // case 2-TS: `async` `<` or async `<<` + // for `<`, is possible to be a + // - typeParameter: for a async function declaration + // - typeArguments: for a function call which callee is `async` + // - binary expression: `async < literal-item`. + if (kind === SyntaxKinds.LtOperator) { + const id = this.parseIdentifierReference(); + const typeParameterResult = this.tryParse(() => this.parseTSTypeParameterDeclaration(false)); + if (typeParameterResult) { + // there + const [ + [{ start, end, nodes, trailingComma, typeAnnotations }, strictModeScope], + arrowExprScope, + ] = this.parseWithArrowExpressionScope(() => + this.parseWithCatpureLayer(() => this.parseArgumentsWithType()), + ); + const returnType = this.tryParseTSReturnTypeOrTypePredicateForArrowExpression(true, nodes); + if (this.match(SyntaxKinds.ArrowOperator)) { + this.enterArrowFunctionBodyScope(true); + const arrowExpr = this.parseArrowFunctionExpression( + { start, end, nodes, trailingComma, typeAnnotations }, + undefined, + strictModeScope, + arrowExprScope, + ); + this.exitArrowFunctionBodyScope(); + arrowExpr.returnType = returnType; + arrowExpr.typeParameters = typeParameterResult[0]; + return arrowExpr; + } + this.abortTryParseResult( + typeParameterResult[1], + typeParameterResult[2], + typeParameterResult[3], + ); + } + const typeArgumentResult = this.tryParse(() => this.parseTSTypeParameterInstantiation(false)); + if (typeArgumentResult) { + const typeArguments = typeArgumentResult[0]; + const callArguments = this.parseArguments().nodes; + return Factory.createCallExpression( + id, + callArguments, + typeArguments, + false, + cloneSourcePosition(id.start), + this.getLastTokenEndPositon(), + ); + } + return id; + } + // for '<<', it must be `async< async as function call + if (kind === SyntaxKinds.BitwiseLeftShiftOperator) { + const id = this.parseIdentifierReference(); + this.lexer.reLexLtRelateToken(); + const typeArguments = this.parseTSTypeParameterInstantiation(false); + const callArguments = this.parseArguments().nodes; + return Factory.createCallExpression( + id, + callArguments, + typeArguments, + false, + cloneSourcePosition(id.start), + this.getLastTokenEndPositon(), + ); + } + // case 3: `async` `Identifer` ... + // There might be two case : + // 1.frist case is there are line change after async, or there is no arrow operator, + // which make this case into async as identifier + // 2.second case is not change line after async, making it become async arrow + // function. + if ( + kind === SyntaxKinds.Identifier || + kind === SyntaxKinds.YieldKeyword || + kind === SyntaxKinds.AwaitKeyword + ) { + // async followed by line break + if (flag) { + return this.parseIdentifierReference(); + } + const isAsyncContainUnicode = this.getEscFlag(); + const { start, end } = this.expect(SyntaxKinds.Identifier); // eat async + const { kind: maybeArrowToken } = this.lookahead(); + // there is no arrow operator. + if (maybeArrowToken !== SyntaxKinds.ArrowOperator) { + return Factory.createIdentifier("async", start, end, undefined, undefined); + } + if (isAsyncContainUnicode) { + this.raiseError(ErrorMessageMap.invalid_esc_char_in_keyword, start); + } + const [[argus, strictModeScope], arrowExprScope] = this.parseWithArrowExpressionScope(() => + this.parseWithCatpureLayer(() => [this.parseIdentifierReference()]), + ); + if (this.getLineTerminatorFlag()) { + this.raiseError( + ErrorMessageMap.extra_error_no_line_break_is_allowed_before_arrow, + this.getStartPosition(), + ); + } + this.enterArrowFunctionBodyScope(true); + const arrowExpr = this.parseArrowFunctionExpression( + { + nodes: argus, + start: argus[0].start, + end: argus[0].end, + trailingComma: false, + typeAnnotations: undefined, + }, + undefined, + strictModeScope, + arrowExprScope, + ); + this.exitArrowFunctionBodyScope(); + return arrowExpr; + } + } + } + return this.parseIdentifierReference(); + } + default: + throw this.createUnexpectError(); + } +} diff --git a/web-infras/parser/src/parser/js/index.ts b/web-infras/parser/src/parser/js/index.ts new file mode 100644 index 00000000..20f44b3a --- /dev/null +++ b/web-infras/parser/src/parser/js/index.ts @@ -0,0 +1,6 @@ +export * from "./expression"; +export * from "./literal"; +export * from "./pattern"; +export * from "./declaration"; +export * from "./statement"; +export * from "./module"; diff --git a/web-infras/parser/src/parser/js/literal.ts b/web-infras/parser/src/parser/js/literal.ts new file mode 100644 index 00000000..1533df0a --- /dev/null +++ b/web-infras/parser/src/parser/js/literal.ts @@ -0,0 +1,1587 @@ +import { + RegexLiteral, + SyntaxKinds, + Factory, + Identifier, + SourcePosition, + PrivateName, + NumberLiteral, + TemplateElement, + MetaProperty, + cloneSourcePosition, + CallExpression, + Expression, + isCallExpression, + ThisExpression, + PropertyName, + isIdentifer, + isStringLiteral, + ObjectMethodDefinition, + ModuleItem, + NumericLiteralKinds, + isNumnerLiteral, + Decorator, + ClassMethodDefinition, + ObjectAccessor, + ClassAccessor, + ClassConstructor, + MethodDefinition, + Keywords, + Pattern, + isRestElement, + isPrivateName, + isSpreadElement, + ArrorFunctionExpression, + PropertyDefinition, + FunctionBody, + TSParameter, + TSTypeAnnotation, + isAssignmentPattern, +} from "web-infra-common"; +import { ParserPlugin } from "@/src/parser/config"; +import { ErrorMessageMap } from "@/src/parser/error"; +import { ExpressionScopeKind } from "@/src/parser/scope/type"; +import { Parser } from ".."; +import { StrictModeScope } from "@/src/parser/scope/strictModeScope"; +import { AsyncArrowExpressionScope } from "@/src/parser/scope/arrowExprScope"; +import { + ASTArrayWithMetaData, + IdentiferWithKeyworArray, + PreserveWordSet, + KeywordSet, +} from "@/src/parser/type"; + +export function parseRegexLiteral(this: Parser): RegexLiteral { + this.expectButNotEat([SyntaxKinds.DivideOperator, SyntaxKinds.DivideAssignOperator]); + const startWithAssignOperator = this.match(SyntaxKinds.DivideAssignOperator); + const start = this.getStartPosition(); + // eslint-disable-next-line prefer-const + let { pattern, flag } = this.readRegex(); + this.nextToken(); + if (startWithAssignOperator) { + pattern = "=" + pattern; + } + return Factory.createRegexLiteral(pattern, flag, start, this.getEndPosition()); +} +/** + * IdentifierReference, IdentifierName and BindingIdentifier is not samething in the + * spec. + * - IdentifierReference is a id in Lval or Rval + * - IdentifierName is a property of member expression or object, class + * - BindingIdentifier is a lval. + * @returns {Identifier} + */ +export function parseIdentifierReference(this: Parser): Identifier { + this.expectButNotEat([ + SyntaxKinds.Identifier, + SyntaxKinds.AwaitKeyword, + SyntaxKinds.YieldKeyword, + SyntaxKinds.LetKeyword, + ]); + // sematic check for a binding identifier + let identifer: Identifier; + switch (this.getToken()) { + // for most of yield keyword, if it should treat as identifier, + // it should not in generator function. + case SyntaxKinds.YieldKeyword: { + const { value, start, end } = this.expect(SyntaxKinds.YieldKeyword); + this.staticSematicForIdentifierAsYield(start); + identifer = Factory.createIdentifier(value, start, end, undefined, undefined); + break; + } + // for most of await keyword, if it should treat as identifier, + // it should not in async function. + case SyntaxKinds.AwaitKeyword: { + const { value, start, end } = this.expect(SyntaxKinds.AwaitKeyword); + this.staticSematicForIdentifierAsAwait(start); + identifer = Factory.createIdentifier(value, start, end, undefined, undefined); + break; + } + // let maybe treat as identifier in not strict mode, and not lexical binding declaration. + // so lexical binding declaration should implement it's own checker logical with parseIdentifierWithKeyword + case SyntaxKinds.LetKeyword: { + const { value, start, end } = this.expect(SyntaxKinds.LetKeyword); + this.staticSematicForIdentifierAsLet(start); + identifer = Factory.createIdentifier(value, start, end, undefined, undefined); + break; + } + case SyntaxKinds.Identifier: { + const { value, start, end } = this.expect(SyntaxKinds.Identifier); + this.staticSematicForIdentifierDefault(value, start); + identifer = Factory.createIdentifier(value, start, end, undefined, undefined); + break; + } + default: { + throw this.createUnexpectError(); + } + } + return identifer; +} +/** + * Yield only could be used as a identifier when + * + * - it is not in strict mode. + * - not in a generator context. + * + * record it's usage for defer check. + * @param {SourcePosition} start + */ +export function staticSematicForIdentifierAsYield(this: Parser, start: SourcePosition) { + if (this.isCurrentScopeParseYieldAsExpression() || this.isInStrictMode()) { + this.raiseError(ErrorMessageMap.babel_error_invalid_yield, start); + } + this.recordScope(ExpressionScopeKind.YieldIdentifier, start); +} +/** + * Await only could be used as identifirt when + * + * - it is not in module mode + * - not in async context + * + * record it's usgae for defer check. + * @param {SourcePosition} start + */ +export function staticSematicForIdentifierAsAwait(this: Parser, start: SourcePosition) { + if (this.isCurrentScopeParseAwaitAsExpression() || this.config.sourceType === "module") { + this.raiseError( + ErrorMessageMap.babel_error_can_not_use_await_as_identifier_inside_an_async_function, + start, + ); + } + // skip if is using await in class property name in async context + if (this.isDirectToClassScope() && !this.isInPropertyName()) { + return; + } + this.recordScope(ExpressionScopeKind.AwaitIdentifier, start); +} +/** + * Let only could be used as identifirt when + * + * - it is not in strict mode + * + * record it's usgae for defer check. + * @param {SourcePosition} start + */ +export function staticSematicForIdentifierAsLet(this: Parser, start: SourcePosition) { + if (this.isInStrictMode()) { + this.raiseError(ErrorMessageMap.unexpect_keyword_in_stric_mode, start); + } + this.recordScope(ExpressionScopeKind.LetIdentifiier, start); +} +/** + * Checking the usage for arguments and eval, presverveword + * + * - for presverveword, only could be used when not in strict mode + * - for argument, can not used when + * 1. in strict mode, and in the lhs + * 2. in strict mode, not in function. + * - for eval, can not used when + * 1. in strict mode, and in the lhs + * + * record it's usgae for defer check. + * @param {SourcePosition} start + */ +export function staticSematicForIdentifierDefault(this: Parser, value: string, start: SourcePosition) { + const isPreserveWord = PreserveWordSet.has(value); + if (isPreserveWord) { + if (this.isInStrictMode()) { + this.raiseError(ErrorMessageMap.unexpect_keyword_in_stric_mode, start); + } + this.recordScope(ExpressionScopeKind.PresveredWordIdentifier, start); + } + if (value === "arguments") { + if (this.isInStrictMode()) { + if (!this.isEncloseInFunction() && !this.isInPropertyName()) { + // invalud usage + this.raiseError(ErrorMessageMap.syntax_error_arguments_is_not_valid_in_fields, start); + } + if (this.strictModeScopeRecorder.isInLHS()) { + // invalid assignment + this.raiseError(ErrorMessageMap.unexpect_keyword_in_stric_mode, start); + } + } + this.recordScope(ExpressionScopeKind.ArgumentsIdentifier, start); + } + if (value === "eval") { + if (this.isInStrictMode() && this.strictModeScopeRecorder.isInLHS()) { + this.raiseError(ErrorMessageMap.unexpect_keyword_in_stric_mode, start); + } + this.recordScope(ExpressionScopeKind.EvalIdentifier, start); + } +} +/** + * Relatedly loose function for parseIdentifier, it not only can parse identifier, + * it also can parse keyword as identifier. + * @returns {Identifier} + */ +export function parseIdentifierName(this: Parser): Identifier { + const { value, start, end } = this.expect(IdentiferWithKeyworArray); + return Factory.createIdentifier(value, start, end, undefined, undefined); +} +/** + * ECMA spec has every strict rule to private name, but in this parser, most of + * strict rule check is implemented by callee, there we only gonna check is in + * class scope or not. + * @returns {PrivateName} + */ +export function parsePrivateName(this: Parser): PrivateName { + const { value, start, end } = this.expect(SyntaxKinds.PrivateName); + if (!this.isInClassScope()) { + this.raiseError(ErrorMessageMap.syntax_error_unexpected_hash_used_outside_of_class_body, start); // semantics check for private + } + return Factory.createPrivateName(value, start, end); +} +export function parseNullLiteral(this: Parser) { + const { start, end } = this.expect(SyntaxKinds.NullKeyword); + return Factory.createNullLiteral(start, end); +} +export function parseUndefinedLiteral(this: Parser) { + const { start, end } = this.expect(SyntaxKinds.UndefinedKeyword); + return Factory.createUndefinedLiteral(start, end); +} +export function parseDecimalLiteral(this: Parser) { + const { start, end, value } = this.expect(SyntaxKinds.DecimalLiteral); + return Factory.createDecimalLiteral(value, start, end); +} +export function parseDecimalBigIntegerLiteral(this: Parser) { + const { start, end, value } = this.expect(SyntaxKinds.DecimalBigIntegerLiteral); + return Factory.createDecimalBigIntegerLiteral(value, start, end); +} +export function parseNonOctalDecimalLiteral(this: Parser) { + const { start, end, value } = this.expect(SyntaxKinds.NonOctalDecimalLiteral); + if (this.isInStrictMode()) { + this.raiseError(ErrorMessageMap.Syntax_error_0_prefixed_octal_literals_are_deprecated, start); + } + return Factory.createNonOctalDecimalLiteral(value, start, end); +} +export function parseBinaryIntegerLiteral(this: Parser) { + const { start, end, value } = this.expect(SyntaxKinds.BinaryIntegerLiteral); + return Factory.createBinaryIntegerLiteral(value, start, end); +} +export function parseBinaryBigIntegerLiteral(this: Parser) { + const { start, end, value } = this.expect(SyntaxKinds.BinaryBigIntegerLiteral); + return Factory.createBinaryBigIntegerLiteral(value, start, end); +} +export function parseOctalIntegerLiteral(this: Parser) { + const { start, end, value } = this.expect(SyntaxKinds.OctalIntegerLiteral); + return Factory.createOctalIntegerLiteral(value, start, end); +} +export function parseOctalBigIntegerLiteral(this: Parser) { + const { start, end, value } = this.expect(SyntaxKinds.OctalBigIntegerLiteral); + return Factory.createOctBigIntegerLiteral(value, start, end); +} +export function parseHexIntegerLiteral(this: Parser) { + const { start, end, value } = this.expect(SyntaxKinds.HexIntegerLiteral); + return Factory.createHexIntegerLiteral(value, start, end); +} +export function parseHexBigIntegerLiteral(this: Parser) { + const { start, end, value } = this.expect(SyntaxKinds.HexBigIntegerLiteral); + return Factory.createHexBigIntegerLiteral(value, start, end); +} +export function parseLegacyOctalIntegerLiteral(this: Parser) { + const { start, end, value } = this.expect(SyntaxKinds.LegacyOctalIntegerLiteral); + if (this.isInStrictMode()) { + this.raiseError(ErrorMessageMap.Syntax_error_0_prefixed_octal_literals_are_deprecated, start); + } + return Factory.createLegacyOctalIntegerLiteral(value, start, end); +} +export function parseNumericLiteral(this: Parser): NumberLiteral { + switch (this.getToken()) { + case SyntaxKinds.DecimalLiteral: + return this.parseDecimalLiteral(); + case SyntaxKinds.DecimalBigIntegerLiteral: + return this.parseDecimalBigIntegerLiteral(); + case SyntaxKinds.NonOctalDecimalLiteral: + return this.parseNonOctalDecimalLiteral(); + case SyntaxKinds.BinaryIntegerLiteral: + return this.parseBinaryIntegerLiteral(); + case SyntaxKinds.BinaryBigIntegerLiteral: + return this.parseBinaryBigIntegerLiteral(); + case SyntaxKinds.OctalIntegerLiteral: + return this.parseOctalIntegerLiteral(); + case SyntaxKinds.OctalBigIntegerLiteral: + return this.parseOctalBigIntegerLiteral(); + case SyntaxKinds.HexIntegerLiteral: + return this.parseHexIntegerLiteral(); + case SyntaxKinds.HexBigIntegerLiteral: + return this.parseHexBigIntegerLiteral(); + case SyntaxKinds.LegacyOctalIntegerLiteral: + return this.parseLegacyOctalIntegerLiteral(); + default: + throw this.createUnexpectError(); + } +} +export function parseStringLiteral(this: Parser) { + const { start, end, value } = this.expect(SyntaxKinds.StringLiteral); + return Factory.createStringLiteral(value, start, end); +} +export function parseBoolLiteral(this: Parser) { + const { start, end, value } = this.expect([SyntaxKinds.TrueKeyword, SyntaxKinds.FalseKeyword]); + return Factory.createBoolLiteral(value === "true" ? true : false, start, end); +} +export function parseTemplateLiteral(this: Parser, tagged: boolean) { + if (!this.match([SyntaxKinds.TemplateHead, SyntaxKinds.TemplateNoSubstitution])) { + throw this.createUnreachError([SyntaxKinds.TemplateHead, SyntaxKinds.TemplateNoSubstitution]); + } + const templateLiteralStart = this.getStartPosition(); + if (this.match(SyntaxKinds.TemplateNoSubstitution)) { + if (!tagged && this.lexer.getTemplateLiteralTag()) { + this.raiseError(ErrorMessageMap.v8_error_invalid_hexadecimal_escape_sequence, this.getStartPosition()); + } + const value = this.getSourceValue(); + const templateLiteralEnd = this.getEndPosition(); + this.nextToken(); + return Factory.createTemplateLiteral( + [Factory.createTemplateElement(value, true, templateLiteralStart, templateLiteralEnd)], + [], + templateLiteralStart, + templateLiteralEnd, + ); + } + this.nextToken(); + const expressions = [this.parseExpressionAllowIn()]; + const quasis: Array = []; + while ( + !this.match(SyntaxKinds.TemplateTail) && + this.match(SyntaxKinds.TemplateMiddle) && + !this.match(SyntaxKinds.EOFToken) + ) { + if (!tagged && this.lexer.getTemplateLiteralTag()) { + this.raiseError(ErrorMessageMap.v8_error_invalid_hexadecimal_escape_sequence, this.getStartPosition()); + } + quasis.push( + Factory.createTemplateElement( + this.getSourceValue(), + false, + this.getStartPosition(), + this.getEndPosition(), + ), + ); + this.nextToken(); + expressions.push(this.parseExpressionAllowIn()); + } + if (this.match(SyntaxKinds.EOFToken)) { + throw this.createUnexpectError(); + } + if (!tagged && this.lexer.getTemplateLiteralTag()) { + this.raiseError(ErrorMessageMap.v8_error_invalid_hexadecimal_escape_sequence, this.getStartPosition()); + } + quasis.push( + Factory.createTemplateElement( + this.getSourceValue(), + true, + this.getStartPosition(), + this.getEndPosition(), + ), + ); + const templateLiteralEnd = this.getEndPosition(); + this.nextToken(); + return Factory.createTemplateLiteral(quasis, expressions, templateLiteralStart, templateLiteralEnd); +} +/** + * Parse import meta property + * ``` + * ImportMeta := import . meta + * ``` + * @returns {MetaProperty} + */ +export function parseImportMeta(this: Parser): MetaProperty { + const { start, end } = this.expect(SyntaxKinds.ImportKeyword); + this.expect(SyntaxKinds.DotOperator); + const ecaFlag = this.getEscFlag(); + const property = this.parseIdentifierReference(); + this.staticSematicForImportMeta(property, ecaFlag, start); + return Factory.createMetaProperty( + Factory.createIdentifier("import", start, end, undefined, undefined), + property, + start, + cloneSourcePosition(property.end), + ); +} +/** + * Sematic check for import meta + * - import member expression's property only could be meta + * - meta should be a contextual keyword + * - import meta can't use in script mode + * @param property + * @param ecaFlag + */ +export function staticSematicForImportMeta( + this: Parser, + property: Identifier, + ecaFlag: boolean, + start: SourcePosition, +) { + if (property.name !== "meta") { + this.raiseError( + ErrorMessageMap.babel_error_the_only_valid_meta_property_for_import_is_import_meta, + property.start, + ); + } + if (ecaFlag) { + this.raiseError(ErrorMessageMap.invalid_esc_char_in_keyword, start); + } + if (this.config.sourceType === "script") { + this.raiseError(ErrorMessageMap.babel_error_import_meta_may_appear_only_with_source_type_module, start); + } +} +/** + * Parse Import call + * ``` + * ImportCall := import ( AssignmentExpression[+In], (optional support attribute) ) + * ``` + * @returns {CallExpression} + */ +export function parseImportCall(this: Parser): CallExpression { + const { start, end } = this.expect(SyntaxKinds.ImportKeyword); + this.expect(SyntaxKinds.ParenthesesLeftPunctuator); + const argument = this.parseAssignmentExpressionAllowIn(); + const option = this.parseImportAttributeOptional(); + const { end: finalEnd } = this.expect(SyntaxKinds.ParenthesesRightPunctuator); + return Factory.createCallExpression( + Factory.createImport(start, end), + option ? [argument, option] : [argument], + undefined, + false, + cloneSourcePosition(start), + cloneSourcePosition(finalEnd), + ); +} +/** + * Parse import attribute (stage 3 syntax) + * ref: https://github.com/tc39/proposal-import-attributes + * @returns + */ +export function parseImportAttributeOptional(this: Parser): Expression | null { + if ( + !this.requirePlugin(ParserPlugin.ImportAssertions) && + !this.requirePlugin(ParserPlugin.ImportAttribute) + ) { + return null; + } + if (!this.match(SyntaxKinds.CommaToken)) { + return null; + } + this.nextToken(); + if (this.match(SyntaxKinds.ParenthesesRightPunctuator)) { + return null; + } + const option = this.parseAssignmentExpressionAllowIn(); + if (this.match(SyntaxKinds.CommaToken)) { + this.nextToken(); + } + return option; +} +/** + * Parse new target + * ``` + * NewTarget := new . target + * ``` + * @returns {MetaProperty} + */ +export function parseNewTarget(this: Parser): MetaProperty { + const { start, end } = this.expect(SyntaxKinds.NewKeyword); + this.expect(SyntaxKinds.DotOperator); + this.staticSematicForNewTarget(start); + const targetStart = this.getStartPosition(); + const targetEnd = this.getEndPosition(); + this.nextToken(); + return Factory.createMetaProperty( + Factory.createIdentifier("new", start, end, undefined, undefined), + Factory.createIdentifier("target", targetStart, targetEnd, undefined, undefined), + start, + targetEnd, + ); +} +export function staticSematicForNewTarget(this: Parser, start: SourcePosition) { + if (!this.isContextKeyword("target")) { + // recoverable error + throw this.createUnexpectError(); + } + if (!this.config.allowNewTargetOutsideFunction && this.isTopLevel() && !this.isInClassScope()) { + // recoverable error + this.raiseError( + ErrorMessageMap.babel_error_new_target_can_only_be_used_in_class_or_function_scope, + start, + ); + } +} +/** + * Parse New Expression, the callee part of new expression is a trick one, + * this is not a member expression, it can not contain qustion dot or call + * expression. + * ``` + * NewExpression := 'new' NewExpression + * := 'new' MemberExpressionWithoutOptional Arugment? + * ``` + * @returns {Expression} + */ +export function parseNewExpression(this: Parser): Expression { + const { start } = this.expect(SyntaxKinds.NewKeyword); + // maybe is new.target + if (this.match(SyntaxKinds.NewKeyword) && this.lookahead().kind !== SyntaxKinds.DotOperator) { + return this.parseNewExpression(); + } + let base = this.parsePrimaryExpression(); + this.staticSematicForBaseInNewExpression(base); + base = this.parseNewExpressionCallee(base); + const typeArgument = this.tryParseTSTypeParameterInstantiationForNewExpression(); + if (!this.match(SyntaxKinds.ParenthesesLeftPunctuator)) { + // accpect New XXX -> No argument + return Factory.createNewExpression(base, [], typeArgument, start, cloneSourcePosition(base.end)); + } + const { end, nodes } = this.parseArguments(); + return Factory.createNewExpression(base, nodes, typeArgument, start, end); +} +/** + * The base of new expression can not be a import call expression, if must be a import + * call expression, it must be have a paran. + * @param {Expression} base + */ +export function staticSematicForBaseInNewExpression(this: Parser, base: Expression) { + if (!base.parentheses && isCallExpression(base) && base.callee.kind === SyntaxKinds.Import) { + // recoverable error + this.raiseError(ErrorMessageMap.babel_error_cannot_use_new_with_import, base.start); + } +} +/** + * Parse the callee of new expression, base of new expression can not + * be a call expression or a qustion dot expression. + * @param {Expression} base + * @returns + */ +export function parseNewExpressionCallee(this: Parser, base: Expression): Expression { + while ( + this.match(SyntaxKinds.DotOperator) || + this.match(SyntaxKinds.BracketLeftPunctuator) || + this.match(SyntaxKinds.QustionDotOperator) + ) { + if (this.match(SyntaxKinds.QustionDotOperator)) { + // recoverable error + this.raiseError( + ErrorMessageMap.babel_error_constructors_in_after_an_optional_chain_are_not_allowed, + this.getStartPosition(), + ); + this.nextToken(); + base = this.parseMemberExpression(base, true); + continue; + } + base = this.parseMemberExpression(base, false); + } + return base; +} +export function tryParseTSTypeParameterInstantiationForNewExpression(this: Parser) { + if (this.match(SyntaxKinds.LtOperator) || this.match(SyntaxKinds.BitwiseLeftShiftOperator)) { + const result = this.tryParse(() => this.tryParseTSTypeParameterInstantiation(false)); + if ( + this.match([ + SyntaxKinds.ParenthesesLeftPunctuator, + SyntaxKinds.TemplateNoSubstitution, + SyntaxKinds.TemplateHead, + ]) + ) { + return result?.[0]; + } + if ( + this.match([ + SyntaxKinds.LtOperator, + SyntaxKinds.GtOperator, + SyntaxKinds.MinusOperator, + SyntaxKinds.MinusOperator, + ]) || + !(this.getLineTerminatorFlag() || this.isBinaryOps(this.getToken()) || !this.canStartExpression()) + ) { + if (result) this.abortTryParseResult(result[1], result[2], result[3]); + return; + } + return result?.[0]; + } +} +// TODO: finish all possible +// reference: https://github.com/oxc-project/oxc/blob/eac34b676f473f79bcb4a55d6322d0b02a15d6fa/crates/oxc_parser/src/ts/types.rs#L1382 +export function canStartExpression(this: Parser) { + switch (this.getToken()) { + case SyntaxKinds.Identifier: + case SyntaxKinds.PlusOperator: + case SyntaxKinds.MinusOperator: + return true; + case SyntaxKinds.TrueKeyword: + case SyntaxKinds.FalseKeyword: + case SyntaxKinds.NullKeyword: + case SyntaxKinds.UndefinedKeyword: + case SyntaxKinds.StringLiteral: + return true; + default: + return false; + } +} +/** + * Parse super expression, only parse the arguments and super or a first level + * of access of member expression. Contain sematic check: + * - Super call only valid in ctor. + * - super property can be used in any method of class. + * ``` + * SuperCall := super argument + * SuperProperty := super[Expression] + * := super.IdentifierName + * ``` + * @returns {Expression} + */ +export function parseSuper(this: Parser): Expression { + if (!this.isCurrentClassExtend()) { + // recoverable error + this.raiseError( + ErrorMessageMap.syntax_error_super_is_only_valid_in_derived_class_constructors, + this.getStartPosition(), + ); + } + const { start: keywordStart, end: keywordEnd } = this.expect([SyntaxKinds.SuperKeyword]); + if (this.match(SyntaxKinds.ParenthesesLeftPunctuator)) { + if (!this.lexicalScopeRecorder.isInCtor()) { + // recoverable error + this.raiseError(ErrorMessageMap.babel_error_call_super_outside_of_ctor, keywordStart); + } + const typeArguments = this.tryParseTSTypeParameterInstantiation(false); + const { nodes, end: argusEnd } = this.parseArguments(); + return Factory.createCallExpression( + Factory.createSuper(keywordStart, keywordEnd), + nodes, + typeArguments, + false, + cloneSourcePosition(keywordStart), + argusEnd, + ); + } + let property: Expression; + let isComputed = false; + let end: SourcePosition; + switch (this.getToken()) { + case SyntaxKinds.QustionDotOperator: + // recoverable error. + this.raiseError(ErrorMessageMap.babel_invalid_usage_of_super_call, this.getStartPosition()); + // eslint-disable-next-line no-fallthrough + case SyntaxKinds.DotOperator: { + this.nextToken(); + if (this.match(SyntaxKinds.PrivateName)) { + property = this.parsePrivateName(); + // recoverable error + this.raiseError(ErrorMessageMap.babel_error_private_fields_cant_be_accessed_on_super, property.start); + } else { + property = this.parseIdentifierName(); + } + end = cloneSourcePosition(property.end); + break; + } + case SyntaxKinds.BracketLeftPunctuator: { + this.nextToken(); + property = this.parseExpressionAllowIn(); + isComputed = true; + ({ end } = this.expect(SyntaxKinds.BracketRightPunctuator)); + break; + } + default: + throw this.createUnexpectError(); + } + return Factory.createMemberExpression( + isComputed, + Factory.createSuper(keywordStart, keywordEnd), + property, + false, + cloneSourcePosition(keywordStart), + end, + ); +} +/** + * Parse this expression, only eat `this` token + * @returns {ThisExpression} + */ +export function parseThisExpression(this: Parser): ThisExpression { + const { start, end } = this.expect([SyntaxKinds.ThisKeyword]); + return Factory.createThisExpression(start, end); +} +/** + * Parse ObjectLiterial, object property just a list of PropertyDefinition. + * ### Trailing Comma problem + * object expression maybe transform into `ObjectPattern` in `AssignmentExpression` + * so i add a trailing comma field to object expression to AST struct for `toAssignment` + * function. + * ``` + * ObjectLiteral := '{' PropertyDefinitionList ','? '}' + * PropertyDefinitionList := PropertyDefinitionList ',' PropertyDefinition + * := PropertyDefinition + * ``` + * @returns {Expression} actually is `ObjectExpression` + */ +export function parseObjectExpression(this: Parser): Expression { + const { start } = this.expect(SyntaxKinds.BracesLeftPunctuator); + let isStart = true; + const propertyDefinitionList: Array = []; + let trailingComma = false; + const protoPropertyNames: Array = []; + while (!this.match(SyntaxKinds.BracesRightPunctuator) && !this.match(SyntaxKinds.EOFToken)) { + if (isStart) { + propertyDefinitionList.push(this.parsePropertyDefinition(protoPropertyNames)); + isStart = false; + continue; + } + this.expect(SyntaxKinds.CommaToken); + if (this.match(SyntaxKinds.BracesRightPunctuator) || this.match(SyntaxKinds.EOFToken)) { + trailingComma = true; + break; + } + propertyDefinitionList.push(this.parsePropertyDefinition(protoPropertyNames)); + } + this.staticSematicEarlyErrorForObjectExpression(protoPropertyNames); + const { end } = this.expect(SyntaxKinds.BracesRightPunctuator); + return Factory.createObjectExpression(propertyDefinitionList, trailingComma, start, end); +} +/** + * Adding `__proto__` property key to duplication set, if object expression transform to pattern + * duplication of `__proto__` is ok, but when is not pattern, it not a correct syntax. + * @param {Array} protoPropertyNames + * reference: 13.2.5.1 + */ +export function staticSematicEarlyErrorForObjectExpression( + this: Parser, + protoPropertyNames: Array, +) { + if (protoPropertyNames.length > 1) { + for (let index = 1; index < protoPropertyNames.length; ++index) + this.context.propertiesProtoDuplicateSet.add(protoPropertyNames[index]); + } +} +/** + * Helper for property definition to record the object property which property is + * `__proto__`, since duplication of `__proto__` is a error. + * @param protoPropertyNames + * @param propertyName + * @param isComputed + * @returns + */ +export function staticSematicHelperRecordPropertyNameForEarlyError( + protoPropertyNames: Array, + propertyName: PropertyName, + isComputed: boolean, +) { + if (isComputed) return; + if ( + (isIdentifer(propertyName) && propertyName.name === "__proto__") || + (isStringLiteral(propertyName) && propertyName.value === "__proto__") + ) { + protoPropertyNames.push(propertyName); + return; + } +} +/** + * Parse PropertyDefinition + * ``` + * PropertyDefinition := MethodDefintion + * := Property + * := SpreadElement + * Property := PropertyName '=' AssignmentExpression + * SpreadElement := '...' AssigmentExpression + * ``` + * ### How to parse + * 1. start with `...` operator, must be SpreadElment + * 2. start with privatename is syntax error, but it is common, so we handle it as sematic problem. + * 3. check is start with method modifier prefix by helper function `checkIsMethodStartWithModifier`. + * 4. default case, property name with colon operator. + * 5. this is speical case, we accept a coverinit in object expression, because object expression + * might be transform into object pattern, so we mark accept it and mark it. it coverInit of + * object expression is not transform by `toAssignment` function, it would throw error in the + * end of `parseProgram` + * #### ref: https://tc39.es/ecma262/#prod-PropertyDefinition + */ +export function parsePropertyDefinition( + this: Parser, + protoPropertyNameLocations: Array, +): PropertyDefinition { + // semantics check for private + if (this.match(SyntaxKinds.PrivateName)) { + // TODO: make it recoverable + throw this.createMessageError(ErrorMessageMap.extra_error_private_field_in_object_expression); + } + // spreadElement + if (this.match(SyntaxKinds.SpreadOperator)) { + const spreadElementStart = this.getStartPosition(); + this.nextToken(); + const expr = this.parseAssignmentExpressionAllowIn(); + return Factory.createSpreadElement(expr, spreadElementStart, cloneSourcePosition(expr.end)); + } + // start with possible method modifier + if (this.checkIsMethodStartWithModifier()) { + return this.parseMethodDefintion() as ObjectMethodDefinition; + } + // otherwise, it would be Property start with PropertyName or MethodDeinftion start with PropertyName + const isComputedRef = { isComputed: false }; + const propertyName = this.parsePropertyName(isComputedRef); + if (this.match(SyntaxKinds.ParenthesesLeftPunctuator)) { + return this.parseMethodDefintion(false, [ + propertyName, + isComputedRef.isComputed, + ]) as ObjectMethodDefinition; + } + if (isComputedRef.isComputed || this.match(SyntaxKinds.ColonPunctuator)) { + staticSematicHelperRecordPropertyNameForEarlyError( + protoPropertyNameLocations, + propertyName, + isComputedRef.isComputed, + ); + this.nextToken(); + const expr = this.parseAssignmentExpressionAllowIn(); + return Factory.createObjectProperty( + propertyName, + expr, + isComputedRef.isComputed, + false, + cloneSourcePosition(propertyName.start), + cloneSourcePosition(expr.end), + ); + } + this.recordIdentifierValue(propertyName); + if (this.match(SyntaxKinds.AssginOperator)) { + staticSematicHelperRecordPropertyNameForEarlyError( + protoPropertyNameLocations, + propertyName, + isComputedRef.isComputed, + ); + this.nextToken(); + const expr = this.parseAssignmentExpressionAllowIn(); + const property = Factory.createObjectProperty( + propertyName, + expr, + isComputedRef.isComputed, + false, + cloneSourcePosition(propertyName.start), + cloneSourcePosition(expr.end), + ); + this.context.propertiesInitSet.add(property); + return property; + } + this.staticSematicForShortedPropertyNameInObjectLike(propertyName); + this.staticSematicForShortedPropertyNameInObjectExpression(propertyName as Identifier); + return Factory.createObjectProperty( + propertyName, + undefined, + isComputedRef.isComputed, + true, + cloneSourcePosition(propertyName.start), + cloneSourcePosition(propertyName.end), + ); +} +export function recordIdentifierValue(this: Parser, propertyName: ModuleItem) { + if (isIdentifer(propertyName)) { + if (propertyName.name === "await") { + this.recordScope(ExpressionScopeKind.AwaitIdentifier, propertyName.start); + } + if (propertyName.name === "yield") { + this.recordScope(ExpressionScopeKind.YieldIdentifier, propertyName.start); + } + if (propertyName.name === "arguments") { + this.recordScope(ExpressionScopeKind.ArgumentsIdentifier, propertyName.start); + } + if (propertyName.name === "eval") { + this.recordScope(ExpressionScopeKind.EvalIdentifier, propertyName.start); + } + if (propertyName.name === "let") { + this.recordScope(ExpressionScopeKind.LetIdentifiier, propertyName.start); + } + if (PreserveWordSet.has(propertyName.name)) { + this.recordScope(ExpressionScopeKind.PresveredWordIdentifier, propertyName.start); + } + } +} +/** + * Parse PropertyName, using context ref which passed in to record this property is computed or not. + * + * ### Extra action need for callee + * In this function, we accept keywrod as property name, but when the property name use as a shorted + * property name, it will be a syntax error, so father syntax check is needed handle by callee. + * ``` + * PropertyName := Identifer (IdentifierName, not BindingIdentifier) + * := NumberLiteral + * := StringLiteral + * := ComputedPropertyName + * ComputedPropertyName := '[' AssignmentExpression ']' + * ``` + * ref: https://tc39.es/ecma262/#prod-PropertyName + * @returns {PropertyName} + */ +export function parsePropertyName(this: Parser, isComputedRef: { isComputed: boolean }): PropertyName { + this.expectButNotEat([ + SyntaxKinds.BracketLeftPunctuator, + SyntaxKinds.StringLiteral, + ...IdentiferWithKeyworArray, + ...NumericLiteralKinds, + ]); + switch (this.getToken()) { + case SyntaxKinds.StringLiteral: { + return this.parseStringLiteral(); + } + case SyntaxKinds.BracketLeftPunctuator: { + this.nextToken(); + this.lexicalScopeRecorder.enterPropertyName(); + const expr = this.parseAssignmentExpressionAllowIn(); + this.lexicalScopeRecorder.exitPropertyName(); + this.expect(SyntaxKinds.BracketRightPunctuator); + isComputedRef.isComputed = true; + return expr; + } + default: { + if (this.match(NumericLiteralKinds)) { + return this.parseNumericLiteral(); + } + // propty name is a spical test of binding identifier. + // if `await` and `yield` is propty name with colon (means assign), it dose not affected by scope. + if (this.match(IdentiferWithKeyworArray)) { + const identifer = this.parseIdentifierName(); + return identifer; + } + throw this.createUnexpectError(); + } + } +} +/** + * Sematic check when a property name is shorted property + * @param {PropertyName} propertyName + * @returns + */ +export function staticSematicForShortedPropertyNameInObjectLike(this: Parser, propertyName: PropertyName) { + if (isStringLiteral(propertyName) || isNumnerLiteral(propertyName)) { + // recoverable error. + this.raiseError( + ErrorMessageMap.extra_error_when_binding_pattern_property_name_is_literal_can_not_be_shorted, + propertyName.start, + ); + } +} +/** + * Like `staticCheckForPropertyNameAsSingleBinding` for object pattern, when shorted property in + * object expression, if will no longer just + * @param {PropertyName} propertyName + * @returns + */ +export function staticSematicForShortedPropertyNameInObjectExpression( + this: Parser, + propertyName: Identifier, +) { + if (propertyName.name === "await") { + if (this.isCurrentScopeParseAwaitAsExpression() || this.config.sourceType === "module") { + this.raiseError( + ErrorMessageMap.babel_error_can_not_use_await_as_identifier_inside_an_async_function, + propertyName.start, + ); + } + return; + } + if (propertyName.name === "yield") { + if (this.isCurrentScopeParseYieldAsExpression() || this.isInStrictMode()) { + this.raiseError(ErrorMessageMap.babel_error_invalid_yield, propertyName.start); + } + return; + } + if (KeywordSet.has(propertyName.name)) { + // recoverable error + this.raiseError(ErrorMessageMap.babel_error_unexpected_keyword, propertyName.start); + } + if (PreserveWordSet.has(propertyName.name) && this.isInStrictMode()) { + // recoverable error + this.raiseError(ErrorMessageMap.babel_error_unexpected_reserved_word, propertyName.start); + } +} +/** Parse MethodDefintion, this method should allow using when in class or in object literal. + * 1. ClassElement can be PrivateName, when it used in object literal, it should throw a error. + * 2. It should parse modifier when `withPropertyName` is falsey. + * + * ### Parse Modifier + * we parse modifier according to the pattern `('set' | 'get')? 'async' '*' ClassElement `, this + * is not a regulat syntax, it may accept wrong syntax, but by accept more case then spec, we cam + * provide more concies sematic message to developer. + * ``` + * MethodDefintion := ClassElementName BindingList FunctionBody + * := AyncMethod + * := GeneratorMethod + * := AsyncGeneratorMethod + * := 'set' ClassElementName BindingList FunctionBody + * := 'get' ClassElementName '('')' FunctionBody + * AyncMethod := 'async' ClassElementName BindingList FunctionBody + * GeneratorMethod := '*' ClassElementName BindingList FunctionBody + * AsyncGeneratorMethod := 'async' '*' ClassElementName BindingList FunctionBody + * ClassElementName := PropertyName + * := PrivateName + * ``` + * @param {boolean} inClass is used in class or not. + * @param {PropertyName | PrivateName | undefined } withPropertyName parse methodDeinfition with exited propertyName or not + * @param {boolean} isStatic + * @returns {ObjectMethodDefinition | ClassMethodDefinition | ObjectAccessor | ClassAccessor | ClassConstructor} + */ +export function parseMethodDefintion( + this: Parser, + inClass: boolean = false, + withPropertyName: [PropertyName | PrivateName, boolean] | undefined = undefined, + isStatic: boolean = false, + decorators: Decorator[] | null = null, +): ObjectMethodDefinition | ClassMethodDefinition | ObjectAccessor | ClassAccessor | ClassConstructor { + if (!this.checkIsMethodStartWithModifier() && !withPropertyName) { + throw this.createUnreachError([SyntaxKinds.MultiplyAssignOperator, SyntaxKinds.Identifier]); + } + /** + * Step 1 : if not with propertyName , parse modifier frist, otherwise, if with propertyName, it shouldn't do anything. + * structure would be like : ('set' | 'get')? 'async' '*' PropertyName ...., this strcuture isn't match the spec. + * but in this structure, we can detect some syntax error more concies, like set and get can not use with async + * or generator. + */ + let type: MethodDefinition["type"] = "method"; + let isAsync: MethodDefinition["async"] = false; + let generator: MethodDefinition["generator"] = false; + let computed: MethodDefinition["computed"] = withPropertyName ? withPropertyName[1] : false; + let start: SourcePosition | null = null; + let propertyName: PropertyName; + if (!withPropertyName) { + // frist, is setter or getter + if (this.isContextKeyword("set")) { + type = "set"; + start = this.getStartPosition(); + this.nextToken(); + } else if (this.isContextKeyword("get")) { + type = "get"; + start = this.getStartPosition(); + this.nextToken(); + } + // second, parser async and generator + const { kind } = this.lookahead(); + if (this.isContextKeyword("async") && kind !== SyntaxKinds.ParenthesesLeftPunctuator) { + start = this.getStartPosition(); + isAsync = true; + this.nextToken(); + if (this.match(SyntaxKinds.MultiplyOperator)) { + this.nextToken(); + generator = true; + } + } else if (this.match(SyntaxKinds.MultiplyOperator)) { + start = this.getStartPosition(); + generator = true; + this.nextToken(); + } + if (this.match(SyntaxKinds.PrivateName)) { + propertyName = this.parsePrivateName(); + this.defPrivateName( + propertyName.name, + propertyName.start, + type === "method" ? "other" : isStatic ? `static-${type}` : type, + ); + } else { + const isComputedRef = { isComputed: false }; + propertyName = this.parsePropertyName(isComputedRef); + computed = isComputedRef.isComputed; + } + if (!start) start = cloneSourcePosition(propertyName.start); + } else { + start = cloneSourcePosition(withPropertyName[0].start); + propertyName = withPropertyName[0]; + } + const isCtor = inClass && !isStatic && !computed && helperIsPropertyNameIsCtor(propertyName); + if (isCtor) { + this.lexicalScopeRecorder.enterCtor(); + if (this.lexicalScopeRecorder.testAndSetCtor()) { + this.raiseError(ErrorMessageMap.v8_error_a_class_may_only_have_one_constructor, propertyName.start); + } + } + const typeParameters = this.tryParseTSTypeParameterDeclaration(false); + this.enterFunctionScope(isAsync, generator); + const [parmas, scope] = this.parseWithCatpureLayer(() => this.parseFunctionParam()); + const returnType = this.tryParseTSReturnTypeOrTypePredicate(SyntaxKinds.ColonPunctuator); + const body = this.parseFunctionBody(); + this.postStaticSematicEarlyErrorForStrictModeOfFunction(null, scope); + this.exitFunctionScope(true); + if (isCtor) this.lexicalScopeRecorder.exitCtor(); + /** + * Step 2: semantic and more concise syntax check instead just throw a unexpect + * token error. + */ + this.staticSematicEarlyErrorForClassMethodDefinition( + propertyName, + inClass, + isStatic, + isAsync, + generator, + parmas, + type, + ); + /** + * Step 3 return based on type, if accessor or methodDefintion + */ + if (inClass) { + if (isCtor) { + if (decorators) { + this.raiseError( + ErrorMessageMap.babel_error_decorators_can_not_be_used_with_a_constructor, + decorators[0].start, + ); + } + return Factory.createClassConstructor( + propertyName as ClassConstructor["key"], + body, + parmas, + returnType, + start as SourcePosition, + cloneSourcePosition(body.end), + ); + } + if (type === "set" || type === "get") { + return Factory.createClassAccessor( + propertyName, + body, + parmas, + typeParameters, + returnType, + type, + computed, + decorators, + start as SourcePosition, + cloneSourcePosition(body.end), + ); + } + return Factory.createClassMethodDefintion( + propertyName, + body, + parmas, + typeParameters, + returnType, + isAsync, + generator, + computed, + isStatic, + decorators, + start ? start : cloneSourcePosition(propertyName.start), + cloneSourcePosition(body.end), + ); + } + if (type === "set" || type === "get") { + return Factory.createObjectAccessor( + propertyName, + body, + parmas, + typeParameters, + returnType, + type, + computed, + start as SourcePosition, + cloneSourcePosition(body.end), + ); + } + return Factory.createObjectMethodDefintion( + propertyName, + body, + parmas, + typeParameters, + returnType, + isAsync, + generator, + computed, + start ? start : cloneSourcePosition(propertyName.start), + cloneSourcePosition(body.end), + ); +} +/** + * This is a helper function for object expression and class for determiate is property + * a method definition or not. + * + * Please notes that this function not only accept regualer syntax, but also accept something + * like set and get generator, it will left sematic job for `parseMetodDefinition` method. + * @returns {boolean} + */ +export function checkIsMethodStartWithModifier(this: Parser): boolean { + if (this.match(SyntaxKinds.MultiplyOperator)) { + return true; + } + const { kind, lineTerminatorFlag: flag } = this.lookahead(); + const isLookAheadValidatePropertyNameStart = + Keywords.find((keyword) => keyword === kind) || + kind === SyntaxKinds.Identifier || + kind === SyntaxKinds.PrivateName || + kind === SyntaxKinds.StringLiteral || + NumericLiteralKinds.includes(kind) || + kind === SyntaxKinds.BracketLeftPunctuator || + kind === SyntaxKinds.MultiplyOperator; + if (this.isContextKeyword("set") && isLookAheadValidatePropertyNameStart) { + return true; + } + if (this.isContextKeyword("get") && isLookAheadValidatePropertyNameStart) { + return true; + } + if (this.isContextKeyword("async") && isLookAheadValidatePropertyNameStart && !flag) { + return true; + } + return false; +} +function helperIsPropertyNameIsCtor(propertyName: PropertyName) { + switch (propertyName.kind) { + case SyntaxKinds.Identifier: { + return propertyName.name === "constructor"; + } + case SyntaxKinds.StringLiteral: { + return propertyName.value === "constructor"; + } + default: { + return false; + } + } +} +/** + * Spec def of class method, only implement some of spec. + * @param propertyName + * @param isClass + * @param isStatic + * @param isAsync + * @param isGenerator + * @param params + * @param type + * reference: https://tc39.es/ecma262/#sec-class-definitions-static-semantics-early-errors + */ +export function staticSematicEarlyErrorForClassMethodDefinition( + this: Parser, + propertyName: PropertyName, + isClass: boolean, + isStatic: boolean, + isAsync: boolean, + isGenerator: boolean, + params: Array, + type: MethodDefinition["type"], +) { + // general check + if (type === "get" && params.length > 0) { + this.raiseError(ErrorMessageMap.syntax_error_getter_functions_must_have_no_arguments, propertyName.start); + } + if (type === "set") { + if (params.length !== 1) { + this.raiseError(ErrorMessageMap.syntax_error_setter_functions_must_have_one_argument, params[0].start); + } + for (const param of params) { + if (isRestElement(param)) { + this.raiseError( + ErrorMessageMap.syntax_error_setter_functions_must_have_one_argument_not_rest, + param.start, + ); + } + } + } + if (type === "get" && (isAsync || isGenerator)) { + this.raiseError(ErrorMessageMap.extra_error_getter_can_not_be_async_or_generator, propertyName.start); + } + if (type === "set" && (isAsync || isGenerator)) { + this.raiseError(ErrorMessageMap.extra_error_setter_can_not_be_async_or_generator, propertyName.start); + } + // class check + if (isClass) { + let valueOfName: string | undefined, + isPrivate = false, + fromLiteral = false; // + if (isStringLiteral(propertyName)) { + valueOfName = propertyName.value; + fromLiteral = true; + } else if (isIdentifer(propertyName)) { + valueOfName = propertyName.name; + } else if (isPrivateName(propertyName)) { + valueOfName = propertyName.name; + isPrivate = true; + } + if (valueOfName === "constructor" && !fromLiteral) { + if (isAsync) { + this.raiseError( + ErrorMessageMap.v8_error_class_constructor_may_not_be_an_async_method, + propertyName.start, + ); + } + if (isGenerator) { + this.raiseError( + ErrorMessageMap.v8_error_class_constructor_may_not_be_a_generator, + propertyName.start, + ); + } + if (type === "get" || type === "set") { + this.raiseError( + ErrorMessageMap.v8_error_class_constructor_may_not_be_an_accessor, + propertyName.start, + ); + } + if (isPrivate) { + this.raiseError( + ErrorMessageMap.v8_error_class_may_not_have_a_private_field_named_constructor, + propertyName.start, + ); + } + } + if (valueOfName === "prototype" && !isPrivate && type === "method" && isStatic) { + this.raiseError( + ErrorMessageMap.v8_error_class_may_not_have_static_property_named_prototype, + propertyName.start, + ); + } + } +} +export function parseArrayExpression(this: Parser) { + const { start } = this.expect(SyntaxKinds.BracketLeftPunctuator); + const elements: Array = []; + let tralingComma = false; + let isStart = true; + while (!this.match(SyntaxKinds.BracketRightPunctuator) && !this.match(SyntaxKinds.EOFToken)) { + if (isStart) { + isStart = false; + } else { + this.expect(SyntaxKinds.CommaToken); + } + if (this.match([SyntaxKinds.BracketRightPunctuator, SyntaxKinds.EOFToken])) { + tralingComma = true; + break; + } + if (this.match(SyntaxKinds.CommaToken)) { + elements.push(null); + continue; + } + if (this.match(SyntaxKinds.SpreadOperator)) { + const start = this.getStartPosition(); + this.nextToken(); + const expr = this.parseAssignmentExpressionAllowIn(); + elements.push(Factory.createSpreadElement(expr, start, cloneSourcePosition(expr.end))); + } else { + const expr = this.parseAssignmentExpressionAllowIn(); + elements.push(expr); + } + } + const { end } = this.expect(SyntaxKinds.BracketRightPunctuator); + return Factory.createArrayExpression(elements, start, end, tralingComma); +} +export function parseFunctionExpression(this: Parser, isAsync: boolean) { + this.enterFunctionScope(isAsync); + const funcExpr = this.parseFunction(true); + this.exitFunctionScope(false); + return Factory.transFormFunctionToFunctionExpression(funcExpr); +} +export function parseClassExpression(this: Parser, decoratorList: Decorator[] | null) { + return Factory.transFormClassToClassExpression(this.parseClass(decoratorList)); +} +export function parseCoverExpressionORArrowFunction(this: Parser) { + const possibleBeArrow = this.canParseAsArrowFunction(); + this.expectButNotEat(SyntaxKinds.ParenthesesLeftPunctuator); + const [[{ start, end, nodes, trailingComma, typeAnnotations }, strictModeScope], arrowExprScope] = + this.parseWithArrowExpressionScope(() => this.parseWithCatpureLayer(() => this.parseArgumentsWithType())); + const returnType = this.tryParseTSReturnTypeOrTypePredicateForArrowExpression(possibleBeArrow, nodes); + const notArrowExpression = !possibleBeArrow || !this.match(SyntaxKinds.ArrowOperator); + + if (notArrowExpression) { + // transfor to sequence or signal expression + for (const element of nodes) { + if (isSpreadElement(element)) { + // recoverable error + this.raiseError(ErrorMessageMap.extra_error_rest_element_invalid, element.start); + } + } + if (trailingComma) { + // recoverable error + this.raiseError(ErrorMessageMap.extra_error_sequence_expression_can_not_have_trailing_comma, end); + } + if (nodes.length === 1) { + nodes[0].parentheses = true; + return nodes[0]; + } + if (nodes.length === 0) { + // recoverable error + this.raiseError(ErrorMessageMap.extra_error_empty_parentheses_expression, start); + } + const seq = Factory.createSequenceExpression(nodes, start, end); + seq.parentheses = true; + return seq; + } + this.enterArrowFunctionBodyScope(); + const arrowExpr = this.parseArrowFunctionExpression( + { start, end, nodes, trailingComma, typeAnnotations }, + undefined, + strictModeScope, + arrowExprScope, + ); + this.exitArrowFunctionBodyScope(); + arrowExpr.returnType = returnType; + return arrowExpr; +} +export function tryParseTSReturnTypeOrTypePredicateForArrowExpression( + this: Parser, + possibleBeArrow: boolean, + functionArguments: Expression[], +) { + let returnType: undefined | ArrorFunctionExpression["returnType"] = undefined; + if ( + possibleBeArrow && + simpleCheckIsArgumentCanBeAssignable(functionArguments) && + this.match(SyntaxKinds.ColonPunctuator) && + this.requirePlugin(ParserPlugin.TypeScript) + ) { + const result = this.tryParse(() => this.parseTSReturnTypeOrTypePredicate(SyntaxKinds.ColonPunctuator)); + if (!this.match(SyntaxKinds.ArrowOperator)) { + if (!result) throw this.createUnreachError(); + this.lexer.restoreState(result[1], result[2]); + this.errorHandler.restoreTryFail(result[3]); + } else { + returnType = result?.[0]; + } + } + return returnType; +} +export function simpleCheckIsArgumentCanBeAssignable(functionArguments: Array) { + for (const argu of functionArguments) { + switch (argu.kind) { + case SyntaxKinds.ObjectExpression: + case SyntaxKinds.ArrayExpression: + case SyntaxKinds.Identifier: + case SyntaxKinds.SpreadElement: + continue; + case SyntaxKinds.AssigmentExpression: + if (argu.operator === SyntaxKinds.AssginOperator) { + continue; + } + return false; + default: + return false; + } + } + return true; +} + +/** + * Parse arrow function expression, by given argumentlist and meta data, include + * - start of `(` + * - end of `)`, + * - is trailing comma of argument list + * please notes that this function accept with arguments, not paramemter list, so we need to + * transform arguments to parameter list, so we need to call `toAssignment` for each argument. + * and we also need to check is parameter duplicate. + * + * @param {ASTArrayWithMetaData & { trailingComma: boolean }} metaData + * @returns {ArrorFunctionExpression} + */ +export function parseArrowFunctionExpression( + this: Parser, + metaData: ASTArrayWithMetaData & { + trailingComma: boolean; + typeAnnotations: Array<[TSTypeAnnotation | undefined, boolean]> | undefined; + }, + typeParameters: ArrorFunctionExpression["typeParameters"], + strictModeScope: StrictModeScope, + arrowExprScope: AsyncArrowExpressionScope, +): ArrorFunctionExpression { + if (this.getLineTerminatorFlag()) { + // recoverable error + this.raiseError( + ErrorMessageMap.extra_error_no_line_break_is_allowed_before_arrow, + this.getStartPosition(), + ); + } + this.expect(SyntaxKinds.ArrowOperator); + const functionArguments = this.argumentToFunctionParams( + metaData.nodes, + metaData.trailingComma, + strictModeScope, + arrowExprScope, + ); + let body: Expression | FunctionBody; + let isExpression = false; + if (this.match(SyntaxKinds.BracesLeftPunctuator)) { + body = this.parseFunctionBody(); + } else { + body = this.parseAssignmentExpressionInheritIn(); + isExpression = true; + } + this.postStaticSematicEarlyErrorForStrictModeOfFunction(null, strictModeScope); + this.attachTypeToPattern(functionArguments, metaData.typeAnnotations); + return Factory.createArrowExpression( + isExpression, + body, + functionArguments, + typeParameters, + undefined, + this.isCurrentScopeParseAwaitAsExpression(), + cloneSourcePosition(metaData.start), + cloneSourcePosition(body.end), + ); +} +export function attachTypeToPattern( + this: Parser, + patterns: Array, + typeAnnotations: Array<[TSTypeAnnotation | undefined, boolean]> | undefined, +) { + if (!typeAnnotations || !this.requirePlugin(ParserPlugin.TypeScript)) { + return; + } + let index = 0; + for (const pat of patterns) { + if (isAssignmentPattern(pat)) { + const tsPat = pat.left as TSParameter; + tsPat.typeAnnotation = typeAnnotations[index][0]; + tsPat.optional = typeAnnotations[index][1]; + continue; + } + (pat as TSParameter).typeAnnotation = typeAnnotations[index][0]; + (pat as TSParameter).optional = typeAnnotations[index][1]; + index++; + } +} +/** + * Transform function from expressions to patterns (arguments to params), checking syntax error + * by expression scope and post statci sematic check for pattern rule. + * - asycn arrow scope: check await expression, yield expression + * - strict mode scope: expression Rval to Lval has different rule in strict mode + * - multi spread vs multi rest: rest is unique, spread can be multi. + * @param functionArguments + * @param trailingComma + * @param strictModeScope + * @param arrowExprScope + * @returns + */ +export function argumentToFunctionParams( + this: Parser, + functionArguments: Array, + trailingComma: boolean, + strictModeScope: StrictModeScope, + arrowExprScope: AsyncArrowExpressionScope, +): Array { + const params = functionArguments.map((node) => this.exprToPattern(node, true)) as Array; + if ( + this.isCurrentScopeParseAwaitAsExpression() || + this.isParentFunctionAsync() || + this.isParentFunctionGenerator() + ) { + this.checkAsyncArrowExprScopeError(arrowExprScope); + } + if (this.isInStrictMode()) { + this.checkStrictModeScopeError(strictModeScope); + } + const isMultiSpread = this.postStaticSematicForArrowParamAfterTransform(params); + if (isMultiSpread && trailingComma) + // recoverable error + this.raiseError( + ErrorMessageMap.babel_error_unexpected_trailing_comma_after_rest_element, + this.lexer.getLastTokenEndPositon(), + ); + // check as function params + this.setContextIfParamsIsSimpleParameterList(params); + return params; +} +export function postStaticSematicForArrowParamAfterTransform(this: Parser, params: Array) { + let flag = false; + params.forEach((param) => { + if (flag && isRestElement(param)) { + // recoverable error + this.raiseError(ErrorMessageMap.babel_error_unexpected_trailing_comma_after_rest_element, param.start); + return; + } + if (flag) { + // recoverable error + this.raiseError(ErrorMessageMap.babel_error_unexpected_trailing_comma_after_rest_element, param.start); + return; + } + if (!flag && isRestElement(param)) { + flag = true; + } + }); + return flag; +} diff --git a/web-infras/parser/src/parser/js/module.ts b/web-infras/parser/src/parser/js/module.ts new file mode 100644 index 00000000..f4efb516 --- /dev/null +++ b/web-infras/parser/src/parser/js/module.ts @@ -0,0 +1,565 @@ +import { + ClassDeclaration, + ClassExpression, + cloneSourcePosition, + ExportAllDeclaration, + ExportDeclaration, + ExportDefaultDeclaration, + ExportNamedDeclarations, + ExportSpecifier, + Factory, + Identifier, + ImportAttribute, + ImportDeclaration, + ImportDefaultSpecifier, + ImportNamespaceSpecifier, + ImportSpecifier, + isIdentifer, + isStringLiteral, + Keywords, + ModuleItem, + SourcePosition, + StringLiteral, + SyntaxKinds, +} from "web-infra-common"; +import { ParserPlugin } from "@/src/parser/config"; +import { ErrorMessageMap } from "@/src/parser/error"; +import { ExportContext } from "@/src/parser/scope/lexicalScope"; +import { KeywordSet } from "@/src/parser/type"; +import { Parser } from "@/src/parser"; + +export function parseProgram(this: Parser) { + const body: Array = []; + this.enterProgram(); + while (!this.match(SyntaxKinds.EOFToken)) { + body.push(this.parseModuleItem()); + } + for (const propertyHasInit of this.context.propertiesInitSet) { + this.raiseError( + ErrorMessageMap.Syntax_error_Invalid_shorthand_property_initializer, + propertyHasInit.start, + ); + } + for (const duplicateProto of this.context.propertiesProtoDuplicateSet) { + this.raiseError( + ErrorMessageMap.syntax_error_property_name__proto__appears_more_than_once_in_object_literal, + duplicateProto.start, + ); + } + this.exitProgram(); + return Factory.createProgram( + body, + body.length === 0 ? this.getStartPosition() : cloneSourcePosition(body[0].start), + this.getEndPosition(), + ); +} +export function parseModuleItem(this: Parser): ModuleItem { + if (this.match(SyntaxKinds.AtPunctuator)) { + this.parseDecoratorListToCache(); + } + const token = this.getToken(); + switch (token) { + case SyntaxKinds.ImportKeyword: { + const { kind } = this.lookahead(); + if (kind === SyntaxKinds.DotOperator || kind === SyntaxKinds.ParenthesesLeftPunctuator) { + return this.parseStatementListItem(); + } + return this.parseImportDeclaration(); + } + case SyntaxKinds.ExportKeyword: + return this.parseExportDeclaration(); + default: + return this.parseStatementListItem(); + } +} +/** ================================================================================ + * Parse Import Declaration + * entry point: https://tc39.es/ecma262/#sec-imports + * ================================================================================== + */ +export function expectFormKeyword(this: Parser) { + if (this.getSourceValue() !== "from") { + throw this.createUnexpectError(); + } + if (this.getEscFlag()) { + this.raiseError(ErrorMessageMap.invalid_esc_char_in_keyword, this.getStartPosition()); + } + this.nextToken(); +} +/** + * Parse Import Declaration + * ``` + * ImportDeclaration := 'import' ImportClasue FromClause WithClause? + * := 'import' StringLiteral WithClause? + * FromClause := 'from' StringLiteral + * ImportClause := ImportDefaultBinding + * := ImportNamesapce + * := ImportNamed + * := ImportDefaultBindling ',' ImportNamed + * := ImportDefaultBindling ',' ImportNamespace + * ``` + * - frist, eat import keyword + * 1. if it is string literal, must be `import StringLiteral` + * 2. if it start with `*`, must be import name space + * 3. if it start with '{', must be import named + * 4. fallback case: default import with import named or import namesspace + * or nothing + * @returns {ImportDeclaration} + */ +export function parseImportDeclaration(this: Parser): ImportDeclaration { + const { start } = this.expect(SyntaxKinds.ImportKeyword); + if (this.config.sourceType === "script") { + this.raiseError( + ErrorMessageMap.babel_error_import_and_export_may_appear_only_with_sourceType_module, + start, + ); + } + const specifiers: Array = []; + if (this.match(SyntaxKinds.StringLiteral)) { + const source = this.parseStringLiteral(); + const attributes = this.parseImportAttributesOptional(); + this.shouldInsertSemi(); + return Factory.createImportDeclaration( + specifiers, + source, + attributes, + start, + cloneSourcePosition(source.end), + ); + } + if (this.match(SyntaxKinds.MultiplyOperator)) { + specifiers.push(this.parseImportNamespaceSpecifier()); + this.expectFormKeyword(); + const source = this.parseStringLiteral(); + const attributes = this.parseImportAttributesOptional(); + this.shouldInsertSemi(); + return Factory.createImportDeclaration( + specifiers, + source, + attributes, + start, + cloneSourcePosition(source.end), + ); + } + if (this.match(SyntaxKinds.BracesLeftPunctuator)) { + this.parseImportSpecifiers(specifiers); + this.expectFormKeyword(); + const source = this.parseStringLiteral(); + const attributes = this.parseImportAttributesOptional(); + this.shouldInsertSemi(); + return Factory.createImportDeclaration( + specifiers, + source, + attributes, + start, + cloneSourcePosition(source.end), + ); + } + specifiers.push(this.parseImportDefaultSpecifier()); + if (this.match(SyntaxKinds.CommaToken)) { + this.nextToken(); + if (this.match(SyntaxKinds.BracesLeftPunctuator)) { + this.parseImportSpecifiers(specifiers); + } else if (this.match(SyntaxKinds.MultiplyOperator)) { + specifiers.push(this.parseImportNamespaceSpecifier()); + } else { + throw this.createMessageError( + "import default specifier can only concat with namespace of import named specifier", + ); + } + } + this.expectFormKeyword(); + const source = this.parseStringLiteral(); + const attributes = this.parseImportAttributesOptional(); + this.shouldInsertSemi(); + return Factory.createImportDeclaration( + specifiers, + source, + attributes, + start, + cloneSourcePosition(source.end), + ); +} +/** + * Parse Default import binding + * ``` + * ImportDefaultBinding := Identifer + * ``` + * @returns {ImportDefaultSpecifier} + */ +export function parseImportDefaultSpecifier(this: Parser): ImportDefaultSpecifier { + const name = this.parseIdentifierReference(); + this.declarateLetSymbol(name.name, name.start); + return Factory.createImportDefaultSpecifier( + name, + cloneSourcePosition(name.start), + cloneSourcePosition(name.end), + ); +} +/** + * Parse namespace import + * ``` + * ImportNamespace := '*' 'as' Identifer + * ``` + * @returns {ImportNamespaceSpecifier} + */ +export function parseImportNamespaceSpecifier(this: Parser): ImportNamespaceSpecifier { + const { start } = this.expect(SyntaxKinds.MultiplyOperator); + if (!this.isContextKeyword("as")) { + this.raiseError(ErrorMessageMap.babel_error_unexpected_token_expected_as, this.getStartPosition()); + } + this.nextToken(); + const id = this.parseIdentifierReference(); + this.declarateLetSymbol(id.name, id.start); + return Factory.createImportNamespaceSpecifier(id, start, cloneSourcePosition(id.end)); +} +/** + * Parse Import Nameds + * ``` + * ImportNamed := '{' ImportList ','? '}' + * ImportList := [ ImportItem ] + * ImportItem := IdentiferWithKeyword + * := (Identifer | StringLiteral) 'as' Identifer + * ``` + * @param specifiers + * @return {void} + */ +export function parseImportSpecifiers( + this: Parser, + specifiers: Array, +): void { + this.expect(SyntaxKinds.BracesLeftPunctuator); + let isStart = true; + while (!this.match(SyntaxKinds.BracesRightPunctuator) && !this.match(SyntaxKinds.EOFToken)) { + if (isStart) { + isStart = false; + } else { + this.expect(SyntaxKinds.CommaToken); + } + if (this.match(SyntaxKinds.BracesRightPunctuator) || this.match(SyntaxKinds.EOFToken)) { + break; + } + const imported = this.parseModuleExportName(); + if (!this.isContextKeyword("as")) { + if (isIdentifer(imported) && KeywordSet.has(imported.name)) { + // recoverable error + this.raiseError(ErrorMessageMap.extra_error_unexpect_keyword_in_module_name, imported.start); + } else if (isStringLiteral(imported)) { + // recoverable error + this.raiseError( + ErrorMessageMap.babel_error_string_literal_cannot_be_used_as_an_imported_binding, + imported.start, + ); + } + if (isIdentifer(imported)) this.declarateLetSymbol(imported.name, imported.start); + specifiers.push( + Factory.createImportSpecifier( + imported, + null, + cloneSourcePosition(imported.start), + cloneSourcePosition(imported.end), + ), + ); + continue; + } + this.nextToken(); + const local = this.parseIdentifierReference(); + this.declarateLetSymbol(local.name, local.start); + specifiers.push( + Factory.createImportSpecifier( + imported, + local, + cloneSourcePosition(imported.start), + cloneSourcePosition(local.end), + ), + ); + } + this.expect(SyntaxKinds.BracesRightPunctuator); +} +export function parseImportAttributesOptional(this: Parser): ImportAttribute[] | undefined { + if ( + (this.requirePlugin(ParserPlugin.ImportAttribute) && this.match(SyntaxKinds.WithKeyword)) || + (this.requirePlugin(ParserPlugin.ImportAssertions) && + this.match(SyntaxKinds.Identifier) && + this.getSourceValue() === "assert") + ) { + this.nextToken(); + return this.parseImportAttributes(); + } + return undefined; +} +export function parseImportAttributes(this: Parser): ImportAttribute[] { + this.expect(SyntaxKinds.BracesLeftPunctuator); + const attributes: Array = [this.parseImportAttribute()]; + while (!this.match([SyntaxKinds.BracesRightPunctuator, SyntaxKinds.EOFToken])) { + this.expect(SyntaxKinds.CommaToken); + if (this.match([SyntaxKinds.BracesRightPunctuator, SyntaxKinds.EOFToken])) { + break; + } + attributes.push(this.parseImportAttribute()); + } + this.expect(SyntaxKinds.BracesRightPunctuator); + return attributes; +} +export function parseImportAttribute(this: Parser): ImportAttribute { + const key = this.parseIdentifierName(); + this.expect(SyntaxKinds.ColonPunctuator); + const value = this.parseStringLiteral(); + return Factory.createImportAttribute( + key, + value, + cloneSourcePosition(key.start), + cloneSourcePosition(value.end), + ); +} +/** ================================================================================ + * Parse Export Declaration + * entry point: https://tc39.es/ecma262/#prod-ExportDeclaration + * ================================================================================== + */ +/** + * Parse Export Declaration + * ``` + * ExportDeclaration := 'export' ExportNamedDeclaration ';'? + * := 'export' ExportDefaultDeclaration + * := 'export' ExportAllDeclaration + * ExportNamedDeclaration := '{' ExportList '}' ('from' StringLiteral)? + * := Declaration + * := VarStatement + * ExportAllDeclaration := '*' 'from' StringLiteral + * := '*' 'as' Identifer 'from' StringLiteral + * ``` + * @returns {ExportDeclaration} + */ +export function parseExportDeclaration(this: Parser): ExportDeclaration { + this.setExportContext(ExportContext.InExport); + + const { start } = this.expect(SyntaxKinds.ExportKeyword); + if (this.config.sourceType === "script") { + this.raiseError( + ErrorMessageMap.babel_error_import_and_export_may_appear_only_with_sourceType_module, + start, + ); + } + let exportDeclaration: ExportDeclaration; + switch (this.getToken()) { + case SyntaxKinds.DefaultKeyword: { + exportDeclaration = this.parseExportDefaultDeclaration(start); + break; + } + case SyntaxKinds.MultiplyOperator: { + exportDeclaration = this.parseExportAllDeclaration(start); + break; + } + case SyntaxKinds.BracesLeftPunctuator: { + exportDeclaration = this.parseExportNamedDeclaration(start); + break; + } + default: { + const declaration = this.match(SyntaxKinds.VarKeyword) + ? this.parseVariableDeclaration() + : this.parseDeclaration(); + exportDeclaration = Factory.createExportNamedDeclaration( + [], + declaration, + null, + start, + cloneSourcePosition(declaration.end), + ); + break; + } + } + this.setExportContext(ExportContext.NotInExport); + return exportDeclaration; +} +/** + * Parse default export declaration + * ``` + * ``` + * @param {SourcePosition} start + * @returns {ExportDefaultDeclaration} + */ +export function parseExportDefaultDeclaration(this: Parser, start: SourcePosition): ExportDefaultDeclaration { + this.expect(SyntaxKinds.DefaultKeyword); + switch (this.getToken()) { + case SyntaxKinds.ClassKeyword: + case SyntaxKinds.AtPunctuator: { + let decoratorList = this.takeCacheDecorator(); + if (this.match(SyntaxKinds.AtPunctuator)) { + decoratorList = this.mergeDecoratorList(decoratorList, this.parseDecoratorList()); + } + const classDeclar = Factory.transFormClassToClassDeclaration(this.parseClass(decoratorList)); + this.staticSematicForDuplicateDefaultExport(classDeclar); + return Factory.createExportDefaultDeclaration( + classDeclar as ClassDeclaration | ClassExpression, + start, + cloneSourcePosition(classDeclar.end), + ); + } + case SyntaxKinds.FunctionKeyword: { + const funcDeclar = this.parseFunctionDeclaration(false, true); + this.staticSematicForDuplicateDefaultExport(funcDeclar); + return Factory.createExportDefaultDeclaration(funcDeclar, start, cloneSourcePosition(funcDeclar.end)); + } + default: { + if (this.isContextKeyword("async") && this.lookahead().kind === SyntaxKinds.FunctionKeyword) { + this.nextToken(); + const funcDeclar = this.parseFunctionDeclaration(true, true); + // funcDeclar.async = true; + this.staticSematicForDuplicateDefaultExport(funcDeclar); + return Factory.createExportDefaultDeclaration(funcDeclar, start, cloneSourcePosition(funcDeclar.end)); + } + const typeDeclar = this.tryParseDeclarationWithIdentifierStart(); + if (typeDeclar) { + this.shouldInsertSemi(); + return Factory.createExportDefaultDeclaration( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + typeDeclar as any, + start, + this.getLastTokenEndPositon(), + ); + } + // TODO: parse export default from ""; (experimental feature) + const expr = this.parseAssignmentExpressionAllowIn(); + this.shouldInsertSemi(); + this.staticSematicForDuplicateDefaultExport(expr); + return Factory.createExportDefaultDeclaration(expr, start, cloneSourcePosition(expr.end)); + } + } +} +/** + * Using symbol scope recorder for record the default export. + * @param node + */ +export function staticSematicForDuplicateDefaultExport(this: Parser, node: ModuleItem) { + const isDefaultAlreadyBeDeclarated = this.symbolScopeRecorder.testAndSetDefaultExport(node.start); + if (isDefaultAlreadyBeDeclarated) { + this.raiseError(ErrorMessageMap.v8_error_duplicate_identifier, isDefaultAlreadyBeDeclarated); + } +} +export function parseExportNamedDeclaration(this: Parser, start: SourcePosition): ExportNamedDeclarations { + this.expect(SyntaxKinds.BracesLeftPunctuator); + const specifier: Array = []; + let isStart = true; + let isMatchKeyword = false; + const undefExportSymbols: Array<[string, SourcePosition]> = []; + while (!this.match(SyntaxKinds.BracesRightPunctuator) && !this.match(SyntaxKinds.EOFToken)) { + if (isStart) { + isStart = false; + } else { + this.expect(SyntaxKinds.CommaToken); + } + if (this.match(SyntaxKinds.BracesRightPunctuator) || this.match(SyntaxKinds.EOFToken)) { + break; + } + if (this.match(Keywords)) { + isMatchKeyword = true; + } + const exported = this.parseModuleExportName(); + if (!this.isVariableDeclarated(helperGetValueOfExportName(exported))) { + undefExportSymbols.push([helperGetValueOfExportName(exported), exported.start]); + } + if (this.isContextKeyword("as")) { + this.nextToken(); + const local = this.parseModuleExportName(); + this.staticSematicForDuplicateExportName(local); + specifier.push( + Factory.createExportSpecifier( + exported, + local, + cloneSourcePosition(exported.start), + cloneSourcePosition(local.end), + ), + ); + continue; + } + this.staticSematicForDuplicateExportName(exported); + specifier.push( + Factory.createExportSpecifier( + exported, + null, + cloneSourcePosition(exported.start), + cloneSourcePosition(exported.end), + ), + ); + } + const { end: bracesRightPunctuatorEnd } = this.expect(SyntaxKinds.BracesRightPunctuator); + let source: StringLiteral | null = null; + if (this.getSourceValue() === "from") { + this.nextToken(); + source = this.parseStringLiteral(); + } else { + if (isMatchKeyword) { + throw new Error(); + } + if (undefExportSymbols.length > 0) { + undefExportSymbols.forEach(([sym, pos]) => { + this.symbolScopeRecorder.addToUndefExportSource(sym, pos); + }); + } + this.staticSematicEarlyErrorForExportName(specifier); + } + this.shouldInsertSemi(); + const end = source + ? source.end + : specifier.length === 0 + ? bracesRightPunctuatorEnd + : specifier[specifier.length - 1].end; + return Factory.createExportNamedDeclaration(specifier, null, source, start, cloneSourcePosition(end)); +} +/** + * Static Sematic Check based on + * - 16.2.3.1 Static Semantics: Early Errors + * @param specifiers + */ +export function staticSematicEarlyErrorForExportName(this: Parser, specifiers: Array) { + for (const specifier of specifiers) { + if (isStringLiteral(specifier.exported)) { + this.raiseError( + ErrorMessageMap.babel_error_string_literal_cannot_be_used_as_an_exported_binding_without_from, + specifier.exported.start, + ); + } + } +} +/** + * Using symbol scope recorder for record export name identifier + * @param exportName + */ +export function staticSematicForDuplicateExportName(this: Parser, exportName: StringLiteral | Identifier) { + const name = helperGetValueOfExportName(exportName); + const isExportNameAlreadyBeDeclar = this.declarateExportSymbol(name, exportName.start); + if (isExportNameAlreadyBeDeclar) { + this.raiseError(ErrorMessageMap.v8_error_duplicate_identifier, isExportNameAlreadyBeDeclar); + } + const isDefaultAlreadyBeDeclarated = this.symbolScopeRecorder.testAndSetDefaultExport(exportName.start); + if (name === "default" && isDefaultAlreadyBeDeclarated) { + this.raiseError(ErrorMessageMap.v8_error_duplicate_identifier, isDefaultAlreadyBeDeclarated); + } +} +export function parseExportAllDeclaration(this: Parser, start: SourcePosition): ExportAllDeclaration { + this.expect(SyntaxKinds.MultiplyOperator); + let exported: Identifier | StringLiteral | null = null; + if (this.isContextKeyword("as")) { + this.nextToken(); + exported = this.parseModuleExportName(); + } else { + exported = null; + } + this.expectFormKeyword(); + const source = this.parseStringLiteral(); + this.shouldInsertSemi(); + return Factory.createExportAllDeclaration(exported, source, start, cloneSourcePosition(source.end)); +} +export function parseModuleExportName(this: Parser) { + if (this.match(SyntaxKinds.StringLiteral)) { + return this.parseStringLiteral(); + } + return this.parseIdentifierName(); +} +export function helperGetValueOfExportName(exportName: StringLiteral | Identifier) { + if (isIdentifer(exportName)) { + return exportName.name; + } + return exportName.value; +} diff --git a/web-infras/parser/src/parser/js/pattern.ts b/web-infras/parser/src/parser/js/pattern.ts new file mode 100644 index 00000000..bd1dcc18 --- /dev/null +++ b/web-infras/parser/src/parser/js/pattern.ts @@ -0,0 +1,710 @@ +import { + ArrayExpression, + ArrayPattern, + AssigmentExpression, + AssignmentPattern, + cloneSourcePosition, + Expression, + Factory, + Identifier, + isArrayPattern, + isAssignmentPattern, + isIdentifer, + isMemberExpression, + isObjectPattern, + isObjectPatternProperty, + isPattern, + isRestElement, + isSpreadElement, + ModuleItem, + ObjectExpression, + ObjectPattern, + ObjectPatternProperty, + ObjectProperty, + Pattern, + PropertyName, + RestElement, + SourcePosition, + SpreadElement, + SyntaxKinds, +} from "web-infra-common"; +import { Parser } from ".."; +import { ErrorMessageMap } from "@/src/parser/error"; +import { ExpressionScopeKind } from "@/src/parser/scope/type"; +import { + BindingIdentifierSyntaxKindArray, + IdentiferWithKeyworArray, + KeywordSet, + PreserveWordSet, +} from "@/src/parser/type"; + +/** + * This is a critial helper function for transform expression (major is ObjectExpression + * and ArrayExpression) to Pattern (`BindingObjectPattern`, `BindingArrayPattern`, `AssignmentObjectPattern` + * `AssignmentArrayPattern`). + * + * ### Use Case : ParseAssignmentExpression + * This function is used when `parseAssignmentExpression`, because parseAssignmentExpression + * would parse left as expression first, when left is followed by assignment operator, we need + * to transform expression to AssignmentPattern. + * + * ### Use Case : ParseArrowFunctionExpression + * When `parseArrowFunctionExpression`, it would use this function too. Because `parseArrowFunctionExpresssion` + * might accept argument (array of `AssignmentExpression`) as param, so we need to transform arguments to function + * parameter, which is transform `AssignmenExpression` to `BiningElement`(`Identifier` or `BindingPattern`). + * + * ### Paramemter: isBinding + * Most of BindingPattern and AssignmentPattern's production rule is alike, one key different is that BindingPattern + * `PropertyName` can only have `BindingElement`, but `PropertyName` of AssignmentPattern can have LeftHandSideExpression + * so we add a param `isBinding` to determinate is transform to BindingPattern or not. + * @param {Expression} expr target for transform to Pattern + * @param {boolean} isBinding Is transform to BindingPattern + */ +export function exprToPattern(this: Parser, expr: Expression, isBinding: boolean): Pattern { + // TODO, remove impl function. + return this.exprToPatternImpl(expr, isBinding); +} +export function exprToPatternImpl(this: Parser, node: Expression, isBinding: boolean): Pattern { + /** + * parentheses in pattern only allow in Assignment Pattern + * for MemberExpression and Identifier + */ + if (node.parentheses) { + if (!isParanValidationInPattern(isBinding, node)) + // recoverable error + this.raiseError(ErrorMessageMap.babel_error_invalid_parenthesized_pattern, node.start); + } + switch (node.kind) { + case SyntaxKinds.TSAsExpression: + case SyntaxKinds.TSTypeAssertionExpression: + case SyntaxKinds.TSSatisfiesExpression: + case SyntaxKinds.TSNonNullExpression: + if (!isBinding) { + // only accept id, member expression and nested TS expression. + node.expression = this.exprToPattern(node.expression, isBinding) as Expression; + return node; + } else { + throw this.createMessageError(ErrorMessageMap.syntax_error_invalid_assignment_left_hand_side); + } + case SyntaxKinds.AssigmentExpression: { + return this.assignmentExpressionToAssignmentPattern(node, isBinding); + } + case SyntaxKinds.SpreadElement: { + return this.spreadElementToFunctionRestParameter(node); + } + case SyntaxKinds.ArrayExpression: { + return this.arrayExpressionToArrayPattern(node, isBinding); + } + case SyntaxKinds.ObjectExpression: { + return this.objectExpressionToObjectPattern(node, isBinding); + } + case SyntaxKinds.Identifier: + this.declarateSymbolInBindingPatternAsParam(node.name, isBinding, node.start); + return node as Identifier; + case SyntaxKinds.MemberExpression: + if (!isBinding) { + return node as Pattern; + } + // fall to error + // eslint-disable-next-line no-fallthrough + default: + throw this.createMessageError(ErrorMessageMap.syntax_error_invalid_assignment_left_hand_side); + } +} +export function isParanValidationInPattern(isBinding: boolean, expr: Expression): boolean { + if (isBinding) return false; + return isAssignable(expr); +} +/** + * Is a node match the DestructuringAssignmentTarget in ECMA spec. + * @param node + * @returns + */ +export function isAssignable(node: ModuleItem) { + switch (node.kind) { + case SyntaxKinds.Identifier: + case SyntaxKinds.MemberExpression: + return true; + case SyntaxKinds.TSAsExpression: + case SyntaxKinds.TSTypeAssertionExpression: + case SyntaxKinds.TSSatisfiesExpression: + case SyntaxKinds.TSNonNullExpression: + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return isAssignable((node as any).expression); + default: + return false; + } +} +/** + * ## Transform Assignment Expression + * @param expr + * @param isBinding + * @returns + */ +export function assignmentExpressionToAssignmentPattern( + this: Parser, + expr: AssigmentExpression, + isBinding: boolean, +) { + const left = isBinding ? this.helperCheckPatternWithBinding(expr.left) : expr.left; + if (expr.operator !== SyntaxKinds.AssginOperator) { + this.raiseError(ErrorMessageMap.syntax_error_invalid_assignment_left_hand_side, expr.start); + } + return Factory.createAssignmentPattern( + left as Pattern, + expr.right, + undefined, + undefined, + expr.start, + expr.end, + ); +} +/** + * Transform a assignment pattern to a binding assignment pattern + * @param leftValue + * @returns + */ +export function helperCheckPatternWithBinding(this: Parser, leftValue: Pattern): Pattern { + if (isObjectPattern(leftValue)) { + for (const property of leftValue.properties) { + if (isObjectPatternProperty(property)) { + if (property.value && isMemberExpression(property.value)) { + this.raiseError(ErrorMessageMap.babel_error_binding_member_expression, property.start); + } + if (property.value && isAssignable(property.value) && (property.value as Expression).parentheses) { + // recoverable error + this.raiseError(ErrorMessageMap.babel_error_invalid_parenthesized_pattern, leftValue.start); + } + } + } + return leftValue; + } + if (isAssignmentPattern(leftValue)) { + this.helperCheckPatternWithBinding(leftValue.left); + return leftValue; + } + if (isRestElement(leftValue)) { + this.helperCheckPatternWithBinding(leftValue.argument); + return leftValue; + } + if (isArrayPattern(leftValue)) { + for (const pat of leftValue.elements) { + if (pat) { + this.helperCheckPatternWithBinding(pat); + } + } + } + if (isAssignable(leftValue)) { + const expr = leftValue as Expression; + if (expr.parentheses) { + // recoverable error + this.raiseError(ErrorMessageMap.babel_error_invalid_parenthesized_pattern, leftValue.start); + } + } + return leftValue; +} +/** + * ## Transform `SpreadElement` to RestElement in function param + * + * Accoring to production rule, `FunctionRestParameter` is just alias + * of `BindingRestElement` which be used in ArrayPattern. + * @param spreadElement + * @returns + */ +export function spreadElementToFunctionRestParameter(this: Parser, spreadElement: SpreadElement) { + return this.spreadElementToArrayRestElement(spreadElement, true); +} +/** + * ## Transform `ArrayExpression` to `ArrayPattern` + * @param elements + * @param isBinding + * @returns + */ +export function arrayExpressionToArrayPattern( + this: Parser, + expr: ArrayExpression, + isBinding: boolean, +): ArrayPattern { + const arrayPatternElements: Array = []; + const restElementIndexs = []; + for (let index = 0; index < expr.elements.length; ++index) { + const element = expr.elements[index]; + if (!element) { + arrayPatternElements.push(null); + continue; + } + if (isSpreadElement(element)) { + arrayPatternElements.push(this.spreadElementToArrayRestElement(element, isBinding)); + restElementIndexs.push(index); + continue; + } + arrayPatternElements.push(this.exprToPattern(element, isBinding)); + } + if ( + restElementIndexs.length > 1 || + (restElementIndexs.length === 1 && + (restElementIndexs[0] !== arrayPatternElements.length - 1 || expr.trailingComma)) + ) { + this.raiseError(ErrorMessageMap.syntax_error_parameter_after_rest_parameter, expr.end); + } + return Factory.createArrayPattern(arrayPatternElements, undefined, undefined, expr.start, expr.end); +} +/** + * ## Transform `SpreadElement` in ArrayPattern + * This function transform spread element to following two production rule AST: + * + * - `BindingRestElement` in `ArrayBindingPattern` + * - `AssignmentRestElement` in `ArrayAssignmentPattern` + * + * According to production rule, `BindingRestElement`'s argument can only be identifier or ObjectPattern + * or ArrayPattern, and argument of `AssignmentRestElement` can only be identifier or memberExpression. + * ``` + * BindingRestElement := ... BindingIdentifier + * := ... BindingPattern + * AssignmentRestElement :=... DestructuringAssignmentTarget + * ``` + * @param spreadElement + * @param isBinding + */ +export function spreadElementToArrayRestElement( + this: Parser, + spreadElement: SpreadElement, + isBinding: boolean, +): RestElement { + const argument = this.exprToPattern(spreadElement.argument, isBinding); + if (isAssignmentPattern(argument)) { + // recoverable error + this.raiseError( + ErrorMessageMap.v8_error_rest_assignment_property_must_be_followed_by_an_identifier_in_declaration_contexts, + argument.start, + ); + } + return Factory.createRestElement(argument, undefined, undefined, spreadElement.start, argument.end); +} +/** + * ## Transform `ObjectExpression` To `ObjectPattern` + * @param properties + * @param isBinding + * @returns + */ +export function objectExpressionToObjectPattern( + this: Parser, + expr: ObjectExpression, + isBinding: boolean, +): ObjectPattern { + const objectPatternProperties: Array = []; + const restElementIndexs = []; + for (let index = 0; index < expr.properties.length; ++index) { + const property = expr.properties[index]; + switch (property.kind) { + case SyntaxKinds.ObjectProperty: + objectPatternProperties.push(this.ObjectPropertyToObjectPatternProperty(property, isBinding)); + break; + case SyntaxKinds.SpreadElement: + restElementIndexs.push(index); + objectPatternProperties.push(this.spreadElementToObjectRestElement(property, isBinding)); + break; + default: + throw this.createMessageError(ErrorMessageMap.invalid_left_value); + } + } + if ( + restElementIndexs.length > 1 || + (restElementIndexs.length === 1 && + (restElementIndexs[0] !== objectPatternProperties.length - 1 || expr.trailingComma)) + ) { + this.raiseError(ErrorMessageMap.syntax_error_parameter_after_rest_parameter, expr.end); + } + return Factory.createObjectPattern(objectPatternProperties, undefined, undefined, expr.start, expr.end); +} +/** + * ## Transform `SpreadElement` in ObjectPattern + * This function transform spread element to following two production rule AST: + * + * - `BindingRestProperty` in BindingObjectPattern + * - `AssignmentRestProperty` in AssignObjectPattern + * + * According to production rule, `BindingRestProperty`'s argument can only be identifier, + * and argument of `AssignmentRestProperty` can only be identifier or memberExpression. + * ``` + * BindingRestProperty := ... BindingIdentifier + * AssignmentRestProperty:= ... DestructuringAssignmentTarget + * ``` + */ +export function spreadElementToObjectRestElement( + this: Parser, + spreadElement: SpreadElement, + isBinding: boolean, +): RestElement { + const argument = this.exprToPattern(spreadElement.argument, isBinding); + if (isBinding) { + if (!isIdentifer(argument)) { + // recoverable error + this.raiseError( + ErrorMessageMap.v8_error_rest_binding_property_must_be_followed_by_an_identifier_in_declaration_contexts, + argument.start, + ); + } + } else { + if (!isAssignable(argument)) { + // recoverable error + this.raiseError( + ErrorMessageMap.v8_error_rest_assignment_property_must_be_followed_by_an_identifier_in_declaration_contexts, + argument.start, + ); + } + } + return Factory.createRestElement(argument, undefined, undefined, spreadElement.start, argument.end); +} +export function ObjectPropertyToObjectPatternProperty( + this: Parser, + objectPropertyNode: ObjectProperty, + isBinding = false, +): ObjectPatternProperty | AssignmentPattern { + // object property's value can not has parentheses. + if (objectPropertyNode.value && objectPropertyNode.value.parentheses && isBinding) { + // recoverable error + this.raiseError(ErrorMessageMap.babel_error_invalid_parenthesized_pattern, objectPropertyNode.start); + } + if (this.context.propertiesProtoDuplicateSet.has(objectPropertyNode.key)) { + this.context.propertiesProtoDuplicateSet.delete(objectPropertyNode.key); + } + // When a property name is a CoverInitializedName, we need to cover to assignment pattern + if (this.context.propertiesInitSet.has(objectPropertyNode) && !objectPropertyNode.shorted) { + this.context.propertiesInitSet.delete(objectPropertyNode); + if (objectPropertyNode.computed || !isIdentifer(objectPropertyNode.key)) { + // property name of assignment pattern can not use computed propertyname or literal + throw this.createMessageError( + ErrorMessageMap.assignment_pattern_left_value_can_only_be_idenifier_or_pattern, + ); + } + this.declarateSymbolInBindingPatternAsParam( + objectPropertyNode.key.name, + isBinding, + objectPropertyNode.start, + ); + return Factory.createAssignmentPattern( + objectPropertyNode.key, + objectPropertyNode.value as Expression, + undefined, + undefined, + objectPropertyNode.start, + objectPropertyNode.end, + ); + } + const patternValue = !objectPropertyNode.value + ? objectPropertyNode.value + : this.exprToPatternImpl(objectPropertyNode.value, isBinding); + // for binding pattern, member expression is not allow + // - for assignment pattern: value production rule is `DestructuringAssignmentTarget`, which just a LeftHandSideExpression + // - for binding pattern: value production rule is `BindingElement`, which only can be object-pattern, array-pattern, id. + if (isBinding && patternValue && isMemberExpression(patternValue)) { + this.raiseError(ErrorMessageMap.babel_error_binding_member_expression, patternValue.start); + } + return Factory.createObjectPatternProperty( + objectPropertyNode.key, + patternValue, + objectPropertyNode.computed, + objectPropertyNode.shorted, + objectPropertyNode.start, + objectPropertyNode.end, + ); +} +export function declarateSymbolInBindingPatternAsParam( + this: Parser, + name: string, + isBinding: boolean, + position: SourcePosition, +) { + if (isBinding) { + this.declarateParam(name, position); + } +} +/** ================================================================================ + * Parse Pattern + * entry point: https://tc39.es/ecma262/#sec-destructuring-binding-patterns + * ================================================================================== + */ +/** + * Parse BindingElement + * ``` + * BindingElemet := Identifer ('=' AssigmentExpression)? + * := BindingPattern ('=' AssigmentExpression)? + * ``` + * @returns + */ +export function parseBindingElement(this: Parser, shouldParseAssignment = true): Pattern { + this.expectButNotEat([ + ...IdentiferWithKeyworArray, + SyntaxKinds.BracesLeftPunctuator, + SyntaxKinds.BracketLeftPunctuator, + ]); + let left: Pattern | undefined; + if (this.match(BindingIdentifierSyntaxKindArray)) { + left = this.parseBindingIdentifier(); + } else { + left = this.parseBindingPattern(); + } + if (this.match(SyntaxKinds.AssginOperator) && shouldParseAssignment) { + return this.parseDefaultValueForBindingElement(left); + } + return left; +} +export function parseDefaultValueForBindingElement(this: Parser, left: Pattern) { + this.expect(SyntaxKinds.AssginOperator); + const right = this.parseWithRHSLayer(() => this.parseAssignmentExpressionAllowIn()); + return Factory.createAssignmentPattern( + left, + right, + undefined, + undefined, + cloneSourcePosition(left.start), + cloneSourcePosition(right.end), + ); +} +export function parseRestElement(this: Parser, allowPattern: boolean): RestElement { + const { start } = this.expect([SyntaxKinds.SpreadOperator]); + let id: Pattern | null = null; + if (this.match(BindingIdentifierSyntaxKindArray)) { + id = this.parseBindingIdentifier(); + } + if (this.match([SyntaxKinds.BracesLeftPunctuator, SyntaxKinds.BracketLeftPunctuator])) { + if (allowPattern) { + id = this.parseBindingPattern(); + } + if (!allowPattern) { + // recoverable error ? + throw this.createUnexpectError(); + } + } + if (!id) { + throw this.createUnexpectError(); + } + return Factory.createRestElement(id, undefined, undefined, start, cloneSourcePosition(id.end)); +} +export function parseBindingIdentifier(this: Parser) { + const id = this.parseWithLHSLayer(() => this.parseIdentifierReference()); + this.declarateNonFunctionalSymbol(id.name, id.start); + return id; +} +/** + * Parse BindingPattern + * ``` + * BindingPattern := ObjectPattern + * := ArrayPattern + * ``` + */ +export function parseBindingPattern(this: Parser): ObjectPattern | ArrayPattern { + return this.parseWithLHSLayer(() => { + this.expectButNotEat([SyntaxKinds.BracesLeftPunctuator, SyntaxKinds.BracketLeftPunctuator]); + if (this.match(SyntaxKinds.BracesLeftPunctuator)) { + return this.parseObjectPattern(); + } + return this.parseArrayPattern(); + }); +} +/** Parse Object Pattern + * ``` + * ObjectPattern := '{' ObjectPatternProperties '}' + * := '{' ObjtecPatternProperties ',' '}' + * := '{' ObjectPatternProperties ',' RestElement '}' + * := '{' RestElement '} + * ObjectPatternProperties := ObjectPatternProperties ',' ObjectPatternProperty + * ObjectPatternProperty := Identifer ('=' AssigmentExpression) + * := BindingPattern ('=' AssignmentExpression) + * ``` + * @return {ObjectPattern} + */ +export function parseObjectPattern(this: Parser): ObjectPattern { + const { start } = this.expect(SyntaxKinds.BracesLeftPunctuator); + if (this.match(SyntaxKinds.BracesRightPunctuator)) { + const end = this.getEndPosition(); + this.nextToken(); + const objectPattern = Factory.createObjectPattern([], undefined, undefined, start, end); + return objectPattern; + } + const properties: Array = [ + this.parseObjectPatternPossibelProperty(), + ]; + while (!this.match([SyntaxKinds.BracesRightPunctuator, SyntaxKinds.EOFToken])) { + this.expect(SyntaxKinds.CommaToken); + if (this.match(SyntaxKinds.BracesRightPunctuator) || this.match(SyntaxKinds.EOFToken)) { + continue; + } + properties.push(this.parseObjectPatternPossibelProperty()); + } + const { end } = this.expect(SyntaxKinds.BracesRightPunctuator); + const objectPattern = Factory.createObjectPattern(properties, undefined, undefined, start, end); + return objectPattern; +} +export function parseObjectPatternPossibelProperty( + this: Parser, +): ObjectPatternProperty | RestElement | AssignmentPattern { + // parse Rest property + if (this.match(SyntaxKinds.SpreadOperator)) { + const rest = this.parseRestElement(false); + this.staticSematicForRestElementInObjectPattern(); + return rest; + } + // parse Object pattern property (rename) + const isComputedRef = { isComputed: false }; + const propertyName = this.parsePropertyName(isComputedRef); + if (isComputedRef.isComputed || this.match(SyntaxKinds.ColonPunctuator)) { + this.nextToken(); + const pattern = this.parseBindingElement(); + return Factory.createObjectPatternProperty( + propertyName, + pattern, + isComputedRef.isComputed, + false, + cloneSourcePosition(propertyName.start), + cloneSourcePosition(pattern.end), + ); + } + this.staticCheckForPropertyNameAsSingleBinding(propertyName); + // parse object pattern as Assignment pattern + if (this.match(SyntaxKinds.AssginOperator)) { + this.nextToken(); + const expr = this.parseWithRHSLayer(() => this.parseAssignmentExpressionAllowIn()); + this.staticSematicForAssignmentPatternInObjectPattern(propertyName); + this.declarateNonFunctionalSymbol((propertyName as Identifier).name, propertyName.start); + return Factory.createAssignmentPattern( + propertyName as Pattern, + expr, + undefined, + undefined, + cloneSourcePosition(propertyName.start), + cloneSourcePosition(expr.end), + ); + } + // parse object pattern as shorted property. + this.staticSematicForShortedPropertyNameInObjectLike(propertyName); + this.declarateNonFunctionalSymbol((propertyName as Identifier).name, propertyName.start); + return Factory.createObjectPatternProperty( + propertyName, + undefined, + isComputedRef.isComputed, + true, + cloneSourcePosition(propertyName.start), + cloneSourcePosition(propertyName.end), + ); +} +/** + * In Object Pattern, Rest Element should be last one, and can + * not have trailing comma. + */ +export function staticSematicForRestElementInObjectPattern(this: Parser) { + if ( + !this.match(SyntaxKinds.BracesRightPunctuator) || + (this.match(SyntaxKinds.CommaToken) && this.lookahead().kind === SyntaxKinds.BracesRightPunctuator) + ) { + // recoverable error + this.raiseError( + ErrorMessageMap.babel_error_unexpected_trailing_comma_after_rest_element, + this.getStartPosition(), + ); + } +} +/** + * Ban some usage like `{ "string-key" = "name" }` in onject pattern + * @param propertyName + */ +export function staticSematicForAssignmentPatternInObjectPattern(this: Parser, propertyName: PropertyName) { + if (!isPattern(propertyName)) { + throw this.createMessageError("assignment pattern left value can only allow identifier or pattern"); + } +} +/** + * As for shorted and assignment patern in object pattern, the property name should be + * a bidning identifier, so we need to check and record the property name. + * @param propertyName + * @returns + */ +export function staticCheckForPropertyNameAsSingleBinding(this: Parser, propertyName: PropertyName) { + if (isIdentifer(propertyName)) { + switch (propertyName.name) { + case "await": { + if (this.isCurrentScopeParseAwaitAsExpression() || this.config.sourceType === "module") { + this.raiseError( + ErrorMessageMap.babel_error_can_not_use_await_as_identifier_inside_an_async_function, + propertyName.start, + ); + } + return; + } + case "yield": { + if (this.isCurrentScopeParseYieldAsExpression() || this.isInStrictMode()) { + this.raiseError(ErrorMessageMap.babel_error_invalid_yield, propertyName.start); + } + return; + } + case "arguments": { + if (this.isInStrictMode() && this.strictModeScopeRecorder.isInLHS()) { + this.raiseError(ErrorMessageMap.syntax_error_bad_strict_arguments_eval, propertyName.start); + } + this.recordScope(ExpressionScopeKind.ArgumentsIdentifier, propertyName.start); + return; + } + case "eval": { + if (this.isInStrictMode() && this.strictModeScopeRecorder.isInLHS()) { + this.raiseError(ErrorMessageMap.syntax_error_bad_strict_arguments_eval, propertyName.start); + } + this.recordScope(ExpressionScopeKind.EvalIdentifier, propertyName.start); + return; + } + case "let": { + if (this.isInStrictMode()) { + this.raiseError(ErrorMessageMap.babel_error_unexpected_keyword, propertyName.start); + } + this.recordScope(ExpressionScopeKind.LetIdentifiier, propertyName.start); + return; + } + default: { + if (KeywordSet.has(propertyName.name)) { + // recoverable error + this.raiseError(ErrorMessageMap.babel_error_unexpected_keyword, propertyName.start); + } + if (PreserveWordSet.has(propertyName.name) && this.isInStrictMode()) { + // recoverable error + this.raiseError(ErrorMessageMap.babel_error_unexpected_reserved_word, propertyName.start); + } + return; + } + } + } +} +export function parseArrayPattern(this: Parser): ArrayPattern { + const { start } = this.expect(SyntaxKinds.BracketLeftPunctuator); + let isStart = true; + const elements: Array = []; + while (!this.match(SyntaxKinds.BracketRightPunctuator) && !this.match(SyntaxKinds.EOFToken)) { + if (isStart) { + isStart = false; + } else { + this.expect(SyntaxKinds.CommaToken); + } + if (this.match(SyntaxKinds.BracketRightPunctuator) || this.match(SyntaxKinds.EOFToken)) { + continue; + } + if (this.match(SyntaxKinds.CommaToken)) { + elements.push(null); + continue; + } + if (this.match(SyntaxKinds.SpreadOperator)) { + elements.push(this.parseRestElement(true)); + if (!this.match(SyntaxKinds.BracketRightPunctuator)) { + // recoverable error + this.raiseError( + ErrorMessageMap.babel_error_unexpected_trailing_comma_after_rest_element, + this.getStartPosition(), + ); + } + break; + } + const pattern = this.parseBindingElement(); + elements.push(pattern); + } + const { end } = this.expect(SyntaxKinds.BracketRightPunctuator); + const arrayPattern = Factory.createArrayPattern(elements, undefined, undefined, start, end); + return arrayPattern; +} diff --git a/web-infras/parser/src/parser/js/statement.ts b/web-infras/parser/src/parser/js/statement.ts new file mode 100644 index 00000000..a0526741 --- /dev/null +++ b/web-infras/parser/src/parser/js/statement.ts @@ -0,0 +1,729 @@ +import { + BlockStatement, + BreakStatement, + CatchClause, + cloneSourcePosition, + ContinueStatement, + DebuggerStatement, + DoWhileStatement, + EmptyStatement, + Expression, + Factory, + ForInStatement, + ForOfStatement, + ForStatement, + FunctionDeclaration, + Identifier, + IfStatement, + isArrayPattern, + isAssignmentPattern, + isFunctionDeclaration, + isIdentifer, + isObjectPattern, + isVarDeclaration, + LabeledStatement, + ReturnStatement, + SourcePosition, + Statement, + StatementListItem, + SwitchCase, + SyntaxKinds, + TryStatement, + TSParameter, + VariableDeclaration, + WhileStatement, + WithStatement, +} from "web-infra-common"; +import { ErrorMessageMap } from "@/src/parser/error"; +import { SymbolType } from "@/src/parser/scope/symbolScope"; +import { Parser } from "@/src/parser"; +import { ASTArrayWithMetaData } from "@/src/parser/type"; + +export function parseStatementListItem(this: Parser): StatementListItem { + const token = this.getToken(); + switch (token) { + // 'aync' maybe is + // 1. aync function -> declaration + // 2. aync arrow function -> statement(expressionStatement) + // 3. identifer -> statement (expressionStatement) + case SyntaxKinds.ConstKeyword: + case SyntaxKinds.FunctionKeyword: + case SyntaxKinds.ClassKeyword: + case SyntaxKinds.AtPunctuator: + case SyntaxKinds.EnumKeyword: + return this.parseDeclaration(); + case SyntaxKinds.Identifier: { + const declar = this.tryParseDeclarationWithIdentifierStart(); + if (!declar) { + return this.parseStatement(); + } + return declar; + } + case SyntaxKinds.LetKeyword: + if (this.isLetPossibleIdentifier()) { + return this.parseStatement(); + } + return this.parseDeclaration(); + default: + return this.parseStatement(); + } +} +export function isLetPossibleIdentifier(this: Parser) { + const { kind: kind } = this.lookahead(); + if ( + kind === SyntaxKinds.BracesLeftPunctuator || // object pattern + kind === SyntaxKinds.BracketLeftPunctuator || // array pattern + kind === SyntaxKinds.Identifier || // id + kind === SyntaxKinds.AwaitKeyword || + kind === SyntaxKinds.YieldKeyword + ) { + return false; + } + return true; +} +/** + * ref: https://tc39.es/ecma262/#prod-Statement + */ +export function parseStatement(this: Parser): Statement { + const token = this.getToken(); + switch (token) { + case SyntaxKinds.SwitchKeyword: + return this.parseSwitchStatement(); + case SyntaxKinds.ContinueKeyword: + return this.parseContinueStatement(); + case SyntaxKinds.BreakKeyword: + return this.parseBreakStatement(); + case SyntaxKinds.ReturnKeyword: + return this.parseReturnStatement(); + case SyntaxKinds.BracesLeftPunctuator: + return this.parseBlockStatement(); + case SyntaxKinds.TryKeyword: + return this.parseTryStatement(); + case SyntaxKinds.ThrowKeyword: + return this.parseThrowStatement(); + case SyntaxKinds.WithKeyword: + return this.parseWithStatement(); + case SyntaxKinds.DebuggerKeyword: + return this.parseDebuggerStatement(); + case SyntaxKinds.SemiPunctuator: + return this.parseEmptyStatement(); + case SyntaxKinds.IfKeyword: + return this.parseIfStatement(); + case SyntaxKinds.ForKeyword: + return this.parseForStatement(); + case SyntaxKinds.WhileKeyword: + return this.parseWhileStatement(); + case SyntaxKinds.DoKeyword: + return this.parseDoWhileStatement(); + case SyntaxKinds.VarKeyword: + return this.parseVariableDeclaration(); + default: + if (this.match(SyntaxKinds.Identifier) && this.lookahead().kind === SyntaxKinds.ColonPunctuator) { + return this.parseLabeledStatement(); + } + return this.parseExpressionStatement(); + } +} + +/** + * Parse For-related Statement, include ForStatement, ForInStatement, ForOfStatement. + * + * This function is pretty complex and hard to understand, some function's flag is only + * used in this function. ex: allowIn flag of parseExpression, parseAssignmentExpression. + * @returns {ForStatement | ForInStatement | ForOfStatement} + */ +export function parseForStatement(this: Parser): ForStatement | ForInStatement | ForOfStatement { + // symbolScopeRecorder.enterPreBlockScope(); + this.symbolScopeRecorder.enterBlockSymbolScope(); + const { start: keywordStart } = this.expect(SyntaxKinds.ForKeyword); + // First, parse await modifier and lefthandside or init of for-related statement, + // init might start with let, const, var keyword, but if is let keyword need to + // lookahead to determinate is identifier. + // delcaration in there should not eat semi, becuase semi is seperator of ForStatement, + // and might not need init for pattern, because maybe used by ForIn or ForOf. + // If not start with let, var or const keyword, it should be expression, but this + // expression can not take `in` operator as operator in toplevel, so we need pass + // false to disallow parseExpression to take in as operator + let isAwait: SourcePosition | null = null, + isParseLetAsExpr: SourcePosition | null = null, + leftOrInit: VariableDeclaration | Expression | null = null; + if (this.match(SyntaxKinds.AwaitKeyword)) { + isAwait = this.getStartPosition(); + this.nextToken(); + if (!this.config.allowAwaitOutsideFunction && !this.isCurrentScopeParseAwaitAsExpression()) { + this.raiseError(ErrorMessageMap.babel_error_invalid_await, isAwait); + } + } + this.expect(SyntaxKinds.ParenthesesLeftPunctuator); + if (this.match([SyntaxKinds.LetKeyword, SyntaxKinds.ConstKeyword, SyntaxKinds.VarKeyword])) { + if (this.match(SyntaxKinds.LetKeyword) && this.isLetPossibleIdentifier()) { + isParseLetAsExpr = this.getStartPosition(); + leftOrInit = this.parseExpressionDisallowIn(); + } else { + leftOrInit = this.disAllowInOperaotr(() => this.parseVariableDeclaration(true)); + } + } else if (this.match(SyntaxKinds.SemiPunctuator)) { + // for test case `for(;;)` + leftOrInit = null; + } else { + leftOrInit = this.parseExpressionDisallowIn(); + } + // Second is branching part, determinate the branch by following token + // - if start with semi it should be ForStatement, + // - if is in operator, it should be ForInStatement, + // - if is of contextual keyword, it should be ForOfStatement. + // then according to branch case, parse the following part and do the + // sematic check. + // - ForStatement: if init is variable declaration pattern, it need init. + // - ForInStatement: if left is variable decalration, must not have init, and delcaration length must be 1. + // then if left is expression, must transform it to pattern. + // - ForOfStatement: same as ForInStatement. + // There is one case that even we disallow in operator in top level, there maybe + // wrong init of expression like `for(a = 0 in []);` or `for(a=0 of [])` which would + // make leftOrInit parse all token in () as a expression, so we need to check if those + // case happend. + if (this.match(SyntaxKinds.SemiPunctuator)) { + if (isAwait) { + // recoverable error + this.raiseError(ErrorMessageMap.extra_error_for_await_not_of_loop, isAwait); + } + if (leftOrInit && isVarDeclaration(leftOrInit)) { + for (const delcar of leftOrInit.declarations) { + if ((isArrayPattern(delcar.id) || isObjectPattern(delcar.id)) && !delcar.init) { + // recoverable error + this.raiseError( + ErrorMessageMap.babel_error_destructing_pattern_must_need_initializer, + delcar.start, + ); + } + } + } + this.nextToken(); + let test: Expression | null = null, + update: Expression | null = null; + if (!this.match(SyntaxKinds.SemiPunctuator)) { + test = this.parseExpressionAllowIn(); + } + this.expect(SyntaxKinds.SemiPunctuator); + if (!this.match(SyntaxKinds.ParenthesesRightPunctuator)) { + update = this.parseExpressionAllowIn(); + } + this.expect(SyntaxKinds.ParenthesesRightPunctuator); + const body = this.parseForStatementBody(); + const forStatement = Factory.createForStatement( + body, + leftOrInit, + test, + update, + keywordStart, + cloneSourcePosition(body.end), + ); + this.staticSematicEarlyErrorForFORStatement(forStatement); + return forStatement; + } + // unreach case, even if syntax error, when leftOrInit, it must match semi token. + // and because it match semi token, if would enter forStatement case, will not + // reach there. even syntax error, error would be throw at parseExpression or + // parseDeclaration. + if (!leftOrInit) { + throw this.createUnreachError(); + } + // for case `for(a = 0 of [])`; leftOrInit would parse all token before `of` as one expression + // in this case , leftOrInit would be a assignment expression, and when it pass to toAssignment + // function, it would transform to assignment pattern, so we need to checko if there is Assignment + // pattern, it is , means original is assignment expression, it should throw a error. + if (!isVarDeclaration(leftOrInit)) { + leftOrInit = this.exprToPattern(leftOrInit, false) as Expression; + if (isAssignmentPattern(leftOrInit)) { + throw this.createMessageError(ErrorMessageMap.invalid_left_value); + } + } + // branch case for `for-in` statement + if (this.match(SyntaxKinds.InKeyword)) { + if (isAwait) { + // recoverable error + this.raiseError(ErrorMessageMap.extra_error_for_await_not_of_loop, isAwait); + } + if (isVarDeclaration(leftOrInit)) { + this.helperCheckDeclarationmaybeForInOrForOfStatement(leftOrInit, "ForIn"); + } + this.nextToken(); + const right = this.parseExpressionAllowIn(); + this.expect(SyntaxKinds.ParenthesesRightPunctuator); + const body = this.parseForStatementBody(); + const forInStatement = Factory.createForInStatement( + leftOrInit, + right, + body, + keywordStart, + cloneSourcePosition(body.end), + ); + this.staticSematicEarlyErrorForFORStatement(forInStatement); + return forInStatement; + } + // branch case for `for-of` statement + if (this.isContextKeyword("of")) { + if (isVarDeclaration(leftOrInit)) { + this.helperCheckDeclarationmaybeForInOrForOfStatement(leftOrInit, "ForOf"); + } + if (isParseLetAsExpr) { + this.raiseError(ErrorMessageMap.extra_error_for_of_can_not_use_let_as_identifier, isParseLetAsExpr); + } + this.nextToken(); + const right = this.parseAssignmentExpressionAllowIn(); + this.expect(SyntaxKinds.ParenthesesRightPunctuator); + const body = this.parseForStatementBody(); + const forOfStatement = Factory.createForOfStatement( + !!isAwait, + leftOrInit, + right, + body, + keywordStart, + cloneSourcePosition(body.end), + ); + this.staticSematicEarlyErrorForFORStatement(forOfStatement); + return forOfStatement; + } + throw this.createUnexpectError(); +} +export function parseForStatementBody(this: Parser): Statement { + const stmt = this.parseAsLoop(() => this.parseStatement()); + this.symbolScopeRecorder.exitSymbolScope(); + return stmt; +} +export function staticSematicEarlyErrorForFORStatement( + this: Parser, + statement: ForStatement | ForInStatement | ForOfStatement, +) { + if (checkIsLabelledFunction(statement.body)) { + this.raiseError( + this.isInStrictMode() + ? ErrorMessageMap.syntax_error_functions_declare_strict_mode + : ErrorMessageMap.syntax_error_functions_declare_non_strict_mode, + statement.body.start, + ); + } +} +/** + * Helper function for check sematic error of VariableDeclaration of ForInStatement and ForOfStatement, + * please reference to comment in parseForStatement. + * @param {VariableDeclaration} declaration + */ +export function helperCheckDeclarationmaybeForInOrForOfStatement( + this: Parser, + declaration: VariableDeclaration, + kind: "ForIn" | "ForOf", +) { + if (declaration.declarations.length > 1) { + // recoverable error + this.raiseError( + ErrorMessageMap.v8_error_Invalid_left_hand_side_in_for_in_loop_must_have_a_single_binding, + declaration.start, + ); + } + const delcarationVariant = declaration.variant; + const onlyDeclaration = declaration.declarations[0]; + if (kind === "ForIn") { + if (onlyDeclaration.init !== null) { + if (delcarationVariant === "var" && !this.isInStrictMode() && isIdentifer(onlyDeclaration.id)) { + return; + } + // recoverable error + this.raiseError( + ErrorMessageMap.syntax_error_for_in_loop_head_declarations_may_not_have_initializer, + onlyDeclaration.start, + ); + } + } else { + if (onlyDeclaration.init !== null) { + // recoverable error + this.raiseError( + ErrorMessageMap.syntax_error_for_of_loop_variable_declaration_may_not_have_an_initializer, + onlyDeclaration.init.start, + ); + } + } +} +export function parseIfStatement(this: Parser): IfStatement { + const { start: keywordStart } = this.expect(SyntaxKinds.IfKeyword); + this.expect(SyntaxKinds.ParenthesesLeftPunctuator); + const test = this.parseExpressionAllowIn(); + const { end: headerEnd } = this.expect(SyntaxKinds.ParenthesesRightPunctuator); + this.context.lastTokenIndexOfIfStmt = headerEnd.index; + const consequnce = this.parseStatement(); + if (this.match(SyntaxKinds.ElseKeyword)) { + this.nextToken(); + const alter = this.parseStatement(); + return Factory.createIfStatement(test, consequnce, alter, keywordStart, cloneSourcePosition(alter.end)); + } + const ifStatement = Factory.createIfStatement( + test, + consequnce, + null, + keywordStart, + cloneSourcePosition(consequnce.end), + ); + this.staticSematicEarlyErrorForIfStatement(ifStatement); + return ifStatement; +} +export function staticSematicEarlyErrorForIfStatement(this: Parser, statement: IfStatement) { + if (checkIsLabelledFunction(statement.conseqence)) { + this.raiseError( + this.isInStrictMode() + ? ErrorMessageMap.syntax_error_functions_declare_strict_mode + : ErrorMessageMap.syntax_error_functions_declare_non_strict_mode, + statement.conseqence.start, + ); + } + if (statement.alternative && checkIsLabelledFunction(statement.alternative)) { + this.raiseError( + this.isInStrictMode() + ? ErrorMessageMap.syntax_error_functions_declare_strict_mode + : ErrorMessageMap.syntax_error_functions_declare_non_strict_mode, + statement.alternative.start, + ); + } +} +export function parseWhileStatement(this: Parser): WhileStatement { + const { start: keywordStart } = this.expect(SyntaxKinds.WhileKeyword); + this.expect(SyntaxKinds.ParenthesesLeftPunctuator); + const test = this.parseExpressionAllowIn(); + this.expect(SyntaxKinds.ParenthesesRightPunctuator); + const body = this.parseAsLoop(() => this.parseStatement()); + const whileStatement = Factory.createWhileStatement( + test, + body, + keywordStart, + cloneSourcePosition(body.end), + ); + this.staticSematicEarlyErrorForWhileStatement(whileStatement); + return whileStatement; +} +export function checkIsLabelledFunction(statement: Statement) { + while (statement.kind === SyntaxKinds.LabeledStatement) { + if (statement.body.kind === SyntaxKinds.FunctionDeclaration) { + return true; + } + statement = statement.body; + } +} +export function staticSematicEarlyErrorForWhileStatement(this: Parser, statement: WhileStatement) { + if (checkIsLabelledFunction(statement.body)) { + // recoverable error + this.raiseError( + this.isInStrictMode() + ? ErrorMessageMap.syntax_error_functions_declare_strict_mode + : ErrorMessageMap.syntax_error_functions_declare_non_strict_mode, + statement.body.start, + ); + } +} +export function parseDoWhileStatement(this: Parser): DoWhileStatement { + const { start: keywordStart } = this.expect(SyntaxKinds.DoKeyword); + const body = this.parseAsLoop(() => this.parseStatement()); + this.expect(SyntaxKinds.WhileKeyword); + this.expect(SyntaxKinds.ParenthesesLeftPunctuator); + const test = this.parseExpressionAllowIn(); + const { end: punctEnd } = this.expect(SyntaxKinds.ParenthesesRightPunctuator); + this.isSoftInsertSemi(); + const doWhileStatement = Factory.createDoWhileStatement(test, body, keywordStart, punctEnd); + this.staticSematicEarlyErrorForDoWhileStatement(doWhileStatement); + return doWhileStatement; +} +export function staticSematicEarlyErrorForDoWhileStatement(this: Parser, statement: DoWhileStatement) { + if (checkIsLabelledFunction(statement.body)) { + // recoverable error + this.raiseError( + this.isInStrictMode() + ? ErrorMessageMap.syntax_error_functions_declare_strict_mode + : ErrorMessageMap.syntax_error_functions_declare_non_strict_mode, + statement.body.start, + ); + } +} +export function parseBlockStatement(this: Parser) { + const { start: puncStart } = this.expect(SyntaxKinds.BracesLeftPunctuator); + this.enterBlockScope(); + const body: Array = []; + while (!this.match(SyntaxKinds.BracesRightPunctuator) && !this.match(SyntaxKinds.EOFToken)) { + body.push(this.parseStatementListItem()); + } + this.exitBlockScope(); + const { end: puncEnd } = this.expect(SyntaxKinds.BracesRightPunctuator); + return Factory.createBlockStatement(body, puncStart, puncEnd); +} +export function parseSwitchStatement(this: Parser) { + const { start: keywordStart } = this.expect(SyntaxKinds.SwitchKeyword); + this.expect(SyntaxKinds.ParenthesesLeftPunctuator); + const discriminant = this.parseExpressionAllowIn(); + this.expect(SyntaxKinds.ParenthesesRightPunctuator); + const { nodes, end } = this.parseAsSwitch(() => this.parseSwitchCases()); + return Factory.createSwitchStatement(discriminant, nodes, keywordStart, end); +} +export function parseSwitchCases(this: Parser): ASTArrayWithMetaData { + this.enterBlockScope(); + const { start } = this.expect(SyntaxKinds.BracesLeftPunctuator); + const cases: Array = []; + let haveDefault = false; + while (!this.match(SyntaxKinds.BracesRightPunctuator) && !this.match(SyntaxKinds.EOFToken)) { + let test: Expression | null = null; + const start = this.getStartPosition(); + if (this.match(SyntaxKinds.CaseKeyword)) { + this.nextToken(); + test = this.parseExpressionAllowIn(); + } else if (this.match(SyntaxKinds.DefaultKeyword)) { + const start = this.getStartPosition(); + this.nextToken(); + if (haveDefault) { + // recoverable error + this.raiseError(ErrorMessageMap.v8_error_more_than_one_default_clause_in_switch_statement, start); + } else { + haveDefault = true; + } + } + this.expect(SyntaxKinds.ColonPunctuator); + const consequence: Array = []; + while ( + !this.match([ + SyntaxKinds.BracesRightPunctuator, + SyntaxKinds.EOFToken, + SyntaxKinds.CaseKeyword, + SyntaxKinds.DefaultKeyword, + ]) + ) { + consequence.push(this.parseStatementListItem()); + } + const end = this.getStartPosition(); + cases.push(Factory.createSwitchCase(test, consequence, start, end)); + } + const { end } = this.expect(SyntaxKinds.BracesRightPunctuator); + this.exitBlockScope(); + return { + nodes: cases, + start, + end, + }; +} +export function parseContinueStatement(this: Parser): ContinueStatement { + const { start: keywordStart, end: keywordEnd } = this.expect(SyntaxKinds.ContinueKeyword); + this.staticSematicEarlyErrorForContinueStatement(keywordStart); + if (this.match(SyntaxKinds.Identifier) && !this.getLineTerminatorFlag()) { + const id = this.parseIdentifierReference(); + this.shouldInsertSemi(); + this.staticSematicEarlyErrorForLabelInContinueStatement(id); + return Factory.createContinueStatement(id, keywordStart, cloneSourcePosition(id.end)); + } + this.shouldInsertSemi(); + return Factory.createContinueStatement(null, keywordStart, keywordEnd); +} +export function staticSematicEarlyErrorForContinueStatement(this: Parser, start: SourcePosition) { + if (!this.isContinueValidate()) { + // recoverable error + this.raiseError(ErrorMessageMap.syntax_error_continue_must_be_inside_loop, start); + } +} +export function staticSematicEarlyErrorForLabelInContinueStatement(this: Parser, label: Identifier) { + if (!this.canLabelReach(label.name)) { + // recoverable error + this.raiseError(ErrorMessageMap.syntax_error_label_not_found, label.start); + } +} +/** + * Parse Break Statement. + * ``` + * BreakStatement := break; + * := break [no lineTerminator] LabeledIdentifier; + * ``` + * @returns {BreakStatement} + */ +export function parseBreakStatement(this: Parser): BreakStatement { + const { start, end } = this.expect(SyntaxKinds.BreakKeyword); + if (this.match(SyntaxKinds.Identifier) && !this.getLineTerminatorFlag()) { + const label = this.parseIdentifierReference(); + this.shouldInsertSemi(); + this.staticSematicEarlyErrorForLabelInBreakStatement(label); + return Factory.createBreakStatement(label, start, end); + } + this.shouldInsertSemi(); + const breakStmt = Factory.createBreakStatement(null, start, end); + this.staticSematicEarlyErrorForBreakStatement(breakStmt); + return breakStmt; +} +/** + * Spec def early error checking for break statement. + * @param {BreakStatement} breakStmt + * reference: https://tc39.es/ecma262/#sec-break-statement-static-semantics-early-errors + */ +export function staticSematicEarlyErrorForBreakStatement(this: Parser, breakStmt: BreakStatement) { + if (!this.isBreakValidate()) { + // recoverable error + this.raiseError( + ErrorMessageMap.syntax_error_unlabeled_break_must_be_inside_loop_or_switch, + breakStmt.start, + ); + } +} +/** + * Spec def early error checking for break statement with break label + * @param {Identifier} label + * reference: https://tc39.es/ecma262/#sec-break-statement-static-semantics-early-errors + */ +export function staticSematicEarlyErrorForLabelInBreakStatement(this: Parser, label: Identifier) { + if (!this.canLabelReach(label.name)) { + // recoverable error + this.raiseError(ErrorMessageMap.syntax_error_label_not_found, label.start); + } +} +/** + * Parse labeled statement + * ``` + * LabelledStatement := LabelIdentifier: LabelledItem + * LabelledItem := Statement + * := FunctionDeclaration + * ``` + * @returns {LabeledStatement} + */ +export function parseLabeledStatement(this: Parser): LabeledStatement { + // TODO: using dev mode unreach checking + // if (!this.match(SyntaxKinds.Identifier) || this.lookahead().kind !== SyntaxKinds.ColonPunctuator) { + // } + const label = this.parseIdentifierReference(); + if (this.lexicalScopeRecorder.enterVirtualBlockScope("Label", label.name)) { + // recoverable error + this.raiseError(ErrorMessageMap.v8_error_label_has_already_been_declared, label.start); + } + this.expect(SyntaxKinds.ColonPunctuator); + const labeled = this.match(SyntaxKinds.FunctionKeyword) + ? this.parseFunctionDeclaration(false, false) + : this.parseStatement(); + this.lexicalScopeRecorder.exitVirtualBlockScope(); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + this.staticSematicEarlyErrorForLabelStatement(labeled as any); + return Factory.createLabeledStatement( + label, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + labeled as any, + cloneSourcePosition(label.start), + cloneSourcePosition(labeled.end), + ); +} +/** + * Spec def early error. using alter production rule. + * @param labeled + * reference: https://tc39.es/ecma262/#sec-labelled-statements-static-semantics-early-errors + */ +export function staticSematicEarlyErrorForLabelStatement( + this: Parser, + labeled: Statement | FunctionDeclaration, +) { + if (isFunctionDeclaration(labeled)) { + if (labeled.generator) { + this.raiseError(ErrorMessageMap.syntax_error_generator_function_declare, labeled.start); + } + if (this.isInStrictMode()) { + this.raiseError(ErrorMessageMap.syntax_error_functions_declare_strict_mode, labeled.start); + } + } +} +export function parseReturnStatement(this: Parser): ReturnStatement { + const { start, end } = this.expect(SyntaxKinds.ReturnKeyword); + if (!this.isReturnValidate()) { + this.raiseError(ErrorMessageMap.syntax_error_return_not_in_function, start); + } + if (this.isSoftInsertSemi(true)) { + return Factory.createReturnStatement(null, start, end); + } + const expr = this.parseExpressionAllowIn(); + this.shouldInsertSemi(); + return Factory.createReturnStatement(expr, start, cloneSourcePosition(expr.end)); +} +export function parseTryStatement(this: Parser): TryStatement { + const { start: tryKeywordStart } = this.expect(SyntaxKinds.TryKeyword); + const body = this.parseBlockStatement(); + let handler: CatchClause | null = null, + finalizer: BlockStatement | null = null; + if (this.match(SyntaxKinds.CatchKeyword)) { + const catchKeywordStart = this.getStartPosition(); + this.nextToken(); + //symbolScopeRecorder.enterFunctionSymbolScope(); + this.enterCatchBlockScope(); + if (this.match(SyntaxKinds.ParenthesesLeftPunctuator)) { + this.nextToken(); + this.symbolScopeRecorder.enterCatchParam(); + // catch clause should not have init + const param = this.parseBindingElement(false); + this.parseFunctionParamType(param as TSParameter, false); + if (!this.symbolScopeRecorder.setCatchParamTo(isIdentifer(param) ? SymbolType.Var : SymbolType.Let)) { + throw this.createMessageError(ErrorMessageMap.v8_error_duplicate_identifier); + } + // should check param is duplicate or not. + this.expect(SyntaxKinds.ParenthesesRightPunctuator); + const body = this.parseCatchBlock(); + handler = Factory.createCatchClause(param, body, catchKeywordStart, cloneSourcePosition(body.end)); + } else { + const body = this.parseCatchBlock(); + handler = Factory.createCatchClause(null, body, catchKeywordStart, cloneSourcePosition(body.end)); + } + this.exitCatchBlockScope(); + } + if (this.match(SyntaxKinds.FinallyKeyword)) { + this.nextToken(); + finalizer = this.parseBlockStatement(); + } + if (!handler && !finalizer) { + this.raiseError(ErrorMessageMap.v8_error_missing_catch_or_finally_after_try, tryKeywordStart); + } + return Factory.createTryStatement( + body, + handler, + finalizer, + tryKeywordStart, + cloneSourcePosition(finalizer ? finalizer.end : handler ? handler.end : body.end), + ); +} +export function parseCatchBlock(this: Parser) { + const { start: puncStart } = this.expect(SyntaxKinds.BracesLeftPunctuator); + const body: Array = []; + while (!this.match(SyntaxKinds.BracesRightPunctuator) && !this.match(SyntaxKinds.EOFToken)) { + body.push(this.parseStatementListItem()); + } + const { end: puncEnd } = this.expect(SyntaxKinds.BracesRightPunctuator); + return Factory.createBlockStatement(body, puncStart, puncEnd); +} +export function parseThrowStatement(this: Parser) { + const { start } = this.expect(SyntaxKinds.ThrowKeyword); + this.staticSmaticEarlyErrorForThrowStatement(); + const expr = this.parseExpressionAllowIn(); + this.shouldInsertSemi(); + return Factory.createThrowStatement(expr, start, cloneSourcePosition(expr.end)); +} +export function staticSmaticEarlyErrorForThrowStatement(this: Parser) { + if (this.getLineTerminatorFlag()) { + this.raiseError(ErrorMessageMap.babel_error_illegal_newline_after_throw, this.getStartPosition()); + } +} +export function parseWithStatement(this: Parser): WithStatement { + const { start } = this.expect(SyntaxKinds.WithKeyword); + this.expect(SyntaxKinds.ParenthesesLeftPunctuator); + const object = this.parseExpressionAllowIn(); + this.expect(SyntaxKinds.ParenthesesRightPunctuator); + const body = this.parseStatement(); + const withStmt = Factory.createWithStatement(object, body, start, cloneSourcePosition(body.end)); + this.staticSmaticEarlyErrorForWithStatement(withStmt); + return withStmt; +} +export function staticSmaticEarlyErrorForWithStatement(this: Parser, withStatement: WithStatement) { + if (this.isInStrictMode()) { + // recoverable error. + this.raiseError(ErrorMessageMap.babel_error_with_statement_in_strict_mode, withStatement.start); + } +} +export function parseDebuggerStatement(this: Parser): DebuggerStatement { + const { start, end } = this.expect(SyntaxKinds.DebuggerKeyword); + this.shouldInsertSemi(); + return Factory.createDebuggerStatement(start, end); +} +export function parseEmptyStatement(this: Parser): EmptyStatement { + const { start, end } = this.expect([SyntaxKinds.SemiPunctuator]); + return Factory.createEmptyStatement(start, end); +} diff --git a/web-infras/parser/src/parser/jsx/index.ts b/web-infras/parser/src/parser/jsx/index.ts new file mode 100644 index 00000000..e0892df2 --- /dev/null +++ b/web-infras/parser/src/parser/jsx/index.ts @@ -0,0 +1,413 @@ +/** ================================================================================ + * Parse JSX + * entry point: https://facebook.github.io/jsx/ + * ================================================================================== + */ + +import { + JSXElement, + JSXFragment, + SyntaxKinds, + Factory, + cloneSourcePosition, + JSXOpeningElement, + JSXClosingElement, + JSXIdentifier, + JSXMemberExpression, + JSXNamespacedName, + JSXAttribute, + JSXSpreadAttribute, + JSXExpressionContainer, +} from "web-infra-common"; +import { ParserPlugin } from "@/src/parser/config"; +import { Parser } from "@/src/parser"; +import { ErrorMessageMap } from "@/src/parser/error"; +import { IdentiferWithKeyworArray } from "@/src/parser/type"; + +/** + * Parse JSX Element or JSX Fragment + * ``` + * PrimaryExpression := JSXElement + * := JSXFragment + * ``` + */ +export function parseJSXElementOrJSXFragment(this: Parser, inJSXChildren: boolean): JSXElement | JSXFragment { + if (!this.requirePlugin(ParserPlugin.JSX)) { + this.raiseError(ErrorMessageMap.babel_error_need_enable_jsx, this.getStartPosition()); + } + const lookaheadToken = this.lookahead(); + if (lookaheadToken.kind !== SyntaxKinds.GtOperator) { + return this.parseJSXElement(inJSXChildren); + } else { + return this.parseJSXFragment(inJSXChildren); + } +} +/** + * Parse JSX Element + * ``` + * JSXElement := JSXOpeningElement JSXChildren JSXClosingElement + * := JSXOpeningElement + * ``` + * @returns {JSXElement} + */ +export function parseJSXElement(this: Parser, inJSXChildren: boolean): JSXElement { + const opeingElement = this.parseJSXOpeingElement(inJSXChildren); + if (opeingElement.selfClosing) { + return Factory.createJSXElement( + opeingElement, + null, + [], + cloneSourcePosition(opeingElement.start), + cloneSourcePosition(opeingElement.end), + ); + } + const children = this.parseJSXChildren(); + const closingElement = this.parseJSXClosingElement(inJSXChildren); + this.staticSematicEarlyErrorForJSXElement(opeingElement, closingElement); + return Factory.createJSXElement( + opeingElement, + closingElement, + children, + cloneSourcePosition(opeingElement.start), + cloneSourcePosition(opeingElement.end), + ); +} +export function staticSematicEarlyErrorForJSXElement( + this: Parser, + openingElement: JSXOpeningElement, + closingElement: JSXClosingElement, +) { + const openElementSourceText = this.lexer.getSourceValueByIndex( + openingElement.name.start.index, + openingElement.name.end.index, + ); + const closeElementSourceText = this.lexer.getSourceValueByIndex( + closingElement.name.start.index, + closingElement.name.end.index, + ); + if (openElementSourceText !== closeElementSourceText) { + throw new Error(); + } +} +/** + * Parse JSXOpeingElement + * ``` + * JSXOpeningElement := `<` JSXElementName JSXAtrributes `>` + * := `<` JSXElementName JSXAtrributes `/>` + * ``` + * @returns {JSXOpeningElement} + */ +export function parseJSXOpeingElement(this: Parser, inJSXChildren: boolean): JSXOpeningElement { + const { start } = this.expect(SyntaxKinds.LtOperator); + const lastLexerJSXEndTagContext = this.lexer.getJSXGtContext(); + this.lexer.setJSXGtContext(true); + const name = this.parseJSXElementName(); + const attributes = this.parseJSXAttributes(); + this.lexer.setJSXGtContext(lastLexerJSXEndTagContext); + if (this.match(SyntaxKinds.GtOperator)) { + const end = this.getEndPosition(); + this.nextTokenInJSXChildren(true); + return Factory.createJSXOpeningElement(name, attributes, false, start, end); + } + if (this.match(SyntaxKinds.JSXSelfClosedToken)) { + const end = this.getEndPosition(); + this.nextTokenInJSXChildren(inJSXChildren); + return Factory.createJSXOpeningElement(name, attributes, true, start, end); + } + // for `/ >` + if (this.match(SyntaxKinds.DivideOperator) && this.lookahead().kind === SyntaxKinds.GtOperator) { + this.nextToken(); + const end = this.getEndPosition(); + this.nextTokenInJSXChildren(inJSXChildren); + return Factory.createJSXOpeningElement(name, attributes, true, start, end); + } + throw this.createUnexpectError(); +} +/** + * Parse name of jsx element or jsx fragment + * ``` + * JSXElementName := JSXIdentifier + * := JSXMemberExpression + * := JSXNamespaceName + * ``` + * @returns {JSXIdentifier | JSXMemberExpression | JSXNamespacedName} + */ +export function parseJSXElementName(this: Parser): JSXIdentifier | JSXMemberExpression | JSXNamespacedName { + let name: JSXIdentifier | JSXMemberExpression | JSXNamespacedName = this.parseJSXIdentifier(); + if (this.match(SyntaxKinds.ColonPunctuator)) { + this.nextToken(); + const subName = this.parseJSXIdentifier(); + name = Factory.createJSXNamespacedName( + name, + subName, + cloneSourcePosition(name.start), + cloneSourcePosition(subName.end), + ); + } else if (this.match(SyntaxKinds.DotOperator)) { + while (this.match(SyntaxKinds.DotOperator) && !this.match(SyntaxKinds.EOFToken)) { + this.nextToken(); + const property = this.parseJSXIdentifier(); + name = Factory.createJSXMemberExpression( + name, + property, + cloneSourcePosition(name.start), + cloneSourcePosition(property.end), + ); + } + } + return name; +} +/** + * Parse JSX Attributes. + * ``` + * JSXAttributes := JSXAttributes JSXAttribute + * := JSXAttributes JSXSpreadAttribute + * := JSXAttribute + * := JSXSpreadAttribute + * JSXAttribute := JSXAttributeName '=' StringLiteral + * := JSXAttributeName '=' JSXExpressionContainer (expression can not be null) + * := JSXAttributeName '=' JSXElement + * := JSxAttributeName '=' JSXFragment + * := JSXAttrbuteName + * JSXSpreadAttribute := '{''...' AssignmentExpression '}' + * JSXAttributeName := JSXIdentifier + * := JSXNamespaceName + * ``` + * @returns {Array} + */ +export function parseJSXAttributes(this: Parser): Array { + const attribute: Array = []; + while ( + !this.match(SyntaxKinds.EOFToken) && + !this.match(SyntaxKinds.GtOperator) && + !this.match(SyntaxKinds.JSXSelfClosedToken) && + !(this.match(SyntaxKinds.DivideOperator) && this.lookahead().kind === SyntaxKinds.GtOperator) + ) { + // parse spread + if (this.match(SyntaxKinds.BracesLeftPunctuator)) { + this.nextToken(); + this.expect(SyntaxKinds.SpreadOperator); + const expression = this.parseAssignmentExpressionAllowIn(); + this.expect(SyntaxKinds.BracesRightPunctuator); + attribute.push( + Factory.createJSXSpreadAttribute( + expression, + cloneSourcePosition(expression.start), + cloneSourcePosition(expression.end), + ), + ); + continue; + } + // parse name + let name: JSXIdentifier | JSXNamespacedName = this.parseJSXIdentifier(); + if (this.match(SyntaxKinds.ColonPunctuator)) { + this.nextToken(); + const subName = this.parseJSXIdentifier(); + name = Factory.createJSXNamespacedName( + name, + subName, + cloneSourcePosition(name.start), + cloneSourcePosition(subName.end), + ); + } + // parse value + if (this.match(SyntaxKinds.AssginOperator)) { + this.lexer.setJSXStringContext(true); + this.nextToken(); + this.lexer.setJSXStringContext(false); + if (this.match(SyntaxKinds.StringLiteral)) { + const value = this.parseStringLiteral(); + attribute.push( + Factory.createJSXAttribute( + name, + value, + cloneSourcePosition(name.start), + cloneSourcePosition(value.end), + ), + ); + continue; + } + if (this.match(SyntaxKinds.BracesLeftPunctuator)) { + const expression = this.parseJSXExpressionContainer(false); + if (!expression.expression) { + throw new Error("right hand side of jsx attribute must have expression if start with `{`"); + } + attribute.push( + Factory.createJSXAttribute( + name, + expression, + cloneSourcePosition(name.start), + cloneSourcePosition(expression.end), + ), + ); + continue; + } + const element = this.parseJSXElementOrJSXFragment(false); + attribute.push( + Factory.createJSXAttribute( + name, + element, + cloneSourcePosition(name.start), + cloneSourcePosition(element.end), + ), + ); + } else { + attribute.push( + Factory.createJSXAttribute( + name, + null, + cloneSourcePosition(name.start), + cloneSourcePosition(name.end), + ), + ); + } + } + return attribute; +} +/** + * Parse JSX Children + * ``` + * JSXChildren := JSXChildren JSXChild + * := JSXChild + * JSXChild := JSXText + * := JSXExpressionContainer + * := JSXElement + * := JSXFragment + * := JSXSpreadChild + * JSXSpreadChild := {'...AssignmentExpression '}' + * ``` + * @returns {Array} + */ +export function parseJSXChildren(this: Parser): JSXElement["children"] { + const children: JSXElement["children"] = []; + while (!this.match(SyntaxKinds.JSXCloseTagStart) && !this.match(SyntaxKinds.EOFToken)) { + if (this.match(SyntaxKinds.LtOperator)) { + children.push(this.parseJSXElementOrJSXFragment(true)); + continue; + } + if (this.match(SyntaxKinds.BracesLeftPunctuator)) { + if (this.lookahead().kind == SyntaxKinds.SpreadOperator) { + this.expect(SyntaxKinds.BracesLeftPunctuator); + this.expect(SyntaxKinds.SpreadOperator); + const expression = this.parseAssignmentExpressionAllowIn(); + this.expect(SyntaxKinds.BracesRightPunctuator); + children.push( + Factory.createJSXSpreadChild( + expression, + cloneSourcePosition(expression.start), + cloneSourcePosition(expression.end), + ), + ); + continue; + } + children.push(this.parseJSXExpressionContainer(true)); + continue; + } + children.push(this.parseJSXText()); + } + return children; +} +/** + * Parse JSX expression container + * ``` + * JSXExpressionContainer = '{' AssignmentExpression '}' + * ``` + * @returns {JSXExpressionContainer} + */ +export function parseJSXExpressionContainer(this: Parser, inJSXChildren: boolean): JSXExpressionContainer { + const { start } = this.expect(SyntaxKinds.BracesLeftPunctuator); + const expression = this.match(SyntaxKinds.BracesRightPunctuator) + ? null + : this.parseAssignmentExpressionAllowIn(); + const { end } = this.expectInJSXChildren(SyntaxKinds.BracesRightPunctuator, inJSXChildren); + return Factory.createsJSXExpressionContainer(expression, start, end); +} +/** + * Parse Closing Element of JSXElement + * ``` + * JSXClosingElement := '' + * ``` + * @returns {JSXClosingElement} + */ +export function parseJSXClosingElement(this: Parser, inJSXChildren: boolean): JSXClosingElement { + const { start } = this.expect(SyntaxKinds.JSXCloseTagStart); + const lastLexerJSXEndTagContext = this.lexer.getJSXGtContext(); + this.lexer.setJSXGtContext(true); + const name = this.parseJSXElementName(); + const { end } = this.expectInJSXChildren(SyntaxKinds.GtOperator, inJSXChildren); + this.lexer.setJSXGtContext(lastLexerJSXEndTagContext); + return Factory.createJSXClosingElement(name, start, end); +} +/** + * + * @returns {JSXIdentifier} + */ +export function parseJSXIdentifier(this: Parser): JSXIdentifier { + // eslint-disable-next-line prefer-const + let { start, end } = this.expect(IdentiferWithKeyworArray); + // eslint-disable-next-line no-constant-condition + while (1) { + if (this.match(SyntaxKinds.MinusOperator)) { + end = this.getEndPosition(); + this.nextToken(); + } else { + break; + } + if (this.match(IdentiferWithKeyworArray)) { + end = this.getEndPosition(); + this.nextToken(); + } else { + break; + } + } + const value = this.lexer.getSourceValueByIndex(start.index, end.index); + return Factory.createJSXIdentifier(value, start, end); +} +export function parseJSXText(this: Parser) { + const { start, end, value } = this.expect(SyntaxKinds.JSXText); + return Factory.createJSXText(value, start, end); +} +/** + * Parse JSXFragment + * ``` + * JSXFragment := `<``/>` JSXChildern `` + * ``` + * @returns {JSXFragment} + */ +export function parseJSXFragment(this: Parser, inJSXChildren: boolean): JSXFragment { + const { start: openingStart } = this.expect(SyntaxKinds.LtOperator); + const { end: openingEnd } = this.expectInJSXChildren(SyntaxKinds.GtOperator, true); + const children = this.parseJSXChildren(); + const { start: closingStart } = this.expect(SyntaxKinds.JSXCloseTagStart); + const { end: closingEnd } = this.expectInJSXChildren(SyntaxKinds.GtOperator, inJSXChildren); + return Factory.createJSXFragment( + Factory.createJSXOpeningFragment(openingStart, openingEnd), + Factory.createJSXClosingFragment(closingStart, closingEnd), + children, + cloneSourcePosition(openingStart), + cloneSourcePosition(closingEnd), + ); +} +export function expectInJSXChildren(this: Parser, kind: SyntaxKinds, inJSXChildren: boolean) { + if (this.match(kind)) { + const metaData = { + value: this.getSourceValue(), + start: this.getStartPosition(), + end: this.getEndPosition(), + }; + if (inJSXChildren) { + this.lexer.nextTokenInJSXChildrenContext(); + } else { + this.lexer.nextToken(); + } + return metaData; + } + throw this.createUnexpectError(); +} +export function nextTokenInJSXChildren(this: Parser, inJSXChildren: boolean) { + if (inJSXChildren) { + this.lexer.nextTokenInJSXChildrenContext(); + } else { + this.lexer.nextToken(); + } +} diff --git a/web-infras/parser/src/parser/parser.ts b/web-infras/parser/src/parser/parser.ts deleted file mode 100644 index 72d90c83..00000000 --- a/web-infras/parser/src/parser/parser.ts +++ /dev/null @@ -1,6022 +0,0 @@ -import { - Expression, - FunctionBody, - Function as FunctionAST, - Identifier, - ModuleItem, - Pattern, - PropertyDefinition, - PropertyName, - MethodDefinition, - TemplateElement, - PrivateName, - ObjectMethodDefinition, - ClassMethodDefinition, - ClassElement, - ClassBody, - Class, - VariableDeclaration, - VariableDeclarator, - ImportDeclaration, - ImportDefaultSpecifier, - ImportNamespaceSpecifier, - ImportSpecifier, - RestElement, - ObjectPattern, - ArrayPattern, - StatementListItem, - Declaration, - Statement, - IfStatement, - SwitchCase, - LabeledStatement, - BreakStatement, - ContinueStatement, - ReturnStatement, - WhileStatement, - DoWhileStatement, - TryStatement, - CatchClause, - BlockStatement, - WithStatement, - DebuggerStatement, - ForStatement, - ForInStatement, - ForOfStatement, - ExportDeclaration, - ExportAllDeclaration, - ExportNamedDeclarations, - ExportSpecifier, - ExportDefaultDeclaration, - FunctionDeclaration, - ClassDeclaration, - ClassExpression, - ObjectAccessor, - ClassAccessor, - StringLiteral, - ClassConstructor, - ObjectPatternProperty, - SyntaxKinds, - UnaryOperators, - BinaryOperators, - AssigmentOperators, - AssigmentOperatorKinds, - BinaryOperatorKinds, - UnaryOperatorKinds, - UpdateOperators, - UpdateOperatorKinds, - Keywords, - SourcePosition, - cloneSourcePosition, - Factory, - EmptyStatement, - ObjectExpression, - ArrayExpression, - SpreadElement, - SytaxKindsMapLexicalLiteral, - AssigmentExpression, - isRestElement, - isSpreadElement, - isAssignmentPattern, - isVarDeclaration, - RegexLiteral, - isArrowFunctionExpression, - isIdentifer, - isArrayPattern, - isObjectPattern, - AssignmentPattern, - ObjectProperty, - isMemberExpression, - LexicalLiteral, - isAwaitExpression, - isObjectPatternProperty, - ArrorFunctionExpression, - YieldExpression, - isCallExpression, - isStringLiteral, - ExpressionStatement, - Program, - isPattern, - isUnaryExpression, - JSXElement, - JSXOpeningElement, - JSXAttribute, - JSXSpreadAttribute, - JSXIdentifier, - JSXNamespacedName, - JSXFragment, - JSXMemberExpression, - JSXExpressionContainer, - JSXClosingElement, - isNumnerLiteral, - isFunctionExpression, - isPrivateName, - isFunctionDeclaration, - isClassExpression, - NumericLiteralKinds, - NumberLiteral, - UnaryExpression, - ImportAttribute, - Decorator, - MetaProperty, - CallExpression, - ThisExpression, -} from "web-infra-common"; -import { ExpectToken } from "./type"; -import { ErrorMessageMap } from "./error"; -import { ParserUserConfig, getConfigFromUserInput } from "./config"; -import { LookaheadToken } from "../lexer/type"; -import { createLexer } from "../lexer/index"; -import { createAsyncArrowExpressionScopeRecorder, AsyncArrowExpressionScope } from "./scope/arrowExprScope"; -import { createStrictModeScopeRecorder, StrictModeScope } from "./scope/strictModeScope"; -import { ExpressionScopeKind } from "./scope/type"; -import { createLexicalScopeRecorder, ExportContext, PrivateNameDefKind } from "./scope/lexicalScope"; -import { - createSymbolScopeRecorder, - FunctionSymbolScope, - NonFunctionalSymbolType, - SymbolType, -} from "./scope/symbolScope"; -import { SyntaxErrorHandler } from "@/src/errorHandler/type"; - -interface Context { - maybeArrowStart: number; - inOperatorStack: Array; - propertiesInitSet: Set; - propertiesProtoDuplicateSet: Set; - lastTokenIndexOfIfStmt: number; - cache: { - decorators: Decorator[] | null; - }; -} - -interface ASTArrayWithMetaData { - nodes: Array; - start: SourcePosition; - end: SourcePosition; -} -/** - * Create context for parser - * @returns {Context} - */ -function createContext(): Context { - return { - maybeArrowStart: -1, - inOperatorStack: [], - propertiesInitSet: new Set(), - propertiesProtoDuplicateSet: new Set(), - lastTokenIndexOfIfStmt: -1, - cache: { - decorators: null, - }, - }; -} - -const IdentiferWithKeyworArray = [SyntaxKinds.Identifier, ...Keywords]; -const BindingIdentifierSyntaxKindArray = [ - SyntaxKinds.Identifier, - SyntaxKinds.AwaitKeyword, - SyntaxKinds.YieldKeyword, - SyntaxKinds.LetKeyword, -]; -const PreserveWordSet = new Set(LexicalLiteral.preserveword); -const KeywordSet = new Set([ - ...LexicalLiteral.keywords, - ...LexicalLiteral.BooleanLiteral, - ...LexicalLiteral.NullLiteral, - ...LexicalLiteral.UndefinbedLiteral, -]); -/** - * create parser for input code. - * @param {string} code - * @returns - */ -export function createParser(code: string, errorhandler: SyntaxErrorHandler, option?: ParserUserConfig) { - const lexer = createLexer(code); - const context = createContext(); - const config = getConfigFromUserInput(option); - const lexicalScopeRecorder = createLexicalScopeRecorder(); - const symbolScopeRecorder = createSymbolScopeRecorder(); - const strictModeScopeRecorder = createStrictModeScopeRecorder(); - const asyncArrowExprScopeRecorder = createAsyncArrowExpressionScopeRecorder(); - /** =========================================================== - * Public API for Parser - * =========================================================== - */ - /** - * Only Public API for parser, parse code and - * return a program. - * @returns {Program} - */ - function parse(): Program { - return parseProgram(); - } - return { parse }; - /** =========================================================== - * Private API for other Parser API - * =========================================================== - */ - /** - * Private API for parser, move to next token, skip comment and - * block comment token. - * @returns {SyntaxKinds} - */ - function nextToken(): SyntaxKinds { - lexer.nextToken(); - const token = lexer.getTokenKind(); - if (token === SyntaxKinds.Comment || token == SyntaxKinds.BlockComment) { - return nextToken(); - } - return token; - } - /** - * Private API for parser, get current token kind, skip comment - * and block comment token - * @returns {SyntaxKinds} - */ - function getToken(): SyntaxKinds { - const token = lexer.getTokenKind(); - if (token === SyntaxKinds.Comment || token == SyntaxKinds.BlockComment) { - return nextToken(); - } - return token; - } - /** - * Private API for parser, get current token's string value. - * @returns {string} - */ - function getSourceValue(): string { - return lexer.getSourceValue(); - } - /** - * Private API for parser, just wrapper of lexer, get start - * position of current token. - * @return {SourcePosition} - */ - function getStartPosition(): SourcePosition { - return lexer.getStartPosition(); - } - /** - * Private API for parser, just wrapper of lexer, get end - * position of current token. - * @return {SourcePosition} - */ - function getEndPosition(): SourcePosition { - return lexer.getEndPosition(); - } - /** - * Private API for parser, just wrapper of lookahead method - * of lexer. - * @returns - */ - function lookahead(): LookaheadToken { - return lexer.lookahead(); - } - /** - * Private API for parser, just wrapper of lexer method. - * @returns - */ - function readRegex() { - return lexer.readRegex(); - } - /** - * Private API for parser, just wrapper of lexer method, check - * is a line terminator in the range of last token end and start - * of current token. - * @returns {boolean} - */ - function getLineTerminatorFlag(): boolean { - return lexer.getLineTerminatorFlag(); - } - /** - * Private API for parser, just wrapper of lexer methid, check - * is current token contain a unicode esc. - */ - function getEscFlag(): boolean { - return lexer.getEscFlag(); - } - /** - * Private API for parser, is current token kind match the - * given token kind ? - * @param {SyntaxKinds | Array} kind - * @returns {boolean} - */ - function match(kind: SyntaxKinds | Array): boolean { - const currentToken = getToken(); - if (Array.isArray(kind)) { - const tokenSet = new Set(kind); - return tokenSet.has(currentToken); - } - return currentToken === kind; - } - /** - * Private API for check if current identifier is a given value, - * used when we need to detect a contextual keyword (like `async`). - * @param {string} value - * @returns {boolean} - */ - function isContextKeyword(value: string): boolean { - if (getSourceValue() === value && getToken() === SyntaxKinds.Identifier && !lexer.getEscFlag()) { - return true; - } - return false; - } - /** - * Private API for parser, expect current token is one of given token(s), - * it not, it will create a unexpect error, if is one of given token, it will - * eat token and return `value`, `start`, `end` of token - * @param kind - * @param message - * @returns {ExpectToken} - */ - function expect(kind: SyntaxKinds | Array): ExpectToken { - if (match(kind)) { - const metaData = { - value: getSourceValue(), - start: getStartPosition(), - end: getEndPosition(), - }; - nextToken(); - return metaData; - } - throw createUnexpectError(); - } - /** - * Private API for parser, expect current token is one of given token(s), - * it not, it will create a unexpect error, if is one of given token, it - * will NOT eat token. - * @param kind - * @param message - * @returns {void} - */ - function expectButNotEat(kind: SyntaxKinds | Array): void { - if (match(kind)) { - return; - } - throw createUnexpectError(); - } - /** - * Private API for `shouldInsertSemi` and `isSoftInsertSemi`, - * test is there a semi or equal syntax, return three state - * - `SemiExisted`: there is a semi token. - * - `SemiInsertAble`: there is a equal to semi syntax. - * - `SemiNotExisted`: there is no semi or equal syntax, - * @returns - */ - function isSemiInsertable() { - if (match(SyntaxKinds.SemiPunctuator)) { - return "SemiExisted"; - } - if (match([SyntaxKinds.BracesRightPunctuator, SyntaxKinds.EOFToken])) { - return "SemiInsertAble"; - } - if (getLineTerminatorFlag()) { - return "SemiInsertAble"; - } - return "SemiNotExisted"; - } - /** - * Private API for most of insert semi check, if semi exist, eat token, - * pass if equal syntax exist, throw error if not existed semi or equal - * syntax. - * @returns - */ - function shouldInsertSemi() { - const semiState = isSemiInsertable(); - switch (semiState) { - case "SemiExisted": - nextToken(); - return; - case "SemiInsertAble": - return; - case "SemiNotExisted": - // recoverable error - raiseError(ErrorMessageMap.missing_semicolon, getStartPosition()); - } - } - /** - * Private API for insert semi for three edge case - * - `DoWhileStatement` - * - `ReturnStatement` - * - `YeildExpression` - * @param {boolean} shouldEat - false whem used in yield expression. - * @returns - */ - function isSoftInsertSemi(shouldEat: boolean = true) { - const semiState = isSemiInsertable(); - switch (semiState) { - case "SemiExisted": - if (shouldEat) { - nextToken(); - } - return true; - case "SemiInsertAble": - return true; - case "SemiNotExisted": - return false; - } - } - /** - * Create a Message error from parser's error map. - * @param {string} messsage - */ - function createMessageError(messsage: string, position?: SourcePosition) { - if (position === undefined) position = getStartPosition(); - - return new Error(`[Syntax Error]: ${messsage} (${position.row}, ${position.col})`); - } - /** - * Create a error object with message tell developer that get a - * unexpect token. - * @returns {Error} - */ - function createUnexpectError(): Error { - const startPos = getStartPosition(); - return new Error( - `[Syntax Error]: Unexpect token ${SytaxKindsMapLexicalLiteral[getToken()]}(${startPos.row}, ${startPos.col}).`, - ); - } - /** - * Given that this parser is recurive decent parser, some - * function must call with some start token, if function call - * with unexecpt start token, it should throw this error. - * @param {Array} startTokens - * @returns {Error} - */ - function createUnreachError(startTokens: Array = []): Error { - const start = getStartPosition(); - let message = `[Unreach Zone]: this piece of code should not be reach (${start.row}, ${start.col}), have a unexpect token ${getToken()} (${getSourceValue()}).`; - if (startTokens.length !== 0) { - message += " it should call with start token["; - for (const token of startTokens) { - message += `${token}, `; - } - message += "]"; - } - message += ", please report to developer."; - return new Error(message); - } - function disAllowInOperaotr(parseCallback: () => T): T { - context.inOperatorStack.push(false); - const result = parseCallback(); - context.inOperatorStack.pop(); - return result; - } - /** - * Private API for parse api for expression, in ECMAscript, there is - * a syntax tranlation for in operator production rule. - * @param parseCallback - * @returns - */ - function allowInOperaotr(parseCallback: () => T) { - context.inOperatorStack.push(true); - const result = parseCallback(); - context.inOperatorStack.pop(); - return result; - } - /** =========================================================== - * Private API for other Parser API, just wrapper of recorder - * =========================================================== - */ - - /** - * please reference to recorder api - */ - function enterFunctionScope(isAsync: boolean = false, isGenerator: boolean = false) { - asyncArrowExprScopeRecorder.enterFunctionScope(); - strictModeScopeRecorder.enterRHSStrictModeScope(); - symbolScopeRecorder.enterFunctionSymbolScope(); - lexicalScopeRecorder.enterFunctionLexicalScope(isAsync, isGenerator); - lexer.setStrictModeContext(isInStrictMode()); - } - function exitFunctionScope(focusCheck: boolean) { - const isNonSimpleParam = !isCurrentFunctionParameterListSimple(); - const isStrict = isInStrictMode(); - const symbolScope = symbolScopeRecorder.exitSymbolScope()!; - if (isNonSimpleParam || isStrict || focusCheck) { - const functionSymbolScope = symbolScope as FunctionSymbolScope; - for (const symPos of functionSymbolScope.duplicateParams) { - raiseError(ErrorMessageMap.duplicate_param, symPos); - } - } - asyncArrowExprScopeRecorder.exitAsyncArrowExpressionScope(); - strictModeScopeRecorder.exitStrictModeScope(); - lexicalScopeRecorder.exitFunctionLexicalScope(); - lexer.setStrictModeContext(isInStrictMode()); - } - function enterProgram() { - symbolScopeRecorder.enterProgramSymbolScope(); - lexicalScopeRecorder.enterProgramLexicalScope( - config.allowAwaitOutsideFunction || false, - config.sourceType === "module", - ); - lexer.setStrictModeContext(config.sourceType === "module"); - } - function exitProgram() { - if (!config.allowUndeclaredExports) { - for (const pos of symbolScopeRecorder.getProgramContainUndefSymbol()) { - raiseError(ErrorMessageMap.babel_error_export_is_not_defined, pos); - } - } - symbolScopeRecorder.exitSymbolScope(); - lexicalScopeRecorder.exitProgramLexicalScope(); - lexer.setStrictModeContext(false); - } - function enterBlockScope() { - lexicalScopeRecorder.enterBlockLexicalScope(false); - symbolScopeRecorder.enterBlockSymbolScope(); - } - function exitBlockScope() { - lexicalScopeRecorder.exitBlockLexicalScope(); - symbolScopeRecorder.exitSymbolScope(); - } - function enterCatchBlockScope() { - lexicalScopeRecorder.enterBlockLexicalScope(true); - symbolScopeRecorder.enterFunctionSymbolScope(); - } - function exitCatchBlockScope() { - lexicalScopeRecorder.exitBlockLexicalScope(); - symbolScopeRecorder.exitSymbolScope(); - } - function parseAsLoop(callback: () => T): T { - lexicalScopeRecorder.enterVirtualBlockScope("Loop"); - const result = callback(); - lexicalScopeRecorder.exitVirtualBlockScope(); - return result; - } - function parseAsSwitch(callback: () => T): T { - lexicalScopeRecorder.enterVirtualBlockScope("Switch"); - const result = callback(); - lexicalScopeRecorder.exitVirtualBlockScope(); - return result; - } - function recordScope(kind: ExpressionScopeKind, position: SourcePosition) { - strictModeScopeRecorder.record(kind, position); - asyncArrowExprScopeRecorder.record(kind, position); - } - function enterArrowFunctionBodyScope(isAsync: boolean = false) { - lexicalScopeRecorder.enterArrowFunctionBodyScope(isAsync); - symbolScopeRecorder.enterFunctionSymbolScope(); - } - function exitArrowFunctionBodyScope() { - const symbolScope = symbolScopeRecorder.exitSymbolScope()!; - const functionSymbolScope = symbolScope as FunctionSymbolScope; - for (const symPos of functionSymbolScope.duplicateParams) { - raiseError(ErrorMessageMap.duplicate_param, symPos); - } - lexicalScopeRecorder.exitArrowFunctionBodyScope(); - } - function parseWithArrowExpressionScope(callback: () => T): [T, AsyncArrowExpressionScope] { - asyncArrowExprScopeRecorder.enterAsyncArrowExpressionScope(); - const result = callback(); - const scope = asyncArrowExprScopeRecorder.getCurrentAsyncArrowExpressionScope()!; - asyncArrowExprScopeRecorder.exitAsyncArrowExpressionScope(); - return [result, scope]; - } - function parseWithCatpureLayer(callback: () => T): [T, StrictModeScope] { - strictModeScopeRecorder.enterCatpureStrictModeScope(); - const result = callback(); - const scope = strictModeScopeRecorder.getCurrentStrictModeScope(); - strictModeScopeRecorder.exitStrictModeScope(); - return [result, scope]; - } - function parseWithLHSLayer(callback: () => T): T { - strictModeScopeRecorder.enterLHSStrictModeScope(); - const result = callback(); - strictModeScopeRecorder.exitStrictModeScope(); - return result; - } - function parseWithLHSLayerReturnScope(callback: () => T): [T, StrictModeScope] { - strictModeScopeRecorder.enterLHSStrictModeScope(); - const result = callback(); - const scope = strictModeScopeRecorder.getCurrentStrictModeScope(); - strictModeScopeRecorder.exitStrictModeScope(); - return [result, scope]; - } - function parseWithRHSLayer(callback: () => T): T { - strictModeScopeRecorder.enterRHSStrictModeScope(); - const result = callback(); - strictModeScopeRecorder.exitStrictModeScope(); - return result; - } - function checkStrictModeScopeError(scope: StrictModeScope) { - if (isInStrictMode() && strictModeScopeRecorder.isStrictModeScopeViolateStrictMode(scope)) { - if (scope.kind !== "RHSLayer") { - for (const pos of scope.argumentsIdentifier) { - raiseError(ErrorMessageMap.syntax_error_bad_strict_arguments_eval, pos); - } - for (const pos of scope.evalIdentifier) { - raiseError(ErrorMessageMap.syntax_error_bad_strict_arguments_eval, pos); - } - for (const pos of scope.letIdentifier) { - raiseError(ErrorMessageMap.unexpect_keyword_in_stric_mode, pos); - } - for (const pos of scope.yieldIdentifier) { - raiseError(ErrorMessageMap.unexpect_keyword_in_stric_mode, pos); - } - for (const pos of scope.preservedWordIdentifier) { - raiseError(ErrorMessageMap.unexpect_keyword_in_stric_mode, pos); - } - } - } - } - function checkAsyncArrowExprScopeError(scope: AsyncArrowExpressionScope) { - if (asyncArrowExprScopeRecorder.isAsyncArrowExpressionScopeHaveError(scope)) { - for (const pos of scope.awaitExpressionInParameter) { - raiseError(ErrorMessageMap.extra_error_await_expression_can_not_used_in_parameter_list, pos); - } - for (const pos of scope.yieldExpressionInParameter) { - raiseError(ErrorMessageMap.extra_error_yield_expression_can_not_used_in_parameter_list, pos); - } - for (const pos of scope.awaitIdentifier) { - raiseError(ErrorMessageMap.babel_error_can_not_use_await_as_identifier_inside_an_async_function, pos); - } - } - } - function enterFunctionParameter() { - lexicalScopeRecorder.enterFunctionLexicalScopeParamemter(); - } - function existFunctionParameter() { - lexicalScopeRecorder.exitFunctionLexicalScopeParamemter(); - } - function setCurrentFunctionContextAsGenerator() { - lexicalScopeRecorder.setCurrentFunctionLexicalScopeAsGenerator(); - } - function setCurrentFunctionContextAsStrictMode() { - lexicalScopeRecorder.setCurrentFunctionLexicalScopeAsStrictMode(); - lexer.setStrictModeContext(true); - } - /** - * Private API for `For-In` parsering problem. - * @returns {boolean} - */ - function getCurrentInOperatorStack(): boolean { - if (context.inOperatorStack.length === 0) { - return false; - } - return context.inOperatorStack[context.inOperatorStack.length - 1]; - } - function isTopLevel(): boolean { - return lexicalScopeRecorder.isInTopLevel(); - } - function isCurrentScopeParseAwaitAsExpression(): boolean { - return lexicalScopeRecorder.canAwaitParseAsExpression(); - } - function isCurrentScopeParseYieldAsExpression(): boolean { - return lexicalScopeRecorder.canYieldParseAsExpression(); - } - function isInParameter(): boolean { - return lexicalScopeRecorder.isInParameter(); - } - function setCurrentFunctionParameterListAsNonSimple() { - return lexicalScopeRecorder.setCurrentFunctionLexicalScopeParameterAsNonSimple(); - } - function isCurrentFunctionParameterListSimple(): boolean { - return lexicalScopeRecorder.isCurrentFunctionLexicalScopeParameterSimple(); - } - function isParentFunctionAsync(): boolean { - return lexicalScopeRecorder.isParentFunctionAsync(); - } - function isParentFunctionGenerator(): boolean { - return lexicalScopeRecorder.isParentFunctionGenerator(); - } - function enterClassScope(isExtend: boolean = false) { - lexicalScopeRecorder.enterClassLexicalScope(isExtend); - asyncArrowExprScopeRecorder.enterAsyncArrowExpressionScope(); - symbolScopeRecorder.enterClassSymbolScope(); - } - function existClassScope() { - const duplicateSet = symbolScopeRecorder.isDuplicatePrivateName(); - if (duplicateSet) { - for (const pos of duplicateSet.values()) { - raiseError(ErrorMessageMap.babel_error_private_name_duplicate, pos); - } - } - const undefSet = symbolScopeRecorder.isUndeinfedPrivateName(); - if (undefSet) { - for (const pos of undefSet.values()) { - raiseError(ErrorMessageMap.babel_error_private_name_undeinfed, pos); - } - } - lexicalScopeRecorder.exitClassLexicalScope(); - symbolScopeRecorder.exitClassSymbolScope(); - asyncArrowExprScopeRecorder.exitAsyncArrowExpressionScope(); - } - function isInClassScope(): boolean { - return lexicalScopeRecorder.isInClassScope(); - } - function isCurrentClassExtend(): boolean { - return lexicalScopeRecorder.isCurrentClassExtend(); - } - function usePrivateName(name: string, position: SourcePosition, type: PrivateNameDefKind = "other") { - return symbolScopeRecorder.usePrivateName(name, position, type); - } - function defPrivateName(name: string, position: SourcePosition, type: PrivateNameDefKind = "other") { - return symbolScopeRecorder.defPrivateName(name, position, type); - } - function enterDelete() { - lexicalScopeRecorder.enterDelete(); - } - function exitDelete() { - lexicalScopeRecorder.exitDelete(); - } - function isInDelete() { - return lexicalScopeRecorder.isCurrentInDelete(); - } - function isInStrictMode(): boolean { - return lexicalScopeRecorder.isInStrictMode(); - } - function isDirectToFunctionContext(): boolean { - return lexicalScopeRecorder.isDirectToFunctionContext(); - } - function isDirectToClassScope(): boolean { - return lexicalScopeRecorder.isDirectToClassScope(); - } - function isReturnValidate(): boolean { - return config.allowReturnOutsideFunction || lexicalScopeRecorder.isReturnValidate(); - } - function isBreakValidate(): boolean { - return lexicalScopeRecorder.isBreakValidate(); - } - function isContinueValidate(): boolean { - return lexicalScopeRecorder.isContinueValidate(); - } - function canLabelReach(name: string): boolean { - return lexicalScopeRecorder.canLabelReach(name); - } - function isEncloseInFunction(): boolean { - return lexicalScopeRecorder.isEncloseInFunction(); - } - function isInPropertyName(): boolean { - return lexicalScopeRecorder.isInPropertyName(); - } - function setExportContext(context: ExportContext) { - lexicalScopeRecorder.setExportContext(context); - } - function getExportContext(): ExportContext { - return lexicalScopeRecorder.getExportContext(); - } - function takeCacheDecorator() { - const list = context.cache.decorators; - context.cache.decorators = null; - return list; - } - function mergeDecoratorList(input1: Decorator[] | null, input2: Decorator[] | null) { - const list = [...(input1 || []), ...(input2 || [])]; - if (list.length === 0) { - return null; - } - return list; - } - /** - * - * @param name - * @param position - * @returns - */ - function declarateNonFunctionalSymbol(name: string, position: SourcePosition) { - if (isInParameter()) { - symbolScopeRecorder.declarateParam(name, position); - return; - } - if (!symbolScopeRecorder.declarateNonFunctionalSymbol(name)) { - raiseError(ErrorMessageMap.v8_error_duplicate_identifier, position); - } - const isExportAlreadyExist = declarateExportSymbolIfInContext(name, position); - if (isExportAlreadyExist) { - raiseError(ErrorMessageMap.v8_error_duplicate_identifier, isExportAlreadyExist); - } - return; - } - /** - * - * @param name - * @param generator - * @param position - * @returns - */ - function delcarateFcuntionSymbol(name: string, generator: boolean, position: SourcePosition) { - const duplicateType = symbolScopeRecorder.declarateFuncrtionSymbol(name, generator); - if (duplicateType) { - if ( - (!generator && - ((duplicateType === SymbolType.Function && config.sourceType === "module") || - duplicateType === SymbolType.GenFunction)) || - (generator && - ((duplicateType === SymbolType.GenFunction && config.sourceType === "module") || - duplicateType === SymbolType.Function)) || - (duplicateType === SymbolType.Var && lexicalScopeRecorder.isInCatch()) || - duplicateType === SymbolType.Let || - duplicateType === SymbolType.Const - ) - raiseError(ErrorMessageMap.v8_error_duplicate_identifier, position); - } - const isExportAlreadyExist = declarateExportSymbolIfInContext(name, position); - if (isExportAlreadyExist) { - raiseError(ErrorMessageMap.v8_error_duplicate_identifier, isExportAlreadyExist); - } - return; - } - function declarateLetSymbol(name: string, position: SourcePosition) { - if (!symbolScopeRecorder.declarateLetSymbol(name)) { - raiseError(ErrorMessageMap.v8_error_duplicate_identifier, position); - } - const isExportAlreadyExist = declarateExportSymbolIfInContext(name, position); - if (isExportAlreadyExist) { - raiseError(ErrorMessageMap.v8_error_duplicate_identifier, isExportAlreadyExist); - } - } - function declarateParam(name: string, position: SourcePosition) { - symbolScopeRecorder.declarateParam(name, position); - declarateExportSymbolIfInContext(name, position); - return; - } - function declarateExportSymbolIfInContext(name: string, position: SourcePosition) { - switch (getExportContext()) { - case ExportContext.NotInExport: - return null; - case ExportContext.InExport: { - setExportContext(ExportContext.NotInExport); - return declarateExportSymbol(name, position); - } - case ExportContext.InExportBinding: { - return declarateExportSymbol(name, position); - } - } - } - function declarateExportSymbol(name: string, position: SourcePosition) { - return symbolScopeRecorder.declarateExportSymbol(name, position); - } - function isVariableDeclarated(name: string) { - return symbolScopeRecorder.isVariableDeclarated(name); - } - function getSymbolType() { - return symbolScopeRecorder.getSymbolType() as NonFunctionalSymbolType; - } - function setSymbolType(symbolType: NonFunctionalSymbolType) { - symbolScopeRecorder.setSymbolType(symbolType); - } - /** - * Raise a error, if config recoverable set to false, it will throw a error and - * cause stack unwidning. - * @param message - * @param position - */ - function raiseError(message: string, position: SourcePosition) { - errorhandler.pushSyntaxErrors({ - message, - position, - }); - } - /** =========================================================== - * Parser internal Parse API - * =========================================================== - */ - /** ================================================== - * Top level parse function - * ================================================== - */ - function parseProgram() { - const body: Array = []; - enterProgram(); - while (!match(SyntaxKinds.EOFToken)) { - body.push(parseModuleItem()); - } - for (const propertyHasInit of context.propertiesInitSet) { - raiseError(ErrorMessageMap.Syntax_error_Invalid_shorthand_property_initializer, propertyHasInit.start); - } - for (const duplicateProto of context.propertiesProtoDuplicateSet) { - raiseError( - ErrorMessageMap.syntax_error_property_name__proto__appears_more_than_once_in_object_literal, - duplicateProto.start, - ); - } - exitProgram(); - return Factory.createProgram( - body, - body.length === 0 ? getStartPosition() : cloneSourcePosition(body[0].start), - getEndPosition(), - ); - } - function parseModuleItem(): ModuleItem { - if (match(SyntaxKinds.AtPunctuator)) { - parseDecoratorListToCache(); - } - const token = getToken(); - switch (token) { - case SyntaxKinds.ImportKeyword: { - const { kind } = lookahead(); - if (kind === SyntaxKinds.DotOperator || kind === SyntaxKinds.ParenthesesLeftPunctuator) { - return parseStatementListItem(); - } - return parseImportDeclaration(); - } - case SyntaxKinds.ExportKeyword: - return parseExportDeclaration(); - default: - return parseStatementListItem(); - } - } - function parseStatementListItem(): StatementListItem { - const token = getToken(); - switch (token) { - // 'aync' maybe is - // 1. aync function -> declaration - // 2. aync arrow function -> statement(expressionStatement) - // 3. identifer -> statement (expressionStatement) - case SyntaxKinds.ConstKeyword: - case SyntaxKinds.FunctionKeyword: - case SyntaxKinds.ClassKeyword: - case SyntaxKinds.AtPunctuator: - return parseDeclaration(); - case SyntaxKinds.Identifier: - if (isContextKeyword("async")) { - const { kind, lineTerminatorFlag: flag } = lookahead(); - if (kind === SyntaxKinds.FunctionKeyword && flag == false) { - nextToken(); - return parseFunctionDeclaration(true); - } - } - return parseStatement(); - case SyntaxKinds.LetKeyword: - if (isLetPossibleIdentifier()) { - return parseStatement(); - } - return parseDeclaration(); - default: - return parseStatement(); - } - } - function isLetPossibleIdentifier() { - const { kind: kind } = lookahead(); - if ( - kind === SyntaxKinds.BracesLeftPunctuator || // object pattern - kind === SyntaxKinds.BracketLeftPunctuator || // array pattern - kind === SyntaxKinds.Identifier || // id - kind === SyntaxKinds.AwaitKeyword || - kind === SyntaxKinds.YieldKeyword - ) { - return false; - } - return true; - } - /** - * Parse Declaration - * - * ``` - * Declaration := ('let' | 'const') BindingLst - * := FunctionDeclaration - * := FunctionGeneratorDeclaration - * := 'async' FunctionDeclaration - * := 'async' FunctionGeneratorDeclaration - * := ClassDeclaration - * ``` - * when call parseDeclaration, please make sure currentToken is - * - `let` or `const` keyword - * - `function` keyword - * - `class` keyword - * - `async` with `function` keyword - * - * ref: https://tc39.es/ecma262/#prod-Declaration - * @returns - */ - function parseDeclaration(): Declaration { - const token = getToken(); - switch (token) { - // async function declaration - case SyntaxKinds.Identifier: - if (isContextKeyword("async")) { - nextToken(); - if (getLineTerminatorFlag()) { - raiseError(ErrorMessageMap.missing_semicolon, getStartPosition()); - } - return parseFunctionDeclaration(true); - } else { - throw createUnreachError(); - } - // function delcaration - case SyntaxKinds.FunctionKeyword: - return parseFunctionDeclaration(false); - case SyntaxKinds.ConstKeyword: - case SyntaxKinds.LetKeyword: - return parseVariableDeclaration(); - case SyntaxKinds.AtPunctuator: - return parseClassDeclaration(parseDecoratorList()); - case SyntaxKinds.ClassKeyword: - return parseClassDeclaration(null); - default: - throw createUnexpectError(); - } - } - /** - * ref: https://tc39.es/ecma262/#prod-Statement - */ - function parseStatement(): Statement { - const token = getToken(); - switch (token) { - case SyntaxKinds.SwitchKeyword: - return parseSwitchStatement(); - case SyntaxKinds.ContinueKeyword: - return parseContinueStatement(); - case SyntaxKinds.BreakKeyword: - return parseBreakStatement(); - case SyntaxKinds.ReturnKeyword: - return parseReturnStatement(); - case SyntaxKinds.BracesLeftPunctuator: - return parseBlockStatement(); - case SyntaxKinds.TryKeyword: - return parseTryStatement(); - case SyntaxKinds.ThrowKeyword: - return parseThrowStatement(); - case SyntaxKinds.WithKeyword: - return parseWithStatement(); - case SyntaxKinds.DebuggerKeyword: - return parseDebuggerStatement(); - case SyntaxKinds.SemiPunctuator: - return parseEmptyStatement(); - case SyntaxKinds.IfKeyword: - return parseIfStatement(); - case SyntaxKinds.ForKeyword: - return parseForStatement(); - case SyntaxKinds.WhileKeyword: - return parseWhileStatement(); - case SyntaxKinds.DoKeyword: - return parseDoWhileStatement(); - case SyntaxKinds.VarKeyword: - return parseVariableDeclaration(); - default: - if (match(SyntaxKinds.Identifier) && lookahead().kind === SyntaxKinds.ColonPunctuator) { - return parseLabeledStatement(); - } - return parseExpressionStatement(); - } - } - /** - * This is a critial helper function for transform expression (major is ObjectExpression - * and ArrayExpression) to Pattern (`BindingObjectPattern`, `BindingArrayPattern`, `AssignmentObjectPattern` - * `AssignmentArrayPattern`). - * - * ### Use Case : ParseAssignmentExpression - * This function is used when `parseAssignmentExpression`, because parseAssignmentExpression - * would parse left as expression first, when left is followed by assignment operator, we need - * to transform expression to AssignmentPattern. - * - * ### Use Case : ParseArrowFunctionExpression - * When `parseArrowFunctionExpression`, it would use this function too. Because `parseArrowFunctionExpresssion` - * might accept argument (array of `AssignmentExpression`) as param, so we need to transform arguments to function - * parameter, which is transform `AssignmenExpression` to `BiningElement`(`Identifier` or `BindingPattern`). - * - * ### Paramemter: isBinding - * Most of BindingPattern and AssignmentPattern's production rule is alike, one key different is that BindingPattern - * `PropertyName` can only have `BindingElement`, but `PropertyName` of AssignmentPattern can have LeftHandSideExpression - * so we add a param `isBinding` to determinate is transform to BindingPattern or not. - * @param {Expression} expr target for transform to Pattern - * @param {boolean} isBinding Is transform to BindingPattern - */ - function exprToPattern(expr: Expression, isBinding: boolean): Pattern { - // TODO, remove impl function. - return exprToPatternImpl(expr, isBinding); - } - function exprToPatternImpl(node: Expression, isBinding: boolean): Pattern { - /** - * parentheses in pattern only allow in Assignment Pattern - * for MemberExpression and Identifier - */ - if (node.parentheses) { - if (isBinding || (!isBinding && !isMemberExpression(node) && !isIdentifer(node))) - // recoverable error - raiseError(ErrorMessageMap.babel_error_invalid_parenthesized_pattern, node.start); - } - switch (node.kind) { - case SyntaxKinds.AssigmentExpression: { - return assignmentExpressionToAssignmentPattern(node, isBinding); - } - case SyntaxKinds.SpreadElement: { - return spreadElementToFunctionRestParameter(node); - } - case SyntaxKinds.ArrayExpression: { - return arrayExpressionToArrayPattern(node, isBinding); - } - case SyntaxKinds.ObjectExpression: { - return objectExpressionToObjectPattern(node, isBinding); - } - case SyntaxKinds.Identifier: - declarateSymbolInBindingPatternAsParam(node.name, isBinding, node.start); - return node as Identifier; - case SyntaxKinds.MemberExpression: - if (!isBinding) { - return node as Pattern; - } - // fall to error - // eslint-disable-next-line no-fallthrough - default: - throw createMessageError(ErrorMessageMap.syntax_error_invalid_assignment_left_hand_side); - } - } - /** - * ## Transform Assignment Expression - * @param expr - * @param isBinding - * @returns - */ - function assignmentExpressionToAssignmentPattern(expr: AssigmentExpression, isBinding: boolean) { - const left = isBinding ? helperCheckPatternWithBinding(expr.left) : expr.left; - if (expr.operator !== SyntaxKinds.AssginOperator) { - raiseError(ErrorMessageMap.syntax_error_invalid_assignment_left_hand_side, expr.start); - } - return Factory.createAssignmentPattern(left as Pattern, expr.right, expr.start, expr.end); - } - /** - * Transform a assignment pattern to a binding assignment pattern - * @param leftValue - * @returns - */ - function helperCheckPatternWithBinding(leftValue: Pattern): Pattern { - if (isObjectPattern(leftValue)) { - for (const property of leftValue.properties) { - if (isObjectPatternProperty(property)) { - if (property.value && isMemberExpression(property.value)) { - raiseError(ErrorMessageMap.babel_error_binding_member_expression, property.start); - } - if ( - property.value && - (isMemberExpression(property.value) || isIdentifer(property.value)) && - property.value.parentheses - ) { - // recoverable error - raiseError(ErrorMessageMap.babel_error_invalid_parenthesized_pattern, leftValue.start); - } - } - } - return leftValue; - } - if (isAssignmentPattern(leftValue)) { - helperCheckPatternWithBinding(leftValue.left); - return leftValue; - } - if (isRestElement(leftValue)) { - helperCheckPatternWithBinding(leftValue.argument); - return leftValue; - } - if (isArrayPattern(leftValue)) { - for (const pat of leftValue.elements) { - if (pat) { - helperCheckPatternWithBinding(pat); - } - } - } - if (isMemberExpression(leftValue) || isIdentifer(leftValue)) { - if (leftValue.parentheses) { - // recoverable error - raiseError(ErrorMessageMap.babel_error_invalid_parenthesized_pattern, leftValue.start); - } - } - return leftValue; - } - /** - * ## Transform `SpreadElement` to RestElement in function param - * - * Accoring to production rule, `FunctionRestParameter` is just alias - * of `BindingRestElement` which be used in ArrayPattern. - * @param spreadElement - * @returns - */ - function spreadElementToFunctionRestParameter(spreadElement: SpreadElement) { - return spreadElementToArrayRestElement(spreadElement, true); - } - /** - * ## Transform `ArrayExpression` to `ArrayPattern` - * @param elements - * @param isBinding - * @returns - */ - function arrayExpressionToArrayPattern(expr: ArrayExpression, isBinding: boolean): ArrayPattern { - const arrayPatternElements: Array = []; - const restElementIndexs = []; - for (let index = 0; index < expr.elements.length; ++index) { - const element = expr.elements[index]; - if (!element) { - arrayPatternElements.push(null); - continue; - } - if (isSpreadElement(element)) { - arrayPatternElements.push(spreadElementToArrayRestElement(element, isBinding)); - restElementIndexs.push(index); - continue; - } - arrayPatternElements.push(exprToPattern(element, isBinding)); - } - if ( - restElementIndexs.length > 1 || - (restElementIndexs.length === 1 && - (restElementIndexs[0] !== arrayPatternElements.length - 1 || expr.trailingComma)) - ) { - raiseError(ErrorMessageMap.syntax_error_parameter_after_rest_parameter, expr.end); - } - return Factory.createArrayPattern(arrayPatternElements, expr.start, expr.end); - } - /** - * ## Transform `SpreadElement` in ArrayPattern - * This function transform spread element to following two production rule AST: - * - * - `BindingRestElement` in `ArrayBindingPattern` - * - `AssignmentRestElement` in `ArrayAssignmentPattern` - * - * According to production rule, `BindingRestElement`'s argument can only be identifier or ObjectPattern - * or ArrayPattern, and argument of `AssignmentRestProperty` can only be identifier or memberExpression. - * ``` - * BindingRestElement := ... BindingIdentifier - * := ... BindingPattern - * AssignmentRestElement :=... DestructuringAssignmentTarget - * ``` - * @param spreadElement - * @param isBinding - */ - function spreadElementToArrayRestElement(spreadElement: SpreadElement, isBinding: boolean): RestElement { - const argument = exprToPattern(spreadElement.argument, isBinding); - if (isAssignmentPattern(argument)) { - // recoverable error - raiseError( - ErrorMessageMap.v8_error_rest_assignment_property_must_be_followed_by_an_identifier_in_declaration_contexts, - argument.start, - ); - } - return Factory.createRestElement(argument, spreadElement.start, argument.end); - } - /** - * ## Transform `ObjectExpression` To `ObjectPattern` - * @param properties - * @param isBinding - * @returns - */ - function objectExpressionToObjectPattern(expr: ObjectExpression, isBinding: boolean): ObjectPattern { - const objectPatternProperties: Array = []; - const restElementIndexs = []; - for (let index = 0; index < expr.properties.length; ++index) { - const property = expr.properties[index]; - switch (property.kind) { - case SyntaxKinds.ObjectProperty: - objectPatternProperties.push(ObjectPropertyToObjectPatternProperty(property, isBinding)); - break; - case SyntaxKinds.SpreadElement: - restElementIndexs.push(index); - objectPatternProperties.push(spreadElementToObjectRestElement(property, isBinding)); - break; - default: - throw createMessageError(ErrorMessageMap.invalid_left_value); - } - } - if ( - restElementIndexs.length > 1 || - (restElementIndexs.length === 1 && - (restElementIndexs[0] !== objectPatternProperties.length - 1 || expr.trailingComma)) - ) { - raiseError(ErrorMessageMap.syntax_error_parameter_after_rest_parameter, expr.end); - } - return Factory.createObjectPattern(objectPatternProperties, expr.start, expr.end); - } - /** - * ## Transform `SpreadElement` in ObjectPattern - * This function transform spread element to following two production rule AST: - * - * - `BindingRestProperty` in BindingObjectPattern - * - `AssignmentRestProperty` in AssignObjectPattern - * - * According to production rule, `BindingRestProperty`'s argument can only be identifier, - * and argument of `AssignmentRestProperty` can only be identifier or memberExpression. - * ``` - * BindingRestProperty := ... BindingIdentifier - * AssignmentRestProperty:= ... DestructuringAssignmentTarget - * ``` - */ - function spreadElementToObjectRestElement(spreadElement: SpreadElement, isBinding: boolean): RestElement { - const argument = exprToPattern(spreadElement.argument, isBinding); - if (isBinding) { - if (!isIdentifer(argument)) { - // recoverable error - raiseError( - ErrorMessageMap.v8_error_rest_binding_property_must_be_followed_by_an_identifier_in_declaration_contexts, - argument.start, - ); - } - } else { - if (!isIdentifer(argument) && !isMemberExpression(argument)) { - // recoverable error - raiseError( - ErrorMessageMap.v8_error_rest_assignment_property_must_be_followed_by_an_identifier_in_declaration_contexts, - argument.start, - ); - } - } - return Factory.createRestElement(argument, spreadElement.start, argument.end); - } - function ObjectPropertyToObjectPatternProperty( - objectPropertyNode: ObjectProperty, - isBinding = false, - ): ObjectPatternProperty | AssignmentPattern { - // object property's value can not has parentheses. - if (objectPropertyNode.value && objectPropertyNode.value.parentheses && isBinding) { - // recoverable error - raiseError(ErrorMessageMap.babel_error_invalid_parenthesized_pattern, objectPropertyNode.start); - } - if (context.propertiesProtoDuplicateSet.has(objectPropertyNode.key)) { - context.propertiesProtoDuplicateSet.delete(objectPropertyNode.key); - } - // When a property name is a CoverInitializedName, we need to cover to assignment pattern - if (context.propertiesInitSet.has(objectPropertyNode) && !objectPropertyNode.shorted) { - context.propertiesInitSet.delete(objectPropertyNode); - if (objectPropertyNode.computed || !isIdentifer(objectPropertyNode.key)) { - // property name of assignment pattern can not use computed propertyname or literal - throw createMessageError( - ErrorMessageMap.assignment_pattern_left_value_can_only_be_idenifier_or_pattern, - ); - } - declarateSymbolInBindingPatternAsParam( - objectPropertyNode.key.name, - isBinding, - objectPropertyNode.start, - ); - return Factory.createAssignmentPattern( - objectPropertyNode.key, - objectPropertyNode.value as Expression, - objectPropertyNode.start, - objectPropertyNode.end, - ); - } - const patternValue = !objectPropertyNode.value - ? objectPropertyNode.value - : exprToPatternImpl(objectPropertyNode.value, isBinding); - // for binding pattern, member expression is not allow - // - for assignment pattern: value production rule is `DestructuringAssignmentTarget`, which just a LeftHandSideExpression - // - for binding pattern: value production rule is `BindingElement`, which only can be object-pattern, array-pattern, id. - if (isBinding && patternValue && isMemberExpression(patternValue)) { - raiseError(ErrorMessageMap.babel_error_binding_member_expression, patternValue.start); - } - return Factory.createObjectPatternProperty( - objectPropertyNode.key, - patternValue, - objectPropertyNode.computed, - objectPropertyNode.shorted, - objectPropertyNode.start, - objectPropertyNode.end, - ); - } - function declarateSymbolInBindingPatternAsParam( - name: string, - isBinding: boolean, - position: SourcePosition, - ) { - if (isBinding) { - declarateParam(name, position); - } - } - /** - * Parse For-related Statement, include ForStatement, ForInStatement, ForOfStatement. - * - * This function is pretty complex and hard to understand, some function's flag is only - * used in this function. ex: allowIn flag of parseExpression, parseAssignmentExpression. - * @returns {ForStatement | ForInStatement | ForOfStatement} - */ - function parseForStatement(): ForStatement | ForInStatement | ForOfStatement { - // symbolScopeRecorder.enterPreBlockScope(); - symbolScopeRecorder.enterBlockSymbolScope(); - const { start: keywordStart } = expect(SyntaxKinds.ForKeyword); - // First, parse await modifier and lefthandside or init of for-related statement, - // init might start with let, const, var keyword, but if is let keyword need to - // lookahead to determinate is identifier. - // delcaration in there should not eat semi, becuase semi is seperator of ForStatement, - // and might not need init for pattern, because maybe used by ForIn or ForOf. - // If not start with let, var or const keyword, it should be expression, but this - // expression can not take `in` operator as operator in toplevel, so we need pass - // false to disallow parseExpression to take in as operator - let isAwait: SourcePosition | null = null, - isParseLetAsExpr: SourcePosition | null = null, - leftOrInit: VariableDeclaration | Expression | null = null; - if (match(SyntaxKinds.AwaitKeyword)) { - isAwait = getStartPosition(); - nextToken(); - if (!config.allowAwaitOutsideFunction && !isCurrentScopeParseAwaitAsExpression()) { - raiseError(ErrorMessageMap.babel_error_invalid_await, isAwait); - } - } - expect(SyntaxKinds.ParenthesesLeftPunctuator); - if (match([SyntaxKinds.LetKeyword, SyntaxKinds.ConstKeyword, SyntaxKinds.VarKeyword])) { - if (match(SyntaxKinds.LetKeyword) && isLetPossibleIdentifier()) { - isParseLetAsExpr = getStartPosition(); - leftOrInit = parseExpressionDisallowIn(); - } else { - leftOrInit = disAllowInOperaotr(() => parseVariableDeclaration(true)); - } - } else if (match(SyntaxKinds.SemiPunctuator)) { - // for test case `for(;;)` - leftOrInit = null; - } else { - leftOrInit = parseExpressionDisallowIn(); - } - // Second is branching part, determinate the branch by following token - // - if start with semi it should be ForStatement, - // - if is in operator, it should be ForInStatement, - // - if is of contextual keyword, it should be ForOfStatement. - // then according to branch case, parse the following part and do the - // sematic check. - // - ForStatement: if init is variable declaration pattern, it need init. - // - ForInStatement: if left is variable decalration, must not have init, and delcaration length must be 1. - // then if left is expression, must transform it to pattern. - // - ForOfStatement: same as ForInStatement. - // There is one case that even we disallow in operator in top level, there maybe - // wrong init of expression like `for(a = 0 in []);` or `for(a=0 of [])` which would - // make leftOrInit parse all token in () as a expression, so we need to check if those - // case happend. - if (match(SyntaxKinds.SemiPunctuator)) { - if (isAwait) { - // recoverable error - raiseError(ErrorMessageMap.extra_error_for_await_not_of_loop, isAwait); - } - if (leftOrInit && isVarDeclaration(leftOrInit)) { - for (const delcar of leftOrInit.declarations) { - if ((isArrayPattern(delcar.id) || isObjectPattern(delcar.id)) && !delcar.init) { - // recoverable error - raiseError(ErrorMessageMap.babel_error_destructing_pattern_must_need_initializer, delcar.start); - } - } - } - nextToken(); - let test: Expression | null = null, - update: Expression | null = null; - if (!match(SyntaxKinds.SemiPunctuator)) { - test = parseExpressionAllowIn(); - } - expect(SyntaxKinds.SemiPunctuator); - if (!match(SyntaxKinds.ParenthesesRightPunctuator)) { - update = parseExpressionAllowIn(); - } - expect(SyntaxKinds.ParenthesesRightPunctuator); - const body = parseForStatementBody(); - const forStatement = Factory.createForStatement( - body, - leftOrInit, - test, - update, - keywordStart, - cloneSourcePosition(body.end), - ); - staticSematicEarlyErrorForFORStatement(forStatement); - return forStatement; - } - // unreach case, even if syntax error, when leftOrInit, it must match semi token. - // and because it match semi token, if would enter forStatement case, will not - // reach there. even syntax error, error would be throw at parseExpression or - // parseDeclaration. - if (!leftOrInit) { - throw createUnreachError(); - } - // for case `for(a = 0 of [])`; leftOrInit would parse all token before `of` as one expression - // in this case , leftOrInit would be a assignment expression, and when it pass to toAssignment - // function, it would transform to assignment pattern, so we need to checko if there is Assignment - // pattern, it is , means original is assignment expression, it should throw a error. - if (!isVarDeclaration(leftOrInit)) { - leftOrInit = exprToPattern(leftOrInit, false) as Expression; - if (isAssignmentPattern(leftOrInit)) { - throw createMessageError(ErrorMessageMap.invalid_left_value); - } - } - // branch case for `for-in` statement - if (match(SyntaxKinds.InKeyword)) { - if (isAwait) { - // recoverable error - raiseError(ErrorMessageMap.extra_error_for_await_not_of_loop, isAwait); - } - if (isVarDeclaration(leftOrInit)) { - helperCheckDeclarationmaybeForInOrForOfStatement(leftOrInit, "ForIn"); - } - nextToken(); - const right = parseExpressionAllowIn(); - expect(SyntaxKinds.ParenthesesRightPunctuator); - const body = parseForStatementBody(); - const forInStatement = Factory.createForInStatement( - leftOrInit, - right, - body, - keywordStart, - cloneSourcePosition(body.end), - ); - staticSematicEarlyErrorForFORStatement(forInStatement); - return forInStatement; - } - // branch case for `for-of` statement - if (isContextKeyword("of")) { - if (isVarDeclaration(leftOrInit)) { - helperCheckDeclarationmaybeForInOrForOfStatement(leftOrInit, "ForOf"); - } - if (isParseLetAsExpr) { - raiseError(ErrorMessageMap.extra_error_for_of_can_not_use_let_as_identifier, isParseLetAsExpr); - } - nextToken(); - const right = parseAssignmentExpressionAllowIn(); - expect(SyntaxKinds.ParenthesesRightPunctuator); - const body = parseForStatementBody(); - const forOfStatement = Factory.createForOfStatement( - !!isAwait, - leftOrInit, - right, - body, - keywordStart, - cloneSourcePosition(body.end), - ); - staticSematicEarlyErrorForFORStatement(forOfStatement); - return forOfStatement; - } - throw createUnexpectError(); - } - function parseForStatementBody(): Statement { - const stmt = parseAsLoop(parseStatement); - symbolScopeRecorder.exitSymbolScope(); - return stmt; - } - function staticSematicEarlyErrorForFORStatement(statement: ForStatement | ForInStatement | ForOfStatement) { - if (checkIsLabelledFunction(statement.body)) { - raiseError( - isInStrictMode() - ? ErrorMessageMap.syntax_error_functions_declare_strict_mode - : ErrorMessageMap.syntax_error_functions_declare_non_strict_mode, - statement.body.start, - ); - } - } - /** - * Helper function for check sematic error of VariableDeclaration of ForInStatement and ForOfStatement, - * please reference to comment in parseForStatement. - * @param {VariableDeclaration} declaration - */ - function helperCheckDeclarationmaybeForInOrForOfStatement( - declaration: VariableDeclaration, - kind: "ForIn" | "ForOf", - ) { - if (declaration.declarations.length > 1) { - // recoverable error - raiseError( - ErrorMessageMap.v8_error_Invalid_left_hand_side_in_for_in_loop_must_have_a_single_binding, - declaration.start, - ); - } - const delcarationVariant = declaration.variant; - const onlyDeclaration = declaration.declarations[0]; - if (kind === "ForIn") { - if (onlyDeclaration.init !== null) { - if (delcarationVariant === "var" && !isInStrictMode() && isIdentifer(onlyDeclaration.id)) { - return; - } - // recoverable error - raiseError( - ErrorMessageMap.syntax_error_for_in_loop_head_declarations_may_not_have_initializer, - onlyDeclaration.start, - ); - } - } else { - if (onlyDeclaration.init !== null) { - // recoverable error - raiseError( - ErrorMessageMap.syntax_error_for_of_loop_variable_declaration_may_not_have_an_initializer, - onlyDeclaration.init.start, - ); - } - } - } - function parseIfStatement(): IfStatement { - const { start: keywordStart } = expect(SyntaxKinds.IfKeyword); - expect(SyntaxKinds.ParenthesesLeftPunctuator); - const test = parseExpressionAllowIn(); - const { end: headerEnd } = expect(SyntaxKinds.ParenthesesRightPunctuator); - context.lastTokenIndexOfIfStmt = headerEnd.index; - const consequnce = parseStatement(); - if (match(SyntaxKinds.ElseKeyword)) { - nextToken(); - const alter = parseStatement(); - return Factory.createIfStatement(test, consequnce, alter, keywordStart, cloneSourcePosition(alter.end)); - } - const ifStatement = Factory.createIfStatement( - test, - consequnce, - null, - keywordStart, - cloneSourcePosition(consequnce.end), - ); - staticSematicEarlyErrorForIfStatement(ifStatement); - return ifStatement; - } - function staticSematicEarlyErrorForIfStatement(statement: IfStatement) { - if (checkIsLabelledFunction(statement.conseqence)) { - raiseError( - isInStrictMode() - ? ErrorMessageMap.syntax_error_functions_declare_strict_mode - : ErrorMessageMap.syntax_error_functions_declare_non_strict_mode, - statement.conseqence.start, - ); - } - if (statement.alternative && checkIsLabelledFunction(statement.alternative)) { - raiseError( - isInStrictMode() - ? ErrorMessageMap.syntax_error_functions_declare_strict_mode - : ErrorMessageMap.syntax_error_functions_declare_non_strict_mode, - statement.alternative.start, - ); - } - } - function parseWhileStatement(): WhileStatement { - const { start: keywordStart } = expect(SyntaxKinds.WhileKeyword); - expect(SyntaxKinds.ParenthesesLeftPunctuator); - const test = parseExpressionAllowIn(); - expect(SyntaxKinds.ParenthesesRightPunctuator); - const body = parseAsLoop(parseStatement); - const whileStatement = Factory.createWhileStatement( - test, - body, - keywordStart, - cloneSourcePosition(body.end), - ); - staticSematicEarlyErrorForWhileStatement(whileStatement); - return whileStatement; - } - function checkIsLabelledFunction(statement: Statement) { - while (statement.kind === SyntaxKinds.LabeledStatement) { - if (statement.body.kind === SyntaxKinds.FunctionDeclaration) { - return true; - } - statement = statement.body; - } - } - function staticSematicEarlyErrorForWhileStatement(statement: WhileStatement) { - if (checkIsLabelledFunction(statement.body)) { - // recoverable error - raiseError( - isInStrictMode() - ? ErrorMessageMap.syntax_error_functions_declare_strict_mode - : ErrorMessageMap.syntax_error_functions_declare_non_strict_mode, - statement.body.start, - ); - } - } - function parseDoWhileStatement(): DoWhileStatement { - const { start: keywordStart } = expect(SyntaxKinds.DoKeyword); - const body = parseAsLoop(parseStatement); - expect(SyntaxKinds.WhileKeyword); - expect(SyntaxKinds.ParenthesesLeftPunctuator); - const test = parseExpressionAllowIn(); - const { end: punctEnd } = expect(SyntaxKinds.ParenthesesRightPunctuator); - isSoftInsertSemi(); - const doWhileStatement = Factory.createDoWhileStatement(test, body, keywordStart, punctEnd); - staticSematicEarlyErrorForDoWhileStatement(doWhileStatement); - return doWhileStatement; - } - function staticSematicEarlyErrorForDoWhileStatement(statement: DoWhileStatement) { - if (checkIsLabelledFunction(statement.body)) { - // recoverable error - raiseError( - isInStrictMode() - ? ErrorMessageMap.syntax_error_functions_declare_strict_mode - : ErrorMessageMap.syntax_error_functions_declare_non_strict_mode, - statement.body.start, - ); - } - } - function parseBlockStatement() { - const { start: puncStart } = expect(SyntaxKinds.BracesLeftPunctuator); - enterBlockScope(); - const body: Array = []; - while (!match(SyntaxKinds.BracesRightPunctuator) && !match(SyntaxKinds.EOFToken)) { - body.push(parseStatementListItem()); - } - exitBlockScope(); - const { end: puncEnd } = expect(SyntaxKinds.BracesRightPunctuator); - return Factory.createBlockStatement(body, puncStart, puncEnd); - } - function parseSwitchStatement() { - const { start: keywordStart } = expect(SyntaxKinds.SwitchKeyword); - expect(SyntaxKinds.ParenthesesLeftPunctuator); - const discriminant = parseExpressionAllowIn(); - expect(SyntaxKinds.ParenthesesRightPunctuator); - const { nodes, end } = parseAsSwitch(parseSwitchCases); - return Factory.createSwitchStatement(discriminant, nodes, keywordStart, end); - } - function parseSwitchCases(): ASTArrayWithMetaData { - enterBlockScope(); - const { start } = expect(SyntaxKinds.BracesLeftPunctuator); - const cases: Array = []; - let haveDefault = false; - while (!match(SyntaxKinds.BracesRightPunctuator) && !match(SyntaxKinds.EOFToken)) { - let test: Expression | null = null; - const start = getStartPosition(); - if (match(SyntaxKinds.CaseKeyword)) { - nextToken(); - test = parseExpressionAllowIn(); - } else if (match(SyntaxKinds.DefaultKeyword)) { - const start = getStartPosition(); - nextToken(); - if (haveDefault) { - // recoverable error - raiseError(ErrorMessageMap.v8_error_more_than_one_default_clause_in_switch_statement, start); - } else { - haveDefault = true; - } - } - expect(SyntaxKinds.ColonPunctuator); - const consequence: Array = []; - while ( - !match([ - SyntaxKinds.BracesRightPunctuator, - SyntaxKinds.EOFToken, - SyntaxKinds.CaseKeyword, - SyntaxKinds.DefaultKeyword, - ]) - ) { - consequence.push(parseStatementListItem()); - } - const end = getStartPosition(); - cases.push(Factory.createSwitchCase(test, consequence, start, end)); - } - const { end } = expect(SyntaxKinds.BracesRightPunctuator); - exitBlockScope(); - return { - nodes: cases, - start, - end, - }; - } - function parseContinueStatement(): ContinueStatement { - const { start: keywordStart, end: keywordEnd } = expect(SyntaxKinds.ContinueKeyword); - staticSematicEarlyErrorForContinueStatement(keywordStart); - if (match(SyntaxKinds.Identifier) && !getLineTerminatorFlag()) { - const id = parseIdentifierReference(); - shouldInsertSemi(); - staticSematicEarlyErrorForLabelInContinueStatement(id); - return Factory.createContinueStatement(id, keywordStart, cloneSourcePosition(id.end)); - } - shouldInsertSemi(); - return Factory.createContinueStatement(null, keywordStart, keywordEnd); - } - function staticSematicEarlyErrorForContinueStatement(start: SourcePosition) { - if (!isContinueValidate()) { - // recoverable error - raiseError(ErrorMessageMap.syntax_error_continue_must_be_inside_loop, start); - } - } - function staticSematicEarlyErrorForLabelInContinueStatement(label: Identifier) { - if (!canLabelReach(label.name)) { - // recoverable error - raiseError(ErrorMessageMap.syntax_error_label_not_found, label.start); - } - } - /** - * Parse Break Statement. - * ``` - * BreakStatement := break; - * := break [no lineTerminator] LabeledIdentifier; - * ``` - * @returns {BreakStatement} - */ - function parseBreakStatement(): BreakStatement { - const { start, end } = expect(SyntaxKinds.BreakKeyword); - if (match(SyntaxKinds.Identifier) && !getLineTerminatorFlag()) { - const label = parseIdentifierReference(); - shouldInsertSemi(); - staticSematicEarlyErrorForLabelInBreakStatement(label); - return Factory.createBreakStatement(label, start, end); - } - shouldInsertSemi(); - const breakStmt = Factory.createBreakStatement(null, start, end); - staticSematicEarlyErrorForBreakStatement(breakStmt); - return breakStmt; - } - /** - * Spec def early error checking for break statement. - * @param {BreakStatement} breakStmt - * reference: https://tc39.es/ecma262/#sec-break-statement-static-semantics-early-errors - */ - function staticSematicEarlyErrorForBreakStatement(breakStmt: BreakStatement) { - if (!isBreakValidate()) { - // recoverable error - raiseError(ErrorMessageMap.syntax_error_unlabeled_break_must_be_inside_loop_or_switch, breakStmt.start); - } - } - /** - * Spec def early error checking for break statement with break label - * @param {Identifier} label - * reference: https://tc39.es/ecma262/#sec-break-statement-static-semantics-early-errors - */ - function staticSematicEarlyErrorForLabelInBreakStatement(label: Identifier) { - if (!canLabelReach(label.name)) { - // recoverable error - raiseError(ErrorMessageMap.syntax_error_label_not_found, label.start); - } - } - /** - * Parse labeled statement - * ``` - * LabelledStatement := LabelIdentifier: LabelledItem - * LabelledItem := Statement - * := FunctionDeclaration - * ``` - * @returns {LabeledStatement} - */ - function parseLabeledStatement(): LabeledStatement { - // TODO: using dev mode unreach checking - // if (!match(SyntaxKinds.Identifier) || lookahead().kind !== SyntaxKinds.ColonPunctuator) { - // } - const label = parseIdentifierReference(); - if (lexicalScopeRecorder.enterVirtualBlockScope("Label", label.name)) { - // recoverable error - raiseError(ErrorMessageMap.v8_error_label_has_already_been_declared, label.start); - } - expect(SyntaxKinds.ColonPunctuator); - const labeled = match(SyntaxKinds.FunctionKeyword) ? parseFunctionDeclaration(false) : parseStatement(); - lexicalScopeRecorder.exitVirtualBlockScope(); - staticSematicEarlyErrorForLabelStatement(labeled); - return Factory.createLabeledStatement( - label, - labeled, - cloneSourcePosition(label.start), - cloneSourcePosition(labeled.end), - ); - } - /** - * Spec def early error. using alter production rule. - * @param labeled - * reference: https://tc39.es/ecma262/#sec-labelled-statements-static-semantics-early-errors - */ - function staticSematicEarlyErrorForLabelStatement(labeled: Statement | FunctionDeclaration) { - if (isFunctionDeclaration(labeled)) { - if (labeled.generator) { - raiseError(ErrorMessageMap.syntax_error_generator_function_declare, labeled.start); - } - if (isInStrictMode()) { - raiseError(ErrorMessageMap.syntax_error_functions_declare_strict_mode, labeled.start); - } - } - } - function parseReturnStatement(): ReturnStatement { - const { start, end } = expect(SyntaxKinds.ReturnKeyword); - if (!isReturnValidate()) { - raiseError(ErrorMessageMap.syntax_error_return_not_in_function, start); - } - if (isSoftInsertSemi(true)) { - return Factory.createReturnStatement(null, start, end); - } - const expr = parseExpressionAllowIn(); - shouldInsertSemi(); - return Factory.createReturnStatement(expr, start, cloneSourcePosition(expr.end)); - } - function parseTryStatement(): TryStatement { - const { start: tryKeywordStart } = expect(SyntaxKinds.TryKeyword); - const body = parseBlockStatement(); - let handler: CatchClause | null = null, - finalizer: BlockStatement | null = null; - if (match(SyntaxKinds.CatchKeyword)) { - const catchKeywordStart = getStartPosition(); - nextToken(); - //symbolScopeRecorder.enterFunctionSymbolScope(); - enterCatchBlockScope(); - if (match(SyntaxKinds.ParenthesesLeftPunctuator)) { - nextToken(); - symbolScopeRecorder.enterCatchParam(); - // catch clause should not have init - const param = parseBindingElement(false); - if (!symbolScopeRecorder.setCatchParamTo(isIdentifer(param) ? SymbolType.Var : SymbolType.Let)) { - throw createMessageError(ErrorMessageMap.v8_error_duplicate_identifier); - } - // should check param is duplicate or not. - expect(SyntaxKinds.ParenthesesRightPunctuator); - const body = parseCatchBlock(); - handler = Factory.createCatchClause(param, body, catchKeywordStart, cloneSourcePosition(body.end)); - } else { - const body = parseCatchBlock(); - handler = Factory.createCatchClause(null, body, catchKeywordStart, cloneSourcePosition(body.end)); - } - exitCatchBlockScope(); - } - if (match(SyntaxKinds.FinallyKeyword)) { - nextToken(); - finalizer = parseBlockStatement(); - } - if (!handler && !finalizer) { - raiseError(ErrorMessageMap.v8_error_missing_catch_or_finally_after_try, tryKeywordStart); - } - return Factory.createTryStatement( - body, - handler, - finalizer, - tryKeywordStart, - cloneSourcePosition(finalizer ? finalizer.end : handler ? handler.end : body.end), - ); - } - function parseCatchBlock() { - const { start: puncStart } = expect(SyntaxKinds.BracesLeftPunctuator); - const body: Array = []; - while (!match(SyntaxKinds.BracesRightPunctuator) && !match(SyntaxKinds.EOFToken)) { - body.push(parseStatementListItem()); - } - const { end: puncEnd } = expect(SyntaxKinds.BracesRightPunctuator); - return Factory.createBlockStatement(body, puncStart, puncEnd); - } - function parseThrowStatement() { - const { start } = expect(SyntaxKinds.ThrowKeyword); - staticSmaticEarlyErrorForThrowStatement(); - const expr = parseExpressionAllowIn(); - shouldInsertSemi(); - return Factory.createThrowStatement(expr, start, cloneSourcePosition(expr.end)); - } - function staticSmaticEarlyErrorForThrowStatement() { - if (getLineTerminatorFlag()) { - raiseError(ErrorMessageMap.babel_error_illegal_newline_after_throw, getStartPosition()); - } - } - function parseWithStatement(): WithStatement { - const { start } = expect(SyntaxKinds.WithKeyword); - expect(SyntaxKinds.ParenthesesLeftPunctuator); - const object = parseExpressionAllowIn(); - expect(SyntaxKinds.ParenthesesRightPunctuator); - const body = parseStatement(); - const withStmt = Factory.createWithStatement(object, body, start, cloneSourcePosition(body.end)); - staticSmaticEarlyErrorForWithStatement(withStmt); - return withStmt; - } - function staticSmaticEarlyErrorForWithStatement(withStatement: WithStatement) { - if (isInStrictMode()) { - // recoverable error. - raiseError(ErrorMessageMap.babel_error_with_statement_in_strict_mode, withStatement.start); - } - } - function parseDebuggerStatement(): DebuggerStatement { - const { start, end } = expect(SyntaxKinds.DebuggerKeyword); - shouldInsertSemi(); - return Factory.createDebuggerStatement(start, end); - } - function parseEmptyStatement(): EmptyStatement { - const { start, end } = expect([SyntaxKinds.SemiPunctuator]); - return Factory.createEmptyStatement(start, end); - } - /** ================================================================= - * Parse Delcarations - * entry point reference: https://tc39.es/ecma262/#prod-Declaration - * ================================================================== - */ - /** - * Parse VariableStatement and LexicalBindingDeclaration. - * - * when in for-in statement, variable declaration do not need semi for - * ending, in binding pattern of for-in statement, variable declaration - * maybe do not need init.(for-in, for-of do not need, but for still need) - * - * Anthoer side, let can be identifier in VariableStatement. and parsrIdentifier - * function would always parse let as identifier if not in strict mode. so we need - * to implement custom function for check is identifier or value of pattern is let - * when in LexicalBindingDeclaration - * ``` - * VariableStatement := 'var' VariableDeclarationList - * LexicalBidningDeclaration := '(let | const)' LexicalBinding - * VariableDeclarationList := BindingIdentidier initalizer - * := BindingPattern initalizer - * LexicalBinding := BindingIdentidier initalizer - * := BindingPattern initalizer - * ``` - * @returns {VariableDeclaration} - */ - function parseVariableDeclaration(inForInit: boolean = false): VariableDeclaration { - const variableKind = match(SyntaxKinds.VarKeyword) ? "var" : "lexical"; - const { start: keywordStart, value: variant } = expect([ - SyntaxKinds.VarKeyword, - SyntaxKinds.ConstKeyword, - SyntaxKinds.LetKeyword, - ]); - let shouldStop = false, - isStart = true; - const declarations: Array = []; - const lastSymbolKind = getSymbolType(); - setSymbolType( - variant === "var" ? SymbolType.Var : variant === "const" ? SymbolType.Const : SymbolType.Let, - ); - if (getExportContext() === ExportContext.InExport) { - setExportContext(ExportContext.InExportBinding); - } - while (!shouldStop) { - if (isStart) { - isStart = false; - } else { - if (!match(SyntaxKinds.CommaToken)) { - shouldStop = true; - continue; - } - nextToken(); - } - const [id, scope] = parseWithCatpureLayer(() => parseBindingElement(false)); - const isBindingPattern = !isIdentifer(id); - if (variableKind === "lexical" && scope.kind !== "RHSLayer" && scope.letIdentifier.length > 0) { - throw new Error("TODO ERROR: Better"); - } - // custom logical for check is lexical binding have let identifier ? - if ( - // variable declarations binding pattern but but have init. - (isBindingPattern || variant === "const") && - !match(SyntaxKinds.AssginOperator) && - // variable declaration in for statement can existed with `of`, `in` operator - !inForInit - ) { - // recoverable error - raiseError(ErrorMessageMap.syntax_error_missing_init_in_const_declaration, id.start); - } - if (match(SyntaxKinds.AssginOperator)) { - nextToken(); - const init = parseAssignmentExpressionInheritIn(); - declarations.push( - Factory.createVariableDeclarator( - id, - init, - cloneSourcePosition(id.start), - cloneSourcePosition(init.end), - ), - ); - continue; - } - declarations.push( - Factory.createVariableDeclarator( - id, - null, - cloneSourcePosition(id.start), - cloneSourcePosition(id.end), - ), - ); - } - setSymbolType(lastSymbolKind); - setExportContext(ExportContext.NotInExport); - if (!inForInit) { - shouldInsertSemi(); - } - return Factory.createVariableDeclaration( - declarations, - variant as VariableDeclaration["variant"], - keywordStart, - declarations[declarations.length - 1].end, - ); - } - function parseFunctionDeclaration(isAsync: boolean) { - enterFunctionScope(isAsync); - const func = parseFunction(false); - exitFunctionScope(false); - // for function declaration, symbol should declar in parent scope. - const name = func.name!; - delcarateFcuntionSymbol(name.name, func.generator, func.start); - return Factory.transFormFunctionToFunctionDeclaration(func); - } - /** - * Parse function maybe call by parseFunctionDeclaration and parseFunctionExpression, - * first different of those two function is that function-declaration can not have null - * name. - * @returns {FunctionAST} - */ - function parseFunction(isExpression: boolean): FunctionAST { - const { start } = expect(SyntaxKinds.FunctionKeyword); - let generator = false; - if (match(SyntaxKinds.MultiplyOperator)) { - generator = true; - setCurrentFunctionContextAsGenerator(); - nextToken(); - } - const [[name, params], scope] = parseWithCatpureLayer(() => { - const name = parseFunctionName(isExpression); - if (!name && !isExpression) { - // recoverable error - raiseError(ErrorMessageMap.syntax_error_function_statement_requires_a_name, getStartPosition()); - } - const params = parseFunctionParam(); - return [name, params]; - }); - const body = parseFunctionBody(); - postStaticSematicEarlyErrorForStrictModeOfFunction(name, scope); - return Factory.createFunction( - name, - body, - params, - generator, - isCurrentScopeParseAwaitAsExpression(), - start, - cloneSourcePosition(body.end), - ); - } - /** - * Because we "use strict" directive is in function body, we will not sure - * if this function contain stric directive or not until we enter the function body. - * as the result, we need to check function name and function paramemter's name after - * parseFunctionBody. - * @param name - * @param params - */ - function postStaticSematicEarlyErrorForStrictModeOfFunction( - name: Identifier | null, - scope: StrictModeScope, - ) { - if (isInStrictMode()) { - checkStrictModeScopeError(scope); - if (name) { - if ( - name.name === "arugments" || - name.name === "eval" || - name.name === "yield" || - name.name === "let" || - PreserveWordSet.has(name.name) - ) { - raiseError(ErrorMessageMap.unexpect_keyword_in_stric_mode, name.start); - } - } - } - } - /** - * When parse name of function, can not just call parseIdentifier, because function name - * maybe await or yield, and function name's context rule is different from identifier in - * scope (function body). so there we need to implement special logical for parse function - * name. and you need to note that name of function expression and name of function delcaration - * have different context rule for parse function name. - * @param {boolean} isExpression - * @returns {Identifier | null} - */ - function parseFunctionName(isExpression: boolean): Identifier | null { - return parseWithLHSLayer(() => { - let name: Identifier | null = null; - // there we do not just using parseIdentifier function as the reason above - // let can be function name as other place - if (match([SyntaxKinds.Identifier, SyntaxKinds.LetKeyword])) { - name = parseIdentifierReference(); - } else { - if (match(SyntaxKinds.AwaitKeyword)) { - // for function expression, can await treat as function name is dep on current scope. - if (isExpression && isCurrentScopeParseAwaitAsExpression()) { - raiseError( - ErrorMessageMap.babel_error_can_not_use_await_as_identifier_inside_an_async_function, - getStartPosition(), - ); - } - // for function declaration, can await treat as function name is dep on parent scope. - if (!isExpression && isParentFunctionAsync()) { - raiseError( - ErrorMessageMap.babel_error_can_not_use_await_as_identifier_inside_an_async_function, - getStartPosition(), - ); - } - if (config.sourceType === "module") { - raiseError( - ErrorMessageMap.babel_error_can_not_use_await_as_identifier_inside_an_async_function, - getStartPosition(), - ); - } - name = parseIdentifierName(); - } else if (match(SyntaxKinds.YieldKeyword)) { - // for function expression, can yield treat as function name is dep on current scope. - if (isExpression && isCurrentScopeParseYieldAsExpression()) { - raiseError(ErrorMessageMap.babel_error_invalid_yield, getStartPosition()); - } - // for function declaration, can yield treat as function name is dep on parent scope. - if (!isExpression && isParentFunctionGenerator()) { - raiseError(ErrorMessageMap.babel_error_invalid_yield, getStartPosition()); - } - // if in strict mode, yield can not be function name. - if (isInStrictMode()) { - raiseError(ErrorMessageMap.babel_error_invalid_yield, getStartPosition()); - } - name = parseIdentifierName(); - } - } - return name; - }); - } - /** - * Parse Function Body - * ``` - * FunctionBody := '{' StatementList '}' - * StatementList := StatementList StatementListItem - * := StatementListItem - * ``` - * @return {FunctionBody} - */ - function parseFunctionBody(): FunctionBody { - const { start } = expect(SyntaxKinds.BracesLeftPunctuator); - const body: Array = []; - while (!match(SyntaxKinds.BracesRightPunctuator) && !match(SyntaxKinds.EOFToken)) { - body.push(parseStatementListItem()); - } - const { end } = expect(SyntaxKinds.BracesRightPunctuator); - return Factory.createFunctionBody(body, start, end); - } - /** - * Parse Function Params, parameter list is a spcial place for await and yield, - * function parameter list is in current function scope, so await and yield would - * parse as expression, but parameter list can not call await and yield expression. - * - * Anthoer thing is that trailing comma of restElement is error, multi restElement is - * error for function param list. - * ``` - * FunctionParams := '(' FunctionParamsList ')' - * := '(' FunctionParamsList ',' ')' - * := '(' FunctionPramsList ',' RestElement ')' - * := '(' RestElement ')' - * FunctiinParamList := FunctionParamList ',' FunctionParam - * := FunctionParam - * FunctionParam := BindingElement - * ``` - */ - function parseFunctionParam(): Array { - expect(SyntaxKinds.ParenthesesLeftPunctuator); - enterFunctionParameter(); - let isStart = true; - let isEndWithRest = false; - const params: Array = []; - while (!match(SyntaxKinds.ParenthesesRightPunctuator)) { - if (isStart) { - if (match(SyntaxKinds.CommaToken)) { - // recoverable error - raiseError(ErrorMessageMap.extra_error_unexpect_trailing_comma, getStartPosition()); - nextToken(); - } - isStart = false; - } else { - expect(SyntaxKinds.CommaToken); - } - if (match(SyntaxKinds.ParenthesesRightPunctuator)) { - continue; - } - // parse SpreadElement (identifer, Object, Array) - if (match(SyntaxKinds.SpreadOperator)) { - isEndWithRest = true; - params.push(parseRestElement(true)); - break; - } - params.push(parseBindingElement()); - } - if (!match(SyntaxKinds.ParenthesesRightPunctuator)) { - if (isEndWithRest && match(SyntaxKinds.CommaToken)) { - // recoverable error - raiseError( - ErrorMessageMap.babel_error_unexpected_trailing_comma_after_rest_element, - getStartPosition(), - ); - nextToken(); - } - throw createUnexpectError(); - } - nextToken(); - setContextIfParamsIsSimpleParameterList(params); - existFunctionParameter(); - return params; - } - /** - * Helper function for check if parameter list is simple - * parameter list or not, if is simple parameter, set - * the context. - * @param {Array} params - * @returns - */ - function setContextIfParamsIsSimpleParameterList(params: Array) { - for (const param of params) { - if (!isIdentifer(param)) { - setCurrentFunctionParameterListAsNonSimple(); - return; - } - } - } - function parseDecoratorListToCache() { - const decoratorList = parseDecoratorList(); - context.cache.decorators = decoratorList; - } - function parseDecoratorList(): [Decorator] { - const decoratorList: [Decorator] = [parseDecorator()]; - while (match(SyntaxKinds.AtPunctuator)) { - decoratorList.push(parseDecorator()); - } - if ( - match(SyntaxKinds.ClassKeyword) || - (match(SyntaxKinds.ExportKeyword) && config.sourceType === "module") || - isInClassScope() - ) { - return decoratorList; - } - raiseError( - ErrorMessageMap.babel_error_leading_decorators_must_be_attached_to_a_class_declaration, - decoratorList[0].start, - ); - return decoratorList; - } - function parseDecorator(): Decorator { - const { start } = expect(SyntaxKinds.AtPunctuator); - switch (getToken()) { - case SyntaxKinds.ParenthesesLeftPunctuator: { - nextToken(); - const expr = parseExpressionAllowIn(); - expect(SyntaxKinds.ParenthesesRightPunctuator); - return Factory.createDecorator(expr, start, expr.end); - } - default: { - let expr: Expression = parseIdentifierName(); - while (match(SyntaxKinds.DotOperator)) { - nextToken(); - const property = match(SyntaxKinds.PrivateName) ? parsePrivateName() : parseIdentifierName(); - expr = Factory.createMemberExpression( - false, - property, - expr, - false, - cloneSourcePosition(expr.start), - cloneSourcePosition(property.end), - ); - } - if (match(SyntaxKinds.ParenthesesLeftPunctuator)) { - const { nodes, end } = parseArguments(); - const callExpr = Factory.createCallExpression( - expr, - nodes, - false, - cloneSourcePosition(expr.start), - end, - ); - return Factory.createDecorator(callExpr, start, cloneSourcePosition(callExpr.end)); - } - return Factory.createDecorator(expr, start, expr.end); - } - } - } - - /** - * - */ - function parseClassDeclaration(decoratorList: Decorator[] | null): ClassDeclaration { - expectButNotEat(SyntaxKinds.ClassKeyword); - const classDelcar = parseClass(decoratorList); - if (classDelcar.id === null) { - raiseError(ErrorMessageMap.babel_error_a_class_name_is_required, classDelcar.start); - } - return Factory.transFormClassToClassDeclaration(classDelcar); - } - /** - * Parse Class - * ``` - * Class := 'class' identifer ('extends' LeftHandSideExpression) ClassBody - * ``` - * @returns {Class} - */ - function parseClass(decoratorList: Decorator[] | null): Class { - const { start } = expect(SyntaxKinds.ClassKeyword); - let name: Identifier | null = null; - if (match(BindingIdentifierSyntaxKindArray)) { - name = parseIdentifierReference(); - declarateLetSymbol(name.name, name.start); - } - let superClass: Expression | null = null; - if (match(SyntaxKinds.ExtendsKeyword)) { - enterClassScope(true); - nextToken(); - superClass = parseLeftHandSideExpression(); - } else { - enterClassScope(false); - } - const body = parseClassBody(); - existClassScope(); - return Factory.createClass(name, superClass, body, decoratorList, start, cloneSourcePosition(body.end)); - } - /** - * Parse ClassBody - * ``` - * ClassBody := '{' [ClassElement] '}' - * ``` - * @return {ClassBody} - */ - function parseClassBody(): ClassBody { - const { start } = expect(SyntaxKinds.BracesLeftPunctuator); - const classbody: ClassBody["body"] = []; - while (!match(SyntaxKinds.BracesRightPunctuator) && !match(SyntaxKinds.EOFToken)) { - if (match(SyntaxKinds.SemiPunctuator)) { - nextToken(); - continue; - } - classbody.push(parseClassElement()); - } - const { end } = expect(SyntaxKinds.BracesRightPunctuator); - return Factory.createClassBody(classbody, cloneSourcePosition(start), cloneSourcePosition(end)); - } - /** - * Parse ClassElement - * ``` - * ClassElement := MethodDefinition - * := 'static' MethodDefinition - * := FieldDefintion ; - * := 'static' FieldDefintion ; - * := ClassStaticBlock - * := ; (this production rule handle by caller) - * FieldDefintion := ClassElementName ('=' AssignmentExpression)? - * ``` - * - frist, parse 'static' keyword if possible, next follow cases - * 1. start with some method modifier like 'set', 'get', 'async', '*' must be methodDefintion - * 2. start with '{', must be static block - * - then parse ClassElement - * 1. if next token is '(', must be MethodDefintion, - * 2. else this only case is FieldDefinition with init or not. - * @returns {ClassElement} - */ - function parseClassElement(): ClassElement { - let decorators: [Decorator] | null = null; - if (match(SyntaxKinds.AtPunctuator)) { - decorators = parseDecoratorList(); - } - // parse static modifier - const isStatic = checkIsMethodStartWithStaticModifier(); - if (checkIsMethodStartWithModifier()) { - return parseMethodDefintion(true, undefined, isStatic, decorators) as ClassMethodDefinition; - } - if (match(SyntaxKinds.BracesLeftPunctuator) && isStatic) { - if (decorators) { - raiseError( - ErrorMessageMap.babel_error_decorators_can_not_be_used_with_a_static_block, - decorators[0].start, - ); - } - const { start } = expect(SyntaxKinds.BracesLeftPunctuator); - symbolScopeRecorder.enterFunctionSymbolScope(); - const body: Array = []; - while (!match(SyntaxKinds.BracesRightPunctuator) && !match(SyntaxKinds.EOFToken)) { - body.push(parseStatementListItem()); - } - symbolScopeRecorder.exitSymbolScope(); - const { end } = expect(SyntaxKinds.BracesRightPunctuator); - return Factory.createClassStaticBlock(body, start, end); - } - let accessor = false; - if (isContextKeyword("accessor")) { - const { kind, lineTerminatorFlag } = lookahead(); - if (kind === SyntaxKinds.Identifier && !lineTerminatorFlag) { - nextToken(); - accessor = true; - } - } - // parse ClassElementName - const isComputedRef = { isComputed: false }; - let key: PropertyName | PrivateName | undefined; - if (match(SyntaxKinds.PrivateName)) { - key = parsePrivateName(); - defPrivateName(key.name, key.start); - } else { - key = parsePropertyName(isComputedRef); - } - if (match(SyntaxKinds.ParenthesesLeftPunctuator)) { - return parseMethodDefintion( - true, - [key, isComputedRef.isComputed], - isStatic, - decorators, - ) as ClassMethodDefinition; - } - staticSematicForClassPropertyName(key, isComputedRef.isComputed, isStatic); - let propertyValue = undefined, - shorted = true; - if (match([SyntaxKinds.AssginOperator])) { - nextToken(); - shorted = false; - const [value, scope] = parseWithCatpureLayer(parseAssignmentExpressionAllowIn); - propertyValue = value; - staticSematicForClassPropertyValue(scope); - } - shouldInsertSemi(); - if (accessor) { - return Factory.createClassAccessorProperty( - key, - propertyValue, - isComputedRef.isComputed, - isStatic, - shorted, - decorators, - cloneSourcePosition(key.start), - cloneSourcePosition(key.end), - ); - } - return Factory.createClassProperty( - key, - propertyValue, - isComputedRef.isComputed, - isStatic, - shorted, - decorators, - cloneSourcePosition(key.start), - cloneSourcePosition(key.end), - ); - } - function checkIsMethodStartWithStaticModifier() { - const { kind } = lookahead(); - if (isContextKeyword("static")) { - switch (kind) { - // static - // static get/set/async - // static { - // static [] - // static * - case SyntaxKinds.Identifier: - case SyntaxKinds.PrivateName: - case SyntaxKinds.StringLiteral: - case SyntaxKinds.BracesLeftPunctuator: - case SyntaxKinds.BracketLeftPunctuator: - case SyntaxKinds.MultiplyOperator: - nextToken(); - return true; - default: - // static for/if ...etc - if (Keywords.find((kw) => kw === kind)) return true; - return false; - } - } - return false; - } - /** - * For a class scope, it must be strict mode, so argument identifier can - * @param {StrictModeScope} scope - * @returns - */ - function staticSematicForClassPropertyValue(scope: StrictModeScope) { - if (scope.kind !== "CatpureLayer") { - return; - } - for (const pos of scope.argumentsIdentifier) { - raiseError(ErrorMessageMap.syntax_error_bad_strict_arguments_eval, pos); - } - } - /** - * Check sematic for class property name. - * - `constructor` can not used as property name - * - `prototype` can not be a static property - * @param {PropertyName | PrivateName} propertyName - * @param isComputed - * @param {boolean} isStatic - * @returns - */ - function staticSematicForClassPropertyName( - propertyName: PropertyName | PrivateName, - isComputed: boolean, - isStatic: boolean, - ) { - if (isComputed) return; - let value; - if (isPrivateName(propertyName) || isIdentifer(propertyName)) { - value = propertyName.name; - } else if (isStringLiteral(propertyName)) { - value = propertyName.value; - } - if (value) { - if (value === "constructor") { - // recoverable error - raiseError( - ErrorMessageMap.babel_error_classe_may_not_have_a_field_named_constructor, - propertyName.start, - ); - } - if (value === "prototype" && isStatic) { - raiseError( - ErrorMessageMap.v8_error_class_may_not_have_static_property_named_prototype, - propertyName.start, - ); - } - } - } - /** ==================================================================== - * Parse Expression - * entry point reference : https://tc39.es/ecma262/#sec-comma-operator - * ===================================================================== - */ - - /** - * Entry function for parse a expression statement. - * @returns {ExpressionStatement} - */ - function parseExpressionStatement(): ExpressionStatement { - preStaticSematicEarlyErrorForExpressionStatement(); - const lastTokenIndex = lexer.getLastTokenEndPositon().index; - const expr = parseExpressionAllowIn(); - checkStrictMode(expr); - postStaticSematicEarlyErrorForExpressionStatement(expr, lastTokenIndex); - shouldInsertSemi(); - return Factory.createExpressionStatement( - expr, - cloneSourcePosition(expr.start), - cloneSourcePosition(expr.end), - ); - } - /** - * Implement part of NOTE section in 14.5 - */ - function preStaticSematicEarlyErrorForExpressionStatement() { - if (match(SyntaxKinds.LetKeyword)) { - const { kind, lineTerminatorFlag } = lookahead(); - if ( - kind === SyntaxKinds.BracketLeftPunctuator || - (!lineTerminatorFlag && - (kind === SyntaxKinds.BracesLeftPunctuator || kind === SyntaxKinds.Identifier)) - ) { - raiseError( - ErrorMessageMap.v8_error_lexical_declaration_cannot_appear_in_a_single_statement_context, - getStartPosition(), - ); - } - } - } - /** - * Implement part of NOTE section in 14.5 - */ - function postStaticSematicEarlyErrorForExpressionStatement(expr: Expression, lastTokenIndex: number) { - if (!expr.parentheses) { - if (isClassExpression(expr)) { - raiseError(ErrorMessageMap.syntax_error_functions_declare_non_strict_mode, expr.start); - return; - } - if (isFunctionExpression(expr)) { - if (expr.async) { - raiseError(ErrorMessageMap.syntax_error_async_function_declare, expr.start); - } - if (expr.generator) { - raiseError(ErrorMessageMap.syntax_error_generator_function_declare, expr.start); - } - if (isInStrictMode()) { - raiseError(ErrorMessageMap.syntax_error_functions_declare_strict_mode, expr.start); - } else { - if (lastTokenIndex !== context.lastTokenIndexOfIfStmt) { - raiseError(ErrorMessageMap.syntax_error_functions_declare_non_strict_mode, expr.start); - } - } - } - } - } - /** - * Helper function for checking `use strict` directive, according to - * ECMA spec, `use strict` directive is a `ExpressionStatement` in - * which value is `use strict`, and this function is doing the same - * thing as spec required. - * - * NOTE: this function would perform side effect to parse context - * - * ref: https://tc39.es/ecma262/#use-strict-directive - * @param {Expression} expr - */ - function checkStrictMode(expr: Expression) { - if (isStringLiteral(expr)) { - if (expr.value === "use strict" && !expr.parentheses) { - if (isDirectToFunctionContext()) { - if (!isCurrentFunctionParameterListSimple()) { - // recoverable error - raiseError( - ErrorMessageMap.syntax_error_use_strict_not_allowed_in_function_with_non_simple_parameters, - expr.start, - ); - } - setCurrentFunctionContextAsStrictMode(); - } - } - } - } - /** - * Private Parse API, parse Expression. - * ``` - * Expression: - * AssignmentExpression - * Expression, AssignmentExpression - * ``` - * Since Expression have in operator syntax action, so there we split parseExpression - * into three kind of function. - * - `parseExpressionAllowIn`: equal to production rule with parameter `Expression[+In]` - * - `parseExpressionDisallowIn`: equal to production rule with parameter `Expression[~In]` - * - `parseExpressionInheritIn`: equal to production rule with parameter `Expression[?in]` - * @returns {Expression} - */ - function parseExpressionAllowIn(): Expression { - return allowInOperaotr(parseExpressionInheritIn); - } - /** - * Private Parse API, parse Expression. - * - allow disallow in operator syntax transition action. - * - for more detail, please refer to `parseExpressionAllowIn`. - * @returns {Expression} - */ - function parseExpressionDisallowIn(): Expression { - return disAllowInOperaotr(parseExpressionInheritIn); - } - /** - * Private Parse API, parse Expression. - * - inherit in operator syntax transition action. - * - for more detail, please refer to `parseExpressionAllowIn`. - * @returns {Expression} - */ - function parseExpressionInheritIn(): Expression { - const exprs = [parseAssignmentExpressionInheritIn()]; - while (match(SyntaxKinds.CommaToken)) { - nextToken(); - exprs.push(parseAssignmentExpressionInheritIn()); - } - if (exprs.length === 1) { - return exprs[0]; - } - return Factory.createSequenceExpression( - exprs, - cloneSourcePosition(exprs[0].start), - cloneSourcePosition(exprs[exprs.length - 1].end), - ); - } - /** - * Private Parse API, parse AssignmentExpression - * - * Since AssignmentExpression usually is a entry point of in operator syntax action. just like - * parseExpression, there we split function into three kind: - * - `parseAssignmentExpressionAllowIn`: equals to production rule with parameter - * - `parseAssignmentExpressionInhertIn`: equals to production rule with parameter - * - It since that disallow is not show in current spec, so ignore it. - * @returns {Expression} - */ - function parseAssignmentExpressionAllowIn(): Expression { - return allowInOperaotr(parseAssignmentExpressionInheritIn); - } - /** - * Private Parse API, parse AssignmentExpression - * - inherit in operator syntax transition action. - * - for more detail, please refer to `parseAssignmentExpressionAllowIn`. - * @returns {Expression} - */ - function parseAssignmentExpressionInheritIn(): Expression { - if ( - match([ - SyntaxKinds.ParenthesesLeftPunctuator, - SyntaxKinds.Identifier, - SyntaxKinds.LetKeyword, - SyntaxKinds.YieldKeyword, - SyntaxKinds.AwaitKeyword, - ]) - ) { - context.maybeArrowStart = getStartPosition().index; - } - if (match(SyntaxKinds.YieldKeyword) && isCurrentScopeParseYieldAsExpression()) { - return parseYieldExpression(); - } - const [leftExpr, scope] = parseWithCatpureLayer(parseConditionalExpression); - if (!match(AssigmentOperators)) { - return leftExpr; - } - const left = exprToPattern(leftExpr, false); - checkStrictModeScopeError(scope); - const operator = getToken(); - if (operator !== SyntaxKinds.AssginOperator) { - checkExpressionAsLeftValue(left); - } - nextToken(); - const right = parseAssignmentExpressionInheritIn(); - return Factory.createAssignmentExpression( - left as Pattern, - right, - operator as AssigmentOperatorKinds, - cloneSourcePosition(left.start), - cloneSourcePosition(right.end), - ); - } - /** - * Helper function for any parse API that need to parse Arrow function. - * From production rule in `AssignmentExpression`, `ArrowFunctionExpression` and - * `AsyncArrowFunctionExpression` is same level of `ConditionalExpression`, but we - * parse ArrowFunction in the bottom of parse recursion(parsePrimary), so we should - * mark context there to make parseArrowFunction only parse when context is mark. - * @returns {boolean} - */ - function canParseAsArrowFunction(): boolean { - return getStartPosition().index === context.maybeArrowStart; - } - /** - * Parse Yield Expression, when current function scope is generator, yield would - * seems as keyword of yield expression, but even if in generator function scope, - * function parameter can call yield expression, so this function would check is - * current place is in function paramter or not. if yield expression shows in - * parameter list, it would throw error. - * ``` - * YieldExpression := 'yield' - * := 'yield' AssignmentExpression - * := 'yield' '*' AssignmentExpression - * ``` - * @returns {YieldExpression} - */ - function parseYieldExpression(): YieldExpression { - const { start } = expect(SyntaxKinds.YieldKeyword); - let delegate = false; - if (match(SyntaxKinds.MultiplyOperator)) { - if (!getLineTerminatorFlag()) { - nextToken(); - delegate = true; - } - } - const isLineDterminator = getLineTerminatorFlag(); - let argument: Expression | null = null; - if (!isSoftInsertSemi(false) && checkIsFollowByExpreesion()) { - if (delegate || (!delegate && !isLineDterminator)) { - argument = parseAssignmentExpressionInheritIn(); - } - } - if (delegate && !argument) { - raiseError( - ErrorMessageMap.extra_error_yield_deletgate_can_must_be_followed_by_assignment_expression, - getStartPosition(), - ); - } - if (isInParameter()) { - raiseError(ErrorMessageMap.extra_error_yield_expression_can_not_used_in_parameter_list, start); - } - recordScope(ExpressionScopeKind.YieldExpressionInParameter, start); - return Factory.createYieldExpression( - argument, - delegate, - start, - cloneSourcePosition(argument ? argument.end : start), - ); - } - function checkIsFollowByExpreesion() { - switch (getToken()) { - case SyntaxKinds.ColonPunctuator: - case SyntaxKinds.ParenthesesRightPunctuator: - case SyntaxKinds.BracketRightPunctuator: - case SyntaxKinds.CommaToken: - return false; - default: - return true; - } - } - function parseConditionalExpression(): Expression { - const test = parseBinaryExpression(); - if (shouldEarlyReturn(test)) { - return test; - } - if (!match(SyntaxKinds.QustionOperator)) { - return test; - } - nextToken(); - const conseq = parseAssignmentExpressionAllowIn(); - expect(SyntaxKinds.ColonPunctuator); - const alter = parseAssignmentExpressionInheritIn(); - return Factory.createConditionalExpression( - test, - conseq, - alter, - cloneSourcePosition(test.start), - cloneSourcePosition(alter.end), - ); - } - /** - * Private Parse Helper API for parse arrow function. - * @param {Expression} expr - * @returns - */ - function shouldEarlyReturn(expr: Expression) { - return isArrowFunctionExpression(expr) && !expr.parentheses; - } - /** - * Using Operator-precedence parser algorithm is used for parse binary expressiom - * with precedence order. and this is entry function for parseBinaryExpression. - * @returns {Expression} - */ - function parseBinaryExpression(): Expression { - let atom = parseUnaryOrPrivateName(); - if (shouldEarlyReturn(atom)) { - return atom; - } - if (match(BinaryOperators)) { - atom = parseBinaryOps(atom); - } - if (isPrivateName(atom)) { - raiseError(ErrorMessageMap.babel_error_private_name_wrong_used, atom.start); - } - return atom; - } - /** - * Return the precedence order by given binary operator. - * this function should only used by parseBinaryOps - * @param {SyntaxKinds} kind Binary Operator - * @returns {number} - */ - function getBinaryPrecedence(kind: SyntaxKinds): number { - switch (kind) { - case SyntaxKinds.NullishOperator: - case SyntaxKinds.LogicalOROperator: - return 4; - case SyntaxKinds.LogicalANDOperator: - return 5; - case SyntaxKinds.BitwiseOROperator: - return 6; - case SyntaxKinds.BitwiseXOROperator: - return 7; - case SyntaxKinds.BitwiseANDOperator: - return 8; - case SyntaxKinds.StrictEqOperator: - case SyntaxKinds.StrictNotEqOperator: - case SyntaxKinds.EqOperator: - case SyntaxKinds.NotEqOperator: - return 9; - case SyntaxKinds.InKeyword: - case SyntaxKinds.InstanceofKeyword: - case SyntaxKinds.GtOperator: - case SyntaxKinds.GeqtOperator: - case SyntaxKinds.LeqtOperator: - case SyntaxKinds.LtOperator: - if (kind === SyntaxKinds.InKeyword && !getCurrentInOperatorStack()) { - return -1; - } - return 10; - case SyntaxKinds.BitwiseLeftShiftOperator: - case SyntaxKinds.BitwiseRightShiftOperator: - case SyntaxKinds.BitwiseRightShiftFillOperator: - return 11; - case SyntaxKinds.PlusOperator: - case SyntaxKinds.MinusOperator: - return 12; - case SyntaxKinds.ModOperator: - case SyntaxKinds.DivideOperator: - case SyntaxKinds.MultiplyOperator: - return 13; - case SyntaxKinds.ExponOperator: - return 14; - default: - return -1; - } - } - function isBinaryOps(kind: SyntaxKinds) { - return getBinaryPrecedence(kind) > 0; - } - /** - * Bottom up recurive function for parse binary operator and next - * expression. - * @param {Expression} left - * @param {number} lastPre - * @returns {Expression} - */ - function parseBinaryOps(left: Expression, lastPre: number = 0): Expression { - // eslint-disable-next-line no-constant-condition - while (1) { - const currentOp = getToken(); - if (!isBinaryOps(currentOp) || getBinaryPrecedence(currentOp) < lastPre) { - break; - } - nextToken(); - let right = parseUnaryOrPrivateName(); - const nextOp = getToken(); - if (isBinaryOps(nextOp) && getBinaryPrecedence(nextOp) > getBinaryPrecedence(currentOp)) { - right = parseBinaryOps(right, getBinaryPrecedence(nextOp)); - } - staticSematicForBinaryExpr(currentOp, nextOp, left, right); - left = Factory.createBinaryExpression( - left, - right, - currentOp as BinaryOperatorKinds, - cloneSourcePosition(left.start), - cloneSourcePosition(right.end), - ); - } - return left; - } - function staticSematicForBinaryExpr( - currentOps: SyntaxKinds, - nextOps: SyntaxKinds, - left: Expression, - right: Expression, - ) { - if (isPrivateName(right) || (isPrivateName(left) && currentOps !== SyntaxKinds.InKeyword)) { - // recoverable error - raiseError(ErrorMessageMap.babel_error_private_name_wrong_used, left.start); - } - if (left.parentheses) { - return; - } - if (currentOps === SyntaxKinds.ExponOperator) { - if (isUnaryExpression(left) || isAwaitExpression(left)) { - // recoverable error - raiseError(ErrorMessageMap.v8_error_expont_operator_need_parans, left.start); - } - } - // if currentOp is nullish, next is logical or not - // if current Ops is logical, check next is nullish or not - if ( - currentOps === SyntaxKinds.NullishOperator && - (nextOps === SyntaxKinds.LogicalANDOperator || nextOps === SyntaxKinds.LogicalOROperator) - ) { - // recoverable error - raiseError(ErrorMessageMap.v8_error_nullish_require_parans, left.end); - } - if ( - nextOps === SyntaxKinds.NullishOperator && - (currentOps === SyntaxKinds.LogicalANDOperator || currentOps === SyntaxKinds.LogicalOROperator) - ) { - // recoverable error - raiseError(ErrorMessageMap.v8_error_nullish_require_parans, left.end); - } - } - function parseUnaryOrPrivateName(): Expression { - if (match(SyntaxKinds.PrivateName)) { - const privateName = parsePrivateName(); - usePrivateName(privateName.name, privateName.start); - return privateName; - } - return parseUnaryExpression(); - } - function parseUnaryExpression(): Expression { - if (match(UnaryOperators)) { - const operator = getToken() as UnaryOperatorKinds; - const isDelete = operator === SyntaxKinds.DeleteKeyword; - const start = getStartPosition(); - nextToken(); - let argument; - if (isDelete) { - enterDelete(); - argument = parseUnaryExpression(); - exitDelete(); - } else { - argument = parseUnaryExpression(); - } - const unaryExpr = Factory.createUnaryExpression( - argument, - operator, - start, - cloneSourcePosition(argument.end), - ); - staticSematicEarlyErrorForUnaryExpression(unaryExpr); - return unaryExpr; - } - if (match(SyntaxKinds.AwaitKeyword) && isCurrentScopeParseAwaitAsExpression()) { - return parseAwaitExpression(); - } - return parseUpdateExpression(); - } - // 13.5.1.1 - function staticSematicEarlyErrorForUnaryExpression(expr: UnaryExpression) { - if (isInStrictMode() && expr.operator === SyntaxKinds.DeleteKeyword && isIdentifer(expr.argument)) { - raiseError( - ErrorMessageMap.syntax_error_applying_the_delete_operator_to_an_unqualified_name_is_deprecated, - expr.start, - ); - } - } - function parseAwaitExpression() { - if (isInParameter()) { - raiseError( - ErrorMessageMap.extra_error_await_expression_can_not_used_in_parameter_list, - getStartPosition(), - ); - } - const start = getStartPosition(); - nextToken(); - recordScope(ExpressionScopeKind.AwaitExpressionImParameter, start); - const argu = parseUnaryExpression(); - return Factory.createAwaitExpression(argu, start, cloneSourcePosition(argu.end)); - } - function parseUpdateExpression(): Expression { - if (match(UpdateOperators)) { - const operator = getToken() as UpdateOperatorKinds; - const start = getStartPosition(); - nextToken(); - const argument = parseWithLHSLayer(parseLeftHandSideExpression); - checkExpressionAsLeftValue(argument); - return Factory.createUpdateExpression( - argument, - operator, - true, - start, - cloneSourcePosition(argument.end), - ); - } - const [argument, scope] = parseWithCatpureLayer(parseLeftHandSideExpression); - if (match(UpdateOperators) && !getLineTerminatorFlag()) { - checkStrictModeScopeError(scope); - checkExpressionAsLeftValue(argument); - const operator = getToken() as UpdateOperatorKinds; - const end = getEndPosition(); - nextToken(); - return Factory.createUpdateExpression( - argument, - operator, - false, - cloneSourcePosition(argument.start), - end, - ); - } - return argument; - } - /** - * Parse Left hand side Expression. This syntax is reference babel function, which is simplify original syntax of TS39, - * 'this' and super 'super' would be meanful when apper at start of atoms, which can be handle by parseAtoms. NewExpression - * is a spacial case , because it can not using optionalChain, so i handle it into a atom. - * ``` - * LeftHandSideExpression := Atoms '?.' CallExpression - * := Atoms '?.' MemberExpression - * := Atoms TagTemplateExpression - * ``` - * @returns {Expression} - */ - function parseLeftHandSideExpression(): Expression { - let base = parsePrimaryExpression(); - if (shouldEarlyReturn(base)) { - return base; - } - let shouldStop = false; - let hasOptional = false; - while (!shouldStop) { - let optional = false; - if (match(SyntaxKinds.QustionDotOperator)) { - optional = true; - hasOptional = true; - nextToken(); - } - if (match(SyntaxKinds.ParenthesesLeftPunctuator)) { - // callexpression - base = parseCallExpression(base, optional); - } else if (match([SyntaxKinds.DotOperator, SyntaxKinds.BracketLeftPunctuator]) || optional) { - // memberexpression - base = parseMemberExpression(base, optional); - } else if (match(SyntaxKinds.TemplateHead) || match(SyntaxKinds.TemplateNoSubstitution)) { - // tag template expressuin - if (hasOptional) { - // recoverable error - raiseError( - ErrorMessageMap.syntax_error_tag_template_expression_can_not_use_option_chain, - getStartPosition(), - ); - } - base = parseTagTemplateExpression(base); - } else { - shouldStop = true; - } - } - if (hasOptional) { - return Factory.createChainExpression( - base, - cloneSourcePosition(base.start), - cloneSourcePosition(base.end), - ); - } - return base; - } - /** - * Check is a assignable left value - * @param expression - * @returns - */ - function checkExpressionAsLeftValue(expression: ModuleItem) { - if (isIdentifer(expression) || isMemberExpression(expression)) { - return; - } - raiseError(ErrorMessageMap.invalid_left_value, expression.start); - } - /** - * Parse CallExpression - * ``` - * CallExpresion := GivenBase(base, optional) '(' Arguments ')' - * ``` - * @param {Expression} callee base expression - * @param {boolean} optional is this call optional ? - * @returns {Expression} - */ - function parseCallExpression(callee: Expression, optional: boolean): Expression { - expectButNotEat([SyntaxKinds.ParenthesesLeftPunctuator]); - const { nodes, end } = parseArguments(); - return Factory.createCallExpression(callee, nodes, optional, cloneSourcePosition(callee.start), end); - } - /** - * // TODO: remove possble dep of arrow function paramemter need to call this function. - * - * Parse Arguments, used by call expression, and arrow function paramemter. - * ``` - * Arguments := '(' ArgumentList ')' - * ArgumentList := ArgumentList AssigmentExpression - * := ArgumentList SpreadElement - * := AssignmentExpression - * := SpreadElement - * ``` - * @returns {Array} - */ - function parseArguments(): ASTArrayWithMetaData & { - trailingComma: boolean; - } { - const { start } = expect(SyntaxKinds.ParenthesesLeftPunctuator); - let isStart = true; - // TODO: refactor logic to remove shoulStop - const callerArguments: Array = []; - let trailingComma = false; - while (!match(SyntaxKinds.ParenthesesRightPunctuator) && !match(SyntaxKinds.EOFToken)) { - if (isStart) { - isStart = false; - if (match(SyntaxKinds.CommaToken)) { - // trailing comma - raiseError(ErrorMessageMap.extra_error_unexpect_trailing_comma, getStartPosition()); - nextToken(); - } - } else { - trailingComma = true; - expect(SyntaxKinds.CommaToken); - } - // case 1: ',' following by ')' - if (match(SyntaxKinds.ParenthesesRightPunctuator)) { - break; - } - trailingComma = false; - // case 2: ',' following by SpreadElement, maybe follwed by ',' - if (match(SyntaxKinds.SpreadOperator)) { - const spreadElementStart = getStartPosition(); - nextToken(); - const argu = parseAssignmentExpressionAllowIn(); - callerArguments.push( - Factory.createSpreadElement(argu, spreadElementStart, cloneSourcePosition(argu.end)), - ); - continue; - } - // case 3 : ',' AssigmentExpression - callerArguments.push(parseAssignmentExpressionAllowIn()); - } - const { end } = expect(SyntaxKinds.ParenthesesRightPunctuator); - return { - end, - start, - nodes: callerArguments, - trailingComma, - }; - } - /** - * Parse with base, this different between parseLeftHandSideExpression is - * that parseMemberExpression would only eat a `atom` of chain of expression. - * ``` - * MemberExpression := GivenBase(base ,optional) '.' IdentiferWithKeyword - * := GivenBase(base, optional) '[' Expreession ']' - * := GivenBase(base, optional) IdentiferWithKeyword - * // for last condition, optional prope must be True - * ``` - * @param {Expression} base base expression - * @param {boolean} optional is base expression contain a optional - * @returns {Expression} - */ - function parseMemberExpression(base: Expression, optional: boolean): Expression { - if (!match(SyntaxKinds.DotOperator) && !match(SyntaxKinds.BracketLeftPunctuator) && !optional) { - throw createUnreachError([SyntaxKinds.DotOperator, SyntaxKinds.BracketLeftPunctuator]); - } - // if start with dot, must be a access property, can not with optional. - // because optional means that last token is `?.` - if (match(SyntaxKinds.DotOperator) && !optional) { - expect(SyntaxKinds.DotOperator); - const property = parseMemberExpressionProperty(); - - return Factory.createMemberExpression( - false, - base, - property, - optional, - cloneSourcePosition(base.start), - cloneSourcePosition(property.end), - ); - } - // if start with `[`, must be computed property access. - else if (match(SyntaxKinds.BracketLeftPunctuator)) { - expect(SyntaxKinds.BracketLeftPunctuator); - const property = parseExpressionAllowIn(); - const { end } = expect(SyntaxKinds.BracketRightPunctuator); - return Factory.createMemberExpression( - true, - base, - property, - optional, - cloneSourcePosition(base.start), - end, - ); - } else { - // because parseLeftHandSideExpression would eat optional mark (QustionDotToken) frist, so maybe there - // is not dot or `[` for start a member expression, so we can check optional is - const property = parseMemberExpressionProperty(); - return Factory.createMemberExpression( - false, - base, - property, - optional, - cloneSourcePosition(base.start), - cloneSourcePosition(property.end), - ); - } - } - function parseMemberExpressionProperty() { - let property: Expression | PrivateName; - if (match(SyntaxKinds.PrivateName)) { - property = parsePrivateName(); - usePrivateName(property.name, property.start); - if (isInDelete()) { - raiseError( - ErrorMessageMap.syntax_error_applying_the_delete_operator_to_an_unqualified_name_is_deprecated, - property.start, - ); - } - } else { - property = parseIdentifierName(); - } - return property; - } - function parseTagTemplateExpression(base: Expression) { - const quasi = parseTemplateLiteral(true); - return Factory.createTagTemplateExpression( - base, - quasi, - cloneSourcePosition(base.end), - cloneSourcePosition(quasi.end), - ); - } - function parsePrimaryExpression(): Expression { - switch (getToken()) { - case SyntaxKinds.LtOperator: - return parseJSXElementOrJSXFragment(false); - case SyntaxKinds.DivideOperator: - case SyntaxKinds.DivideAssignOperator: - return parseRegexLiteral(); - case SyntaxKinds.NullKeyword: - return parseNullLiteral(); - case SyntaxKinds.UndefinedKeyword: - return parseUndefinedLiteral(); - case SyntaxKinds.TrueKeyword: - case SyntaxKinds.FalseKeyword: - return parseBoolLiteral(); - case SyntaxKinds.DecimalLiteral: - return parseDecimalLiteral(); - case SyntaxKinds.DecimalBigIntegerLiteral: - return parseDecimalBigIntegerLiteral(); - case SyntaxKinds.NonOctalDecimalLiteral: - return parseNonOctalDecimalLiteral(); - case SyntaxKinds.BinaryIntegerLiteral: - return parseBinaryIntegerLiteral(); - case SyntaxKinds.BinaryBigIntegerLiteral: - return parseBinaryBigIntegerLiteral(); - case SyntaxKinds.OctalIntegerLiteral: - return parseOctalIntegerLiteral(); - case SyntaxKinds.OctalBigIntegerLiteral: - return parseOctalBigIntegerLiteral(); - case SyntaxKinds.HexIntegerLiteral: - return parseHexIntegerLiteral(); - case SyntaxKinds.HexBigIntegerLiteral: - return parseHexBigIntegerLiteral(); - case SyntaxKinds.LegacyOctalIntegerLiteral: - return parseLegacyOctalIntegerLiteral(); - case SyntaxKinds.StringLiteral: - return parseStringLiteral(); - case SyntaxKinds.TemplateHead: - case SyntaxKinds.TemplateNoSubstitution: - return parseTemplateLiteral(false); - case SyntaxKinds.ImportKeyword: { - const { kind } = lookahead(); - if (kind === SyntaxKinds.DotOperator) return parseImportMeta(); - if (kind === SyntaxKinds.ParenthesesLeftPunctuator) { - return parseImportCall(); - } - throw createUnexpectError(); - } - case SyntaxKinds.NewKeyword: { - const { kind } = lookahead(); - if (kind === SyntaxKinds.DotOperator) { - return parseNewTarget(); - } - return parseNewExpression(); - } - case SyntaxKinds.SuperKeyword: - return parseSuper(); - case SyntaxKinds.ThisKeyword: - return parseThisExpression(); - case SyntaxKinds.BracesLeftPunctuator: - return parseObjectExpression(); - case SyntaxKinds.BracketLeftPunctuator: - return parseArrayExpression(); - case SyntaxKinds.FunctionKeyword: - return parseFunctionExpression(false); - case SyntaxKinds.AtPunctuator: { - return parseClassExpression(parseDecoratorList()); - } - case SyntaxKinds.ClassKeyword: - return parseClassExpression(null); - case SyntaxKinds.ParenthesesLeftPunctuator: - return parseCoverExpressionORArrowFunction(); - // TODO: consider wrap as function or default case ? - case SyntaxKinds.PrivateName: - // recoverable error - raiseError(ErrorMessageMap.babel_error_private_name_wrong_used, getStartPosition()); - return parsePrivateName(); - // return parsePrivateName(); - case SyntaxKinds.Identifier: - case SyntaxKinds.LetKeyword: - case SyntaxKinds.AwaitKeyword: - case SyntaxKinds.YieldKeyword: { - const { kind, lineTerminatorFlag: flag } = lookahead(); - // case 0: identifier `=>` ... - if (kind === SyntaxKinds.ArrowOperator && canParseAsArrowFunction()) { - const [[argus, strictModeScope], arrowExprScope] = parseWithArrowExpressionScope(() => - parseWithLHSLayerReturnScope(() => [parseIdentifierReference()]), - ); - if (getLineTerminatorFlag()) { - raiseError(ErrorMessageMap.extra_error_no_line_break_is_allowed_before_arrow, getStartPosition()); - } - enterArrowFunctionBodyScope(); - const arrowExpr = parseArrowFunctionExpression( - { - nodes: argus, - start: argus[0].start, - end: argus[0].end, - trailingComma: false, - }, - strictModeScope, - arrowExprScope, - ); - exitArrowFunctionBodyScope(); - return arrowExpr; - } - if (getSourceValue() === "async") { - // case 1 async function ==> must be async function () {} - if (kind === SyntaxKinds.FunctionKeyword && !getEscFlag()) { - const { value, start, end } = expect(SyntaxKinds.Identifier); - if (getLineTerminatorFlag()) { - return Factory.createIdentifier(value, start, end); - } - return parseFunctionExpression(true); - } - if (canParseAsArrowFunction()) { - // case 2 `async` `(` - // There might be two case : - // 1.frist case is there are line change after async, which make this case into - // call expression - // 2.second case is not change line after async, making it become async arrow - // function. - if (kind === SyntaxKinds.ParenthesesLeftPunctuator) { - const containEsc = getEscFlag(); - const id = parseIdentifierReference(); - const [[meta, strictModeScope], arrowExprScope] = parseWithArrowExpressionScope(() => - parseWithCatpureLayer(parseArguments), - ); - if (flag || !match(SyntaxKinds.ArrowOperator)) { - return Factory.createCallExpression( - id, - meta.nodes, - false, - cloneSourcePosition(id.start), - meta.end, - ); - } - if (containEsc) { - raiseError(ErrorMessageMap.invalid_esc_char_in_keyword, id.start); - } - enterArrowFunctionBodyScope(true); - const arrowFunExpr = parseArrowFunctionExpression(meta, strictModeScope, arrowExprScope); - exitArrowFunctionBodyScope(); - return arrowFunExpr; - } - // case 3: `async` `Identifer` ... - // There might be two case : - // 1.frist case is there are line change after async, or there is no arrow operator, - // which make this case into async as identifier - // 2.second case is not change line after async, making it become async arrow - // function. - if ( - kind === SyntaxKinds.Identifier || - kind === SyntaxKinds.YieldKeyword || - kind === SyntaxKinds.AwaitKeyword - ) { - // async followed by line break - if (flag) { - return parseIdentifierReference(); - } - const isAsyncContainUnicode = getEscFlag(); - const { start, end } = expect(SyntaxKinds.Identifier); // eat async - const { kind: maybeArrowToken } = lookahead(); - // there is no arrow operator. - if (maybeArrowToken !== SyntaxKinds.ArrowOperator) { - return Factory.createIdentifier("async", start, end); - } - if (isAsyncContainUnicode) { - raiseError(ErrorMessageMap.invalid_esc_char_in_keyword, start); - } - const [[argus, strictModeScope], arrowExprScope] = parseWithArrowExpressionScope(() => - parseWithCatpureLayer(() => [parseIdentifierReference()]), - ); - if (getLineTerminatorFlag()) { - raiseError( - ErrorMessageMap.extra_error_no_line_break_is_allowed_before_arrow, - getStartPosition(), - ); - } - enterArrowFunctionBodyScope(true); - const arrowExpr = parseArrowFunctionExpression( - { - nodes: argus, - start: argus[0].start, - end: argus[0].end, - trailingComma: false, - }, - strictModeScope, - arrowExprScope, - ); - exitArrowFunctionBodyScope(); - return arrowExpr; - } - } - } - return parseIdentifierReference(); - } - default: - throw createUnexpectError(); - } - } - function parseRegexLiteral(): RegexLiteral { - expectButNotEat([SyntaxKinds.DivideOperator, SyntaxKinds.DivideAssignOperator]); - const startWithAssignOperator = match(SyntaxKinds.DivideAssignOperator); - const start = getStartPosition(); - // eslint-disable-next-line prefer-const - let { pattern, flag } = readRegex(); - nextToken(); - if (startWithAssignOperator) { - pattern = "=" + pattern; - } - return Factory.createRegexLiteral(pattern, flag, start, getEndPosition()); - } - /** - * IdentifierReference, IdentifierName and BindingIdentifier is not samething in the - * spec. - * - IdentifierReference is a id in Lval or Rval - * - IdentifierName is a property of member expression or object, class - * - BindingIdentifier is a lval. - * @returns {Identifier} - */ - function parseIdentifierReference(): Identifier { - expectButNotEat([ - SyntaxKinds.Identifier, - SyntaxKinds.AwaitKeyword, - SyntaxKinds.YieldKeyword, - SyntaxKinds.LetKeyword, - ]); - // sematic check for a binding identifier - let identifer: Identifier; - switch (getToken()) { - // for most of yield keyword, if it should treat as identifier, - // it should not in generator function. - case SyntaxKinds.YieldKeyword: { - const { value, start, end } = expect(SyntaxKinds.YieldKeyword); - staticSematicForIdentifierAsYield(start); - identifer = Factory.createIdentifier(value, start, end); - break; - } - // for most of await keyword, if it should treat as identifier, - // it should not in async function. - case SyntaxKinds.AwaitKeyword: { - const { value, start, end } = expect(SyntaxKinds.AwaitKeyword); - staticSematicForIdentifierAsAwait(start); - identifer = Factory.createIdentifier(value, start, end); - break; - } - // let maybe treat as identifier in not strict mode, and not lexical binding declaration. - // so lexical binding declaration should implement it's own checker logical with parseIdentifierWithKeyword - case SyntaxKinds.LetKeyword: { - const { value, start, end } = expect(SyntaxKinds.LetKeyword); - staticSematicForIdentifierAsLet(start); - identifer = Factory.createIdentifier(value, start, end); - break; - } - case SyntaxKinds.Identifier: { - const { value, start, end } = expect(SyntaxKinds.Identifier); - staticSematicForIdentifierDefault(value, start); - identifer = Factory.createIdentifier(value, start, end); - break; - } - default: { - throw createUnexpectError(); - } - } - return identifer; - } - /** - * Yield only could be used as a identifier when - * - * - it is not in strict mode. - * - not in a generator context. - * - * record it's usage for defer check. - * @param {SourcePosition} start - */ - function staticSematicForIdentifierAsYield(start: SourcePosition) { - if (isCurrentScopeParseYieldAsExpression() || isInStrictMode()) { - raiseError(ErrorMessageMap.babel_error_invalid_yield, start); - } - recordScope(ExpressionScopeKind.YieldIdentifier, start); - } - /** - * Await only could be used as identifirt when - * - * - it is not in module mode - * - not in async context - * - * record it's usgae for defer check. - * @param {SourcePosition} start - */ - function staticSematicForIdentifierAsAwait(start: SourcePosition) { - if (isCurrentScopeParseAwaitAsExpression() || config.sourceType === "module") { - raiseError(ErrorMessageMap.babel_error_can_not_use_await_as_identifier_inside_an_async_function, start); - } - // skip if is using await in class property name in async context - if (isDirectToClassScope() && !isInPropertyName()) { - return; - } - recordScope(ExpressionScopeKind.AwaitIdentifier, start); - } - /** - * Let only could be used as identifirt when - * - * - it is not in strict mode - * - * record it's usgae for defer check. - * @param {SourcePosition} start - */ - function staticSematicForIdentifierAsLet(start: SourcePosition) { - if (isInStrictMode()) { - raiseError(ErrorMessageMap.unexpect_keyword_in_stric_mode, start); - } - recordScope(ExpressionScopeKind.LetIdentifiier, start); - } - /** - * Checking the usage for arguments and eval, presverveword - * - * - for presverveword, only could be used when not in strict mode - * - for argument, can not used when - * 1. in strict mode, and in the lhs - * 2. in strict mode, not in function. - * - for eval, can not used when - * 1. in strict mode, and in the lhs - * - * record it's usgae for defer check. - * @param {SourcePosition} start - */ - function staticSematicForIdentifierDefault(value: string, start: SourcePosition) { - const isPreserveWord = PreserveWordSet.has(value); - if (isPreserveWord) { - if (isInStrictMode()) { - raiseError(ErrorMessageMap.unexpect_keyword_in_stric_mode, start); - } - recordScope(ExpressionScopeKind.PresveredWordIdentifier, start); - } - if (value === "arguments") { - if (isInStrictMode()) { - if (!isEncloseInFunction() && !isInPropertyName()) { - // invalud usage - raiseError(ErrorMessageMap.syntax_error_arguments_is_not_valid_in_fields, start); - } - if (strictModeScopeRecorder.isInLHS()) { - // invalid assignment - raiseError(ErrorMessageMap.unexpect_keyword_in_stric_mode, start); - } - } - recordScope(ExpressionScopeKind.ArgumentsIdentifier, start); - } - if (value === "eval") { - if (isInStrictMode() && strictModeScopeRecorder.isInLHS()) { - raiseError(ErrorMessageMap.unexpect_keyword_in_stric_mode, start); - } - recordScope(ExpressionScopeKind.EvalIdentifier, start); - } - } - /** - * Relatedly loose function for parseIdentifier, it not only can parse identifier, - * it also can parse keyword as identifier. - * @returns {Identifier} - */ - function parseIdentifierName(): Identifier { - const { value, start, end } = expect(IdentiferWithKeyworArray); - return Factory.createIdentifier(value, start, end); - } - /** - * ECMA spec has every strict rule to private name, but in this parser, most of - * strict rule check is implemented by callee, there we only gonna check is in - * class scope or not. - * @returns {PrivateName} - */ - function parsePrivateName(): PrivateName { - const { value, start, end } = expect(SyntaxKinds.PrivateName); - if (!isInClassScope()) { - raiseError(ErrorMessageMap.syntax_error_unexpected_hash_used_outside_of_class_body, start); // semantics check for private - } - return Factory.createPrivateName(value, start, end); - } - function parseNullLiteral() { - const { start, end } = expect(SyntaxKinds.NullKeyword); - return Factory.createNullLiteral(start, end); - } - function parseUndefinedLiteral() { - const { start, end } = expect(SyntaxKinds.UndefinedKeyword); - return Factory.createUndefinedLiteral(start, end); - } - function parseDecimalLiteral() { - const { start, end, value } = expect(SyntaxKinds.DecimalLiteral); - return Factory.createDecimalLiteral(value, start, end); - } - function parseDecimalBigIntegerLiteral() { - const { start, end, value } = expect(SyntaxKinds.DecimalBigIntegerLiteral); - return Factory.createDecimalBigIntegerLiteral(value, start, end); - } - function parseNonOctalDecimalLiteral() { - const { start, end, value } = expect(SyntaxKinds.NonOctalDecimalLiteral); - if (isInStrictMode()) { - raiseError(ErrorMessageMap.Syntax_error_0_prefixed_octal_literals_are_deprecated, start); - } - return Factory.createNonOctalDecimalLiteral(value, start, end); - } - function parseBinaryIntegerLiteral() { - const { start, end, value } = expect(SyntaxKinds.BinaryIntegerLiteral); - return Factory.createBinaryIntegerLiteral(value, start, end); - } - function parseBinaryBigIntegerLiteral() { - const { start, end, value } = expect(SyntaxKinds.BinaryBigIntegerLiteral); - return Factory.createBinaryBigIntegerLiteral(value, start, end); - } - function parseOctalIntegerLiteral() { - const { start, end, value } = expect(SyntaxKinds.OctalIntegerLiteral); - return Factory.createOctalIntegerLiteral(value, start, end); - } - function parseOctalBigIntegerLiteral() { - const { start, end, value } = expect(SyntaxKinds.OctalBigIntegerLiteral); - return Factory.createOctBigIntegerLiteral(value, start, end); - } - function parseHexIntegerLiteral() { - const { start, end, value } = expect(SyntaxKinds.HexIntegerLiteral); - return Factory.createHexIntegerLiteral(value, start, end); - } - function parseHexBigIntegerLiteral() { - const { start, end, value } = expect(SyntaxKinds.HexBigIntegerLiteral); - return Factory.createHexBigIntegerLiteral(value, start, end); - } - function parseLegacyOctalIntegerLiteral() { - const { start, end, value } = expect(SyntaxKinds.LegacyOctalIntegerLiteral); - if (isInStrictMode()) { - raiseError(ErrorMessageMap.Syntax_error_0_prefixed_octal_literals_are_deprecated, start); - } - return Factory.createLegacyOctalIntegerLiteral(value, start, end); - } - function parseNumericLiteral(): NumberLiteral { - switch (getToken()) { - case SyntaxKinds.DecimalLiteral: - return parseDecimalLiteral(); - case SyntaxKinds.DecimalBigIntegerLiteral: - return parseDecimalBigIntegerLiteral(); - case SyntaxKinds.NonOctalDecimalLiteral: - return parseNonOctalDecimalLiteral(); - case SyntaxKinds.BinaryIntegerLiteral: - return parseBinaryIntegerLiteral(); - case SyntaxKinds.BinaryBigIntegerLiteral: - return parseBinaryBigIntegerLiteral(); - case SyntaxKinds.OctalIntegerLiteral: - return parseOctalIntegerLiteral(); - case SyntaxKinds.OctalBigIntegerLiteral: - return parseOctalBigIntegerLiteral(); - case SyntaxKinds.HexIntegerLiteral: - return parseHexIntegerLiteral(); - case SyntaxKinds.HexBigIntegerLiteral: - return parseHexBigIntegerLiteral(); - case SyntaxKinds.LegacyOctalIntegerLiteral: - return parseLegacyOctalIntegerLiteral(); - default: - throw createUnexpectError(); - } - } - function parseStringLiteral() { - const { start, end, value } = expect(SyntaxKinds.StringLiteral); - return Factory.createStringLiteral(value, start, end); - } - function parseBoolLiteral() { - const { start, end, value } = expect([SyntaxKinds.TrueKeyword, SyntaxKinds.FalseKeyword]); - return Factory.createBoolLiteral(value === "true" ? true : false, start, end); - } - function parseTemplateLiteral(tagged: boolean) { - if (!match([SyntaxKinds.TemplateHead, SyntaxKinds.TemplateNoSubstitution])) { - throw createUnreachError([SyntaxKinds.TemplateHead, SyntaxKinds.TemplateNoSubstitution]); - } - const templateLiteralStart = getStartPosition(); - if (match(SyntaxKinds.TemplateNoSubstitution)) { - if (!tagged && lexer.getTemplateLiteralTag()) { - raiseError(ErrorMessageMap.v8_error_invalid_hexadecimal_escape_sequence, getStartPosition()); - } - const value = getSourceValue(); - const templateLiteralEnd = getEndPosition(); - nextToken(); - return Factory.createTemplateLiteral( - [Factory.createTemplateElement(value, true, templateLiteralStart, templateLiteralEnd)], - [], - templateLiteralStart, - templateLiteralEnd, - ); - } - nextToken(); - const expressions = [parseExpressionAllowIn()]; - const quasis: Array = []; - while ( - !match(SyntaxKinds.TemplateTail) && - match(SyntaxKinds.TemplateMiddle) && - !match(SyntaxKinds.EOFToken) - ) { - if (!tagged && lexer.getTemplateLiteralTag()) { - raiseError(ErrorMessageMap.v8_error_invalid_hexadecimal_escape_sequence, getStartPosition()); - } - quasis.push( - Factory.createTemplateElement(getSourceValue(), false, getStartPosition(), getEndPosition()), - ); - nextToken(); - expressions.push(parseExpressionAllowIn()); - } - if (match(SyntaxKinds.EOFToken)) { - throw createUnexpectError(); - } - if (!tagged && lexer.getTemplateLiteralTag()) { - raiseError(ErrorMessageMap.v8_error_invalid_hexadecimal_escape_sequence, getStartPosition()); - } - quasis.push(Factory.createTemplateElement(getSourceValue(), true, getStartPosition(), getEndPosition())); - const templateLiteralEnd = getEndPosition(); - nextToken(); - return Factory.createTemplateLiteral(quasis, expressions, templateLiteralStart, templateLiteralEnd); - } - /** - * Parse import meta property - * ``` - * ImportMeta := import . meta - * ``` - * @returns {MetaProperty} - */ - function parseImportMeta(): MetaProperty { - const { start, end } = expect(SyntaxKinds.ImportKeyword); - expect(SyntaxKinds.DotOperator); - const ecaFlag = getEscFlag(); - const property = parseIdentifierReference(); - staticSematicForImportMeta(property, ecaFlag, start); - return Factory.createMetaProperty( - Factory.createIdentifier("import", start, end), - property, - start, - cloneSourcePosition(property.end), - ); - } - /** - * Sematic check for import meta - * - import member expression's property only could be meta - * - meta should be a contextual keyword - * - import meta can't use in script mode - * @param property - * @param ecaFlag - */ - function staticSematicForImportMeta(property: Identifier, ecaFlag: boolean, start: SourcePosition) { - if (property.name !== "meta") { - raiseError( - ErrorMessageMap.babel_error_the_only_valid_meta_property_for_import_is_import_meta, - property.start, - ); - } - if (ecaFlag) { - raiseError(ErrorMessageMap.invalid_esc_char_in_keyword, start); - } - if (config.sourceType === "script") { - raiseError(ErrorMessageMap.babel_error_import_meta_may_appear_only_with_source_type_module, start); - } - } - /** - * Parse Import call - * ``` - * ImportCall := import ( AssignmentExpression[+In], (optional support attribute) ) - * ``` - * @returns {CallExpression} - */ - function parseImportCall(): CallExpression { - const { start, end } = expect(SyntaxKinds.ImportKeyword); - expect(SyntaxKinds.ParenthesesLeftPunctuator); - const argument = parseAssignmentExpressionAllowIn(); - const option = parseImportAttributeOptional(); - const { end: finalEnd } = expect(SyntaxKinds.ParenthesesRightPunctuator); - return Factory.createCallExpression( - Factory.createImport(start, end), - option ? [argument, option] : [argument], - false, - cloneSourcePosition(start), - cloneSourcePosition(finalEnd), - ); - } - /** - * Parse import attribute (stage 3 syntax) - * ref: https://github.com/tc39/proposal-import-attributes - * @returns - */ - function parseImportAttributeOptional(): Expression | null { - if (!config.plugins.includes("importAttributes") && !config.plugins.includes("importAssertions")) { - return null; - } - if (!match(SyntaxKinds.CommaToken)) { - return null; - } - nextToken(); - if (match(SyntaxKinds.ParenthesesRightPunctuator)) { - return null; - } - const option = parseAssignmentExpressionAllowIn(); - if (match(SyntaxKinds.CommaToken)) { - nextToken(); - } - return option; - } - /** - * Parse new target - * ``` - * NewTarget := new . target - * ``` - * @returns {MetaProperty} - */ - function parseNewTarget(): MetaProperty { - const { start, end } = expect(SyntaxKinds.NewKeyword); - expect(SyntaxKinds.DotOperator); - staticSematicForNewTarget(start); - const targetStart = getStartPosition(); - const targetEnd = getEndPosition(); - nextToken(); - return Factory.createMetaProperty( - Factory.createIdentifier("new", start, end), - Factory.createIdentifier("target", targetStart, targetEnd), - start, - targetEnd, - ); - } - function staticSematicForNewTarget(start: SourcePosition) { - if (!isContextKeyword("target")) { - // recoverable error - throw createUnexpectError(); - } - if (!config.allowNewTargetOutsideFunction && isTopLevel() && !isInClassScope()) { - // recoverable error - raiseError(ErrorMessageMap.babel_error_new_target_can_only_be_used_in_class_or_function_scope, start); - } - } - /** - * Parse New Expression, the callee part of new expression is a trick one, - * this is not a member expression, it can not contain qustion dot or call - * expression. - * ``` - * NewExpression := 'new' NewExpression - * := 'new' MemberExpressionWithoutOptional Arugment? - * ``` - * @returns {Expression} - */ - function parseNewExpression(): Expression { - const { start } = expect(SyntaxKinds.NewKeyword); - // maybe is new.target - if (match(SyntaxKinds.NewKeyword) && lookahead().kind !== SyntaxKinds.DotOperator) { - return parseNewExpression(); - } - let base = parsePrimaryExpression(); - staticSematicForBaseInNewExpression(base); - base = parseNewExpressionCallee(base); - if (!match(SyntaxKinds.ParenthesesLeftPunctuator)) { - // accpect New XXX -> No argument - return Factory.createNewExpression(base, [], start, cloneSourcePosition(base.end)); - } - const { end, nodes } = parseArguments(); - return Factory.createNewExpression(base, nodes, start, end); - } - /** - * The base of new expression can not be a import call expression, if must be a import - * call expression, it must be have a paran. - * @param {Expression} base - */ - function staticSematicForBaseInNewExpression(base: Expression) { - if (!base.parentheses && isCallExpression(base) && base.callee.kind === SyntaxKinds.Import) { - // recoverable error - raiseError(ErrorMessageMap.babel_error_cannot_use_new_with_import, base.start); - } - } - /** - * Parse the callee of new expression, base of new expression can not - * be a call expression or a qustion dot expression. - * @param {Expression} base - * @returns - */ - function parseNewExpressionCallee(base: Expression): Expression { - while ( - match(SyntaxKinds.DotOperator) || - match(SyntaxKinds.BracketLeftPunctuator) || - match(SyntaxKinds.QustionDotOperator) - ) { - if (match(SyntaxKinds.QustionDotOperator)) { - // recoverable error - raiseError( - ErrorMessageMap.babel_error_constructors_in_after_an_optional_chain_are_not_allowed, - getStartPosition(), - ); - nextToken(); - base = parseMemberExpression(base, true); - continue; - } - base = parseMemberExpression(base, false); - } - return base; - } - /** - * Parse super expression, only parse the arguments and super or a first level - * of access of member expression. Contain sematic check: - * - Super call only valid in ctor. - * - super property can be used in any method of class. - * ``` - * SuperCall := super argument - * SuperProperty := super[Expression] - * := super.IdentifierName - * ``` - * @returns {Expression} - */ - function parseSuper(): Expression { - if (!isCurrentClassExtend()) { - // recoverable error - raiseError( - ErrorMessageMap.syntax_error_super_is_only_valid_in_derived_class_constructors, - getStartPosition(), - ); - } - const { start: keywordStart, end: keywordEnd } = expect([SyntaxKinds.SuperKeyword]); - if (match(SyntaxKinds.ParenthesesLeftPunctuator)) { - if (!lexicalScopeRecorder.isInCtor()) { - // recoverable error - raiseError(ErrorMessageMap.babel_error_call_super_outside_of_ctor, keywordStart); - } - const { nodes, end: argusEnd } = parseArguments(); - return Factory.createCallExpression( - Factory.createSuper(keywordStart, keywordEnd), - nodes, - false, - cloneSourcePosition(keywordStart), - argusEnd, - ); - } - let property: Expression; - let isComputed = false; - let end: SourcePosition; - switch (getToken()) { - case SyntaxKinds.QustionDotOperator: - // recoverable error. - raiseError(ErrorMessageMap.babel_invalid_usage_of_super_call, getStartPosition()); - // eslint-disable-next-line no-fallthrough - case SyntaxKinds.DotOperator: { - nextToken(); - if (match(SyntaxKinds.PrivateName)) { - property = parsePrivateName(); - // recoverable error - raiseError(ErrorMessageMap.babel_error_private_fields_cant_be_accessed_on_super, property.start); - } else { - property = parseIdentifierName(); - } - end = cloneSourcePosition(property.end); - break; - } - case SyntaxKinds.BracketLeftPunctuator: { - nextToken(); - property = parseExpressionAllowIn(); - isComputed = true; - ({ end } = expect(SyntaxKinds.BracketRightPunctuator)); - break; - } - default: - throw createUnexpectError(); - } - return Factory.createMemberExpression( - isComputed, - Factory.createSuper(keywordStart, keywordEnd), - property, - false, - cloneSourcePosition(keywordStart), - end, - ); - } - /** - * Parse this expression, only eat `this` token - * @returns {ThisExpression} - */ - function parseThisExpression(): ThisExpression { - const { start, end } = expect([SyntaxKinds.ThisKeyword]); - return Factory.createThisExpression(start, end); - } - /** - * Parse ObjectLiterial, object property just a list of PropertyDefinition. - * ### Trailing Comma problem - * object expression maybe transform into `ObjectPattern` in `AssignmentExpression` - * so i add a trailing comma field to object expression to AST struct for `toAssignment` - * function. - * ``` - * ObjectLiteral := '{' PropertyDefinitionList ','? '}' - * PropertyDefinitionList := PropertyDefinitionList ',' PropertyDefinition - * := PropertyDefinition - * ``` - * @returns {Expression} actually is `ObjectExpression` - */ - function parseObjectExpression(): Expression { - const { start } = expect(SyntaxKinds.BracesLeftPunctuator); - let isStart = true; - const propertyDefinitionList: Array = []; - let trailingComma = false; - const protoPropertyNames: Array = []; - while (!match(SyntaxKinds.BracesRightPunctuator) && !match(SyntaxKinds.EOFToken)) { - if (isStart) { - propertyDefinitionList.push(parsePropertyDefinition(protoPropertyNames)); - isStart = false; - continue; - } - expect(SyntaxKinds.CommaToken); - if (match(SyntaxKinds.BracesRightPunctuator) || match(SyntaxKinds.EOFToken)) { - trailingComma = true; - break; - } - propertyDefinitionList.push(parsePropertyDefinition(protoPropertyNames)); - } - staticSematicEarlyErrorForObjectExpression(protoPropertyNames); - const { end } = expect(SyntaxKinds.BracesRightPunctuator); - return Factory.createObjectExpression(propertyDefinitionList, trailingComma, start, end); - } - /** - * Adding `__proto__` property key to duplication set, if object expression transform to pattern - * duplication of `__proto__` is ok, but when is not pattern, it not a correct syntax. - * @param {Array} protoPropertyNames - * reference: 13.2.5.1 - */ - function staticSematicEarlyErrorForObjectExpression(protoPropertyNames: Array) { - if (protoPropertyNames.length > 1) { - for (let index = 1; index < protoPropertyNames.length; ++index) - context.propertiesProtoDuplicateSet.add(protoPropertyNames[index]); - } - } - /** - * Helper for property definition to record the object property which property is - * `__proto__`, since duplication of `__proto__` is a error. - * @param protoPropertyNames - * @param propertyName - * @param isComputed - * @returns - */ - function staticSematicHelperRecordPropertyNameForEarlyError( - protoPropertyNames: Array, - propertyName: PropertyName, - isComputed: boolean, - ) { - if (isComputed) return; - if ( - (isIdentifer(propertyName) && propertyName.name === "__proto__") || - (isStringLiteral(propertyName) && propertyName.value === "__proto__") - ) { - protoPropertyNames.push(propertyName); - return; - } - } - /** - * Parse PropertyDefinition - * ``` - * PropertyDefinition := MethodDefintion - * := Property - * := SpreadElement - * Property := PropertyName '=' AssignmentExpression - * SpreadElement := '...' AssigmentExpression - * ``` - * ### How to parse - * 1. start with `...` operator, must be SpreadElment - * 2. start with privatename is syntax error, but it is common, so we handle it as sematic problem. - * 3. check is start with method modifier prefix by helper function `checkIsMethodStartWithModifier`. - * 4. default case, property name with colon operator. - * 5. this is speical case, we accept a coverinit in object expression, because object expression - * might be transform into object pattern, so we mark accept it and mark it. it coverInit of - * object expression is not transform by `toAssignment` function, it would throw error in the - * end of `parseProgram` - * #### ref: https://tc39.es/ecma262/#prod-PropertyDefinition - */ - function parsePropertyDefinition(protoPropertyNameLocations: Array): PropertyDefinition { - // semantics check for private - if (match(SyntaxKinds.PrivateName)) { - // TODO: make it recoverable - throw createMessageError(ErrorMessageMap.extra_error_private_field_in_object_expression); - } - // spreadElement - if (match(SyntaxKinds.SpreadOperator)) { - const spreadElementStart = getStartPosition(); - nextToken(); - const expr = parseAssignmentExpressionAllowIn(); - return Factory.createSpreadElement(expr, spreadElementStart, cloneSourcePosition(expr.end)); - } - // start with possible method modifier - if (checkIsMethodStartWithModifier()) { - return parseMethodDefintion() as ObjectMethodDefinition; - } - // otherwise, it would be Property start with PropertyName or MethodDeinftion start with PropertyName - const isComputedRef = { isComputed: false }; - const propertyName = parsePropertyName(isComputedRef); - if (match(SyntaxKinds.ParenthesesLeftPunctuator)) { - return parseMethodDefintion(false, [propertyName, isComputedRef.isComputed]) as ObjectMethodDefinition; - } - if (isComputedRef.isComputed || match(SyntaxKinds.ColonPunctuator)) { - staticSematicHelperRecordPropertyNameForEarlyError( - protoPropertyNameLocations, - propertyName, - isComputedRef.isComputed, - ); - nextToken(); - const expr = parseAssignmentExpressionAllowIn(); - return Factory.createObjectProperty( - propertyName, - expr, - isComputedRef.isComputed, - false, - cloneSourcePosition(propertyName.start), - cloneSourcePosition(expr.end), - ); - } - recordIdentifierValue(propertyName); - if (match(SyntaxKinds.AssginOperator)) { - staticSematicHelperRecordPropertyNameForEarlyError( - protoPropertyNameLocations, - propertyName, - isComputedRef.isComputed, - ); - nextToken(); - const expr = parseAssignmentExpressionAllowIn(); - const property = Factory.createObjectProperty( - propertyName, - expr, - isComputedRef.isComputed, - false, - cloneSourcePosition(propertyName.start), - cloneSourcePosition(expr.end), - ); - context.propertiesInitSet.add(property); - return property; - } - staticSematicForShortedPropertyNameInObjectLike(propertyName); - staticSematicForShortedPropertyNameInObjectExpression(propertyName as Identifier); - return Factory.createObjectProperty( - propertyName, - undefined, - isComputedRef.isComputed, - true, - cloneSourcePosition(propertyName.start), - cloneSourcePosition(propertyName.end), - ); - } - function recordIdentifierValue(propertyName: ModuleItem) { - if (isIdentifer(propertyName)) { - if (propertyName.name === "await") { - recordScope(ExpressionScopeKind.AwaitIdentifier, propertyName.start); - } - if (propertyName.name === "yield") { - recordScope(ExpressionScopeKind.YieldIdentifier, propertyName.start); - } - if (propertyName.name === "arguments") { - recordScope(ExpressionScopeKind.ArgumentsIdentifier, propertyName.start); - } - if (propertyName.name === "eval") { - recordScope(ExpressionScopeKind.EvalIdentifier, propertyName.start); - } - if (propertyName.name === "let") { - recordScope(ExpressionScopeKind.LetIdentifiier, propertyName.start); - } - if (PreserveWordSet.has(propertyName.name)) { - recordScope(ExpressionScopeKind.PresveredWordIdentifier, propertyName.start); - } - } - } - /** - * Parse PropertyName, using context ref which passed in to record this property is computed or not. - * - * ### Extra action need for callee - * In this function, we accept keywrod as property name, but when the property name use as a shorted - * property name, it will be a syntax error, so father syntax check is needed handle by callee. - * ``` - * PropertyName := Identifer (IdentifierName, not BindingIdentifier) - * := NumberLiteral - * := StringLiteral - * := ComputedPropertyName - * ComputedPropertyName := '[' AssignmentExpression ']' - * ``` - * ref: https://tc39.es/ecma262/#prod-PropertyName - * @returns {PropertyName} - */ - function parsePropertyName(isComputedRef: { isComputed: boolean }): PropertyName { - expectButNotEat([ - SyntaxKinds.BracketLeftPunctuator, - SyntaxKinds.StringLiteral, - ...IdentiferWithKeyworArray, - ...NumericLiteralKinds, - ]); - switch (getToken()) { - case SyntaxKinds.StringLiteral: { - return parseStringLiteral(); - } - case SyntaxKinds.BracketLeftPunctuator: { - nextToken(); - lexicalScopeRecorder.enterPropertyName(); - const expr = parseAssignmentExpressionAllowIn(); - lexicalScopeRecorder.exitPropertyName(); - expect(SyntaxKinds.BracketRightPunctuator); - isComputedRef.isComputed = true; - return expr; - } - default: { - if (match(NumericLiteralKinds)) { - return parseNumericLiteral(); - } - // propty name is a spical test of binding identifier. - // if `await` and `yield` is propty name with colon (means assign), it dose not affected by scope. - if (match(IdentiferWithKeyworArray)) { - const identifer = parseIdentifierName(); - return identifer; - } - throw createUnexpectError(); - } - } - } - /** - * Sematic check when a property name is shorted property - * @param {PropertyName} propertyName - * @returns - */ - function staticSematicForShortedPropertyNameInObjectLike(propertyName: PropertyName) { - if (isStringLiteral(propertyName) || isNumnerLiteral(propertyName)) { - // recoverable error. - raiseError( - ErrorMessageMap.extra_error_when_binding_pattern_property_name_is_literal_can_not_be_shorted, - propertyName.start, - ); - } - } - /** - * Like `staticCheckForPropertyNameAsSingleBinding` for object pattern, when shorted property in - * object expression, if will no longer just - * @param {PropertyName} propertyName - * @returns - */ - function staticSematicForShortedPropertyNameInObjectExpression(propertyName: Identifier) { - if (propertyName.name === "await") { - if (isCurrentScopeParseAwaitAsExpression() || config.sourceType === "module") { - raiseError( - ErrorMessageMap.babel_error_can_not_use_await_as_identifier_inside_an_async_function, - propertyName.start, - ); - } - return; - } - if (propertyName.name === "yield") { - if (isCurrentScopeParseYieldAsExpression() || isInStrictMode()) { - raiseError(ErrorMessageMap.babel_error_invalid_yield, propertyName.start); - } - return; - } - if (KeywordSet.has(propertyName.name)) { - // recoverable error - raiseError(ErrorMessageMap.babel_error_unexpected_keyword, propertyName.start); - } - if (PreserveWordSet.has(propertyName.name) && isInStrictMode()) { - // recoverable error - raiseError(ErrorMessageMap.babel_error_unexpected_reserved_word, propertyName.start); - } - } - /** Parse MethodDefintion, this method should allow using when in class or in object literal. - * 1. ClassElement can be PrivateName, when it used in object literal, it should throw a error. - * 2. It should parse modifier when `withPropertyName` is falsey. - * - * ### Parse Modifier - * we parse modifier according to the pattern `('set' | 'get')? 'async' '*' ClassElement `, this - * is not a regulat syntax, it may accept wrong syntax, but by accept more case then spec, we cam - * provide more concies sematic message to developer. - * ``` - * MethodDefintion := ClassElementName BindingList FunctionBody - * := AyncMethod - * := GeneratorMethod - * := AsyncGeneratorMethod - * := 'set' ClassElementName BindingList FunctionBody - * := 'get' ClassElementName '('')' FunctionBody - * AyncMethod := 'async' ClassElementName BindingList FunctionBody - * GeneratorMethod := '*' ClassElementName BindingList FunctionBody - * AsyncGeneratorMethod := 'async' '*' ClassElementName BindingList FunctionBody - * ClassElementName := PropertyName - * := PrivateName - * ``` - * @param {boolean} inClass is used in class or not. - * @param {PropertyName | PrivateName | undefined } withPropertyName parse methodDeinfition with exited propertyName or not - * @param {boolean} isStatic - * @returns {ObjectMethodDefinition | ClassMethodDefinition | ObjectAccessor | ClassAccessor | ClassConstructor} - */ - function parseMethodDefintion( - inClass: boolean = false, - withPropertyName: [PropertyName | PrivateName, boolean] | undefined = undefined, - isStatic: boolean = false, - decorators: [Decorator] | null = null, - ): ObjectMethodDefinition | ClassMethodDefinition | ObjectAccessor | ClassAccessor | ClassConstructor { - if (!checkIsMethodStartWithModifier() && !withPropertyName) { - throw createUnreachError([SyntaxKinds.MultiplyAssignOperator, SyntaxKinds.Identifier]); - } - /** - * Step 1 : if not with propertyName , parse modifier frist, otherwise, if with propertyName, it shouldn't do anything. - * structure would be like : ('set' | 'get')? 'async' '*' PropertyName ...., this strcuture isn't match the spec. - * but in this structure, we can detect some syntax error more concies, like set and get can not use with async - * or generator. - */ - let type: MethodDefinition["type"] = "method"; - let isAsync: MethodDefinition["async"] = false; - let generator: MethodDefinition["generator"] = false; - let computed: MethodDefinition["computed"] = withPropertyName ? withPropertyName[1] : false; - let start: SourcePosition | null = null; - let propertyName: PropertyName; - if (!withPropertyName) { - // frist, is setter or getter - if (isContextKeyword("set")) { - type = "set"; - start = getStartPosition(); - nextToken(); - } else if (isContextKeyword("get")) { - type = "get"; - start = getStartPosition(); - nextToken(); - } - // second, parser async and generator - const { kind } = lookahead(); - if (isContextKeyword("async") && kind !== SyntaxKinds.ParenthesesLeftPunctuator) { - start = getStartPosition(); - isAsync = true; - nextToken(); - if (match(SyntaxKinds.MultiplyOperator)) { - nextToken(); - generator = true; - } - } else if (match(SyntaxKinds.MultiplyOperator)) { - start = getStartPosition(); - generator = true; - nextToken(); - } - if (match(SyntaxKinds.PrivateName)) { - propertyName = parsePrivateName(); - defPrivateName( - propertyName.name, - propertyName.start, - type === "method" ? "other" : isStatic ? `static-${type}` : type, - ); - } else { - const isComputedRef = { isComputed: false }; - propertyName = parsePropertyName(isComputedRef); - computed = isComputedRef.isComputed; - } - if (!start) start = cloneSourcePosition(propertyName.start); - } else { - start = cloneSourcePosition(withPropertyName[0].start); - propertyName = withPropertyName[0]; - } - const isCtor = inClass && !isStatic && !computed && helperIsPropertyNameIsCtor(propertyName); - if (isCtor) { - lexicalScopeRecorder.enterCtor(); - if (lexicalScopeRecorder.testAndSetCtor()) { - raiseError(ErrorMessageMap.v8_error_a_class_may_only_have_one_constructor, propertyName.start); - } - } - enterFunctionScope(isAsync, generator); - const [parmas, scope] = parseWithCatpureLayer(parseFunctionParam); - const body = parseFunctionBody(); - postStaticSematicEarlyErrorForStrictModeOfFunction(null, scope); - exitFunctionScope(true); - if (isCtor) lexicalScopeRecorder.exitCtor(); - /** - * Step 2: semantic and more concise syntax check instead just throw a unexpect - * token error. - */ - staticSematicEarlyErrorForClassMethodDefinition( - propertyName, - inClass, - isStatic, - isAsync, - generator, - parmas, - type, - ); - /** - * Step 3 return based on type, if accessor or methodDefintion - */ - if (inClass) { - if (isCtor) { - if (decorators) { - raiseError( - ErrorMessageMap.babel_error_decorators_can_not_be_used_with_a_constructor, - decorators[0].start, - ); - } - return Factory.createClassConstructor( - propertyName as ClassConstructor["key"], - body, - parmas, - start as SourcePosition, - cloneSourcePosition(body.end), - ); - } - if (type === "set" || type === "get") { - return Factory.createClassAccessor( - propertyName, - body, - parmas, - type, - computed, - decorators, - start as SourcePosition, - cloneSourcePosition(body.end), - ); - } - return Factory.createClassMethodDefintion( - propertyName, - body, - parmas, - isAsync, - generator, - computed, - isStatic, - decorators, - start ? start : cloneSourcePosition(propertyName.start), - cloneSourcePosition(body.end), - ); - } - if (type === "set" || type === "get") { - return Factory.createObjectAccessor( - propertyName, - body, - parmas, - type, - computed, - start as SourcePosition, - cloneSourcePosition(body.end), - ); - } - return Factory.createObjectMethodDefintion( - propertyName, - body, - parmas, - isAsync, - generator, - computed, - start ? start : cloneSourcePosition(propertyName.start), - cloneSourcePosition(body.end), - ); - } - /** - * This is a helper function for object expression and class for determiate is property - * a method definition or not. - * - * Please notes that this function not only accept regualer syntax, but also accept something - * like set and get generator, it will left sematic job for `parseMetodDefinition` method. - * @returns {boolean} - */ - function checkIsMethodStartWithModifier(): boolean { - if (match(SyntaxKinds.MultiplyOperator)) { - return true; - } - const { kind, lineTerminatorFlag: flag } = lookahead(); - const isLookAheadValidatePropertyNameStart = - Keywords.find((keyword) => keyword === kind) || - kind === SyntaxKinds.Identifier || - kind === SyntaxKinds.PrivateName || - kind === SyntaxKinds.StringLiteral || - NumericLiteralKinds.includes(kind) || - kind === SyntaxKinds.BracketLeftPunctuator || - kind === SyntaxKinds.MultiplyOperator; - if (isContextKeyword("set") && isLookAheadValidatePropertyNameStart) { - return true; - } - if (isContextKeyword("get") && isLookAheadValidatePropertyNameStart) { - return true; - } - if (isContextKeyword("async") && isLookAheadValidatePropertyNameStart && !flag) { - return true; - } - return false; - } - function helperIsPropertyNameIsCtor(propertyName: PropertyName) { - switch (propertyName.kind) { - case SyntaxKinds.Identifier: { - return propertyName.name === "constructor"; - } - case SyntaxKinds.StringLiteral: { - return propertyName.value === "constructor"; - } - default: { - return false; - } - } - } - /** - * Spec def of class method, only implement some of spec. - * @param propertyName - * @param isClass - * @param isStatic - * @param isAsync - * @param isGenerator - * @param params - * @param type - * reference: https://tc39.es/ecma262/#sec-class-definitions-static-semantics-early-errors - */ - function staticSematicEarlyErrorForClassMethodDefinition( - propertyName: PropertyName, - isClass: boolean, - isStatic: boolean, - isAsync: boolean, - isGenerator: boolean, - params: Array, - type: MethodDefinition["type"], - ) { - // general check - if (type === "get" && params.length > 0) { - raiseError(ErrorMessageMap.syntax_error_getter_functions_must_have_no_arguments, propertyName.start); - } - if (type === "set") { - if (params.length !== 1) { - raiseError(ErrorMessageMap.syntax_error_setter_functions_must_have_one_argument, params[0].start); - } - for (const param of params) { - if (isRestElement(param)) { - raiseError( - ErrorMessageMap.syntax_error_setter_functions_must_have_one_argument_not_rest, - param.start, - ); - } - } - } - if (type === "get" && (isAsync || isGenerator)) { - raiseError(ErrorMessageMap.extra_error_getter_can_not_be_async_or_generator, propertyName.start); - } - if (type === "set" && (isAsync || isGenerator)) { - raiseError(ErrorMessageMap.extra_error_setter_can_not_be_async_or_generator, propertyName.start); - } - // class check - if (isClass) { - let valueOfName: string | undefined, - isPrivate = false, - fromLiteral = false; // - if (isStringLiteral(propertyName)) { - valueOfName = propertyName.value; - fromLiteral = true; - } else if (isIdentifer(propertyName)) { - valueOfName = propertyName.name; - } else if (isPrivateName(propertyName)) { - valueOfName = propertyName.name; - isPrivate = true; - } - if (valueOfName === "constructor" && !fromLiteral) { - if (isAsync) { - raiseError( - ErrorMessageMap.v8_error_class_constructor_may_not_be_an_async_method, - propertyName.start, - ); - } - if (isGenerator) { - raiseError(ErrorMessageMap.v8_error_class_constructor_may_not_be_a_generator, propertyName.start); - } - if (type === "get" || type === "set") { - raiseError(ErrorMessageMap.v8_error_class_constructor_may_not_be_an_accessor, propertyName.start); - } - if (isPrivate) { - raiseError( - ErrorMessageMap.v8_error_class_may_not_have_a_private_field_named_constructor, - propertyName.start, - ); - } - } - if (valueOfName === "prototype" && !isPrivate && type === "method" && isStatic) { - raiseError( - ErrorMessageMap.v8_error_class_may_not_have_static_property_named_prototype, - propertyName.start, - ); - } - } - } - function parseArrayExpression() { - const { start } = expect(SyntaxKinds.BracketLeftPunctuator); - const elements: Array = []; - let tralingComma = false; - let isStart = true; - while (!match(SyntaxKinds.BracketRightPunctuator) && !match(SyntaxKinds.EOFToken)) { - if (isStart) { - isStart = false; - } else { - expect(SyntaxKinds.CommaToken); - } - if (match([SyntaxKinds.BracketRightPunctuator, SyntaxKinds.EOFToken])) { - tralingComma = true; - break; - } - if (match(SyntaxKinds.CommaToken)) { - elements.push(null); - continue; - } - if (match(SyntaxKinds.SpreadOperator)) { - const start = getStartPosition(); - nextToken(); - const expr = parseAssignmentExpressionAllowIn(); - elements.push(Factory.createSpreadElement(expr, start, cloneSourcePosition(expr.end))); - } else { - const expr = parseAssignmentExpressionAllowIn(); - elements.push(expr); - } - } - const { end } = expect(SyntaxKinds.BracketRightPunctuator); - return Factory.createArrayExpression(elements, start, end, tralingComma); - } - function parseFunctionExpression(isAsync: boolean) { - enterFunctionScope(isAsync); - const funcExpr = parseFunction(true); - exitFunctionScope(false); - return Factory.transFormFunctionToFunctionExpression(funcExpr); - } - function parseClassExpression(decoratorList: Decorator[] | null) { - return Factory.transFormClassToClassExpression(parseClass(decoratorList)); - } - function parseCoverExpressionORArrowFunction() { - const possibleBeArrow = canParseAsArrowFunction(); - expectButNotEat(SyntaxKinds.ParenthesesLeftPunctuator); - const [[{ start, end, nodes, trailingComma }, strictModeScope], arrowExprScope] = - parseWithArrowExpressionScope(() => parseWithCatpureLayer(parseArguments)); - if (!possibleBeArrow || !match(SyntaxKinds.ArrowOperator)) { - // transfor to sequence or signal expression - for (const element of nodes) { - if (isSpreadElement(element)) { - // recoverable error - raiseError(ErrorMessageMap.extra_error_rest_element_invalid, element.start); - } - } - if (trailingComma) { - // recoverable error - raiseError(ErrorMessageMap.extra_error_sequence_expression_can_not_have_trailing_comma, end); - } - if (nodes.length === 1) { - nodes[0].parentheses = true; - return nodes[0]; - } - if (nodes.length === 0) { - // recoverable error - raiseError(ErrorMessageMap.extra_error_empty_parentheses_expression, start); - } - const seq = Factory.createSequenceExpression(nodes, start, end); - seq.parentheses = true; - return seq; - } - enterArrowFunctionBodyScope(); - const arrowExpr = parseArrowFunctionExpression( - { start, end, nodes, trailingComma }, - strictModeScope, - arrowExprScope, - ); - exitArrowFunctionBodyScope(); - return arrowExpr; - } - /** - * Parse arrow function expression, by given argumentlist and meta data, include - * - start of `(` - * - end of `)`, - * - is trailing comma of argument list - * please notes that this function accept with arguments, not paramemter list, so we need to - * transform arguments to parameter list, so we need to call `toAssignment` for each argument. - * and we also need to check is parameter duplicate. - * - * @param {ASTArrayWithMetaData & { trailingComma: boolean }} metaData - * @returns {ArrorFunctionExpression} - */ - function parseArrowFunctionExpression( - metaData: ASTArrayWithMetaData & { trailingComma: boolean }, - strictModeScope: StrictModeScope, - arrowExprScope: AsyncArrowExpressionScope, - ): ArrorFunctionExpression { - if (getLineTerminatorFlag()) { - // recoverable error - raiseError(ErrorMessageMap.extra_error_no_line_break_is_allowed_before_arrow, getStartPosition()); - } - expect(SyntaxKinds.ArrowOperator); - const functionArguments = argumentToFunctionParams( - metaData.nodes, - metaData.trailingComma, - strictModeScope, - arrowExprScope, - ); - let body: Expression | FunctionBody | undefined; - let isExpression = false; - if (match(SyntaxKinds.BracesLeftPunctuator)) { - body = parseFunctionBody(); - } else { - body = parseAssignmentExpressionInheritIn(); - isExpression = true; - } - postStaticSematicEarlyErrorForStrictModeOfFunction(null, strictModeScope); - return Factory.createArrowExpression( - isExpression, - body, - functionArguments, - isCurrentScopeParseAwaitAsExpression(), - cloneSourcePosition(metaData.start), - cloneSourcePosition(body.end), - ); - } - /** - * Transform function from expressions to patterns (arguments to params), checking syntax error - * by expression scope and post statci sematic check for pattern rule. - * - asycn arrow scope: check await expression, yield expression - * - strict mode scope: expression Rval to Lval has different rule in strict mode - * - multi spread vs multi rest: rest is unique, spread can be multi. - * @param functionArguments - * @param trailingComma - * @param strictModeScope - * @param arrowExprScope - * @returns - */ - function argumentToFunctionParams( - functionArguments: Array, - trailingComma: boolean, - strictModeScope: StrictModeScope, - arrowExprScope: AsyncArrowExpressionScope, - ): Array { - const params = functionArguments.map((node) => exprToPattern(node, true)) as Array; - if (isCurrentScopeParseAwaitAsExpression() || isParentFunctionAsync() || isParentFunctionGenerator()) { - checkAsyncArrowExprScopeError(arrowExprScope); - } - if (isInStrictMode()) { - checkStrictModeScopeError(strictModeScope); - } - const isMultiSpread = postStaticSematicForArrowParamAfterTransform(params); - if (isMultiSpread && trailingComma) - // recoverable error - raiseError( - ErrorMessageMap.babel_error_unexpected_trailing_comma_after_rest_element, - lexer.getLastTokenEndPositon(), - ); - // check as function params - setContextIfParamsIsSimpleParameterList(params); - return params; - } - function postStaticSematicForArrowParamAfterTransform(params: Array) { - let flag = false; - params.forEach((param) => { - if (flag && isRestElement(param)) { - // recoverable error - raiseError(ErrorMessageMap.babel_error_unexpected_trailing_comma_after_rest_element, param.start); - return; - } - if (flag) { - // recoverable error - raiseError(ErrorMessageMap.babel_error_unexpected_trailing_comma_after_rest_element, param.start); - return; - } - if (!flag && isRestElement(param)) { - flag = true; - } - }); - return flag; - } - /** ================================================================================ - * Parse JSX - * entry point: https://facebook.github.io/jsx/ - * ================================================================================== - */ - /** - * Parse JSX Element or JSX Fragment - * ``` - * PrimaryExpression := JSXElement - * := JSXFragment - * ``` - */ - function parseJSXElementOrJSXFragment(inJSXChildren: boolean): JSXElement | JSXFragment { - if (!config.plugins.includes("jsx")) { - raiseError(ErrorMessageMap.babel_error_need_enable_jsx, getStartPosition()); - } - const lookaheadToken = lookahead(); - if (lookaheadToken.kind !== SyntaxKinds.GtOperator) { - return parseJSXElement(inJSXChildren); - } else { - return parseJSXFragment(inJSXChildren); - } - } - /** - * Parse JSX Element - * ``` - * JSXElement := JSXOpeningElement JSXChildren JSXClosingElement - * := JSXOpeningElement - * ``` - * @returns {JSXElement} - */ - function parseJSXElement(inJSXChildren: boolean): JSXElement { - const opeingElement = parseJSXOpeingElement(inJSXChildren); - if (opeingElement.selfClosing) { - return Factory.createJSXElement( - opeingElement, - null, - [], - cloneSourcePosition(opeingElement.start), - cloneSourcePosition(opeingElement.end), - ); - } - const children = parseJSXChildren(); - const closingElement = parseJSXClosingElement(inJSXChildren); - staticSematicEarlyErrorForJSXElement(opeingElement, closingElement); - return Factory.createJSXElement( - opeingElement, - closingElement, - children, - cloneSourcePosition(opeingElement.start), - cloneSourcePosition(opeingElement.end), - ); - } - function staticSematicEarlyErrorForJSXElement( - openingElement: JSXOpeningElement, - closingElement: JSXClosingElement, - ) { - const openElementSourceText = lexer.getSourceValueByIndex( - openingElement.name.start.index, - openingElement.name.end.index, - ); - const closeElementSourceText = lexer.getSourceValueByIndex( - closingElement.name.start.index, - closingElement.name.end.index, - ); - if (openElementSourceText !== closeElementSourceText) { - throw new Error(); - } - } - /** - * Parse JSXOpeingElement - * ``` - * JSXOpeningElement := `<` JSXElementName JSXAtrributes `>` - * := `<` JSXElementName JSXAtrributes `/>` - * ``` - * @returns {JSXOpeningElement} - */ - function parseJSXOpeingElement(inJSXChildren: boolean): JSXOpeningElement { - const { start } = expect(SyntaxKinds.LtOperator); - const lastLexerJSXEndTagContext = lexer.getJSXGtContext(); - lexer.setJSXGtContext(true); - const name = parseJSXElementName(); - const attributes = parseJSXAttributes(); - lexer.setJSXGtContext(lastLexerJSXEndTagContext); - if (match(SyntaxKinds.GtOperator)) { - const end = getEndPosition(); - nextTokenInJSXChildren(true); - return Factory.createJSXOpeningElement(name, attributes, false, start, end); - } - if (match(SyntaxKinds.JSXSelfClosedToken)) { - const end = getEndPosition(); - nextTokenInJSXChildren(inJSXChildren); - return Factory.createJSXOpeningElement(name, attributes, true, start, end); - } - // for `/ >` - if (match(SyntaxKinds.DivideOperator) && lookahead().kind === SyntaxKinds.GtOperator) { - nextToken(); - const end = getEndPosition(); - nextTokenInJSXChildren(inJSXChildren); - return Factory.createJSXOpeningElement(name, attributes, true, start, end); - } - throw createUnexpectError(); - } - /** - * Parse name of jsx element or jsx fragment - * ``` - * JSXElementName := JSXIdentifier - * := JSXMemberExpression - * := JSXNamespaceName - * ``` - * @returns {JSXIdentifier | JSXMemberExpression | JSXNamespacedName} - */ - function parseJSXElementName(): JSXIdentifier | JSXMemberExpression | JSXNamespacedName { - let name: JSXIdentifier | JSXMemberExpression | JSXNamespacedName = parseJSXIdentifier(); - if (match(SyntaxKinds.ColonPunctuator)) { - nextToken(); - const subName = parseJSXIdentifier(); - name = Factory.createJSXNamespacedName( - name, - subName, - cloneSourcePosition(name.start), - cloneSourcePosition(subName.end), - ); - } else if (match(SyntaxKinds.DotOperator)) { - while (match(SyntaxKinds.DotOperator) && !match(SyntaxKinds.EOFToken)) { - nextToken(); - const property = parseJSXIdentifier(); - name = Factory.createJSXMemberExpression( - name, - property, - cloneSourcePosition(name.start), - cloneSourcePosition(property.end), - ); - } - } - return name; - } - /** - * Parse JSX Attributes. - * ``` - * JSXAttributes := JSXAttributes JSXAttribute - * := JSXAttributes JSXSpreadAttribute - * := JSXAttribute - * := JSXSpreadAttribute - * JSXAttribute := JSXAttributeName '=' StringLiteral - * := JSXAttributeName '=' JSXExpressionContainer (expression can not be null) - * := JSXAttributeName '=' JSXElement - * := JSxAttributeName '=' JSXFragment - * := JSXAttrbuteName - * JSXSpreadAttribute := '{''...' AssignmentExpression '}' - * JSXAttributeName := JSXIdentifier - * := JSXNamespaceName - * ``` - * @returns {Array} - */ - function parseJSXAttributes(): Array { - const attribute: Array = []; - while ( - !match(SyntaxKinds.EOFToken) && - !match(SyntaxKinds.GtOperator) && - !match(SyntaxKinds.JSXSelfClosedToken) && - !(match(SyntaxKinds.DivideOperator) && lookahead().kind === SyntaxKinds.GtOperator) - ) { - // parse spread - if (match(SyntaxKinds.BracesLeftPunctuator)) { - nextToken(); - expect(SyntaxKinds.SpreadOperator); - const expression = parseAssignmentExpressionAllowIn(); - expect(SyntaxKinds.BracesRightPunctuator); - attribute.push( - Factory.createJSXSpreadAttribute( - expression, - cloneSourcePosition(expression.start), - cloneSourcePosition(expression.end), - ), - ); - continue; - } - // parse name - let name: JSXIdentifier | JSXNamespacedName = parseJSXIdentifier(); - if (match(SyntaxKinds.ColonPunctuator)) { - nextToken(); - const subName = parseJSXIdentifier(); - name = Factory.createJSXNamespacedName( - name, - subName, - cloneSourcePosition(name.start), - cloneSourcePosition(subName.end), - ); - } - // parse value - if (match(SyntaxKinds.AssginOperator)) { - lexer.setJSXStringContext(true); - nextToken(); - lexer.setJSXStringContext(false); - if (match(SyntaxKinds.StringLiteral)) { - const value = parseStringLiteral(); - attribute.push( - Factory.createJSXAttribute( - name, - value, - cloneSourcePosition(name.start), - cloneSourcePosition(value.end), - ), - ); - continue; - } - if (match(SyntaxKinds.BracesLeftPunctuator)) { - const expression = parseJSXExpressionContainer(false); - if (!expression.expression) { - throw new Error("right hand side of jsx attribute must have expression if start with `{`"); - } - attribute.push( - Factory.createJSXAttribute( - name, - expression, - cloneSourcePosition(name.start), - cloneSourcePosition(expression.end), - ), - ); - continue; - } - const element = parseJSXElementOrJSXFragment(false); - attribute.push( - Factory.createJSXAttribute( - name, - element, - cloneSourcePosition(name.start), - cloneSourcePosition(element.end), - ), - ); - } else { - attribute.push( - Factory.createJSXAttribute( - name, - null, - cloneSourcePosition(name.start), - cloneSourcePosition(name.end), - ), - ); - } - } - return attribute; - } - /** - * Parse JSX Children - * ``` - * JSXChildren := JSXChildren JSXChild - * := JSXChild - * JSXChild := JSXText - * := JSXExpressionContainer - * := JSXElement - * := JSXFragment - * := JSXSpreadChild - * JSXSpreadChild := {'...AssignmentExpression '}' - * ``` - * @returns {Array} - */ - function parseJSXChildren(): JSXElement["children"] { - const children: JSXElement["children"] = []; - while (!match(SyntaxKinds.JSXCloseTagStart) && !match(SyntaxKinds.EOFToken)) { - if (match(SyntaxKinds.LtOperator)) { - children.push(parseJSXElementOrJSXFragment(true)); - continue; - } - if (match(SyntaxKinds.BracesLeftPunctuator)) { - if (lookahead().kind == SyntaxKinds.SpreadOperator) { - expect(SyntaxKinds.BracesLeftPunctuator); - expect(SyntaxKinds.SpreadOperator); - const expression = parseAssignmentExpressionAllowIn(); - expect(SyntaxKinds.BracesRightPunctuator); - children.push( - Factory.createJSXSpreadChild( - expression, - cloneSourcePosition(expression.start), - cloneSourcePosition(expression.end), - ), - ); - continue; - } - children.push(parseJSXExpressionContainer(true)); - continue; - } - children.push(parseJSXText()); - } - return children; - } - /** - * Parse JSX expression container - * ``` - * JSXExpressionContainer = '{' AssignmentExpression '}' - * ``` - * @returns {JSXExpressionContainer} - */ - function parseJSXExpressionContainer(inJSXChildren: boolean): JSXExpressionContainer { - const { start } = expect(SyntaxKinds.BracesLeftPunctuator); - const expression = match(SyntaxKinds.BracesRightPunctuator) ? null : parseAssignmentExpressionAllowIn(); - const { end } = expectInJSXChildren(SyntaxKinds.BracesRightPunctuator, inJSXChildren); - return Factory.createsJSXExpressionContainer(expression, start, end); - } - /** - * Parse Closing Element of JSXElement - * ``` - * JSXClosingElement := '' - * ``` - * @returns {JSXClosingElement} - */ - function parseJSXClosingElement(inJSXChildren: boolean): JSXClosingElement { - const { start } = expect(SyntaxKinds.JSXCloseTagStart); - const lastLexerJSXEndTagContext = lexer.getJSXGtContext(); - lexer.setJSXGtContext(true); - const name = parseJSXElementName(); - const { end } = expectInJSXChildren(SyntaxKinds.GtOperator, inJSXChildren); - lexer.setJSXGtContext(lastLexerJSXEndTagContext); - return Factory.createJSXClosingElement(name, start, end); - } - /** - * - * @returns {JSXIdentifier} - */ - function parseJSXIdentifier(): JSXIdentifier { - // eslint-disable-next-line prefer-const - let { start, end } = expect(IdentiferWithKeyworArray); - // eslint-disable-next-line no-constant-condition - while (1) { - if (match(SyntaxKinds.MinusOperator)) { - end = getEndPosition(); - nextToken(); - } else { - break; - } - if (match(IdentiferWithKeyworArray)) { - end = getEndPosition(); - nextToken(); - } else { - break; - } - } - const value = lexer.getSourceValueByIndex(start.index, end.index); - return Factory.createJSXIdentifier(value, start, end); - } - function parseJSXText() { - const { start, end, value } = expect(SyntaxKinds.JSXText); - return Factory.createJSXText(value, start, end); - } - /** - * Parse JSXFragment - * ``` - * JSXFragment := `<``/>` JSXChildern `` - * ``` - * @returns {JSXFragment} - */ - function parseJSXFragment(inJSXChildren: boolean): JSXFragment { - const { start: openingStart } = expect(SyntaxKinds.LtOperator); - const { end: openingEnd } = expectInJSXChildren(SyntaxKinds.GtOperator, true); - const children = parseJSXChildren(); - const { start: closingStart } = expect(SyntaxKinds.JSXCloseTagStart); - const { end: closingEnd } = expectInJSXChildren(SyntaxKinds.GtOperator, inJSXChildren); - return Factory.createJSXFragment( - Factory.createJSXOpeningFragment(openingStart, openingEnd), - Factory.createJSXClosingFragment(closingStart, closingEnd), - children, - cloneSourcePosition(openingStart), - cloneSourcePosition(closingEnd), - ); - } - function expectInJSXChildren(kind: SyntaxKinds, inJSXChildren: boolean) { - if (match(kind)) { - const metaData = { - value: getSourceValue(), - start: getStartPosition(), - end: getEndPosition(), - }; - if (inJSXChildren) { - lexer.nextTokenInJSXChildrenContext(); - } else { - lexer.nextToken(); - } - return metaData; - } - throw createUnexpectError(); - } - function nextTokenInJSXChildren(inJSXChildren: boolean) { - if (inJSXChildren) { - lexer.nextTokenInJSXChildrenContext(); - } else { - lexer.nextToken(); - } - } - /** ================================================================================ - * Parse Pattern - * entry point: https://tc39.es/ecma262/#sec-destructuring-binding-patterns - * ================================================================================== - */ - /** - * Parse BindingElement - * ``` - * BindingElemet := Identifer ('=' AssigmentExpression)? - * := BindingPattern ('=' AssigmentExpression)? - * ``` - * @returns - */ - function parseBindingElement(shouldParseAssignment = true): Pattern { - expectButNotEat([ - ...IdentiferWithKeyworArray, - SyntaxKinds.BracesLeftPunctuator, - SyntaxKinds.BracketLeftPunctuator, - ]); - let left: Pattern | undefined; - if (match(BindingIdentifierSyntaxKindArray)) { - left = parseBindingIdentifier(); - } else { - left = parseBindingPattern(); - } - if (match(SyntaxKinds.AssginOperator) && shouldParseAssignment) { - nextToken(); - const right = parseWithRHSLayer(parseAssignmentExpressionAllowIn); - return Factory.createAssignmentPattern( - left, - right, - cloneSourcePosition(left.start), - cloneSourcePosition(right.end), - ); - } - return left; - } - function parseRestElement(allowPattern: boolean): RestElement { - const { start } = expect([SyntaxKinds.SpreadOperator]); - let id: Pattern | null = null; - if (match(BindingIdentifierSyntaxKindArray)) { - id = parseBindingIdentifier(); - } - if (match([SyntaxKinds.BracesLeftPunctuator, SyntaxKinds.BracketLeftPunctuator])) { - if (allowPattern) { - id = parseBindingPattern(); - } - if (!allowPattern) { - // recoverable error ? - throw createUnexpectError(); - } - } - if (!id) { - throw createUnexpectError(); - } - return Factory.createRestElement(id, start, cloneSourcePosition(id.end)); - } - function parseBindingIdentifier() { - const id = parseWithLHSLayer(parseIdentifierReference); - declarateNonFunctionalSymbol(id.name, id.start); - return id; - } - /** - * Parse BindingPattern - * ``` - * BindingPattern := ObjectPattern - * := ArrayPattern - * ``` - */ - function parseBindingPattern(): ObjectPattern | ArrayPattern { - return parseWithLHSLayer(() => { - expectButNotEat([SyntaxKinds.BracesLeftPunctuator, SyntaxKinds.BracketLeftPunctuator]); - if (match(SyntaxKinds.BracesLeftPunctuator)) { - return parseObjectPattern(); - } - return parseArrayPattern(); - }); - } - /** Parse Object Pattern - * ``` - * ObjectPattern := '{' ObjectPatternProperties '}' - * := '{' ObjtecPatternProperties ',' '}' - * := '{' ObjectPatternProperties ',' RestElement '}' - * := '{' RestElement '} - * ObjectPatternProperties := ObjectPatternProperties ',' ObjectPatternProperty - * ObjectPatternProperty := Identifer ('=' AssigmentExpression) - * := BindingPattern ('=' AssignmentExpression) - * ``` - * @return {ObjectPattern} - */ - function parseObjectPattern(): ObjectPattern { - const { start } = expect(SyntaxKinds.BracesLeftPunctuator); - if (match(SyntaxKinds.BracesRightPunctuator)) { - const end = getEndPosition(); - nextToken(); - const objectPattern = Factory.createObjectPattern([], start, end); - return objectPattern; - } - const properties: Array = [ - parseObjectPatternPossibelProperty(), - ]; - while (!match([SyntaxKinds.BracesRightPunctuator, SyntaxKinds.EOFToken])) { - expect(SyntaxKinds.CommaToken); - if (match(SyntaxKinds.BracesRightPunctuator) || match(SyntaxKinds.EOFToken)) { - continue; - } - properties.push(parseObjectPatternPossibelProperty()); - } - const { end } = expect(SyntaxKinds.BracesRightPunctuator); - const objectPattern = Factory.createObjectPattern(properties, start, end); - return objectPattern; - } - function parseObjectPatternPossibelProperty(): ObjectPatternProperty | RestElement | AssignmentPattern { - // parse Rest property - if (match(SyntaxKinds.SpreadOperator)) { - const rest = parseRestElement(false); - staticSematicForRestElementInObjectPattern(); - return rest; - } - // parse Object pattern property (rename) - const isComputedRef = { isComputed: false }; - const propertyName = parsePropertyName(isComputedRef); - if (isComputedRef.isComputed || match(SyntaxKinds.ColonPunctuator)) { - nextToken(); - const pattern = parseBindingElement(); - return Factory.createObjectPatternProperty( - propertyName, - pattern, - isComputedRef.isComputed, - false, - cloneSourcePosition(propertyName.start), - cloneSourcePosition(pattern.end), - ); - } - staticCheckForPropertyNameAsSingleBinding(propertyName); - // parse object pattern as Assignment pattern - if (match(SyntaxKinds.AssginOperator)) { - nextToken(); - const expr = parseWithRHSLayer(parseAssignmentExpressionAllowIn); - staticSematicForAssignmentPatternInObjectPattern(propertyName); - declarateNonFunctionalSymbol((propertyName as Identifier).name, propertyName.start); - return Factory.createAssignmentPattern( - propertyName as Pattern, - expr, - cloneSourcePosition(propertyName.start), - cloneSourcePosition(expr.end), - ); - } - // parse object pattern as shorted property. - staticSematicForShortedPropertyNameInObjectLike(propertyName); - declarateNonFunctionalSymbol((propertyName as Identifier).name, propertyName.start); - return Factory.createObjectPatternProperty( - propertyName, - undefined, - isComputedRef.isComputed, - true, - cloneSourcePosition(propertyName.start), - cloneSourcePosition(propertyName.end), - ); - } - /** - * In Object Pattern, Rest Element should be last one, and can - * not have trailing comma. - */ - function staticSematicForRestElementInObjectPattern() { - if ( - !match(SyntaxKinds.BracesRightPunctuator) || - (match(SyntaxKinds.CommaToken) && lookahead().kind === SyntaxKinds.BracesRightPunctuator) - ) { - // recoverable error - raiseError( - ErrorMessageMap.babel_error_unexpected_trailing_comma_after_rest_element, - getStartPosition(), - ); - } - } - /** - * Ban some usage like `{ "string-key" = "name" }` in onject pattern - * @param propertyName - */ - function staticSematicForAssignmentPatternInObjectPattern(propertyName: PropertyName) { - if (!isPattern(propertyName)) { - throw createMessageError("assignment pattern left value can only allow identifier or pattern"); - } - } - /** - * As for shorted and assignment patern in object pattern, the property name should be - * a bidning identifier, so we need to check and record the property name. - * @param propertyName - * @returns - */ - function staticCheckForPropertyNameAsSingleBinding(propertyName: PropertyName) { - if (isIdentifer(propertyName)) { - switch (propertyName.name) { - case "await": { - if (isCurrentScopeParseAwaitAsExpression() || config.sourceType === "module") { - raiseError( - ErrorMessageMap.babel_error_can_not_use_await_as_identifier_inside_an_async_function, - propertyName.start, - ); - } - return; - } - case "yield": { - if (isCurrentScopeParseYieldAsExpression() || isInStrictMode()) { - raiseError(ErrorMessageMap.babel_error_invalid_yield, propertyName.start); - } - return; - } - case "arguments": { - if (isInStrictMode() && strictModeScopeRecorder.isInLHS()) { - raiseError(ErrorMessageMap.syntax_error_bad_strict_arguments_eval, propertyName.start); - } - recordScope(ExpressionScopeKind.ArgumentsIdentifier, propertyName.start); - return; - } - case "eval": { - if (isInStrictMode() && strictModeScopeRecorder.isInLHS()) { - raiseError(ErrorMessageMap.syntax_error_bad_strict_arguments_eval, propertyName.start); - } - recordScope(ExpressionScopeKind.EvalIdentifier, propertyName.start); - return; - } - case "let": { - if (isInStrictMode()) { - raiseError(ErrorMessageMap.babel_error_unexpected_keyword, propertyName.start); - } - recordScope(ExpressionScopeKind.LetIdentifiier, propertyName.start); - return; - } - default: { - if (KeywordSet.has(propertyName.name)) { - // recoverable error - raiseError(ErrorMessageMap.babel_error_unexpected_keyword, propertyName.start); - } - if (PreserveWordSet.has(propertyName.name) && isInStrictMode()) { - // recoverable error - raiseError(ErrorMessageMap.babel_error_unexpected_reserved_word, propertyName.start); - } - return; - } - } - } - } - function parseArrayPattern(): ArrayPattern { - const { start } = expect(SyntaxKinds.BracketLeftPunctuator); - let isStart = true; - const elements: Array = []; - while (!match(SyntaxKinds.BracketRightPunctuator) && !match(SyntaxKinds.EOFToken)) { - if (isStart) { - isStart = false; - } else { - expect(SyntaxKinds.CommaToken); - } - if (match(SyntaxKinds.BracketRightPunctuator) || match(SyntaxKinds.EOFToken)) { - continue; - } - if (match(SyntaxKinds.CommaToken)) { - elements.push(null); - continue; - } - if (match(SyntaxKinds.SpreadOperator)) { - elements.push(parseRestElement(true)); - if (!match(SyntaxKinds.BracketRightPunctuator)) { - // recoverable error - raiseError( - ErrorMessageMap.babel_error_unexpected_trailing_comma_after_rest_element, - getStartPosition(), - ); - } - break; - } - const pattern = parseBindingElement(); - elements.push(pattern); - } - const { end } = expect(SyntaxKinds.BracketRightPunctuator); - const arrayPattern = Factory.createArrayPattern(elements, start, end); - return arrayPattern; - } - /** ================================================================================ - * Parse Import Declaration - * entry point: https://tc39.es/ecma262/#sec-imports - * ================================================================================== - */ - function expectFormKeyword() { - if (getSourceValue() !== "from") { - throw createUnexpectError(); - } - if (getEscFlag()) { - raiseError(ErrorMessageMap.invalid_esc_char_in_keyword, getStartPosition()); - } - nextToken(); - } - /** - * Parse Import Declaration - * ``` - * ImportDeclaration := 'import' ImportClasue FromClause WithClause? - * := 'import' StringLiteral WithClause? - * FromClause := 'from' StringLiteral - * ImportClause := ImportDefaultBinding - * := ImportNamesapce - * := ImportNamed - * := ImportDefaultBindling ',' ImportNamed - * := ImportDefaultBindling ',' ImportNamespace - * ``` - * - frist, eat import keyword - * 1. if it is string literal, must be `import StringLiteral` - * 2. if it start with `*`, must be import name space - * 3. if it start with '{', must be import named - * 4. fallback case: default import with import named or import namesspace - * or nothing - * @returns {ImportDeclaration} - */ - function parseImportDeclaration(): ImportDeclaration { - const { start } = expect(SyntaxKinds.ImportKeyword); - if (config.sourceType === "script") { - raiseError(ErrorMessageMap.babel_error_import_and_export_may_appear_only_with_sourceType_module, start); - } - const specifiers: Array = []; - if (match(SyntaxKinds.StringLiteral)) { - const source = parseStringLiteral(); - const attributes = parseImportAttributesOptional(); - shouldInsertSemi(); - return Factory.createImportDeclaration( - specifiers, - source, - attributes, - start, - cloneSourcePosition(source.end), - ); - } - if (match(SyntaxKinds.MultiplyOperator)) { - specifiers.push(parseImportNamespaceSpecifier()); - expectFormKeyword(); - const source = parseStringLiteral(); - const attributes = parseImportAttributesOptional(); - shouldInsertSemi(); - return Factory.createImportDeclaration( - specifiers, - source, - attributes, - start, - cloneSourcePosition(source.end), - ); - } - if (match(SyntaxKinds.BracesLeftPunctuator)) { - parseImportSpecifiers(specifiers); - expectFormKeyword(); - const source = parseStringLiteral(); - const attributes = parseImportAttributesOptional(); - shouldInsertSemi(); - return Factory.createImportDeclaration( - specifiers, - source, - attributes, - start, - cloneSourcePosition(source.end), - ); - } - specifiers.push(parseImportDefaultSpecifier()); - if (match(SyntaxKinds.CommaToken)) { - nextToken(); - if (match(SyntaxKinds.BracesLeftPunctuator)) { - parseImportSpecifiers(specifiers); - } else if (match(SyntaxKinds.MultiplyOperator)) { - specifiers.push(parseImportNamespaceSpecifier()); - } else { - throw createMessageError( - "import default specifier can only concat with namespace of import named specifier", - ); - } - } - expectFormKeyword(); - const source = parseStringLiteral(); - const attributes = parseImportAttributesOptional(); - shouldInsertSemi(); - return Factory.createImportDeclaration( - specifiers, - source, - attributes, - start, - cloneSourcePosition(source.end), - ); - } - /** - * Parse Default import binding - * ``` - * ImportDefaultBinding := Identifer - * ``` - * @returns {ImportDefaultSpecifier} - */ - function parseImportDefaultSpecifier(): ImportDefaultSpecifier { - const name = parseIdentifierReference(); - declarateLetSymbol(name.name, name.start); - return Factory.createImportDefaultSpecifier( - name, - cloneSourcePosition(name.start), - cloneSourcePosition(name.end), - ); - } - /** - * Parse namespace import - * ``` - * ImportNamespace := '*' 'as' Identifer - * ``` - * @returns {ImportNamespaceSpecifier} - */ - function parseImportNamespaceSpecifier(): ImportNamespaceSpecifier { - const { start } = expect(SyntaxKinds.MultiplyOperator); - if (!isContextKeyword("as")) { - raiseError(ErrorMessageMap.babel_error_unexpected_token_expected_as, getStartPosition()); - } - nextToken(); - const id = parseIdentifierReference(); - declarateLetSymbol(id.name, id.start); - return Factory.createImportNamespaceSpecifier(id, start, cloneSourcePosition(id.end)); - } - /** - * Parse Import Nameds - * ``` - * ImportNamed := '{' ImportList ','? '}' - * ImportList := [ ImportItem ] - * ImportItem := IdentiferWithKeyword - * := (Identifer | StringLiteral) 'as' Identifer - * ``` - * @param specifiers - * @return {void} - */ - function parseImportSpecifiers( - specifiers: Array, - ): void { - expect(SyntaxKinds.BracesLeftPunctuator); - let isStart = true; - while (!match(SyntaxKinds.BracesRightPunctuator) && !match(SyntaxKinds.EOFToken)) { - if (isStart) { - isStart = false; - } else { - expect(SyntaxKinds.CommaToken); - } - if (match(SyntaxKinds.BracesRightPunctuator) || match(SyntaxKinds.EOFToken)) { - break; - } - const imported = parseModuleExportName(); - if (!isContextKeyword("as")) { - if (isIdentifer(imported) && KeywordSet.has(imported.name)) { - // recoverable error - raiseError(ErrorMessageMap.extra_error_unexpect_keyword_in_module_name, imported.start); - } else if (isStringLiteral(imported)) { - // recoverable error - raiseError( - ErrorMessageMap.babel_error_string_literal_cannot_be_used_as_an_imported_binding, - imported.start, - ); - } - if (isIdentifer(imported)) declarateLetSymbol(imported.name, imported.start); - specifiers.push( - Factory.createImportSpecifier( - imported, - null, - cloneSourcePosition(imported.start), - cloneSourcePosition(imported.end), - ), - ); - continue; - } - nextToken(); - const local = parseIdentifierReference(); - declarateLetSymbol(local.name, local.start); - specifiers.push( - Factory.createImportSpecifier( - imported, - local, - cloneSourcePosition(imported.start), - cloneSourcePosition(local.end), - ), - ); - } - expect(SyntaxKinds.BracesRightPunctuator); - } - function parseImportAttributesOptional(): ImportAttribute[] | undefined { - if ( - (config.plugins.includes("importAttributes") && match(SyntaxKinds.WithKeyword)) || - (config.plugins.includes("importAssertions") && - match(SyntaxKinds.Identifier) && - getSourceValue() === "assert") - ) { - nextToken(); - return parseImportAttributes(); - } - return undefined; - } - function parseImportAttributes(): ImportAttribute[] { - expect(SyntaxKinds.BracesLeftPunctuator); - const attributes: Array = [parseImportAttribute()]; - while (!match([SyntaxKinds.BracesRightPunctuator, SyntaxKinds.EOFToken])) { - expect(SyntaxKinds.CommaToken); - if (match([SyntaxKinds.BracesRightPunctuator, SyntaxKinds.EOFToken])) { - break; - } - attributes.push(parseImportAttribute()); - } - expect(SyntaxKinds.BracesRightPunctuator); - return attributes; - } - function parseImportAttribute(): ImportAttribute { - const key = parseIdentifierName(); - expect(SyntaxKinds.ColonPunctuator); - const value = parseStringLiteral(); - return Factory.createImportAttribute( - key, - value, - cloneSourcePosition(key.start), - cloneSourcePosition(value.end), - ); - } - /** ================================================================================ - * Parse Export Declaration - * entry point: https://tc39.es/ecma262/#prod-ExportDeclaration - * ================================================================================== - */ - /** - * Parse Export Declaration - * ``` - * ExportDeclaration := 'export' ExportNamedDeclaration ';'? - * := 'export' ExportDefaultDeclaration - * := 'export' ExportAllDeclaration - * ExportNamedDeclaration := '{' ExportList '}' ('from' StringLiteral)? - * := Declaration - * := VarStatement - * ExportAllDeclaration := '*' 'from' StringLiteral - * := '*' 'as' Identifer 'from' StringLiteral - * ``` - * @returns {ExportDeclaration} - */ - function parseExportDeclaration(): ExportDeclaration { - setExportContext(ExportContext.InExport); - - const { start } = expect(SyntaxKinds.ExportKeyword); - if (config.sourceType === "script") { - raiseError(ErrorMessageMap.babel_error_import_and_export_may_appear_only_with_sourceType_module, start); - } - let exportDeclaration: ExportDeclaration; - switch (getToken()) { - case SyntaxKinds.DefaultKeyword: { - exportDeclaration = parseExportDefaultDeclaration(start); - break; - } - case SyntaxKinds.MultiplyOperator: { - exportDeclaration = parseExportAllDeclaration(start); - break; - } - case SyntaxKinds.BracesLeftPunctuator: { - exportDeclaration = parseExportNamedDeclaration(start); - break; - } - default: { - const declaration = match(SyntaxKinds.VarKeyword) ? parseVariableDeclaration() : parseDeclaration(); - exportDeclaration = Factory.createExportNamedDeclaration( - [], - declaration, - null, - start, - cloneSourcePosition(declaration.end), - ); - break; - } - } - setExportContext(ExportContext.NotInExport); - return exportDeclaration; - } - /** - * Parse default export declaration - * ``` - * ``` - * @param {SourcePosition} start - * @returns {ExportDefaultDeclaration} - */ - function parseExportDefaultDeclaration(start: SourcePosition): ExportDefaultDeclaration { - expect(SyntaxKinds.DefaultKeyword); - switch (getToken()) { - case SyntaxKinds.ClassKeyword: - case SyntaxKinds.AtPunctuator: { - let decoratorList = takeCacheDecorator(); - if (match(SyntaxKinds.AtPunctuator)) { - decoratorList = mergeDecoratorList(decoratorList, parseDecoratorList()); - } - const classDeclar = Factory.transFormClassToClassDeclaration(parseClass(decoratorList)); - staticSematicForDuplicateDefaultExport(classDeclar); - return Factory.createExportDefaultDeclaration( - classDeclar as ClassDeclaration | ClassExpression, - start, - cloneSourcePosition(classDeclar.end), - ); - } - case SyntaxKinds.FunctionKeyword: { - enterFunctionScope(); - const func = parseFunction(true); - exitFunctionScope(false); - const funcDeclar = Factory.transFormFunctionToFunctionDeclaration(func); - staticSematicForDuplicateDefaultExport(funcDeclar); - const name = funcDeclar.name; - if (name) { - delcarateFcuntionSymbol(name.name, func.generator, func.start); - } - return Factory.createExportDefaultDeclaration(funcDeclar, start, cloneSourcePosition(funcDeclar.end)); - } - default: { - if (isContextKeyword("async") && lookahead().kind === SyntaxKinds.FunctionKeyword) { - nextToken(); - enterFunctionScope(true); - const func = parseFunction(true); - exitFunctionScope(false); - const funcDeclar = Factory.transFormFunctionToFunctionDeclaration(func); - funcDeclar.async = true; - staticSematicForDuplicateDefaultExport(funcDeclar); - if (funcDeclar.name) { - delcarateFcuntionSymbol(funcDeclar.name.name, func.generator, func.start); - } - return Factory.createExportDefaultDeclaration( - funcDeclar, - start, - cloneSourcePosition(funcDeclar.end), - ); - } - // TODO: parse export default from ""; (experimental feature) - const expr = parseAssignmentExpressionAllowIn(); - shouldInsertSemi(); - staticSematicForDuplicateDefaultExport(expr); - return Factory.createExportDefaultDeclaration(expr, start, cloneSourcePosition(expr.end)); - } - } - } - /** - * Using symbol scope recorder for record the default export. - * @param node - */ - function staticSematicForDuplicateDefaultExport(node: ModuleItem) { - const isDefaultAlreadyBeDeclarated = symbolScopeRecorder.testAndSetDefaultExport(node.start); - if (isDefaultAlreadyBeDeclarated) { - raiseError(ErrorMessageMap.v8_error_duplicate_identifier, isDefaultAlreadyBeDeclarated); - } - } - function parseExportNamedDeclaration(start: SourcePosition): ExportNamedDeclarations { - expect(SyntaxKinds.BracesLeftPunctuator); - const specifier: Array = []; - let isStart = true; - let isMatchKeyword = false; - const undefExportSymbols: Array<[string, SourcePosition]> = []; - while (!match(SyntaxKinds.BracesRightPunctuator) && !match(SyntaxKinds.EOFToken)) { - if (isStart) { - isStart = false; - } else { - expect(SyntaxKinds.CommaToken); - } - if (match(SyntaxKinds.BracesRightPunctuator) || match(SyntaxKinds.EOFToken)) { - break; - } - if (match(Keywords)) { - isMatchKeyword = true; - } - const exported = parseModuleExportName(); - if (!isVariableDeclarated(helperGetValueOfExportName(exported))) { - undefExportSymbols.push([helperGetValueOfExportName(exported), exported.start]); - } - if (isContextKeyword("as")) { - nextToken(); - const local = parseModuleExportName(); - staticSematicForDuplicateExportName(local); - specifier.push( - Factory.createExportSpecifier( - exported, - local, - cloneSourcePosition(exported.start), - cloneSourcePosition(local.end), - ), - ); - continue; - } - staticSematicForDuplicateExportName(exported); - specifier.push( - Factory.createExportSpecifier( - exported, - null, - cloneSourcePosition(exported.start), - cloneSourcePosition(exported.end), - ), - ); - } - const { end: bracesRightPunctuatorEnd } = expect(SyntaxKinds.BracesRightPunctuator); - let source: StringLiteral | null = null; - if (getSourceValue() === "from") { - nextToken(); - source = parseStringLiteral(); - } else { - if (isMatchKeyword) { - throw new Error(); - } - if (undefExportSymbols.length > 0) { - undefExportSymbols.forEach(([sym, pos]) => { - symbolScopeRecorder.addToUndefExportSource(sym, pos); - }); - } - staticSematicEarlyErrorForExportName(specifier); - } - shouldInsertSemi(); - const end = source - ? source.end - : specifier.length === 0 - ? bracesRightPunctuatorEnd - : specifier[specifier.length - 1].end; - return Factory.createExportNamedDeclaration(specifier, null, source, start, cloneSourcePosition(end)); - } - /** - * Static Sematic Check based on - * - 16.2.3.1 Static Semantics: Early Errors - * @param specifiers - */ - function staticSematicEarlyErrorForExportName(specifiers: Array) { - for (const specifier of specifiers) { - if (isStringLiteral(specifier.exported)) { - raiseError( - ErrorMessageMap.babel_error_string_literal_cannot_be_used_as_an_exported_binding_without_from, - specifier.exported.start, - ); - } - } - } - /** - * Using symbol scope recorder for record export name identifier - * @param exportName - */ - function staticSematicForDuplicateExportName(exportName: StringLiteral | Identifier) { - const name = helperGetValueOfExportName(exportName); - const isExportNameAlreadyBeDeclar = declarateExportSymbol(name, exportName.start); - if (isExportNameAlreadyBeDeclar) { - raiseError(ErrorMessageMap.v8_error_duplicate_identifier, isExportNameAlreadyBeDeclar); - } - const isDefaultAlreadyBeDeclarated = symbolScopeRecorder.testAndSetDefaultExport(exportName.start); - if (name === "default" && isDefaultAlreadyBeDeclarated) { - raiseError(ErrorMessageMap.v8_error_duplicate_identifier, isDefaultAlreadyBeDeclarated); - } - } - function parseExportAllDeclaration(start: SourcePosition): ExportAllDeclaration { - expect(SyntaxKinds.MultiplyOperator); - let exported: Identifier | StringLiteral | null = null; - if (isContextKeyword("as")) { - nextToken(); - exported = parseModuleExportName(); - } else { - exported = null; - } - expectFormKeyword(); - const source = parseStringLiteral(); - shouldInsertSemi(); - return Factory.createExportAllDeclaration(exported, source, start, cloneSourcePosition(source.end)); - } - function parseModuleExportName() { - if (match(SyntaxKinds.StringLiteral)) { - return parseStringLiteral(); - } - return parseIdentifierName(); - } - function helperGetValueOfExportName(exportName: StringLiteral | Identifier) { - if (isIdentifer(exportName)) { - return exportName.name; - } - return exportName.value; - } -} diff --git a/web-infras/parser/src/parser/scope/arrowExprScope.ts b/web-infras/parser/src/parser/scope/arrowExprScope.ts index 9239d7ed..7d11cde8 100644 --- a/web-infras/parser/src/parser/scope/arrowExprScope.ts +++ b/web-infras/parser/src/parser/scope/arrowExprScope.ts @@ -17,6 +17,8 @@ function mergeScope(target: AsyncArrowExpressionScope, source: AsyncArrowExpress ); } +export type AsyncArrowExpressionScopeRecorder = ReturnType; + export function createAsyncArrowExpressionScopeRecorder() { const asyncArrowExpressionScopes: Array = []; diff --git a/web-infras/parser/src/parser/scope/lexicalScope/lexicalScope.ts b/web-infras/parser/src/parser/scope/lexicalScope/lexicalScope.ts index 95fedf38..58d1f154 100644 --- a/web-infras/parser/src/parser/scope/lexicalScope/lexicalScope.ts +++ b/web-infras/parser/src/parser/scope/lexicalScope/lexicalScope.ts @@ -7,6 +7,7 @@ import { ExportContext, } from "./type"; +export type LexicalScopeRecorder = ReturnType; /** * Lexical Scope Recorder is focus on the position of the current * parse position, is it in function, what kind of function ?, is in diff --git a/web-infras/parser/src/parser/scope/strictModeScope.ts b/web-infras/parser/src/parser/scope/strictModeScope.ts index 9cd4ba56..d0dadb1a 100644 --- a/web-infras/parser/src/parser/scope/strictModeScope.ts +++ b/web-infras/parser/src/parser/scope/strictModeScope.ts @@ -14,6 +14,8 @@ export type StrictModeScope = kind: "RHSLayer"; }; +export type StrictModeScopeRecorder = ReturnType; + export function createStrictModeScopeRecorder() { const strictModeScopes: Array = []; diff --git a/web-infras/parser/src/parser/scope/symbolScope/symbolScope.ts b/web-infras/parser/src/parser/scope/symbolScope/symbolScope.ts index fde3ff89..7a63b6fa 100644 --- a/web-infras/parser/src/parser/scope/symbolScope/symbolScope.ts +++ b/web-infras/parser/src/parser/scope/symbolScope/symbolScope.ts @@ -12,6 +12,9 @@ import { createSymbolScopeRecorderContext, isPrivateNameExist, } from "./type"; + +export type SymbolScopeRecorder = ReturnType; + /** * Symbol recorder is used to check the duplicate identifier, it should work the the lexical * scope recorder for position relate context in program. diff --git a/web-infras/parser/src/parser/ts/index.ts b/web-infras/parser/src/parser/ts/index.ts new file mode 100644 index 00000000..dca6b308 --- /dev/null +++ b/web-infras/parser/src/parser/ts/index.ts @@ -0,0 +1,927 @@ +import { + TSEnumDeclaration, + Factory, + TSEnumBody, + SyntaxKinds, + TSEnumMember, + Expression, + cloneSourcePosition, + TSTypeAliasDeclaration, + TSInterfaceDeclaration, + TSInterfaceHeritage, + TSTypeParameterDeclaration, + TSTypeParameter, + TSTypeNode, + TSTypeParameterInstantiation, + TSFunctionType, + ArrorFunctionExpression, + TSTypeAnnotation, + SourcePosition, + TSTypeOperator, + TSStringKeyword, + TSNumberKeyword, + TSBigIntKeyword, + TSBooleanKeyword, + TSNullKeyword, + TSUndefinedKeyword, + TSSymbolKeyword, + TSAnyKeyword, + TSUnknowKeyword, + TSVoidKeyword, + TSTypeQuery, + TSTupleType, + TSLiteralType, + TSParameter, + TSTypeReference, + TSEntityName, + TSTypeLiteral, + TSTypeElement, +} from "web-infra-common"; +import { LexerState, LexerContext } from "@/src/lexer/type"; +import { ParserPlugin } from "@/src/parser/config"; +import { ASTArrayWithMetaData } from "@/src/parser/type"; +import { AsyncArrowExpressionScope } from "@/src/parser/scope/arrowExprScope"; +import { StrictModeScope } from "@/src/parser/scope/strictModeScope"; +import { Parser } from "@/src/parser"; + +/** + * + * @param tryFunc + * @returns + */ +export function tryParse( + this: Parser, + tryFunc: () => T, +): [T, LexerState, LexerContext, number] | undefined { + const [state, context] = this.lexer.forkState(); + const errorIndex = this.errorHandler.markAsTry(); + try { + return [tryFunc(), state, context, errorIndex]; + } catch { + this.lexer.restoreState(state, context); + this.errorHandler.restoreTryFail(errorIndex); + } + return; +} +export function abortTryParseResult(this: Parser, state: LexerState, context: LexerContext, index: number) { + this.lexer.restoreState(state, context); + this.errorHandler.restoreTryFail(index); +} +export function parseInType(this: Parser, worker: () => T): T { + this.context.isInType = true; + let result; + try { + result = worker(); + } catch (e) { + this.context.isInType = false; + throw e; + } + return result; +} +export function parseTSEnumDeclaration(this: Parser): TSEnumDeclaration { + const start = this.getStartPosition(); + this.nextToken(); // eat `enum` + const id = this.parseIdentifierReference(); + const body = this.parseTSEnumBody(); + return Factory.createTSEnumDeclaration(id, body, start, this.getLastTokenEndPositon()); +} +export function parseTSEnumBody(this: Parser): TSEnumBody { + const { start } = this.expect(SyntaxKinds.BracesLeftPunctuator); + const members = []; + let isStart = true; + while (!this.match([SyntaxKinds.BracesRightPunctuator, SyntaxKinds.EOFToken])) { + if (isStart) { + isStart = false; + } else { + this.expect(SyntaxKinds.CommaToken); + } + // allow trailing comma + if (this.match([SyntaxKinds.BracesRightPunctuator, SyntaxKinds.EOFToken])) { + break; + } + members.push(this.parseTSEnumMember()); + } + const { end } = this.expect(SyntaxKinds.BracesRightPunctuator); + return Factory.createTSEnumBody(members, start, end); +} +export function parseTSEnumMember(this: Parser): TSEnumMember { + const name = this.parseIdentifierName(); + let init: Expression | undefined = undefined; + if (this.match(SyntaxKinds.AssginOperator)) { + this.nextToken(); + init = this.parseAssignmentExpressionAllowIn(); + } + return Factory.createTSEnumMember( + name, + false, + init, + cloneSourcePosition(name.start), + this.getLastTokenEndPositon(), + ); +} +export function parseTSTypeAlias(this: Parser): TSTypeAliasDeclaration { + // TODO: TS garud + const start = this.getStartPosition(); + this.nextToken(); // eat `type` + const name = this.parseIdentifierReference(); + const typeParameters = this.tryParseTSTypeParameterDeclaration(true); + this.expect(SyntaxKinds.AssginOperator); + const typeNode = this.parseTSTypeNode(); + this.shouldInsertSemi(); + return Factory.createTSTypeAliasDeclaration( + name, + typeNode, + typeParameters, + start, + this.getLastTokenEndPositon(), + ); +} +export function parseTSInterfaceDeclaration(this: Parser): TSInterfaceDeclaration { + // TODO: TS garud + const start = this.getStartPosition(); + this.nextToken(); // eat `interface` + const id = this.parseIdentifierReference(); + const typeParameters = this.tryParseTSTypeParameterDeclaration(false); + const extendTypes = this.tryParseTSInterfaceDeclarationExtends(); + const body = this.parseTSInterfaceBody(); + this.shouldInsertSemi(); + return Factory.createTSInterface( + id, + typeParameters, + extendTypes, + body, + start, + this.getLastTokenEndPositon(), + ); +} +export function tryParseTSInterfaceDeclarationExtends(this: Parser): Array { + if (this.match(SyntaxKinds.ExtendsKeyword)) { + this.nextToken(); + const extendsInterfaces = [this.parseTSInterfaceHeritage()]; + while (this.match(SyntaxKinds.CommaToken)) { + this.nextToken(); + extendsInterfaces.push(this.parseTSInterfaceHeritage()); + } + return extendsInterfaces; + } + return []; +} +export function parseTSInterfaceHeritage(this: Parser) { + const name = this.parseTSEntityName(); + const typeArguments = this.tryParseTSTypeParameterInstantiation(false); + return Factory.createTSInterfaceHeritage( + name, + typeArguments, + cloneSourcePosition(name.start), + this.getLastTokenEndPositon(), + ); +} +export function tryParseTSTypeParameterDeclaration(this: Parser, allowAssign: boolean) { + // TODO: TS garud + if (this.match(SyntaxKinds.LtOperator)) { + return this.parseTSTypeParameterDeclaration(allowAssign); + } +} +export function parseTSTypeParameterDeclaration( + this: Parser, + allowAssign: boolean, +): TSTypeParameterDeclaration { + const { start } = this.expect(SyntaxKinds.LtOperator); + const params = [this.parseTSTypeParameter()]; + while (this.match(SyntaxKinds.CommaToken)) { + this.nextToken(); + params.push(this.parseTSTypeParameter()); + } + this.parseGtTokenAsEndOfTypeParameters(allowAssign); + return Factory.createTSTypeParameterDeclaration(params, start, this.getLastTokenEndPositon()); +} +export function parseTSTypeParameter(this: Parser): TSTypeParameter { + const name = this.parseIdentifierReference(); + let constraint: TSTypeNode | undefined = undefined; + if (this.match(SyntaxKinds.ExtendsKeyword)) { + this.nextToken(); + constraint = this.parseTSTypeNode(); + } + let defaultType: TSTypeNode | undefined = undefined; + if (this.match(SyntaxKinds.AssginOperator)) { + this.nextToken(); + defaultType = this.parseTSTypeNode(); + } + return Factory.createTSTypeParameter( + constraint, + defaultType, + name, + cloneSourcePosition(name.start), + this.getLastTokenEndPositon(), + ); +} +export function tryParseTSTypeParameterInstantiation( + this: Parser, + allowAssign: boolean, +): TSTypeParameterInstantiation | undefined { + if (this.match(SyntaxKinds.LtOperator)) { + return this.parseTSTypeParameterInstantiation(allowAssign); + } + if (this.match(SyntaxKinds.BitwiseLeftShiftOperator)) { + this.lexer.reLexLtRelateToken(); + return this.parseTSTypeParameterInstantiation(allowAssign); + } +} +export function parseTSTypeParameterInstantiation( + this: Parser, + allowAssign: boolean, +): TSTypeParameterInstantiation { + const { start } = this.expect(SyntaxKinds.LtOperator); + const params = [this.parseTSTypeNode()]; + while (this.match(SyntaxKinds.CommaToken)) { + this.nextToken(); + params.push(this.parseTSTypeNode()); + } + this.parseGtTokenAsEndOfTypeParameters(allowAssign); + return Factory.createTSTypeParameterInstantiation(params, start, this.getLastTokenEndPositon()); +} +export function parseGtTokenAsEndOfTypeParameters(this: Parser, allowAssign: boolean) { + if ( + this.match([ + SyntaxKinds.GeqtOperator, + SyntaxKinds.BitwiseLeftShiftOperator, + SyntaxKinds.BitwiseLeftShiftAssginOperator, + SyntaxKinds.BitwiseRightShiftFillOperator, + SyntaxKinds.BitwiseRightShiftFillAssginOperator, + ]) + ) { + this.lexer.reLexGtRelateToken(allowAssign); + } + this.expect(SyntaxKinds.GtOperator); +} +export function parseTSTypeNode(this: Parser): TSTypeNode { + const checkType = this.parseTSNonConditionalType(); + if (!this.match(SyntaxKinds.ExtendsKeyword)) { + return checkType; + } + this.nextToken(); + const extendType = this.parseTSNonConditionalType(); + this.expect(SyntaxKinds.QustionOperator); + const trueType = this.parseTSTypeNode(); + this.expect(SyntaxKinds.ColonPunctuator); + const falseType = this.parseTSTypeNode(); + return Factory.createTSConditionType( + checkType, + extendType, + trueType, + falseType, + cloneSourcePosition(checkType.start), + this.getLastTokenEndPositon(), + ); +} +export function parseTSNonConditionalType(this: Parser): TSTypeNode { + if (this.isTSFunctionTypeStart()) { + return this.parseTSFunctionType(); + } + if (this.match(SyntaxKinds.NewKeyword)) { + const start = this.getStartPosition(); + this.nextToken(); + const { typeParameters, parameters, returnType } = this.parseTSFunctionSingnature( + SyntaxKinds.ArrowOperator, + false, + ); + return Factory.createTSConstrcutorType( + returnType, + parameters, + typeParameters, + start, + this.getLastTokenEndPositon(), + ); + } + if (this.isContextKeyword("abstract")) { + const start = this.getStartPosition(); + this.nextToken(); + this.expect(SyntaxKinds.NewKeyword); + const { typeParameters, parameters, returnType } = this.parseTSFunctionSingnature( + SyntaxKinds.ArrowOperator, + false, + ); + return Factory.createTSConstrcutorType( + returnType, + parameters, + typeParameters, + start, + this.getLastTokenEndPositon(), + ); + } + return this.parseTSUnionType(); +} +export function parseTSFunctionType(this: Parser): TSFunctionType { + const start = this.getStartPosition(); + const { parameters, returnType, typeParameters } = this.parseTSFunctionSingnature( + SyntaxKinds.ArrowOperator, + false, + ); + return Factory.createTSFunctionType( + returnType, + parameters, + typeParameters, + start, + this.getLastTokenEndPositon(), + ); +} +export function parseTSGenericArrowFunctionExpression(this: Parser): ArrorFunctionExpression | undefined { + const result = this.tryParse( + (): [ + TSTypeParameterDeclaration | undefined, + [ + ASTArrayWithMetaData & { + trailingComma: boolean; + typeAnnotations: Array<[TSTypeAnnotation | undefined, boolean]> | undefined; + }, + StrictModeScope, + AsyncArrowExpressionScope, + ], + TSTypeAnnotation | undefined, + ] => { + const typeParameters = this.tryParseTSTypeParameterDeclaration(false); + const [[meta, strictModeScope], arrowExprScope] = this.parseWithArrowExpressionScope(() => + this.parseWithCatpureLayer(() => this.parseArgumentsWithType()), + ); + meta.start = typeParameters?.start || meta.start; + const returnType = this.tryParseTSReturnTypeOrTypePredicate(SyntaxKinds.ColonPunctuator); + return [typeParameters, [meta, strictModeScope, arrowExprScope], returnType]; + }, + ); + if (!result) { + return; + } + const [[typeParameters, [meta, strictModeScope, arrowExprScope], returnType], state, context, index] = + result; + if (!this.match(SyntaxKinds.ArrowOperator)) { + this.abortTryParseResult(state, context, index); + return; + } + this.enterArrowFunctionBodyScope(); + const arrowExpr = this.parseArrowFunctionExpression(meta, typeParameters, strictModeScope, arrowExprScope); + this.exitArrowFunctionBodyScope(); + arrowExpr.returnType = returnType; + return arrowExpr; +} +export function isTSFunctionTypeStart(this: Parser) { + if (this.match(SyntaxKinds.LtOperator)) { + return true; + } + return this.match(SyntaxKinds.ParenthesesLeftPunctuator); +} + +export function parseTSUnionType(this: Parser): TSTypeNode { + if (this.match(SyntaxKinds.BitwiseANDOperator)) { + return this.parseTSIntersectionType(); + } + let leadingOperator = false; + const start: SourcePosition = this.getStartPosition(); + if (this.match(SyntaxKinds.BitwiseOROperator)) { + this.nextToken(); + leadingOperator = true; + } + const types: Array = [this.parseTSIntersectionType()]; + while (this.match(SyntaxKinds.BitwiseOROperator)) { + this.nextToken(); + types.push(this.parseTSIntersectionType()); + } + if (types.length === 1 && !leadingOperator) { + return types[0]; + } + return Factory.createTSUnionType(types, start, this.getLastTokenEndPositon()); +} +export function parseTSIntersectionType(this: Parser): TSTypeNode { + let leadingOperator = false; + const start: SourcePosition = this.getStartPosition(); + if (this.match(SyntaxKinds.BitwiseANDOperator)) { + this.nextToken(); + leadingOperator = true; + } + const types: Array = [this.parseTSTypeOperator()]; + while (this.match(SyntaxKinds.BitwiseANDOperator)) { + this.nextToken(); + types.push(this.parseTSTypeOperator()); + } + if (types.length === 1 && !leadingOperator) { + return types[0]; + } + return Factory.createTSUnionType(types, start, this.getLastTokenEndPositon()); +} +export function parseTSTypeOperator(this: Parser): TSTypeNode { + let operator: TSTypeOperator["operator"] | undefined = undefined; + let start: SourcePosition | undefined = undefined; + if (!this.getEscFlag()) { + const sourceValue = this.getSourceValue(); + switch (sourceValue) { + case "unique": { + operator = "unique"; + start = this.getStartPosition(); + this.nextToken(); + break; + } + case "keyof": { + operator = "keyof"; + start = this.getStartPosition(); + this.nextToken(); + break; + } + case "readonly": { + operator = "readonly"; + start = this.getStartPosition(); + this.nextToken(); + break; + } + } + } + if (operator && start) { + const typeNode = this.parseTSTypeOperator(); + return Factory.createTSTypeOperator(typeNode, operator, start, this.getLastTokenEndPositon()); + } + return this.parseTSArrayType(); +} +export function parseTSArrayType(this: Parser) { + let base = this.parseTSNonArrayType(); + while (this.match(SyntaxKinds.BracketLeftPunctuator)) { + this.nextToken(); + if (this.match(SyntaxKinds.BracketRightPunctuator)) { + this.nextToken(); + base = Factory.createTSArrayType(base, cloneSourcePosition(base.start), this.getLastTokenEndPositon()); + } else { + const indexedType = this.parseTSTypeNode(); + base = Factory.createTSIndexedAccessType( + indexedType, + base, + cloneSourcePosition(base.start), + this.getLastTokenEndPositon(), + ); + this.expect(SyntaxKinds.BracketRightPunctuator); + } + } + return base; +} +export function parseTSNonArrayType(this: Parser): TSTypeNode { + switch (this.getToken()) { + case SyntaxKinds.BracesLeftPunctuator: { + return this.parseTSTypeLiteral(); + } + case SyntaxKinds.BracketLeftPunctuator: { + return this.parseTSTupleType(); + } + case SyntaxKinds.TypeofKeyword: { + return this.parseTypeQuery(); + } + case SyntaxKinds.NullKeyword: + case SyntaxKinds.UndefinedKeyword: + case SyntaxKinds.TrueKeyword: + case SyntaxKinds.FalseKeyword: + case SyntaxKinds.DecimalLiteral: + case SyntaxKinds.DecimalBigIntegerLiteral: + case SyntaxKinds.NonOctalDecimalLiteral: + case SyntaxKinds.BinaryIntegerLiteral: + case SyntaxKinds.BinaryBigIntegerLiteral: + case SyntaxKinds.OctalIntegerLiteral: + case SyntaxKinds.OctalBigIntegerLiteral: + case SyntaxKinds.HexIntegerLiteral: + case SyntaxKinds.HexBigIntegerLiteral: + case SyntaxKinds.LegacyOctalIntegerLiteral: + case SyntaxKinds.StringLiteral: { + return this.parseTSLiteralType(); + } + case SyntaxKinds.VoidKeyword: { + return this.parseTSVoidKeyword(); + } + default: { + const currentValue = this.getSourceValue(); + switch (currentValue) { + case "string": { + return this.parseTSStringKeyword(); + } + case "number": { + return this.parseTSNunberKeyword(); + } + case "bigint": { + return this.parseTSBigIntKeyword(); + } + case "boolean": { + return this.parseTSBoolKeyword(); + } + case "null": { + return this.parseTSNullKeyword(); + } + case "undefined": { + return this.parseTSUndefiniedKeyword(); + } + case "symbol": { + return this.parseTSSymbolKeyword(); + } + case "any": { + return this.parseTSAnyKeyword(); + } + case "never": { + return this.parseTSNeverKeyword(); + } + case "unknown": { + return this.parseTSUnknownKeyword(); + } + default: { + return this.parseTSTypeReference(); + } + } + } + } +} +export function parseTSStringKeyword(this: Parser): TSStringKeyword { + const { start, end } = this.expect(SyntaxKinds.Identifier); + return Factory.createTSStringKeyword(start, end); +} +export function parseTSNunberKeyword(this: Parser): TSNumberKeyword { + const { start, end } = this.expect(SyntaxKinds.Identifier); + return Factory.createTSNumberKeyword(start, end); +} +export function parseTSBigIntKeyword(this: Parser): TSBigIntKeyword { + const { start, end } = this.expect(SyntaxKinds.Identifier); + return Factory.createTSBigintKeyword(start, end); +} +export function parseTSBoolKeyword(this: Parser): TSBooleanKeyword { + const { start, end } = this.expect(SyntaxKinds.Identifier); + return Factory.createTSBoolKeyword(start, end); +} +export function parseTSNullKeyword(this: Parser): TSNullKeyword { + const { start, end } = this.expect(SyntaxKinds.Identifier); + return Factory.createTSNullKeyword(start, end); +} +export function parseTSUndefiniedKeyword(this: Parser): TSUndefinedKeyword { + const { start, end } = this.expect(SyntaxKinds.Identifier); + return Factory.createTSUndefinedKeyword(start, end); +} +export function parseTSSymbolKeyword(this: Parser): TSSymbolKeyword { + const { start, end } = this.expect(SyntaxKinds.Identifier); + return Factory.createTSSymbolKeyword(start, end); +} +export function parseTSAnyKeyword(this: Parser): TSAnyKeyword { + const { start, end } = this.expect(SyntaxKinds.Identifier); + return Factory.createTSAnyKeyword(start, end); +} +export function parseTSNeverKeyword(this: Parser): TSUndefinedKeyword { + const { start, end } = this.expect(SyntaxKinds.Identifier); + return Factory.createTSNeverKeyword(start, end); +} +export function parseTSUnknownKeyword(this: Parser): TSUnknowKeyword { + const { start, end } = this.expect(SyntaxKinds.Identifier); + return Factory.createTSUnknowKeyword(start, end); +} +export function parseTSVoidKeyword(this: Parser): TSVoidKeyword { + const { start, end } = this.expect(SyntaxKinds.VoidKeyword); + return Factory.createTSVoidKeyword(start, end); +} +export function parseTypeQuery(this: Parser): TSTypeQuery { + const { start } = this.expect(SyntaxKinds.TypeofKeyword); + const exprName = this.parseTSEntityName(); + return Factory.createTSTypeQuery(exprName, start, this.getLastTokenEndPositon()); +} +export function parseTSTupleType(this: Parser): TSTupleType { + const { start } = this.expect(SyntaxKinds.BracketLeftPunctuator); + const elementTypes: Array = [this.parseTSTypeNode()]; + while (!this.match([SyntaxKinds.BracketRightPunctuator, SyntaxKinds.EOFToken])) { + this.expect(SyntaxKinds.CommaToken); + if (this.match([SyntaxKinds.BracketRightPunctuator, SyntaxKinds.EOFToken])) { + break; + } + elementTypes.push(this.parseTSTypeNode()); + } + this.expect(SyntaxKinds.BracketRightPunctuator); + return Factory.createTSTupleType(elementTypes, start, this.getLastTokenEndPositon()); +} +export function parseTSLiteralType(this: Parser): TSLiteralType { + const start = this.getStartPosition(); + const literal = this.parsePrimaryExpression(); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return Factory.createTSLiteralType(literal as unknown as any, start, this.getLastTokenEndPositon()); +} +/** + * Try parse type annotation, optional mark and default vakue + * for function param, parse pattern : + * ``` + * (`?`)? (`:` TypeNode )? (`=` expression)? + * ``` + * This function will create a assignment pattern if default + * value exist. + * @param {TSParameter} param + * @returns + */ +export function parseFunctionParamType(this: Parser, param: TSParameter, shouldParseDefaultValue: boolean) { + if (!this.requirePlugin(ParserPlugin.TypeScript)) return param; + const optional = this.tryParseOptionalTypeParam(); + const type = this.tryParseTypeAnnotation(); + param.typeAnnotation = type; + param.optional = optional; + if (this.match(SyntaxKinds.AssginOperator) && shouldParseDefaultValue) { + return this.parseDefaultValueForBindingElement(param); + } + return param; +} +/** + * First helper of parse possible type annotation for argument. parse + * expect pattern + * ``` + * (`?`)? (`:` TypeNode)? + * ``` + * return binary tuple, optional TypeAnnotation Node and is optional value. + * + * NOTE: This function only used to parse type of argument for possible arrow + * expression. + * + * @returns {[TSTypeAnnotation | undefined, boolean]} + */ +export function parsePossibleArugmentType(this: Parser): [TSTypeAnnotation | undefined, boolean] { + const optional = this.tryParseOptionalTypeParam(); + const type = this.tryParseTypeAnnotation(); + return [type, optional]; +} +/** + * Second helper for parse possible default value for type argument, expect + * parse pattern: + * ``` + * (`=` Expression)? + * ``` + * If assignment operator is exist, will create a assignment expression + * which wrap left expression as left value, so it gonna transform left + * expression into pattern. + * + * NOTE: This function only used to parse type of argument for possible arrow + * expression. + * + * @param {Expression} left + * @returns + */ +export function parsePossibleArugmentDefaultValue(this: Parser, left: Expression) { + if (this.match(SyntaxKinds.AssginOperator)) { + this.nextToken(); + const leftPat = this.exprToPattern(left, false); + const right = this.parseAssignmentExpressionInheritIn(); + return Factory.createAssignmentExpression( + leftPat, + right, + SyntaxKinds.AssginOperator, + cloneSourcePosition(left.start), + cloneSourcePosition(right.end), + ); + } + return left; +} +/** + * Util helper for parse qustion mark for function param type + * @returns + */ +export function tryParseOptionalTypeParam(this: Parser) { + let optional = false; + if (this.match(SyntaxKinds.QustionOperator)) { + optional = true; + this.nextToken(); + } + return optional; +} +export function parseTSTypeReference(this: Parser): TSTypeReference { + // TODO: TS garud + const typeName = this.parseTSEntityName(); + const typeArguments = this.tryParseTSTypeParameterInstantiation(false); + return Factory.createTSTypeReference( + typeName, + typeArguments, + cloneSourcePosition(typeName.start), + cloneSourcePosition(typeName.end), + ); +} +export function parseTSEntityName(this: Parser): TSEntityName { + let left: TSEntityName = this.parseIdentifierReference(); + while (this.match(SyntaxKinds.DotOperator)) { + this.nextToken(); + const right = this.parseIdentifierName(); + left = Factory.createTSQualifiedName( + left, + right, + cloneSourcePosition(left.start), + cloneSourcePosition(right.end), + ); + } + return left; +} +export function parseTSFunctionSingnature(this: Parser, expectToken: SyntaxKinds, optional: boolean) { + const typeParameters = this.tryParseTSTypeParameterDeclaration(false); + const parameters = this.parseInType(() => this.parseFunctionParam()) as TSParameter[]; + const matchToken = this.match(expectToken); + if (optional && !matchToken) { + return { + typeParameters, + parameters: parameters, + returnType: undefined, + }; + } + const returnType = this.parseTSReturnTypeOrTypePredicate(expectToken); + return { + parameters, + returnType, + typeParameters, + }; +} +/** + * try parse return type or type predicate, expect syntax is + * ``` + * TypeNode + * TypePredicate + * ``` + * @param {SyntaxKinds} expectToken + * @returns + */ +export function tryParseTSReturnTypeOrTypePredicate(this: Parser, expectToken: SyntaxKinds) { + if (!this.match(expectToken)) { + return; + } + return this.parseTSReturnTypeOrTypePredicate(expectToken); +} +export function parseTSReturnTypeOrTypePredicate( + this: Parser, + expectToken: SyntaxKinds, +): TSTypeAnnotation | undefined { + // parse type or type predication + const { start } = this.expect(expectToken); + const assertion = this.parseTSAssertionInReturnType(); + const typePredicatePrefix = this.parseTypePredicatePrefixInReturnType(); + if (!typePredicatePrefix) { + if (!assertion) { + // : type + const returnType = this.parseTypeAnnoationWithoutColon(start); + return returnType; + } + // : asserts type + const name = this.parseIdentifierReference(); + const typePredicate = Factory.createTSTypePredicate( + name, + true, + undefined, + start, + cloneSourcePosition(name.end), + ); + const returnType = Factory.createTSTypeAnnotation( + typePredicate, + cloneSourcePosition(typePredicate.start), + cloneSourcePosition(typePredicate.end), + ); + return returnType; + } + // : asserts type is otherType + const name = this.parseIdentifierReference(); + this.nextToken(); // eat `is` + const typeAnnotation = this.parseTypeAnnoationWithoutColon(this.getStartPosition()); + const typePredicate = Factory.createTSTypePredicate( + name, + assertion, + typeAnnotation, + start, + cloneSourcePosition(typeAnnotation.end), + ); + const returnType = Factory.createTSTypeAnnotation( + typePredicate, + cloneSourcePosition(typePredicate.start), + cloneSourcePosition(typePredicate.end), + ); + return returnType; +} +export function parseTSAssertionInReturnType(this: Parser): boolean { + if (this.isContextKeyword("asserts")) { + const { kind: lookaheadToken, value, lineTerminatorFlag } = this.lookahead(); + if ((lookaheadToken === SyntaxKinds.Identifier || value === "is") && !lineTerminatorFlag) { + this.nextToken(); + return true; + } + } + return false; +} +export function parseTypePredicatePrefixInReturnType(this: Parser) { + return this.match(SyntaxKinds.Identifier) && this.lookahead().value === "is"; +} +export function parseTSTypeLiteral(this: Parser): TSTypeLiteral { + const { start } = this.expect(SyntaxKinds.BracesLeftPunctuator); + const members: Array = []; + while (!this.match([SyntaxKinds.EOFToken, SyntaxKinds.BracesRightPunctuator])) { + members.push(this.parseTSTypeElment()); + this.parseTSInterTypeElement(); + } + const { end } = this.expect(SyntaxKinds.BracesRightPunctuator); + return { + kind: SyntaxKinds.TSTypeLiteral, + members, + start, + end, + }; +} +export function parseTSInterfaceBody(this: Parser) { + const { start } = this.expect(SyntaxKinds.BracesLeftPunctuator); + const members: Array = []; + while (!this.match([SyntaxKinds.EOFToken, SyntaxKinds.BracesRightPunctuator])) { + members.push(this.parseTSTypeElment()); + this.parseTSInterTypeElement(); + } + const { end } = this.expect(SyntaxKinds.BracesRightPunctuator); + return Factory.createTSInterfaceBody(members, start, end); +} +export function parseTSTypeElment(this: Parser): TSTypeElement { + switch (this.getToken()) { + case SyntaxKinds.ParenthesesLeftPunctuator: + case SyntaxKinds.LtOperator: { + // TSCallSignatureDeclaration + const start = this.getStartPosition(); + const { parameters, returnType, typeParameters } = this.parseTSFunctionSingnature( + SyntaxKinds.ColonPunctuator, + true, + ); + return Factory.createTSCallSignatureDeclaration( + parameters, + returnType, + typeParameters, + start, + this.getLastTokenEndPositon(), + ); + } + case SyntaxKinds.NewKeyword: { + // TSConstructSignatureDeclaration + const start = this.getStartPosition(); + this.nextToken(); + const { parameters, returnType, typeParameters } = this.parseTSFunctionSingnature( + SyntaxKinds.ColonPunctuator, + true, + ); + return Factory.createTSConstructSignatureDeclaration( + parameters, + returnType, + typeParameters, + start, + this.getLastTokenEndPositon(), + ); + } + default: { + // TSMethodSignature + // TSPropertySignature + const isComputedRef = { isComputed: false }; + const key = this.parsePropertyName(isComputedRef); + let optional = false; + if (this.match(SyntaxKinds.QustionOperator)) { + optional = true; + this.nextToken(); + } + if (this.match(SyntaxKinds.ParenthesesLeftPunctuator) || this.match(SyntaxKinds.LtOperator)) { + const { parameters, returnType, typeParameters } = this.parseTSFunctionSingnature( + SyntaxKinds.ColonPunctuator, + true, + ); + return Factory.createTSMethodSignature( + key, + isComputedRef.isComputed, + optional, + parameters, + returnType, + typeParameters, + cloneSourcePosition(key.start), + this.getLastTokenEndPositon(), + ); + } + const typeAnnotation = this.tryParseTypeAnnotation(); + return Factory.createTSPropertySignature( + key, + isComputedRef.isComputed, + optional, + typeAnnotation, + cloneSourcePosition(key.start), + this.getLastTokenEndPositon(), + ); + } + } +} +export function parseTSInterTypeElement(this: Parser) { + if (this.match([SyntaxKinds.SemiPunctuator, SyntaxKinds.CommaToken])) { + this.nextToken(); + return; + } + if (this.match(SyntaxKinds.BracesRightPunctuator)) { + return; + } + if (this.getLineTerminatorFlag()) { + return; + } + // TODO: should error +} +export function tryParseTypeAnnotation(this: Parser): TSTypeAnnotation | undefined { + if (this.match(SyntaxKinds.ColonPunctuator)) { + return this.parseTypeAnnoation(); + } + return undefined; +} +export function parseTypeAnnoation(this: Parser): TSTypeAnnotation { + const { start } = this.expect(SyntaxKinds.ColonPunctuator); + const typeNode = this.parseTSTypeNode(); + return Factory.createTSTypeAnnotation(typeNode, start, cloneSourcePosition(typeNode.end)); +} +export function parseTypeAnnoationWithoutColon(this: Parser, start: SourcePosition): TSTypeAnnotation { + const typeNode = this.parseTSTypeNode(); + return Factory.createTSTypeAnnotation(typeNode, start, cloneSourcePosition(typeNode.end)); +} diff --git a/web-infras/parser/src/parser/type.ts b/web-infras/parser/src/parser/type.ts index 3d9502e9..bf181f3a 100644 --- a/web-infras/parser/src/parser/type.ts +++ b/web-infras/parser/src/parser/type.ts @@ -1,141 +1,28 @@ -import { SourcePosition } from "web-infra-common"; +import { Keywords, LexicalLiteral, SourcePosition, SyntaxKinds } from "web-infra-common"; import { Token } from "../lexer/type"; export type ExpectToken = Omit & { start: SourcePosition; end: SourcePosition; }; -/** - * Function Scope structure, Being used for determinate - * current structure context for async, generator, in- - * parameter and in strict mode. - * @member {"FunctionContext"} type - type enum string. - * @member {boolean} isAsync - * @member {boolean} isGenerator - * @member {boolean} inParameter - * @member {boolean} inStrict - */ -export interface FunctionContext { - readonly type: "FunctionContext"; - readonly isArrow: boolean; - isAsync: boolean; - isGenerator: boolean; - inParameter: boolean; - isSimpleParameter: boolean; - inStrict: boolean; -} -/** - * Simple scope structure for block statement. - * @member {"BlockStatement"} type - type enum string. - */ -export interface BlockContext { - readonly type: "BlockContext"; -} -/** - * Scope structure for function body and block statement, - * just a conbinmation of function scope and block scope. - */ -export type ScopeContext = FunctionContext | BlockContext; -/** - * Inspirt by V8's ExpressionScope - */ -export enum ExpressionErrorKind { - YieldExpressionInParameter, - AwaitExpressionImParameter, - AwaitIdentifier, - - YieldIdentifier, - - LetIdentifiier, - EvalIdentifier, - ArgumentsIdentifier, -} - -type ArrowExpressionErrorScope = { - yieldExpressionInParameter: Array; - awaitExpressionInParameter: Array; - awaitIdentifier: Array; - yieldIdentifier: Array; -}; -export function createExpressionErrorRecorder() { - let arrowExpressionErrorScopesIndex = -1; - let arrowExpressionErrorScopes: Array = []; - - function enterArrowExpressionScope() { - arrowExpressionErrorScopesIndex++; - arrowExpressionErrorScopes.push({ - awaitExpressionInParameter: [], - yieldExpressionInParameter: [], - awaitIdentifier: [], - yieldIdentifier: [], - }); - } - - function enterBlankArrowExpressionScope() { - arrowExpressionErrorScopesIndex++; - arrowExpressionErrorScopes.push(null); - } - - function exitArrowExpressionScope() { - const currentIndex = arrowExpressionErrorScopesIndex; - const currentScope = arrowExpressionErrorScopes[currentIndex]; - arrowExpressionErrorScopesIndex--; - if (arrowExpressionErrorScopesIndex < 0) { - arrowExpressionErrorScopesIndex = 0; - arrowExpressionErrorScopes = []; - } - if (currentScope === null) { - arrowExpressionErrorScopes = arrowExpressionErrorScopes.slice(0, currentIndex); - } - } - - function record(kind: ExpressionErrorKind, position: SourcePosition) { - const scope = arrowExpressionErrorScopes[arrowExpressionErrorScopesIndex]; - if (!scope) { - return; - } - switch (kind) { - case ExpressionErrorKind.AwaitExpressionImParameter: { - scope.awaitExpressionInParameter.push(position); - break; - } - case ExpressionErrorKind.YieldExpressionInParameter: { - scope.yieldExpressionInParameter.push(position); - break; - } - case ExpressionErrorKind.AwaitIdentifier: { - scope.awaitIdentifier.push(position); - break; - } - case ExpressionErrorKind.YieldIdentifier: { - scope.yieldIdentifier.push(position); - break; - } - } - } - function isArrowExpressionScopeHaveError(scope: ArrowExpressionErrorScope) { - return ( - scope.awaitExpressionInParameter.length || - scope.yieldExpressionInParameter.length || - scope.awaitIdentifier.length - ); - } - function getCurrentArrowExpressionScope() { - for (let index = arrowExpressionErrorScopesIndex; index < arrowExpressionErrorScopes.length; ++index) { - const scope = arrowExpressionErrorScopes[index]; - if (scope && isArrowExpressionScopeHaveError(scope)) { - return true; - } - } - return false; - } - - return { - record, - enterArrowExpressionScope, - enterBlankArrowExpressionScope, - exitArrowExpressionScope, - getCurrentArrowExpressionScope, - }; +export const IdentiferWithKeyworArray = [SyntaxKinds.Identifier, ...Keywords]; +export const PreserveWordSet = new Set(LexicalLiteral.preserveword); +export const BindingIdentifierSyntaxKindArray = [ + SyntaxKinds.Identifier, + SyntaxKinds.AwaitKeyword, + SyntaxKinds.YieldKeyword, + SyntaxKinds.LetKeyword, +]; +export const KeywordSet = new Set([ + ...LexicalLiteral.keywords, + ...LexicalLiteral.BooleanLiteral, + ...LexicalLiteral.NullLiteral, + ...LexicalLiteral.UndefinbedLiteral, +]); + +export interface ASTArrayWithMetaData { + nodes: Array; + start: SourcePosition; + end: SourcePosition; } diff --git a/web-infras/parser/tests/fixtures/babel/comments/decorators/decorator-before-export/output.json b/web-infras/parser/tests/fixtures/babel/comments/decorators/decorator-before-export/output.json index ce59da84..e63fcd47 100644 --- a/web-infras/parser/tests/fixtures/babel/comments/decorators/decorator-before-export/output.json +++ b/web-infras/parser/tests/fixtures/babel/comments/decorators/decorator-before-export/output.json @@ -45,7 +45,62 @@ "col": 51, "index": 86 }, - "decorators": null + "decorators": [ + { + "kind": "Decorator", + "expression": { + "kind": "Identifer", + "name": "dec1", + "start": { + "row": 1, + "col": 10, + "index": 9 + }, + "end": { + "row": 1, + "col": 14, + "index": 13 + } + }, + "start": { + "row": 1, + "col": 9, + "index": 8 + }, + "end": { + "row": 1, + "col": 14, + "index": 13 + } + }, + { + "kind": "Decorator", + "expression": { + "kind": "Identifer", + "name": "dec2", + "start": { + "row": 1, + "col": 24, + "index": 23 + }, + "end": { + "row": 1, + "col": 28, + "index": 27 + } + }, + "start": { + "row": 1, + "col": 23, + "index": 22 + }, + "end": { + "row": 1, + "col": 28, + "index": 27 + } + } + ] }, "source": null, "start": { diff --git a/web-infras/parser/tests/fixtures/babel/comments/decorators/decorators-legacy-before-export/output.json b/web-infras/parser/tests/fixtures/babel/comments/decorators/decorators-legacy-before-export/output.json index ce59da84..e63fcd47 100644 --- a/web-infras/parser/tests/fixtures/babel/comments/decorators/decorators-legacy-before-export/output.json +++ b/web-infras/parser/tests/fixtures/babel/comments/decorators/decorators-legacy-before-export/output.json @@ -45,7 +45,62 @@ "col": 51, "index": 86 }, - "decorators": null + "decorators": [ + { + "kind": "Decorator", + "expression": { + "kind": "Identifer", + "name": "dec1", + "start": { + "row": 1, + "col": 10, + "index": 9 + }, + "end": { + "row": 1, + "col": 14, + "index": 13 + } + }, + "start": { + "row": 1, + "col": 9, + "index": 8 + }, + "end": { + "row": 1, + "col": 14, + "index": 13 + } + }, + { + "kind": "Decorator", + "expression": { + "kind": "Identifer", + "name": "dec2", + "start": { + "row": 1, + "col": 24, + "index": 23 + }, + "end": { + "row": 1, + "col": 28, + "index": 27 + } + }, + "start": { + "row": 1, + "col": 23, + "index": 22 + }, + "end": { + "row": 1, + "col": 28, + "index": 27 + } + } + ] }, "source": null, "start": { diff --git a/web-infras/parser/tests/fixtures/babel/core/escape-string/invalid-decimal-escape-strict-directive-function/output.txt b/web-infras/parser/tests/fixtures/babel/core/escape-string/invalid-decimal-escape-strict-directive-function/output.txt index cdb93d76..6fbd93c4 100644 --- a/web-infras/parser/tests/fixtures/babel/core/escape-string/invalid-decimal-escape-strict-directive-function/output.txt +++ b/web-infras/parser/tests/fixtures/babel/core/escape-string/invalid-decimal-escape-strict-directive-function/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Octal escape sequences are not allowed in strict mode., start position is (14, 3) \ No newline at end of file +[Error]: Lexical Error, Octal escape sequences are not allowed in strict mode., start position is (14, 3) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/core/escape-string/non-octal-eight-and-nine-before-use-strict/output.txt b/web-infras/parser/tests/fixtures/babel/core/escape-string/non-octal-eight-and-nine-before-use-strict/output.txt index 772bd047..de668a06 100644 --- a/web-infras/parser/tests/fixtures/babel/core/escape-string/non-octal-eight-and-nine-before-use-strict/output.txt +++ b/web-infras/parser/tests/fixtures/babel/core/escape-string/non-octal-eight-and-nine-before-use-strict/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Octal escape sequences are not allowed in strict mode., start position is (4, 3) \ No newline at end of file +[Error]: Lexical Error, Octal escape sequences are not allowed in strict mode., start position is (4, 3) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/core/escape-string/non-octal-eight-and-nine/output.txt b/web-infras/parser/tests/fixtures/babel/core/escape-string/non-octal-eight-and-nine/output.txt index 772bd047..de668a06 100644 --- a/web-infras/parser/tests/fixtures/babel/core/escape-string/non-octal-eight-and-nine/output.txt +++ b/web-infras/parser/tests/fixtures/babel/core/escape-string/non-octal-eight-and-nine/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Octal escape sequences are not allowed in strict mode., start position is (4, 3) \ No newline at end of file +[Error]: Lexical Error, Octal escape sequences are not allowed in strict mode., start position is (4, 3) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/core/escape-string/numeric-escape-in-directive/output.txt b/web-infras/parser/tests/fixtures/babel/core/escape-string/numeric-escape-in-directive/output.txt index 42364c6d..ad1c55b0 100644 --- a/web-infras/parser/tests/fixtures/babel/core/escape-string/numeric-escape-in-directive/output.txt +++ b/web-infras/parser/tests/fixtures/babel/core/escape-string/numeric-escape-in-directive/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Octal escape sequences are not allowed in strict mode., start position is (1, 53) \ No newline at end of file +[Error]: Lexical Error, Octal escape sequences are not allowed in strict mode., start position is (1, 53) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/core/escape-string/numeric-escape-in-property-name/output.txt b/web-infras/parser/tests/fixtures/babel/core/escape-string/numeric-escape-in-property-name/output.txt index 86a3fa78..ba24a98e 100644 --- a/web-infras/parser/tests/fixtures/babel/core/escape-string/numeric-escape-in-property-name/output.txt +++ b/web-infras/parser/tests/fixtures/babel/core/escape-string/numeric-escape-in-property-name/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Octal escape sequences are not allowed in strict mode., start position is (1, 37) \ No newline at end of file +[Error]: Lexical Error, Octal escape sequences are not allowed in strict mode., start position is (1, 37) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/core/uncategorised/348/output.txt b/web-infras/parser/tests/fixtures/babel/core/uncategorised/348/output.txt index 13e05fd4..7386e1b4 100644 --- a/web-infras/parser/tests/fixtures/babel/core/uncategorised/348/output.txt +++ b/web-infras/parser/tests/fixtures/babel/core/uncategorised/348/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Identifier directly after number., start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Identifier directly after number., start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/core/uncategorised/352/output.txt b/web-infras/parser/tests/fixtures/babel/core/uncategorised/352/output.txt index 13e05fd4..7386e1b4 100644 --- a/web-infras/parser/tests/fixtures/babel/core/uncategorised/352/output.txt +++ b/web-infras/parser/tests/fixtures/babel/core/uncategorised/352/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Identifier directly after number., start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Identifier directly after number., start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/core/uncategorised/353/output.txt b/web-infras/parser/tests/fixtures/babel/core/uncategorised/353/output.txt index 13e05fd4..7386e1b4 100644 --- a/web-infras/parser/tests/fixtures/babel/core/uncategorised/353/output.txt +++ b/web-infras/parser/tests/fixtures/babel/core/uncategorised/353/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Identifier directly after number., start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Identifier directly after number., start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/core/uncategorised/357/output.txt b/web-infras/parser/tests/fixtures/babel/core/uncategorised/357/output.txt index 13e05fd4..7386e1b4 100644 --- a/web-infras/parser/tests/fixtures/babel/core/uncategorised/357/output.txt +++ b/web-infras/parser/tests/fixtures/babel/core/uncategorised/357/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Identifier directly after number., start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Identifier directly after number., start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/core/uncategorised/358/output.txt b/web-infras/parser/tests/fixtures/babel/core/uncategorised/358/output.txt index 13e05fd4..7386e1b4 100644 --- a/web-infras/parser/tests/fixtures/babel/core/uncategorised/358/output.txt +++ b/web-infras/parser/tests/fixtures/babel/core/uncategorised/358/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Identifier directly after number., start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Identifier directly after number., start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/core/uncategorised/359/output.txt b/web-infras/parser/tests/fixtures/babel/core/uncategorised/359/output.txt index 13e05fd4..7386e1b4 100644 --- a/web-infras/parser/tests/fixtures/babel/core/uncategorised/359/output.txt +++ b/web-infras/parser/tests/fixtures/babel/core/uncategorised/359/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Identifier directly after number., start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Identifier directly after number., start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/core/uncategorised/362/output.txt b/web-infras/parser/tests/fixtures/babel/core/uncategorised/362/output.txt index e2f4f280..75d14345 100644 --- a/web-infras/parser/tests/fixtures/babel/core/uncategorised/362/output.txt +++ b/web-infras/parser/tests/fixtures/babel/core/uncategorised/362/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/core/uncategorised/363/output.txt b/web-infras/parser/tests/fixtures/babel/core/uncategorised/363/output.txt index e2f4f280..75d14345 100644 --- a/web-infras/parser/tests/fixtures/babel/core/uncategorised/363/output.txt +++ b/web-infras/parser/tests/fixtures/babel/core/uncategorised/363/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/core/uncategorised/366/output.txt b/web-infras/parser/tests/fixtures/babel/core/uncategorised/366/output.txt index 03a39685..61d368a9 100644 --- a/web-infras/parser/tests/fixtures/babel/core/uncategorised/366/output.txt +++ b/web-infras/parser/tests/fixtures/babel/core/uncategorised/366/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid Unicode escape sequence, start position is (1, 16) \ No newline at end of file +[Error]: Lexical Error, Invalid Unicode escape sequence, start position is (1, 16) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/core/uncategorised/380/output.txt b/web-infras/parser/tests/fixtures/babel/core/uncategorised/380/output.txt index 0caa1df6..dd336af2 100644 --- a/web-infras/parser/tests/fixtures/babel/core/uncategorised/380/output.txt +++ b/web-infras/parser/tests/fixtures/babel/core/uncategorised/380/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid regular expression flags, start position is (1, 9) \ No newline at end of file +[Error]: Lexical Error, Invalid regular expression flags, start position is (1, 9) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/core/uncategorised/426/output.txt b/web-infras/parser/tests/fixtures/babel/core/uncategorised/426/output.txt index e2f4f280..75d14345 100644 --- a/web-infras/parser/tests/fixtures/babel/core/uncategorised/426/output.txt +++ b/web-infras/parser/tests/fixtures/babel/core/uncategorised/426/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/core/uncategorised/441/output.txt b/web-infras/parser/tests/fixtures/babel/core/uncategorised/441/output.txt index ab34e45a..d587117e 100644 --- a/web-infras/parser/tests/fixtures/babel/core/uncategorised/441/output.txt +++ b/web-infras/parser/tests/fixtures/babel/core/uncategorised/441/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid regular expression flags, start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Invalid regular expression flags, start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/core/uncategorised/446/output.txt b/web-infras/parser/tests/fixtures/babel/core/uncategorised/446/output.txt index e2f4f280..75d14345 100644 --- a/web-infras/parser/tests/fixtures/babel/core/uncategorised/446/output.txt +++ b/web-infras/parser/tests/fixtures/babel/core/uncategorised/446/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/core/uncategorised/447/output.txt b/web-infras/parser/tests/fixtures/babel/core/uncategorised/447/output.txt index e2f4f280..75d14345 100644 --- a/web-infras/parser/tests/fixtures/babel/core/uncategorised/447/output.txt +++ b/web-infras/parser/tests/fixtures/babel/core/uncategorised/447/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/core/uncategorised/448/output.txt b/web-infras/parser/tests/fixtures/babel/core/uncategorised/448/output.txt index e2f4f280..75d14345 100644 --- a/web-infras/parser/tests/fixtures/babel/core/uncategorised/448/output.txt +++ b/web-infras/parser/tests/fixtures/babel/core/uncategorised/448/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/core/uncategorised/449/output.txt b/web-infras/parser/tests/fixtures/babel/core/uncategorised/449/output.txt index e2f4f280..75d14345 100644 --- a/web-infras/parser/tests/fixtures/babel/core/uncategorised/449/output.txt +++ b/web-infras/parser/tests/fixtures/babel/core/uncategorised/449/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/core/uncategorised/450/output.txt b/web-infras/parser/tests/fixtures/babel/core/uncategorised/450/output.txt index e2f4f280..75d14345 100644 --- a/web-infras/parser/tests/fixtures/babel/core/uncategorised/450/output.txt +++ b/web-infras/parser/tests/fixtures/babel/core/uncategorised/450/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/core/uncategorised/451/output.txt b/web-infras/parser/tests/fixtures/babel/core/uncategorised/451/output.txt index e2f4f280..75d14345 100644 --- a/web-infras/parser/tests/fixtures/babel/core/uncategorised/451/output.txt +++ b/web-infras/parser/tests/fixtures/babel/core/uncategorised/451/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/core/uncategorised/453/output.txt b/web-infras/parser/tests/fixtures/babel/core/uncategorised/453/output.txt index e2f4f280..75d14345 100644 --- a/web-infras/parser/tests/fixtures/babel/core/uncategorised/453/output.txt +++ b/web-infras/parser/tests/fixtures/babel/core/uncategorised/453/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2015/regex/duplicate-flags/output.txt b/web-infras/parser/tests/fixtures/babel/es2015/regex/duplicate-flags/output.txt index ab34e45a..d587117e 100644 --- a/web-infras/parser/tests/fixtures/babel/es2015/regex/duplicate-flags/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2015/regex/duplicate-flags/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid regular expression flags, start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Invalid regular expression flags, start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/199/output.txt b/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/199/output.txt index 13e05fd4..7386e1b4 100644 --- a/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/199/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/199/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Identifier directly after number., start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Identifier directly after number., start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/203/output.txt b/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/203/output.txt index 13e05fd4..7386e1b4 100644 --- a/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/203/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/203/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Identifier directly after number., start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Identifier directly after number., start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/207/output.txt b/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/207/output.txt index 13e05fd4..7386e1b4 100644 --- a/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/207/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/207/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Identifier directly after number., start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Identifier directly after number., start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/212/output.txt b/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/212/output.txt index 13e05fd4..7386e1b4 100644 --- a/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/212/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/212/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Identifier directly after number., start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Identifier directly after number., start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/218/output.txt b/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/218/output.txt index e2f4f280..75d14345 100644 --- a/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/218/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/218/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/219/output.txt b/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/219/output.txt index e2f4f280..75d14345 100644 --- a/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/219/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/219/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/268/output.txt b/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/268/output.txt index 8f246886..5b9ff1ba 100644 --- a/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/268/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/268/output.txt @@ -1 +1,3 @@ -[Syntax Error]: Unexpect token DecimalLiteral(1, 14). \ No newline at end of file +[SyntaxError]: Missing semicolon or line terminator. (1,14) +1|function a() 1 // expression closure is not supported + | ^ diff --git a/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/326/output.txt b/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/326/output.txt index 606c1ee4..8094748f 100644 --- a/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/326/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/326/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid Unicode escape sequence, start position is (1, 6) \ No newline at end of file +[Error]: Lexical Error, Invalid Unicode escape sequence, start position is (1, 6) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/327/output.txt b/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/327/output.txt index 09b04508..0100d24f 100644 --- a/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/327/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/327/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid Unicode escape sequence, start position is (1, 5) \ No newline at end of file +[Error]: Lexical Error, Invalid Unicode escape sequence, start position is (1, 5) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/368/output.txt b/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/368/output.txt index f00b1369..977f0f09 100644 --- a/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/368/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/368/output.txt @@ -1 +1 @@ -[Syntax Error]: Unexpect token enum(1, 1). \ No newline at end of file +[Syntax Error]: Unexpect token =(1, 6). \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/369/output.txt b/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/369/output.txt index f00b1369..977f0f09 100644 --- a/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/369/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/369/output.txt @@ -1 +1 @@ -[Syntax Error]: Unexpect token enum(1, 1). \ No newline at end of file +[Syntax Error]: Unexpect token =(1, 6). \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/388/output.txt b/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/388/output.txt index 022f7b98..d9eeebde 100644 --- a/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/388/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2015/uncategorised/388/output.txt @@ -1 +1,6 @@ -Cannot read properties of null (reading 'name') \ No newline at end of file +[SyntaxError]: 'import' and 'export' may appear only with 'sourceType: "module"' (1,1) +1|export function() {}; + |^ +[SyntaxError]: function statement requires a name (1,16) +1|export function() {}; + | ^ diff --git a/web-infras/parser/tests/fixtures/babel/es2017/async-functions/export-async/output.txt b/web-infras/parser/tests/fixtures/babel/es2017/async-functions/export-async/output.txt index 52e7a74e..d10bc2e4 100644 --- a/web-infras/parser/tests/fixtures/babel/es2017/async-functions/export-async/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2017/async-functions/export-async/output.txt @@ -1 +1 @@ -[Syntax Error]: Unexpect token ;(1, 13). \ No newline at end of file +[Syntax Error]: Unexpect token Identifer(1, 8). \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2017/async-functions/export/input.js b/web-infras/parser/tests/fixtures/babel/es2017/async-functions/export/input.js index 3f043e61..120136ec 100644 --- a/web-infras/parser/tests/fixtures/babel/es2017/async-functions/export/input.js +++ b/web-infras/parser/tests/fixtures/babel/es2017/async-functions/export/input.js @@ -1,2 +1,2 @@ export async function foo() {} -export default async function bar() {} +export default function bar() {} diff --git a/web-infras/parser/tests/fixtures/babel/es2017/async-functions/export/output.json b/web-infras/parser/tests/fixtures/babel/es2017/async-functions/export/output.json index d5a30cf7..189d49c3 100644 --- a/web-infras/parser/tests/fixtures/babel/es2017/async-functions/export/output.json +++ b/web-infras/parser/tests/fixtures/babel/es2017/async-functions/export/output.json @@ -69,41 +69,41 @@ "name": "bar", "start": { "row": 2, - "col": 31, - "index": 61 + "col": 25, + "index": 55 }, "end": { "row": 2, - "col": 34, - "index": 64 + "col": 28, + "index": 58 } }, "generator": false, - "async": true, + "async": false, "body": { "kind": "FunctionBody", "body": [], "start": { "row": 2, - "col": 37, - "index": 67 + "col": 31, + "index": 61 }, "end": { "row": 2, - "col": 39, - "index": 69 + "col": 33, + "index": 63 } }, "params": [], "start": { "row": 2, - "col": 22, - "index": 52 + "col": 16, + "index": 46 }, "end": { "row": 2, - "col": 39, - "index": 69 + "col": 33, + "index": 63 } }, "start": { @@ -113,8 +113,8 @@ }, "end": { "row": 2, - "col": 39, - "index": 69 + "col": 33, + "index": 63 } } ], @@ -126,6 +126,6 @@ "end": { "row": 3, "col": 1, - "index": 70 + "index": 64 } } \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2017/async-functions/invalid-escape-export-async-function/output.txt b/web-infras/parser/tests/fixtures/babel/es2017/async-functions/invalid-escape-export-async-function/output.txt index 2d7fbb0a..d10bc2e4 100644 --- a/web-infras/parser/tests/fixtures/babel/es2017/async-functions/invalid-escape-export-async-function/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2017/async-functions/invalid-escape-export-async-function/output.txt @@ -1 +1 @@ -[Unreach Zone]: this piece of code should not be reach (1, 8), have a unexpect token 10130 (async)., please report to developer. \ No newline at end of file +[Syntax Error]: Unexpect token Identifer(1, 8). \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2017/async-functions/invalid-escape-sequence-function/output.txt b/web-infras/parser/tests/fixtures/babel/es2017/async-functions/invalid-escape-sequence-function/output.txt index 022f7b98..aca74b46 100644 --- a/web-infras/parser/tests/fixtures/babel/es2017/async-functions/invalid-escape-sequence-function/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2017/async-functions/invalid-escape-sequence-function/output.txt @@ -1 +1,9 @@ -Cannot read properties of null (reading 'name') \ No newline at end of file +[SyntaxError]: Missing semicolon or line terminator. (1,12) +1|\u0061sync function() { await x } + | ^ +[SyntaxError]: function statement requires a name (1,20) +1|\u0061sync function() { await x } + | ^ +[SyntaxError]: Missing semicolon or line terminator. (1,31) +1|\u0061sync function() { await x } + | ^ diff --git a/web-infras/parser/tests/fixtures/babel/es2020/bigint/invalid-decimal/output.txt b/web-infras/parser/tests/fixtures/babel/es2020/bigint/invalid-decimal/output.txt index cfdb7ff1..6c3626fa 100644 --- a/web-infras/parser/tests/fixtures/babel/es2020/bigint/invalid-decimal/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2020/bigint/invalid-decimal/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid hexadecimal escape sequence, start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Invalid hexadecimal escape sequence, start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2020/bigint/invalid-e/output.txt b/web-infras/parser/tests/fixtures/babel/es2020/bigint/invalid-e/output.txt index cfdb7ff1..6c3626fa 100644 --- a/web-infras/parser/tests/fixtures/babel/es2020/bigint/invalid-e/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2020/bigint/invalid-e/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid hexadecimal escape sequence, start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Invalid hexadecimal escape sequence, start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2020/bigint/invalid-non-octal-decimal-int/output.txt b/web-infras/parser/tests/fixtures/babel/es2020/bigint/invalid-non-octal-decimal-int/output.txt index 13e05fd4..7386e1b4 100644 --- a/web-infras/parser/tests/fixtures/babel/es2020/bigint/invalid-non-octal-decimal-int/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2020/bigint/invalid-non-octal-decimal-int/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Identifier directly after number., start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Identifier directly after number., start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2020/bigint/invalid-octal-legacy/output.txt b/web-infras/parser/tests/fixtures/babel/es2020/bigint/invalid-octal-legacy/output.txt index 13e05fd4..7386e1b4 100644 --- a/web-infras/parser/tests/fixtures/babel/es2020/bigint/invalid-octal-legacy/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2020/bigint/invalid-octal-legacy/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Identifier directly after number., start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Identifier directly after number., start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2020/optional-chaining/new-ts-createParenthesizedExpressions-false/output.txt b/web-infras/parser/tests/fixtures/babel/es2020/optional-chaining/new-ts-createParenthesizedExpressions-false/output.txt new file mode 100644 index 00000000..5703efd2 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/es2020/optional-chaining/new-ts-createParenthesizedExpressions-false/output.txt @@ -0,0 +1 @@ +[Syntax Error]: Unexpect token ((2, 14). \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2020/optional-chaining/new-ts-createParenthesizedExpressions-true copy/output.txt b/web-infras/parser/tests/fixtures/babel/es2020/optional-chaining/new-ts-createParenthesizedExpressions-true copy/output.txt new file mode 100644 index 00000000..5703efd2 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/es2020/optional-chaining/new-ts-createParenthesizedExpressions-true copy/output.txt @@ -0,0 +1 @@ +[Syntax Error]: Unexpect token ((2, 14). \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-hex/output.txt b/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-hex/output.txt index cfdb7ff1..6c3626fa 100644 --- a/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-hex/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-hex/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid hexadecimal escape sequence, start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Invalid hexadecimal escape sequence, start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-leading-zero/output.txt b/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-leading-zero/output.txt index 13e05fd4..7386e1b4 100644 --- a/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-leading-zero/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-leading-zero/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Identifier directly after number., start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Identifier directly after number., start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-non-octal-decimal-int/output.txt b/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-non-octal-decimal-int/output.txt index 13e05fd4..7386e1b4 100644 --- a/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-non-octal-decimal-int/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-non-octal-decimal-int/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Identifier directly after number., start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Identifier directly after number., start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-unicode-2/output.txt b/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-unicode-2/output.txt index e2f4f280..75d14345 100644 --- a/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-unicode-2/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-unicode-2/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-unicode-3/output.txt b/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-unicode-3/output.txt index e2f4f280..75d14345 100644 --- a/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-unicode-3/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-unicode-3/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-unicode-4/output.txt b/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-unicode-4/output.txt index e2f4f280..75d14345 100644 --- a/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-unicode-4/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-unicode-4/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-unicode-5/output.txt b/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-unicode-5/output.txt index e2f4f280..75d14345 100644 --- a/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-unicode-5/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-unicode-5/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-unicode-6/output.txt b/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-unicode-6/output.txt index e2f4f280..75d14345 100644 --- a/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-unicode-6/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-unicode-6/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-unicode-7/output.txt b/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-unicode-7/output.txt index e2f4f280..75d14345 100644 --- a/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-unicode-7/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-unicode-7/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-unicode/output.txt b/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-unicode/output.txt index e2f4f280..75d14345 100644 --- a/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-unicode/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2021/numeric-separator/invalid-unicode/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2022/class-private-methods/failure-spaces/output.txt b/web-infras/parser/tests/fixtures/babel/es2022/class-private-methods/failure-spaces/output.txt index 1b9692a6..69669fcf 100644 --- a/web-infras/parser/tests/fixtures/babel/es2022/class-private-methods/failure-spaces/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2022/class-private-methods/failure-spaces/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid Unicode escape sequence, start position is (2, 3) \ No newline at end of file +[Error]: Lexical Error, Invalid Unicode escape sequence, start position is (2, 3) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2022/class-private-properties/failure-computed/output.txt b/web-infras/parser/tests/fixtures/babel/es2022/class-private-properties/failure-computed/output.txt index f240bab2..7c29b1f7 100644 --- a/web-infras/parser/tests/fixtures/babel/es2022/class-private-properties/failure-computed/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2022/class-private-properties/failure-computed/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid Unicode escape sequence, start position is (3, 3) \ No newline at end of file +[Error]: Lexical Error, Invalid Unicode escape sequence, start position is (3, 3) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2022/class-private-properties/failure-numeric-literal/output.txt b/web-infras/parser/tests/fixtures/babel/es2022/class-private-properties/failure-numeric-literal/output.txt index 1b9692a6..69669fcf 100644 --- a/web-infras/parser/tests/fixtures/babel/es2022/class-private-properties/failure-numeric-literal/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2022/class-private-properties/failure-numeric-literal/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid Unicode escape sequence, start position is (2, 3) \ No newline at end of file +[Error]: Lexical Error, Invalid Unicode escape sequence, start position is (2, 3) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2022/class-private-properties/failure-numeric-start-identifier/output.txt b/web-infras/parser/tests/fixtures/babel/es2022/class-private-properties/failure-numeric-start-identifier/output.txt index 1b9692a6..69669fcf 100644 --- a/web-infras/parser/tests/fixtures/babel/es2022/class-private-properties/failure-numeric-start-identifier/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2022/class-private-properties/failure-numeric-start-identifier/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid Unicode escape sequence, start position is (2, 3) \ No newline at end of file +[Error]: Lexical Error, Invalid Unicode escape sequence, start position is (2, 3) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2022/class-private-properties/failure-spaces/output.txt b/web-infras/parser/tests/fixtures/babel/es2022/class-private-properties/failure-spaces/output.txt index 1b9692a6..69669fcf 100644 --- a/web-infras/parser/tests/fixtures/babel/es2022/class-private-properties/failure-spaces/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2022/class-private-properties/failure-spaces/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid Unicode escape sequence, start position is (2, 3) \ No newline at end of file +[Error]: Lexical Error, Invalid Unicode escape sequence, start position is (2, 3) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2022/class-private-properties/failure-string-literal/output.txt b/web-infras/parser/tests/fixtures/babel/es2022/class-private-properties/failure-string-literal/output.txt index 1b9692a6..69669fcf 100644 --- a/web-infras/parser/tests/fixtures/babel/es2022/class-private-properties/failure-string-literal/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2022/class-private-properties/failure-string-literal/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid Unicode escape sequence, start position is (2, 3) \ No newline at end of file +[Error]: Lexical Error, Invalid Unicode escape sequence, start position is (2, 3) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2022/class-private-properties/invalid-ts-type-literal/output.txt b/web-infras/parser/tests/fixtures/babel/es2022/class-private-properties/invalid-ts-type-literal/output.txt index b4b851c2..279e44e4 100644 --- a/web-infras/parser/tests/fixtures/babel/es2022/class-private-properties/invalid-ts-type-literal/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2022/class-private-properties/invalid-ts-type-literal/output.txt @@ -1 +1 @@ -[Syntax Error]: Unexpect token :(2, 5). \ No newline at end of file +[Syntax Error]: Unexpect token PrivateName(2, 3). \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2024/regexp-unicode-sets/uv-error/output.txt b/web-infras/parser/tests/fixtures/babel/es2024/regexp-unicode-sets/uv-error/output.txt index ab34e45a..d587117e 100644 --- a/web-infras/parser/tests/fixtures/babel/es2024/regexp-unicode-sets/uv-error/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2024/regexp-unicode-sets/uv-error/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid regular expression flags, start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Invalid regular expression flags, start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/es2024/regexp-unicode-sets/vu-error/output.txt b/web-infras/parser/tests/fixtures/babel/es2024/regexp-unicode-sets/vu-error/output.txt index ab34e45a..d587117e 100644 --- a/web-infras/parser/tests/fixtures/babel/es2024/regexp-unicode-sets/vu-error/output.txt +++ b/web-infras/parser/tests/fixtures/babel/es2024/regexp-unicode-sets/vu-error/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid regular expression flags, start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Invalid regular expression flags, start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/estree/export/decorator-before-export/output.json b/web-infras/parser/tests/fixtures/babel/estree/export/decorator-before-export/output.json index f1ed96b6..06fcbce5 100644 --- a/web-infras/parser/tests/fixtures/babel/estree/export/decorator-before-export/output.json +++ b/web-infras/parser/tests/fixtures/babel/estree/export/decorator-before-export/output.json @@ -45,7 +45,35 @@ "col": 23, "index": 22 }, - "decorators": null + "decorators": [ + { + "kind": "Decorator", + "expression": { + "kind": "Identifer", + "name": "dec", + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 5, + "index": 4 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 5, + "index": 4 + } + } + ] }, "source": null, "start": { diff --git a/web-infras/parser/tests/fixtures/babel/jsx/errors/_no-plugin-fragment/output.txt b/web-infras/parser/tests/fixtures/babel/jsx/errors/_no-plugin-fragment/output.txt index 15aa789a..de10bcb3 100644 --- a/web-infras/parser/tests/fixtures/babel/jsx/errors/_no-plugin-fragment/output.txt +++ b/web-infras/parser/tests/fixtures/babel/jsx/errors/_no-plugin-fragment/output.txt @@ -1,3 +1 @@ -[SyntaxError]: This experimental syntax requires enabling jsx plugins. (3,5) -3| <>Hello - | ^ +[Syntax Error]: Unexpect token >(3, 6). \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/jsx/errors/_no-plugin-jsx-expression/output.txt b/web-infras/parser/tests/fixtures/babel/jsx/errors/_no-plugin-jsx-expression/output.txt index ad61d5fe..59476430 100644 --- a/web-infras/parser/tests/fixtures/babel/jsx/errors/_no-plugin-jsx-expression/output.txt +++ b/web-infras/parser/tests/fixtures/babel/jsx/errors/_no-plugin-jsx-expression/output.txt @@ -1,3 +1 @@ -[SyntaxError]: This experimental syntax requires enabling jsx plugins. (1,1) -1|
{name}
- |^ +[Syntax Error]: Unexpect token JSXClosedTagStart(1, 12). \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/jsx/errors/_no_plugin-non-BMP-identifier/output.txt b/web-infras/parser/tests/fixtures/babel/jsx/errors/_no_plugin-non-BMP-identifier/output.txt index 3f625f72..c7110acc 100644 --- a/web-infras/parser/tests/fixtures/babel/jsx/errors/_no_plugin-non-BMP-identifier/output.txt +++ b/web-infras/parser/tests/fixtures/babel/jsx/errors/_no_plugin-non-BMP-identifier/output.txt @@ -1,3 +1 @@ -[SyntaxError]: This experimental syntax requires enabling jsx plugins. (1,1) -1|< - |^ +[Syntax Error]: Unexpect token JSXClosedTagStart(3, 2). \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/jsx/errors/_no_plugin/output.txt b/web-infras/parser/tests/fixtures/babel/jsx/errors/_no_plugin/output.txt index 07fa8bcc..4ca34740 100644 --- a/web-infras/parser/tests/fixtures/babel/jsx/errors/_no_plugin/output.txt +++ b/web-infras/parser/tests/fixtures/babel/jsx/errors/_no_plugin/output.txt @@ -1,3 +1 @@ -[SyntaxError]: This experimental syntax requires enabling jsx plugins. (1,1) -1|
- |^ +[Syntax Error]: Unexpect token JSXClosedTagStart(1, 6). \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/annotated/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/annotated/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/annotated/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/annotated/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/annotated/input.ts new file mode 100644 index 00000000..ae22bd8d --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/annotated/input.ts @@ -0,0 +1 @@ +(x: number): number => x; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/annotated/output.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/annotated/output.json new file mode 100644 index 00000000..e50d4e71 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/annotated/output.json @@ -0,0 +1,126 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "ArrowFunctionExpression", + "expressionBody": true, + "async": false, + "arguments": [ + { + "kind": "Identifer", + "name": "x", + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 1, + "col": 5, + "index": 4 + }, + "end": { + "row": 1, + "col": 11, + "index": 10 + } + }, + "start": { + "row": 1, + "col": 3, + "index": 2 + }, + "end": { + "row": 1, + "col": 11, + "index": 10 + } + }, + "optional": false, + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 3, + "index": 2 + } + } + ], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 1, + "col": 14, + "index": 13 + }, + "end": { + "row": 1, + "col": 20, + "index": 19 + } + }, + "start": { + "row": 1, + "col": 12, + "index": 11 + }, + "end": { + "row": 1, + "col": 20, + "index": 19 + } + }, + "body": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 1, + "col": 24, + "index": 23 + }, + "end": { + "row": 1, + "col": 25, + "index": 24 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 25, + "index": 24 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 25, + "index": 24 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 26 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-function-with-newline/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-function-with-newline/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-function-with-newline/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-function-with-newline/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-function-with-newline/input.ts new file mode 100644 index 00000000..5868c4e2 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-function-with-newline/input.ts @@ -0,0 +1,2 @@ +async (f) +: t => { } diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-function-with-newline/output.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-function-with-newline/output.json new file mode 100644 index 00000000..4943a383 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-function-with-newline/output.json @@ -0,0 +1,114 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "ArrowFunctionExpression", + "expressionBody": false, + "async": true, + "arguments": [ + { + "kind": "Identifer", + "name": "f", + "optional": false, + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 1, + "col": 9, + "index": 8 + } + } + ], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "t", + "start": { + "row": 2, + "col": 3, + "index": 12 + }, + "end": { + "row": 2, + "col": 4, + "index": 13 + } + }, + "start": { + "row": 2, + "col": 3, + "index": 12 + }, + "end": { + "row": 2, + "col": 4, + "index": 13 + } + }, + "start": { + "row": 2, + "col": 1, + "index": 10 + }, + "end": { + "row": 2, + "col": 4, + "index": 13 + } + }, + "body": { + "kind": "FunctionBody", + "body": [], + "start": { + "row": 2, + "col": 8, + "index": 17 + }, + "end": { + "row": 2, + "col": 11, + "index": 20 + } + }, + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 2, + "col": 11, + "index": 20 + } + }, + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 2, + "col": 11, + "index": 20 + } + } + ], + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 3, + "col": 1, + "index": 21 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-1/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-1/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-1/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-1/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-1/input.ts new file mode 100644 index 00000000..809d50b6 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-1/input.ts @@ -0,0 +1,2 @@ +// https://github.com/babel/babel/issues/11038 +0 ? v => (sum += v) : v => 0; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-1/output.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-1/output.json new file mode 100644 index 00000000..0a3f919a --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-1/output.json @@ -0,0 +1,174 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "ConditionalExpression", + "test": { + "kind": "DecimalLiteral", + "rawValue": "0", + "start": { + "row": 2, + "col": 1, + "index": 47 + }, + "end": { + "row": 2, + "col": 2, + "index": 48 + } + }, + "consequnce": { + "kind": "ArrowFunctionExpression", + "expressionBody": true, + "async": false, + "arguments": [ + { + "kind": "Identifer", + "name": "v", + "start": { + "row": 2, + "col": 5, + "index": 51 + }, + "end": { + "row": 2, + "col": 6, + "index": 52 + } + } + ], + "body": { + "kind": "AssigmentExpression", + "operator": "+=", + "left": { + "kind": "Identifer", + "name": "sum", + "start": { + "row": 2, + "col": 11, + "index": 57 + }, + "end": { + "row": 2, + "col": 14, + "index": 60 + } + }, + "right": { + "kind": "Identifer", + "name": "v", + "start": { + "row": 2, + "col": 18, + "index": 64 + }, + "end": { + "row": 2, + "col": 19, + "index": 65 + } + }, + "start": { + "row": 2, + "col": 11, + "index": 57 + }, + "end": { + "row": 2, + "col": 19, + "index": 65 + }, + "parentheses": true + }, + "start": { + "row": 2, + "col": 5, + "index": 51 + }, + "end": { + "row": 2, + "col": 19, + "index": 65 + } + }, + "alter": { + "kind": "ArrowFunctionExpression", + "expressionBody": true, + "async": false, + "arguments": [ + { + "kind": "Identifer", + "name": "v", + "start": { + "row": 2, + "col": 23, + "index": 69 + }, + "end": { + "row": 2, + "col": 24, + "index": 70 + } + } + ], + "body": { + "kind": "DecimalLiteral", + "rawValue": "0", + "start": { + "row": 2, + "col": 28, + "index": 74 + }, + "end": { + "row": 2, + "col": 29, + "index": 75 + } + }, + "start": { + "row": 2, + "col": 23, + "index": 69 + }, + "end": { + "row": 2, + "col": 29, + "index": 75 + } + }, + "start": { + "row": 2, + "col": 1, + "index": 47 + }, + "end": { + "row": 2, + "col": 29, + "index": 75 + } + }, + "start": { + "row": 2, + "col": 1, + "index": 47 + }, + "end": { + "row": 2, + "col": 29, + "index": 75 + } + } + ], + "start": { + "row": 2, + "col": 1, + "index": 47 + }, + "end": { + "row": 3, + "col": 1, + "index": 77 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-2/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-2/expect.json new file mode 100644 index 00000000..e5936a86 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-2/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Failed", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-2/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-2/input.ts new file mode 100644 index 00000000..83145302 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-2/input.ts @@ -0,0 +1 @@ +0 ? v => (sum = v) : v => 0; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-2/output.txt b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-2/output.txt new file mode 100644 index 00000000..27344152 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-2/output.txt @@ -0,0 +1 @@ +[Syntax Error]: Unexpect token ;(1, 28). \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-3/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-3/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-3/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-3/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-3/input.ts new file mode 100644 index 00000000..d7db2a7d --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-3/input.ts @@ -0,0 +1 @@ +0 ? v => (sum = v) : v => 0 : v => 0; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-3/output.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-3/output.json new file mode 100644 index 00000000..2f1f85b8 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-3/output.json @@ -0,0 +1,244 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "ConditionalExpression", + "test": { + "kind": "DecimalLiteral", + "rawValue": "0", + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 2, + "index": 1 + } + }, + "consequnce": { + "kind": "ArrowFunctionExpression", + "expressionBody": true, + "async": false, + "arguments": [ + { + "kind": "Identifer", + "name": "v", + "start": { + "row": 1, + "col": 5, + "index": 4 + }, + "end": { + "row": 1, + "col": 6, + "index": 5 + } + } + ], + "body": { + "kind": "ArrowFunctionExpression", + "expressionBody": true, + "async": false, + "arguments": [ + { + "kind": "AssigmentPattern", + "left": { + "kind": "Identifer", + "name": "sum", + "optional": false, + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 14, + "index": 13 + } + }, + "right": { + "kind": "Identifer", + "name": "v", + "start": { + "row": 1, + "col": 17, + "index": 16 + }, + "end": { + "row": 1, + "col": 18, + "index": 17 + } + }, + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 18, + "index": 17 + } + } + ], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "v", + "start": { + "row": 1, + "col": 22, + "index": 21 + }, + "end": { + "row": 1, + "col": 23, + "index": 22 + } + }, + "start": { + "row": 1, + "col": 22, + "index": 21 + }, + "end": { + "row": 1, + "col": 23, + "index": 22 + } + }, + "start": { + "row": 1, + "col": 20, + "index": 19 + }, + "end": { + "row": 1, + "col": 23, + "index": 22 + } + }, + "body": { + "kind": "DecimalLiteral", + "rawValue": "0", + "start": { + "row": 1, + "col": 27, + "index": 26 + }, + "end": { + "row": 1, + "col": 28, + "index": 27 + } + }, + "start": { + "row": 1, + "col": 10, + "index": 9 + }, + "end": { + "row": 1, + "col": 28, + "index": 27 + } + }, + "start": { + "row": 1, + "col": 5, + "index": 4 + }, + "end": { + "row": 1, + "col": 28, + "index": 27 + } + }, + "alter": { + "kind": "ArrowFunctionExpression", + "expressionBody": true, + "async": false, + "arguments": [ + { + "kind": "Identifer", + "name": "v", + "start": { + "row": 1, + "col": 31, + "index": 30 + }, + "end": { + "row": 1, + "col": 32, + "index": 31 + } + } + ], + "body": { + "kind": "DecimalLiteral", + "rawValue": "0", + "start": { + "row": 1, + "col": 36, + "index": 35 + }, + "end": { + "row": 1, + "col": 37, + "index": 36 + } + }, + "start": { + "row": 1, + "col": 31, + "index": 30 + }, + "end": { + "row": 1, + "col": 37, + "index": 36 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 37, + "index": 36 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 37, + "index": 36 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 38 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-4/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-4/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-4/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-4/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-4/input.ts new file mode 100644 index 00000000..7875a506 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-4/input.ts @@ -0,0 +1 @@ +0 ? v => (...rest) : v => 0 : v => 0; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-4/output.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-4/output.json new file mode 100644 index 00000000..84107866 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/arrow-like-in-conditional-4/output.json @@ -0,0 +1,230 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "ConditionalExpression", + "test": { + "kind": "DecimalLiteral", + "rawValue": "0", + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 2, + "index": 1 + } + }, + "consequnce": { + "kind": "ArrowFunctionExpression", + "expressionBody": true, + "async": false, + "arguments": [ + { + "kind": "Identifer", + "name": "v", + "start": { + "row": 1, + "col": 5, + "index": 4 + }, + "end": { + "row": 1, + "col": 6, + "index": 5 + } + } + ], + "body": { + "kind": "ArrowFunctionExpression", + "expressionBody": true, + "async": false, + "arguments": [ + { + "kind": "RestElement", + "argument": { + "kind": "Identifer", + "name": "rest", + "start": { + "row": 1, + "col": 14, + "index": 13 + }, + "end": { + "row": 1, + "col": 18, + "index": 17 + } + }, + "optional": false, + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 18, + "index": 17 + } + } + ], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "v", + "start": { + "row": 1, + "col": 22, + "index": 21 + }, + "end": { + "row": 1, + "col": 23, + "index": 22 + } + }, + "start": { + "row": 1, + "col": 22, + "index": 21 + }, + "end": { + "row": 1, + "col": 23, + "index": 22 + } + }, + "start": { + "row": 1, + "col": 20, + "index": 19 + }, + "end": { + "row": 1, + "col": 23, + "index": 22 + } + }, + "body": { + "kind": "DecimalLiteral", + "rawValue": "0", + "start": { + "row": 1, + "col": 27, + "index": 26 + }, + "end": { + "row": 1, + "col": 28, + "index": 27 + } + }, + "start": { + "row": 1, + "col": 10, + "index": 9 + }, + "end": { + "row": 1, + "col": 28, + "index": 27 + } + }, + "start": { + "row": 1, + "col": 5, + "index": 4 + }, + "end": { + "row": 1, + "col": 28, + "index": 27 + } + }, + "alter": { + "kind": "ArrowFunctionExpression", + "expressionBody": true, + "async": false, + "arguments": [ + { + "kind": "Identifer", + "name": "v", + "start": { + "row": 1, + "col": 31, + "index": 30 + }, + "end": { + "row": 1, + "col": 32, + "index": 31 + } + } + ], + "body": { + "kind": "DecimalLiteral", + "rawValue": "0", + "start": { + "row": 1, + "col": 36, + "index": 35 + }, + "end": { + "row": 1, + "col": 37, + "index": 36 + } + }, + "start": { + "row": 1, + "col": 31, + "index": 30 + }, + "end": { + "row": 1, + "col": 37, + "index": 36 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 37, + "index": 36 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 37, + "index": 36 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 38 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-arrow-function-after-binary-operator/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-arrow-function-after-binary-operator/expect.json new file mode 100644 index 00000000..e5936a86 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-arrow-function-after-binary-operator/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Failed", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-arrow-function-after-binary-operator/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-arrow-function-after-binary-operator/input.ts new file mode 100644 index 00000000..cace33f2 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-arrow-function-after-binary-operator/input.ts @@ -0,0 +1 @@ +4 + async() => 2 diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-arrow-function-after-binary-operator/output.txt b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-arrow-function-after-binary-operator/output.txt new file mode 100644 index 00000000..e2bc2230 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-arrow-function-after-binary-operator/output.txt @@ -0,0 +1 @@ +[Syntax Error]: Unexpect token =>(1, 21). \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-await-null/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-await-null/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-await-null/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-await-null/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-await-null/input.ts new file mode 100644 index 00000000..924ee33c --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-await-null/input.ts @@ -0,0 +1 @@ +async () => await null; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-await-null/output.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-await-null/output.json new file mode 100644 index 00000000..5053f9bd --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-await-null/output.json @@ -0,0 +1,112 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "ArrowFunctionExpression", + "expressionBody": true, + "async": true, + "arguments": [], + "typeParameters": { + "kind": "TSTypeParameterDeclaration", + "params": [ + { + "kind": "TSTypeParameter", + "name": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 1, + "col": 9, + "index": 8 + } + }, + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 1, + "col": 9, + "index": 8 + } + } + ], + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 10, + "index": 9 + } + }, + "body": { + "kind": "AwaitExpression", + "argument": { + "kind": "NullLiteral", + "start": { + "row": 1, + "col": 22, + "index": 21 + }, + "end": { + "row": 1, + "col": 26, + "index": 25 + } + }, + "start": { + "row": 1, + "col": 16, + "index": 15 + }, + "end": { + "row": 1, + "col": 26, + "index": 25 + } + }, + "start": { + "row": 1, + "col": 10, + "index": 9 + }, + "end": { + "row": 1, + "col": 26, + "index": 25 + } + }, + "start": { + "row": 1, + "col": 10, + "index": 9 + }, + "end": { + "row": 1, + "col": 26, + "index": 25 + } + } + ], + "start": { + "row": 1, + "col": 10, + "index": 9 + }, + "end": { + "row": 2, + "col": 1, + "index": 27 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-generic-after-await/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-generic-after-await/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-generic-after-await/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-generic-after-await/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-generic-after-await/input.ts new file mode 100644 index 00000000..8be8e436 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-generic-after-await/input.ts @@ -0,0 +1,5 @@ +async () => { + await null; + async () => null; + }; + \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-generic-after-await/output.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-generic-after-await/output.json new file mode 100644 index 00000000..c3a545be --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-generic-after-await/output.json @@ -0,0 +1,182 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "ArrowFunctionExpression", + "expressionBody": false, + "async": true, + "arguments": [], + "body": { + "kind": "FunctionBody", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "AwaitExpression", + "argument": { + "kind": "NullLiteral", + "start": { + "row": 2, + "col": 11, + "index": 24 + }, + "end": { + "row": 2, + "col": 15, + "index": 28 + } + }, + "start": { + "row": 2, + "col": 5, + "index": 18 + }, + "end": { + "row": 2, + "col": 15, + "index": 28 + } + }, + "start": { + "row": 2, + "col": 5, + "index": 18 + }, + "end": { + "row": 2, + "col": 15, + "index": 28 + } + }, + { + "kind": "ExpressionStatement", + "expr": { + "kind": "ArrowFunctionExpression", + "expressionBody": true, + "async": true, + "arguments": [], + "typeParameters": { + "kind": "TSTypeParameterDeclaration", + "params": [ + { + "kind": "TSTypeParameter", + "name": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 3, + "col": 12, + "index": 41 + }, + "end": { + "row": 3, + "col": 13, + "index": 42 + } + }, + "start": { + "row": 3, + "col": 12, + "index": 41 + }, + "end": { + "row": 3, + "col": 13, + "index": 42 + } + } + ], + "start": { + "row": 3, + "col": 11, + "index": 40 + }, + "end": { + "row": 3, + "col": 14, + "index": 43 + } + }, + "body": { + "kind": "NullLiteral", + "start": { + "row": 3, + "col": 20, + "index": 49 + }, + "end": { + "row": 3, + "col": 24, + "index": 53 + } + }, + "start": { + "row": 3, + "col": 14, + "index": 43 + }, + "end": { + "row": 3, + "col": 24, + "index": 53 + } + }, + "start": { + "row": 3, + "col": 14, + "index": 43 + }, + "end": { + "row": 3, + "col": 24, + "index": 53 + } + } + ], + "start": { + "row": 1, + "col": 13, + "index": 12 + }, + "end": { + "row": 4, + "col": 4, + "index": 58 + } + }, + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 4, + "col": 4, + "index": 58 + } + }, + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 4, + "col": 4, + "index": 58 + } + } + ], + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 5, + "col": 3, + "index": 62 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-generic-false-positive/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-generic-false-positive/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-generic-false-positive/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-generic-false-positive/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-generic-false-positive/input.ts new file mode 100644 index 00000000..94b8ba09 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-generic-false-positive/input.ts @@ -0,0 +1 @@ +f<(v: T) => void>(); diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-generic-false-positive/output.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-generic-false-positive/output.json new file mode 100644 index 00000000..3a0cf7c9 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-generic-false-positive/output.json @@ -0,0 +1,210 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "CallExpression", + "optional": false, + "callee": { + "kind": "Identifer", + "name": "f", + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 2, + "index": 1 + } + }, + "typeArguments": { + "kind": "TSTypeParameterInstantiation", + "params": [ + { + "kind": "TSFunctionType", + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSVoidKeyword", + "start": { + "row": 1, + "col": 16, + "index": 15 + }, + "end": { + "row": 1, + "col": 20, + "index": 19 + } + }, + "start": { + "row": 1, + "col": 13, + "index": 12 + }, + "end": { + "row": 1, + "col": 20, + "index": 19 + } + }, + "parameters": [ + { + "kind": "Identifer", + "name": "v", + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 10, + "index": 9 + }, + "end": { + "row": 1, + "col": 11, + "index": 10 + } + }, + "start": { + "row": 1, + "col": 10, + "index": 9 + }, + "end": { + "row": 1, + "col": 11, + "index": 10 + } + }, + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 1, + "col": 11, + "index": 10 + } + }, + "optional": false, + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 8, + "index": 7 + } + } + ], + "typeParameters": { + "kind": "TSTypeParameterDeclaration", + "params": [ + { + "kind": "TSTypeParameter", + "name": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 4, + "index": 3 + }, + "end": { + "row": 1, + "col": 5, + "index": 4 + } + }, + "start": { + "row": 1, + "col": 4, + "index": 3 + }, + "end": { + "row": 1, + "col": 5, + "index": 4 + } + } + ], + "start": { + "row": 1, + "col": 3, + "index": 2 + }, + "end": { + "row": 1, + "col": 6, + "index": 5 + } + }, + "start": { + "row": 1, + "col": 3, + "index": 2 + }, + "end": { + "row": 1, + "col": 20, + "index": 19 + } + } + ], + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 21, + "index": 20 + } + }, + "arguments": [], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 23, + "index": 22 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 23, + "index": 22 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 24 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-generic-tokens-true/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-generic-tokens-true/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-generic-tokens-true/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-generic-tokens-true/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-generic-tokens-true/input.ts new file mode 100644 index 00000000..62958011 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-generic-tokens-true/input.ts @@ -0,0 +1 @@ +async (a: T): T => a; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-generic-tokens-true/output.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-generic-tokens-true/output.json new file mode 100644 index 00000000..161e17ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-generic-tokens-true/output.json @@ -0,0 +1,196 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "ArrowFunctionExpression", + "expressionBody": true, + "async": true, + "arguments": [ + { + "kind": "Identifer", + "name": "a", + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 14, + "index": 13 + }, + "end": { + "row": 1, + "col": 15, + "index": 14 + } + }, + "start": { + "row": 1, + "col": 14, + "index": 13 + }, + "end": { + "row": 1, + "col": 15, + "index": 14 + } + }, + "start": { + "row": 1, + "col": 12, + "index": 11 + }, + "end": { + "row": 1, + "col": 15, + "index": 14 + } + }, + "optional": false, + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + } + ], + "typeParameters": { + "kind": "TSTypeParameterDeclaration", + "params": [ + { + "kind": "TSTypeParameter", + "name": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 1, + "col": 9, + "index": 8 + } + }, + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 1, + "col": 9, + "index": 8 + } + } + ], + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 10, + "index": 9 + } + }, + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 18, + "index": 17 + }, + "end": { + "row": 1, + "col": 19, + "index": 18 + } + }, + "start": { + "row": 1, + "col": 18, + "index": 17 + }, + "end": { + "row": 1, + "col": 19, + "index": 18 + } + }, + "start": { + "row": 1, + "col": 16, + "index": 15 + }, + "end": { + "row": 1, + "col": 19, + "index": 18 + } + }, + "body": { + "kind": "Identifer", + "name": "a", + "start": { + "row": 1, + "col": 23, + "index": 22 + }, + "end": { + "row": 1, + "col": 24, + "index": 23 + } + }, + "start": { + "row": 1, + "col": 10, + "index": 9 + }, + "end": { + "row": 1, + "col": 24, + "index": 23 + } + }, + "start": { + "row": 1, + "col": 10, + "index": 9 + }, + "end": { + "row": 1, + "col": 24, + "index": 23 + } + } + ], + "start": { + "row": 1, + "col": 10, + "index": 9 + }, + "end": { + "row": 2, + "col": 1, + "index": 25 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-rest-optional-parameter/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-rest-optional-parameter/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-rest-optional-parameter/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-rest-optional-parameter/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-rest-optional-parameter/input.ts new file mode 100644 index 00000000..a78054d5 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-rest-optional-parameter/input.ts @@ -0,0 +1 @@ +async(...args?: any[]) : any => {} diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-rest-optional-parameter/output.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-rest-optional-parameter/output.json new file mode 100644 index 00000000..c12b5adb --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-rest-optional-parameter/output.json @@ -0,0 +1,152 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "ArrowFunctionExpression", + "expressionBody": false, + "async": true, + "arguments": [ + { + "kind": "RestElement", + "argument": { + "kind": "Identifer", + "name": "args", + "start": { + "row": 1, + "col": 10, + "index": 9 + }, + "end": { + "row": 1, + "col": 14, + "index": 13 + } + }, + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSArrayType", + "elementType": { + "kind": "TSAnyKeyword", + "start": { + "row": 1, + "col": 17, + "index": 16 + }, + "end": { + "row": 1, + "col": 20, + "index": 19 + } + }, + "start": { + "row": 1, + "col": 17, + "index": 16 + }, + "end": { + "row": 1, + "col": 22, + "index": 21 + } + }, + "start": { + "row": 1, + "col": 15, + "index": 14 + }, + "end": { + "row": 1, + "col": 22, + "index": 21 + } + }, + "optional": true, + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 14, + "index": 13 + } + } + ], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSAnyKeyword", + "start": { + "row": 1, + "col": 26, + "index": 25 + }, + "end": { + "row": 1, + "col": 29, + "index": 28 + } + }, + "start": { + "row": 1, + "col": 24, + "index": 23 + }, + "end": { + "row": 1, + "col": 29, + "index": 28 + } + }, + "body": { + "kind": "FunctionBody", + "body": [], + "start": { + "row": 1, + "col": 33, + "index": 32 + }, + "end": { + "row": 1, + "col": 35, + "index": 34 + } + }, + "start": { + "row": 1, + "col": 6, + "index": 5 + }, + "end": { + "row": 1, + "col": 35, + "index": 34 + } + }, + "start": { + "row": 1, + "col": 6, + "index": 5 + }, + "end": { + "row": 1, + "col": 35, + "index": 34 + } + } + ], + "start": { + "row": 1, + "col": 6, + "index": 5 + }, + "end": { + "row": 2, + "col": 1, + "index": 35 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-rest/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-rest/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-rest/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-rest/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-rest/input.ts new file mode 100644 index 00000000..2da2ab47 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-rest/input.ts @@ -0,0 +1 @@ +async (...args: any[]) : any => {} diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-rest/output.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-rest/output.json new file mode 100644 index 00000000..72e6057c --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async-rest/output.json @@ -0,0 +1,152 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "ArrowFunctionExpression", + "expressionBody": false, + "async": true, + "arguments": [ + { + "kind": "RestElement", + "argument": { + "kind": "Identifer", + "name": "args", + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 15, + "index": 14 + } + }, + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSArrayType", + "elementType": { + "kind": "TSAnyKeyword", + "start": { + "row": 1, + "col": 17, + "index": 16 + }, + "end": { + "row": 1, + "col": 20, + "index": 19 + } + }, + "start": { + "row": 1, + "col": 17, + "index": 16 + }, + "end": { + "row": 1, + "col": 22, + "index": 21 + } + }, + "start": { + "row": 1, + "col": 15, + "index": 14 + }, + "end": { + "row": 1, + "col": 22, + "index": 21 + } + }, + "optional": false, + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 1, + "col": 15, + "index": 14 + } + } + ], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSAnyKeyword", + "start": { + "row": 1, + "col": 26, + "index": 25 + }, + "end": { + "row": 1, + "col": 29, + "index": 28 + } + }, + "start": { + "row": 1, + "col": 24, + "index": 23 + }, + "end": { + "row": 1, + "col": 29, + "index": 28 + } + }, + "body": { + "kind": "FunctionBody", + "body": [], + "start": { + "row": 1, + "col": 33, + "index": 32 + }, + "end": { + "row": 1, + "col": 35, + "index": 34 + } + }, + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 35, + "index": 34 + } + }, + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 35, + "index": 34 + } + } + ], + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 2, + "col": 1, + "index": 35 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async/input.ts new file mode 100644 index 00000000..5f4fa39a --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async/input.ts @@ -0,0 +1 @@ +async (x?: number): any => x; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async/output.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async/output.json new file mode 100644 index 00000000..537dd14a --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/async/output.json @@ -0,0 +1,126 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "ArrowFunctionExpression", + "expressionBody": true, + "async": true, + "arguments": [ + { + "kind": "Identifer", + "name": "x", + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 1, + "col": 12, + "index": 11 + }, + "end": { + "row": 1, + "col": 18, + "index": 17 + } + }, + "start": { + "row": 1, + "col": 10, + "index": 9 + }, + "end": { + "row": 1, + "col": 18, + "index": 17 + } + }, + "optional": true, + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 1, + "col": 9, + "index": 8 + } + } + ], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSAnyKeyword", + "start": { + "row": 1, + "col": 21, + "index": 20 + }, + "end": { + "row": 1, + "col": 24, + "index": 23 + } + }, + "start": { + "row": 1, + "col": 19, + "index": 18 + }, + "end": { + "row": 1, + "col": 24, + "index": 23 + } + }, + "body": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 1, + "col": 28, + "index": 27 + }, + "end": { + "row": 1, + "col": 29, + "index": 28 + } + }, + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 29, + "index": 28 + } + }, + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 29, + "index": 28 + } + } + ], + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 2, + "col": 1, + "index": 30 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/destructuring-with-annotation-newline/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/destructuring-with-annotation-newline/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/destructuring-with-annotation-newline/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/destructuring-with-annotation-newline/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/destructuring-with-annotation-newline/input.ts new file mode 100644 index 00000000..67fb36ba --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/destructuring-with-annotation-newline/input.ts @@ -0,0 +1,3 @@ +( + { a, b }: T, +): T => {}; \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/destructuring-with-annotation-newline/output.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/destructuring-with-annotation-newline/output.json new file mode 100644 index 00000000..08337f00 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/destructuring-with-annotation-newline/output.json @@ -0,0 +1,213 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "ArrowFunctionExpression", + "expressionBody": false, + "async": false, + "arguments": [ + { + "kind": "ObjectPattern", + "properties": [ + { + "kind": "ObjectPatternProperty", + "computed": false, + "shorted": true, + "key": { + "kind": "Identifer", + "name": "a", + "start": { + "row": 2, + "col": 7, + "index": 8 + }, + "end": { + "row": 2, + "col": 8, + "index": 9 + } + }, + "start": { + "row": 2, + "col": 7, + "index": 8 + }, + "end": { + "row": 2, + "col": 8, + "index": 9 + } + }, + { + "kind": "ObjectPatternProperty", + "computed": false, + "shorted": true, + "key": { + "kind": "Identifer", + "name": "b", + "start": { + "row": 2, + "col": 10, + "index": 11 + }, + "end": { + "row": 2, + "col": 11, + "index": 12 + } + }, + "start": { + "row": 2, + "col": 10, + "index": 11 + }, + "end": { + "row": 2, + "col": 11, + "index": 12 + } + } + ], + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 2, + "col": 15, + "index": 16 + }, + "end": { + "row": 2, + "col": 16, + "index": 17 + } + }, + "start": { + "row": 2, + "col": 15, + "index": 16 + }, + "end": { + "row": 2, + "col": 16, + "index": 17 + } + }, + "start": { + "row": 2, + "col": 13, + "index": 14 + }, + "end": { + "row": 2, + "col": 16, + "index": 17 + } + }, + "optional": false, + "start": { + "row": 2, + "col": 5, + "index": 6 + }, + "end": { + "row": 2, + "col": 13, + "index": 14 + } + } + ], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 3, + "col": 4, + "index": 22 + }, + "end": { + "row": 3, + "col": 5, + "index": 23 + } + }, + "start": { + "row": 3, + "col": 4, + "index": 22 + }, + "end": { + "row": 3, + "col": 5, + "index": 23 + } + }, + "start": { + "row": 3, + "col": 2, + "index": 20 + }, + "end": { + "row": 3, + "col": 5, + "index": 23 + } + }, + "body": { + "kind": "FunctionBody", + "body": [], + "start": { + "row": 3, + "col": 9, + "index": 27 + }, + "end": { + "row": 3, + "col": 11, + "index": 29 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 3, + "col": 11, + "index": 29 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 3, + "col": 11, + "index": 29 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 3, + "col": 12, + "index": 30 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/destructuring/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/destructuring/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/destructuring/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/destructuring/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/destructuring/input.ts new file mode 100644 index 00000000..4bb8dcbf --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/destructuring/input.ts @@ -0,0 +1 @@ +({ a = 0 }) => 0; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/destructuring/output.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/destructuring/output.json new file mode 100644 index 00000000..fcd26c49 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/destructuring/output.json @@ -0,0 +1,116 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "ArrowFunctionExpression", + "expressionBody": true, + "async": false, + "arguments": [ + { + "kind": "ObjectPattern", + "properties": [ + { + "kind": "AssigmentPattern", + "left": { + "kind": "Identifer", + "name": "a", + "start": { + "row": 1, + "col": 4, + "index": 3 + }, + "end": { + "row": 1, + "col": 5, + "index": 4 + } + }, + "right": { + "kind": "DecimalLiteral", + "rawValue": "0", + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 1, + "col": 9, + "index": 8 + } + }, + "start": { + "row": 1, + "col": 4, + "index": 3 + }, + "end": { + "row": 1, + "col": 9, + "index": 8 + } + } + ], + "optional": false, + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 11, + "index": 10 + } + } + ], + "body": { + "kind": "DecimalLiteral", + "rawValue": "0", + "start": { + "row": 1, + "col": 16, + "index": 15 + }, + "end": { + "row": 1, + "col": 17, + "index": 16 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 17, + "index": 16 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 17, + "index": 16 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 18 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/generic/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/generic/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/generic/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/generic/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/generic/input.ts new file mode 100644 index 00000000..110f5836 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/generic/input.ts @@ -0,0 +1 @@ +(a: T): T => a; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/generic/output.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/generic/output.json new file mode 100644 index 00000000..e659a98a --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/generic/output.json @@ -0,0 +1,196 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "ArrowFunctionExpression", + "expressionBody": true, + "async": false, + "arguments": [ + { + "kind": "Identifer", + "name": "a", + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 1, + "col": 9, + "index": 8 + } + }, + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 1, + "col": 9, + "index": 8 + } + }, + "start": { + "row": 1, + "col": 6, + "index": 5 + }, + "end": { + "row": 1, + "col": 9, + "index": 8 + } + }, + "optional": false, + "start": { + "row": 1, + "col": 5, + "index": 4 + }, + "end": { + "row": 1, + "col": 6, + "index": 5 + } + } + ], + "typeParameters": { + "kind": "TSTypeParameterDeclaration", + "params": [ + { + "kind": "TSTypeParameter", + "name": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 3, + "index": 2 + } + }, + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 3, + "index": 2 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 4, + "index": 3 + } + }, + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 12, + "index": 11 + }, + "end": { + "row": 1, + "col": 13, + "index": 12 + } + }, + "start": { + "row": 1, + "col": 12, + "index": 11 + }, + "end": { + "row": 1, + "col": 13, + "index": 12 + } + }, + "start": { + "row": 1, + "col": 10, + "index": 9 + }, + "end": { + "row": 1, + "col": 13, + "index": 12 + } + }, + "body": { + "kind": "Identifer", + "name": "a", + "start": { + "row": 1, + "col": 17, + "index": 16 + }, + "end": { + "row": 1, + "col": 18, + "index": 17 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 18, + "index": 17 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 18, + "index": 17 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 19 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/optional-parameter/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/optional-parameter/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/optional-parameter/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/optional-parameter/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/optional-parameter/input.ts new file mode 100644 index 00000000..f3019ef4 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/optional-parameter/input.ts @@ -0,0 +1,2 @@ +(x?: number): any => x; +((k?) => k + 1)(); diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/optional-parameter/output.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/optional-parameter/output.json new file mode 100644 index 00000000..04b0aebf --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/optional-parameter/output.json @@ -0,0 +1,229 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "ArrowFunctionExpression", + "expressionBody": true, + "async": false, + "arguments": [ + { + "kind": "Identifer", + "name": "x", + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 1, + "col": 6, + "index": 5 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + }, + "start": { + "row": 1, + "col": 4, + "index": 3 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + }, + "optional": true, + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 3, + "index": 2 + } + } + ], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSAnyKeyword", + "start": { + "row": 1, + "col": 15, + "index": 14 + }, + "end": { + "row": 1, + "col": 18, + "index": 17 + } + }, + "start": { + "row": 1, + "col": 13, + "index": 12 + }, + "end": { + "row": 1, + "col": 18, + "index": 17 + } + }, + "body": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 1, + "col": 22, + "index": 21 + }, + "end": { + "row": 1, + "col": 23, + "index": 22 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 23, + "index": 22 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 23, + "index": 22 + } + }, + { + "kind": "ExpressionStatement", + "expr": { + "kind": "CallExpression", + "optional": false, + "callee": { + "kind": "ArrowFunctionExpression", + "expressionBody": true, + "async": false, + "arguments": [ + { + "kind": "Identifer", + "name": "k", + "optional": true, + "start": { + "row": 2, + "col": 3, + "index": 26 + }, + "end": { + "row": 2, + "col": 4, + "index": 27 + } + } + ], + "body": { + "kind": "BinaryExpression", + "operator": "+", + "left": { + "kind": "Identifer", + "name": "k", + "start": { + "row": 2, + "col": 10, + "index": 33 + }, + "end": { + "row": 2, + "col": 11, + "index": 34 + } + }, + "right": { + "kind": "DecimalLiteral", + "rawValue": "1", + "start": { + "row": 2, + "col": 14, + "index": 37 + }, + "end": { + "row": 2, + "col": 15, + "index": 38 + } + }, + "start": { + "row": 2, + "col": 10, + "index": 33 + }, + "end": { + "row": 2, + "col": 15, + "index": 38 + } + }, + "start": { + "row": 2, + "col": 2, + "index": 25 + }, + "end": { + "row": 2, + "col": 15, + "index": 38 + }, + "parentheses": true + }, + "arguments": [], + "start": { + "row": 2, + "col": 2, + "index": 25 + }, + "end": { + "row": 2, + "col": 18, + "index": 41 + } + }, + "start": { + "row": 2, + "col": 2, + "index": 25 + }, + "end": { + "row": 2, + "col": 18, + "index": 41 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 3, + "col": 1, + "index": 43 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/predicate-types/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/predicate-types/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/predicate-types/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/predicate-types/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/predicate-types/input.ts new file mode 100644 index 00000000..5c26fdbc --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/predicate-types/input.ts @@ -0,0 +1 @@ +(x: any): x is string => true; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/predicate-types/output.json b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/predicate-types/output.json new file mode 100644 index 00000000..23f78715 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/arrow-function/predicate-types/output.json @@ -0,0 +1,167 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "ArrowFunctionExpression", + "expressionBody": true, + "async": false, + "arguments": [ + { + "kind": "Identifer", + "name": "x", + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSAnyKeyword", + "start": { + "row": 1, + "col": 5, + "index": 4 + }, + "end": { + "row": 1, + "col": 8, + "index": 7 + } + }, + "start": { + "row": 1, + "col": 3, + "index": 2 + }, + "end": { + "row": 1, + "col": 8, + "index": 7 + } + }, + "optional": false, + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 3, + "index": 2 + } + } + ], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSTypePredicate", + "parameterName": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + }, + "asserts": false, + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSStringKeyword", + "start": { + "row": 1, + "col": 16, + "index": 15 + }, + "end": { + "row": 1, + "col": 22, + "index": 21 + } + }, + "start": { + "row": 1, + "col": 16, + "index": 15 + }, + "end": { + "row": 1, + "col": 22, + "index": 21 + } + }, + "start": { + "row": 1, + "col": 9, + "index": 8 + }, + "end": { + "row": 1, + "col": 22, + "index": 21 + } + }, + "start": { + "row": 1, + "col": 9, + "index": 8 + }, + "end": { + "row": 1, + "col": 22, + "index": 21 + } + }, + "body": { + "kind": "BoolLterial", + "value": true, + "start": { + "row": 1, + "col": 26, + "index": 25 + }, + "end": { + "row": 1, + "col": 30, + "index": 29 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 30, + "index": 29 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 30, + "index": 29 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 31 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/arrow-function/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/arrow-function/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/arrow-function/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/arrow-function/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/arrow-function/input.ts new file mode 100644 index 00000000..5989d8d4 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/arrow-function/input.ts @@ -0,0 +1,3 @@ +const assert1 = (value: unknown): asserts value is string => {} +const assert2 = (value: unknown): asserts value => {} +const assert3 = (value: unknown): asserts => {} diff --git a/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/arrow-function/output.json b/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/arrow-function/output.json new file mode 100644 index 00000000..ab691b57 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/arrow-function/output.json @@ -0,0 +1,511 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "VariableDeclaration", + "variant": "const", + "declarations": [ + { + "kind": "VariableDeclarator", + "id": { + "kind": "Identifer", + "name": "assert1", + "optional": false, + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 14, + "index": 13 + } + }, + "init": { + "kind": "ArrowFunctionExpression", + "expressionBody": false, + "async": false, + "arguments": [ + { + "kind": "Identifer", + "name": "value", + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSUnknowKeyword", + "start": { + "row": 1, + "col": 25, + "index": 24 + }, + "end": { + "row": 1, + "col": 32, + "index": 31 + } + }, + "start": { + "row": 1, + "col": 23, + "index": 22 + }, + "end": { + "row": 1, + "col": 32, + "index": 31 + } + }, + "optional": false, + "start": { + "row": 1, + "col": 18, + "index": 17 + }, + "end": { + "row": 1, + "col": 23, + "index": 22 + } + } + ], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSTypePredicate", + "parameterName": { + "kind": "Identifer", + "name": "value", + "start": { + "row": 1, + "col": 43, + "index": 42 + }, + "end": { + "row": 1, + "col": 48, + "index": 47 + } + }, + "asserts": true, + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSStringKeyword", + "start": { + "row": 1, + "col": 52, + "index": 51 + }, + "end": { + "row": 1, + "col": 58, + "index": 57 + } + }, + "start": { + "row": 1, + "col": 52, + "index": 51 + }, + "end": { + "row": 1, + "col": 58, + "index": 57 + } + }, + "start": { + "row": 1, + "col": 33, + "index": 32 + }, + "end": { + "row": 1, + "col": 58, + "index": 57 + } + }, + "start": { + "row": 1, + "col": 33, + "index": 32 + }, + "end": { + "row": 1, + "col": 58, + "index": 57 + } + }, + "body": { + "kind": "FunctionBody", + "body": [], + "start": { + "row": 1, + "col": 62, + "index": 61 + }, + "end": { + "row": 1, + "col": 64, + "index": 63 + } + }, + "start": { + "row": 1, + "col": 17, + "index": 16 + }, + "end": { + "row": 1, + "col": 64, + "index": 63 + } + }, + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 64, + "index": 63 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 64, + "index": 63 + } + }, + { + "kind": "VariableDeclaration", + "variant": "const", + "declarations": [ + { + "kind": "VariableDeclarator", + "id": { + "kind": "Identifer", + "name": "assert2", + "optional": false, + "start": { + "row": 2, + "col": 7, + "index": 70 + }, + "end": { + "row": 2, + "col": 14, + "index": 77 + } + }, + "init": { + "kind": "ArrowFunctionExpression", + "expressionBody": false, + "async": false, + "arguments": [ + { + "kind": "Identifer", + "name": "value", + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSUnknowKeyword", + "start": { + "row": 2, + "col": 25, + "index": 88 + }, + "end": { + "row": 2, + "col": 32, + "index": 95 + } + }, + "start": { + "row": 2, + "col": 23, + "index": 86 + }, + "end": { + "row": 2, + "col": 32, + "index": 95 + } + }, + "optional": false, + "start": { + "row": 2, + "col": 18, + "index": 81 + }, + "end": { + "row": 2, + "col": 23, + "index": 86 + } + } + ], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSTypePredicate", + "parameterName": { + "kind": "Identifer", + "name": "value", + "start": { + "row": 2, + "col": 43, + "index": 106 + }, + "end": { + "row": 2, + "col": 48, + "index": 111 + } + }, + "asserts": true, + "start": { + "row": 2, + "col": 33, + "index": 96 + }, + "end": { + "row": 2, + "col": 48, + "index": 111 + } + }, + "start": { + "row": 2, + "col": 33, + "index": 96 + }, + "end": { + "row": 2, + "col": 48, + "index": 111 + } + }, + "body": { + "kind": "FunctionBody", + "body": [], + "start": { + "row": 2, + "col": 52, + "index": 115 + }, + "end": { + "row": 2, + "col": 54, + "index": 117 + } + }, + "start": { + "row": 2, + "col": 17, + "index": 80 + }, + "end": { + "row": 2, + "col": 54, + "index": 117 + } + }, + "start": { + "row": 2, + "col": 7, + "index": 70 + }, + "end": { + "row": 2, + "col": 54, + "index": 117 + } + } + ], + "start": { + "row": 2, + "col": 1, + "index": 64 + }, + "end": { + "row": 2, + "col": 54, + "index": 117 + } + }, + { + "kind": "VariableDeclaration", + "variant": "const", + "declarations": [ + { + "kind": "VariableDeclarator", + "id": { + "kind": "Identifer", + "name": "assert3", + "optional": false, + "start": { + "row": 3, + "col": 7, + "index": 124 + }, + "end": { + "row": 3, + "col": 14, + "index": 131 + } + }, + "init": { + "kind": "ArrowFunctionExpression", + "expressionBody": false, + "async": false, + "arguments": [ + { + "kind": "Identifer", + "name": "value", + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSUnknowKeyword", + "start": { + "row": 3, + "col": 25, + "index": 142 + }, + "end": { + "row": 3, + "col": 32, + "index": 149 + } + }, + "start": { + "row": 3, + "col": 23, + "index": 140 + }, + "end": { + "row": 3, + "col": 32, + "index": 149 + } + }, + "optional": false, + "start": { + "row": 3, + "col": 18, + "index": 135 + }, + "end": { + "row": 3, + "col": 23, + "index": 140 + } + } + ], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "asserts", + "start": { + "row": 3, + "col": 35, + "index": 152 + }, + "end": { + "row": 3, + "col": 42, + "index": 159 + } + }, + "start": { + "row": 3, + "col": 35, + "index": 152 + }, + "end": { + "row": 3, + "col": 42, + "index": 159 + } + }, + "start": { + "row": 3, + "col": 33, + "index": 150 + }, + "end": { + "row": 3, + "col": 42, + "index": 159 + } + }, + "body": { + "kind": "FunctionBody", + "body": [], + "start": { + "row": 3, + "col": 46, + "index": 163 + }, + "end": { + "row": 3, + "col": 48, + "index": 165 + } + }, + "start": { + "row": 3, + "col": 17, + "index": 134 + }, + "end": { + "row": 3, + "col": 48, + "index": 165 + } + }, + "start": { + "row": 3, + "col": 7, + "index": 124 + }, + "end": { + "row": 3, + "col": 48, + "index": 165 + } + } + ], + "start": { + "row": 3, + "col": 1, + "index": 118 + }, + "end": { + "row": 3, + "col": 48, + "index": 165 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 4, + "col": 1, + "index": 166 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/asserts-var-with-predicate/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/asserts-var-with-predicate/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/asserts-var-with-predicate/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/asserts-var-with-predicate/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/asserts-var-with-predicate/input.ts new file mode 100644 index 00000000..0bb18752 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/asserts-var-with-predicate/input.ts @@ -0,0 +1,4 @@ +class C { + assertIsString(value: unknown): asserts value is string {} +} + \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/asserts-var-with-predicate/output.json b/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/asserts-var-with-predicate/output.json new file mode 100644 index 00000000..5241f7ef --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/asserts-var-with-predicate/output.json @@ -0,0 +1,215 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ClassDeclaration", + "id": { + "kind": "Identifer", + "name": "C", + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 8, + "index": 7 + } + }, + "superClass": null, + "body": { + "kind": "ClassBody", + "body": [ + { + "kind": "ClassMethodDefinition", + "async": false, + "generator": false, + "computed": false, + "static": false, + "key": { + "kind": "Identifer", + "name": "assertIsString", + "start": { + "row": 2, + "col": 5, + "index": 14 + }, + "end": { + "row": 2, + "col": 19, + "index": 28 + } + }, + "params": [ + { + "kind": "Identifer", + "name": "value", + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSUnknowKeyword", + "start": { + "row": 2, + "col": 27, + "index": 36 + }, + "end": { + "row": 2, + "col": 34, + "index": 43 + } + }, + "start": { + "row": 2, + "col": 25, + "index": 34 + }, + "end": { + "row": 2, + "col": 34, + "index": 43 + } + }, + "optional": false, + "start": { + "row": 2, + "col": 20, + "index": 29 + }, + "end": { + "row": 2, + "col": 25, + "index": 34 + } + } + ], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSTypePredicate", + "parameterName": { + "kind": "Identifer", + "name": "value", + "start": { + "row": 2, + "col": 45, + "index": 54 + }, + "end": { + "row": 2, + "col": 50, + "index": 59 + } + }, + "asserts": true, + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSStringKeyword", + "start": { + "row": 2, + "col": 54, + "index": 63 + }, + "end": { + "row": 2, + "col": 60, + "index": 69 + } + }, + "start": { + "row": 2, + "col": 54, + "index": 63 + }, + "end": { + "row": 2, + "col": 60, + "index": 69 + } + }, + "start": { + "row": 2, + "col": 35, + "index": 44 + }, + "end": { + "row": 2, + "col": 60, + "index": 69 + } + }, + "start": { + "row": 2, + "col": 35, + "index": 44 + }, + "end": { + "row": 2, + "col": 60, + "index": 69 + } + }, + "body": { + "kind": "FunctionBody", + "body": [], + "start": { + "row": 2, + "col": 61, + "index": 70 + }, + "end": { + "row": 2, + "col": 63, + "index": 72 + } + }, + "decorators": null, + "start": { + "row": 2, + "col": 5, + "index": 14 + }, + "end": { + "row": 2, + "col": 63, + "index": 72 + } + } + ], + "start": { + "row": 1, + "col": 9, + "index": 8 + }, + "end": { + "row": 3, + "col": 2, + "index": 74 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 3, + "col": 2, + "index": 74 + }, + "decorators": null + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 4, + "col": 3, + "index": 77 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/function-declaration-with-line-break/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/function-declaration-with-line-break/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/function-declaration-with-line-break/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/function-declaration-with-line-break/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/function-declaration-with-line-break/input.ts new file mode 100644 index 00000000..404da1ba --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/function-declaration-with-line-break/input.ts @@ -0,0 +1,2 @@ +function assert(condition: any): +asserts condition {} diff --git a/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/function-declaration-with-line-break/output.json b/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/function-declaration-with-line-break/output.json new file mode 100644 index 00000000..0f866e7e --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/function-declaration-with-line-break/output.json @@ -0,0 +1,142 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "FunctionDeclaration", + "name": { + "kind": "Identifer", + "name": "assert", + "start": { + "row": 1, + "col": 10, + "index": 9 + }, + "end": { + "row": 1, + "col": 16, + "index": 15 + } + }, + "generator": false, + "async": false, + "body": { + "kind": "FunctionBody", + "body": [], + "start": { + "row": 2, + "col": 19, + "index": 51 + }, + "end": { + "row": 2, + "col": 21, + "index": 53 + } + }, + "params": [ + { + "kind": "Identifer", + "name": "condition", + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSAnyKeyword", + "start": { + "row": 1, + "col": 28, + "index": 27 + }, + "end": { + "row": 1, + "col": 31, + "index": 30 + } + }, + "start": { + "row": 1, + "col": 26, + "index": 25 + }, + "end": { + "row": 1, + "col": 31, + "index": 30 + } + }, + "optional": false, + "start": { + "row": 1, + "col": 17, + "index": 16 + }, + "end": { + "row": 1, + "col": 26, + "index": 25 + } + } + ], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSTypePredicate", + "parameterName": { + "kind": "Identifer", + "name": "condition", + "start": { + "row": 2, + "col": 9, + "index": 41 + }, + "end": { + "row": 2, + "col": 18, + "index": 50 + } + }, + "asserts": true, + "start": { + "row": 1, + "col": 32, + "index": 31 + }, + "end": { + "row": 2, + "col": 18, + "index": 50 + } + }, + "start": { + "row": 1, + "col": 32, + "index": 31 + }, + "end": { + "row": 2, + "col": 18, + "index": 50 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 21, + "index": 53 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 3, + "col": 1, + "index": 54 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/function-declaration/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/function-declaration/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/function-declaration/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/function-declaration/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/function-declaration/input.ts new file mode 100644 index 00000000..b04da834 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/function-declaration/input.ts @@ -0,0 +1,3 @@ +function asserts1 (value: unknown): asserts value is string {} +function asserts2 (value: unknown): asserts value {} +function asserts3 (value: unknown): asserts {} diff --git a/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/function-declaration/output.json b/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/function-declaration/output.json new file mode 100644 index 00000000..0fecc8f6 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/assert-predicate/function-declaration/output.json @@ -0,0 +1,421 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "FunctionDeclaration", + "name": { + "kind": "Identifer", + "name": "asserts1", + "start": { + "row": 1, + "col": 10, + "index": 9 + }, + "end": { + "row": 1, + "col": 18, + "index": 17 + } + }, + "generator": false, + "async": false, + "body": { + "kind": "FunctionBody", + "body": [], + "start": { + "row": 1, + "col": 61, + "index": 60 + }, + "end": { + "row": 1, + "col": 63, + "index": 62 + } + }, + "params": [ + { + "kind": "Identifer", + "name": "value", + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSUnknowKeyword", + "start": { + "row": 1, + "col": 27, + "index": 26 + }, + "end": { + "row": 1, + "col": 34, + "index": 33 + } + }, + "start": { + "row": 1, + "col": 25, + "index": 24 + }, + "end": { + "row": 1, + "col": 34, + "index": 33 + } + }, + "optional": false, + "start": { + "row": 1, + "col": 20, + "index": 19 + }, + "end": { + "row": 1, + "col": 25, + "index": 24 + } + } + ], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSTypePredicate", + "parameterName": { + "kind": "Identifer", + "name": "value", + "start": { + "row": 1, + "col": 45, + "index": 44 + }, + "end": { + "row": 1, + "col": 50, + "index": 49 + } + }, + "asserts": true, + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSStringKeyword", + "start": { + "row": 1, + "col": 54, + "index": 53 + }, + "end": { + "row": 1, + "col": 60, + "index": 59 + } + }, + "start": { + "row": 1, + "col": 54, + "index": 53 + }, + "end": { + "row": 1, + "col": 60, + "index": 59 + } + }, + "start": { + "row": 1, + "col": 35, + "index": 34 + }, + "end": { + "row": 1, + "col": 60, + "index": 59 + } + }, + "start": { + "row": 1, + "col": 35, + "index": 34 + }, + "end": { + "row": 1, + "col": 60, + "index": 59 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 63, + "index": 62 + } + }, + { + "kind": "FunctionDeclaration", + "name": { + "kind": "Identifer", + "name": "asserts2", + "start": { + "row": 2, + "col": 10, + "index": 73 + }, + "end": { + "row": 2, + "col": 18, + "index": 81 + } + }, + "generator": false, + "async": false, + "body": { + "kind": "FunctionBody", + "body": [], + "start": { + "row": 2, + "col": 51, + "index": 114 + }, + "end": { + "row": 2, + "col": 53, + "index": 116 + } + }, + "params": [ + { + "kind": "Identifer", + "name": "value", + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSUnknowKeyword", + "start": { + "row": 2, + "col": 27, + "index": 90 + }, + "end": { + "row": 2, + "col": 34, + "index": 97 + } + }, + "start": { + "row": 2, + "col": 25, + "index": 88 + }, + "end": { + "row": 2, + "col": 34, + "index": 97 + } + }, + "optional": false, + "start": { + "row": 2, + "col": 20, + "index": 83 + }, + "end": { + "row": 2, + "col": 25, + "index": 88 + } + } + ], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSTypePredicate", + "parameterName": { + "kind": "Identifer", + "name": "value", + "start": { + "row": 2, + "col": 45, + "index": 108 + }, + "end": { + "row": 2, + "col": 50, + "index": 113 + } + }, + "asserts": true, + "start": { + "row": 2, + "col": 35, + "index": 98 + }, + "end": { + "row": 2, + "col": 50, + "index": 113 + } + }, + "start": { + "row": 2, + "col": 35, + "index": 98 + }, + "end": { + "row": 2, + "col": 50, + "index": 113 + } + }, + "start": { + "row": 2, + "col": 1, + "index": 64 + }, + "end": { + "row": 2, + "col": 53, + "index": 116 + } + }, + { + "kind": "FunctionDeclaration", + "name": { + "kind": "Identifer", + "name": "asserts3", + "start": { + "row": 3, + "col": 10, + "index": 126 + }, + "end": { + "row": 3, + "col": 18, + "index": 134 + } + }, + "generator": false, + "async": false, + "body": { + "kind": "FunctionBody", + "body": [], + "start": { + "row": 3, + "col": 45, + "index": 161 + }, + "end": { + "row": 3, + "col": 47, + "index": 163 + } + }, + "params": [ + { + "kind": "Identifer", + "name": "value", + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSUnknowKeyword", + "start": { + "row": 3, + "col": 27, + "index": 143 + }, + "end": { + "row": 3, + "col": 34, + "index": 150 + } + }, + "start": { + "row": 3, + "col": 25, + "index": 141 + }, + "end": { + "row": 3, + "col": 34, + "index": 150 + } + }, + "optional": false, + "start": { + "row": 3, + "col": 20, + "index": 136 + }, + "end": { + "row": 3, + "col": 25, + "index": 141 + } + } + ], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "asserts", + "start": { + "row": 3, + "col": 37, + "index": 153 + }, + "end": { + "row": 3, + "col": 44, + "index": 160 + } + }, + "start": { + "row": 3, + "col": 37, + "index": 153 + }, + "end": { + "row": 3, + "col": 44, + "index": 160 + } + }, + "start": { + "row": 3, + "col": 35, + "index": 151 + }, + "end": { + "row": 3, + "col": 44, + "index": 160 + } + }, + "start": { + "row": 3, + "col": 1, + "index": 117 + }, + "end": { + "row": 3, + "col": 47, + "index": 163 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 4, + "col": 1, + "index": 164 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-async-parameter-as/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-async-parameter-as/expect.json new file mode 100644 index 00000000..e5936a86 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-async-parameter-as/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Failed", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-async-parameter-as/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-async-parameter-as/input.ts new file mode 100644 index 00000000..746078a2 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-async-parameter-as/input.ts @@ -0,0 +1 @@ +async (a as T) => {}; \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-async-parameter-as/output.txt b/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-async-parameter-as/output.txt new file mode 100644 index 00000000..a2761756 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-async-parameter-as/output.txt @@ -0,0 +1 @@ +[Syntax Error]: invalid assignment left-hand side (1, 19) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-async-parameter-assertion/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-async-parameter-assertion/expect.json new file mode 100644 index 00000000..e5936a86 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-async-parameter-assertion/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Failed", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-async-parameter-assertion/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-async-parameter-assertion/input.ts new file mode 100644 index 00000000..5e3f1481 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-async-parameter-assertion/input.ts @@ -0,0 +1 @@ +async ( a) => {}; \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-async-parameter-assertion/output.txt b/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-async-parameter-assertion/output.txt new file mode 100644 index 00000000..237c4223 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-async-parameter-assertion/output.txt @@ -0,0 +1 @@ +[Syntax Error]: invalid assignment left-hand side (1, 18) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-in-parens/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-in-parens/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-in-parens/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-in-parens/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-in-parens/input.ts new file mode 100644 index 00000000..f9f64497 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-in-parens/input.ts @@ -0,0 +1 @@ +var asserted1 = ((n) => { return n; }); diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-in-parens/output.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-in-parens/output.json new file mode 100644 index 00000000..3accb901 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-in-parens/output.json @@ -0,0 +1,160 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "VariableDeclaration", + "variant": "var", + "declarations": [ + { + "kind": "VariableDeclarator", + "id": { + "kind": "Identifer", + "name": "asserted1", + "optional": false, + "start": { + "row": 1, + "col": 5, + "index": 4 + }, + "end": { + "row": 1, + "col": 14, + "index": 13 + } + }, + "init": { + "kind": "TSTypeAssertionExpression", + "expression": { + "kind": "ArrowFunctionExpression", + "expressionBody": false, + "async": false, + "arguments": [ + { + "kind": "Identifer", + "name": "n", + "optional": false, + "start": { + "row": 1, + "col": 24, + "index": 23 + }, + "end": { + "row": 1, + "col": 25, + "index": 24 + } + } + ], + "body": { + "kind": "FunctionBody", + "body": [ + { + "kind": "ReturnStatement", + "argu": { + "kind": "Identifer", + "name": "n", + "start": { + "row": 1, + "col": 39, + "index": 38 + }, + "end": { + "row": 1, + "col": 40, + "index": 39 + } + }, + "start": { + "row": 1, + "col": 32, + "index": 31 + }, + "end": { + "row": 1, + "col": 40, + "index": 39 + } + } + ], + "start": { + "row": 1, + "col": 30, + "index": 29 + }, + "end": { + "row": 1, + "col": 43, + "index": 42 + } + }, + "start": { + "row": 1, + "col": 23, + "index": 22 + }, + "end": { + "row": 1, + "col": 43, + "index": 42 + }, + "parentheses": true + }, + "typeAnnotation": { + "kind": "TSAnyKeyword", + "start": { + "row": 1, + "col": 18, + "index": 17 + }, + "end": { + "row": 1, + "col": 21, + "index": 20 + } + }, + "start": { + "row": 1, + "col": 17, + "index": 16 + }, + "end": { + "row": 1, + "col": 44, + "index": 43 + } + }, + "start": { + "row": 1, + "col": 5, + "index": 4 + }, + "end": { + "row": 1, + "col": 44, + "index": 43 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 44, + "index": 43 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 45 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-parameter-as/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-parameter-as/expect.json new file mode 100644 index 00000000..e5936a86 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-parameter-as/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Failed", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-parameter-as/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-parameter-as/input.ts new file mode 100644 index 00000000..dc2282c6 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-parameter-as/input.ts @@ -0,0 +1 @@ +(a as T) => {}; \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-parameter-as/output.txt b/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-parameter-as/output.txt new file mode 100644 index 00000000..703cb79b --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-parameter-as/output.txt @@ -0,0 +1 @@ +[Syntax Error]: invalid assignment left-hand side (1, 13) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-parameter-assertion/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-parameter-assertion/expect.json new file mode 100644 index 00000000..e5936a86 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-parameter-assertion/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Failed", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-parameter-assertion/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-parameter-assertion/input.ts new file mode 100644 index 00000000..39dae7d0 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-parameter-assertion/input.ts @@ -0,0 +1 @@ +( a) => {}; \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-parameter-assertion/output.txt b/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-parameter-assertion/output.txt new file mode 100644 index 00000000..b9bcb6e2 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/arrow-parameter-assertion/output.txt @@ -0,0 +1 @@ +[Syntax Error]: invalid assignment left-hand side (1, 12) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/as/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/as/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/as/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/as/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/cast/as/input.ts new file mode 100644 index 00000000..3d6627d1 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/as/input.ts @@ -0,0 +1,6 @@ +x as T; +x < y as boolean; // (x < y) as boolean; +x as boolean <= y; // (x as boolean) <= y; +x === 1 as number; // x === (1 as number); +x as any as T; +x as boolean ?? y; // (x as boolean) ?? y; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/as/output.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/as/output.json new file mode 100644 index 00000000..96f11b57 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/as/output.json @@ -0,0 +1,499 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "TSAsExpression", + "expression": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 2, + "index": 1 + } + }, + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 6, + "index": 5 + }, + "end": { + "row": 1, + "col": 7, + "index": 6 + } + }, + "start": { + "row": 1, + "col": 6, + "index": 5 + }, + "end": { + "row": 1, + "col": 7, + "index": 6 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 7, + "index": 6 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 7, + "index": 6 + } + }, + { + "kind": "ExpressionStatement", + "expr": { + "kind": "TSAsExpression", + "expression": { + "kind": "BinaryExpression", + "operator": "<", + "left": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 2, + "col": 1, + "index": 8 + }, + "end": { + "row": 2, + "col": 2, + "index": 9 + } + }, + "right": { + "kind": "Identifer", + "name": "y", + "start": { + "row": 2, + "col": 5, + "index": 12 + }, + "end": { + "row": 2, + "col": 6, + "index": 13 + } + }, + "start": { + "row": 2, + "col": 1, + "index": 8 + }, + "end": { + "row": 2, + "col": 6, + "index": 13 + } + }, + "typeAnnotation": { + "kind": "TSBooleanKeyword", + "start": { + "row": 2, + "col": 10, + "index": 17 + }, + "end": { + "row": 2, + "col": 17, + "index": 24 + } + }, + "start": { + "row": 2, + "col": 1, + "index": 8 + }, + "end": { + "row": 2, + "col": 17, + "index": 24 + } + }, + "start": { + "row": 2, + "col": 1, + "index": 8 + }, + "end": { + "row": 2, + "col": 17, + "index": 24 + } + }, + { + "kind": "ExpressionStatement", + "expr": { + "kind": "BinaryExpression", + "operator": "<=", + "left": { + "kind": "TSAsExpression", + "expression": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 3, + "col": 1, + "index": 49 + }, + "end": { + "row": 3, + "col": 2, + "index": 50 + } + }, + "typeAnnotation": { + "kind": "TSBooleanKeyword", + "start": { + "row": 3, + "col": 6, + "index": 54 + }, + "end": { + "row": 3, + "col": 13, + "index": 61 + } + }, + "start": { + "row": 3, + "col": 1, + "index": 49 + }, + "end": { + "row": 3, + "col": 13, + "index": 61 + } + }, + "right": { + "kind": "Identifer", + "name": "y", + "start": { + "row": 3, + "col": 17, + "index": 65 + }, + "end": { + "row": 3, + "col": 18, + "index": 66 + } + }, + "start": { + "row": 3, + "col": 1, + "index": 49 + }, + "end": { + "row": 3, + "col": 18, + "index": 66 + } + }, + "start": { + "row": 3, + "col": 1, + "index": 49 + }, + "end": { + "row": 3, + "col": 18, + "index": 66 + } + }, + { + "kind": "ExpressionStatement", + "expr": { + "kind": "TSAsExpression", + "expression": { + "kind": "BinaryExpression", + "operator": "===", + "left": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 4, + "col": 1, + "index": 92 + }, + "end": { + "row": 4, + "col": 2, + "index": 93 + } + }, + "right": { + "kind": "DecimalLiteral", + "rawValue": "1", + "start": { + "row": 4, + "col": 7, + "index": 98 + }, + "end": { + "row": 4, + "col": 8, + "index": 99 + } + }, + "start": { + "row": 4, + "col": 1, + "index": 92 + }, + "end": { + "row": 4, + "col": 8, + "index": 99 + } + }, + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 4, + "col": 12, + "index": 103 + }, + "end": { + "row": 4, + "col": 18, + "index": 109 + } + }, + "start": { + "row": 4, + "col": 1, + "index": 92 + }, + "end": { + "row": 4, + "col": 18, + "index": 109 + } + }, + "start": { + "row": 4, + "col": 1, + "index": 92 + }, + "end": { + "row": 4, + "col": 18, + "index": 109 + } + }, + { + "kind": "ExpressionStatement", + "expr": { + "kind": "TSAsExpression", + "expression": { + "kind": "TSAsExpression", + "expression": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 5, + "col": 1, + "index": 135 + }, + "end": { + "row": 5, + "col": 2, + "index": 136 + } + }, + "typeAnnotation": { + "kind": "TSAnyKeyword", + "start": { + "row": 5, + "col": 6, + "index": 140 + }, + "end": { + "row": 5, + "col": 9, + "index": 143 + } + }, + "start": { + "row": 5, + "col": 1, + "index": 135 + }, + "end": { + "row": 5, + "col": 9, + "index": 143 + } + }, + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 5, + "col": 13, + "index": 147 + }, + "end": { + "row": 5, + "col": 14, + "index": 148 + } + }, + "start": { + "row": 5, + "col": 13, + "index": 147 + }, + "end": { + "row": 5, + "col": 14, + "index": 148 + } + }, + "start": { + "row": 5, + "col": 1, + "index": 135 + }, + "end": { + "row": 5, + "col": 14, + "index": 148 + } + }, + "start": { + "row": 5, + "col": 1, + "index": 135 + }, + "end": { + "row": 5, + "col": 14, + "index": 148 + } + }, + { + "kind": "ExpressionStatement", + "expr": { + "kind": "BinaryExpression", + "operator": "??", + "left": { + "kind": "TSAsExpression", + "expression": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 6, + "col": 1, + "index": 150 + }, + "end": { + "row": 6, + "col": 2, + "index": 151 + } + }, + "typeAnnotation": { + "kind": "TSBooleanKeyword", + "start": { + "row": 6, + "col": 6, + "index": 155 + }, + "end": { + "row": 6, + "col": 13, + "index": 162 + } + }, + "start": { + "row": 6, + "col": 1, + "index": 150 + }, + "end": { + "row": 6, + "col": 13, + "index": 162 + } + }, + "right": { + "kind": "Identifer", + "name": "y", + "start": { + "row": 6, + "col": 17, + "index": 166 + }, + "end": { + "row": 6, + "col": 18, + "index": 167 + } + }, + "start": { + "row": 6, + "col": 1, + "index": 150 + }, + "end": { + "row": 6, + "col": 18, + "index": 167 + } + }, + "start": { + "row": 6, + "col": 1, + "index": 150 + }, + "end": { + "row": 6, + "col": 18, + "index": 167 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 7, + "col": 1, + "index": 193 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/assert-and-assign/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/assert-and-assign/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/assert-and-assign/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/assert-and-assign/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/cast/assert-and-assign/input.ts new file mode 100644 index 00000000..1e4413d4 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/assert-and-assign/input.ts @@ -0,0 +1,2 @@ +(a as number) = 42; +({ a: (b as any) = 2000 } = x); diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/assert-and-assign/output.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/assert-and-assign/output.json new file mode 100644 index 00000000..e0a4e496 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/assert-and-assign/output.json @@ -0,0 +1,251 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "AssigmentExpression", + "operator": "=", + "left": { + "kind": "TSAsExpression", + "expression": { + "kind": "Identifer", + "name": "a", + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 3, + "index": 2 + } + }, + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 13, + "index": 12 + } + }, + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 13, + "index": 12 + }, + "parentheses": true + }, + "right": { + "kind": "DecimalLiteral", + "rawValue": "42", + "start": { + "row": 1, + "col": 17, + "index": 16 + }, + "end": { + "row": 1, + "col": 19, + "index": 18 + } + }, + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 19, + "index": 18 + } + }, + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 19, + "index": 18 + } + }, + { + "kind": "ExpressionStatement", + "expr": { + "kind": "AssigmentExpression", + "operator": "=", + "left": { + "kind": "ObjectPattern", + "properties": [ + { + "kind": "ObjectPatternProperty", + "computed": false, + "shorted": false, + "key": { + "kind": "Identifer", + "name": "a", + "start": { + "row": 2, + "col": 4, + "index": 23 + }, + "end": { + "row": 2, + "col": 5, + "index": 24 + } + }, + "value": { + "kind": "AssigmentPattern", + "left": { + "kind": "TSAsExpression", + "expression": { + "kind": "Identifer", + "name": "b", + "start": { + "row": 2, + "col": 8, + "index": 27 + }, + "end": { + "row": 2, + "col": 9, + "index": 28 + } + }, + "typeAnnotation": { + "kind": "TSAnyKeyword", + "start": { + "row": 2, + "col": 13, + "index": 32 + }, + "end": { + "row": 2, + "col": 16, + "index": 35 + } + }, + "start": { + "row": 2, + "col": 8, + "index": 27 + }, + "end": { + "row": 2, + "col": 16, + "index": 35 + }, + "parentheses": true + }, + "right": { + "kind": "DecimalLiteral", + "rawValue": "2000", + "start": { + "row": 2, + "col": 20, + "index": 39 + }, + "end": { + "row": 2, + "col": 24, + "index": 43 + } + }, + "start": { + "row": 2, + "col": 8, + "index": 27 + }, + "end": { + "row": 2, + "col": 24, + "index": 43 + } + }, + "start": { + "row": 2, + "col": 4, + "index": 23 + }, + "end": { + "row": 2, + "col": 24, + "index": 43 + } + } + ], + "start": { + "row": 2, + "col": 2, + "index": 21 + }, + "end": { + "row": 2, + "col": 26, + "index": 45 + } + }, + "right": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 2, + "col": 29, + "index": 48 + }, + "end": { + "row": 2, + "col": 30, + "index": 49 + } + }, + "start": { + "row": 2, + "col": 2, + "index": 21 + }, + "end": { + "row": 2, + "col": 30, + "index": 49 + }, + "parentheses": true + }, + "start": { + "row": 2, + "col": 2, + "index": 21 + }, + "end": { + "row": 2, + "col": 30, + "index": 49 + } + } + ], + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 3, + "col": 1, + "index": 52 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/destructure-and-assign/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/destructure-and-assign/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/destructure-and-assign/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/destructure-and-assign/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/cast/destructure-and-assign/input.ts new file mode 100644 index 00000000..ece9096f --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/destructure-and-assign/input.ts @@ -0,0 +1,2 @@ +[a as number] = [42]; +[a] = [42]; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/destructure-and-assign/output.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/destructure-and-assign/output.json new file mode 100644 index 00000000..19a76a57 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/destructure-and-assign/output.json @@ -0,0 +1,239 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "AssigmentExpression", + "operator": "=", + "left": { + "kind": "ArrayPattern", + "elements": [ + { + "kind": "TSAsExpression", + "expression": { + "kind": "Identifer", + "name": "a", + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 3, + "index": 2 + } + }, + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 13, + "index": 12 + } + }, + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 13, + "index": 12 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 14, + "index": 13 + } + }, + "right": { + "kind": "ArrayExpression", + "elements": [ + { + "kind": "DecimalLiteral", + "rawValue": "42", + "start": { + "row": 1, + "col": 18, + "index": 17 + }, + "end": { + "row": 1, + "col": 20, + "index": 19 + } + } + ], + "trailingComma": false, + "start": { + "row": 1, + "col": 17, + "index": 16 + }, + "end": { + "row": 1, + "col": 21, + "index": 20 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 21, + "index": 20 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 21, + "index": 20 + } + }, + { + "kind": "ExpressionStatement", + "expr": { + "kind": "AssigmentExpression", + "operator": "=", + "left": { + "kind": "ArrayPattern", + "elements": [ + { + "kind": "TSTypeAssertionExpression", + "expression": { + "kind": "Identifer", + "name": "a", + "start": { + "row": 2, + "col": 10, + "index": 31 + }, + "end": { + "row": 2, + "col": 11, + "index": 32 + } + }, + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 2, + "col": 3, + "index": 24 + }, + "end": { + "row": 2, + "col": 9, + "index": 30 + } + }, + "start": { + "row": 2, + "col": 2, + "index": 23 + }, + "end": { + "row": 2, + "col": 11, + "index": 32 + } + } + ], + "start": { + "row": 2, + "col": 1, + "index": 22 + }, + "end": { + "row": 2, + "col": 12, + "index": 33 + } + }, + "right": { + "kind": "ArrayExpression", + "elements": [ + { + "kind": "DecimalLiteral", + "rawValue": "42", + "start": { + "row": 2, + "col": 16, + "index": 37 + }, + "end": { + "row": 2, + "col": 18, + "index": 39 + } + } + ], + "trailingComma": false, + "start": { + "row": 2, + "col": 15, + "index": 36 + }, + "end": { + "row": 2, + "col": 19, + "index": 40 + } + }, + "start": { + "row": 2, + "col": 1, + "index": 22 + }, + "end": { + "row": 2, + "col": 19, + "index": 40 + } + }, + "start": { + "row": 2, + "col": 1, + "index": 22 + }, + "end": { + "row": 2, + "col": 19, + "index": 40 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 3, + "col": 1, + "index": 42 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/destructuring-assignent-rest-invalid/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/destructuring-assignent-rest-invalid/expect.json new file mode 100644 index 00000000..e5936a86 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/destructuring-assignent-rest-invalid/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Failed", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/destructuring-assignent-rest-invalid/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/cast/destructuring-assignent-rest-invalid/input.ts new file mode 100644 index 00000000..3946f7f0 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/destructuring-assignent-rest-invalid/input.ts @@ -0,0 +1,5 @@ +0, { ...{} as T} = b; +[...[] as T] = b; + +0, { ...({} as T)} = b; +[...([] as T)] = b; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/destructuring-assignent-rest-invalid/output.txt b/web-infras/parser/tests/fixtures/babel/typescript/cast/destructuring-assignent-rest-invalid/output.txt new file mode 100644 index 00000000..dd81d85a --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/destructuring-assignent-rest-invalid/output.txt @@ -0,0 +1,12 @@ +[SyntaxError]: `...` must be followed by an assignable reference in assignment contexts (1,9) +1|0, { ...{} as T} = b; + | ^ +[SyntaxError]: Invalid parenthesized assignment pattern. (4,10) +4|0, { ...({} as T)} = b; + | ^ +[SyntaxError]: `...` must be followed by an assignable reference in assignment contexts (4,10) +4|0, { ...({} as T)} = b; + | ^ +[SyntaxError]: Invalid parenthesized assignment pattern. (5,6) +5|[...([] as T)] = b; + | ^ diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/destructuring-assignment-in-parens/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/destructuring-assignment-in-parens/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/destructuring-assignment-in-parens/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/destructuring-assignment-in-parens/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/cast/destructuring-assignment-in-parens/input.ts new file mode 100644 index 00000000..bd876102 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/destructuring-assignment-in-parens/input.ts @@ -0,0 +1,7 @@ +({a: x as T} = b); +([a as T] = b); +({a: (x as T) = c} = b); +([(a as T) = c] = b); +({ ...a as T} = b); +([...a as T] = b); +({...x!} = y); diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/destructuring-assignment-in-parens/output.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/destructuring-assignment-in-parens/output.json new file mode 100644 index 00000000..590474b1 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/destructuring-assignment-in-parens/output.json @@ -0,0 +1,918 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "AssigmentExpression", + "operator": "=", + "left": { + "kind": "ObjectPattern", + "properties": [ + { + "kind": "ObjectPatternProperty", + "computed": false, + "shorted": false, + "key": { + "kind": "Identifer", + "name": "a", + "start": { + "row": 1, + "col": 3, + "index": 2 + }, + "end": { + "row": 1, + "col": 4, + "index": 3 + } + }, + "value": { + "kind": "TSAsExpression", + "expression": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 1, + "col": 6, + "index": 5 + }, + "end": { + "row": 1, + "col": 7, + "index": 6 + } + }, + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + }, + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + }, + "start": { + "row": 1, + "col": 6, + "index": 5 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + }, + "start": { + "row": 1, + "col": 3, + "index": 2 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + } + ], + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 13, + "index": 12 + } + }, + "right": { + "kind": "Identifer", + "name": "b", + "start": { + "row": 1, + "col": 16, + "index": 15 + }, + "end": { + "row": 1, + "col": 17, + "index": 16 + } + }, + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 17, + "index": 16 + }, + "parentheses": true + }, + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 17, + "index": 16 + } + }, + { + "kind": "ExpressionStatement", + "expr": { + "kind": "AssigmentExpression", + "operator": "=", + "left": { + "kind": "ArrayPattern", + "elements": [ + { + "kind": "TSAsExpression", + "expression": { + "kind": "Identifer", + "name": "a", + "start": { + "row": 2, + "col": 3, + "index": 21 + }, + "end": { + "row": 2, + "col": 4, + "index": 22 + } + }, + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 2, + "col": 8, + "index": 26 + }, + "end": { + "row": 2, + "col": 9, + "index": 27 + } + }, + "start": { + "row": 2, + "col": 8, + "index": 26 + }, + "end": { + "row": 2, + "col": 9, + "index": 27 + } + }, + "start": { + "row": 2, + "col": 3, + "index": 21 + }, + "end": { + "row": 2, + "col": 9, + "index": 27 + } + } + ], + "start": { + "row": 2, + "col": 2, + "index": 20 + }, + "end": { + "row": 2, + "col": 10, + "index": 28 + } + }, + "right": { + "kind": "Identifer", + "name": "b", + "start": { + "row": 2, + "col": 13, + "index": 31 + }, + "end": { + "row": 2, + "col": 14, + "index": 32 + } + }, + "start": { + "row": 2, + "col": 2, + "index": 20 + }, + "end": { + "row": 2, + "col": 14, + "index": 32 + }, + "parentheses": true + }, + "start": { + "row": 2, + "col": 2, + "index": 20 + }, + "end": { + "row": 2, + "col": 14, + "index": 32 + } + }, + { + "kind": "ExpressionStatement", + "expr": { + "kind": "AssigmentExpression", + "operator": "=", + "left": { + "kind": "ObjectPattern", + "properties": [ + { + "kind": "ObjectPatternProperty", + "computed": false, + "shorted": false, + "key": { + "kind": "Identifer", + "name": "a", + "start": { + "row": 3, + "col": 3, + "index": 37 + }, + "end": { + "row": 3, + "col": 4, + "index": 38 + } + }, + "value": { + "kind": "AssigmentPattern", + "left": { + "kind": "TSAsExpression", + "expression": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 3, + "col": 7, + "index": 41 + }, + "end": { + "row": 3, + "col": 8, + "index": 42 + } + }, + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 3, + "col": 12, + "index": 46 + }, + "end": { + "row": 3, + "col": 13, + "index": 47 + } + }, + "start": { + "row": 3, + "col": 12, + "index": 46 + }, + "end": { + "row": 3, + "col": 13, + "index": 47 + } + }, + "start": { + "row": 3, + "col": 7, + "index": 41 + }, + "end": { + "row": 3, + "col": 13, + "index": 47 + }, + "parentheses": true + }, + "right": { + "kind": "Identifer", + "name": "c", + "start": { + "row": 3, + "col": 17, + "index": 51 + }, + "end": { + "row": 3, + "col": 18, + "index": 52 + } + }, + "start": { + "row": 3, + "col": 7, + "index": 41 + }, + "end": { + "row": 3, + "col": 18, + "index": 52 + } + }, + "start": { + "row": 3, + "col": 3, + "index": 37 + }, + "end": { + "row": 3, + "col": 18, + "index": 52 + } + } + ], + "start": { + "row": 3, + "col": 2, + "index": 36 + }, + "end": { + "row": 3, + "col": 19, + "index": 53 + } + }, + "right": { + "kind": "Identifer", + "name": "b", + "start": { + "row": 3, + "col": 22, + "index": 56 + }, + "end": { + "row": 3, + "col": 23, + "index": 57 + } + }, + "start": { + "row": 3, + "col": 2, + "index": 36 + }, + "end": { + "row": 3, + "col": 23, + "index": 57 + }, + "parentheses": true + }, + "start": { + "row": 3, + "col": 2, + "index": 36 + }, + "end": { + "row": 3, + "col": 23, + "index": 57 + } + }, + { + "kind": "ExpressionStatement", + "expr": { + "kind": "AssigmentExpression", + "operator": "=", + "left": { + "kind": "ArrayPattern", + "elements": [ + { + "kind": "AssigmentPattern", + "left": { + "kind": "TSAsExpression", + "expression": { + "kind": "Identifer", + "name": "a", + "start": { + "row": 4, + "col": 4, + "index": 63 + }, + "end": { + "row": 4, + "col": 5, + "index": 64 + } + }, + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 4, + "col": 9, + "index": 68 + }, + "end": { + "row": 4, + "col": 10, + "index": 69 + } + }, + "start": { + "row": 4, + "col": 9, + "index": 68 + }, + "end": { + "row": 4, + "col": 10, + "index": 69 + } + }, + "start": { + "row": 4, + "col": 4, + "index": 63 + }, + "end": { + "row": 4, + "col": 10, + "index": 69 + }, + "parentheses": true + }, + "right": { + "kind": "Identifer", + "name": "c", + "start": { + "row": 4, + "col": 14, + "index": 73 + }, + "end": { + "row": 4, + "col": 15, + "index": 74 + } + }, + "start": { + "row": 4, + "col": 4, + "index": 63 + }, + "end": { + "row": 4, + "col": 15, + "index": 74 + } + } + ], + "start": { + "row": 4, + "col": 2, + "index": 61 + }, + "end": { + "row": 4, + "col": 16, + "index": 75 + } + }, + "right": { + "kind": "Identifer", + "name": "b", + "start": { + "row": 4, + "col": 19, + "index": 78 + }, + "end": { + "row": 4, + "col": 20, + "index": 79 + } + }, + "start": { + "row": 4, + "col": 2, + "index": 61 + }, + "end": { + "row": 4, + "col": 20, + "index": 79 + }, + "parentheses": true + }, + "start": { + "row": 4, + "col": 2, + "index": 61 + }, + "end": { + "row": 4, + "col": 20, + "index": 79 + } + }, + { + "kind": "ExpressionStatement", + "expr": { + "kind": "AssigmentExpression", + "operator": "=", + "left": { + "kind": "ObjectPattern", + "properties": [ + { + "kind": "RestElement", + "argument": { + "kind": "TSAsExpression", + "expression": { + "kind": "Identifer", + "name": "a", + "start": { + "row": 5, + "col": 7, + "index": 88 + }, + "end": { + "row": 5, + "col": 8, + "index": 89 + } + }, + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 5, + "col": 12, + "index": 93 + }, + "end": { + "row": 5, + "col": 13, + "index": 94 + } + }, + "start": { + "row": 5, + "col": 12, + "index": 93 + }, + "end": { + "row": 5, + "col": 13, + "index": 94 + } + }, + "start": { + "row": 5, + "col": 7, + "index": 88 + }, + "end": { + "row": 5, + "col": 13, + "index": 94 + } + }, + "start": { + "row": 5, + "col": 4, + "index": 85 + }, + "end": { + "row": 5, + "col": 13, + "index": 94 + } + } + ], + "start": { + "row": 5, + "col": 2, + "index": 83 + }, + "end": { + "row": 5, + "col": 14, + "index": 95 + } + }, + "right": { + "kind": "Identifer", + "name": "b", + "start": { + "row": 5, + "col": 17, + "index": 98 + }, + "end": { + "row": 5, + "col": 18, + "index": 99 + } + }, + "start": { + "row": 5, + "col": 2, + "index": 83 + }, + "end": { + "row": 5, + "col": 18, + "index": 99 + }, + "parentheses": true + }, + "start": { + "row": 5, + "col": 2, + "index": 83 + }, + "end": { + "row": 5, + "col": 18, + "index": 99 + } + }, + { + "kind": "ExpressionStatement", + "expr": { + "kind": "AssigmentExpression", + "operator": "=", + "left": { + "kind": "ArrayPattern", + "elements": [ + { + "kind": "RestElement", + "argument": { + "kind": "TSAsExpression", + "expression": { + "kind": "Identifer", + "name": "a", + "start": { + "row": 6, + "col": 6, + "index": 107 + }, + "end": { + "row": 6, + "col": 7, + "index": 108 + } + }, + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 6, + "col": 11, + "index": 112 + }, + "end": { + "row": 6, + "col": 12, + "index": 113 + } + }, + "start": { + "row": 6, + "col": 11, + "index": 112 + }, + "end": { + "row": 6, + "col": 12, + "index": 113 + } + }, + "start": { + "row": 6, + "col": 6, + "index": 107 + }, + "end": { + "row": 6, + "col": 12, + "index": 113 + } + }, + "start": { + "row": 6, + "col": 3, + "index": 104 + }, + "end": { + "row": 6, + "col": 12, + "index": 113 + } + } + ], + "start": { + "row": 6, + "col": 2, + "index": 103 + }, + "end": { + "row": 6, + "col": 13, + "index": 114 + } + }, + "right": { + "kind": "Identifer", + "name": "b", + "start": { + "row": 6, + "col": 16, + "index": 117 + }, + "end": { + "row": 6, + "col": 17, + "index": 118 + } + }, + "start": { + "row": 6, + "col": 2, + "index": 103 + }, + "end": { + "row": 6, + "col": 17, + "index": 118 + }, + "parentheses": true + }, + "start": { + "row": 6, + "col": 2, + "index": 103 + }, + "end": { + "row": 6, + "col": 17, + "index": 118 + } + }, + { + "kind": "ExpressionStatement", + "expr": { + "kind": "AssigmentExpression", + "operator": "=", + "left": { + "kind": "ObjectPattern", + "properties": [ + { + "kind": "RestElement", + "argument": { + "kind": 10255, + "expression": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 7, + "col": 6, + "index": 126 + }, + "end": { + "row": 7, + "col": 7, + "index": 127 + } + }, + "start": { + "row": 7, + "col": 6, + "index": 126 + }, + "end": { + "row": 7, + "col": 8, + "index": 128 + } + }, + "start": { + "row": 7, + "col": 3, + "index": 123 + }, + "end": { + "row": 7, + "col": 8, + "index": 128 + } + } + ], + "start": { + "row": 7, + "col": 2, + "index": 122 + }, + "end": { + "row": 7, + "col": 9, + "index": 129 + } + }, + "right": { + "kind": "Identifer", + "name": "y", + "start": { + "row": 7, + "col": 12, + "index": 132 + }, + "end": { + "row": 7, + "col": 13, + "index": 133 + } + }, + "start": { + "row": 7, + "col": 2, + "index": 122 + }, + "end": { + "row": 7, + "col": 13, + "index": 133 + }, + "parentheses": true + }, + "start": { + "row": 7, + "col": 2, + "index": 122 + }, + "end": { + "row": 7, + "col": 13, + "index": 133 + } + } + ], + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 8, + "col": 1, + "index": 136 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/false-positive/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/false-positive/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/false-positive/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/false-positive/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/cast/false-positive/input.ts new file mode 100644 index 00000000..51f9677f --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/false-positive/input.ts @@ -0,0 +1 @@ +f(x < 0, /a/); diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/false-positive/output.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/false-positive/output.json new file mode 100644 index 00000000..29dbb503 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/false-positive/output.json @@ -0,0 +1,115 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "CallExpression", + "optional": false, + "callee": { + "kind": "Identifer", + "name": "f", + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 2, + "index": 1 + } + }, + "arguments": [ + { + "kind": "BinaryExpression", + "operator": "<", + "left": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 1, + "col": 3, + "index": 2 + }, + "end": { + "row": 1, + "col": 4, + "index": 3 + } + }, + "right": { + "kind": "DecimalLiteral", + "rawValue": "0", + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 8, + "index": 7 + } + }, + "start": { + "row": 1, + "col": 3, + "index": 2 + }, + "end": { + "row": 1, + "col": 8, + "index": 7 + } + }, + { + "kind": "RegexLiteral", + "pattern": "a", + "flag": "", + "start": { + "row": 1, + "col": 10, + "index": 9 + }, + "end": { + "row": 1, + "col": 14, + "index": 13 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 14, + "index": 13 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 14, + "index": 13 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 15 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/for-of-lhs/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/for-of-lhs/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/for-of-lhs/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/for-of-lhs/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/cast/for-of-lhs/input.ts new file mode 100644 index 00000000..63549667 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/for-of-lhs/input.ts @@ -0,0 +1,2 @@ +for (a as T of []); +for ( a of []); diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/for-of-lhs/output.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/for-of-lhs/output.json new file mode 100644 index 00000000..28832c7f --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/for-of-lhs/output.json @@ -0,0 +1,207 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ForOfStatement", + "await": false, + "left": { + "kind": "TSAsExpression", + "expression": { + "kind": "Identifer", + "name": "a", + "start": { + "row": 1, + "col": 6, + "index": 5 + }, + "end": { + "row": 1, + "col": 7, + "index": 6 + } + }, + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + }, + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + }, + "start": { + "row": 1, + "col": 6, + "index": 5 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + }, + "right": { + "kind": "ArrayExpression", + "elements": [], + "trailingComma": false, + "start": { + "row": 1, + "col": 16, + "index": 15 + }, + "end": { + "row": 1, + "col": 18, + "index": 17 + } + }, + "body": { + "kind": "EmptyStatement", + "start": { + "row": 1, + "col": 19, + "index": 18 + }, + "end": { + "row": 1, + "col": 20, + "index": 19 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 20, + "index": 19 + } + }, + { + "kind": "ForOfStatement", + "await": false, + "left": { + "kind": "TSTypeAssertionExpression", + "expression": { + "kind": "Identifer", + "name": "a", + "start": { + "row": 2, + "col": 10, + "index": 29 + }, + "end": { + "row": 2, + "col": 11, + "index": 30 + } + }, + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 2, + "col": 7, + "index": 26 + }, + "end": { + "row": 2, + "col": 8, + "index": 27 + } + }, + "start": { + "row": 2, + "col": 7, + "index": 26 + }, + "end": { + "row": 2, + "col": 8, + "index": 27 + } + }, + "start": { + "row": 2, + "col": 6, + "index": 25 + }, + "end": { + "row": 2, + "col": 11, + "index": 30 + } + }, + "right": { + "kind": "ArrayExpression", + "elements": [], + "trailingComma": false, + "start": { + "row": 2, + "col": 15, + "index": 34 + }, + "end": { + "row": 2, + "col": 17, + "index": 36 + } + }, + "body": { + "kind": "EmptyStatement", + "start": { + "row": 2, + "col": 18, + "index": 37 + }, + "end": { + "row": 2, + "col": 19, + "index": 38 + } + }, + "start": { + "row": 2, + "col": 1, + "index": 20 + }, + "end": { + "row": 2, + "col": 19, + "index": 38 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 3, + "col": 1, + "index": 39 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/invalid/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/invalid/expect.json new file mode 100644 index 00000000..e5936a86 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/invalid/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Failed", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/invalid/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/cast/invalid/input.ts new file mode 100644 index 00000000..517b1675 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/invalid/input.ts @@ -0,0 +1,4 @@ +(a:b); +(a:b,c:d); +[a:b]; +[a:b, c:d]; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/invalid/output.txt b/web-infras/parser/tests/fixtures/babel/typescript/cast/invalid/output.txt new file mode 100644 index 00000000..0d756d13 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/invalid/output.txt @@ -0,0 +1 @@ +[Syntax Error]: Unexpect token :(3, 3). \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/multiple-assert-and-assign/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/multiple-assert-and-assign/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/multiple-assert-and-assign/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/multiple-assert-and-assign/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/cast/multiple-assert-and-assign/input.ts new file mode 100644 index 00000000..c35da37d --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/multiple-assert-and-assign/input.ts @@ -0,0 +1 @@ +(a as number as any) = 42; \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/multiple-assert-and-assign/output.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/multiple-assert-and-assign/output.json new file mode 100644 index 00000000..562c5a80 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/multiple-assert-and-assign/output.json @@ -0,0 +1,123 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "AssigmentExpression", + "operator": "=", + "left": { + "kind": "TSAsExpression", + "expression": { + "kind": "TSAsExpression", + "expression": { + "kind": "Identifer", + "name": "a", + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 3, + "index": 2 + } + }, + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 13, + "index": 12 + } + }, + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 13, + "index": 12 + } + }, + "typeAnnotation": { + "kind": "TSAnyKeyword", + "start": { + "row": 1, + "col": 17, + "index": 16 + }, + "end": { + "row": 1, + "col": 20, + "index": 19 + } + }, + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 20, + "index": 19 + }, + "parentheses": true + }, + "right": { + "kind": "DecimalLiteral", + "rawValue": "42", + "start": { + "row": 1, + "col": 24, + "index": 23 + }, + "end": { + "row": 1, + "col": 26, + "index": 25 + } + }, + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 26, + "index": 25 + } + }, + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 26, + "index": 25 + } + } + ], + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 27, + "index": 26 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/nested-parenthesized-assert-and-assign/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/nested-parenthesized-assert-and-assign/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/nested-parenthesized-assert-and-assign/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/nested-parenthesized-assert-and-assign/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/cast/nested-parenthesized-assert-and-assign/input.ts new file mode 100644 index 00000000..1b43aa2f --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/nested-parenthesized-assert-and-assign/input.ts @@ -0,0 +1 @@ +((a as any) as string) = null diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/nested-parenthesized-assert-and-assign/output.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/nested-parenthesized-assert-and-assign/output.json new file mode 100644 index 00000000..74ba51f8 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/nested-parenthesized-assert-and-assign/output.json @@ -0,0 +1,123 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "AssigmentExpression", + "operator": "=", + "left": { + "kind": "TSAsExpression", + "expression": { + "kind": "TSAsExpression", + "expression": { + "kind": "Identifer", + "name": "a", + "start": { + "row": 1, + "col": 3, + "index": 2 + }, + "end": { + "row": 1, + "col": 4, + "index": 3 + } + }, + "typeAnnotation": { + "kind": "TSAnyKeyword", + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 1, + "col": 11, + "index": 10 + } + }, + "start": { + "row": 1, + "col": 3, + "index": 2 + }, + "end": { + "row": 1, + "col": 11, + "index": 10 + }, + "parentheses": true + }, + "typeAnnotation": { + "kind": "TSStringKeyword", + "start": { + "row": 1, + "col": 16, + "index": 15 + }, + "end": { + "row": 1, + "col": 22, + "index": 21 + } + }, + "start": { + "row": 1, + "col": 3, + "index": 2 + }, + "end": { + "row": 1, + "col": 22, + "index": 21 + }, + "parentheses": true + }, + "right": { + "kind": "NullLiteral", + "start": { + "row": 1, + "col": 26, + "index": 25 + }, + "end": { + "row": 1, + "col": 30, + "index": 29 + } + }, + "start": { + "row": 1, + "col": 3, + "index": 2 + }, + "end": { + "row": 1, + "col": 30, + "index": 29 + } + }, + "start": { + "row": 1, + "col": 3, + "index": 2 + }, + "end": { + "row": 1, + "col": 30, + "index": 29 + } + } + ], + "start": { + "row": 1, + "col": 3, + "index": 2 + }, + "end": { + "row": 2, + "col": 1, + "index": 30 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-2/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-2/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-2/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-2/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-2/input.ts new file mode 100644 index 00000000..29cb0c03 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-2/input.ts @@ -0,0 +1 @@ +x! / 2 diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-2/output.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-2/output.json new file mode 100644 index 00000000..62bc7b68 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-2/output.json @@ -0,0 +1,83 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "BinaryExpression", + "operator": "/", + "left": { + "kind": 10255, + "expression": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 2, + "index": 1 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 3, + "index": 2 + } + }, + "right": { + "kind": "DecimalLiteral", + "rawValue": "2", + "start": { + "row": 1, + "col": 6, + "index": 5 + }, + "end": { + "row": 1, + "col": 7, + "index": 6 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 7, + "index": 6 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 7, + "index": 6 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 7 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-3/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-3/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-3/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-3/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-3/input.ts new file mode 100644 index 00000000..759fd689 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-3/input.ts @@ -0,0 +1 @@ +const x = foo()!; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-3/output.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-3/output.json new file mode 100644 index 00000000..e825a3be --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-3/output.json @@ -0,0 +1,101 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "VariableDeclaration", + "variant": "const", + "declarations": [ + { + "kind": "VariableDeclarator", + "id": { + "kind": "Identifer", + "name": "x", + "optional": false, + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 8, + "index": 7 + } + }, + "init": { + "kind": 10255, + "expression": { + "kind": "CallExpression", + "optional": false, + "callee": { + "kind": "Identifer", + "name": "foo", + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 14, + "index": 13 + } + }, + "arguments": [], + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 16, + "index": 15 + } + }, + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 17, + "index": 16 + } + }, + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 17, + "index": 16 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 17, + "index": 16 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 18 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-and-assign-2/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-and-assign-2/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-and-assign-2/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-and-assign-2/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-and-assign-2/input.ts new file mode 100644 index 00000000..ae793d50 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-and-assign-2/input.ts @@ -0,0 +1 @@ +x! *= 1 diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-and-assign-2/output.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-and-assign-2/output.json new file mode 100644 index 00000000..4104b89f --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-and-assign-2/output.json @@ -0,0 +1,83 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "AssigmentExpression", + "operator": "*=", + "left": { + "kind": 10255, + "expression": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 2, + "index": 1 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 3, + "index": 2 + } + }, + "right": { + "kind": "DecimalLiteral", + "rawValue": "1", + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 8, + "index": 7 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 8, + "index": 7 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 8, + "index": 7 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 8 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-and-assign/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-and-assign/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-and-assign/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-and-assign/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-and-assign/input.ts new file mode 100644 index 00000000..da07f8ef --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-and-assign/input.ts @@ -0,0 +1 @@ +x! += 1; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-and-assign/output.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-and-assign/output.json new file mode 100644 index 00000000..c0468a5f --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-and-assign/output.json @@ -0,0 +1,83 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "AssigmentExpression", + "operator": "+=", + "left": { + "kind": 10255, + "expression": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 2, + "index": 1 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 3, + "index": 2 + } + }, + "right": { + "kind": "DecimalLiteral", + "rawValue": "1", + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 8, + "index": 7 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 8, + "index": 7 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 8, + "index": 7 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 9 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-and-relational/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-and-relational/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-and-relational/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-and-relational/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-and-relational/input.ts new file mode 100644 index 00000000..d60cf58b --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-and-relational/input.ts @@ -0,0 +1 @@ +x.v! < y.v!; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-and-relational/output.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-and-relational/output.json new file mode 100644 index 00000000..277f973d --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-and-relational/output.json @@ -0,0 +1,154 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "BinaryExpression", + "operator": "<", + "left": { + "kind": 10255, + "expression": { + "kind": "MemberExpression", + "computed": false, + "optional": false, + "object": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 2, + "index": 1 + } + }, + "property": { + "kind": "Identifer", + "name": "v", + "start": { + "row": 1, + "col": 3, + "index": 2 + }, + "end": { + "row": 1, + "col": 4, + "index": 3 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 4, + "index": 3 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 5, + "index": 4 + } + }, + "right": { + "kind": 10255, + "expression": { + "kind": "MemberExpression", + "computed": false, + "optional": false, + "object": { + "kind": "Identifer", + "name": "y", + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 1, + "col": 9, + "index": 8 + } + }, + "property": { + "kind": "Identifer", + "name": "v", + "start": { + "row": 1, + "col": 10, + "index": 9 + }, + "end": { + "row": 1, + "col": 11, + "index": 10 + } + }, + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 1, + "col": 11, + "index": 10 + } + }, + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 13 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-false-positive/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-false-positive/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-false-positive/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-false-positive/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-false-positive/input.ts new file mode 100644 index 00000000..0fce6886 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-false-positive/input.ts @@ -0,0 +1,2 @@ +a +!b diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-false-positive/output.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-false-positive/output.json new file mode 100644 index 00000000..736567b8 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-false-positive/output.json @@ -0,0 +1,83 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "Identifer", + "name": "a", + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 2, + "index": 1 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 2, + "index": 1 + } + }, + { + "kind": "ExpressionStatement", + "expr": { + "kind": "UnaryExpression", + "operator": "!", + "argument": { + "kind": "Identifer", + "name": "b", + "start": { + "row": 2, + "col": 2, + "index": 3 + }, + "end": { + "row": 2, + "col": 3, + "index": 4 + } + }, + "start": { + "row": 2, + "col": 1, + "index": 2 + }, + "end": { + "row": 2, + "col": 3, + "index": 4 + } + }, + "start": { + "row": 2, + "col": 1, + "index": 2 + }, + "end": { + "row": 2, + "col": 3, + "index": 4 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 3, + "col": 1, + "index": 5 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-invalid-arrow-param/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-invalid-arrow-param/expect.json new file mode 100644 index 00000000..e5936a86 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-invalid-arrow-param/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Failed", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-invalid-arrow-param/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-invalid-arrow-param/input.ts new file mode 100644 index 00000000..eeeabeef --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-invalid-arrow-param/input.ts @@ -0,0 +1,6 @@ +(a!) => b; +(a! = b) => c; +([a!]) => c; +({a: a!}) => c; +([...a!]) => c; +({...a!}) => c; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-invalid-arrow-param/output.txt b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-invalid-arrow-param/output.txt new file mode 100644 index 00000000..be22d978 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-invalid-arrow-param/output.txt @@ -0,0 +1 @@ +[Syntax Error]: invalid assignment left-hand side (1, 9) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-then-property-access/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-then-property-access/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-then-property-access/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-then-property-access/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-then-property-access/input.ts new file mode 100644 index 00000000..b89be6ad --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-then-property-access/input.ts @@ -0,0 +1 @@ +x!.y; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-then-property-access/output.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-then-property-access/output.json new file mode 100644 index 00000000..5166524f --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion-then-property-access/output.json @@ -0,0 +1,84 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "MemberExpression", + "computed": false, + "optional": false, + "object": { + "kind": 10255, + "expression": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 2, + "index": 1 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 3, + "index": 2 + } + }, + "property": { + "kind": "Identifer", + "name": "y", + "start": { + "row": 1, + "col": 4, + "index": 3 + }, + "end": { + "row": 1, + "col": 5, + "index": 4 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 5, + "index": 4 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 5, + "index": 4 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 6 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion/input.ts new file mode 100644 index 00000000..703cb104 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion/input.ts @@ -0,0 +1 @@ +x!; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion/output.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion/output.json new file mode 100644 index 00000000..0dd8496a --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/null-assertion/output.json @@ -0,0 +1,55 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": 10255, + "expression": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 2, + "index": 1 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 3, + "index": 2 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 3, + "index": 2 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 4 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/satisfies/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/satisfies/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/satisfies/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/satisfies/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/cast/satisfies/input.ts new file mode 100644 index 00000000..b3198b63 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/satisfies/input.ts @@ -0,0 +1,4 @@ +x satisfies T; +x < y satisfies boolean; // (x < y) satisfies boolean; +(a satisfies any) = null; +[(a satisfies any)] = b; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/satisfies/output.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/satisfies/output.json new file mode 100644 index 00000000..4d829357 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/satisfies/output.json @@ -0,0 +1,341 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "TSSatisfiesExpression", + "expression": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 2, + "index": 1 + } + }, + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 13, + "index": 12 + }, + "end": { + "row": 1, + "col": 14, + "index": 13 + } + }, + "start": { + "row": 1, + "col": 13, + "index": 12 + }, + "end": { + "row": 1, + "col": 14, + "index": 13 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 14, + "index": 13 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 14, + "index": 13 + } + }, + { + "kind": "ExpressionStatement", + "expr": { + "kind": "TSSatisfiesExpression", + "expression": { + "kind": "BinaryExpression", + "operator": "<", + "left": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 2, + "col": 1, + "index": 15 + }, + "end": { + "row": 2, + "col": 2, + "index": 16 + } + }, + "right": { + "kind": "Identifer", + "name": "y", + "start": { + "row": 2, + "col": 5, + "index": 19 + }, + "end": { + "row": 2, + "col": 6, + "index": 20 + } + }, + "start": { + "row": 2, + "col": 1, + "index": 15 + }, + "end": { + "row": 2, + "col": 6, + "index": 20 + } + }, + "typeAnnotation": { + "kind": "TSBooleanKeyword", + "start": { + "row": 2, + "col": 17, + "index": 31 + }, + "end": { + "row": 2, + "col": 24, + "index": 38 + } + }, + "start": { + "row": 2, + "col": 1, + "index": 15 + }, + "end": { + "row": 2, + "col": 24, + "index": 38 + } + }, + "start": { + "row": 2, + "col": 1, + "index": 15 + }, + "end": { + "row": 2, + "col": 24, + "index": 38 + } + }, + { + "kind": "ExpressionStatement", + "expr": { + "kind": "AssigmentExpression", + "operator": "=", + "left": { + "kind": "TSSatisfiesExpression", + "expression": { + "kind": "Identifer", + "name": "a", + "start": { + "row": 3, + "col": 2, + "index": 71 + }, + "end": { + "row": 3, + "col": 3, + "index": 72 + } + }, + "typeAnnotation": { + "kind": "TSAnyKeyword", + "start": { + "row": 3, + "col": 14, + "index": 83 + }, + "end": { + "row": 3, + "col": 17, + "index": 86 + } + }, + "start": { + "row": 3, + "col": 2, + "index": 71 + }, + "end": { + "row": 3, + "col": 17, + "index": 86 + }, + "parentheses": true + }, + "right": { + "kind": "NullLiteral", + "start": { + "row": 3, + "col": 21, + "index": 90 + }, + "end": { + "row": 3, + "col": 25, + "index": 94 + } + }, + "start": { + "row": 3, + "col": 2, + "index": 71 + }, + "end": { + "row": 3, + "col": 25, + "index": 94 + } + }, + "start": { + "row": 3, + "col": 2, + "index": 71 + }, + "end": { + "row": 3, + "col": 25, + "index": 94 + } + }, + { + "kind": "ExpressionStatement", + "expr": { + "kind": "AssigmentExpression", + "operator": "=", + "left": { + "kind": "ArrayPattern", + "elements": [ + { + "kind": "TSSatisfiesExpression", + "expression": { + "kind": "Identifer", + "name": "a", + "start": { + "row": 4, + "col": 3, + "index": 98 + }, + "end": { + "row": 4, + "col": 4, + "index": 99 + } + }, + "typeAnnotation": { + "kind": "TSAnyKeyword", + "start": { + "row": 4, + "col": 15, + "index": 110 + }, + "end": { + "row": 4, + "col": 18, + "index": 113 + } + }, + "start": { + "row": 4, + "col": 3, + "index": 98 + }, + "end": { + "row": 4, + "col": 18, + "index": 113 + }, + "parentheses": true + } + ], + "start": { + "row": 4, + "col": 1, + "index": 96 + }, + "end": { + "row": 4, + "col": 20, + "index": 115 + } + }, + "right": { + "kind": "Identifer", + "name": "b", + "start": { + "row": 4, + "col": 23, + "index": 118 + }, + "end": { + "row": 4, + "col": 24, + "index": 119 + } + }, + "start": { + "row": 4, + "col": 1, + "index": 96 + }, + "end": { + "row": 4, + "col": 24, + "index": 119 + } + }, + "start": { + "row": 4, + "col": 1, + "index": 96 + }, + "end": { + "row": 4, + "col": 24, + "index": 119 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 5, + "col": 1, + "index": 121 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion-after-operator/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion-after-operator/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion-after-operator/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion-after-operator/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion-after-operator/input.ts new file mode 100644 index 00000000..7286cf70 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion-after-operator/input.ts @@ -0,0 +1 @@ +1 + 1; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion-after-operator/output.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion-after-operator/output.json new file mode 100644 index 00000000..ac7d1ecf --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion-after-operator/output.json @@ -0,0 +1,96 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "BinaryExpression", + "operator": "+", + "left": { + "kind": "DecimalLiteral", + "rawValue": "1", + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 2, + "index": 1 + } + }, + "right": { + "kind": "TSTypeAssertionExpression", + "expression": { + "kind": "DecimalLiteral", + "rawValue": "1", + "start": { + "row": 1, + "col": 14, + "index": 13 + }, + "end": { + "row": 1, + "col": 15, + "index": 14 + } + }, + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 1, + "col": 6, + "index": 5 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + }, + "start": { + "row": 1, + "col": 5, + "index": 4 + }, + "end": { + "row": 1, + "col": 15, + "index": 14 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 15, + "index": 14 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 15, + "index": 14 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 16 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion-and-assign/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion-and-assign/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion-and-assign/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion-and-assign/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion-and-assign/input.ts new file mode 100644 index 00000000..25af2257 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion-and-assign/input.ts @@ -0,0 +1 @@ +( x) += 1; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion-and-assign/output.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion-and-assign/output.json new file mode 100644 index 00000000..9d429dfe --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion-and-assign/output.json @@ -0,0 +1,97 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "AssigmentExpression", + "operator": "+=", + "left": { + "kind": "TSTypeAssertionExpression", + "expression": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + }, + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 1, + "col": 3, + "index": 2 + }, + "end": { + "row": 1, + "col": 9, + "index": 8 + } + }, + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + }, + "parentheses": true + }, + "right": { + "kind": "DecimalLiteral", + "rawValue": "1", + "start": { + "row": 1, + "col": 17, + "index": 16 + }, + "end": { + "row": 1, + "col": 18, + "index": 17 + } + }, + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 18, + "index": 17 + } + }, + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 18, + "index": 17 + } + } + ], + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 2, + "col": 1, + "index": 19 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion-before-operator/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion-before-operator/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion-before-operator/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion-before-operator/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion-before-operator/input.ts new file mode 100644 index 00000000..03f7f080 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion-before-operator/input.ts @@ -0,0 +1 @@ + 1 + 1; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion-before-operator/output.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion-before-operator/output.json new file mode 100644 index 00000000..09950aa3 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion-before-operator/output.json @@ -0,0 +1,96 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "BinaryExpression", + "operator": "+", + "left": { + "kind": "TSTypeAssertionExpression", + "expression": { + "kind": "DecimalLiteral", + "rawValue": "1", + "start": { + "row": 1, + "col": 10, + "index": 9 + }, + "end": { + "row": 1, + "col": 11, + "index": 10 + } + }, + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 8, + "index": 7 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 11, + "index": 10 + } + }, + "right": { + "kind": "DecimalLiteral", + "rawValue": "1", + "start": { + "row": 1, + "col": 14, + "index": 13 + }, + "end": { + "row": 1, + "col": 15, + "index": 14 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 15, + "index": 14 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 15, + "index": 14 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 16 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion/input.ts new file mode 100644 index 00000000..742b94ba --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion/input.ts @@ -0,0 +1 @@ + 1; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion/output.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion/output.json new file mode 100644 index 00000000..7aa58bb9 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/type-assertion/output.json @@ -0,0 +1,68 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "TSTypeAssertionExpression", + "expression": { + "kind": "DecimalLiteral", + "rawValue": "1", + "start": { + "row": 1, + "col": 10, + "index": 9 + }, + "end": { + "row": 1, + "col": 11, + "index": 10 + } + }, + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 8, + "index": 7 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 11, + "index": 10 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 11, + "index": 10 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 12 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/unparenthesized-assert-and-assign/CHANGE.md b/web-infras/parser/tests/fixtures/babel/typescript/cast/unparenthesized-assert-and-assign/CHANGE.md new file mode 100644 index 00000000..72c9bb38 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/unparenthesized-assert-and-assign/CHANGE.md @@ -0,0 +1,3 @@ +## Reason + +babel and TS playground is failed, but oxc and swc is pass, set to pass now. diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/unparenthesized-assert-and-assign/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/unparenthesized-assert-and-assign/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/unparenthesized-assert-and-assign/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/unparenthesized-assert-and-assign/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/cast/unparenthesized-assert-and-assign/input.ts new file mode 100644 index 00000000..065e483e --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/unparenthesized-assert-and-assign/input.ts @@ -0,0 +1 @@ +foo = '100'; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/unparenthesized-assert-and-assign/output.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/unparenthesized-assert-and-assign/output.json new file mode 100644 index 00000000..6cb228a7 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/unparenthesized-assert-and-assign/output.json @@ -0,0 +1,96 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "AssigmentExpression", + "operator": "=", + "left": { + "kind": "TSTypeAssertionExpression", + "expression": { + "kind": "Identifer", + "name": "foo", + "start": { + "row": 1, + "col": 9, + "index": 8 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + }, + "typeAnnotation": { + "kind": "TSStringKeyword", + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 8, + "index": 7 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + }, + "right": { + "kind": "StringLiteral", + "value": "100", + "start": { + "row": 1, + "col": 15, + "index": 14 + }, + "end": { + "row": 1, + "col": 20, + "index": 19 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 20, + "index": 19 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 20, + "index": 19 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 21 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/unparenthesized-type-assertion-and-assign/CHANGE.md b/web-infras/parser/tests/fixtures/babel/typescript/cast/unparenthesized-type-assertion-and-assign/CHANGE.md new file mode 100644 index 00000000..72c9bb38 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/unparenthesized-type-assertion-and-assign/CHANGE.md @@ -0,0 +1,3 @@ +## Reason + +babel and TS playground is failed, but oxc and swc is pass, set to pass now. diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/unparenthesized-type-assertion-and-assign/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/unparenthesized-type-assertion-and-assign/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/unparenthesized-type-assertion-and-assign/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/unparenthesized-type-assertion-and-assign/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/cast/unparenthesized-type-assertion-and-assign/input.ts new file mode 100644 index 00000000..065e483e --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/unparenthesized-type-assertion-and-assign/input.ts @@ -0,0 +1 @@ +foo = '100'; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/cast/unparenthesized-type-assertion-and-assign/output.json b/web-infras/parser/tests/fixtures/babel/typescript/cast/unparenthesized-type-assertion-and-assign/output.json new file mode 100644 index 00000000..6cb228a7 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/cast/unparenthesized-type-assertion-and-assign/output.json @@ -0,0 +1,96 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "AssigmentExpression", + "operator": "=", + "left": { + "kind": "TSTypeAssertionExpression", + "expression": { + "kind": "Identifer", + "name": "foo", + "start": { + "row": 1, + "col": 9, + "index": 8 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + }, + "typeAnnotation": { + "kind": "TSStringKeyword", + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 8, + "index": 7 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + }, + "right": { + "kind": "StringLiteral", + "value": "100", + "start": { + "row": 1, + "col": 15, + "index": 14 + }, + "end": { + "row": 1, + "col": 20, + "index": 19 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 20, + "index": 19 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 20, + "index": 19 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 21 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/enum/export/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/enum/export/expect.json new file mode 100644 index 00000000..8aebefab --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/enum/export/expect.json @@ -0,0 +1,7 @@ +{ + "expect": "Pass", + "config": { + "sourceType": "module", + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/enum/export/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/enum/export/input.ts new file mode 100644 index 00000000..5bda4c84 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/enum/export/input.ts @@ -0,0 +1 @@ +export enum E {} diff --git a/web-infras/parser/tests/fixtures/babel/typescript/enum/export/output.json b/web-infras/parser/tests/fixtures/babel/typescript/enum/export/output.json new file mode 100644 index 00000000..f53bf0f9 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/enum/export/output.json @@ -0,0 +1,71 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExportNamedDeclaration", + "specifiers": [], + "declaration": { + "kind": "TSEnumDeclaration", + "id": { + "kind": "Identifer", + "name": "E", + "start": { + "row": 1, + "col": 13, + "index": 12 + }, + "end": { + "row": 1, + "col": 14, + "index": 13 + } + }, + "body": { + "kind": "TSEnumBody", + "members": [], + "start": { + "row": 1, + "col": 15, + "index": 14 + }, + "end": { + "row": 1, + "col": 17, + "index": 16 + } + }, + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 1, + "col": 17, + "index": 16 + } + }, + "source": null, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 17, + "index": 16 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 17 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/enum/members-reserved-words/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/enum/members-reserved-words/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/enum/members-reserved-words/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/enum/members-reserved-words/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/enum/members-reserved-words/input.ts new file mode 100644 index 00000000..06c4ab79 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/enum/members-reserved-words/input.ts @@ -0,0 +1,4 @@ +enum E { + const, + default +} diff --git a/web-infras/parser/tests/fixtures/babel/typescript/enum/members-reserved-words/output.json b/web-infras/parser/tests/fixtures/babel/typescript/enum/members-reserved-words/output.json new file mode 100644 index 00000000..cdcf5b12 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/enum/members-reserved-words/output.json @@ -0,0 +1,113 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "TSEnumDeclaration", + "id": { + "kind": "Identifer", + "name": "E", + "start": { + "row": 1, + "col": 6, + "index": 5 + }, + "end": { + "row": 1, + "col": 7, + "index": 6 + } + }, + "body": { + "kind": "TSEnumBody", + "members": [ + { + "kind": "TSEnumMember", + "computed": false, + "id": { + "kind": "Identifer", + "name": "const", + "start": { + "row": 2, + "col": 5, + "index": 13 + }, + "end": { + "row": 2, + "col": 10, + "index": 18 + } + }, + "start": { + "row": 2, + "col": 5, + "index": 13 + }, + "end": { + "row": 2, + "col": 10, + "index": 18 + } + }, + { + "kind": "TSEnumMember", + "computed": false, + "id": { + "kind": "Identifer", + "name": "default", + "start": { + "row": 3, + "col": 5, + "index": 24 + }, + "end": { + "row": 3, + "col": 12, + "index": 31 + } + }, + "start": { + "row": 3, + "col": 5, + "index": 24 + }, + "end": { + "row": 3, + "col": 12, + "index": 31 + } + } + ], + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 4, + "col": 2, + "index": 33 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 4, + "col": 2, + "index": 33 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 5, + "col": 1, + "index": 34 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/enum/members-trailing-comma-with-initializer/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/enum/members-trailing-comma-with-initializer/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/enum/members-trailing-comma-with-initializer/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/enum/members-trailing-comma-with-initializer/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/enum/members-trailing-comma-with-initializer/input.ts new file mode 100644 index 00000000..0c1f115f --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/enum/members-trailing-comma-with-initializer/input.ts @@ -0,0 +1,3 @@ +enum E { + A = 0, +} diff --git a/web-infras/parser/tests/fixtures/babel/typescript/enum/members-trailing-comma-with-initializer/output.json b/web-infras/parser/tests/fixtures/babel/typescript/enum/members-trailing-comma-with-initializer/output.json new file mode 100644 index 00000000..1809ec93 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/enum/members-trailing-comma-with-initializer/output.json @@ -0,0 +1,99 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "TSEnumDeclaration", + "id": { + "kind": "Identifer", + "name": "E", + "start": { + "row": 1, + "col": 6, + "index": 5 + }, + "end": { + "row": 1, + "col": 7, + "index": 6 + } + }, + "body": { + "kind": "TSEnumBody", + "members": [ + { + "kind": "TSEnumMember", + "computed": false, + "id": { + "kind": "Identifer", + "name": "A", + "start": { + "row": 2, + "col": 5, + "index": 13 + }, + "end": { + "row": 2, + "col": 6, + "index": 14 + } + }, + "init": { + "kind": "DecimalLiteral", + "rawValue": "0", + "start": { + "row": 2, + "col": 9, + "index": 17 + }, + "end": { + "row": 2, + "col": 10, + "index": 18 + } + }, + "start": { + "row": 2, + "col": 5, + "index": 13 + }, + "end": { + "row": 2, + "col": 10, + "index": 18 + } + } + ], + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 3, + "col": 2, + "index": 21 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 3, + "col": 2, + "index": 21 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 4, + "col": 1, + "index": 22 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/enum/members-trailing-comma/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/enum/members-trailing-comma/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/enum/members-trailing-comma/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/enum/members-trailing-comma/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/enum/members-trailing-comma/input.ts new file mode 100644 index 00000000..7db24478 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/enum/members-trailing-comma/input.ts @@ -0,0 +1,3 @@ +enum E { + A, +} diff --git a/web-infras/parser/tests/fixtures/babel/typescript/enum/members-trailing-comma/output.json b/web-infras/parser/tests/fixtures/babel/typescript/enum/members-trailing-comma/output.json new file mode 100644 index 00000000..ac4499d6 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/enum/members-trailing-comma/output.json @@ -0,0 +1,85 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "TSEnumDeclaration", + "id": { + "kind": "Identifer", + "name": "E", + "start": { + "row": 1, + "col": 6, + "index": 5 + }, + "end": { + "row": 1, + "col": 7, + "index": 6 + } + }, + "body": { + "kind": "TSEnumBody", + "members": [ + { + "kind": "TSEnumMember", + "computed": false, + "id": { + "kind": "Identifer", + "name": "A", + "start": { + "row": 2, + "col": 5, + "index": 13 + }, + "end": { + "row": 2, + "col": 6, + "index": 14 + } + }, + "start": { + "row": 2, + "col": 5, + "index": 13 + }, + "end": { + "row": 2, + "col": 6, + "index": 14 + } + } + ], + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 3, + "col": 2, + "index": 17 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 3, + "col": 2, + "index": 17 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 4, + "col": 1, + "index": 18 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/enum/members/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/enum/members/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/enum/members/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/enum/members/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/enum/members/input.ts new file mode 100644 index 00000000..c0d9e76d --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/enum/members/input.ts @@ -0,0 +1,4 @@ +enum E { + A, + B = 0 +} diff --git a/web-infras/parser/tests/fixtures/babel/typescript/enum/members/output.json b/web-infras/parser/tests/fixtures/babel/typescript/enum/members/output.json new file mode 100644 index 00000000..1c2c6892 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/enum/members/output.json @@ -0,0 +1,127 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "TSEnumDeclaration", + "id": { + "kind": "Identifer", + "name": "E", + "start": { + "row": 1, + "col": 6, + "index": 5 + }, + "end": { + "row": 1, + "col": 7, + "index": 6 + } + }, + "body": { + "kind": "TSEnumBody", + "members": [ + { + "kind": "TSEnumMember", + "computed": false, + "id": { + "kind": "Identifer", + "name": "A", + "start": { + "row": 2, + "col": 5, + "index": 13 + }, + "end": { + "row": 2, + "col": 6, + "index": 14 + } + }, + "start": { + "row": 2, + "col": 5, + "index": 13 + }, + "end": { + "row": 2, + "col": 6, + "index": 14 + } + }, + { + "kind": "TSEnumMember", + "computed": false, + "id": { + "kind": "Identifer", + "name": "B", + "start": { + "row": 3, + "col": 5, + "index": 20 + }, + "end": { + "row": 3, + "col": 6, + "index": 21 + } + }, + "init": { + "kind": "DecimalLiteral", + "rawValue": "0", + "start": { + "row": 3, + "col": 9, + "index": 24 + }, + "end": { + "row": 3, + "col": 10, + "index": 25 + } + }, + "start": { + "row": 3, + "col": 5, + "index": 20 + }, + "end": { + "row": 3, + "col": 10, + "index": 25 + } + } + ], + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 4, + "col": 2, + "index": 27 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 4, + "col": 2, + "index": 27 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 5, + "col": 1, + "index": 28 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/function/annotated/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/function/annotated/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/function/annotated/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/function/annotated/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/function/annotated/input.ts new file mode 100644 index 00000000..139772fa --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/function/annotated/input.ts @@ -0,0 +1 @@ +function f(x?: T): T {} diff --git a/web-infras/parser/tests/fixtures/babel/typescript/function/annotated/output.json b/web-infras/parser/tests/fixtures/babel/typescript/function/annotated/output.json new file mode 100644 index 00000000..f1d12c12 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/function/annotated/output.json @@ -0,0 +1,197 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "FunctionDeclaration", + "name": { + "kind": "Identifer", + "name": "f", + "start": { + "row": 1, + "col": 10, + "index": 9 + }, + "end": { + "row": 1, + "col": 11, + "index": 10 + } + }, + "generator": false, + "async": false, + "body": { + "kind": "FunctionBody", + "body": [], + "start": { + "row": 1, + "col": 25, + "index": 24 + }, + "end": { + "row": 1, + "col": 27, + "index": 26 + } + }, + "params": [ + { + "kind": "Identifer", + "name": "x", + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 19, + "index": 18 + }, + "end": { + "row": 1, + "col": 20, + "index": 19 + } + }, + "start": { + "row": 1, + "col": 19, + "index": 18 + }, + "end": { + "row": 1, + "col": 20, + "index": 19 + } + }, + "start": { + "row": 1, + "col": 17, + "index": 16 + }, + "end": { + "row": 1, + "col": 20, + "index": 19 + } + }, + "optional": true, + "start": { + "row": 1, + "col": 15, + "index": 14 + }, + "end": { + "row": 1, + "col": 16, + "index": 15 + } + } + ], + "typeParameters": { + "kind": "TSTypeParameterDeclaration", + "params": [ + { + "kind": "TSTypeParameter", + "name": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 12, + "index": 11 + }, + "end": { + "row": 1, + "col": 13, + "index": 12 + } + }, + "start": { + "row": 1, + "col": 12, + "index": 11 + }, + "end": { + "row": 1, + "col": 13, + "index": 12 + } + } + ], + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 14, + "index": 13 + } + }, + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 23, + "index": 22 + }, + "end": { + "row": 1, + "col": 24, + "index": 23 + } + }, + "start": { + "row": 1, + "col": 23, + "index": 22 + }, + "end": { + "row": 1, + "col": 24, + "index": 23 + } + }, + "start": { + "row": 1, + "col": 21, + "index": 20 + }, + "end": { + "row": 1, + "col": 24, + "index": 23 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 27, + "index": 26 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 27 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/function/anonymous-generator/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/function/anonymous-generator/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/function/anonymous-generator/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/function/anonymous-generator/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/function/anonymous-generator/input.ts new file mode 100644 index 00000000..f696b003 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/function/anonymous-generator/input.ts @@ -0,0 +1,4 @@ +const fn = function* (input: T): Generator { + yield 2; + } + \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/function/anonymous-generator/output.json b/web-infras/parser/tests/fixtures/babel/typescript/function/anonymous-generator/output.json new file mode 100644 index 00000000..570d9bfe --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/function/anonymous-generator/output.json @@ -0,0 +1,298 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "VariableDeclaration", + "variant": "const", + "declarations": [ + { + "kind": "VariableDeclarator", + "id": { + "kind": "Identifer", + "name": "fn", + "optional": false, + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 9, + "index": 8 + } + }, + "init": { + "kind": "FunctionExpression", + "name": null, + "generator": true, + "async": false, + "body": { + "kind": "FunctionBody", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "YieldExpression", + "argument": { + "kind": "DecimalLiteral", + "rawValue": "2", + "start": { + "row": 2, + "col": 11, + "index": 66 + }, + "end": { + "row": 2, + "col": 12, + "index": 67 + } + }, + "delegate": false, + "start": { + "row": 2, + "col": 5, + "index": 60 + }, + "end": { + "row": 2, + "col": 12, + "index": 67 + } + }, + "start": { + "row": 2, + "col": 5, + "index": 60 + }, + "end": { + "row": 2, + "col": 12, + "index": 67 + } + } + ], + "start": { + "row": 1, + "col": 55, + "index": 54 + }, + "end": { + "row": 3, + "col": 4, + "index": 72 + } + }, + "params": [ + { + "kind": "Identifer", + "name": "input", + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 33, + "index": 32 + }, + "end": { + "row": 1, + "col": 34, + "index": 33 + } + }, + "start": { + "row": 1, + "col": 33, + "index": 32 + }, + "end": { + "row": 1, + "col": 34, + "index": 33 + } + }, + "start": { + "row": 1, + "col": 31, + "index": 30 + }, + "end": { + "row": 1, + "col": 34, + "index": 33 + } + }, + "optional": false, + "start": { + "row": 1, + "col": 26, + "index": 25 + }, + "end": { + "row": 1, + "col": 31, + "index": 30 + } + } + ], + "typeParameters": { + "kind": "TSTypeParameterDeclaration", + "params": [ + { + "kind": "TSTypeParameter", + "name": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 23, + "index": 22 + }, + "end": { + "row": 1, + "col": 24, + "index": 23 + } + }, + "start": { + "row": 1, + "col": 23, + "index": 22 + }, + "end": { + "row": 1, + "col": 24, + "index": 23 + } + } + ], + "start": { + "row": 1, + "col": 22, + "index": 21 + }, + "end": { + "row": 1, + "col": 25, + "index": 24 + } + }, + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "Generator", + "start": { + "row": 1, + "col": 37, + "index": 36 + }, + "end": { + "row": 1, + "col": 46, + "index": 45 + } + }, + "typeArguments": { + "kind": "TSTypeParameterInstantiation", + "params": [ + { + "kind": "TSNumberKeyword", + "start": { + "row": 1, + "col": 47, + "index": 46 + }, + "end": { + "row": 1, + "col": 53, + "index": 52 + } + } + ], + "start": { + "row": 1, + "col": 46, + "index": 45 + }, + "end": { + "row": 1, + "col": 54, + "index": 53 + } + }, + "start": { + "row": 1, + "col": 37, + "index": 36 + }, + "end": { + "row": 1, + "col": 46, + "index": 45 + } + }, + "start": { + "row": 1, + "col": 35, + "index": 34 + }, + "end": { + "row": 1, + "col": 46, + "index": 45 + } + }, + "start": { + "row": 1, + "col": 12, + "index": 11 + }, + "end": { + "row": 3, + "col": 4, + "index": 72 + } + }, + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 3, + "col": 4, + "index": 72 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 3, + "col": 4, + "index": 72 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 4, + "col": 3, + "index": 75 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/function/anonymous/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/function/anonymous/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/function/anonymous/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/function/anonymous/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/function/anonymous/input.ts new file mode 100644 index 00000000..395ce03c --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/function/anonymous/input.ts @@ -0,0 +1 @@ +const f = function(x?: T): T {}; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/function/anonymous/output.json b/web-infras/parser/tests/fixtures/babel/typescript/function/anonymous/output.json new file mode 100644 index 00000000..0f1a5ae9 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/function/anonymous/output.json @@ -0,0 +1,228 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "VariableDeclaration", + "variant": "const", + "declarations": [ + { + "kind": "VariableDeclarator", + "id": { + "kind": "Identifer", + "name": "f", + "optional": false, + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 8, + "index": 7 + } + }, + "init": { + "kind": "FunctionExpression", + "name": null, + "generator": false, + "async": false, + "body": { + "kind": "FunctionBody", + "body": [], + "start": { + "row": 1, + "col": 33, + "index": 32 + }, + "end": { + "row": 1, + "col": 35, + "index": 34 + } + }, + "params": [ + { + "kind": "Identifer", + "name": "x", + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 27, + "index": 26 + }, + "end": { + "row": 1, + "col": 28, + "index": 27 + } + }, + "start": { + "row": 1, + "col": 27, + "index": 26 + }, + "end": { + "row": 1, + "col": 28, + "index": 27 + } + }, + "start": { + "row": 1, + "col": 25, + "index": 24 + }, + "end": { + "row": 1, + "col": 28, + "index": 27 + } + }, + "optional": true, + "start": { + "row": 1, + "col": 23, + "index": 22 + }, + "end": { + "row": 1, + "col": 24, + "index": 23 + } + } + ], + "typeParameters": { + "kind": "TSTypeParameterDeclaration", + "params": [ + { + "kind": "TSTypeParameter", + "name": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 20, + "index": 19 + }, + "end": { + "row": 1, + "col": 21, + "index": 20 + } + }, + "start": { + "row": 1, + "col": 20, + "index": 19 + }, + "end": { + "row": 1, + "col": 21, + "index": 20 + } + } + ], + "start": { + "row": 1, + "col": 19, + "index": 18 + }, + "end": { + "row": 1, + "col": 22, + "index": 21 + } + }, + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 31, + "index": 30 + }, + "end": { + "row": 1, + "col": 32, + "index": 31 + } + }, + "start": { + "row": 1, + "col": 31, + "index": 30 + }, + "end": { + "row": 1, + "col": 32, + "index": 31 + } + }, + "start": { + "row": 1, + "col": 29, + "index": 28 + }, + "end": { + "row": 1, + "col": 32, + "index": 31 + } + }, + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 35, + "index": 34 + } + }, + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 35, + "index": 34 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 35, + "index": 34 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 36 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/function/empty-type-parameters/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/function/empty-type-parameters/expect.json new file mode 100644 index 00000000..e5936a86 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/function/empty-type-parameters/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Failed", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/function/empty-type-parameters/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/function/empty-type-parameters/input.ts new file mode 100644 index 00000000..0988137a --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/function/empty-type-parameters/input.ts @@ -0,0 +1 @@ +function foo<>() {} diff --git a/web-infras/parser/tests/fixtures/babel/typescript/function/empty-type-parameters/output.txt b/web-infras/parser/tests/fixtures/babel/typescript/function/empty-type-parameters/output.txt new file mode 100644 index 00000000..4bc88203 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/function/empty-type-parameters/output.txt @@ -0,0 +1 @@ +[Syntax Error]: Unexpect token >(1, 14). \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/function/export-default/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/function/export-default/expect.json new file mode 100644 index 00000000..8aebefab --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/function/export-default/expect.json @@ -0,0 +1,7 @@ +{ + "expect": "Pass", + "config": { + "sourceType": "module", + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/function/export-default/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/function/export-default/input.ts new file mode 100644 index 00000000..37e894cd --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/function/export-default/input.ts @@ -0,0 +1 @@ +export default function(x?: number): void; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/function/export-default/output.json b/web-infras/parser/tests/fixtures/babel/typescript/function/export-default/output.json new file mode 100644 index 00000000..474321e9 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/function/export-default/output.json @@ -0,0 +1,113 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExportDefaultDeclaration", + "declaration": { + "kind": "TSDeclareFunction", + "name": null, + "params": [ + { + "kind": "Identifer", + "name": "x", + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 1, + "col": 29, + "index": 28 + }, + "end": { + "row": 1, + "col": 35, + "index": 34 + } + }, + "start": { + "row": 1, + "col": 27, + "index": 26 + }, + "end": { + "row": 1, + "col": 35, + "index": 34 + } + }, + "optional": true, + "start": { + "row": 1, + "col": 25, + "index": 24 + }, + "end": { + "row": 1, + "col": 26, + "index": 25 + } + } + ], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSVoidKeyword", + "start": { + "row": 1, + "col": 38, + "index": 37 + }, + "end": { + "row": 1, + "col": 42, + "index": 41 + } + }, + "start": { + "row": 1, + "col": 36, + "index": 35 + }, + "end": { + "row": 1, + "col": 42, + "index": 41 + } + }, + "generator": false, + "async": false, + "start": { + "row": 1, + "col": 16, + "index": 15 + }, + "end": { + "row": 1, + "col": 42, + "index": 41 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 42, + "index": 41 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 43 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/function/overloads/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/function/overloads/expect.json new file mode 100644 index 00000000..8aebefab --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/function/overloads/expect.json @@ -0,0 +1,7 @@ +{ + "expect": "Pass", + "config": { + "sourceType": "module", + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/function/overloads/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/function/overloads/input.ts new file mode 100644 index 00000000..2fb36ce1 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/function/overloads/input.ts @@ -0,0 +1,2 @@ +export function f(x: number): number; +export function f(x: string): string; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/function/overloads/output.json b/web-infras/parser/tests/fixtures/babel/typescript/function/overloads/output.json new file mode 100644 index 00000000..608b5e48 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/function/overloads/output.json @@ -0,0 +1,241 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExportNamedDeclaration", + "specifiers": [], + "declaration": { + "kind": "TSDeclareFunction", + "name": { + "kind": "Identifer", + "name": "f", + "start": { + "row": 1, + "col": 17, + "index": 16 + }, + "end": { + "row": 1, + "col": 18, + "index": 17 + } + }, + "params": [ + { + "kind": "Identifer", + "name": "x", + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 1, + "col": 22, + "index": 21 + }, + "end": { + "row": 1, + "col": 28, + "index": 27 + } + }, + "start": { + "row": 1, + "col": 20, + "index": 19 + }, + "end": { + "row": 1, + "col": 28, + "index": 27 + } + }, + "optional": false, + "start": { + "row": 1, + "col": 19, + "index": 18 + }, + "end": { + "row": 1, + "col": 20, + "index": 19 + } + } + ], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 1, + "col": 31, + "index": 30 + }, + "end": { + "row": 1, + "col": 37, + "index": 36 + } + }, + "start": { + "row": 1, + "col": 29, + "index": 28 + }, + "end": { + "row": 1, + "col": 37, + "index": 36 + } + }, + "generator": false, + "async": false, + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 1, + "col": 37, + "index": 36 + } + }, + "source": null, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 37, + "index": 36 + } + }, + { + "kind": "ExportNamedDeclaration", + "specifiers": [], + "declaration": { + "kind": "TSDeclareFunction", + "name": { + "kind": "Identifer", + "name": "f", + "start": { + "row": 2, + "col": 17, + "index": 54 + }, + "end": { + "row": 2, + "col": 18, + "index": 55 + } + }, + "params": [ + { + "kind": "Identifer", + "name": "x", + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSStringKeyword", + "start": { + "row": 2, + "col": 22, + "index": 59 + }, + "end": { + "row": 2, + "col": 28, + "index": 65 + } + }, + "start": { + "row": 2, + "col": 20, + "index": 57 + }, + "end": { + "row": 2, + "col": 28, + "index": 65 + } + }, + "optional": false, + "start": { + "row": 2, + "col": 19, + "index": 56 + }, + "end": { + "row": 2, + "col": 20, + "index": 57 + } + } + ], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSStringKeyword", + "start": { + "row": 2, + "col": 31, + "index": 68 + }, + "end": { + "row": 2, + "col": 37, + "index": 74 + } + }, + "start": { + "row": 2, + "col": 29, + "index": 66 + }, + "end": { + "row": 2, + "col": 37, + "index": 74 + } + }, + "generator": false, + "async": false, + "start": { + "row": 2, + "col": 8, + "index": 45 + }, + "end": { + "row": 2, + "col": 37, + "index": 74 + } + }, + "source": null, + "start": { + "row": 2, + "col": 1, + "index": 38 + }, + "end": { + "row": 2, + "col": 37, + "index": 74 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 3, + "col": 1, + "index": 76 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/function/predicate-types/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/function/predicate-types/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/function/predicate-types/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/function/predicate-types/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/function/predicate-types/input.ts new file mode 100644 index 00000000..374c7176 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/function/predicate-types/input.ts @@ -0,0 +1,2 @@ +function f(x: any): x is boolean {} +(function(x: any): x is boolean {}) diff --git a/web-infras/parser/tests/fixtures/babel/typescript/function/predicate-types/output.json b/web-infras/parser/tests/fixtures/babel/typescript/function/predicate-types/output.json new file mode 100644 index 00000000..13c1e6ed --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/function/predicate-types/output.json @@ -0,0 +1,322 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "FunctionDeclaration", + "name": { + "kind": "Identifer", + "name": "f", + "start": { + "row": 1, + "col": 10, + "index": 9 + }, + "end": { + "row": 1, + "col": 11, + "index": 10 + } + }, + "generator": false, + "async": false, + "body": { + "kind": "FunctionBody", + "body": [], + "start": { + "row": 1, + "col": 34, + "index": 33 + }, + "end": { + "row": 1, + "col": 36, + "index": 35 + } + }, + "params": [ + { + "kind": "Identifer", + "name": "x", + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSAnyKeyword", + "start": { + "row": 1, + "col": 15, + "index": 14 + }, + "end": { + "row": 1, + "col": 18, + "index": 17 + } + }, + "start": { + "row": 1, + "col": 13, + "index": 12 + }, + "end": { + "row": 1, + "col": 18, + "index": 17 + } + }, + "optional": false, + "start": { + "row": 1, + "col": 12, + "index": 11 + }, + "end": { + "row": 1, + "col": 13, + "index": 12 + } + } + ], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSTypePredicate", + "parameterName": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 1, + "col": 21, + "index": 20 + }, + "end": { + "row": 1, + "col": 22, + "index": 21 + } + }, + "asserts": false, + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSBooleanKeyword", + "start": { + "row": 1, + "col": 26, + "index": 25 + }, + "end": { + "row": 1, + "col": 33, + "index": 32 + } + }, + "start": { + "row": 1, + "col": 26, + "index": 25 + }, + "end": { + "row": 1, + "col": 33, + "index": 32 + } + }, + "start": { + "row": 1, + "col": 19, + "index": 18 + }, + "end": { + "row": 1, + "col": 33, + "index": 32 + } + }, + "start": { + "row": 1, + "col": 19, + "index": 18 + }, + "end": { + "row": 1, + "col": 33, + "index": 32 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 36, + "index": 35 + } + }, + { + "kind": "ExpressionStatement", + "expr": { + "kind": "FunctionExpression", + "name": null, + "generator": false, + "async": false, + "body": { + "kind": "FunctionBody", + "body": [], + "start": { + "row": 2, + "col": 33, + "index": 68 + }, + "end": { + "row": 2, + "col": 35, + "index": 70 + } + }, + "params": [ + { + "kind": "Identifer", + "name": "x", + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSAnyKeyword", + "start": { + "row": 2, + "col": 14, + "index": 49 + }, + "end": { + "row": 2, + "col": 17, + "index": 52 + } + }, + "start": { + "row": 2, + "col": 12, + "index": 47 + }, + "end": { + "row": 2, + "col": 17, + "index": 52 + } + }, + "optional": false, + "start": { + "row": 2, + "col": 11, + "index": 46 + }, + "end": { + "row": 2, + "col": 12, + "index": 47 + } + } + ], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSTypePredicate", + "parameterName": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 2, + "col": 20, + "index": 55 + }, + "end": { + "row": 2, + "col": 21, + "index": 56 + } + }, + "asserts": false, + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSBooleanKeyword", + "start": { + "row": 2, + "col": 25, + "index": 60 + }, + "end": { + "row": 2, + "col": 32, + "index": 67 + } + }, + "start": { + "row": 2, + "col": 25, + "index": 60 + }, + "end": { + "row": 2, + "col": 32, + "index": 67 + } + }, + "start": { + "row": 2, + "col": 18, + "index": 53 + }, + "end": { + "row": 2, + "col": 32, + "index": 67 + } + }, + "start": { + "row": 2, + "col": 18, + "index": 53 + }, + "end": { + "row": 2, + "col": 32, + "index": 67 + } + }, + "start": { + "row": 2, + "col": 2, + "index": 37 + }, + "end": { + "row": 2, + "col": 35, + "index": 70 + }, + "parentheses": true + }, + "start": { + "row": 2, + "col": 2, + "index": 37 + }, + "end": { + "row": 2, + "col": 35, + "index": 70 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 3, + "col": 1, + "index": 72 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/call-signature/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/call-signature/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/call-signature/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/call-signature/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/interface/call-signature/input.ts new file mode 100644 index 00000000..5d6b5417 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/call-signature/input.ts @@ -0,0 +1,3 @@ +interface I { + (x: number): void; +} diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/call-signature/output.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/call-signature/output.json new file mode 100644 index 00000000..2b605638 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/call-signature/output.json @@ -0,0 +1,140 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "TSInterfaceDeclaration", + "name": { + "kind": 10130, + "name": "I", + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + }, + "extends": [], + "body": { + "kind": "TSInterfaceBody", + "body": [ + { + "kind": "TSCallSignatureDeclaration", + "parameters": [ + { + "kind": "Identifer", + "name": "x", + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 2, + "col": 9, + "index": 22 + }, + "end": { + "row": 2, + "col": 15, + "index": 28 + } + }, + "start": { + "row": 2, + "col": 7, + "index": 20 + }, + "end": { + "row": 2, + "col": 15, + "index": 28 + } + }, + "optional": false, + "start": { + "row": 2, + "col": 6, + "index": 19 + }, + "end": { + "row": 2, + "col": 7, + "index": 20 + } + } + ], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSVoidKeyword", + "start": { + "row": 2, + "col": 18, + "index": 31 + }, + "end": { + "row": 2, + "col": 22, + "index": 35 + } + }, + "start": { + "row": 2, + "col": 16, + "index": 29 + }, + "end": { + "row": 2, + "col": 22, + "index": 35 + } + }, + "start": { + "row": 2, + "col": 5, + "index": 18 + }, + "end": { + "row": 2, + "col": 22, + "index": 35 + } + } + ], + "start": { + "row": 1, + "col": 13, + "index": 12 + }, + "end": { + "row": 3, + "col": 2, + "index": 38 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 3, + "col": 2, + "index": 38 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 4, + "col": 1, + "index": 39 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/construct-signature/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/construct-signature/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/construct-signature/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/construct-signature/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/interface/construct-signature/input.ts new file mode 100644 index 00000000..d726e4c4 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/construct-signature/input.ts @@ -0,0 +1,3 @@ +interface I { + new (x: number): void; +} diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/construct-signature/output.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/construct-signature/output.json new file mode 100644 index 00000000..6a7e8041 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/construct-signature/output.json @@ -0,0 +1,140 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "TSInterfaceDeclaration", + "name": { + "kind": 10130, + "name": "I", + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + }, + "extends": [], + "body": { + "kind": "TSInterfaceBody", + "body": [ + { + "kind": "TSConstructSignatureDeclaration", + "parameters": [ + { + "kind": "Identifer", + "name": "x", + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 2, + "col": 13, + "index": 26 + }, + "end": { + "row": 2, + "col": 19, + "index": 32 + } + }, + "start": { + "row": 2, + "col": 11, + "index": 24 + }, + "end": { + "row": 2, + "col": 19, + "index": 32 + } + }, + "optional": false, + "start": { + "row": 2, + "col": 10, + "index": 23 + }, + "end": { + "row": 2, + "col": 11, + "index": 24 + } + } + ], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSVoidKeyword", + "start": { + "row": 2, + "col": 22, + "index": 35 + }, + "end": { + "row": 2, + "col": 26, + "index": 39 + } + }, + "start": { + "row": 2, + "col": 20, + "index": 33 + }, + "end": { + "row": 2, + "col": 26, + "index": 39 + } + }, + "start": { + "row": 2, + "col": 5, + "index": 18 + }, + "end": { + "row": 2, + "col": 26, + "index": 39 + } + } + ], + "start": { + "row": 1, + "col": 13, + "index": 12 + }, + "end": { + "row": 3, + "col": 2, + "index": 42 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 3, + "col": 2, + "index": 42 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 4, + "col": 1, + "index": 43 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/export-default/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/export-default/expect.json new file mode 100644 index 00000000..e5936a86 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/export-default/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Failed", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/export-default/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/interface/export-default/input.ts new file mode 100644 index 00000000..b0f7156d --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/export-default/input.ts @@ -0,0 +1 @@ +export default interface {} diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/export-default/output.txt b/web-infras/parser/tests/fixtures/babel/typescript/interface/export-default/output.txt new file mode 100644 index 00000000..a67ab555 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/export-default/output.txt @@ -0,0 +1,6 @@ +[SyntaxError]: 'import' and 'export' may appear only with 'sourceType: "module"' (1,1) +1|export default interface {} + |^ +[SyntaxError]: Missing semicolon or line terminator. (1,26) +1|export default interface {} + | ^ diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/export/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/export/expect.json new file mode 100644 index 00000000..8aebefab --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/export/expect.json @@ -0,0 +1,7 @@ +{ + "expect": "Pass", + "config": { + "sourceType": "module", + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/export/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/interface/export/input.ts new file mode 100644 index 00000000..7049da87 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/export/input.ts @@ -0,0 +1,2 @@ +export interface I {} +export default interface A {} diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/export/output.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/export/output.json new file mode 100644 index 00000000..40656ed4 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/export/output.json @@ -0,0 +1,127 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExportNamedDeclaration", + "specifiers": [], + "declaration": { + "kind": "TSInterfaceDeclaration", + "name": { + "kind": 10130, + "name": "I", + "start": { + "row": 1, + "col": 18, + "index": 17 + }, + "end": { + "row": 1, + "col": 19, + "index": 18 + } + }, + "extends": [], + "body": { + "kind": "TSInterfaceBody", + "body": [], + "start": { + "row": 1, + "col": 20, + "index": 19 + }, + "end": { + "row": 1, + "col": 22, + "index": 21 + } + }, + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 1, + "col": 22, + "index": 21 + } + }, + "source": null, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 22, + "index": 21 + } + }, + { + "kind": "ExportDefaultDeclaration", + "declaration": { + "kind": "TSInterfaceDeclaration", + "name": { + "kind": 10130, + "name": "A", + "start": { + "row": 2, + "col": 26, + "index": 47 + }, + "end": { + "row": 2, + "col": 27, + "index": 48 + } + }, + "extends": [], + "body": { + "kind": "TSInterfaceBody", + "body": [], + "start": { + "row": 2, + "col": 28, + "index": 49 + }, + "end": { + "row": 2, + "col": 30, + "index": 51 + } + }, + "start": { + "row": 2, + "col": 16, + "index": 37 + }, + "end": { + "row": 2, + "col": 30, + "index": 51 + } + }, + "start": { + "row": 2, + "col": 1, + "index": 22 + }, + "end": { + "row": 2, + "col": 30, + "index": 51 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 3, + "col": 1, + "index": 52 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/extends/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/extends/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/extends/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/extends/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/interface/extends/input.ts new file mode 100644 index 00000000..8cf474f2 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/extends/input.ts @@ -0,0 +1 @@ +interface I extends X.Y {} diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/extends/output.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/extends/output.json new file mode 100644 index 00000000..1597d9f2 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/extends/output.json @@ -0,0 +1,154 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "TSInterfaceDeclaration", + "name": { + "kind": 10130, + "name": "I", + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + }, + "extends": [ + { + "kind": "TSInterfaceHeritage", + "typeName": { + "kind": "TSQualifiedName", + "left": { + "kind": "Identifer", + "name": "X", + "start": { + "row": 1, + "col": 21, + "index": 20 + }, + "end": { + "row": 1, + "col": 22, + "index": 21 + } + }, + "right": { + "kind": "Identifer", + "name": "Y", + "start": { + "row": 1, + "col": 23, + "index": 22 + }, + "end": { + "row": 1, + "col": 24, + "index": 23 + } + }, + "start": { + "row": 1, + "col": 21, + "index": 20 + }, + "end": { + "row": 1, + "col": 24, + "index": 23 + } + }, + "typeArguments": { + "kind": "TSTypeParameterInstantiation", + "params": [ + { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "Z", + "start": { + "row": 1, + "col": 25, + "index": 24 + }, + "end": { + "row": 1, + "col": 26, + "index": 25 + } + }, + "start": { + "row": 1, + "col": 25, + "index": 24 + }, + "end": { + "row": 1, + "col": 26, + "index": 25 + } + } + ], + "start": { + "row": 1, + "col": 24, + "index": 23 + }, + "end": { + "row": 1, + "col": 27, + "index": 26 + } + }, + "start": { + "row": 1, + "col": 21, + "index": 20 + }, + "end": { + "row": 1, + "col": 27, + "index": 26 + } + } + ], + "body": { + "kind": "TSInterfaceBody", + "body": [], + "start": { + "row": 1, + "col": 28, + "index": 27 + }, + "end": { + "row": 1, + "col": 30, + "index": 29 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 30, + "index": 29 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 30 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-1/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-1/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-1/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-1/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-1/input.ts new file mode 100644 index 00000000..f4160e2f --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-1/input.ts @@ -0,0 +1,4 @@ +interface Foo { + (a: string): string; + } + \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-1/output.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-1/output.json new file mode 100644 index 00000000..2f86b796 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-1/output.json @@ -0,0 +1,182 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "TSInterfaceDeclaration", + "name": { + "kind": 10130, + "name": "Foo", + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 14, + "index": 13 + } + }, + "extends": [], + "body": { + "kind": "TSInterfaceBody", + "body": [ + { + "kind": "TSCallSignatureDeclaration", + "parameters": [ + { + "kind": "Identifer", + "name": "a", + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSStringKeyword", + "start": { + "row": 2, + "col": 12, + "index": 27 + }, + "end": { + "row": 2, + "col": 18, + "index": 33 + } + }, + "start": { + "row": 2, + "col": 10, + "index": 25 + }, + "end": { + "row": 2, + "col": 18, + "index": 33 + } + }, + "optional": false, + "start": { + "row": 2, + "col": 9, + "index": 24 + }, + "end": { + "row": 2, + "col": 10, + "index": 25 + } + } + ], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSStringKeyword", + "start": { + "row": 2, + "col": 21, + "index": 36 + }, + "end": { + "row": 2, + "col": 27, + "index": 42 + } + }, + "start": { + "row": 2, + "col": 19, + "index": 34 + }, + "end": { + "row": 2, + "col": 27, + "index": 42 + } + }, + "typeParameters": { + "kind": 10257, + "params": [ + { + "kind": 10258, + "name": { + "kind": 10130, + "name": "T", + "start": { + "row": 2, + "col": 6, + "index": 21 + }, + "end": { + "row": 2, + "col": 7, + "index": 22 + } + }, + "start": { + "row": 2, + "col": 6, + "index": 21 + }, + "end": { + "row": 2, + "col": 7, + "index": 22 + } + } + ], + "start": { + "row": 2, + "col": 5, + "index": 20 + }, + "end": { + "row": 2, + "col": 8, + "index": 23 + } + }, + "start": { + "row": 2, + "col": 5, + "index": 20 + }, + "end": { + "row": 2, + "col": 27, + "index": 42 + } + } + ], + "start": { + "row": 1, + "col": 15, + "index": 14 + }, + "end": { + "row": 3, + "col": 4, + "index": 47 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 3, + "col": 4, + "index": 47 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 4, + "col": 3, + "index": 50 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-2/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-2/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-2/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-2/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-2/input.ts new file mode 100644 index 00000000..8c9e7dbb --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-2/input.ts @@ -0,0 +1 @@ +type Foo = () => number; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-2/output.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-2/output.json new file mode 100644 index 00000000..63533f6c --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-2/output.json @@ -0,0 +1,124 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "TSTypeAliasDeclaration", + "name": { + "kind": 10130, + "name": "Foo", + "start": { + "row": 1, + "col": 6, + "index": 5 + }, + "end": { + "row": 1, + "col": 9, + "index": 8 + } + }, + "typeAnnotation": { + "kind": "TSFunctionType", + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 1, + "col": 21, + "index": 20 + }, + "end": { + "row": 1, + "col": 27, + "index": 26 + } + }, + "start": { + "row": 1, + "col": 18, + "index": 17 + }, + "end": { + "row": 1, + "col": 27, + "index": 26 + } + }, + "parameters": [], + "typeParameters": { + "kind": "TSTypeParameterDeclaration", + "params": [ + { + "kind": "TSTypeParameter", + "name": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 13, + "index": 12 + }, + "end": { + "row": 1, + "col": 14, + "index": 13 + } + }, + "start": { + "row": 1, + "col": 13, + "index": 12 + }, + "end": { + "row": 1, + "col": 14, + "index": 13 + } + } + ], + "start": { + "row": 1, + "col": 12, + "index": 11 + }, + "end": { + "row": 1, + "col": 15, + "index": 14 + } + }, + "start": { + "row": 1, + "col": 12, + "index": 11 + }, + "end": { + "row": 1, + "col": 27, + "index": 26 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 28, + "index": 27 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 28 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-3/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-3/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-3/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-3/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-3/input.ts new file mode 100644 index 00000000..ffc5771b --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-3/input.ts @@ -0,0 +1 @@ +type Foo = new () => void; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-3/output.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-3/output.json new file mode 100644 index 00000000..fb8c2a71 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-3/output.json @@ -0,0 +1,124 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "TSTypeAliasDeclaration", + "name": { + "kind": 10130, + "name": "Foo", + "start": { + "row": 1, + "col": 6, + "index": 5 + }, + "end": { + "row": 1, + "col": 9, + "index": 8 + } + }, + "typeAnnotation": { + "kind": "TSConstructorType", + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSVoidKeyword", + "start": { + "row": 1, + "col": 25, + "index": 24 + }, + "end": { + "row": 1, + "col": 29, + "index": 28 + } + }, + "start": { + "row": 1, + "col": 22, + "index": 21 + }, + "end": { + "row": 1, + "col": 29, + "index": 28 + } + }, + "parameters": [], + "typeParameters": { + "kind": "TSTypeParameterDeclaration", + "params": [ + { + "kind": "TSTypeParameter", + "name": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 17, + "index": 16 + }, + "end": { + "row": 1, + "col": 18, + "index": 17 + } + }, + "start": { + "row": 1, + "col": 17, + "index": 16 + }, + "end": { + "row": 1, + "col": 18, + "index": 17 + } + } + ], + "start": { + "row": 1, + "col": 16, + "index": 15 + }, + "end": { + "row": 1, + "col": 19, + "index": 18 + } + }, + "start": { + "row": 1, + "col": 12, + "index": 11 + }, + "end": { + "row": 1, + "col": 29, + "index": 28 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 30, + "index": 29 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 30 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-4/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-4/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-4/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-4/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-4/input.ts new file mode 100644 index 00000000..fdaa4c13 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-4/input.ts @@ -0,0 +1,4 @@ +interface Foo { + new(a: string): string; + } + \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-4/output.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-4/output.json new file mode 100644 index 00000000..de118c33 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-4/output.json @@ -0,0 +1,182 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "TSInterfaceDeclaration", + "name": { + "kind": 10130, + "name": "Foo", + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 14, + "index": 13 + } + }, + "extends": [], + "body": { + "kind": "TSInterfaceBody", + "body": [ + { + "kind": "TSConstructSignatureDeclaration", + "parameters": [ + { + "kind": "Identifer", + "name": "a", + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSStringKeyword", + "start": { + "row": 2, + "col": 15, + "index": 30 + }, + "end": { + "row": 2, + "col": 21, + "index": 36 + } + }, + "start": { + "row": 2, + "col": 13, + "index": 28 + }, + "end": { + "row": 2, + "col": 21, + "index": 36 + } + }, + "optional": false, + "start": { + "row": 2, + "col": 12, + "index": 27 + }, + "end": { + "row": 2, + "col": 13, + "index": 28 + } + } + ], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSStringKeyword", + "start": { + "row": 2, + "col": 24, + "index": 39 + }, + "end": { + "row": 2, + "col": 30, + "index": 45 + } + }, + "start": { + "row": 2, + "col": 22, + "index": 37 + }, + "end": { + "row": 2, + "col": 30, + "index": 45 + } + }, + "typeParameters": { + "kind": 10257, + "params": [ + { + "kind": 10258, + "name": { + "kind": 10130, + "name": "T", + "start": { + "row": 2, + "col": 9, + "index": 24 + }, + "end": { + "row": 2, + "col": 10, + "index": 25 + } + }, + "start": { + "row": 2, + "col": 9, + "index": 24 + }, + "end": { + "row": 2, + "col": 10, + "index": 25 + } + } + ], + "start": { + "row": 2, + "col": 8, + "index": 23 + }, + "end": { + "row": 2, + "col": 11, + "index": 26 + } + }, + "start": { + "row": 2, + "col": 5, + "index": 20 + }, + "end": { + "row": 2, + "col": 30, + "index": 45 + } + } + ], + "start": { + "row": 1, + "col": 15, + "index": 14 + }, + "end": { + "row": 3, + "col": 4, + "index": 50 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 3, + "col": 4, + "index": 50 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 4, + "col": 3, + "index": 53 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-5/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-5/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-5/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-5/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-5/input.ts new file mode 100644 index 00000000..2c2ed109 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-5/input.ts @@ -0,0 +1,4 @@ +interface Foo { + foo(x: number): void; + } + \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-5/output.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-5/output.json new file mode 100644 index 00000000..24655388 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/function-like-node-5/output.json @@ -0,0 +1,198 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "TSInterfaceDeclaration", + "name": { + "kind": 10130, + "name": "Foo", + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 14, + "index": 13 + } + }, + "extends": [], + "body": { + "kind": "TSInterfaceBody", + "body": [ + { + "kind": "TSMethodSignature", + "key": { + "kind": "Identifer", + "name": "foo", + "start": { + "row": 2, + "col": 5, + "index": 20 + }, + "end": { + "row": 2, + "col": 8, + "index": 23 + } + }, + "computed": false, + "optional": false, + "parameters": [ + { + "kind": "Identifer", + "name": "x", + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 2, + "col": 15, + "index": 30 + }, + "end": { + "row": 2, + "col": 21, + "index": 36 + } + }, + "start": { + "row": 2, + "col": 13, + "index": 28 + }, + "end": { + "row": 2, + "col": 21, + "index": 36 + } + }, + "optional": false, + "start": { + "row": 2, + "col": 12, + "index": 27 + }, + "end": { + "row": 2, + "col": 13, + "index": 28 + } + } + ], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSVoidKeyword", + "start": { + "row": 2, + "col": 24, + "index": 39 + }, + "end": { + "row": 2, + "col": 28, + "index": 43 + } + }, + "start": { + "row": 2, + "col": 22, + "index": 37 + }, + "end": { + "row": 2, + "col": 28, + "index": 43 + } + }, + "typeParameters": { + "kind": "TSTypeParameterDeclaration", + "params": [ + { + "kind": "TSTypeParameter", + "name": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 2, + "col": 9, + "index": 24 + }, + "end": { + "row": 2, + "col": 10, + "index": 25 + } + }, + "start": { + "row": 2, + "col": 9, + "index": 24 + }, + "end": { + "row": 2, + "col": 10, + "index": 25 + } + } + ], + "start": { + "row": 2, + "col": 8, + "index": 23 + }, + "end": { + "row": 2, + "col": 11, + "index": 26 + } + }, + "start": { + "row": 2, + "col": 5, + "index": 20 + }, + "end": { + "row": 2, + "col": 28, + "index": 43 + } + } + ], + "start": { + "row": 1, + "col": 15, + "index": 14 + }, + "end": { + "row": 3, + "col": 4, + "index": 48 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 3, + "col": 4, + "index": 48 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 4, + "col": 3, + "index": 51 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/generic/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/generic/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/generic/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/generic/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/interface/generic/input.ts new file mode 100644 index 00000000..62f2ede3 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/generic/input.ts @@ -0,0 +1 @@ +interface I {} diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/generic/output.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/generic/output.json new file mode 100644 index 00000000..a17cc8f5 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/generic/output.json @@ -0,0 +1,196 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "TSInterfaceDeclaration", + "name": { + "kind": 10130, + "name": "I", + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + }, + "typeParameters": { + "kind": "TSTypeParameterDeclaration", + "params": [ + { + "kind": "TSTypeParameter", + "constraint": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "object", + "start": { + "row": 1, + "col": 23, + "index": 22 + }, + "end": { + "row": 1, + "col": 29, + "index": 28 + } + }, + "start": { + "row": 1, + "col": 23, + "index": 22 + }, + "end": { + "row": 1, + "col": 29, + "index": 28 + } + }, + "default": { + "kind": "TSTypeLiteral", + "members": [ + { + "kind": "TSPropertySignature", + "key": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 1, + "col": 34, + "index": 33 + }, + "end": { + "row": 1, + "col": 35, + "index": 34 + } + }, + "computed": false, + "optional": false, + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 1, + "col": 37, + "index": 36 + }, + "end": { + "row": 1, + "col": 43, + "index": 42 + } + }, + "start": { + "row": 1, + "col": 35, + "index": 34 + }, + "end": { + "row": 1, + "col": 43, + "index": 42 + } + }, + "start": { + "row": 1, + "col": 34, + "index": 33 + }, + "end": { + "row": 1, + "col": 43, + "index": 42 + } + } + ], + "start": { + "row": 1, + "col": 32, + "index": 31 + }, + "end": { + "row": 1, + "col": 45, + "index": 44 + } + }, + "name": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 13, + "index": 12 + }, + "end": { + "row": 1, + "col": 14, + "index": 13 + } + }, + "start": { + "row": 1, + "col": 13, + "index": 12 + }, + "end": { + "row": 1, + "col": 45, + "index": 44 + } + } + ], + "start": { + "row": 1, + "col": 12, + "index": 11 + }, + "end": { + "row": 1, + "col": 46, + "index": 45 + } + }, + "extends": [], + "body": { + "kind": "TSInterfaceBody", + "body": [], + "start": { + "row": 1, + "col": 47, + "index": 46 + }, + "end": { + "row": 1, + "col": 49, + "index": 48 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 49, + "index": 48 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 49 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/method-computed/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/method-computed/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/method-computed/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/method-computed/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/interface/method-computed/input.ts new file mode 100644 index 00000000..688dc322 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/method-computed/input.ts @@ -0,0 +1,4 @@ +interface I { + [Symbol.iterator](): void; + [Symbol.iterator]?(): number; +} diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/method-computed/output.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/method-computed/output.json new file mode 100644 index 00000000..70997e16 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/method-computed/output.json @@ -0,0 +1,228 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "TSInterfaceDeclaration", + "name": { + "kind": 10130, + "name": "I", + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + }, + "extends": [], + "body": { + "kind": "TSInterfaceBody", + "body": [ + { + "kind": "TSMethodSignature", + "key": { + "kind": "MemberExpression", + "computed": false, + "optional": false, + "object": { + "kind": "Identifer", + "name": "Symbol", + "start": { + "row": 2, + "col": 6, + "index": 19 + }, + "end": { + "row": 2, + "col": 12, + "index": 25 + } + }, + "property": { + "kind": "Identifer", + "name": "iterator", + "start": { + "row": 2, + "col": 13, + "index": 26 + }, + "end": { + "row": 2, + "col": 21, + "index": 34 + } + }, + "start": { + "row": 2, + "col": 6, + "index": 19 + }, + "end": { + "row": 2, + "col": 21, + "index": 34 + } + }, + "computed": true, + "optional": false, + "parameters": [], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSVoidKeyword", + "start": { + "row": 2, + "col": 26, + "index": 39 + }, + "end": { + "row": 2, + "col": 30, + "index": 43 + } + }, + "start": { + "row": 2, + "col": 24, + "index": 37 + }, + "end": { + "row": 2, + "col": 30, + "index": 43 + } + }, + "start": { + "row": 2, + "col": 6, + "index": 19 + }, + "end": { + "row": 2, + "col": 30, + "index": 43 + } + }, + { + "kind": "TSMethodSignature", + "key": { + "kind": "MemberExpression", + "computed": false, + "optional": false, + "object": { + "kind": "Identifer", + "name": "Symbol", + "start": { + "row": 3, + "col": 6, + "index": 50 + }, + "end": { + "row": 3, + "col": 12, + "index": 56 + } + }, + "property": { + "kind": "Identifer", + "name": "iterator", + "start": { + "row": 3, + "col": 13, + "index": 57 + }, + "end": { + "row": 3, + "col": 21, + "index": 65 + } + }, + "start": { + "row": 3, + "col": 6, + "index": 50 + }, + "end": { + "row": 3, + "col": 21, + "index": 65 + } + }, + "computed": true, + "optional": true, + "parameters": [], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 3, + "col": 27, + "index": 71 + }, + "end": { + "row": 3, + "col": 33, + "index": 77 + } + }, + "start": { + "row": 3, + "col": 25, + "index": 69 + }, + "end": { + "row": 3, + "col": 33, + "index": 77 + } + }, + "start": { + "row": 3, + "col": 6, + "index": 50 + }, + "end": { + "row": 3, + "col": 33, + "index": 77 + } + } + ], + "start": { + "row": 1, + "col": 13, + "index": 12 + }, + "end": { + "row": 4, + "col": 2, + "index": 80 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 4, + "col": 2, + "index": 80 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 5, + "col": 1, + "index": 81 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/method-generic/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/method-generic/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/method-generic/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/method-generic/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/interface/method-generic/input.ts new file mode 100644 index 00000000..27f96200 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/method-generic/input.ts @@ -0,0 +1,3 @@ +interface I { + m(): T; +} diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/method-generic/output.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/method-generic/output.json new file mode 100644 index 00000000..6630293f --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/method-generic/output.json @@ -0,0 +1,267 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "TSInterfaceDeclaration", + "name": { + "kind": 10130, + "name": "I", + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + }, + "extends": [], + "body": { + "kind": "TSInterfaceBody", + "body": [ + { + "kind": "TSMethodSignature", + "key": { + "kind": "Identifer", + "name": "m", + "start": { + "row": 2, + "col": 5, + "index": 18 + }, + "end": { + "row": 2, + "col": 6, + "index": 19 + } + }, + "computed": false, + "optional": false, + "parameters": [], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 2, + "col": 44, + "index": 57 + }, + "end": { + "row": 2, + "col": 45, + "index": 58 + } + }, + "start": { + "row": 2, + "col": 44, + "index": 57 + }, + "end": { + "row": 2, + "col": 45, + "index": 58 + } + }, + "start": { + "row": 2, + "col": 42, + "index": 55 + }, + "end": { + "row": 2, + "col": 45, + "index": 58 + } + }, + "typeParameters": { + "kind": "TSTypeParameterDeclaration", + "params": [ + { + "kind": "TSTypeParameter", + "constraint": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "object", + "start": { + "row": 2, + "col": 17, + "index": 30 + }, + "end": { + "row": 2, + "col": 23, + "index": 36 + } + }, + "start": { + "row": 2, + "col": 17, + "index": 30 + }, + "end": { + "row": 2, + "col": 23, + "index": 36 + } + }, + "default": { + "kind": "TSTypeLiteral", + "members": [ + { + "kind": "TSPropertySignature", + "key": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 2, + "col": 28, + "index": 41 + }, + "end": { + "row": 2, + "col": 29, + "index": 42 + } + }, + "computed": false, + "optional": false, + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 2, + "col": 31, + "index": 44 + }, + "end": { + "row": 2, + "col": 37, + "index": 50 + } + }, + "start": { + "row": 2, + "col": 29, + "index": 42 + }, + "end": { + "row": 2, + "col": 37, + "index": 50 + } + }, + "start": { + "row": 2, + "col": 28, + "index": 41 + }, + "end": { + "row": 2, + "col": 37, + "index": 50 + } + } + ], + "start": { + "row": 2, + "col": 26, + "index": 39 + }, + "end": { + "row": 2, + "col": 39, + "index": 52 + } + }, + "name": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 2, + "col": 7, + "index": 20 + }, + "end": { + "row": 2, + "col": 8, + "index": 21 + } + }, + "start": { + "row": 2, + "col": 7, + "index": 20 + }, + "end": { + "row": 2, + "col": 39, + "index": 52 + } + } + ], + "start": { + "row": 2, + "col": 6, + "index": 19 + }, + "end": { + "row": 2, + "col": 40, + "index": 53 + } + }, + "start": { + "row": 2, + "col": 5, + "index": 18 + }, + "end": { + "row": 2, + "col": 45, + "index": 58 + } + } + ], + "start": { + "row": 1, + "col": 13, + "index": 12 + }, + "end": { + "row": 3, + "col": 2, + "index": 61 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 3, + "col": 2, + "index": 61 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 4, + "col": 1, + "index": 62 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/method-optional/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/method-optional/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/method-optional/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/method-optional/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/interface/method-optional/input.ts new file mode 100644 index 00000000..9ceae32a --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/method-optional/input.ts @@ -0,0 +1,3 @@ +interface I { + m?(): void; +} diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/method-optional/output.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/method-optional/output.json new file mode 100644 index 00000000..9aa98f6c --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/method-optional/output.json @@ -0,0 +1,114 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "TSInterfaceDeclaration", + "name": { + "kind": 10130, + "name": "I", + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + }, + "extends": [], + "body": { + "kind": "TSInterfaceBody", + "body": [ + { + "kind": "TSMethodSignature", + "key": { + "kind": "Identifer", + "name": "m", + "start": { + "row": 2, + "col": 5, + "index": 18 + }, + "end": { + "row": 2, + "col": 6, + "index": 19 + } + }, + "computed": false, + "optional": true, + "parameters": [], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSVoidKeyword", + "start": { + "row": 2, + "col": 11, + "index": 24 + }, + "end": { + "row": 2, + "col": 15, + "index": 28 + } + }, + "start": { + "row": 2, + "col": 9, + "index": 22 + }, + "end": { + "row": 2, + "col": 15, + "index": 28 + } + }, + "start": { + "row": 2, + "col": 5, + "index": 18 + }, + "end": { + "row": 2, + "col": 15, + "index": 28 + } + } + ], + "start": { + "row": 1, + "col": 13, + "index": 12 + }, + "end": { + "row": 3, + "col": 2, + "index": 31 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 3, + "col": 2, + "index": 31 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 4, + "col": 1, + "index": 32 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/method-plain/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/method-plain/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/method-plain/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/method-plain/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/interface/method-plain/input.ts new file mode 100644 index 00000000..8d4d83dc --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/method-plain/input.ts @@ -0,0 +1,4 @@ +interface I { + m(); + m(x?: number, ...y: number[]): void; +} diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/method-plain/output.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/method-plain/output.json new file mode 100644 index 00000000..fe40cbef --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/method-plain/output.json @@ -0,0 +1,253 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "TSInterfaceDeclaration", + "name": { + "kind": 10130, + "name": "I", + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + }, + "extends": [], + "body": { + "kind": "TSInterfaceBody", + "body": [ + { + "kind": "TSMethodSignature", + "key": { + "kind": "Identifer", + "name": "m", + "start": { + "row": 2, + "col": 5, + "index": 18 + }, + "end": { + "row": 2, + "col": 6, + "index": 19 + } + }, + "computed": false, + "optional": false, + "parameters": [], + "start": { + "row": 2, + "col": 5, + "index": 18 + }, + "end": { + "row": 2, + "col": 8, + "index": 21 + } + }, + { + "kind": "TSMethodSignature", + "key": { + "kind": "Identifer", + "name": "m", + "start": { + "row": 3, + "col": 5, + "index": 27 + }, + "end": { + "row": 3, + "col": 6, + "index": 28 + } + }, + "computed": false, + "optional": false, + "parameters": [ + { + "kind": "Identifer", + "name": "x", + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 3, + "col": 11, + "index": 33 + }, + "end": { + "row": 3, + "col": 17, + "index": 39 + } + }, + "start": { + "row": 3, + "col": 9, + "index": 31 + }, + "end": { + "row": 3, + "col": 17, + "index": 39 + } + }, + "optional": true, + "start": { + "row": 3, + "col": 7, + "index": 29 + }, + "end": { + "row": 3, + "col": 8, + "index": 30 + } + }, + { + "kind": "RestElement", + "argument": { + "kind": "Identifer", + "name": "y", + "start": { + "row": 3, + "col": 22, + "index": 44 + }, + "end": { + "row": 3, + "col": 23, + "index": 45 + } + }, + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSArrayType", + "elementType": { + "kind": "TSNumberKeyword", + "start": { + "row": 3, + "col": 25, + "index": 47 + }, + "end": { + "row": 3, + "col": 31, + "index": 53 + } + }, + "start": { + "row": 3, + "col": 25, + "index": 47 + }, + "end": { + "row": 3, + "col": 33, + "index": 55 + } + }, + "start": { + "row": 3, + "col": 23, + "index": 45 + }, + "end": { + "row": 3, + "col": 33, + "index": 55 + } + }, + "optional": false, + "start": { + "row": 3, + "col": 19, + "index": 41 + }, + "end": { + "row": 3, + "col": 23, + "index": 45 + } + } + ], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSVoidKeyword", + "start": { + "row": 3, + "col": 36, + "index": 58 + }, + "end": { + "row": 3, + "col": 40, + "index": 62 + } + }, + "start": { + "row": 3, + "col": 34, + "index": 56 + }, + "end": { + "row": 3, + "col": 40, + "index": 62 + } + }, + "start": { + "row": 3, + "col": 5, + "index": 27 + }, + "end": { + "row": 3, + "col": 40, + "index": 62 + } + } + ], + "start": { + "row": 1, + "col": 13, + "index": 12 + }, + "end": { + "row": 4, + "col": 2, + "index": 65 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 4, + "col": 2, + "index": 65 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 5, + "col": 1, + "index": 66 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/new-line-error/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/new-line-error/expect.json new file mode 100644 index 00000000..e5936a86 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/new-line-error/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Failed", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/new-line-error/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/interface/new-line-error/input.ts new file mode 100644 index 00000000..707fdd6c --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/new-line-error/input.ts @@ -0,0 +1,2 @@ +interface +F {} diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/new-line-error/output.txt b/web-infras/parser/tests/fixtures/babel/typescript/interface/new-line-error/output.txt new file mode 100644 index 00000000..84d13b90 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/new-line-error/output.txt @@ -0,0 +1,3 @@ +[SyntaxError]: Missing semicolon or line terminator. (2,3) +2|F {} + | ^ diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/new-line/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/new-line/expect.json new file mode 100644 index 00000000..bfeea3c0 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/new-line/expect.json @@ -0,0 +1,7 @@ +{ + "expect": "Failed", + "config": { + "sourceType": "module", + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/new-line/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/interface/new-line/input.ts new file mode 100644 index 00000000..2c77ad6a --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/new-line/input.ts @@ -0,0 +1,3 @@ +interface +F +{} diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/new-line/output.txt b/web-infras/parser/tests/fixtures/babel/typescript/interface/new-line/output.txt new file mode 100644 index 00000000..8e6f2642 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/new-line/output.txt @@ -0,0 +1,3 @@ +[SyntaxError]: unexpect keyword in strict mode (1,1) +1|interface + |^ diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/pattern-parameters/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/pattern-parameters/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/pattern-parameters/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/pattern-parameters/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/interface/pattern-parameters/input.ts new file mode 100644 index 00000000..b886f007 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/pattern-parameters/input.ts @@ -0,0 +1,6 @@ +interface A { + foo([]?): void; + bar({}, []?): any; + baz(a: string, b: number, []?): void; + } + \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/pattern-parameters/output.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/pattern-parameters/output.json new file mode 100644 index 00000000..f826e51c --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/pattern-parameters/output.json @@ -0,0 +1,371 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "TSInterfaceDeclaration", + "name": { + "kind": 10130, + "name": "A", + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + }, + "extends": [], + "body": { + "kind": "TSInterfaceBody", + "body": [ + { + "kind": "TSMethodSignature", + "key": { + "kind": "Identifer", + "name": "foo", + "start": { + "row": 2, + "col": 5, + "index": 18 + }, + "end": { + "row": 2, + "col": 8, + "index": 21 + } + }, + "computed": false, + "optional": false, + "parameters": [ + { + "kind": "ArrayPattern", + "elements": [], + "start": { + "row": 2, + "col": 9, + "index": 22 + }, + "optional": true, + "end": { + "row": 2, + "col": 11, + "index": 24 + } + } + ], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSVoidKeyword", + "start": { + "row": 2, + "col": 15, + "index": 28 + }, + "end": { + "row": 2, + "col": 19, + "index": 32 + } + }, + "start": { + "row": 2, + "col": 13, + "index": 26 + }, + "end": { + "row": 2, + "col": 19, + "index": 32 + } + }, + "start": { + "row": 2, + "col": 5, + "index": 18 + }, + "end": { + "row": 2, + "col": 19, + "index": 32 + } + }, + { + "kind": "TSMethodSignature", + "key": { + "kind": "Identifer", + "name": "bar", + "start": { + "row": 3, + "col": 5, + "index": 38 + }, + "end": { + "row": 3, + "col": 8, + "index": 41 + } + }, + "computed": false, + "optional": false, + "parameters": [ + { + "kind": "ObjectPattern", + "properties": [], + "optional": false, + "start": { + "row": 3, + "col": 9, + "index": 42 + }, + "end": { + "row": 3, + "col": 11, + "index": 44 + } + }, + { + "kind": "ArrayPattern", + "elements": [], + "start": { + "row": 3, + "col": 13, + "index": 46 + }, + "optional": true, + "end": { + "row": 3, + "col": 15, + "index": 48 + } + } + ], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSAnyKeyword", + "start": { + "row": 3, + "col": 19, + "index": 52 + }, + "end": { + "row": 3, + "col": 22, + "index": 55 + } + }, + "start": { + "row": 3, + "col": 17, + "index": 50 + }, + "end": { + "row": 3, + "col": 22, + "index": 55 + } + }, + "start": { + "row": 3, + "col": 5, + "index": 38 + }, + "end": { + "row": 3, + "col": 22, + "index": 55 + } + }, + { + "kind": "TSMethodSignature", + "key": { + "kind": "Identifer", + "name": "baz", + "start": { + "row": 4, + "col": 5, + "index": 61 + }, + "end": { + "row": 4, + "col": 8, + "index": 64 + } + }, + "computed": false, + "optional": false, + "parameters": [ + { + "kind": "Identifer", + "name": "a", + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSStringKeyword", + "start": { + "row": 4, + "col": 12, + "index": 68 + }, + "end": { + "row": 4, + "col": 18, + "index": 74 + } + }, + "start": { + "row": 4, + "col": 10, + "index": 66 + }, + "end": { + "row": 4, + "col": 18, + "index": 74 + } + }, + "optional": false, + "start": { + "row": 4, + "col": 9, + "index": 65 + }, + "end": { + "row": 4, + "col": 10, + "index": 66 + } + }, + { + "kind": "Identifer", + "name": "b", + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 4, + "col": 23, + "index": 79 + }, + "end": { + "row": 4, + "col": 29, + "index": 85 + } + }, + "start": { + "row": 4, + "col": 21, + "index": 77 + }, + "end": { + "row": 4, + "col": 29, + "index": 85 + } + }, + "optional": false, + "start": { + "row": 4, + "col": 20, + "index": 76 + }, + "end": { + "row": 4, + "col": 21, + "index": 77 + } + }, + { + "kind": "ArrayPattern", + "elements": [], + "start": { + "row": 4, + "col": 31, + "index": 87 + }, + "optional": true, + "end": { + "row": 4, + "col": 33, + "index": 89 + } + } + ], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSVoidKeyword", + "start": { + "row": 4, + "col": 37, + "index": 93 + }, + "end": { + "row": 4, + "col": 41, + "index": 97 + } + }, + "start": { + "row": 4, + "col": 35, + "index": 91 + }, + "end": { + "row": 4, + "col": 41, + "index": 97 + } + }, + "start": { + "row": 4, + "col": 5, + "index": 61 + }, + "end": { + "row": 4, + "col": 41, + "index": 97 + } + } + ], + "start": { + "row": 1, + "col": 13, + "index": 12 + }, + "end": { + "row": 5, + "col": 4, + "index": 102 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 5, + "col": 4, + "index": 102 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 6, + "col": 3, + "index": 105 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/properties/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/properties/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/properties/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/properties/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/interface/properties/input.ts new file mode 100644 index 00000000..94c10ef4 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/properties/input.ts @@ -0,0 +1,5 @@ +interface I { + x; + y: number; + z?: number; +} diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/properties/output.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/properties/output.json new file mode 100644 index 00000000..ab27ec54 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/properties/output.json @@ -0,0 +1,197 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "TSInterfaceDeclaration", + "name": { + "kind": 10130, + "name": "I", + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + }, + "extends": [], + "body": { + "kind": "TSInterfaceBody", + "body": [ + { + "kind": "TSPropertySignature", + "key": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 2, + "col": 5, + "index": 18 + }, + "end": { + "row": 2, + "col": 6, + "index": 19 + } + }, + "computed": false, + "optional": false, + "start": { + "row": 2, + "col": 5, + "index": 18 + }, + "end": { + "row": 2, + "col": 6, + "index": 19 + } + }, + { + "kind": "TSPropertySignature", + "key": { + "kind": "Identifer", + "name": "y", + "start": { + "row": 3, + "col": 5, + "index": 25 + }, + "end": { + "row": 3, + "col": 6, + "index": 26 + } + }, + "computed": false, + "optional": false, + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 3, + "col": 8, + "index": 28 + }, + "end": { + "row": 3, + "col": 14, + "index": 34 + } + }, + "start": { + "row": 3, + "col": 6, + "index": 26 + }, + "end": { + "row": 3, + "col": 14, + "index": 34 + } + }, + "start": { + "row": 3, + "col": 5, + "index": 25 + }, + "end": { + "row": 3, + "col": 14, + "index": 34 + } + }, + { + "kind": "TSPropertySignature", + "key": { + "kind": "Identifer", + "name": "z", + "start": { + "row": 4, + "col": 5, + "index": 40 + }, + "end": { + "row": 4, + "col": 6, + "index": 41 + } + }, + "computed": false, + "optional": true, + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 4, + "col": 9, + "index": 44 + }, + "end": { + "row": 4, + "col": 15, + "index": 50 + } + }, + "start": { + "row": 4, + "col": 7, + "index": 42 + }, + "end": { + "row": 4, + "col": 15, + "index": 50 + } + }, + "start": { + "row": 4, + "col": 5, + "index": 40 + }, + "end": { + "row": 4, + "col": 15, + "index": 50 + } + } + ], + "start": { + "row": 1, + "col": 13, + "index": 12 + }, + "end": { + "row": 5, + "col": 2, + "index": 53 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 5, + "col": 2, + "index": 53 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 6, + "col": 1, + "index": 54 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/property-computed/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/property-computed/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/property-computed/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/property-computed/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/interface/property-computed/input.ts new file mode 100644 index 00000000..78f3ac4a --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/property-computed/input.ts @@ -0,0 +1,4 @@ +interface I { + [Symbol.iterator]: number; + [Symbol.iterator]?: number; +} diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/property-computed/output.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/property-computed/output.json new file mode 100644 index 00000000..e01b2ed5 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/property-computed/output.json @@ -0,0 +1,226 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "TSInterfaceDeclaration", + "name": { + "kind": 10130, + "name": "I", + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + }, + "extends": [], + "body": { + "kind": "TSInterfaceBody", + "body": [ + { + "kind": "TSPropertySignature", + "key": { + "kind": "MemberExpression", + "computed": false, + "optional": false, + "object": { + "kind": "Identifer", + "name": "Symbol", + "start": { + "row": 2, + "col": 6, + "index": 19 + }, + "end": { + "row": 2, + "col": 12, + "index": 25 + } + }, + "property": { + "kind": "Identifer", + "name": "iterator", + "start": { + "row": 2, + "col": 13, + "index": 26 + }, + "end": { + "row": 2, + "col": 21, + "index": 34 + } + }, + "start": { + "row": 2, + "col": 6, + "index": 19 + }, + "end": { + "row": 2, + "col": 21, + "index": 34 + } + }, + "computed": true, + "optional": false, + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 2, + "col": 24, + "index": 37 + }, + "end": { + "row": 2, + "col": 30, + "index": 43 + } + }, + "start": { + "row": 2, + "col": 22, + "index": 35 + }, + "end": { + "row": 2, + "col": 30, + "index": 43 + } + }, + "start": { + "row": 2, + "col": 6, + "index": 19 + }, + "end": { + "row": 2, + "col": 30, + "index": 43 + } + }, + { + "kind": "TSPropertySignature", + "key": { + "kind": "MemberExpression", + "computed": false, + "optional": false, + "object": { + "kind": "Identifer", + "name": "Symbol", + "start": { + "row": 3, + "col": 6, + "index": 50 + }, + "end": { + "row": 3, + "col": 12, + "index": 56 + } + }, + "property": { + "kind": "Identifer", + "name": "iterator", + "start": { + "row": 3, + "col": 13, + "index": 57 + }, + "end": { + "row": 3, + "col": 21, + "index": 65 + } + }, + "start": { + "row": 3, + "col": 6, + "index": 50 + }, + "end": { + "row": 3, + "col": 21, + "index": 65 + } + }, + "computed": true, + "optional": true, + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 3, + "col": 25, + "index": 69 + }, + "end": { + "row": 3, + "col": 31, + "index": 75 + } + }, + "start": { + "row": 3, + "col": 23, + "index": 67 + }, + "end": { + "row": 3, + "col": 31, + "index": 75 + } + }, + "start": { + "row": 3, + "col": 6, + "index": 50 + }, + "end": { + "row": 3, + "col": 31, + "index": 75 + } + } + ], + "start": { + "row": 1, + "col": 13, + "index": 12 + }, + "end": { + "row": 4, + "col": 2, + "index": 78 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 4, + "col": 2, + "index": 78 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 5, + "col": 1, + "index": 79 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/property-initializer/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/property-initializer/expect.json new file mode 100644 index 00000000..e5936a86 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/property-initializer/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Failed", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/property-initializer/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/interface/property-initializer/input.ts new file mode 100644 index 00000000..2eb4e828 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/property-initializer/input.ts @@ -0,0 +1 @@ +interface I { x: number = 1;} diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/property-initializer/output.txt b/web-infras/parser/tests/fixtures/babel/typescript/interface/property-initializer/output.txt new file mode 100644 index 00000000..9992215b --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/property-initializer/output.txt @@ -0,0 +1 @@ +[Syntax Error]: Unexpect token =(1, 25). \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/reserved-method-name/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/reserved-method-name/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/reserved-method-name/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/reserved-method-name/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/interface/reserved-method-name/input.ts new file mode 100644 index 00000000..76dff7a5 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/reserved-method-name/input.ts @@ -0,0 +1,3 @@ +interface I { + catch(): void; +} diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/reserved-method-name/output.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/reserved-method-name/output.json new file mode 100644 index 00000000..3b44da77 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/reserved-method-name/output.json @@ -0,0 +1,114 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "TSInterfaceDeclaration", + "name": { + "kind": 10130, + "name": "I", + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + }, + "extends": [], + "body": { + "kind": "TSInterfaceBody", + "body": [ + { + "kind": "TSMethodSignature", + "key": { + "kind": "Identifer", + "name": "catch", + "start": { + "row": 2, + "col": 5, + "index": 18 + }, + "end": { + "row": 2, + "col": 10, + "index": 23 + } + }, + "computed": false, + "optional": false, + "parameters": [], + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSVoidKeyword", + "start": { + "row": 2, + "col": 14, + "index": 27 + }, + "end": { + "row": 2, + "col": 18, + "index": 31 + } + }, + "start": { + "row": 2, + "col": 12, + "index": 25 + }, + "end": { + "row": 2, + "col": 18, + "index": 31 + } + }, + "start": { + "row": 2, + "col": 5, + "index": 18 + }, + "end": { + "row": 2, + "col": 18, + "index": 31 + } + } + ], + "start": { + "row": 1, + "col": 13, + "index": 12 + }, + "end": { + "row": 3, + "col": 2, + "index": 34 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 3, + "col": 2, + "index": 34 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 4, + "col": 1, + "index": 35 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/separators/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/separators/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/separators/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/separators/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/interface/separators/input.ts new file mode 100644 index 00000000..f8e941cd --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/separators/input.ts @@ -0,0 +1,6 @@ +interface Comma { x: number, y: number } +interface Semi { x: number; y: number } +interface Newline { + x: number + y: number +} diff --git a/web-infras/parser/tests/fixtures/babel/typescript/interface/separators/output.json b/web-infras/parser/tests/fixtures/babel/typescript/interface/separators/output.json new file mode 100644 index 00000000..6c43e921 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/interface/separators/output.json @@ -0,0 +1,474 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "TSInterfaceDeclaration", + "name": { + "kind": 10130, + "name": "Comma", + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 16, + "index": 15 + } + }, + "extends": [], + "body": { + "kind": "TSInterfaceBody", + "body": [ + { + "kind": "TSPropertySignature", + "key": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 1, + "col": 19, + "index": 18 + }, + "end": { + "row": 1, + "col": 20, + "index": 19 + } + }, + "computed": false, + "optional": false, + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 1, + "col": 22, + "index": 21 + }, + "end": { + "row": 1, + "col": 28, + "index": 27 + } + }, + "start": { + "row": 1, + "col": 20, + "index": 19 + }, + "end": { + "row": 1, + "col": 28, + "index": 27 + } + }, + "start": { + "row": 1, + "col": 19, + "index": 18 + }, + "end": { + "row": 1, + "col": 28, + "index": 27 + } + }, + { + "kind": "TSPropertySignature", + "key": { + "kind": "Identifer", + "name": "y", + "start": { + "row": 1, + "col": 30, + "index": 29 + }, + "end": { + "row": 1, + "col": 31, + "index": 30 + } + }, + "computed": false, + "optional": false, + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 1, + "col": 33, + "index": 32 + }, + "end": { + "row": 1, + "col": 39, + "index": 38 + } + }, + "start": { + "row": 1, + "col": 31, + "index": 30 + }, + "end": { + "row": 1, + "col": 39, + "index": 38 + } + }, + "start": { + "row": 1, + "col": 30, + "index": 29 + }, + "end": { + "row": 1, + "col": 39, + "index": 38 + } + } + ], + "start": { + "row": 1, + "col": 17, + "index": 16 + }, + "end": { + "row": 1, + "col": 41, + "index": 40 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 41, + "index": 40 + } + }, + { + "kind": "TSInterfaceDeclaration", + "name": { + "kind": 10130, + "name": "Semi", + "start": { + "row": 2, + "col": 11, + "index": 51 + }, + "end": { + "row": 2, + "col": 15, + "index": 55 + } + }, + "extends": [], + "body": { + "kind": "TSInterfaceBody", + "body": [ + { + "kind": "TSPropertySignature", + "key": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 2, + "col": 18, + "index": 58 + }, + "end": { + "row": 2, + "col": 19, + "index": 59 + } + }, + "computed": false, + "optional": false, + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 2, + "col": 21, + "index": 61 + }, + "end": { + "row": 2, + "col": 27, + "index": 67 + } + }, + "start": { + "row": 2, + "col": 19, + "index": 59 + }, + "end": { + "row": 2, + "col": 27, + "index": 67 + } + }, + "start": { + "row": 2, + "col": 18, + "index": 58 + }, + "end": { + "row": 2, + "col": 27, + "index": 67 + } + }, + { + "kind": "TSPropertySignature", + "key": { + "kind": "Identifer", + "name": "y", + "start": { + "row": 2, + "col": 29, + "index": 69 + }, + "end": { + "row": 2, + "col": 30, + "index": 70 + } + }, + "computed": false, + "optional": false, + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 2, + "col": 32, + "index": 72 + }, + "end": { + "row": 2, + "col": 38, + "index": 78 + } + }, + "start": { + "row": 2, + "col": 30, + "index": 70 + }, + "end": { + "row": 2, + "col": 38, + "index": 78 + } + }, + "start": { + "row": 2, + "col": 29, + "index": 69 + }, + "end": { + "row": 2, + "col": 38, + "index": 78 + } + } + ], + "start": { + "row": 2, + "col": 16, + "index": 56 + }, + "end": { + "row": 2, + "col": 40, + "index": 80 + } + }, + "start": { + "row": 2, + "col": 1, + "index": 41 + }, + "end": { + "row": 2, + "col": 40, + "index": 80 + } + }, + { + "kind": "TSInterfaceDeclaration", + "name": { + "kind": 10130, + "name": "Newline", + "start": { + "row": 3, + "col": 11, + "index": 91 + }, + "end": { + "row": 3, + "col": 18, + "index": 98 + } + }, + "extends": [], + "body": { + "kind": "TSInterfaceBody", + "body": [ + { + "kind": "TSPropertySignature", + "key": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 4, + "col": 5, + "index": 105 + }, + "end": { + "row": 4, + "col": 6, + "index": 106 + } + }, + "computed": false, + "optional": false, + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 4, + "col": 8, + "index": 108 + }, + "end": { + "row": 4, + "col": 14, + "index": 114 + } + }, + "start": { + "row": 4, + "col": 6, + "index": 106 + }, + "end": { + "row": 4, + "col": 14, + "index": 114 + } + }, + "start": { + "row": 4, + "col": 5, + "index": 105 + }, + "end": { + "row": 4, + "col": 14, + "index": 114 + } + }, + { + "kind": "TSPropertySignature", + "key": { + "kind": "Identifer", + "name": "y", + "start": { + "row": 5, + "col": 5, + "index": 119 + }, + "end": { + "row": 5, + "col": 6, + "index": 120 + } + }, + "computed": false, + "optional": false, + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 5, + "col": 8, + "index": 122 + }, + "end": { + "row": 5, + "col": 14, + "index": 128 + } + }, + "start": { + "row": 5, + "col": 6, + "index": 120 + }, + "end": { + "row": 5, + "col": 14, + "index": 128 + } + }, + "start": { + "row": 5, + "col": 5, + "index": 119 + }, + "end": { + "row": 5, + "col": 14, + "index": 128 + } + } + ], + "start": { + "row": 3, + "col": 19, + "index": 99 + }, + "end": { + "row": 6, + "col": 2, + "index": 130 + } + }, + "start": { + "row": 3, + "col": 1, + "index": 81 + }, + "end": { + "row": 6, + "col": 2, + "index": 130 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 7, + "col": 1, + "index": 131 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-alias/generic-complex-tokens-true/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/type-alias/generic-complex-tokens-true/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-alias/generic-complex-tokens-true/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-alias/generic-complex-tokens-true/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/type-alias/generic-complex-tokens-true/input.ts new file mode 100644 index 00000000..9fb8928d --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-alias/generic-complex-tokens-true/input.ts @@ -0,0 +1 @@ +type T = Array; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-alias/generic-complex-tokens-true/output.json b/web-infras/parser/tests/fixtures/babel/typescript/type-alias/generic-complex-tokens-true/output.json new file mode 100644 index 00000000..873fee5f --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-alias/generic-complex-tokens-true/output.json @@ -0,0 +1,250 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "TSTypeAliasDeclaration", + "name": { + "kind": 10130, + "name": "T", + "start": { + "row": 1, + "col": 6, + "index": 5 + }, + "end": { + "row": 1, + "col": 7, + "index": 6 + } + }, + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "Array", + "start": { + "row": 1, + "col": 44, + "index": 43 + }, + "end": { + "row": 1, + "col": 49, + "index": 48 + } + }, + "typeArguments": { + "kind": "TSTypeParameterInstantiation", + "params": [ + { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "U", + "start": { + "row": 1, + "col": 50, + "index": 49 + }, + "end": { + "row": 1, + "col": 51, + "index": 50 + } + }, + "start": { + "row": 1, + "col": 50, + "index": 49 + }, + "end": { + "row": 1, + "col": 51, + "index": 50 + } + } + ], + "start": { + "row": 1, + "col": 49, + "index": 48 + }, + "end": { + "row": 1, + "col": 52, + "index": 51 + } + }, + "start": { + "row": 1, + "col": 44, + "index": 43 + }, + "end": { + "row": 1, + "col": 49, + "index": 48 + } + }, + "typeParameters": { + "kind": "TSTypeParameterDeclaration", + "params": [ + { + "kind": "TSTypeParameter", + "constraint": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "object", + "start": { + "row": 1, + "col": 18, + "index": 17 + }, + "end": { + "row": 1, + "col": 24, + "index": 23 + } + }, + "start": { + "row": 1, + "col": 18, + "index": 17 + }, + "end": { + "row": 1, + "col": 24, + "index": 23 + } + }, + "default": { + "kind": "TSTypeLiteral", + "members": [ + { + "kind": "TSPropertySignature", + "key": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 1, + "col": 29, + "index": 28 + }, + "end": { + "row": 1, + "col": 30, + "index": 29 + } + }, + "computed": false, + "optional": false, + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 1, + "col": 32, + "index": 31 + }, + "end": { + "row": 1, + "col": 38, + "index": 37 + } + }, + "start": { + "row": 1, + "col": 30, + "index": 29 + }, + "end": { + "row": 1, + "col": 38, + "index": 37 + } + }, + "start": { + "row": 1, + "col": 29, + "index": 28 + }, + "end": { + "row": 1, + "col": 38, + "index": 37 + } + } + ], + "start": { + "row": 1, + "col": 27, + "index": 26 + }, + "end": { + "row": 1, + "col": 40, + "index": 39 + } + }, + "name": { + "kind": "Identifer", + "name": "U", + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 1, + "col": 9, + "index": 8 + } + }, + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 1, + "col": 40, + "index": 39 + } + } + ], + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 41, + "index": 40 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 53, + "index": 52 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 53 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-alias/generic/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/type-alias/generic/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-alias/generic/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-alias/generic/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/type-alias/generic/input.ts new file mode 100644 index 00000000..48dcc5dd --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-alias/generic/input.ts @@ -0,0 +1 @@ +type T=U; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-alias/generic/output.json b/web-infras/parser/tests/fixtures/babel/typescript/type-alias/generic/output.json new file mode 100644 index 00000000..c8fe72fc --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-alias/generic/output.json @@ -0,0 +1,111 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "TSTypeAliasDeclaration", + "name": { + "kind": 10130, + "name": "T", + "start": { + "row": 1, + "col": 6, + "index": 5 + }, + "end": { + "row": 1, + "col": 7, + "index": 6 + } + }, + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "U", + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + }, + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + }, + "typeParameters": { + "kind": "TSTypeParameterDeclaration", + "params": [ + { + "kind": "TSTypeParameter", + "name": { + "kind": "Identifer", + "name": "U", + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 1, + "col": 9, + "index": 8 + } + }, + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 1, + "col": 9, + "index": 8 + } + } + ], + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 10, + "index": 9 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 13, + "index": 12 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 13 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-alias/plain/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/type-alias/plain/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-alias/plain/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-alias/plain/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/type-alias/plain/input.ts new file mode 100644 index 00000000..42126b96 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-alias/plain/input.ts @@ -0,0 +1 @@ +type T = number; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-alias/plain/output.json b/web-infras/parser/tests/fixtures/babel/typescript/type-alias/plain/output.json new file mode 100644 index 00000000..f7a41329 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-alias/plain/output.json @@ -0,0 +1,55 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "TSTypeAliasDeclaration", + "name": { + "kind": 10130, + "name": "T", + "start": { + "row": 1, + "col": 6, + "index": 5 + }, + "end": { + "row": 1, + "col": 7, + "index": 6 + } + }, + "typeAnnotation": { + "kind": "TSNumberKeyword", + "start": { + "row": 1, + "col": 10, + "index": 9 + }, + "end": { + "row": 1, + "col": 16, + "index": 15 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 17, + "index": 16 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 17 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/after-bit-shift/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/after-bit-shift/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/after-bit-shift/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/after-bit-shift/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/after-bit-shift/input.ts new file mode 100644 index 00000000..22101bcf --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/after-bit-shift/input.ts @@ -0,0 +1 @@ +f<<(x) diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/after-bit-shift/output.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/after-bit-shift/output.json new file mode 100644 index 00000000..d8333915 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/after-bit-shift/output.json @@ -0,0 +1,111 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "BinaryExpression", + "operator": "<<", + "left": { + "kind": "Identifer", + "name": "f", + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 2, + "index": 1 + } + }, + "right": { + "kind": "TSTypeAssertionExpression", + "expression": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 1, + "col": 9, + "index": 8 + }, + "parentheses": true + }, + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 5, + "index": 4 + }, + "end": { + "row": 1, + "col": 6, + "index": 5 + } + }, + "start": { + "row": 1, + "col": 5, + "index": 4 + }, + "end": { + "row": 1, + "col": 6, + "index": 5 + } + }, + "start": { + "row": 1, + "col": 4, + "index": 3 + }, + "end": { + "row": 1, + "col": 10, + "index": 9 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 10, + "index": 9 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 10, + "index": 9 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 10 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/call-expression/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/call-expression/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/call-expression/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/call-expression/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/call-expression/input.ts new file mode 100644 index 00000000..94b8ba09 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/call-expression/input.ts @@ -0,0 +1 @@ +f<(v: T) => void>(); diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/call-expression/output.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/call-expression/output.json new file mode 100644 index 00000000..3a0cf7c9 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/call-expression/output.json @@ -0,0 +1,210 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "CallExpression", + "optional": false, + "callee": { + "kind": "Identifer", + "name": "f", + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 2, + "index": 1 + } + }, + "typeArguments": { + "kind": "TSTypeParameterInstantiation", + "params": [ + { + "kind": "TSFunctionType", + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSVoidKeyword", + "start": { + "row": 1, + "col": 16, + "index": 15 + }, + "end": { + "row": 1, + "col": 20, + "index": 19 + } + }, + "start": { + "row": 1, + "col": 13, + "index": 12 + }, + "end": { + "row": 1, + "col": 20, + "index": 19 + } + }, + "parameters": [ + { + "kind": "Identifer", + "name": "v", + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 10, + "index": 9 + }, + "end": { + "row": 1, + "col": 11, + "index": 10 + } + }, + "start": { + "row": 1, + "col": 10, + "index": 9 + }, + "end": { + "row": 1, + "col": 11, + "index": 10 + } + }, + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 1, + "col": 11, + "index": 10 + } + }, + "optional": false, + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 8, + "index": 7 + } + } + ], + "typeParameters": { + "kind": "TSTypeParameterDeclaration", + "params": [ + { + "kind": "TSTypeParameter", + "name": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 4, + "index": 3 + }, + "end": { + "row": 1, + "col": 5, + "index": 4 + } + }, + "start": { + "row": 1, + "col": 4, + "index": 3 + }, + "end": { + "row": 1, + "col": 5, + "index": 4 + } + } + ], + "start": { + "row": 1, + "col": 3, + "index": 2 + }, + "end": { + "row": 1, + "col": 6, + "index": 5 + } + }, + "start": { + "row": 1, + "col": 3, + "index": 2 + }, + "end": { + "row": 1, + "col": 20, + "index": 19 + } + } + ], + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 21, + "index": 20 + } + }, + "arguments": [], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 23, + "index": 22 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 23, + "index": 22 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 24 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/new-expression/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/new-expression/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/new-expression/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/new-expression/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/new-expression/input.ts new file mode 100644 index 00000000..7991a4bb --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/new-expression/input.ts @@ -0,0 +1 @@ +new f<(v: T) => void>(); diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/new-expression/output.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/new-expression/output.json new file mode 100644 index 00000000..14022fc4 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/new-expression/output.json @@ -0,0 +1,209 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "NewExpression", + "callee": { + "kind": "Identifer", + "name": "f", + "start": { + "row": 1, + "col": 5, + "index": 4 + }, + "end": { + "row": 1, + "col": 6, + "index": 5 + } + }, + "arguments": [], + "typeArguments": { + "kind": "TSTypeParameterInstantiation", + "params": [ + { + "kind": "TSFunctionType", + "returnType": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSVoidKeyword", + "start": { + "row": 1, + "col": 20, + "index": 19 + }, + "end": { + "row": 1, + "col": 24, + "index": 23 + } + }, + "start": { + "row": 1, + "col": 17, + "index": 16 + }, + "end": { + "row": 1, + "col": 24, + "index": 23 + } + }, + "parameters": [ + { + "kind": "Identifer", + "name": "v", + "typeAnnotation": { + "kind": "TSTypeAnnotation", + "typeAnnotation": { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 14, + "index": 13 + }, + "end": { + "row": 1, + "col": 15, + "index": 14 + } + }, + "start": { + "row": 1, + "col": 14, + "index": 13 + }, + "end": { + "row": 1, + "col": 15, + "index": 14 + } + }, + "start": { + "row": 1, + "col": 12, + "index": 11 + }, + "end": { + "row": 1, + "col": 15, + "index": 14 + } + }, + "optional": false, + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + } + ], + "typeParameters": { + "kind": "TSTypeParameterDeclaration", + "params": [ + { + "kind": "TSTypeParameter", + "name": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 1, + "col": 9, + "index": 8 + } + }, + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 1, + "col": 9, + "index": 8 + } + } + ], + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 10, + "index": 9 + } + }, + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 24, + "index": 23 + } + } + ], + "start": { + "row": 1, + "col": 6, + "index": 5 + }, + "end": { + "row": 1, + "col": 25, + "index": 24 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 27, + "index": 26 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 27, + "index": 26 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 28 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/type-arguments-like/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/type-arguments-like/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/type-arguments-like/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/type-arguments-like/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/type-arguments-like/input.ts new file mode 100644 index 00000000..7e2a54ba --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/type-arguments-like/input.ts @@ -0,0 +1 @@ +f<< T > (()=>T) > T diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/type-arguments-like/output.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/type-arguments-like/output.json new file mode 100644 index 00000000..a3deafcc --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments-bit-shift-left-like/type-arguments-like/output.json @@ -0,0 +1,143 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "BinaryExpression", + "operator": ">", + "left": { + "kind": "BinaryExpression", + "operator": ">", + "left": { + "kind": "BinaryExpression", + "operator": "<<", + "left": { + "kind": "Identifer", + "name": "f", + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 2, + "index": 1 + } + }, + "right": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 5, + "index": 4 + }, + "end": { + "row": 1, + "col": 6, + "index": 5 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 6, + "index": 5 + } + }, + "right": { + "kind": "ArrowFunctionExpression", + "expressionBody": true, + "async": false, + "arguments": [], + "body": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 14, + "index": 13 + }, + "end": { + "row": 1, + "col": 15, + "index": 14 + } + }, + "start": { + "row": 1, + "col": 10, + "index": 9 + }, + "end": { + "row": 1, + "col": 15, + "index": 14 + }, + "parentheses": true + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 15, + "index": 14 + } + }, + "right": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 19, + "index": 18 + }, + "end": { + "row": 1, + "col": 20, + "index": 19 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 20, + "index": 19 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 20, + "index": 19 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 20 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call-newline/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call-newline/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call-newline/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call-newline/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call-newline/input.ts new file mode 100644 index 00000000..cfa4f2ee --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call-newline/input.ts @@ -0,0 +1,2 @@ +makeBox +(a) diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call-newline/output.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call-newline/output.json new file mode 100644 index 00000000..a492ec32 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call-newline/output.json @@ -0,0 +1,100 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "CallExpression", + "optional": false, + "callee": { + "kind": "Identifer", + "name": "makeBox", + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 8, + "index": 7 + } + }, + "typeArguments": { + "kind": "TSTypeParameterInstantiation", + "params": [ + { + "kind": "TSNumberKeyword", + "start": { + "row": 1, + "col": 9, + "index": 8 + }, + "end": { + "row": 1, + "col": 15, + "index": 14 + } + } + ], + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 1, + "col": 16, + "index": 15 + } + }, + "arguments": [ + { + "kind": "Identifer", + "name": "a", + "start": { + "row": 2, + "col": 2, + "index": 17 + }, + "end": { + "row": 2, + "col": 3, + "index": 18 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 4, + "index": 19 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 4, + "index": 19 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 3, + "col": 1, + "index": 20 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call-optional-chain-invalid/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call-optional-chain-invalid/expect.json new file mode 100644 index 00000000..e5936a86 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call-optional-chain-invalid/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Failed", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call-optional-chain-invalid/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call-optional-chain-invalid/input.ts new file mode 100644 index 00000000..ba51adb7 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call-optional-chain-invalid/input.ts @@ -0,0 +1 @@ +f?.[1]; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call-optional-chain-invalid/output.txt b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call-optional-chain-invalid/output.txt new file mode 100644 index 00000000..0593796a --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call-optional-chain-invalid/output.txt @@ -0,0 +1 @@ +[Syntax Error]: Unexpect token <(1, 4). \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call-optional-chain/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call-optional-chain/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call-optional-chain/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call-optional-chain/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call-optional-chain/input.ts new file mode 100644 index 00000000..1f2bdf0d --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call-optional-chain/input.ts @@ -0,0 +1,4 @@ +f?.(); +f?.(); +f +?.(); diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call-optional-chain/output.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call-optional-chain/output.json new file mode 100644 index 00000000..9eef9755 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call-optional-chain/output.json @@ -0,0 +1,333 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "ChainExpression", + "expression": { + "kind": "CallExpression", + "optional": true, + "callee": { + "kind": "Identifer", + "name": "f", + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 2, + "index": 1 + } + }, + "typeArguments": { + "kind": "TSTypeParameterInstantiation", + "params": [ + { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "Q", + "start": { + "row": 1, + "col": 5, + "index": 4 + }, + "end": { + "row": 1, + "col": 6, + "index": 5 + } + }, + "start": { + "row": 1, + "col": 5, + "index": 4 + }, + "end": { + "row": 1, + "col": 6, + "index": 5 + } + } + ], + "start": { + "row": 1, + "col": 4, + "index": 3 + }, + "end": { + "row": 1, + "col": 7, + "index": 6 + } + }, + "arguments": [], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 9, + "index": 8 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 9, + "index": 8 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 9, + "index": 8 + } + }, + { + "kind": "ExpressionStatement", + "expr": { + "kind": "ChainExpression", + "expression": { + "kind": "CallExpression", + "optional": true, + "callee": { + "kind": "Identifer", + "name": "f", + "start": { + "row": 2, + "col": 1, + "index": 10 + }, + "end": { + "row": 2, + "col": 2, + "index": 11 + } + }, + "typeArguments": { + "kind": "TSTypeParameterInstantiation", + "params": [ + { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "Q", + "start": { + "row": 2, + "col": 5, + "index": 14 + }, + "end": { + "row": 2, + "col": 6, + "index": 15 + } + }, + "start": { + "row": 2, + "col": 5, + "index": 14 + }, + "end": { + "row": 2, + "col": 6, + "index": 15 + } + }, + { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "W", + "start": { + "row": 2, + "col": 8, + "index": 17 + }, + "end": { + "row": 2, + "col": 9, + "index": 18 + } + }, + "start": { + "row": 2, + "col": 8, + "index": 17 + }, + "end": { + "row": 2, + "col": 9, + "index": 18 + } + } + ], + "start": { + "row": 2, + "col": 4, + "index": 13 + }, + "end": { + "row": 2, + "col": 10, + "index": 19 + } + }, + "arguments": [], + "start": { + "row": 2, + "col": 1, + "index": 10 + }, + "end": { + "row": 2, + "col": 12, + "index": 21 + } + }, + "start": { + "row": 2, + "col": 1, + "index": 10 + }, + "end": { + "row": 2, + "col": 12, + "index": 21 + } + }, + "start": { + "row": 2, + "col": 1, + "index": 10 + }, + "end": { + "row": 2, + "col": 12, + "index": 21 + } + }, + { + "kind": "ExpressionStatement", + "expr": { + "kind": "ChainExpression", + "expression": { + "kind": "CallExpression", + "optional": true, + "callee": { + "kind": "Identifer", + "name": "f", + "start": { + "row": 3, + "col": 1, + "index": 23 + }, + "end": { + "row": 3, + "col": 2, + "index": 24 + } + }, + "typeArguments": { + "kind": "TSTypeParameterInstantiation", + "params": [ + { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "Q", + "start": { + "row": 4, + "col": 4, + "index": 28 + }, + "end": { + "row": 4, + "col": 5, + "index": 29 + } + }, + "start": { + "row": 4, + "col": 4, + "index": 28 + }, + "end": { + "row": 4, + "col": 5, + "index": 29 + } + } + ], + "start": { + "row": 4, + "col": 3, + "index": 27 + }, + "end": { + "row": 4, + "col": 6, + "index": 30 + } + }, + "arguments": [], + "start": { + "row": 3, + "col": 1, + "index": 23 + }, + "end": { + "row": 4, + "col": 8, + "index": 32 + } + }, + "start": { + "row": 3, + "col": 1, + "index": 23 + }, + "end": { + "row": 4, + "col": 8, + "index": 32 + } + }, + "start": { + "row": 3, + "col": 1, + "index": 23 + }, + "end": { + "row": 4, + "col": 8, + "index": 32 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 5, + "col": 1, + "index": 34 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call/input.ts new file mode 100644 index 00000000..3a4d08a5 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call/input.ts @@ -0,0 +1,2 @@ +f(); +f(); diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call/output.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call/output.json new file mode 100644 index 00000000..3a2d1278 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/call/output.json @@ -0,0 +1,210 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "CallExpression", + "optional": false, + "callee": { + "kind": "Identifer", + "name": "f", + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 2, + "index": 1 + } + }, + "typeArguments": { + "kind": "TSTypeParameterInstantiation", + "params": [ + { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 3, + "index": 2 + }, + "end": { + "row": 1, + "col": 4, + "index": 3 + } + }, + "start": { + "row": 1, + "col": 3, + "index": 2 + }, + "end": { + "row": 1, + "col": 4, + "index": 3 + } + } + ], + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 5, + "index": 4 + } + }, + "arguments": [], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 7, + "index": 6 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 7, + "index": 6 + } + }, + { + "kind": "ExpressionStatement", + "expr": { + "kind": "CallExpression", + "optional": false, + "callee": { + "kind": "Identifer", + "name": "f", + "start": { + "row": 2, + "col": 1, + "index": 8 + }, + "end": { + "row": 2, + "col": 2, + "index": 9 + } + }, + "typeArguments": { + "kind": "TSTypeParameterInstantiation", + "params": [ + { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 2, + "col": 3, + "index": 10 + }, + "end": { + "row": 2, + "col": 4, + "index": 11 + } + }, + "start": { + "row": 2, + "col": 3, + "index": 10 + }, + "end": { + "row": 2, + "col": 4, + "index": 11 + } + }, + { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "U", + "start": { + "row": 2, + "col": 6, + "index": 13 + }, + "end": { + "row": 2, + "col": 7, + "index": 14 + } + }, + "start": { + "row": 2, + "col": 6, + "index": 13 + }, + "end": { + "row": 2, + "col": 7, + "index": 14 + } + } + ], + "start": { + "row": 2, + "col": 2, + "index": 9 + }, + "end": { + "row": 2, + "col": 8, + "index": 15 + } + }, + "arguments": [], + "start": { + "row": 2, + "col": 1, + "index": 8 + }, + "end": { + "row": 2, + "col": 10, + "index": 17 + } + }, + "start": { + "row": 2, + "col": 1, + "index": 8 + }, + "end": { + "row": 2, + "col": 10, + "index": 17 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 3, + "col": 1, + "index": 19 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/empty-function/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/empty-function/expect.json new file mode 100644 index 00000000..e5936a86 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/empty-function/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Failed", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/empty-function/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/empty-function/input.ts new file mode 100644 index 00000000..63cf8bbe --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/empty-function/input.ts @@ -0,0 +1 @@ +foo<>() diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/empty-function/output.txt b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/empty-function/output.txt new file mode 100644 index 00000000..bd5a3cac --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/empty-function/output.txt @@ -0,0 +1 @@ +[Syntax Error]: Unexpect token >(1, 5). \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-2/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-2/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-2/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-2/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-2/input.ts new file mode 100644 index 00000000..9a26b526 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-2/input.ts @@ -0,0 +1 @@ +a>c; \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-2/output.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-2/output.json new file mode 100644 index 00000000..1dd5c2a5 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-2/output.json @@ -0,0 +1,98 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "BinaryExpression", + "operator": "<", + "left": { + "kind": "Identifer", + "name": "a", + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 2, + "index": 1 + } + }, + "right": { + "kind": "BinaryExpression", + "operator": ">>", + "left": { + "kind": "Identifer", + "name": "b", + "start": { + "row": 1, + "col": 3, + "index": 2 + }, + "end": { + "row": 1, + "col": 4, + "index": 3 + } + }, + "right": { + "kind": "Identifer", + "name": "c", + "start": { + "row": 1, + "col": 6, + "index": 5 + }, + "end": { + "row": 1, + "col": 7, + "index": 6 + } + }, + "start": { + "row": 1, + "col": 3, + "index": 2 + }, + "end": { + "row": 1, + "col": 7, + "index": 6 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 7, + "index": 6 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 7, + "index": 6 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 8, + "index": 7 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-3/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-3/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-3/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-3/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-3/input.ts new file mode 100644 index 00000000..e1204be9 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-3/input.ts @@ -0,0 +1,3 @@ +f < T > true; +f < T > +1; +f < T > -1; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-3/output.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-3/output.json new file mode 100644 index 00000000..3d743fbf --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-3/output.json @@ -0,0 +1,292 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "BinaryExpression", + "operator": ">", + "left": { + "kind": "BinaryExpression", + "operator": "<", + "left": { + "kind": "Identifer", + "name": "f", + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 2, + "index": 1 + } + }, + "right": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 5, + "index": 4 + }, + "end": { + "row": 1, + "col": 6, + "index": 5 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 6, + "index": 5 + } + }, + "right": { + "kind": "BoolLterial", + "value": true, + "start": { + "row": 1, + "col": 9, + "index": 8 + }, + "end": { + "row": 1, + "col": 13, + "index": 12 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 13, + "index": 12 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 13, + "index": 12 + } + }, + { + "kind": "ExpressionStatement", + "expr": { + "kind": "BinaryExpression", + "operator": ">", + "left": { + "kind": "BinaryExpression", + "operator": "<", + "left": { + "kind": "Identifer", + "name": "f", + "start": { + "row": 2, + "col": 1, + "index": 14 + }, + "end": { + "row": 2, + "col": 2, + "index": 15 + } + }, + "right": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 2, + "col": 5, + "index": 18 + }, + "end": { + "row": 2, + "col": 6, + "index": 19 + } + }, + "start": { + "row": 2, + "col": 1, + "index": 14 + }, + "end": { + "row": 2, + "col": 6, + "index": 19 + } + }, + "right": { + "kind": "UnaryExpression", + "operator": "+", + "argument": { + "kind": "DecimalLiteral", + "rawValue": "1", + "start": { + "row": 2, + "col": 10, + "index": 23 + }, + "end": { + "row": 2, + "col": 11, + "index": 24 + } + }, + "start": { + "row": 2, + "col": 9, + "index": 22 + }, + "end": { + "row": 2, + "col": 11, + "index": 24 + } + }, + "start": { + "row": 2, + "col": 1, + "index": 14 + }, + "end": { + "row": 2, + "col": 11, + "index": 24 + } + }, + "start": { + "row": 2, + "col": 1, + "index": 14 + }, + "end": { + "row": 2, + "col": 11, + "index": 24 + } + }, + { + "kind": "ExpressionStatement", + "expr": { + "kind": "BinaryExpression", + "operator": ">", + "left": { + "kind": "BinaryExpression", + "operator": "<", + "left": { + "kind": "Identifer", + "name": "f", + "start": { + "row": 3, + "col": 1, + "index": 26 + }, + "end": { + "row": 3, + "col": 2, + "index": 27 + } + }, + "right": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 3, + "col": 5, + "index": 30 + }, + "end": { + "row": 3, + "col": 6, + "index": 31 + } + }, + "start": { + "row": 3, + "col": 1, + "index": 26 + }, + "end": { + "row": 3, + "col": 6, + "index": 31 + } + }, + "right": { + "kind": "UnaryExpression", + "operator": "-", + "argument": { + "kind": "DecimalLiteral", + "rawValue": "1", + "start": { + "row": 3, + "col": 10, + "index": 35 + }, + "end": { + "row": 3, + "col": 11, + "index": 36 + } + }, + "start": { + "row": 3, + "col": 9, + "index": 34 + }, + "end": { + "row": 3, + "col": 11, + "index": 36 + } + }, + "start": { + "row": 3, + "col": 1, + "index": 26 + }, + "end": { + "row": 3, + "col": 11, + "index": 36 + } + }, + "start": { + "row": 3, + "col": 1, + "index": 26 + }, + "end": { + "row": 3, + "col": 11, + "index": 36 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 4, + "col": 1, + "index": 38 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-4/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-4/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-4/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-4/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-4/input.ts new file mode 100644 index 00000000..684d9d10 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-4/input.ts @@ -0,0 +1,3 @@ +let f, h = 0, j = 0; + +f = h >>> 0 < j >>> 0; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-4/output.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-4/output.json new file mode 100644 index 00000000..119458dd --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-4/output.json @@ -0,0 +1,283 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "VariableDeclaration", + "variant": "let", + "declarations": [ + { + "kind": "VariableDeclarator", + "id": { + "kind": "Identifer", + "name": "f", + "optional": false, + "start": { + "row": 1, + "col": 5, + "index": 4 + }, + "end": { + "row": 1, + "col": 6, + "index": 5 + } + }, + "init": null, + "start": { + "row": 1, + "col": 5, + "index": 4 + }, + "end": { + "row": 1, + "col": 6, + "index": 5 + } + }, + { + "kind": "VariableDeclarator", + "id": { + "kind": "Identifer", + "name": "h", + "optional": false, + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 1, + "col": 9, + "index": 8 + } + }, + "init": { + "kind": "DecimalLiteral", + "rawValue": "0", + "start": { + "row": 1, + "col": 12, + "index": 11 + }, + "end": { + "row": 1, + "col": 13, + "index": 12 + } + }, + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 1, + "col": 13, + "index": 12 + } + }, + { + "kind": "VariableDeclarator", + "id": { + "kind": "Identifer", + "name": "j", + "optional": false, + "start": { + "row": 1, + "col": 15, + "index": 14 + }, + "end": { + "row": 1, + "col": 16, + "index": 15 + } + }, + "init": { + "kind": "DecimalLiteral", + "rawValue": "0", + "start": { + "row": 1, + "col": 19, + "index": 18 + }, + "end": { + "row": 1, + "col": 20, + "index": 19 + } + }, + "start": { + "row": 1, + "col": 15, + "index": 14 + }, + "end": { + "row": 1, + "col": 20, + "index": 19 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 20, + "index": 19 + } + }, + { + "kind": "ExpressionStatement", + "expr": { + "kind": "AssigmentExpression", + "operator": "=", + "left": { + "kind": "Identifer", + "name": "f", + "start": { + "row": 3, + "col": 1, + "index": 22 + }, + "end": { + "row": 3, + "col": 2, + "index": 23 + } + }, + "right": { + "kind": "BinaryExpression", + "operator": "<", + "left": { + "kind": "BinaryExpression", + "operator": ">>>", + "left": { + "kind": "Identifer", + "name": "h", + "start": { + "row": 3, + "col": 5, + "index": 26 + }, + "end": { + "row": 3, + "col": 6, + "index": 27 + } + }, + "right": { + "kind": "DecimalLiteral", + "rawValue": "0", + "start": { + "row": 3, + "col": 11, + "index": 32 + }, + "end": { + "row": 3, + "col": 12, + "index": 33 + } + }, + "start": { + "row": 3, + "col": 5, + "index": 26 + }, + "end": { + "row": 3, + "col": 12, + "index": 33 + } + }, + "right": { + "kind": "BinaryExpression", + "operator": ">>>", + "left": { + "kind": "Identifer", + "name": "j", + "start": { + "row": 3, + "col": 15, + "index": 36 + }, + "end": { + "row": 3, + "col": 16, + "index": 37 + } + }, + "right": { + "kind": "DecimalLiteral", + "rawValue": "0", + "start": { + "row": 3, + "col": 21, + "index": 42 + }, + "end": { + "row": 3, + "col": 22, + "index": 43 + } + }, + "start": { + "row": 3, + "col": 15, + "index": 36 + }, + "end": { + "row": 3, + "col": 22, + "index": 43 + } + }, + "start": { + "row": 3, + "col": 5, + "index": 26 + }, + "end": { + "row": 3, + "col": 22, + "index": 43 + } + }, + "start": { + "row": 3, + "col": 1, + "index": 22 + }, + "end": { + "row": 3, + "col": 22, + "index": 43 + } + }, + "start": { + "row": 3, + "col": 1, + "index": 22 + }, + "end": { + "row": 3, + "col": 22, + "index": 43 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 4, + "col": 1, + "index": 45 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-5/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-5/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-5/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-5/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-5/input.ts new file mode 100644 index 00000000..3b189032 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-5/input.ts @@ -0,0 +1 @@ +fn(x < y, x >= y) diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-5/output.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-5/output.json new file mode 100644 index 00000000..c4371156 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive-5/output.json @@ -0,0 +1,142 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "CallExpression", + "optional": false, + "callee": { + "kind": "Identifer", + "name": "fn", + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 3, + "index": 2 + } + }, + "arguments": [ + { + "kind": "BinaryExpression", + "operator": "<", + "left": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 1, + "col": 4, + "index": 3 + }, + "end": { + "row": 1, + "col": 5, + "index": 4 + } + }, + "right": { + "kind": "Identifer", + "name": "y", + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 1, + "col": 9, + "index": 8 + } + }, + "start": { + "row": 1, + "col": 4, + "index": 3 + }, + "end": { + "row": 1, + "col": 9, + "index": 8 + } + }, + { + "kind": "BinaryExpression", + "operator": ">=", + "left": { + "kind": "Identifer", + "name": "x", + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + }, + "right": { + "kind": "Identifer", + "name": "y", + "start": { + "row": 1, + "col": 16, + "index": 15 + }, + "end": { + "row": 1, + "col": 17, + "index": 16 + } + }, + "start": { + "row": 1, + "col": 11, + "index": 10 + }, + "end": { + "row": 1, + "col": 17, + "index": 16 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 18, + "index": 17 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 18, + "index": 17 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 18 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive/input.ts new file mode 100644 index 00000000..0139f76f --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive/input.ts @@ -0,0 +1 @@ +makeBox[a] diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive/output.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive/output.json new file mode 100644 index 00000000..b17305fe --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression-false-positive/output.json @@ -0,0 +1,114 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "BinaryExpression", + "operator": ">", + "left": { + "kind": "BinaryExpression", + "operator": "<", + "left": { + "kind": "Identifer", + "name": "makeBox", + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 8, + "index": 7 + } + }, + "right": { + "kind": "Identifer", + "name": "number", + "start": { + "row": 1, + "col": 9, + "index": 8 + }, + "end": { + "row": 1, + "col": 15, + "index": 14 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 15, + "index": 14 + } + }, + "right": { + "kind": "ArrayExpression", + "elements": [ + { + "kind": "Identifer", + "name": "a", + "start": { + "row": 1, + "col": 17, + "index": 16 + }, + "end": { + "row": 1, + "col": 18, + "index": 17 + } + } + ], + "trailingComma": false, + "start": { + "row": 1, + "col": 16, + "index": 15 + }, + "end": { + "row": 1, + "col": 19, + "index": 18 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 19, + "index": 18 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 19, + "index": 18 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 19 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression/input.ts new file mode 100644 index 00000000..4c0bb8b2 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression/input.ts @@ -0,0 +1 @@ +makeBox \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression/output.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression/output.json new file mode 100644 index 00000000..1537add2 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/instantiation-expression/output.json @@ -0,0 +1,83 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "TSInstantiationExpression", + "expression": { + "kind": "Identifer", + "name": "makeBox", + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 8, + "index": 7 + } + }, + "typeArguments": { + "kind": "TSTypeParameterInstantiation", + "params": [ + { + "kind": "TSNumberKeyword", + "start": { + "row": 1, + "col": 9, + "index": 8 + }, + "end": { + "row": 1, + "col": 15, + "index": 14 + } + } + ], + "start": { + "row": 1, + "col": 8, + "index": 7 + }, + "end": { + "row": 1, + "col": 16, + "index": 15 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 16, + "index": 15 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 16, + "index": 15 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 16, + "index": 15 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-false-positive-2/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-false-positive-2/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-false-positive-2/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-false-positive-2/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-false-positive-2/input.ts new file mode 100644 index 00000000..9ad4e4e4 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-false-positive-2/input.ts @@ -0,0 +1 @@ +new A < B > C diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-false-positive-2/output.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-false-positive-2/output.json new file mode 100644 index 00000000..4ab08b53 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-false-positive-2/output.json @@ -0,0 +1,112 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "BinaryExpression", + "operator": ">", + "left": { + "kind": "BinaryExpression", + "operator": "<", + "left": { + "kind": "NewExpression", + "callee": { + "kind": "Identifer", + "name": "A", + "start": { + "row": 1, + "col": 5, + "index": 4 + }, + "end": { + "row": 1, + "col": 6, + "index": 5 + } + }, + "arguments": [], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 6, + "index": 5 + } + }, + "right": { + "kind": "Identifer", + "name": "B", + "start": { + "row": 1, + "col": 9, + "index": 8 + }, + "end": { + "row": 1, + "col": 10, + "index": 9 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 10, + "index": 9 + } + }, + "right": { + "kind": "Identifer", + "name": "C", + "start": { + "row": 1, + "col": 13, + "index": 12 + }, + "end": { + "row": 1, + "col": 14, + "index": 13 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 14, + "index": 13 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 14, + "index": 13 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 14 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-false-positive-3/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-false-positive-3/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-false-positive-3/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-false-positive-3/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-false-positive-3/input.ts new file mode 100644 index 00000000..68ec919a --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-false-positive-3/input.ts @@ -0,0 +1,2 @@ +new A < B > +C diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-false-positive-3/output.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-false-positive-3/output.json new file mode 100644 index 00000000..f279e766 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-false-positive-3/output.json @@ -0,0 +1,125 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "NewExpression", + "callee": { + "kind": "Identifer", + "name": "A", + "start": { + "row": 1, + "col": 5, + "index": 4 + }, + "end": { + "row": 1, + "col": 6, + "index": 5 + } + }, + "arguments": [], + "typeArguments": { + "kind": "TSTypeParameterInstantiation", + "params": [ + { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "B", + "start": { + "row": 1, + "col": 9, + "index": 8 + }, + "end": { + "row": 1, + "col": 10, + "index": 9 + } + }, + "start": { + "row": 1, + "col": 9, + "index": 8 + }, + "end": { + "row": 1, + "col": 10, + "index": 9 + } + } + ], + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 12, + "index": 11 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 6, + "index": 5 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 6, + "index": 5 + } + }, + { + "kind": "ExpressionStatement", + "expr": { + "kind": "Identifer", + "name": "C", + "start": { + "row": 2, + "col": 1, + "index": 12 + }, + "end": { + "row": 2, + "col": 2, + "index": 13 + } + }, + "start": { + "row": 2, + "col": 1, + "index": 12 + }, + "end": { + "row": 2, + "col": 2, + "index": 13 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 3, + "col": 1, + "index": 14 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-false-positive/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-false-positive/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-false-positive/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-false-positive/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-false-positive/input.ts new file mode 100644 index 00000000..f7031744 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-false-positive/input.ts @@ -0,0 +1 @@ +new A < T; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-false-positive/output.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-false-positive/output.json new file mode 100644 index 00000000..22981324 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-false-positive/output.json @@ -0,0 +1,84 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "BinaryExpression", + "operator": "<", + "left": { + "kind": "NewExpression", + "callee": { + "kind": "Identifer", + "name": "A", + "start": { + "row": 1, + "col": 5, + "index": 4 + }, + "end": { + "row": 1, + "col": 6, + "index": 5 + } + }, + "arguments": [], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 6, + "index": 5 + } + }, + "right": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 9, + "index": 8 + }, + "end": { + "row": 1, + "col": 10, + "index": 9 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 10, + "index": 9 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 10, + "index": 9 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 11 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-without-arguments-asi/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-without-arguments-asi/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-without-arguments-asi/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-without-arguments-asi/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-without-arguments-asi/input.ts new file mode 100644 index 00000000..bb91b556 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-without-arguments-asi/input.ts @@ -0,0 +1,3 @@ +new A + +if (0); \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-without-arguments-asi/output.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-without-arguments-asi/output.json new file mode 100644 index 00000000..6d214f32 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-without-arguments-asi/output.json @@ -0,0 +1,139 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "NewExpression", + "callee": { + "kind": "Identifer", + "name": "A", + "start": { + "row": 1, + "col": 5, + "index": 4 + }, + "end": { + "row": 1, + "col": 6, + "index": 5 + } + }, + "arguments": [], + "typeArguments": { + "kind": "TSTypeParameterInstantiation", + "params": [ + { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 8, + "index": 7 + } + }, + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 8, + "index": 7 + } + } + ], + "start": { + "row": 1, + "col": 6, + "index": 5 + }, + "end": { + "row": 1, + "col": 9, + "index": 8 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 6, + "index": 5 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 6, + "index": 5 + } + }, + { + "kind": "IfStatement", + "test": { + "kind": "DecimalLiteral", + "rawValue": "0", + "start": { + "row": 3, + "col": 5, + "index": 14 + }, + "end": { + "row": 3, + "col": 6, + "index": 15 + } + }, + "conseqence": { + "kind": "EmptyStatement", + "start": { + "row": 3, + "col": 7, + "index": 16 + }, + "end": { + "row": 3, + "col": 8, + "index": 17 + } + }, + "alternative": null, + "start": { + "row": 3, + "col": 1, + "index": 10 + }, + "end": { + "row": 3, + "col": 8, + "index": 17 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 3, + "col": 8, + "index": 17 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-without-arguments-missing-semicolon/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-without-arguments-missing-semicolon/expect.json new file mode 100644 index 00000000..e5936a86 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-without-arguments-missing-semicolon/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Failed", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-without-arguments-missing-semicolon/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-without-arguments-missing-semicolon/input.ts new file mode 100644 index 00000000..dba5a427 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-without-arguments-missing-semicolon/input.ts @@ -0,0 +1 @@ +new A if (0); \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-without-arguments-missing-semicolon/output.txt b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-without-arguments-missing-semicolon/output.txt new file mode 100644 index 00000000..3c8ed3f6 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-without-arguments-missing-semicolon/output.txt @@ -0,0 +1,3 @@ +[SyntaxError]: Missing semicolon or line terminator. (1,10) +1|new A if (0); + | ^ diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-without-arguments/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-without-arguments/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-without-arguments/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-without-arguments/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-without-arguments/input.ts new file mode 100644 index 00000000..458a4296 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-without-arguments/input.ts @@ -0,0 +1 @@ +new A; diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-without-arguments/output.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-without-arguments/output.json new file mode 100644 index 00000000..bba90c2e --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new-without-arguments/output.json @@ -0,0 +1,98 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "NewExpression", + "callee": { + "kind": "Identifer", + "name": "A", + "start": { + "row": 1, + "col": 5, + "index": 4 + }, + "end": { + "row": 1, + "col": 6, + "index": 5 + } + }, + "arguments": [], + "typeArguments": { + "kind": "TSTypeParameterInstantiation", + "params": [ + { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 8, + "index": 7 + } + }, + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 8, + "index": 7 + } + } + ], + "start": { + "row": 1, + "col": 6, + "index": 5 + }, + "end": { + "row": 1, + "col": 9, + "index": 8 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 6, + "index": 5 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 6, + "index": 5 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 2, + "col": 1, + "index": 10 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new/expect.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new/expect.json new file mode 100644 index 00000000..ef61e5ce --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new/expect.json @@ -0,0 +1,6 @@ +{ + "expect": "Pass", + "config": { + "plugins": ["typescript"] + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new/input.ts b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new/input.ts new file mode 100644 index 00000000..d474bb65 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new/input.ts @@ -0,0 +1,2 @@ +new C(); +new C(); diff --git a/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new/output.json b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new/output.json new file mode 100644 index 00000000..149b0825 --- /dev/null +++ b/web-infras/parser/tests/fixtures/babel/typescript/type-arguments/new/output.json @@ -0,0 +1,208 @@ +{ + "kind": "Program", + "body": [ + { + "kind": "ExpressionStatement", + "expr": { + "kind": "NewExpression", + "callee": { + "kind": "Identifer", + "name": "C", + "start": { + "row": 1, + "col": 5, + "index": 4 + }, + "end": { + "row": 1, + "col": 6, + "index": 5 + } + }, + "arguments": [], + "typeArguments": { + "kind": "TSTypeParameterInstantiation", + "params": [ + { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 8, + "index": 7 + } + }, + "start": { + "row": 1, + "col": 7, + "index": 6 + }, + "end": { + "row": 1, + "col": 8, + "index": 7 + } + } + ], + "start": { + "row": 1, + "col": 6, + "index": 5 + }, + "end": { + "row": 1, + "col": 9, + "index": 8 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 11, + "index": 10 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 11, + "index": 10 + } + }, + { + "kind": "ExpressionStatement", + "expr": { + "kind": "NewExpression", + "callee": { + "kind": "Identifer", + "name": "C", + "start": { + "row": 2, + "col": 5, + "index": 16 + }, + "end": { + "row": 2, + "col": 6, + "index": 17 + } + }, + "arguments": [], + "typeArguments": { + "kind": "TSTypeParameterInstantiation", + "params": [ + { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "T", + "start": { + "row": 2, + "col": 7, + "index": 18 + }, + "end": { + "row": 2, + "col": 8, + "index": 19 + } + }, + "start": { + "row": 2, + "col": 7, + "index": 18 + }, + "end": { + "row": 2, + "col": 8, + "index": 19 + } + }, + { + "kind": "TSTypeReference", + "typeName": { + "kind": "Identifer", + "name": "U", + "start": { + "row": 2, + "col": 10, + "index": 21 + }, + "end": { + "row": 2, + "col": 11, + "index": 22 + } + }, + "start": { + "row": 2, + "col": 10, + "index": 21 + }, + "end": { + "row": 2, + "col": 11, + "index": 22 + } + } + ], + "start": { + "row": 2, + "col": 6, + "index": 17 + }, + "end": { + "row": 2, + "col": 12, + "index": 23 + } + }, + "start": { + "row": 2, + "col": 1, + "index": 12 + }, + "end": { + "row": 2, + "col": 14, + "index": 25 + } + }, + "start": { + "row": 2, + "col": 1, + "index": 12 + }, + "end": { + "row": 2, + "col": 14, + "index": 25 + } + } + ], + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 3, + "col": 1, + "index": 27 + } +} \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/esprima/ES6/generator/generator-parameter-invalid-binding-element/output.txt b/web-infras/parser/tests/fixtures/esprima/ES6/generator/generator-parameter-invalid-binding-element/output.txt index 022f7b98..d923ab07 100644 --- a/web-infras/parser/tests/fixtures/esprima/ES6/generator/generator-parameter-invalid-binding-element/output.txt +++ b/web-infras/parser/tests/fixtures/esprima/ES6/generator/generator-parameter-invalid-binding-element/output.txt @@ -1 +1,6 @@ -Cannot read properties of null (reading 'name') \ No newline at end of file +[SyntaxError]: function statement requires a name (2,14) +2| function*(x = yield 3) {} + | ^ +[SyntaxError]: yield expression can not used in parameter list (2,19) +2| function*(x = yield 3) {} + | ^ diff --git a/web-infras/parser/tests/fixtures/esprima/ES6/generator/generator-parameter-invalid-binding-property/output.txt b/web-infras/parser/tests/fixtures/esprima/ES6/generator/generator-parameter-invalid-binding-property/output.txt index 022f7b98..94211de8 100644 --- a/web-infras/parser/tests/fixtures/esprima/ES6/generator/generator-parameter-invalid-binding-property/output.txt +++ b/web-infras/parser/tests/fixtures/esprima/ES6/generator/generator-parameter-invalid-binding-property/output.txt @@ -1 +1,6 @@ -Cannot read properties of null (reading 'name') \ No newline at end of file +[SyntaxError]: function statement requires a name (2,14) +2| function*({x: y = yield 3}) {} + | ^ +[SyntaxError]: yield expression can not used in parameter list (2,23) +2| function*({x: y = yield 3}) {} + | ^ diff --git a/web-infras/parser/tests/fixtures/esprima/ES6/generator/generator-parameter-invalid-computed-property-name/output.txt b/web-infras/parser/tests/fixtures/esprima/ES6/generator/generator-parameter-invalid-computed-property-name/output.txt index 022f7b98..6097e067 100644 --- a/web-infras/parser/tests/fixtures/esprima/ES6/generator/generator-parameter-invalid-computed-property-name/output.txt +++ b/web-infras/parser/tests/fixtures/esprima/ES6/generator/generator-parameter-invalid-computed-property-name/output.txt @@ -1 +1,6 @@ -Cannot read properties of null (reading 'name') \ No newline at end of file +[SyntaxError]: function statement requires a name (2,14) +2| function*({[yield 3]: y}) {} + | ^ +[SyntaxError]: yield expression can not used in parameter list (2,17) +2| function*({[yield 3]: y}) {} + | ^ diff --git a/web-infras/parser/tests/fixtures/esprima/ES6/identifier/invalid-hex-escape-sequence/output.txt b/web-infras/parser/tests/fixtures/esprima/ES6/identifier/invalid-hex-escape-sequence/output.txt index cfdb7ff1..6c3626fa 100644 --- a/web-infras/parser/tests/fixtures/esprima/ES6/identifier/invalid-hex-escape-sequence/output.txt +++ b/web-infras/parser/tests/fixtures/esprima/ES6/identifier/invalid-hex-escape-sequence/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid hexadecimal escape sequence, start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Invalid hexadecimal escape sequence, start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/esprima/ES6/identifier/invalid_escaped_surrogate_pairs/output.txt b/web-infras/parser/tests/fixtures/esprima/ES6/identifier/invalid_escaped_surrogate_pairs/output.txt index 09b04508..0100d24f 100644 --- a/web-infras/parser/tests/fixtures/esprima/ES6/identifier/invalid_escaped_surrogate_pairs/output.txt +++ b/web-infras/parser/tests/fixtures/esprima/ES6/identifier/invalid_escaped_surrogate_pairs/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid Unicode escape sequence, start position is (1, 5) \ No newline at end of file +[Error]: Lexical Error, Invalid Unicode escape sequence, start position is (1, 5) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/esprima/ES6/identifier/invalid_id_smp/output.txt b/web-infras/parser/tests/fixtures/esprima/ES6/identifier/invalid_id_smp/output.txt index 09b04508..0100d24f 100644 --- a/web-infras/parser/tests/fixtures/esprima/ES6/identifier/invalid_id_smp/output.txt +++ b/web-infras/parser/tests/fixtures/esprima/ES6/identifier/invalid_id_smp/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid Unicode escape sequence, start position is (1, 5) \ No newline at end of file +[Error]: Lexical Error, Invalid Unicode escape sequence, start position is (1, 5) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/esprima/es2017/async/functions/invalid-export-async-function-expression/output.txt b/web-infras/parser/tests/fixtures/esprima/es2017/async/functions/invalid-export-async-function-expression/output.txt index 022f7b98..962042f3 100644 --- a/web-infras/parser/tests/fixtures/esprima/es2017/async/functions/invalid-export-async-function-expression/output.txt +++ b/web-infras/parser/tests/fixtures/esprima/es2017/async/functions/invalid-export-async-function-expression/output.txt @@ -1 +1,6 @@ -Cannot read properties of null (reading 'name') \ No newline at end of file +[SyntaxError]: 'import' and 'export' may appear only with 'sourceType: "module"' (1,1) +1|export async function() {} + |^ +[SyntaxError]: function statement requires a name (1,22) +1|export async function() {} + | ^ diff --git a/web-infras/parser/tests/fixtures/esprima/expression/primary/literal/numeric/invalid_hex/output.txt b/web-infras/parser/tests/fixtures/esprima/expression/primary/literal/numeric/invalid_hex/output.txt index 13e05fd4..7386e1b4 100644 --- a/web-infras/parser/tests/fixtures/esprima/expression/primary/literal/numeric/invalid_hex/output.txt +++ b/web-infras/parser/tests/fixtures/esprima/expression/primary/literal/numeric/invalid_hex/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Identifier directly after number., start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Identifier directly after number., start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/esprima/expression/primary/literal/string/invalid_escaped_hex/output.txt b/web-infras/parser/tests/fixtures/esprima/expression/primary/literal/string/invalid_escaped_hex/output.txt index e2f4f280..75d14345 100644 --- a/web-infras/parser/tests/fixtures/esprima/expression/primary/literal/string/invalid_escaped_hex/output.txt +++ b/web-infras/parser/tests/fixtures/esprima/expression/primary/literal/string/invalid_escaped_hex/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Invalid Unicode escape sequence, start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/esprima/expression/primary/literal/string/invalid_hex/output.txt b/web-infras/parser/tests/fixtures/esprima/expression/primary/literal/string/invalid_hex/output.txt index cfdb7ff1..6c3626fa 100644 --- a/web-infras/parser/tests/fixtures/esprima/expression/primary/literal/string/invalid_hex/output.txt +++ b/web-infras/parser/tests/fixtures/esprima/expression/primary/literal/string/invalid_hex/output.txt @@ -1 +1 @@ -[Error]: Lexical Error, SyntaxError: Invalid hexadecimal escape sequence, start position is (1, 1) \ No newline at end of file +[Error]: Lexical Error, Invalid hexadecimal escape sequence, start position is (1, 1) \ No newline at end of file diff --git a/web-infras/parser/tests/fixtures/self-added/decorators/class-decorator-call-expr/output.json b/web-infras/parser/tests/fixtures/self-added/decorators/class-decorator-call-expr/output.json index aea379c2..12eb2472 100644 --- a/web-infras/parser/tests/fixtures/self-added/decorators/class-decorator-call-expr/output.json +++ b/web-infras/parser/tests/fixtures/self-added/decorators/class-decorator-call-expr/output.json @@ -42,7 +42,124 @@ "col": 2, "index": 59 }, - "decorators": null + "decorators": [ + { + "kind": "Decorator", + "expression": { + "kind": "CallExpression", + "optional": false, + "callee": { + "kind": "Identifer", + "name": "testCallExprDe", + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 16, + "index": 15 + } + }, + "arguments": [ + { + "kind": "Identifer", + "name": "arg1", + "start": { + "row": 1, + "col": 17, + "index": 16 + }, + "end": { + "row": 1, + "col": 21, + "index": 20 + } + }, + { + "kind": "ObjectExpression", + "properties": [ + { + "kind": "ObjectProperty", + "computed": false, + "shorted": false, + "key": { + "kind": "Identifer", + "name": "testProp", + "start": { + "row": 1, + "col": 25, + "index": 24 + }, + "end": { + "row": 1, + "col": 33, + "index": 32 + } + }, + "value": { + "kind": "Identifer", + "name": "argu2", + "start": { + "row": 1, + "col": 35, + "index": 34 + }, + "end": { + "row": 1, + "col": 40, + "index": 39 + } + }, + "start": { + "row": 1, + "col": 25, + "index": 24 + }, + "end": { + "row": 1, + "col": 40, + "index": 39 + } + } + ], + "trailingComma": false, + "start": { + "row": 1, + "col": 23, + "index": 22 + }, + "end": { + "row": 1, + "col": 42, + "index": 41 + } + } + ], + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 43, + "index": 42 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 43, + "index": 42 + } + } + ] } ], "start": { diff --git a/web-infras/parser/tests/fixtures/self-added/decorators/class-decorator-member-expr/output.json b/web-infras/parser/tests/fixtures/self-added/decorators/class-decorator-member-expr/output.json index 65e7a83e..c67ccf96 100644 --- a/web-infras/parser/tests/fixtures/self-added/decorators/class-decorator-member-expr/output.json +++ b/web-infras/parser/tests/fixtures/self-added/decorators/class-decorator-member-expr/output.json @@ -42,7 +42,93 @@ "col": 2, "index": 43 }, - "decorators": null + "decorators": [ + { + "kind": "Decorator", + "expression": { + "kind": "MemberExpression", + "computed": false, + "optional": false, + "object": { + "kind": "Identifer", + "name": "otherProp", + "start": { + "row": 1, + "col": 18, + "index": 17 + }, + "end": { + "row": 1, + "col": 27, + "index": 26 + } + }, + "property": { + "kind": "MemberExpression", + "computed": false, + "optional": false, + "object": { + "kind": "Identifer", + "name": "someProp", + "start": { + "row": 1, + "col": 9, + "index": 8 + }, + "end": { + "row": 1, + "col": 17, + "index": 16 + } + }, + "property": { + "kind": "Identifer", + "name": "testDe", + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 8, + "index": 7 + } + }, + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 17, + "index": 16 + } + }, + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 27, + "index": 26 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 27, + "index": 26 + } + } + ] } ], "start": { diff --git a/web-infras/parser/tests/fixtures/self-added/decorators/class-decorator/output.json b/web-infras/parser/tests/fixtures/self-added/decorators/class-decorator/output.json index fbe6dd41..a67105ea 100644 --- a/web-infras/parser/tests/fixtures/self-added/decorators/class-decorator/output.json +++ b/web-infras/parser/tests/fixtures/self-added/decorators/class-decorator/output.json @@ -42,7 +42,35 @@ "col": 2, "index": 24 }, - "decorators": null + "decorators": [ + { + "kind": "Decorator", + "expression": { + "kind": "Identifer", + "name": "testDe", + "start": { + "row": 1, + "col": 2, + "index": 1 + }, + "end": { + "row": 1, + "col": 8, + "index": 7 + } + }, + "start": { + "row": 1, + "col": 1, + "index": 0 + }, + "end": { + "row": 1, + "col": 8, + "index": 7 + } + } + ] } ], "start": { diff --git a/web-infras/parser/tests/parserRunner/helpers/getTestCase.ts b/web-infras/parser/tests/parserRunner/helpers/getTestCase.ts index 9236b100..2796ba20 100644 --- a/web-infras/parser/tests/parserRunner/helpers/getTestCase.ts +++ b/web-infras/parser/tests/parserRunner/helpers/getTestCase.ts @@ -4,7 +4,7 @@ import { ExpectPassTestCase, ExpectFailedTestCase, ExpectConfig, TestCase } from import { readFile } from "fs/promises"; import { existsSync } from "fs"; -const jsFileRegex = new RegExp(".*.js$"); +const jsFileRegex = new RegExp(".*.(js|ts)$"); async function getExpectObj(dirPath: string): Promise { const expectFilePath = path.join(dirPath, "expect.json"); diff --git a/web-infras/parser/tests/parserRunner/helpers/transform.ts b/web-infras/parser/tests/parserRunner/helpers/transform.ts index ce6a60c8..a5e59c29 100644 --- a/web-infras/parser/tests/parserRunner/helpers/transform.ts +++ b/web-infras/parser/tests/parserRunner/helpers/transform.ts @@ -136,6 +136,49 @@ const VisitorTable: Visitor = { [SyntaxKinds.JSXFragment]: transformKind, [SyntaxKinds.JSXOpeningFragment]: transformKind, [SyntaxKinds.JSXClosingFragment]: transformKind, + [SyntaxKinds.TSConditionalType]: transformKind, + [SyntaxKinds.TSUnionType]: transformKind, + [SyntaxKinds.TSIntersectionType]: transformKind, + [SyntaxKinds.TSArrayType]: transformKind, + [SyntaxKinds.TSTypeOperator]: transformKind, + [SyntaxKinds.TSIndexedAccessType]: transformKind, + [SyntaxKinds.TSFunctionType]: transformKind, + [SyntaxKinds.TSConstructorType]: transformKind, + [SyntaxKinds.TSTypeAliasDeclaration]: transformKind, + [SyntaxKinds.TSInterfaceDeclaration]: transformKind, + [SyntaxKinds.TSTypeLiteral]: transformKind, + [SyntaxKinds.TSCallSignatureDeclaration]: transformKind, + [SyntaxKinds.TSConstructSignatureDeclaration]: transformKind, + [SyntaxKinds.TSPropertySignature]: transformKind, + [SyntaxKinds.TSMethodSignature]: transformKind, + [SyntaxKinds.TSQualifiedName]: transformKind, + [SyntaxKinds.TSTypePredicate]: transformKind, + [SyntaxKinds.TSTypeAnnotation]: transformKind, + [SyntaxKinds.TSTypeReference]: transformKind, + [SyntaxKinds.TSStringKeyword]: transformKind, + [SyntaxKinds.TSNumberKeyword]: transformKind, + [SyntaxKinds.TSBigIntKeyword]: transformKind, + [SyntaxKinds.TSBooleanKeyword]: transformKind, + [SyntaxKinds.TSNullKeyword]: transformKind, + [SyntaxKinds.TSUndefinedKeyword]: transformKind, + [SyntaxKinds.TSSymbolKeyword]: transformKind, + [SyntaxKinds.TSAnyKeyword]: transformKind, + [SyntaxKinds.TSNeverKeyword]: transformKind, + [SyntaxKinds.TSUnknowKeyword]: transformKind, + [SyntaxKinds.TSInterfaceBody]: transformKind, + [SyntaxKinds.TSTypeParameterInstantiation]: transformKind, + [SyntaxKinds.TSTypeParameterDeclaration]: transformKind, + [SyntaxKinds.TSTypeParameter]: transformKind, + [SyntaxKinds.TSVoidKeyword]: transformKind, + [SyntaxKinds.TSInstantiationExpression]: transformKind, + [SyntaxKinds.TSInterfaceHeritage]: transformKind, + [SyntaxKinds.TSTypeAssertionExpression]: transformKind, + [SyntaxKinds.TSAsExpression]: transformKind, + [SyntaxKinds.TSSatisfiesExpression]: transformKind, + [SyntaxKinds.TSEnumDeclaration]: transformKind, + [SyntaxKinds.TSEnumBody]: transformKind, + [SyntaxKinds.TSEnumMember]: transformKind, + [SyntaxKinds.TSDeclareFunction]: transformKind, }; function transformKind(node: ModuleItem, visior: Visitor) { // @ts-expect-error a ast node's syntax kind must be table. diff --git a/web-infras/parser/tests/parserRunner/index.ts b/web-infras/parser/tests/parserRunner/index.ts index 26af0659..3bed5f17 100644 --- a/web-infras/parser/tests/parserRunner/index.ts +++ b/web-infras/parser/tests/parserRunner/index.ts @@ -103,6 +103,9 @@ function reportTestSuit(testResult: TestCaseResultSuite): boolean { console.log( `== ${chalk.red("Timeout Test Case")} : ${testResult.timeoutResult.length} / ${allTestCaseCount}`, ); + if (isVerbose || isCI) { + for (const failedcase of testResult.timeoutResult) console.log(` |---> File ${failedcase.fileId}`); + } return ( testResult.timeoutResult.length === 0 && expectFailedButPass.length === 0 &&