1namespace ts { 2 const enum SignatureFlags { 3 None = 0, 4 Yield = 1 << 0, 5 Await = 1 << 1, 6 Type = 1 << 2, 7 IgnoreMissingOpenBrace = 1 << 4, 8 JSDoc = 1 << 5, 9 } 10 11 const enum SpeculationKind { 12 TryParse, 13 Lookahead, 14 Reparse 15 } 16 17 let NodeConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node; 18 let TokenConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node; 19 let IdentifierConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node; 20 let PrivateIdentifierConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node; 21 let SourceFileConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node; 22 23 /** 24 * NOTE: You should not use this, it is only exported to support `createNode` in `~/src/deprecatedCompat/deprecations.ts`. 25 */ 26 /* @internal */ 27 export const parseBaseNodeFactory: BaseNodeFactory = { 28 createBaseSourceFileNode: kind => new (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))(kind, -1, -1), 29 createBaseIdentifierNode: kind => new (IdentifierConstructor || (IdentifierConstructor = objectAllocator.getIdentifierConstructor()))(kind, -1, -1), 30 createBasePrivateIdentifierNode: kind => new (PrivateIdentifierConstructor || (PrivateIdentifierConstructor = objectAllocator.getPrivateIdentifierConstructor()))(kind, -1, -1), 31 createBaseTokenNode: kind => new (TokenConstructor || (TokenConstructor = objectAllocator.getTokenConstructor()))(kind, -1, -1), 32 createBaseNode: kind => new (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor()))(kind, -1, -1), 33 }; 34 35 /* @internal */ 36 export const parseNodeFactory = createNodeFactory(NodeFactoryFlags.NoParenthesizerRules, parseBaseNodeFactory); 37 38 function visitNode<T>(cbNode: (node: Node) => T, node: Node | undefined): T | undefined { 39 return node && cbNode(node); 40 } 41 42 function visitNodes<T>(cbNode: (node: Node) => T, cbNodes: ((node: NodeArray<Node>) => T | undefined) | undefined, nodes: NodeArray<Node> | undefined): T | undefined { 43 if (nodes) { 44 if (cbNodes) { 45 return cbNodes(nodes); 46 } 47 for (const node of nodes) { 48 const result = cbNode(node); 49 if (result) { 50 return result; 51 } 52 } 53 } 54 } 55 56 /*@internal*/ 57 export function isJSDocLikeText(text: string, start: number) { 58 return text.charCodeAt(start + 1) === CharacterCodes.asterisk && 59 text.charCodeAt(start + 2) === CharacterCodes.asterisk && 60 text.charCodeAt(start + 3) !== CharacterCodes.slash; 61 } 62 63 /*@internal*/ 64 export function isFileProbablyExternalModule(sourceFile: SourceFile) { 65 // Try to use the first top-level import/export when available, then 66 // fall back to looking for an 'import.meta' somewhere in the tree if necessary. 67 return forEach(sourceFile.statements, isAnExternalModuleIndicatorNode) || 68 getImportMetaIfNecessary(sourceFile); 69 } 70 71 function isAnExternalModuleIndicatorNode(node: Node) { 72 return canHaveModifiers(node) && hasModifierOfKind(node, SyntaxKind.ExportKeyword) 73 || isImportEqualsDeclaration(node) && isExternalModuleReference(node.moduleReference) 74 || isImportDeclaration(node) 75 || isExportAssignment(node) 76 || isExportDeclaration(node) ? node : undefined; 77 } 78 79 function getImportMetaIfNecessary(sourceFile: SourceFile) { 80 return sourceFile.flags & NodeFlags.PossiblyContainsImportMeta ? 81 walkTreeForImportMeta(sourceFile) : 82 undefined; 83 } 84 85 function walkTreeForImportMeta(node: Node): Node | undefined { 86 return isImportMeta(node) ? node : forEachChild(node, walkTreeForImportMeta); 87 } 88 89 /** Do not use hasModifier inside the parser; it relies on parent pointers. Use this instead. */ 90 function hasModifierOfKind(node: HasModifiers, kind: SyntaxKind) { 91 return some(node.modifiers, m => m.kind === kind); 92 } 93 94 function isImportMeta(node: Node): boolean { 95 return isMetaProperty(node) && node.keywordToken === SyntaxKind.ImportKeyword && node.name.escapedText === "meta"; 96 } 97 98 type ForEachChildFunction<TNode> = <T>(node: TNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined) => T | undefined; 99 type ForEachChildTable = { [TNode in ForEachChildNodes as TNode["kind"]]: ForEachChildFunction<TNode> }; 100 const forEachChildTable: ForEachChildTable = { 101 [SyntaxKind.QualifiedName]: function forEachChildInQualifiedName<T>(node: QualifiedName, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 102 return visitNode(cbNode, node.left) || 103 visitNode(cbNode, node.right); 104 }, 105 [SyntaxKind.TypeParameter]: function forEachChildInTypeParameter<T>(node: TypeParameterDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 106 return visitNodes(cbNode, cbNodes, node.modifiers) || 107 visitNode(cbNode, node.name) || 108 visitNode(cbNode, node.constraint) || 109 visitNode(cbNode, node.default) || 110 visitNode(cbNode, node.expression); 111 }, 112 [SyntaxKind.ShorthandPropertyAssignment]: function forEachChildInShorthandPropertyAssignment<T>(node: ShorthandPropertyAssignment, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 113 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 114 visitNodes(cbNode, cbNodes, node.modifiers) || 115 visitNode(cbNode, node.name) || 116 visitNode(cbNode, node.questionToken) || 117 visitNode(cbNode, node.exclamationToken) || 118 visitNode(cbNode, node.equalsToken) || 119 visitNode(cbNode, node.objectAssignmentInitializer); 120 }, 121 [SyntaxKind.SpreadAssignment]: function forEachChildInSpreadAssignment<T>(node: SpreadAssignment, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 122 return visitNode(cbNode, node.expression); 123 }, 124 [SyntaxKind.Parameter]: function forEachChildInParameter<T>(node: ParameterDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 125 return visitNodes(cbNode, cbNodes, node.modifiers) || 126 visitNode(cbNode, node.dotDotDotToken) || 127 visitNode(cbNode, node.name) || 128 visitNode(cbNode, node.questionToken) || 129 visitNode(cbNode, node.type) || 130 visitNode(cbNode, node.initializer); 131 }, 132 [SyntaxKind.PropertyDeclaration]: function forEachChildInPropertyDeclaration<T>(node: PropertyDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 133 return visitNodes(cbNode, cbNodes, node.modifiers) || 134 visitNode(cbNode, node.name) || 135 visitNode(cbNode, node.questionToken) || 136 visitNode(cbNode, node.exclamationToken) || 137 visitNode(cbNode, node.type) || 138 visitNode(cbNode, node.initializer); 139 }, 140 [SyntaxKind.AnnotationPropertyDeclaration]: function forEachChildInAnnotationPropertyDeclaration<T>(node: AnnotationPropertyDeclaration, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 141 return visitNode(cbNode, node.name) || 142 visitNode(cbNode, node.type) || 143 visitNode(cbNode, node.initializer); 144 }, 145 [SyntaxKind.PropertySignature]: function forEachChildInPropertySignature<T>(node: PropertySignature, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 146 return visitNodes(cbNode, cbNodes, node.modifiers) || 147 visitNode(cbNode, node.name) || 148 visitNode(cbNode, node.questionToken) || 149 visitNode(cbNode, node.type) || 150 visitNode(cbNode, node.initializer); 151 }, 152 [SyntaxKind.PropertyAssignment]: function forEachChildInPropertyAssignment<T>(node: PropertyAssignment, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 153 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 154 visitNodes(cbNode, cbNodes, node.modifiers) || 155 visitNode(cbNode, node.name) || 156 visitNode(cbNode, node.questionToken) || 157 visitNode(cbNode, node.exclamationToken) || 158 visitNode(cbNode, node.initializer); 159 }, 160 [SyntaxKind.VariableDeclaration]: function forEachChildInVariableDeclaration<T>(node: VariableDeclaration, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 161 return visitNode(cbNode, node.name) || 162 visitNode(cbNode, node.exclamationToken) || 163 visitNode(cbNode, node.type) || 164 visitNode(cbNode, node.initializer); 165 }, 166 [SyntaxKind.BindingElement]: function forEachChildInBindingElement<T>(node: BindingElement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 167 return visitNode(cbNode, node.dotDotDotToken) || 168 visitNode(cbNode, node.propertyName) || 169 visitNode(cbNode, node.name) || 170 visitNode(cbNode, node.initializer); 171 }, 172 [SyntaxKind.IndexSignature]: function forEachChildInIndexSignature<T>(node: IndexSignatureDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 173 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 174 visitNodes(cbNode, cbNodes, node.modifiers) || 175 visitNodes(cbNode, cbNodes, node.typeParameters) || 176 visitNodes(cbNode, cbNodes, node.parameters) || 177 visitNode(cbNode, node.type); 178 }, 179 [SyntaxKind.ConstructorType]: function forEachChildInConstructorType<T>(node: ConstructorTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 180 return visitNodes(cbNode, cbNodes, node.modifiers) || 181 visitNodes(cbNode, cbNodes, node.typeParameters) || 182 visitNodes(cbNode, cbNodes, node.parameters) || 183 visitNode(cbNode, node.type); 184 }, 185 [SyntaxKind.FunctionType]: function forEachChildInFunctionType<T>(node: FunctionTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 186 return visitNodes(cbNode, cbNodes, node.modifiers) || 187 visitNodes(cbNode, cbNodes, node.typeParameters) || 188 visitNodes(cbNode, cbNodes, node.parameters) || 189 visitNode(cbNode, node.type); 190 }, 191 [SyntaxKind.CallSignature]: forEachChildInCallOrConstructSignature, 192 [SyntaxKind.ConstructSignature]: forEachChildInCallOrConstructSignature, 193 [SyntaxKind.EtsComponentExpression]: function forEachChildInEtsComponentExpression<T>(node: EtsComponentExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 194 return visitNode(cbNode, node.expression) || 195 visitNodes(cbNode, cbNodes, node.arguments) || 196 visitNode(cbNode, node.body); 197 }, 198 [SyntaxKind.MethodDeclaration]: function forEachChildInMethodDeclaration<T>(node: MethodDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 199 return visitNodes(cbNode, cbNodes, node.modifiers) || 200 visitNode(cbNode, node.asteriskToken) || 201 visitNode(cbNode, node.name) || 202 visitNode(cbNode, node.questionToken) || 203 visitNode(cbNode, node.exclamationToken) || 204 visitNodes(cbNode, cbNodes, node.typeParameters) || 205 visitNodes(cbNode, cbNodes, node.parameters) || 206 visitNode(cbNode, node.type) || 207 visitNode(cbNode, node.body); 208 }, 209 [SyntaxKind.MethodSignature]: function forEachChildInMethodSignature<T>(node: MethodSignature, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 210 return visitNodes(cbNode, cbNodes, node.modifiers) || 211 visitNode(cbNode, node.name) || 212 visitNode(cbNode, node.questionToken) || 213 visitNodes(cbNode, cbNodes, node.typeParameters) || 214 visitNodes(cbNode, cbNodes, node.parameters) || 215 visitNode(cbNode, node.type); 216 }, 217 [SyntaxKind.Constructor]: function forEachChildInConstructor<T>(node: ConstructorDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 218 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 219 visitNodes(cbNode, cbNodes, node.modifiers) || 220 visitNode(cbNode, node.name) || 221 visitNodes(cbNode, cbNodes, node.typeParameters) || 222 visitNodes(cbNode, cbNodes, node.parameters) || 223 visitNode(cbNode, node.type) || 224 visitNode(cbNode, node.body); 225 }, 226 [SyntaxKind.GetAccessor]: function forEachChildInGetAccessor<T>(node: GetAccessorDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 227 return visitNodes(cbNode, cbNodes, node.modifiers) || 228 visitNode(cbNode, node.name) || 229 visitNodes(cbNode, cbNodes, node.typeParameters) || 230 visitNodes(cbNode, cbNodes, node.parameters) || 231 visitNode(cbNode, node.type) || 232 visitNode(cbNode, node.body); 233 }, 234 [SyntaxKind.SetAccessor]: function forEachChildInSetAccessor<T>(node: SetAccessorDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 235 return visitNodes(cbNode, cbNodes, node.modifiers) || 236 visitNode(cbNode, node.name) || 237 visitNodes(cbNode, cbNodes, node.typeParameters) || 238 visitNodes(cbNode, cbNodes, node.parameters) || 239 visitNode(cbNode, node.type) || 240 visitNode(cbNode, node.body); 241 }, 242 [SyntaxKind.FunctionDeclaration]: function forEachChildInFunctionDeclaration<T>(node: FunctionDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 243 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 244 visitNodes(cbNode, cbNodes, node.modifiers) || 245 visitNode(cbNode, node.asteriskToken) || 246 visitNode(cbNode, node.name) || 247 visitNodes(cbNode, cbNodes, node.typeParameters) || 248 visitNodes(cbNode, cbNodes, node.parameters) || 249 visitNode(cbNode, node.type) || 250 visitNode(cbNode, node.body); 251 }, 252 [SyntaxKind.FunctionExpression]: function forEachChildInFunctionExpression<T>(node: FunctionExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 253 return visitNodes(cbNode, cbNodes, node.modifiers) || 254 visitNode(cbNode, node.asteriskToken) || 255 visitNode(cbNode, node.name) || 256 visitNodes(cbNode, cbNodes, node.typeParameters) || 257 visitNodes(cbNode, cbNodes, node.parameters) || 258 visitNode(cbNode, node.type) || 259 visitNode(cbNode, node.body); 260 }, 261 [SyntaxKind.ArrowFunction]: function forEachChildInArrowFunction<T>(node: ArrowFunction, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 262 return visitNodes(cbNode, cbNodes, node.modifiers) || 263 visitNodes(cbNode, cbNodes, node.typeParameters) || 264 visitNodes(cbNode, cbNodes, node.parameters) || 265 visitNode(cbNode, node.type) || 266 visitNode(cbNode, node.equalsGreaterThanToken) || 267 visitNode(cbNode, node.body); 268 }, 269 [SyntaxKind.ClassStaticBlockDeclaration]: function forEachChildInClassStaticBlockDeclaration<T>(node: ClassStaticBlockDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 270 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 271 visitNodes(cbNode, cbNodes, node.modifiers) || 272 visitNode(cbNode, node.body); 273 }, 274 [SyntaxKind.TypeReference]: function forEachChildInTypeReference<T>(node: TypeReferenceNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 275 return visitNode(cbNode, node.typeName) || 276 visitNodes(cbNode, cbNodes, node.typeArguments); 277 }, 278 [SyntaxKind.TypePredicate]: function forEachChildInTypePredicate<T>(node: TypePredicateNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 279 return visitNode(cbNode, node.assertsModifier) || 280 visitNode(cbNode, node.parameterName) || 281 visitNode(cbNode, node.type); 282 }, 283 [SyntaxKind.TypeQuery]: function forEachChildInTypeQuery<T>(node: TypeQueryNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 284 return visitNode(cbNode, node.exprName) || 285 visitNodes(cbNode, cbNodes, node.typeArguments); 286 }, 287 [SyntaxKind.TypeLiteral]: function forEachChildInTypeLiteral<T>(node: TypeLiteralNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 288 return visitNodes(cbNode, cbNodes, node.members); 289 }, 290 [SyntaxKind.ArrayType]: function forEachChildInArrayType<T>(node: ArrayTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 291 return visitNode(cbNode, node.elementType); 292 }, 293 [SyntaxKind.TupleType]: function forEachChildInTupleType<T>(node: TupleTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 294 return visitNodes(cbNode, cbNodes, node.elements); 295 }, 296 [SyntaxKind.UnionType]: forEachChildInUnionOrIntersectionType, 297 [SyntaxKind.IntersectionType]: forEachChildInUnionOrIntersectionType, 298 [SyntaxKind.ConditionalType]: function forEachChildInConditionalType<T>(node: ConditionalTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 299 return visitNode(cbNode, node.checkType) || 300 visitNode(cbNode, node.extendsType) || 301 visitNode(cbNode, node.trueType) || 302 visitNode(cbNode, node.falseType); 303 }, 304 [SyntaxKind.InferType]: function forEachChildInInferType<T>(node: InferTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 305 return visitNode(cbNode, node.typeParameter); 306 }, 307 [SyntaxKind.ImportType]: function forEachChildInImportType<T>(node: ImportTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 308 return visitNode(cbNode, node.argument) || 309 visitNode(cbNode, node.assertions) || 310 visitNode(cbNode, node.qualifier) || 311 visitNodes(cbNode, cbNodes, node.typeArguments); 312 }, 313 [SyntaxKind.ImportTypeAssertionContainer]: function forEachChildInImportTypeAssertionContainer<T>(node: ImportTypeAssertionContainer, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 314 return visitNode(cbNode, node.assertClause); 315 }, 316 [SyntaxKind.ParenthesizedType]: forEachChildInParenthesizedTypeOrTypeOperator, 317 [SyntaxKind.TypeOperator]: forEachChildInParenthesizedTypeOrTypeOperator, 318 [SyntaxKind.IndexedAccessType]: function forEachChildInIndexedAccessType<T>(node: IndexedAccessTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 319 return visitNode(cbNode, node.objectType) || 320 visitNode(cbNode, node.indexType); 321 }, 322 [SyntaxKind.MappedType]: function forEachChildInMappedType<T>(node: MappedTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 323 return visitNode(cbNode, node.readonlyToken) || 324 visitNode(cbNode, node.typeParameter) || 325 visitNode(cbNode, node.nameType) || 326 visitNode(cbNode, node.questionToken) || 327 visitNode(cbNode, node.type) || 328 visitNodes(cbNode, cbNodes, node.members); 329 }, 330 [SyntaxKind.LiteralType]: function forEachChildInLiteralType<T>(node: LiteralTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 331 return visitNode(cbNode, node.literal); 332 }, 333 [SyntaxKind.NamedTupleMember]: function forEachChildInNamedTupleMember<T>(node: NamedTupleMember, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 334 return visitNode(cbNode, node.dotDotDotToken) || 335 visitNode(cbNode, node.name) || 336 visitNode(cbNode, node.questionToken) || 337 visitNode(cbNode, node.type); 338 }, 339 [SyntaxKind.ObjectBindingPattern]: forEachChildInObjectOrArrayBindingPattern, 340 [SyntaxKind.ArrayBindingPattern]: forEachChildInObjectOrArrayBindingPattern, 341 [SyntaxKind.ArrayLiteralExpression]: function forEachChildInArrayLiteralExpression<T>(node: ArrayLiteralExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 342 return visitNodes(cbNode, cbNodes, node.elements); 343 }, 344 [SyntaxKind.ObjectLiteralExpression]: function forEachChildInObjectLiteralExpression<T>(node: ObjectLiteralExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 345 return visitNodes(cbNode, cbNodes, node.properties); 346 }, 347 [SyntaxKind.PropertyAccessExpression]: function forEachChildInPropertyAccessExpression<T>(node: PropertyAccessExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 348 return visitNode(cbNode, node.expression) || 349 visitNode(cbNode, node.questionDotToken) || 350 visitNode(cbNode, node.name); 351 }, 352 [SyntaxKind.ElementAccessExpression]: function forEachChildInElementAccessExpression<T>(node: ElementAccessExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 353 return visitNode(cbNode, node.expression) || 354 visitNode(cbNode, node.questionDotToken) || 355 visitNode(cbNode, node.argumentExpression); 356 }, 357 [SyntaxKind.CallExpression]: forEachChildInCallOrNewExpression, 358 [SyntaxKind.NewExpression]: forEachChildInCallOrNewExpression, 359 [SyntaxKind.TaggedTemplateExpression]: function forEachChildInTaggedTemplateExpression<T>(node: TaggedTemplateExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 360 return visitNode(cbNode, node.tag) || 361 visitNode(cbNode, node.questionDotToken) || 362 visitNodes(cbNode, cbNodes, node.typeArguments) || 363 visitNode(cbNode, node.template); 364 }, 365 [SyntaxKind.TypeAssertionExpression]: function forEachChildInTypeAssertionExpression<T>(node: TypeAssertion, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 366 return visitNode(cbNode, node.type) || 367 visitNode(cbNode, node.expression); 368 }, 369 [SyntaxKind.ParenthesizedExpression]: function forEachChildInParenthesizedExpression<T>(node: ParenthesizedExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 370 return visitNode(cbNode, node.expression); 371 }, 372 [SyntaxKind.DeleteExpression]: function forEachChildInDeleteExpression<T>(node: DeleteExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 373 return visitNode(cbNode, node.expression); 374 }, 375 [SyntaxKind.TypeOfExpression]: function forEachChildInTypeOfExpression<T>(node: TypeOfExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 376 return visitNode(cbNode, node.expression); 377 }, 378 [SyntaxKind.VoidExpression]: function forEachChildInVoidExpression<T>(node: VoidExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 379 return visitNode(cbNode, node.expression); 380 }, 381 [SyntaxKind.PrefixUnaryExpression]: function forEachChildInPrefixUnaryExpression<T>(node: PrefixUnaryExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 382 return visitNode(cbNode, node.operand); 383 }, 384 [SyntaxKind.YieldExpression]: function forEachChildInYieldExpression<T>(node: YieldExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 385 return visitNode(cbNode, node.asteriskToken) || 386 visitNode(cbNode, node.expression); 387 }, 388 [SyntaxKind.AwaitExpression]: function forEachChildInAwaitExpression<T>(node: AwaitExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 389 return visitNode(cbNode, node.expression); 390 }, 391 [SyntaxKind.PostfixUnaryExpression]: function forEachChildInPostfixUnaryExpression<T>(node: PostfixUnaryExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 392 return visitNode(cbNode, node.operand); 393 }, 394 [SyntaxKind.BinaryExpression]: function forEachChildInBinaryExpression<T>(node: BinaryExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 395 return visitNode(cbNode, node.left) || 396 visitNode(cbNode, node.operatorToken) || 397 visitNode(cbNode, node.right); 398 }, 399 [SyntaxKind.AsExpression]: function forEachChildInAsExpression<T>(node: AsExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 400 return visitNode(cbNode, node.expression) || 401 visitNode(cbNode, node.type); 402 }, 403 [SyntaxKind.NonNullExpression]: function forEachChildInNonNullExpression<T>(node: NonNullExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 404 return visitNode(cbNode, node.expression); 405 }, 406 [SyntaxKind.SatisfiesExpression]: function forEachChildInSatisfiesExpression<T>(node: SatisfiesExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 407 return visitNode(cbNode, node.expression) || visitNode(cbNode, node.type); 408 }, 409 [SyntaxKind.MetaProperty]: function forEachChildInMetaProperty<T>(node: MetaProperty, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 410 return visitNode(cbNode, node.name); 411 }, 412 [SyntaxKind.ConditionalExpression]: function forEachChildInConditionalExpression<T>(node: ConditionalExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 413 return visitNode(cbNode, node.condition) || 414 visitNode(cbNode, node.questionToken) || 415 visitNode(cbNode, node.whenTrue) || 416 visitNode(cbNode, node.colonToken) || 417 visitNode(cbNode, node.whenFalse); 418 }, 419 [SyntaxKind.SpreadElement]: function forEachChildInSpreadElement<T>(node: SpreadElement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 420 return visitNode(cbNode, node.expression); 421 }, 422 [SyntaxKind.Block]: forEachChildInBlock, 423 [SyntaxKind.ModuleBlock]: forEachChildInBlock, 424 [SyntaxKind.SourceFile]: function forEachChildInSourceFile<T>(node: SourceFile, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 425 return visitNodes(cbNode, cbNodes, node.statements) || 426 visitNode(cbNode, node.endOfFileToken); 427 }, 428 [SyntaxKind.VariableStatement]: function forEachChildInVariableStatement<T>(node: VariableStatement, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 429 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 430 visitNodes(cbNode, cbNodes, node.modifiers) || 431 visitNode(cbNode, node.declarationList); 432 }, 433 [SyntaxKind.VariableDeclarationList]: function forEachChildInVariableDeclarationList<T>(node: VariableDeclarationList, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 434 return visitNodes(cbNode, cbNodes, node.declarations); 435 }, 436 [SyntaxKind.ExpressionStatement]: function forEachChildInExpressionStatement<T>(node: ExpressionStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 437 return visitNode(cbNode, node.expression); 438 }, 439 [SyntaxKind.IfStatement]: function forEachChildInIfStatement<T>(node: IfStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 440 return visitNode(cbNode, node.expression) || 441 visitNode(cbNode, node.thenStatement) || 442 visitNode(cbNode, node.elseStatement); 443 }, 444 [SyntaxKind.DoStatement]: function forEachChildInDoStatement<T>(node: DoStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 445 return visitNode(cbNode, node.statement) || 446 visitNode(cbNode, node.expression); 447 }, 448 [SyntaxKind.WhileStatement]: function forEachChildInWhileStatement<T>(node: WhileStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 449 return visitNode(cbNode, node.expression) || 450 visitNode(cbNode, node.statement); 451 }, 452 [SyntaxKind.ForStatement]: function forEachChildInForStatement<T>(node: ForStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 453 return visitNode(cbNode, node.initializer) || 454 visitNode(cbNode, node.condition) || 455 visitNode(cbNode, node.incrementor) || 456 visitNode(cbNode, node.statement); 457 }, 458 [SyntaxKind.ForInStatement]: function forEachChildInForInStatement<T>(node: ForInStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 459 return visitNode(cbNode, node.initializer) || 460 visitNode(cbNode, node.expression) || 461 visitNode(cbNode, node.statement); 462 }, 463 [SyntaxKind.ForOfStatement]: function forEachChildInForOfStatement<T>(node: ForOfStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 464 return visitNode(cbNode, node.awaitModifier) || 465 visitNode(cbNode, node.initializer) || 466 visitNode(cbNode, node.expression) || 467 visitNode(cbNode, node.statement); 468 }, 469 [SyntaxKind.ContinueStatement]: forEachChildInContinueOrBreakStatement, 470 [SyntaxKind.BreakStatement]: forEachChildInContinueOrBreakStatement, 471 [SyntaxKind.ReturnStatement]: function forEachChildInReturnStatement<T>(node: ReturnStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 472 return visitNode(cbNode, node.expression); 473 }, 474 [SyntaxKind.WithStatement]: function forEachChildInWithStatement<T>(node: WithStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 475 return visitNode(cbNode, node.expression) || 476 visitNode(cbNode, node.statement); 477 }, 478 [SyntaxKind.SwitchStatement]: function forEachChildInSwitchStatement<T>(node: SwitchStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 479 return visitNode(cbNode, node.expression) || 480 visitNode(cbNode, node.caseBlock); 481 }, 482 [SyntaxKind.CaseBlock]: function forEachChildInCaseBlock<T>(node: CaseBlock, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 483 return visitNodes(cbNode, cbNodes, node.clauses); 484 }, 485 [SyntaxKind.CaseClause]: function forEachChildInCaseClause<T>(node: CaseClause, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 486 return visitNode(cbNode, node.expression) || 487 visitNodes(cbNode, cbNodes, node.statements); 488 }, 489 [SyntaxKind.DefaultClause]: function forEachChildInDefaultClause<T>(node: DefaultClause, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 490 return visitNodes(cbNode, cbNodes, node.statements); 491 }, 492 [SyntaxKind.LabeledStatement]: function forEachChildInLabeledStatement<T>(node: LabeledStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 493 return visitNode(cbNode, node.label) || 494 visitNode(cbNode, node.statement); 495 }, 496 [SyntaxKind.ThrowStatement]: function forEachChildInThrowStatement<T>(node: ThrowStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 497 return visitNode(cbNode, node.expression); 498 }, 499 [SyntaxKind.TryStatement]: function forEachChildInTryStatement<T>(node: TryStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 500 return visitNode(cbNode, node.tryBlock) || 501 visitNode(cbNode, node.catchClause) || 502 visitNode(cbNode, node.finallyBlock); 503 }, 504 [SyntaxKind.CatchClause]: function forEachChildInCatchClause<T>(node: CatchClause, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 505 return visitNode(cbNode, node.variableDeclaration) || 506 visitNode(cbNode, node.block); 507 }, 508 [SyntaxKind.Decorator]: function forEachChildInDecorator<T>(node: Decorator, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 509 return visitNode(cbNode, node.expression); 510 }, 511 [SyntaxKind.ClassDeclaration]: forEachChildInClassDeclarationOrExpression, 512 [SyntaxKind.ClassExpression]: forEachChildInClassDeclarationOrExpression, 513 [SyntaxKind.StructDeclaration]: forEachChildInClassDeclarationOrExpression, 514 [SyntaxKind.AnnotationDeclaration]: forEachChildInAnnotationDeclaration, 515 [SyntaxKind.InterfaceDeclaration]: function forEachChildInInterfaceDeclaration<T>(node: InterfaceDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 516 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 517 visitNodes(cbNode, cbNodes, node.modifiers) || 518 visitNode(cbNode, node.name) || 519 visitNodes(cbNode, cbNodes, node.typeParameters) || 520 visitNodes(cbNode, cbNodes, node.heritageClauses) || 521 visitNodes(cbNode, cbNodes, node.members); 522 }, 523 [SyntaxKind.TypeAliasDeclaration]: function forEachChildInTypeAliasDeclaration<T>(node: TypeAliasDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 524 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 525 visitNodes(cbNode, cbNodes, node.modifiers) || 526 visitNode(cbNode, node.name) || 527 visitNodes(cbNode, cbNodes, node.typeParameters) || 528 visitNode(cbNode, node.type); 529 }, 530 [SyntaxKind.EnumDeclaration]: function forEachChildInEnumDeclaration<T>(node: EnumDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 531 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 532 visitNodes(cbNode, cbNodes, node.modifiers) || 533 visitNode(cbNode, node.name) || 534 visitNodes(cbNode, cbNodes, node.members); 535 }, 536 [SyntaxKind.EnumMember]: function forEachChildInEnumMember<T>(node: EnumMember, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 537 return visitNode(cbNode, node.name) || 538 visitNode(cbNode, node.initializer); 539 }, 540 [SyntaxKind.ModuleDeclaration]: function forEachChildInModuleDeclaration<T>(node: ModuleDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 541 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 542 visitNodes(cbNode, cbNodes, node.modifiers) || 543 visitNode(cbNode, node.name) || 544 visitNode(cbNode, node.body); 545 }, 546 [SyntaxKind.ImportEqualsDeclaration]: function forEachChildInImportEqualsDeclaration<T>(node: ImportEqualsDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 547 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 548 visitNodes(cbNode, cbNodes, node.modifiers) || 549 visitNode(cbNode, node.name) || 550 visitNode(cbNode, node.moduleReference); 551 }, 552 [SyntaxKind.ImportDeclaration]: function forEachChildInImportDeclaration<T>(node: ImportDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 553 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 554 visitNodes(cbNode, cbNodes, node.modifiers) || 555 visitNode(cbNode, node.importClause) || 556 visitNode(cbNode, node.moduleSpecifier) || 557 visitNode(cbNode, node.assertClause); 558 }, 559 [SyntaxKind.ImportClause]: function forEachChildInImportClause<T>(node: ImportClause, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 560 return visitNode(cbNode, node.name) || 561 visitNode(cbNode, node.namedBindings); 562 }, 563 [SyntaxKind.AssertClause]: function forEachChildInAssertClause<T>(node: AssertClause, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 564 return visitNodes(cbNode, cbNodes, node.elements); 565 }, 566 [SyntaxKind.AssertEntry]: function forEachChildInAssertEntry<T>(node: AssertEntry, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 567 return visitNode(cbNode, node.name) || 568 visitNode(cbNode, node.value); 569 }, 570 [SyntaxKind.NamespaceExportDeclaration]: function forEachChildInNamespaceExportDeclaration<T>(node: NamespaceExportDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 571 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 572 visitNode(cbNode, node.name); 573 }, 574 [SyntaxKind.NamespaceImport]: function forEachChildInNamespaceImport<T>(node: NamespaceImport, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 575 return visitNode(cbNode, node.name); 576 }, 577 [SyntaxKind.NamespaceExport]: function forEachChildInNamespaceExport<T>(node: NamespaceExport, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 578 return visitNode(cbNode, node.name); 579 }, 580 [SyntaxKind.NamedImports]: forEachChildInNamedImportsOrExports, 581 [SyntaxKind.NamedExports]: forEachChildInNamedImportsOrExports, 582 [SyntaxKind.ExportDeclaration]: function forEachChildInExportDeclaration<T>(node: ExportDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 583 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 584 visitNodes(cbNode, cbNodes, node.modifiers) || 585 visitNode(cbNode, node.exportClause) || 586 visitNode(cbNode, node.moduleSpecifier) || 587 visitNode(cbNode, node.assertClause); 588 }, 589 [SyntaxKind.ImportSpecifier]: forEachChildInImportOrExportSpecifier, 590 [SyntaxKind.ExportSpecifier]: forEachChildInImportOrExportSpecifier, 591 [SyntaxKind.ExportAssignment]: function forEachChildInExportAssignment<T>(node: ExportAssignment, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 592 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 593 visitNodes(cbNode, cbNodes, node.modifiers) || 594 visitNode(cbNode, node.expression); 595 }, 596 [SyntaxKind.TemplateExpression]: function forEachChildInTemplateExpression<T>(node: TemplateExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 597 return visitNode(cbNode, node.head) || 598 visitNodes(cbNode, cbNodes, node.templateSpans); 599 }, 600 [SyntaxKind.TemplateSpan]: function forEachChildInTemplateSpan<T>(node: TemplateSpan, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 601 return visitNode(cbNode, node.expression) || 602 visitNode(cbNode, node.literal); 603 }, 604 [SyntaxKind.TemplateLiteralType]: function forEachChildInTemplateLiteralType<T>(node: TemplateLiteralTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 605 return visitNode(cbNode, node.head) || 606 visitNodes(cbNode, cbNodes, node.templateSpans); 607 }, 608 [SyntaxKind.TemplateLiteralTypeSpan]: function forEachChildInTemplateLiteralTypeSpan<T>(node: TemplateLiteralTypeSpan, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 609 return visitNode(cbNode, node.type) || 610 visitNode(cbNode, node.literal); 611 }, 612 [SyntaxKind.ComputedPropertyName]: function forEachChildInComputedPropertyName<T>(node: ComputedPropertyName, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 613 return visitNode(cbNode, node.expression); 614 }, 615 [SyntaxKind.HeritageClause]: function forEachChildInHeritageClause<T>(node: HeritageClause, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 616 return visitNodes(cbNode, cbNodes, node.types); 617 }, 618 [SyntaxKind.ExpressionWithTypeArguments]: function forEachChildInExpressionWithTypeArguments<T>(node: ExpressionWithTypeArguments, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 619 return visitNode(cbNode, node.expression) || 620 visitNodes(cbNode, cbNodes, node.typeArguments); 621 }, 622 [SyntaxKind.ExternalModuleReference]: function forEachChildInExternalModuleReference<T>(node: ExternalModuleReference, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 623 return visitNode(cbNode, node.expression); 624 }, 625 [SyntaxKind.MissingDeclaration]: function forEachChildInMissingDeclaration<T>(node: MissingDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 626 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 627 visitNodes(cbNode, cbNodes, node.modifiers); 628 }, 629 [SyntaxKind.CommaListExpression]: function forEachChildInCommaListExpression<T>(node: CommaListExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 630 return visitNodes(cbNode, cbNodes, node.elements); 631 }, 632 [SyntaxKind.JsxElement]: function forEachChildInJsxElement<T>(node: JsxElement, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 633 return visitNode(cbNode, node.openingElement) || 634 visitNodes(cbNode, cbNodes, node.children) || 635 visitNode(cbNode, node.closingElement); 636 }, 637 [SyntaxKind.JsxFragment]: function forEachChildInJsxFragment<T>(node: JsxFragment, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 638 return visitNode(cbNode, node.openingFragment) || 639 visitNodes(cbNode, cbNodes, node.children) || 640 visitNode(cbNode, node.closingFragment); 641 }, 642 [SyntaxKind.JsxSelfClosingElement]: forEachChildInJsxOpeningOrSelfClosingElement, 643 [SyntaxKind.JsxOpeningElement]: forEachChildInJsxOpeningOrSelfClosingElement, 644 [SyntaxKind.JsxAttributes]: function forEachChildInJsxAttributes<T>(node: JsxAttributes, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 645 return visitNodes(cbNode, cbNodes, node.properties); 646 }, 647 [SyntaxKind.JsxAttribute]: function forEachChildInJsxAttribute<T>(node: JsxAttribute, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 648 return visitNode(cbNode, node.name) || 649 visitNode(cbNode, node.initializer); 650 }, 651 [SyntaxKind.JsxSpreadAttribute]: function forEachChildInJsxSpreadAttribute<T>(node: JsxSpreadAttribute, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 652 return visitNode(cbNode, node.expression); 653 }, 654 [SyntaxKind.JsxExpression]: function forEachChildInJsxExpression<T>(node: JsxExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 655 return visitNode(cbNode, node.dotDotDotToken) || 656 visitNode(cbNode, node.expression); 657 }, 658 [SyntaxKind.JsxClosingElement]: function forEachChildInJsxClosingElement<T>(node: JsxClosingElement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 659 return visitNode(cbNode, node.tagName); 660 }, 661 [SyntaxKind.OptionalType]: forEachChildInOptionalRestOrJSDocParameterModifier, 662 [SyntaxKind.RestType]: forEachChildInOptionalRestOrJSDocParameterModifier, 663 [SyntaxKind.JSDocTypeExpression]: forEachChildInOptionalRestOrJSDocParameterModifier, 664 [SyntaxKind.JSDocNonNullableType]: forEachChildInOptionalRestOrJSDocParameterModifier, 665 [SyntaxKind.JSDocNullableType]: forEachChildInOptionalRestOrJSDocParameterModifier, 666 [SyntaxKind.JSDocOptionalType]: forEachChildInOptionalRestOrJSDocParameterModifier, 667 [SyntaxKind.JSDocVariadicType]: forEachChildInOptionalRestOrJSDocParameterModifier, 668 [SyntaxKind.JSDocFunctionType]: function forEachChildInJSDocFunctionType<T>(node: JSDocFunctionType, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 669 return visitNodes(cbNode, cbNodes, node.parameters) || 670 visitNode(cbNode, node.type); 671 }, 672 [SyntaxKind.JSDoc]: function forEachChildInJSDoc<T>(node: JSDoc, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 673 return (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)) 674 || visitNodes(cbNode, cbNodes, node.tags); 675 }, 676 [SyntaxKind.JSDocSeeTag]: function forEachChildInJSDocSeeTag<T>(node: JSDocSeeTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 677 return visitNode(cbNode, node.tagName) || 678 visitNode(cbNode, node.name) || 679 (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); 680 }, 681 [SyntaxKind.JSDocNameReference]: function forEachChildInJSDocNameReference<T>(node: JSDocNameReference, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 682 return visitNode(cbNode, node.name); 683 }, 684 [SyntaxKind.JSDocMemberName]: function forEachChildInJSDocMemberName<T>(node: JSDocMemberName, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 685 return visitNode(cbNode, node.left) || 686 visitNode(cbNode, node.right); 687 }, 688 [SyntaxKind.JSDocParameterTag]: forEachChildInJSDocParameterOrPropertyTag, 689 [SyntaxKind.JSDocPropertyTag]: forEachChildInJSDocParameterOrPropertyTag, 690 [SyntaxKind.JSDocAuthorTag]: function forEachChildInJSDocAuthorTag<T>(node: JSDocAuthorTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 691 return visitNode(cbNode, node.tagName) || 692 (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); 693 }, 694 [SyntaxKind.JSDocImplementsTag]: function forEachChildInJSDocImplementsTag<T>(node: JSDocImplementsTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 695 return visitNode(cbNode, node.tagName) || 696 visitNode(cbNode, node.class) || 697 (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); 698 }, 699 [SyntaxKind.JSDocAugmentsTag]: function forEachChildInJSDocAugmentsTag<T>(node: JSDocAugmentsTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 700 return visitNode(cbNode, node.tagName) || 701 visitNode(cbNode, node.class) || 702 (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); 703 }, 704 [SyntaxKind.JSDocTemplateTag]: function forEachChildInJSDocTemplateTag<T>(node: JSDocTemplateTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 705 return visitNode(cbNode, node.tagName) || 706 visitNode(cbNode, node.constraint) || 707 visitNodes(cbNode, cbNodes, node.typeParameters) || 708 (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); 709 }, 710 [SyntaxKind.JSDocTypedefTag]: function forEachChildInJSDocTypedefTag<T>(node: JSDocTypedefTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 711 return visitNode(cbNode, node.tagName) || 712 (node.typeExpression && 713 node.typeExpression.kind === SyntaxKind.JSDocTypeExpression 714 ? visitNode(cbNode, node.typeExpression) || 715 visitNode(cbNode, node.fullName) || 716 (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)) 717 : visitNode(cbNode, node.fullName) || 718 visitNode(cbNode, node.typeExpression) || 719 (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment))); 720 }, 721 [SyntaxKind.JSDocCallbackTag]: function forEachChildInJSDocCallbackTag<T>(node: JSDocCallbackTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 722 return visitNode(cbNode, node.tagName) || 723 visitNode(cbNode, node.fullName) || 724 visitNode(cbNode, node.typeExpression) || 725 (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); 726 }, 727 [SyntaxKind.JSDocReturnTag]: forEachChildInJSDocReturnTag, 728 [SyntaxKind.JSDocTypeTag]: forEachChildInJSDocReturnTag, 729 [SyntaxKind.JSDocThisTag]: forEachChildInJSDocReturnTag, 730 [SyntaxKind.JSDocEnumTag]: forEachChildInJSDocReturnTag, 731 [SyntaxKind.JSDocSignature]: function forEachChildInJSDocSignature<T>(node: JSDocSignature, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 732 return forEach(node.typeParameters, cbNode) || 733 forEach(node.parameters, cbNode) || 734 visitNode(cbNode, node.type); 735 }, 736 [SyntaxKind.JSDocLink]: forEachChildInJSDocLinkCodeOrPlain, 737 [SyntaxKind.JSDocLinkCode]: forEachChildInJSDocLinkCodeOrPlain, 738 [SyntaxKind.JSDocLinkPlain]: forEachChildInJSDocLinkCodeOrPlain, 739 [SyntaxKind.JSDocTypeLiteral]: function forEachChildInJSDocTypeLiteral<T>(node: JSDocTypeLiteral, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 740 return forEach(node.jsDocPropertyTags, cbNode); 741 }, 742 [SyntaxKind.JSDocTag]: forEachChildInJSDocTag, 743 [SyntaxKind.JSDocClassTag]: forEachChildInJSDocTag, 744 [SyntaxKind.JSDocPublicTag]: forEachChildInJSDocTag, 745 [SyntaxKind.JSDocPrivateTag]: forEachChildInJSDocTag, 746 [SyntaxKind.JSDocProtectedTag]: forEachChildInJSDocTag, 747 [SyntaxKind.JSDocReadonlyTag]: forEachChildInJSDocTag, 748 [SyntaxKind.JSDocDeprecatedTag]: forEachChildInJSDocTag, 749 [SyntaxKind.JSDocOverrideTag]: forEachChildInJSDocTag, 750 [SyntaxKind.PartiallyEmittedExpression]: forEachChildInPartiallyEmittedExpression, 751 }; 752 753 // shared 754 755 function forEachChildInCallOrConstructSignature<T>(node: CallSignatureDeclaration | ConstructSignatureDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 756 return visitNodes(cbNode, cbNodes, node.typeParameters) || 757 visitNodes(cbNode, cbNodes, node.parameters) || 758 visitNode(cbNode, node.type); 759 } 760 761 function forEachChildInUnionOrIntersectionType<T>(node: UnionTypeNode | IntersectionTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 762 return visitNodes(cbNode, cbNodes, node.types); 763 } 764 765 function forEachChildInParenthesizedTypeOrTypeOperator<T>(node: ParenthesizedTypeNode | TypeOperatorNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 766 return visitNode(cbNode, node.type); 767 } 768 769 function forEachChildInObjectOrArrayBindingPattern<T>(node: BindingPattern, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 770 return visitNodes(cbNode, cbNodes, node.elements); 771 } 772 773 function forEachChildInCallOrNewExpression<T>(node: CallExpression | NewExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 774 return visitNode(cbNode, node.expression) || 775 // TODO: should we separate these branches out? 776 visitNode(cbNode, (node as CallExpression).questionDotToken) || 777 visitNodes(cbNode, cbNodes, node.typeArguments) || 778 visitNodes(cbNode, cbNodes, node.arguments); 779 } 780 781 function forEachChildInBlock<T>(node: Block | ModuleBlock, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 782 return visitNodes(cbNode, cbNodes, node.statements); 783 } 784 785 function forEachChildInContinueOrBreakStatement<T>(node: ContinueStatement | BreakStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 786 return visitNode(cbNode, node.label); 787 } 788 789 function forEachChildInClassDeclarationOrExpression<T>(node: ClassDeclaration | ClassExpression | StructDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 790 return visitNodes(cbNode, cbNodes, node.modifiers) || 791 visitNode(cbNode, node.name) || 792 visitNodes(cbNode, cbNodes, node.typeParameters) || 793 visitNodes(cbNode, cbNodes, node.heritageClauses) || 794 visitNodes(cbNode, cbNodes, node.members); 795 } 796 797 function forEachChildInAnnotationDeclaration<T>(node: AnnotationDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 798 return visitNodes(cbNode, cbNodes, node.modifiers) || 799 visitNode(cbNode, node.name) || 800 visitNodes(cbNode, cbNodes, node.members); 801 } 802 803 function forEachChildInNamedImportsOrExports<T>(node: NamedImports | NamedExports, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 804 return visitNodes(cbNode, cbNodes, node.elements); 805 } 806 807 function forEachChildInImportOrExportSpecifier<T>(node: ImportSpecifier | ExportSpecifier, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 808 return visitNode(cbNode, node.propertyName) || 809 visitNode(cbNode, node.name); 810 } 811 812 function forEachChildInJsxOpeningOrSelfClosingElement<T>(node: JsxOpeningLikeElement, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 813 return visitNode(cbNode, node.tagName) || 814 visitNodes(cbNode, cbNodes, node.typeArguments) || 815 visitNode(cbNode, node.attributes); 816 } 817 818 function forEachChildInOptionalRestOrJSDocParameterModifier<T>(node: OptionalTypeNode | RestTypeNode | JSDocTypeExpression | JSDocNullableType | JSDocNonNullableType | JSDocOptionalType | JSDocVariadicType, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 819 return visitNode(cbNode, node.type); 820 } 821 822 function forEachChildInJSDocParameterOrPropertyTag<T>(node: JSDocParameterTag | JSDocPropertyTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 823 return visitNode(cbNode, node.tagName) || 824 (node.isNameFirst 825 ? visitNode(cbNode, node.name) || visitNode(cbNode, node.typeExpression) 826 : visitNode(cbNode, node.typeExpression) || visitNode(cbNode, node.name)) || 827 (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); 828 } 829 830 function forEachChildInJSDocReturnTag<T>(node: JSDocReturnTag | JSDocTypeTag | JSDocThisTag | JSDocEnumTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 831 return visitNode(cbNode, node.tagName) || 832 visitNode(cbNode, node.typeExpression) || 833 (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); 834 } 835 836 function forEachChildInJSDocLinkCodeOrPlain<T>(node: JSDocLink | JSDocLinkCode | JSDocLinkPlain, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 837 return visitNode(cbNode, node.name); 838 } 839 840 function forEachChildInJSDocTag<T>(node: JSDocUnknownTag | JSDocClassTag | JSDocPublicTag | JSDocPrivateTag | JSDocProtectedTag | JSDocReadonlyTag | JSDocDeprecatedTag | JSDocOverrideTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 841 return visitNode(cbNode, node.tagName) 842 || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); 843 } 844 845 function forEachChildInPartiallyEmittedExpression<T>(node: PartiallyEmittedExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 846 return visitNode(cbNode, node.expression); 847 } 848 849 /** 850 * Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes 851 * stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; otherwise, 852 * embedded arrays are flattened and the 'cbNode' callback is invoked for each element. If a callback returns 853 * a truthy value, iteration stops and that value is returned. Otherwise, undefined is returned. 854 * 855 * @param node a given node to visit its children 856 * @param cbNode a callback to be invoked for all child nodes 857 * @param cbNodes a callback to be invoked for embedded array 858 * 859 * @remarks `forEachChild` must visit the children of a node in the order 860 * that they appear in the source code. The language service depends on this property to locate nodes by position. 861 */ 862 export function forEachChild<T>(node: Node, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 863 if (node === undefined || node.kind <= SyntaxKind.LastToken) { 864 return; 865 } 866 const fn = (forEachChildTable as Record<SyntaxKind, ForEachChildFunction<any>>)[node.kind]; 867 return fn === undefined ? undefined : fn(node, cbNode, cbNodes); 868 } 869 870 /** @internal */ 871 /** 872 * Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes 873 * stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; additionally, 874 * unlike `forEachChild`, embedded arrays are flattened and the 'cbNode' callback is invoked for each element. 875 * If a callback returns a truthy value, iteration stops and that value is returned. Otherwise, undefined is returned. 876 * 877 * @param node a given node to visit its children 878 * @param cbNode a callback to be invoked for all child nodes 879 * @param cbNodes a callback to be invoked for embedded array 880 * 881 * @remarks Unlike `forEachChild`, `forEachChildRecursively` handles recursively invoking the traversal on each child node found, 882 * and while doing so, handles traversing the structure without relying on the callstack to encode the tree structure. 883 */ 884 export function forEachChildRecursively<T>(rootNode: Node, cbNode: (node: Node, parent: Node) => T | "skip" | undefined, cbNodes?: (nodes: NodeArray<Node>, parent: Node) => T | "skip" | undefined): T | undefined { 885 const queue: (Node | NodeArray<Node>)[] = gatherPossibleChildren(rootNode); 886 const parents: Node[] = []; // tracks parent references for elements in queue 887 while (parents.length < queue.length) { 888 parents.push(rootNode); 889 } 890 while (queue.length !== 0) { 891 const current = queue.pop()!; 892 const parent = parents.pop()!; 893 if (isArray(current)) { 894 if (cbNodes) { 895 const res = cbNodes(current, parent); 896 if (res) { 897 if (res === "skip") continue; 898 return res; 899 } 900 } 901 for (let i = current.length - 1; i >= 0; --i) { 902 queue.push(current[i]); 903 parents.push(parent); 904 } 905 } 906 else { 907 const res = cbNode(current, parent); 908 if (res) { 909 if (res === "skip") continue; 910 return res; 911 } 912 if (current.kind >= SyntaxKind.FirstNode) { 913 // add children in reverse order to the queue, so popping gives the first child 914 for (const child of gatherPossibleChildren(current)) { 915 queue.push(child); 916 parents.push(current); 917 } 918 } 919 } 920 } 921 } 922 923 function gatherPossibleChildren(node: Node) { 924 const children: (Node | NodeArray<Node>)[] = []; 925 forEachChild(node, addWorkItem, addWorkItem); // By using a stack above and `unshift` here, we emulate a depth-first preorder traversal 926 return children; 927 928 function addWorkItem(n: Node | NodeArray<Node>) { 929 children.unshift(n); 930 } 931 } 932 933 export interface CreateSourceFileOptions { 934 languageVersion: ScriptTarget; 935 /** 936 * Controls the format the file is detected as - this can be derived from only the path 937 * and files on disk, but needs to be done with a module resolution cache in scope to be performant. 938 * This is usually `undefined` for compilations that do not have `moduleResolution` values of `node16` or `nodenext`. 939 */ 940 impliedNodeFormat?: ModuleKind.ESNext | ModuleKind.CommonJS; 941 /** 942 * Controls how module-y-ness is set for the given file. Usually the result of calling 943 * `getSetExternalModuleIndicator` on a valid `CompilerOptions` object. If not present, the default 944 * check specified by `isFileProbablyExternalModule` will be used to set the field. 945 */ 946 setExternalModuleIndicator?: (file: SourceFile) => void; 947 /*@internal*/ packageJsonLocations?: readonly string[]; 948 /*@internal*/ packageJsonScope?: PackageJsonInfo; 949 } 950 951 function setExternalModuleIndicator(sourceFile: SourceFile) { 952 sourceFile.externalModuleIndicator = isFileProbablyExternalModule(sourceFile); 953 } 954 955 let sourceFileCompilerOptions: CompilerOptions; 956 export function createSourceFile(fileName: string, sourceText: string, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, setParentNodes = false, scriptKind?: ScriptKind, options?: CompilerOptions): SourceFile { 957 tracing?.push(tracing.Phase.Parse, "createSourceFile", { path: fileName }, /*separateBeginAndEnd*/ true); 958 const recordInfo = MemoryDotting.recordStage(MemoryDotting.CREATE_SORUCE_FILE_PARSE); 959 performance.mark("beforeParse"); 960 let result: SourceFile; 961 sourceFileCompilerOptions = options ?? defaultInitCompilerOptions; 962 perfLogger.logStartParseSourceFile(fileName); 963 const { 964 languageVersion, 965 setExternalModuleIndicator: overrideSetExternalModuleIndicator, 966 impliedNodeFormat: format 967 } = typeof languageVersionOrOptions === "object" ? languageVersionOrOptions : ({ languageVersion: languageVersionOrOptions } as CreateSourceFileOptions); 968 if (languageVersion === ScriptTarget.JSON) { 969 result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, ScriptKind.JSON, noop); 970 } 971 else { 972 const setIndicator = format === undefined ? overrideSetExternalModuleIndicator : (file: SourceFile) => { 973 file.impliedNodeFormat = format; 974 return (overrideSetExternalModuleIndicator || setExternalModuleIndicator)(file); 975 }; 976 result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, scriptKind, setIndicator); 977 } 978 perfLogger.logStopParseSourceFile(); 979 980 performance.mark("afterParse"); 981 MemoryDotting.stopRecordStage(recordInfo); 982 performance.measure("Parse", "beforeParse", "afterParse"); 983 tracing?.pop(); 984 return result; 985 } 986 987 export function parseIsolatedEntityName(text: string, languageVersion: ScriptTarget): EntityName | undefined { 988 return Parser.parseIsolatedEntityName(text, languageVersion); 989 } 990 991 /** 992 * Parse json text into SyntaxTree and return node and parse errors if any 993 * @param fileName 994 * @param sourceText 995 */ 996 export function parseJsonText(fileName: string, sourceText: string): JsonSourceFile { 997 return Parser.parseJsonText(fileName, sourceText); 998 } 999 1000 // See also `isExternalOrCommonJsModule` in utilities.ts 1001 export function isExternalModule(file: SourceFile): boolean { 1002 return file.externalModuleIndicator !== undefined; 1003 } 1004 1005 // Produces a new SourceFile for the 'newText' provided. The 'textChangeRange' parameter 1006 // indicates what changed between the 'text' that this SourceFile has and the 'newText'. 1007 // The SourceFile will be created with the compiler attempting to reuse as many nodes from 1008 // this file as possible. 1009 // 1010 // Note: this function mutates nodes from this SourceFile. That means any existing nodes 1011 // from this SourceFile that are being held onto may change as a result (including 1012 // becoming detached from any SourceFile). It is recommended that this SourceFile not 1013 // be used once 'update' is called on it. 1014 export function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks = false, option?: CompilerOptions): SourceFile { 1015 sourceFileCompilerOptions = option ?? defaultInitCompilerOptions; 1016 const newSourceFile = IncrementalParser.updateSourceFile(sourceFile, newText, textChangeRange, aggressiveChecks); 1017 // Because new source file node is created, it may not have the flag PossiblyContainDynamicImport. This is the case if there is no new edit to add dynamic import. 1018 // We will manually port the flag to the new source file. 1019 (newSourceFile as Mutable<SourceFile>).flags |= (sourceFile.flags & NodeFlags.PermanentlySetIncrementalFlags); 1020 return newSourceFile; 1021 } 1022 1023 /* @internal */ 1024 export function parseIsolatedJSDocComment(content: string, start?: number, length?: number) { 1025 const result = Parser.JSDocParser.parseIsolatedJSDocComment(content, start, length); 1026 if (result && result.jsDoc) { 1027 // because the jsDocComment was parsed out of the source file, it might 1028 // not be covered by the fixupParentReferences. 1029 Parser.fixupParentReferences(result.jsDoc); 1030 } 1031 1032 return result; 1033 } 1034 1035 /* @internal */ 1036 // Exposed only for testing. 1037 export function parseJSDocTypeExpressionForTests(content: string, start?: number, length?: number) { 1038 return Parser.JSDocParser.parseJSDocTypeExpressionForTests(content, start, length); 1039 } 1040 1041 // Implement the parser as a singleton module. We do this for perf reasons because creating 1042 // parser instances can actually be expensive enough to impact us on projects with many source 1043 // files. 1044 namespace Parser { 1045 // Share a single scanner across all calls to parse a source file. This helps speed things 1046 // up by avoiding the cost of creating/compiling scanners over and over again. 1047 const scanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ true); 1048 1049 const disallowInAndDecoratorContext = NodeFlags.DisallowInContext | NodeFlags.DecoratorContext; 1050 1051 // capture constructors in 'initializeState' to avoid null checks 1052 let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; 1053 let TokenConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; 1054 let IdentifierConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; 1055 let PrivateIdentifierConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; 1056 let SourceFileConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; 1057 1058 function countNode(node: Node) { 1059 nodeCount++; 1060 return node; 1061 } 1062 1063 // Rather than using `createBaseNodeFactory` here, we establish a `BaseNodeFactory` that closes over the 1064 // constructors above, which are reset each time `initializeState` is called. 1065 const baseNodeFactory: BaseNodeFactory = { 1066 createBaseSourceFileNode: kind => countNode(new SourceFileConstructor(kind, /*pos*/ 0, /*end*/ 0)), 1067 createBaseIdentifierNode: kind => countNode(new IdentifierConstructor(kind, /*pos*/ 0, /*end*/ 0)), 1068 createBasePrivateIdentifierNode: kind => countNode(new PrivateIdentifierConstructor(kind, /*pos*/ 0, /*end*/ 0)), 1069 createBaseTokenNode: kind => countNode(new TokenConstructor(kind, /*pos*/ 0, /*end*/ 0)), 1070 createBaseNode: kind => countNode(new NodeConstructor(kind, /*pos*/ 0, /*end*/ 0)) 1071 }; 1072 1073 const factory = createNodeFactory(NodeFactoryFlags.NoParenthesizerRules | NodeFactoryFlags.NoNodeConverters | NodeFactoryFlags.NoOriginalNode, baseNodeFactory); 1074 1075 let fileName: string; 1076 let sourceFlags: NodeFlags; 1077 let sourceText: string; 1078 let languageVersion: ScriptTarget; 1079 let scriptKind: ScriptKind; 1080 let languageVariant: LanguageVariant; 1081 let parseDiagnostics: DiagnosticWithDetachedLocation[]; 1082 let jsDocDiagnostics: DiagnosticWithDetachedLocation[]; 1083 let syntaxCursor: IncrementalParser.SyntaxCursor | undefined; 1084 1085 let currentToken: SyntaxKind; 1086 let nodeCount: number; 1087 let identifiers: ESMap<string, string>; 1088 let privateIdentifiers: ESMap<string, string>; 1089 let identifierCount: number; 1090 1091 let parsingContext: ParsingContext; 1092 1093 let notParenthesizedArrow: Set<number> | undefined; 1094 1095 // Flags that dictate what parsing context we're in. For example: 1096 // Whether or not we are in strict parsing mode. All that changes in strict parsing mode is 1097 // that some tokens that would be considered identifiers may be considered keywords. 1098 // 1099 // When adding more parser context flags, consider which is the more common case that the 1100 // flag will be in. This should be the 'false' state for that flag. The reason for this is 1101 // that we don't store data in our nodes unless the value is in the *non-default* state. So, 1102 // for example, more often than code 'allows-in' (or doesn't 'disallow-in'). We opt for 1103 // 'disallow-in' set to 'false'. Otherwise, if we had 'allowsIn' set to 'true', then almost 1104 // all nodes would need extra state on them to store this info. 1105 // 1106 // Note: 'allowIn' and 'allowYield' track 1:1 with the [in] and [yield] concepts in the ES6 1107 // grammar specification. 1108 // 1109 // An important thing about these context concepts. By default they are effectively inherited 1110 // while parsing through every grammar production. i.e. if you don't change them, then when 1111 // you parse a sub-production, it will have the same context values as the parent production. 1112 // This is great most of the time. After all, consider all the 'expression' grammar productions 1113 // and how nearly all of them pass along the 'in' and 'yield' context values: 1114 // 1115 // EqualityExpression[In, Yield] : 1116 // RelationalExpression[?In, ?Yield] 1117 // EqualityExpression[?In, ?Yield] == RelationalExpression[?In, ?Yield] 1118 // EqualityExpression[?In, ?Yield] != RelationalExpression[?In, ?Yield] 1119 // EqualityExpression[?In, ?Yield] === RelationalExpression[?In, ?Yield] 1120 // EqualityExpression[?In, ?Yield] !== RelationalExpression[?In, ?Yield] 1121 // 1122 // Where you have to be careful is then understanding what the points are in the grammar 1123 // where the values are *not* passed along. For example: 1124 // 1125 // SingleNameBinding[Yield,GeneratorParameter] 1126 // [+GeneratorParameter]BindingIdentifier[Yield] Initializer[In]opt 1127 // [~GeneratorParameter]BindingIdentifier[?Yield]Initializer[In, ?Yield]opt 1128 // 1129 // Here this is saying that if the GeneratorParameter context flag is set, that we should 1130 // explicitly set the 'yield' context flag to false before calling into the BindingIdentifier 1131 // and we should explicitly unset the 'yield' context flag before calling into the Initializer. 1132 // production. Conversely, if the GeneratorParameter context flag is not set, then we 1133 // should leave the 'yield' context flag alone. 1134 // 1135 // Getting this all correct is tricky and requires careful reading of the grammar to 1136 // understand when these values should be changed versus when they should be inherited. 1137 // 1138 // Note: it should not be necessary to save/restore these flags during speculative/lookahead 1139 // parsing. These context flags are naturally stored and restored through normal recursive 1140 // descent parsing and unwinding. 1141 let contextFlags: NodeFlags; 1142 1143 let etsFlags: EtsFlags; 1144 1145 // Indicates whether we are currently parsing top-level statements. 1146 let topLevel = true; 1147 1148 // Whether or not we've had a parse error since creating the last AST node. If we have 1149 // encountered an error, it will be stored on the next AST node we create. Parse errors 1150 // can be broken down into three categories: 1151 // 1152 // 1) An error that occurred during scanning. For example, an unterminated literal, or a 1153 // character that was completely not understood. 1154 // 1155 // 2) A token was expected, but was not present. This type of error is commonly produced 1156 // by the 'parseExpected' function. 1157 // 1158 // 3) A token was present that no parsing function was able to consume. This type of error 1159 // only occurs in the 'abortParsingListOrMoveToNextToken' function when the parser 1160 // decides to skip the token. 1161 // 1162 // In all of these cases, we want to mark the next node as having had an error before it. 1163 // With this mark, we can know in incremental settings if this node can be reused, or if 1164 // we have to reparse it. If we don't keep this information around, we may just reuse the 1165 // node. in that event we would then not produce the same errors as we did before, causing 1166 // significant confusion problems. 1167 // 1168 // Note: it is necessary that this value be saved/restored during speculative/lookahead 1169 // parsing. During lookahead parsing, we will often create a node. That node will have 1170 // this value attached, and then this value will be set back to 'false'. If we decide to 1171 // rewind, we must get back to the same value we had prior to the lookahead. 1172 // 1173 // Note: any errors at the end of the file that do not precede a regular node, should get 1174 // attached to the EOF token. 1175 let parseErrorBeforeNextFinishedNode = false; 1176 1177 let extendEtsComponentDeclaration: { name: string, type: string, instance: string } | undefined; 1178 1179 let stylesEtsComponentDeclaration: { name: string, type: string, instance: string } | undefined; 1180 1181 // A map to record file scope '@styles' function name 1182 const fileStylesComponents = new Map<string, SyntaxKind>(); 1183 1184 let currentStructName: string | undefined; 1185 1186 let stateStylesRootNode: string | undefined; 1187 1188 // A map to record struct scope '@styles' method name 1189 const structStylesComponents = new Map<string, { structName: string, kind: SyntaxKind }>(); 1190 1191 export function parseSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, syntaxCursor: IncrementalParser.SyntaxCursor | undefined, setParentNodes = false, scriptKind?: ScriptKind, setExternalModuleIndicatorOverride?: (file: SourceFile) => void): SourceFile { 1192 scriptKind = ensureScriptKind(fileName, scriptKind); 1193 if (scriptKind === ScriptKind.JSON) { 1194 const result = parseJsonText(fileName, sourceText, languageVersion, syntaxCursor, setParentNodes); 1195 convertToObjectWorker(result, result.statements[0]?.expression, result.parseDiagnostics, /*returnValue*/ false, /*knownRootOptions*/ undefined, /*jsonConversionNotifier*/ undefined); 1196 result.referencedFiles = emptyArray; 1197 result.typeReferenceDirectives = emptyArray; 1198 result.libReferenceDirectives = emptyArray; 1199 result.amdDependencies = emptyArray; 1200 result.hasNoDefaultLib = false; 1201 result.pragmas = emptyMap as ReadonlyPragmaMap; 1202 return result; 1203 } 1204 1205 initializeState(fileName, sourceText, languageVersion, syntaxCursor, scriptKind); 1206 1207 const result = parseSourceFileWorker(languageVersion, setParentNodes, scriptKind, setExternalModuleIndicatorOverride || setExternalModuleIndicator); 1208 1209 clearState(); 1210 1211 return result; 1212 } 1213 1214 export function parseIsolatedEntityName(content: string, languageVersion: ScriptTarget): EntityName | undefined { 1215 // Choice of `isDeclarationFile` should be arbitrary 1216 initializeState("", content, languageVersion, /*syntaxCursor*/ undefined, ScriptKind.JS); 1217 // Prime the scanner. 1218 nextToken(); 1219 const entityName = parseEntityName(/*allowReservedWords*/ true); 1220 const isInvalid = token() === SyntaxKind.EndOfFileToken && !parseDiagnostics.length; 1221 clearState(); 1222 return isInvalid ? entityName : undefined; 1223 } 1224 1225 export function parseJsonText(fileName: string, sourceText: string, languageVersion: ScriptTarget = ScriptTarget.ES2015, syntaxCursor?: IncrementalParser.SyntaxCursor, setParentNodes = false): JsonSourceFile { 1226 initializeState(fileName, sourceText, languageVersion, syntaxCursor, ScriptKind.JSON); 1227 sourceFlags = contextFlags; 1228 1229 // Prime the scanner. 1230 nextToken(); 1231 const pos = getNodePos(); 1232 let statements, endOfFileToken; 1233 if (token() === SyntaxKind.EndOfFileToken) { 1234 statements = createNodeArray([], pos, pos); 1235 endOfFileToken = parseTokenNode<EndOfFileToken>(); 1236 } 1237 else { 1238 // Loop and synthesize an ArrayLiteralExpression if there are more than 1239 // one top-level expressions to ensure all input text is consumed. 1240 let expressions: Expression[] | Expression | undefined; 1241 while (token() !== SyntaxKind.EndOfFileToken) { 1242 let expression; 1243 switch (token()) { 1244 case SyntaxKind.OpenBracketToken: 1245 expression = parseArrayLiteralExpression(); 1246 break; 1247 case SyntaxKind.TrueKeyword: 1248 case SyntaxKind.FalseKeyword: 1249 case SyntaxKind.NullKeyword: 1250 expression = parseTokenNode<BooleanLiteral | NullLiteral>(); 1251 break; 1252 case SyntaxKind.MinusToken: 1253 if (lookAhead(() => nextToken() === SyntaxKind.NumericLiteral && nextToken() !== SyntaxKind.ColonToken)) { 1254 expression = parsePrefixUnaryExpression() as JsonMinusNumericLiteral; 1255 } 1256 else { 1257 expression = parseObjectLiteralExpression(); 1258 } 1259 break; 1260 case SyntaxKind.NumericLiteral: 1261 case SyntaxKind.StringLiteral: 1262 if (lookAhead(() => nextToken() !== SyntaxKind.ColonToken)) { 1263 expression = parseLiteralNode() as StringLiteral | NumericLiteral; 1264 break; 1265 } 1266 // falls through 1267 default: 1268 expression = parseObjectLiteralExpression(); 1269 break; 1270 } 1271 1272 // Error recovery: collect multiple top-level expressions 1273 if (expressions && isArray(expressions)) { 1274 expressions.push(expression); 1275 } 1276 else if (expressions) { 1277 expressions = [expressions, expression]; 1278 } 1279 else { 1280 expressions = expression; 1281 if (token() !== SyntaxKind.EndOfFileToken) { 1282 parseErrorAtCurrentToken(Diagnostics.Unexpected_token); 1283 } 1284 } 1285 } 1286 1287 const expression = isArray(expressions) ? finishNode(factory.createArrayLiteralExpression(expressions), pos) : Debug.checkDefined(expressions); 1288 const statement = factory.createExpressionStatement(expression) as JsonObjectExpressionStatement; 1289 finishNode(statement, pos); 1290 statements = createNodeArray([statement], pos); 1291 endOfFileToken = parseExpectedToken(SyntaxKind.EndOfFileToken, Diagnostics.Unexpected_token); 1292 } 1293 1294 // Set source file so that errors will be reported with this file name 1295 const sourceFile = createSourceFile(fileName, ScriptTarget.ES2015, ScriptKind.JSON, /*isDeclaration*/ false, statements, endOfFileToken, sourceFlags, noop); 1296 1297 if (setParentNodes) { 1298 fixupParentReferences(sourceFile); 1299 } 1300 1301 sourceFile.nodeCount = nodeCount; 1302 sourceFile.identifierCount = identifierCount; 1303 sourceFile.identifiers = identifiers; 1304 sourceFile.parseDiagnostics = attachFileToDiagnostics(parseDiagnostics, sourceFile); 1305 if (jsDocDiagnostics) { 1306 sourceFile.jsDocDiagnostics = attachFileToDiagnostics(jsDocDiagnostics, sourceFile); 1307 } 1308 1309 const result = sourceFile as JsonSourceFile; 1310 clearState(); 1311 return result; 1312 } 1313 1314 function initializeState(_fileName: string, _sourceText: string, _languageVersion: ScriptTarget, _syntaxCursor: IncrementalParser.SyntaxCursor | undefined, _scriptKind: ScriptKind) { 1315 NodeConstructor = objectAllocator.getNodeConstructor(); 1316 TokenConstructor = objectAllocator.getTokenConstructor(); 1317 IdentifierConstructor = objectAllocator.getIdentifierConstructor(); 1318 PrivateIdentifierConstructor = objectAllocator.getPrivateIdentifierConstructor(); 1319 SourceFileConstructor = objectAllocator.getSourceFileConstructor(); 1320 1321 fileName = normalizePath(_fileName); 1322 sourceText = _sourceText; 1323 languageVersion = _languageVersion; 1324 syntaxCursor = _syntaxCursor; 1325 scriptKind = _scriptKind; 1326 languageVariant = getLanguageVariant(_scriptKind); 1327 1328 parseDiagnostics = []; 1329 parsingContext = 0; 1330 identifiers = new Map<string, string>(); 1331 privateIdentifiers = new Map<string, string>(); 1332 identifierCount = 0; 1333 nodeCount = 0; 1334 sourceFlags = 0; 1335 topLevel = true; 1336 1337 switch (scriptKind) { 1338 case ScriptKind.JS: 1339 case ScriptKind.JSX: 1340 contextFlags = NodeFlags.JavaScriptFile; 1341 break; 1342 case ScriptKind.JSON: 1343 contextFlags = NodeFlags.JavaScriptFile | NodeFlags.JsonFile; 1344 break; 1345 case ScriptKind.ETS: 1346 contextFlags = NodeFlags.EtsContext; 1347 break; 1348 default: 1349 contextFlags = NodeFlags.None; 1350 break; 1351 } 1352 if (fileName.endsWith(Extension.Ets)) { 1353 contextFlags = NodeFlags.EtsContext; 1354 } 1355 parseErrorBeforeNextFinishedNode = false; 1356 1357 // Initialize and prime the scanner before parsing the source elements. 1358 scanner.setText(sourceText); 1359 scanner.setOnError(scanError); 1360 scanner.setScriptTarget(languageVersion); 1361 scanner.setLanguageVariant(languageVariant); 1362 scanner.setEtsContext(inEtsContext()); 1363 } 1364 1365 function clearState() { 1366 // Clear out the text the scanner is pointing at, so it doesn't keep anything alive unnecessarily. 1367 scanner.clearCommentDirectives(); 1368 scanner.setText(""); 1369 scanner.setOnError(undefined); 1370 scanner.setEtsContext(false); 1371 // Clear any data. We don't want to accidentally hold onto it for too long. 1372 sourceText = undefined!; 1373 languageVersion = undefined!; 1374 syntaxCursor = undefined; 1375 scriptKind = undefined!; 1376 languageVariant = undefined!; 1377 sourceFlags = 0; 1378 parseDiagnostics = undefined!; 1379 jsDocDiagnostics = undefined!; 1380 parsingContext = 0; 1381 identifiers = undefined!; 1382 notParenthesizedArrow = undefined; 1383 topLevel = true; 1384 extendEtsComponentDeclaration = undefined; 1385 stylesEtsComponentDeclaration = undefined; 1386 stateStylesRootNode = undefined; 1387 fileStylesComponents.clear(); 1388 structStylesComponents.clear(); 1389 } 1390 1391 function parseSourceFileWorker(languageVersion: ScriptTarget, setParentNodes: boolean, scriptKind: ScriptKind, setExternalModuleIndicator: (file: SourceFile) => void): SourceFile { 1392 const isDeclarationFile = isDeclarationFileName(fileName); 1393 if (isDeclarationFile) { 1394 contextFlags |= NodeFlags.Ambient; 1395 } 1396 1397 sourceFlags = contextFlags; 1398 1399 // Prime the scanner. 1400 nextToken(); 1401 1402 let statements = parseList(ParsingContext.SourceElements, parseStatement); 1403 const markedkitImportRanges = new Array<TextRange>(); 1404 const sdkPath = getSdkPath(sourceFileCompilerOptions); 1405 statements = (!!sourceFileCompilerOptions.noTransformedKitInParser || !sdkPath || parseDiagnostics.length) ? 1406 statements : 1407 createNodeArray(processKit(factory, statements, sdkPath, markedkitImportRanges, inEtsContext()), statements.pos); 1408 Debug.assert(token() === SyntaxKind.EndOfFileToken); 1409 const endOfFileToken = addJSDocComment(parseTokenNode<EndOfFileToken>()); 1410 1411 const sourceFile = createSourceFile(fileName, languageVersion, scriptKind, isDeclarationFile, statements, endOfFileToken, sourceFlags, setExternalModuleIndicator); 1412 if (markedkitImportRanges.length > 0) { 1413 sourceFile.markedKitImportRange = markedkitImportRanges; 1414 } 1415 1416 // A member of ReadonlyArray<T> isn't assignable to a member of T[] (and prevents a direct cast) - but this is where we set up those members so they can be readonly in the future 1417 processCommentPragmas(sourceFile as {} as PragmaContext, sourceText); 1418 processPragmasIntoFields(sourceFile as {} as PragmaContext, reportPragmaDiagnostic); 1419 1420 sourceFile.commentDirectives = scanner.getCommentDirectives(); 1421 sourceFile.nodeCount = nodeCount; 1422 sourceFile.identifierCount = identifierCount; 1423 sourceFile.identifiers = identifiers; 1424 sourceFile.parseDiagnostics = attachFileToDiagnostics(parseDiagnostics, sourceFile); 1425 if (jsDocDiagnostics) { 1426 sourceFile.jsDocDiagnostics = attachFileToDiagnostics(jsDocDiagnostics, sourceFile); 1427 } 1428 1429 if (setParentNodes) { 1430 fixupParentReferences(sourceFile); 1431 } 1432 1433 return sourceFile; 1434 1435 function reportPragmaDiagnostic(pos: number, end: number, diagnostic: DiagnosticMessage) { 1436 parseDiagnostics.push(createDetachedDiagnostic(fileName, pos, end, diagnostic)); 1437 } 1438 } 1439 1440 function withJSDoc<T extends HasJSDoc>(node: T, hasJSDoc: boolean): T { 1441 return hasJSDoc ? addJSDocComment(node) : node; 1442 } 1443 1444 let hasDeprecatedTag = false; 1445 function addJSDocComment<T extends HasJSDoc>(node: T): T { 1446 Debug.assert(!node.jsDoc); // Should only be called once per node 1447 const jsDoc = mapDefined(getJSDocCommentRanges(node, sourceText), comment => JSDocParser.parseJSDocComment(node, comment.pos, comment.end - comment.pos)); 1448 if (jsDoc.length) node.jsDoc = jsDoc; 1449 if (hasDeprecatedTag) { 1450 hasDeprecatedTag = false; 1451 (node as Mutable<T>).flags |= NodeFlags.Deprecated; 1452 } 1453 return node; 1454 } 1455 1456 function reparseTopLevelAwait(sourceFile: SourceFile) { 1457 const savedSyntaxCursor = syntaxCursor; 1458 const baseSyntaxCursor = IncrementalParser.createSyntaxCursor(sourceFile); 1459 syntaxCursor = { currentNode }; 1460 1461 const statements: Statement[] = []; 1462 const savedParseDiagnostics = parseDiagnostics; 1463 1464 parseDiagnostics = []; 1465 1466 let pos = 0; 1467 let start = findNextStatementWithAwait(sourceFile.statements, 0); 1468 while (start !== -1) { 1469 // append all statements between pos and start 1470 const prevStatement = sourceFile.statements[pos]; 1471 const nextStatement = sourceFile.statements[start]; 1472 addRange(statements, sourceFile.statements, pos, start); 1473 pos = findNextStatementWithoutAwait(sourceFile.statements, start); 1474 1475 // append all diagnostics associated with the copied range 1476 const diagnosticStart = findIndex(savedParseDiagnostics, diagnostic => diagnostic.start >= prevStatement.pos); 1477 const diagnosticEnd = diagnosticStart >= 0 ? findIndex(savedParseDiagnostics, diagnostic => diagnostic.start >= nextStatement.pos, diagnosticStart) : -1; 1478 if (diagnosticStart >= 0) { 1479 addRange(parseDiagnostics, savedParseDiagnostics, diagnosticStart, diagnosticEnd >= 0 ? diagnosticEnd : undefined); 1480 } 1481 1482 // reparse all statements between start and pos. We skip existing diagnostics for the same range and allow the parser to generate new ones. 1483 speculationHelper(() => { 1484 const savedContextFlags = contextFlags; 1485 contextFlags |= NodeFlags.AwaitContext; 1486 scanner.setTextPos(nextStatement.pos); 1487 nextToken(); 1488 1489 while (token() !== SyntaxKind.EndOfFileToken) { 1490 const startPos = scanner.getStartPos(); 1491 const statement = parseListElement(ParsingContext.SourceElements, parseStatement); 1492 statements.push(statement); 1493 if (startPos === scanner.getStartPos()) { 1494 nextToken(); 1495 } 1496 1497 if (pos >= 0) { 1498 const nonAwaitStatement = sourceFile.statements[pos]; 1499 if (statement.end === nonAwaitStatement.pos) { 1500 // done reparsing this section 1501 break; 1502 } 1503 if (statement.end > nonAwaitStatement.pos) { 1504 // we ate into the next statement, so we must reparse it. 1505 pos = findNextStatementWithoutAwait(sourceFile.statements, pos + 1); 1506 } 1507 } 1508 } 1509 1510 contextFlags = savedContextFlags; 1511 }, SpeculationKind.Reparse); 1512 1513 // find the next statement containing an `await` 1514 start = pos >= 0 ? findNextStatementWithAwait(sourceFile.statements, pos) : -1; 1515 } 1516 1517 // append all statements between pos and the end of the list 1518 if (pos >= 0) { 1519 const prevStatement = sourceFile.statements[pos]; 1520 addRange(statements, sourceFile.statements, pos); 1521 1522 // append all diagnostics associated with the copied range 1523 const diagnosticStart = findIndex(savedParseDiagnostics, diagnostic => diagnostic.start >= prevStatement.pos); 1524 if (diagnosticStart >= 0) { 1525 addRange(parseDiagnostics, savedParseDiagnostics, diagnosticStart); 1526 } 1527 } 1528 1529 syntaxCursor = savedSyntaxCursor; 1530 return factory.updateSourceFile(sourceFile, setTextRange(factory.createNodeArray(statements), sourceFile.statements)); 1531 1532 function containsPossibleTopLevelAwait(node: Node) { 1533 return !(node.flags & NodeFlags.AwaitContext) 1534 && !!(node.transformFlags & TransformFlags.ContainsPossibleTopLevelAwait); 1535 } 1536 1537 function findNextStatementWithAwait(statements: NodeArray<Statement>, start: number) { 1538 for (let i = start; i < statements.length; i++) { 1539 if (containsPossibleTopLevelAwait(statements[i])) { 1540 return i; 1541 } 1542 } 1543 return -1; 1544 } 1545 1546 function findNextStatementWithoutAwait(statements: NodeArray<Statement>, start: number) { 1547 for (let i = start; i < statements.length; i++) { 1548 if (!containsPossibleTopLevelAwait(statements[i])) { 1549 return i; 1550 } 1551 } 1552 return -1; 1553 } 1554 1555 function currentNode(position: number) { 1556 const node = baseSyntaxCursor.currentNode(position); 1557 if (topLevel && node && containsPossibleTopLevelAwait(node)) { 1558 node.intersectsChange = true; 1559 } 1560 return node; 1561 } 1562 1563 } 1564 1565 export function fixupParentReferences(rootNode: Node) { 1566 // normally parent references are set during binding. However, for clients that only need 1567 // a syntax tree, and no semantic features, then the binding process is an unnecessary 1568 // overhead. This functions allows us to set all the parents, without all the expense of 1569 // binding. 1570 setParentRecursive(rootNode, /*incremental*/ true); 1571 } 1572 1573 function createSourceFile( 1574 fileName: string, 1575 languageVersion: ScriptTarget, 1576 scriptKind: ScriptKind, 1577 isDeclarationFile: boolean, 1578 statements: readonly Statement[], 1579 endOfFileToken: EndOfFileToken, 1580 flags: NodeFlags, 1581 setExternalModuleIndicator: (sourceFile: SourceFile) => void): SourceFile { 1582 // code from createNode is inlined here so createNode won't have to deal with special case of creating source files 1583 // this is quite rare comparing to other nodes and createNode should be as fast as possible 1584 let sourceFile = factory.createSourceFile(statements, endOfFileToken, flags); 1585 setTextRangePosWidth(sourceFile, 0, sourceText.length); 1586 setFields(sourceFile); 1587 1588 // If we parsed this as an external module, it may contain top-level await 1589 if (!isDeclarationFile && isExternalModule(sourceFile) && sourceFile.transformFlags & TransformFlags.ContainsPossibleTopLevelAwait) { 1590 sourceFile = reparseTopLevelAwait(sourceFile); 1591 setFields(sourceFile); 1592 } 1593 1594 return sourceFile; 1595 1596 function setFields(sourceFile: SourceFile) { 1597 sourceFile.text = sourceText; 1598 sourceFile.bindDiagnostics = []; 1599 sourceFile.bindSuggestionDiagnostics = undefined; 1600 sourceFile.languageVersion = languageVersion; 1601 sourceFile.fileName = fileName; 1602 sourceFile.languageVariant = getLanguageVariant(scriptKind); 1603 sourceFile.isDeclarationFile = isDeclarationFile; 1604 sourceFile.scriptKind = scriptKind; 1605 1606 setExternalModuleIndicator(sourceFile); 1607 sourceFile.setExternalModuleIndicator = setExternalModuleIndicator; 1608 } 1609 } 1610 1611 function setContextFlag(val: boolean, flag: NodeFlags) { 1612 if (val) { 1613 contextFlags |= flag; 1614 } 1615 else { 1616 contextFlags &= ~flag; 1617 } 1618 } 1619 1620 function setEtsFlag(val: boolean, flag: EtsFlags) { 1621 if (val) { 1622 etsFlags |= flag; 1623 } 1624 else { 1625 etsFlags &= ~flag; 1626 } 1627 } 1628 1629 function setDisallowInContext(val: boolean) { 1630 setContextFlag(val, NodeFlags.DisallowInContext); 1631 } 1632 1633 function setYieldContext(val: boolean) { 1634 setContextFlag(val, NodeFlags.YieldContext); 1635 } 1636 1637 function setDecoratorContext(val: boolean) { 1638 setContextFlag(val, NodeFlags.DecoratorContext); 1639 } 1640 1641 function setAwaitContext(val: boolean) { 1642 setContextFlag(val, NodeFlags.AwaitContext); 1643 } 1644 1645 function setStructContext(val: boolean) { 1646 setEtsFlag(val, EtsFlags.StructContext); 1647 } 1648 1649 function setEtsComponentsContext(val: boolean) { 1650 setEtsFlag(val, EtsFlags.EtsComponentsContext); 1651 } 1652 1653 function setEtsNewExpressionContext(val: boolean) { 1654 setEtsFlag(val, EtsFlags.EtsNewExpressionContext); 1655 } 1656 1657 function setEtsExtendComponentsContext(val: boolean) { 1658 setEtsFlag(val, EtsFlags.EtsExtendComponentsContext); 1659 } 1660 1661 function setEtsStylesComponentsContext(val: boolean) { 1662 setEtsFlag(val, EtsFlags.EtsStylesComponentsContext); 1663 } 1664 1665 function setEtsBuildContext(val: boolean) { 1666 setEtsFlag(val, EtsFlags.EtsBuildContext); 1667 } 1668 1669 function setEtsBuilderContext(val: boolean) { 1670 setEtsFlag(val, EtsFlags.EtsBuilderContext); 1671 } 1672 1673 function setEtsStateStylesContext(val: boolean) { 1674 setEtsFlag(val, EtsFlags.EtsStateStylesContext); 1675 } 1676 1677 function setUICallbackContext(val: boolean) { 1678 setEtsFlag(val, EtsFlags.UICallbackContext); 1679 } 1680 1681 function setSyntaxComponentContext(val: boolean) { 1682 setEtsFlag(val, EtsFlags.SyntaxComponentContext); 1683 } 1684 1685 function doOutsideOfContext<T>(context: NodeFlags, func: () => T): T { 1686 // contextFlagsToClear will contain only the context flags that are 1687 // currently set that we need to temporarily clear 1688 // We don't just blindly reset to the previous flags to ensure 1689 // that we do not mutate cached flags for the incremental 1690 // parser (ThisNodeHasError, ThisNodeOrAnySubNodesHasError, and 1691 // HasAggregatedChildData). 1692 const contextFlagsToClear = context & contextFlags; 1693 if (contextFlagsToClear) { 1694 // clear the requested context flags 1695 setContextFlag(/*val*/ false, contextFlagsToClear); 1696 const result = func(); 1697 // restore the context flags we just cleared 1698 setContextFlag(/*val*/ true, contextFlagsToClear); 1699 return result; 1700 } 1701 1702 // no need to do anything special as we are not in any of the requested contexts 1703 return func(); 1704 } 1705 1706 function doInsideOfContext<T>(context: NodeFlags, func: () => T): T { 1707 // contextFlagsToSet will contain only the context flags that 1708 // are not currently set that we need to temporarily enable. 1709 // We don't just blindly reset to the previous flags to ensure 1710 // that we do not mutate cached flags for the incremental 1711 // parser (ThisNodeHasError, ThisNodeOrAnySubNodesHasError, and 1712 // HasAggregatedChildData). 1713 const contextFlagsToSet = context & ~contextFlags; 1714 if (contextFlagsToSet) { 1715 // set the requested context flags 1716 setContextFlag(/*val*/ true, contextFlagsToSet); 1717 const result = func(); 1718 // reset the context flags we just set 1719 setContextFlag(/*val*/ false, contextFlagsToSet); 1720 return result; 1721 } 1722 1723 // no need to do anything special as we are already in all of the requested contexts 1724 return func(); 1725 } 1726 1727 function allowInAnd<T>(func: () => T): T { 1728 return doOutsideOfContext(NodeFlags.DisallowInContext, func); 1729 } 1730 1731 function disallowInAnd<T>(func: () => T): T { 1732 return doInsideOfContext(NodeFlags.DisallowInContext, func); 1733 } 1734 1735 function allowConditionalTypesAnd<T>(func: () => T): T { 1736 return doOutsideOfContext(NodeFlags.DisallowConditionalTypesContext, func); 1737 } 1738 1739 function disallowConditionalTypesAnd<T>(func: () => T): T { 1740 return doInsideOfContext(NodeFlags.DisallowConditionalTypesContext, func); 1741 } 1742 1743 function doInYieldContext<T>(func: () => T): T { 1744 return doInsideOfContext(NodeFlags.YieldContext, func); 1745 } 1746 1747 function doInDecoratorContext<T>(func: () => T): T { 1748 // setting Ets Extend Components 1749 const extendDecorator = sourceFileCompilerOptions.ets?.extend?.decorator ?? "Extend"; 1750 if (token() === SyntaxKind.Identifier && scanner.getTokenText() === extendDecorator) { 1751 setEtsFlag(true, EtsFlags.EtsExtendComponentsContext); 1752 } 1753 // setting Ets Styles Components 1754 const stylesDecorator = sourceFileCompilerOptions.ets?.styles?.decorator ?? "Styles"; 1755 if (token() === SyntaxKind.Identifier && scanner.getTokenText() === stylesDecorator) { 1756 setEtsFlag(true, EtsFlags.EtsStylesComponentsContext); 1757 } 1758 return doInsideOfContext(NodeFlags.DecoratorContext, func); 1759 } 1760 1761 function doInAwaitContext<T>(func: () => T): T { 1762 return doInsideOfContext(NodeFlags.AwaitContext, func); 1763 } 1764 1765 function doOutsideOfAwaitContext<T>(func: () => T): T { 1766 return doOutsideOfContext(NodeFlags.AwaitContext, func); 1767 } 1768 1769 function doInYieldAndAwaitContext<T>(func: () => T): T { 1770 return doInsideOfContext(NodeFlags.YieldContext | NodeFlags.AwaitContext, func); 1771 } 1772 1773 function doOutsideOfYieldAndAwaitContext<T>(func: () => T): T { 1774 return doOutsideOfContext(NodeFlags.YieldContext | NodeFlags.AwaitContext, func); 1775 } 1776 1777 function inContext(flags: NodeFlags) { 1778 return (contextFlags & flags) !== 0; 1779 } 1780 1781 function inEtsFlagsContext(flags: EtsFlags) { 1782 return (etsFlags & flags) !== 0; 1783 } 1784 1785 function inYieldContext() { 1786 return inContext(NodeFlags.YieldContext); 1787 } 1788 1789 function inDisallowInContext() { 1790 return inContext(NodeFlags.DisallowInContext); 1791 } 1792 1793 function inDisallowConditionalTypesContext() { 1794 return inContext(NodeFlags.DisallowConditionalTypesContext); 1795 } 1796 1797 function inDecoratorContext() { 1798 return inContext(NodeFlags.DecoratorContext); 1799 } 1800 1801 function inAwaitContext() { 1802 return inContext(NodeFlags.AwaitContext); 1803 } 1804 1805 function parseErrorAtCurrentToken(message: DiagnosticMessage, arg0?: any): DiagnosticWithDetachedLocation | undefined { 1806 return parseErrorAt(scanner.getTokenPos(), scanner.getTextPos(), message, arg0); 1807 } 1808 1809 function inEtsContext() { 1810 return inContext(NodeFlags.EtsContext); 1811 } 1812 1813 function inStructContext() { 1814 return inEtsContext() && inEtsFlagsContext(EtsFlags.StructContext); 1815 } 1816 1817 function inEtsComponentsContext() { 1818 return inEtsContext() && inEtsFlagsContext(EtsFlags.EtsComponentsContext); 1819 } 1820 1821 function inEtsNewExpressionContext() { 1822 return inEtsContext() && inEtsFlagsContext(EtsFlags.EtsNewExpressionContext); 1823 } 1824 1825 function inEtsExtendComponentsContext() { 1826 return inEtsContext() && inEtsFlagsContext(EtsFlags.EtsExtendComponentsContext); 1827 } 1828 1829 function inEtsStylesComponentsContext() { 1830 return inEtsContext() && inEtsFlagsContext(EtsFlags.EtsStylesComponentsContext); 1831 } 1832 1833 function inBuildContext() { 1834 return inEtsContext() && inStructContext() && inEtsFlagsContext(EtsFlags.EtsBuildContext); 1835 } 1836 1837 function inBuilderContext() { 1838 return inEtsContext() && inEtsFlagsContext(EtsFlags.EtsBuilderContext); 1839 } 1840 1841 function inEtsStateStylesContext() { 1842 return inEtsContext() && (inBuildContext() || inBuilderContext() || inEtsExtendComponentsContext() || inEtsStylesComponentsContext()) && inEtsFlagsContext(EtsFlags.EtsStateStylesContext); 1843 } 1844 1845 function inUICallbackContext() { 1846 return inEtsContext() && (inBuildContext() || inBuilderContext()) && inEtsFlagsContext(EtsFlags.UICallbackContext); 1847 } 1848 1849 function inSyntaxComponentContext() { 1850 return inEtsContext() && (inBuildContext() || inBuilderContext()) && inEtsFlagsContext(EtsFlags.SyntaxComponentContext); 1851 } 1852 1853 function inEtsAnnotationContext() { 1854 return inEtsContext() && sourceFileCompilerOptions?.etsAnnotationsEnable === true; 1855 } 1856 1857 function parseErrorAtPosition(start: number, length: number, message: DiagnosticMessage, arg0?: any): DiagnosticWithDetachedLocation | undefined { 1858 // Don't report another error if it would just be at the same position as the last error. 1859 const lastError = lastOrUndefined(parseDiagnostics); 1860 let result: DiagnosticWithDetachedLocation | undefined; 1861 if (!lastError || start !== lastError.start) { 1862 result = createDetachedDiagnostic(fileName, start, length, message, arg0); 1863 parseDiagnostics.push(result); 1864 } 1865 1866 // Mark that we've encountered an error. We'll set an appropriate bit on the next 1867 // node we finish so that it can't be reused incrementally. 1868 parseErrorBeforeNextFinishedNode = true; 1869 return result; 1870 } 1871 1872 function parseErrorAt(start: number, end: number, message: DiagnosticMessage, arg0?: any): DiagnosticWithDetachedLocation | undefined { 1873 return parseErrorAtPosition(start, end - start, message, arg0); 1874 } 1875 1876 function parseErrorAtRange(range: TextRange, message: DiagnosticMessage, arg0?: any): void { 1877 parseErrorAt(range.pos, range.end, message, arg0); 1878 } 1879 1880 function scanError(message: DiagnosticMessage, length: number): void { 1881 parseErrorAtPosition(scanner.getTextPos(), length, message); 1882 } 1883 1884 function getNodePos(): number { 1885 return scanner.getStartPos(); 1886 } 1887 1888 function hasPrecedingJSDocComment() { 1889 return scanner.hasPrecedingJSDocComment(); 1890 } 1891 1892 // Use this function to access the current token instead of reading the currentToken 1893 // variable. Since function results aren't narrowed in control flow analysis, this ensures 1894 // that the type checker doesn't make wrong assumptions about the type of the current 1895 // token (e.g. a call to nextToken() changes the current token but the checker doesn't 1896 // reason about this side effect). Mainstream VMs inline simple functions like this, so 1897 // there is no performance penalty. 1898 function token(): SyntaxKind { 1899 return currentToken; 1900 } 1901 1902 function nextTokenWithoutCheck() { 1903 return currentToken = scanner.scan(); 1904 } 1905 1906 function nextTokenAnd<T>(func: () => T): T { 1907 nextToken(); 1908 return func(); 1909 } 1910 1911 function nextToken(): SyntaxKind { 1912 // if the keyword had an escape 1913 if (isKeyword(currentToken) && (scanner.hasUnicodeEscape() || scanner.hasExtendedUnicodeEscape())) { 1914 // issue a parse error for the escape 1915 parseErrorAt(scanner.getTokenPos(), scanner.getTextPos(), Diagnostics.Keywords_cannot_contain_escape_characters); 1916 } 1917 return nextTokenWithoutCheck(); 1918 } 1919 1920 function nextTokenJSDoc(): JSDocSyntaxKind { 1921 return currentToken = scanner.scanJsDocToken(); 1922 } 1923 1924 function reScanGreaterToken(): SyntaxKind { 1925 return currentToken = scanner.reScanGreaterToken(); 1926 } 1927 1928 function reScanSlashToken(): SyntaxKind { 1929 return currentToken = scanner.reScanSlashToken(); 1930 } 1931 1932 function reScanTemplateToken(isTaggedTemplate: boolean): SyntaxKind { 1933 return currentToken = scanner.reScanTemplateToken(isTaggedTemplate); 1934 } 1935 1936 function reScanTemplateHeadOrNoSubstitutionTemplate(): SyntaxKind { 1937 return currentToken = scanner.reScanTemplateHeadOrNoSubstitutionTemplate(); 1938 } 1939 1940 function reScanLessThanToken(): SyntaxKind { 1941 return currentToken = scanner.reScanLessThanToken(); 1942 } 1943 1944 function reScanHashToken(): SyntaxKind { 1945 return currentToken = scanner.reScanHashToken(); 1946 } 1947 1948 function scanJsxIdentifier(): SyntaxKind { 1949 return currentToken = scanner.scanJsxIdentifier(); 1950 } 1951 1952 function scanJsxText(): SyntaxKind { 1953 return currentToken = scanner.scanJsxToken(); 1954 } 1955 1956 function scanJsxAttributeValue(): SyntaxKind { 1957 return currentToken = scanner.scanJsxAttributeValue(); 1958 } 1959 1960 function speculationHelper<T>(callback: () => T, speculationKind: SpeculationKind): T { 1961 // Keep track of the state we'll need to rollback to if lookahead fails (or if the 1962 // caller asked us to always reset our state). 1963 const saveToken = currentToken; 1964 const saveParseDiagnosticsLength = parseDiagnostics.length; 1965 const saveParseErrorBeforeNextFinishedNode = parseErrorBeforeNextFinishedNode; 1966 1967 // Note: it is not actually necessary to save/restore the context flags here. That's 1968 // because the saving/restoring of these flags happens naturally through the recursive 1969 // descent nature of our parser. However, we still store this here just so we can 1970 // assert that invariant holds. 1971 const saveContextFlags = contextFlags; 1972 1973 // If we're only looking ahead, then tell the scanner to only lookahead as well. 1974 // Otherwise, if we're actually speculatively parsing, then tell the scanner to do the 1975 // same. 1976 const result = speculationKind !== SpeculationKind.TryParse 1977 ? scanner.lookAhead(callback) 1978 : scanner.tryScan(callback); 1979 1980 Debug.assert(saveContextFlags === contextFlags); 1981 1982 // If our callback returned something 'falsy' or we're just looking ahead, 1983 // then unconditionally restore us to where we were. 1984 if (!result || speculationKind !== SpeculationKind.TryParse) { 1985 currentToken = saveToken; 1986 if (speculationKind !== SpeculationKind.Reparse) { 1987 parseDiagnostics.length = saveParseDiagnosticsLength; 1988 } 1989 parseErrorBeforeNextFinishedNode = saveParseErrorBeforeNextFinishedNode; 1990 } 1991 1992 return result; 1993 } 1994 1995 /** Invokes the provided callback then unconditionally restores the parser to the state it 1996 * was in immediately prior to invoking the callback. The result of invoking the callback 1997 * is returned from this function. 1998 */ 1999 function lookAhead<T>(callback: () => T): T { 2000 return speculationHelper(callback, SpeculationKind.Lookahead); 2001 } 2002 2003 /** Invokes the provided callback. If the callback returns something falsy, then it restores 2004 * the parser to the state it was in immediately prior to invoking the callback. If the 2005 * callback returns something truthy, then the parser state is not rolled back. The result 2006 * of invoking the callback is returned from this function. 2007 */ 2008 function tryParse<T>(callback: () => T): T { 2009 return speculationHelper(callback, SpeculationKind.TryParse); 2010 } 2011 2012 function isBindingIdentifier(): boolean { 2013 if (token() === SyntaxKind.Identifier) { 2014 return true; 2015 } 2016 2017 // `let await`/`let yield` in [Yield] or [Await] are allowed here and disallowed in the binder. 2018 return token() > SyntaxKind.LastReservedWord; 2019 } 2020 2021 // Ignore strict mode flag because we will report an error in type checker instead. 2022 function isIdentifier(): boolean { 2023 if (token() === SyntaxKind.Identifier) { 2024 return true; 2025 } 2026 2027 // If we have a 'yield' keyword, and we're in the [yield] context, then 'yield' is 2028 // considered a keyword and is not an identifier. 2029 if (token() === SyntaxKind.YieldKeyword && inYieldContext()) { 2030 return false; 2031 } 2032 2033 // If we have a 'await' keyword, and we're in the [Await] context, then 'await' is 2034 // considered a keyword and is not an identifier. 2035 if (token() === SyntaxKind.AwaitKeyword && inAwaitContext()) { 2036 return false; 2037 } 2038 2039 return token() > SyntaxKind.LastReservedWord; 2040 } 2041 2042 function parseExpected(kind: SyntaxKind, diagnosticMessage?: DiagnosticMessage, shouldAdvance = true): boolean { 2043 if (token() === kind) { 2044 if (shouldAdvance) { 2045 nextToken(); 2046 } 2047 return true; 2048 } 2049 2050 if (token() !== kind && stateStylesRootNode && inEtsStateStylesContext()) { 2051 return true; 2052 } 2053 2054 // Report specific message if provided with one. Otherwise, report generic fallback message. 2055 if (diagnosticMessage) { 2056 parseErrorAtCurrentToken(diagnosticMessage); 2057 } 2058 else { 2059 parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(kind)); 2060 } 2061 return false; 2062 } 2063 2064 const viableKeywordSuggestions = Object.keys(textToKeywordObj).filter(keyword => keyword.length > 2); 2065 2066 /** 2067 * Provides a better error message than the generic "';' expected" if possible for 2068 * known common variants of a missing semicolon, such as from a mispelled names. 2069 * 2070 * @param node Node preceding the expected semicolon location. 2071 */ 2072 function parseErrorForMissingSemicolonAfter(node: Expression | PropertyName): void { 2073 // Tagged template literals are sometimes used in places where only simple strings are allowed, i.e.: 2074 // module `M1` { 2075 // ^^^^^^^^^^^ This block is parsed as a template literal like module`M1`. 2076 if (isTaggedTemplateExpression(node)) { 2077 parseErrorAt(skipTrivia(sourceText, node.template.pos), node.template.end, Diagnostics.Module_declaration_names_may_only_use_or_quoted_strings); 2078 return; 2079 } 2080 2081 // Otherwise, if this isn't a well-known keyword-like identifier, give the generic fallback message. 2082 const expressionText = ts.isIdentifier(node) ? idText(node) : undefined; 2083 if (!expressionText || !isIdentifierText(expressionText, languageVersion)) { 2084 parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.SemicolonToken)); 2085 return; 2086 } 2087 2088 const pos = skipTrivia(sourceText, node.pos); 2089 2090 // Some known keywords are likely signs of syntax being used improperly. 2091 switch (expressionText) { 2092 case "const": 2093 case "let": 2094 case "var": 2095 parseErrorAt(pos, node.end, Diagnostics.Variable_declaration_not_allowed_at_this_location); 2096 return; 2097 2098 case "declare": 2099 // If a declared node failed to parse, it would have emitted a diagnostic already. 2100 return; 2101 2102 case "interface": 2103 parseErrorForInvalidName(Diagnostics.Interface_name_cannot_be_0, Diagnostics.Interface_must_be_given_a_name, SyntaxKind.OpenBraceToken); 2104 return; 2105 2106 case "is": 2107 parseErrorAt(pos, scanner.getTextPos(), Diagnostics.A_type_predicate_is_only_allowed_in_return_type_position_for_functions_and_methods); 2108 return; 2109 2110 case "module": 2111 case "namespace": 2112 parseErrorForInvalidName(Diagnostics.Namespace_name_cannot_be_0, Diagnostics.Namespace_must_be_given_a_name, SyntaxKind.OpenBraceToken); 2113 return; 2114 2115 case "type": 2116 parseErrorForInvalidName(Diagnostics.Type_alias_name_cannot_be_0, Diagnostics.Type_alias_must_be_given_a_name, SyntaxKind.EqualsToken); 2117 return; 2118 } 2119 2120 // The user alternatively might have misspelled or forgotten to add a space after a common keyword. 2121 const suggestion = getSpellingSuggestion(expressionText, viableKeywordSuggestions, n => n) ?? getSpaceSuggestion(expressionText); 2122 if (suggestion) { 2123 parseErrorAt(pos, node.end, Diagnostics.Unknown_keyword_or_identifier_Did_you_mean_0, suggestion); 2124 return; 2125 } 2126 2127 // Unknown tokens are handled with their own errors in the scanner 2128 if (token() === SyntaxKind.Unknown) { 2129 return; 2130 } 2131 2132 // Otherwise, we know this some kind of unknown word, not just a missing expected semicolon. 2133 parseErrorAt(pos, node.end, Diagnostics.Unexpected_keyword_or_identifier); 2134 } 2135 2136 /** 2137 * Reports a diagnostic error for the current token being an invalid name. 2138 * 2139 * @param blankDiagnostic Diagnostic to report for the case of the name being blank (matched tokenIfBlankName). 2140 * @param nameDiagnostic Diagnostic to report for all other cases. 2141 * @param tokenIfBlankName Current token if the name was invalid for being blank (not provided / skipped). 2142 */ 2143 function parseErrorForInvalidName(nameDiagnostic: DiagnosticMessage, blankDiagnostic: DiagnosticMessage, tokenIfBlankName: SyntaxKind) { 2144 if (token() === tokenIfBlankName) { 2145 parseErrorAtCurrentToken(blankDiagnostic); 2146 } 2147 else { 2148 parseErrorAtCurrentToken(nameDiagnostic, scanner.getTokenValue()); 2149 } 2150 } 2151 2152 function getSpaceSuggestion(expressionText: string) { 2153 for (const keyword of viableKeywordSuggestions) { 2154 if (expressionText.length > keyword.length + 2 && startsWith(expressionText, keyword)) { 2155 return `${keyword} ${expressionText.slice(keyword.length)}`; 2156 } 2157 } 2158 2159 return undefined; 2160 } 2161 2162 function parseSemicolonAfterPropertyName(name: PropertyName, type: TypeNode | undefined, initializer: Expression | undefined) { 2163 if (token() === SyntaxKind.AtToken && !scanner.hasPrecedingLineBreak()) { 2164 parseErrorAtCurrentToken(Diagnostics.Decorators_must_precede_the_name_and_all_keywords_of_property_declarations); 2165 return; 2166 } 2167 2168 if (token() === SyntaxKind.OpenParenToken) { 2169 parseErrorAtCurrentToken(Diagnostics.Cannot_start_a_function_call_in_a_type_annotation); 2170 nextToken(); 2171 return; 2172 } 2173 2174 if (type && !canParseSemicolon()) { 2175 if (initializer) { 2176 parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.SemicolonToken)); 2177 } 2178 else { 2179 parseErrorAtCurrentToken(Diagnostics.Expected_for_property_initializer); 2180 } 2181 return; 2182 } 2183 2184 if (tryParseSemicolon()) { 2185 return; 2186 } 2187 2188 if (initializer) { 2189 parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.SemicolonToken)); 2190 return; 2191 } 2192 2193 parseErrorForMissingSemicolonAfter(name); 2194 } 2195 2196 function parseExpectedJSDoc(kind: JSDocSyntaxKind) { 2197 if (token() === kind) { 2198 nextTokenJSDoc(); 2199 return true; 2200 } 2201 parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(kind)); 2202 return false; 2203 } 2204 2205 function parseExpectedMatchingBrackets(openKind: SyntaxKind, closeKind: SyntaxKind, openParsed: boolean, openPosition: number) { 2206 if (token() === closeKind) { 2207 nextToken(); 2208 return; 2209 } 2210 const lastError = parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(closeKind)); 2211 if (!openParsed) { 2212 return; 2213 } 2214 if (lastError) { 2215 addRelatedInfo( 2216 lastError, 2217 createDetachedDiagnostic(fileName, openPosition, 1, Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, tokenToString(openKind), tokenToString(closeKind)) 2218 ); 2219 } 2220 } 2221 2222 function parseOptional(t: SyntaxKind): boolean { 2223 if (token() === t) { 2224 nextToken(); 2225 return true; 2226 } 2227 return false; 2228 } 2229 2230 function parseOptionalToken<TKind extends SyntaxKind>(t: TKind): Token<TKind>; 2231 function parseOptionalToken(t: SyntaxKind): Node | undefined { 2232 if (token() === t) { 2233 return parseTokenNode(); 2234 } 2235 return undefined; 2236 } 2237 2238 function parseOptionalTokenJSDoc<TKind extends JSDocSyntaxKind>(t: TKind): Token<TKind>; 2239 function parseOptionalTokenJSDoc(t: JSDocSyntaxKind): Node | undefined { 2240 if (token() === t) { 2241 return parseTokenNodeJSDoc(); 2242 } 2243 return undefined; 2244 } 2245 2246 function parseExpectedToken<TKind extends SyntaxKind>(t: TKind, diagnosticMessage?: DiagnosticMessage, arg0?: any): Token<TKind>; 2247 function parseExpectedToken(t: SyntaxKind, diagnosticMessage?: DiagnosticMessage, arg0?: any): Node { 2248 return parseOptionalToken(t) || 2249 createMissingNode(t, /*reportAtCurrentPosition*/ false, diagnosticMessage || Diagnostics._0_expected, arg0 || tokenToString(t)); 2250 } 2251 2252 function parseExpectedTokenJSDoc<TKind extends JSDocSyntaxKind>(t: TKind): Token<TKind>; 2253 function parseExpectedTokenJSDoc(t: JSDocSyntaxKind): Node { 2254 return parseOptionalTokenJSDoc(t) || 2255 createMissingNode(t, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, tokenToString(t)); 2256 } 2257 2258 function parseTokenNode<T extends Node>(): T { 2259 const pos = getNodePos(); 2260 const kind = token(); 2261 nextToken(); 2262 return finishNode(factory.createToken(kind), pos) as T; 2263 } 2264 2265 function parseTokenNodeJSDoc<T extends Node>(): T { 2266 const pos = getNodePos(); 2267 const kind = token(); 2268 nextTokenJSDoc(); 2269 return finishNode(factory.createToken(kind), pos) as T; 2270 } 2271 2272 function canParseSemicolon() { 2273 // If there's a real semicolon, then we can always parse it out. 2274 if (token() === SyntaxKind.SemicolonToken) { 2275 return true; 2276 } 2277 2278 // We can parse out an optional semicolon in ASI cases in the following cases. 2279 return token() === SyntaxKind.CloseBraceToken || token() === SyntaxKind.EndOfFileToken || scanner.hasPrecedingLineBreak(); 2280 } 2281 2282 function tryParseSemicolon() { 2283 if (!canParseSemicolon()) { 2284 return false; 2285 } 2286 2287 if (token() === SyntaxKind.SemicolonToken) { 2288 // consume the semicolon if it was explicitly provided. 2289 nextToken(); 2290 } 2291 2292 return true; 2293 } 2294 2295 function parseSemicolon(): boolean { 2296 return tryParseSemicolon() || parseExpected(SyntaxKind.SemicolonToken); 2297 } 2298 2299 function createNodeArray<T extends Node>(elements: T[], pos: number, end?: number, hasTrailingComma?: boolean): NodeArray<T> { 2300 const array = factory.createNodeArray(elements, hasTrailingComma); 2301 setTextRangePosEnd(array, pos, end ?? scanner.getStartPos()); 2302 return array; 2303 } 2304 2305 function finishNode<T extends Node>(node: T, pos: number, end?: number, virtual?: boolean): T { 2306 setTextRangePosEnd(node, pos, end ?? scanner.getStartPos()); 2307 if (contextFlags) { 2308 (node as Mutable<T>).flags |= contextFlags; 2309 } 2310 2311 // Keep track on the node if we encountered an error while parsing it. If we did, then 2312 // we cannot reuse the node incrementally. Once we've marked this node, clear out the 2313 // flag so that we don't mark any subsequent nodes. 2314 if (parseErrorBeforeNextFinishedNode) { 2315 parseErrorBeforeNextFinishedNode = false; 2316 (node as Mutable<T>).flags |= NodeFlags.ThisNodeHasError; 2317 } 2318 2319 if (virtual) { 2320 node.virtual = true; 2321 } 2322 2323 return node; 2324 } 2325 2326 function createMissingNode<T extends Node>(kind: T["kind"], reportAtCurrentPosition: false, diagnosticMessage?: DiagnosticMessage, arg0?: any): T; 2327 function createMissingNode<T extends Node>(kind: T["kind"], reportAtCurrentPosition: boolean, diagnosticMessage: DiagnosticMessage, arg0?: any): T; 2328 function createMissingNode<T extends Node>(kind: T["kind"], reportAtCurrentPosition: boolean, diagnosticMessage: DiagnosticMessage, arg0?: any): T { 2329 if (reportAtCurrentPosition) { 2330 parseErrorAtPosition(scanner.getStartPos(), 0, diagnosticMessage, arg0); 2331 } 2332 else if (diagnosticMessage) { 2333 parseErrorAtCurrentToken(diagnosticMessage, arg0); 2334 } 2335 2336 const pos = getNodePos(); 2337 const result = 2338 kind === SyntaxKind.Identifier ? factory.createIdentifier("", /*typeArguments*/ undefined, /*originalKeywordKind*/ undefined) : 2339 isTemplateLiteralKind(kind) ? factory.createTemplateLiteralLikeNode(kind, "", "", /*templateFlags*/ undefined) : 2340 kind === SyntaxKind.NumericLiteral ? factory.createNumericLiteral("", /*numericLiteralFlags*/ undefined) : 2341 kind === SyntaxKind.StringLiteral ? factory.createStringLiteral("", /*isSingleQuote*/ undefined) : 2342 kind === SyntaxKind.MissingDeclaration ? factory.createMissingDeclaration() : 2343 factory.createToken(kind); 2344 return finishNode(result, pos) as T; 2345 } 2346 2347 function internIdentifier(text: string): string { 2348 let identifier = identifiers.get(text); 2349 if (identifier === undefined) { 2350 identifiers.set(text, identifier = text); 2351 } 2352 return identifier; 2353 } 2354 2355 // An identifier that starts with two underscores has an extra underscore character prepended to it to avoid issues 2356 // with magic property names like '__proto__'. The 'identifiers' object is used to share a single string instance for 2357 // each identifier in order to reduce memory consumption. 2358 function createIdentifier(isIdentifier: boolean, diagnosticMessage?: DiagnosticMessage, privateIdentifierDiagnosticMessage?: DiagnosticMessage): Identifier { 2359 if (isIdentifier) { 2360 identifierCount++; 2361 const pos = getNodePos(); 2362 // Store original token kind if it is not just an Identifier so we can report appropriate error later in type checker 2363 const originalKeywordKind = token(); 2364 const text = internIdentifier(scanner.getTokenValue()); 2365 const hasExtendedUnicodeEscape = scanner.hasExtendedUnicodeEscape(); 2366 nextTokenWithoutCheck(); 2367 return finishNode(factory.createIdentifier(text, /*typeArguments*/ undefined, originalKeywordKind, hasExtendedUnicodeEscape), pos); 2368 } 2369 2370 if (token() === SyntaxKind.PrivateIdentifier) { 2371 parseErrorAtCurrentToken(privateIdentifierDiagnosticMessage || Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies); 2372 return createIdentifier(/*isIdentifier*/ true); 2373 } 2374 2375 if (token() === SyntaxKind.Unknown && scanner.tryScan(() => scanner.reScanInvalidIdentifier() === SyntaxKind.Identifier)) { 2376 // Scanner has already recorded an 'Invalid character' error, so no need to add another from the parser. 2377 return createIdentifier(/*isIdentifier*/ true); 2378 } 2379 2380 if (stateStylesRootNode && inEtsStateStylesContext() && token() === SyntaxKind.DotToken) { 2381 identifierCount++; 2382 const pos = getNodePos(); 2383 return finishVirtualNode( 2384 factory.createIdentifier(`${stateStylesRootNode}Instance`, /*typeArguments*/ undefined, SyntaxKind.Identifier), 2385 pos, 2386 pos 2387 ); 2388 } 2389 2390 identifierCount++; 2391 // Only for end of file because the error gets reported incorrectly on embedded script tags. 2392 const reportAtCurrentPosition = token() === SyntaxKind.EndOfFileToken; 2393 2394 const isReservedWord = scanner.isReservedWord(); 2395 const msgArg = scanner.getTokenText(); 2396 2397 const defaultMessage = isReservedWord ? 2398 Diagnostics.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here : 2399 Diagnostics.Identifier_expected; 2400 2401 return createMissingNode<Identifier>(SyntaxKind.Identifier, reportAtCurrentPosition, diagnosticMessage || defaultMessage, msgArg); 2402 } 2403 2404 function parseBindingIdentifier(privateIdentifierDiagnosticMessage?: DiagnosticMessage) { 2405 return createIdentifier(isBindingIdentifier(), /*diagnosticMessage*/ undefined, privateIdentifierDiagnosticMessage); 2406 } 2407 2408 function parseIdentifier(diagnosticMessage?: DiagnosticMessage, privateIdentifierDiagnosticMessage?: DiagnosticMessage): Identifier { 2409 return createIdentifier(isIdentifier(), diagnosticMessage, privateIdentifierDiagnosticMessage); 2410 } 2411 2412 function parseEtsIdentifier(pos: number): Identifier { 2413 identifierCount++; 2414 const text = internIdentifier(stylesEtsComponentDeclaration!.type); 2415 return finishVirtualNode(factory.createIdentifier(text), pos, pos); 2416 } 2417 2418 function parseIdentifierName(diagnosticMessage?: DiagnosticMessage): Identifier { 2419 return createIdentifier(tokenIsIdentifierOrKeyword(token()), diagnosticMessage); 2420 } 2421 2422 function isLiteralPropertyName(): boolean { 2423 return tokenIsIdentifierOrKeyword(token()) || 2424 token() === SyntaxKind.StringLiteral || 2425 token() === SyntaxKind.NumericLiteral; 2426 } 2427 2428 function isAssertionKey(): boolean { 2429 return tokenIsIdentifierOrKeyword(token()) || 2430 token() === SyntaxKind.StringLiteral; 2431 } 2432 2433 function parsePropertyNameWorker(allowComputedPropertyNames: boolean): PropertyName { 2434 if (token() === SyntaxKind.StringLiteral || token() === SyntaxKind.NumericLiteral) { 2435 const node = parseLiteralNode() as StringLiteral | NumericLiteral; 2436 node.text = internIdentifier(node.text); 2437 return node; 2438 } 2439 if (allowComputedPropertyNames && token() === SyntaxKind.OpenBracketToken) { 2440 return parseComputedPropertyName(); 2441 } 2442 if (token() === SyntaxKind.PrivateIdentifier) { 2443 return parsePrivateIdentifier(); 2444 } 2445 return parseIdentifierName(); 2446 } 2447 2448 function parsePropertyName(): PropertyName { 2449 return parsePropertyNameWorker(/*allowComputedPropertyNames*/ true); 2450 } 2451 2452 function parseComputedPropertyName(): ComputedPropertyName { 2453 // PropertyName [Yield]: 2454 // LiteralPropertyName 2455 // ComputedPropertyName[?Yield] 2456 const pos = getNodePos(); 2457 parseExpected(SyntaxKind.OpenBracketToken); 2458 // We parse any expression (including a comma expression). But the grammar 2459 // says that only an assignment expression is allowed, so the grammar checker 2460 // will error if it sees a comma expression. 2461 const expression = allowInAnd(parseExpression); 2462 parseExpected(SyntaxKind.CloseBracketToken); 2463 return finishNode(factory.createComputedPropertyName(expression), pos); 2464 } 2465 2466 function internPrivateIdentifier(text: string): string { 2467 let privateIdentifier = privateIdentifiers.get(text); 2468 if (privateIdentifier === undefined) { 2469 privateIdentifiers.set(text, privateIdentifier = text); 2470 } 2471 return privateIdentifier; 2472 } 2473 2474 function parsePrivateIdentifier(): PrivateIdentifier { 2475 const pos = getNodePos(); 2476 const node = factory.createPrivateIdentifier(internPrivateIdentifier(scanner.getTokenValue())); 2477 nextToken(); 2478 return finishNode(node, pos); 2479 } 2480 2481 function parseContextualModifier(t: SyntaxKind): boolean { 2482 return token() === t && tryParse(nextTokenCanFollowModifier); 2483 } 2484 2485 function nextTokenIsOnSameLineAndCanFollowModifier() { 2486 nextToken(); 2487 if (scanner.hasPrecedingLineBreak()) { 2488 return false; 2489 } 2490 return canFollowModifier(); 2491 } 2492 2493 function nextTokenCanFollowModifier() { 2494 switch (token()) { 2495 case SyntaxKind.ConstKeyword: 2496 // 'const' is only a modifier if followed by 'enum'. 2497 return nextToken() === SyntaxKind.EnumKeyword; 2498 case SyntaxKind.ExportKeyword: 2499 nextToken(); 2500 if (token() === SyntaxKind.DefaultKeyword) { 2501 return lookAhead(nextTokenCanFollowDefaultKeyword); 2502 } 2503 if (token() === SyntaxKind.TypeKeyword) { 2504 return lookAhead(nextTokenCanFollowExportModifier); 2505 } 2506 if (inEtsAnnotationContext() && token() === SyntaxKind.AtToken) { 2507 return lookAhead(() => nextToken() === SyntaxKind.InterfaceKeyword); 2508 } 2509 return canFollowExportModifier(); 2510 case SyntaxKind.DefaultKeyword: 2511 return nextTokenCanFollowDefaultKeyword(); 2512 case SyntaxKind.AccessorKeyword: 2513 case SyntaxKind.StaticKeyword: 2514 case SyntaxKind.GetKeyword: 2515 case SyntaxKind.SetKeyword: 2516 nextToken(); 2517 return canFollowModifier(); 2518 default: 2519 return nextTokenIsOnSameLineAndCanFollowModifier(); 2520 } 2521 } 2522 2523 function canFollowExportModifier(): boolean { 2524 return token() !== SyntaxKind.AsteriskToken 2525 && token() !== SyntaxKind.AsKeyword 2526 && token() !== SyntaxKind.OpenBraceToken 2527 && canFollowModifier(); 2528 } 2529 2530 function nextTokenCanFollowExportModifier(): boolean { 2531 nextToken(); 2532 return canFollowExportModifier(); 2533 } 2534 2535 function parseAnyContextualModifier(): boolean { 2536 return isModifierKind(token()) && tryParse(nextTokenCanFollowModifier); 2537 } 2538 2539 function canFollowModifier(): boolean { 2540 return token() === SyntaxKind.OpenBracketToken 2541 || token() === SyntaxKind.OpenBraceToken 2542 || token() === SyntaxKind.AsteriskToken 2543 || token() === SyntaxKind.DotDotDotToken 2544 || token() === SyntaxKind.AtToken && inEtsAnnotationContext() && lookAhead(() => nextToken() === SyntaxKind.InterfaceKeyword) 2545 || isLiteralPropertyName(); 2546 } 2547 2548 function nextTokenCanFollowDefaultKeyword(): boolean { 2549 nextToken(); 2550 return token() === SyntaxKind.ClassKeyword || (inEtsContext() && token() === SyntaxKind.StructKeyword) || 2551 token() === SyntaxKind.FunctionKeyword || token() === SyntaxKind.InterfaceKeyword || 2552 (token() === SyntaxKind.AbstractKeyword && lookAhead(nextTokenIsClassKeywordOnSameLine)) || 2553 (token() === SyntaxKind.AsyncKeyword && lookAhead(nextTokenIsFunctionKeywordOnSameLine)); 2554 } 2555 2556 // True if positioned at the start of a list element 2557 function isListElement(parsingContext: ParsingContext, inErrorRecovery: boolean): boolean { 2558 const node = currentNode(parsingContext); 2559 if (node) { 2560 return true; 2561 } 2562 2563 switch (parsingContext) { 2564 case ParsingContext.SourceElements: 2565 case ParsingContext.BlockStatements: 2566 case ParsingContext.SwitchClauseStatements: 2567 // If we're in error recovery, then we don't want to treat ';' as an empty statement. 2568 // The problem is that ';' can show up in far too many contexts, and if we see one 2569 // and assume it's a statement, then we may bail out inappropriately from whatever 2570 // we're parsing. For example, if we have a semicolon in the middle of a class, then 2571 // we really don't want to assume the class is over and we're on a statement in the 2572 // outer module. We just want to consume and move on. 2573 return !(token() === SyntaxKind.SemicolonToken && inErrorRecovery) && isStartOfStatement(); 2574 case ParsingContext.SwitchClauses: 2575 return token() === SyntaxKind.CaseKeyword || token() === SyntaxKind.DefaultKeyword; 2576 case ParsingContext.TypeMembers: 2577 return lookAhead(isTypeMemberStart); 2578 case ParsingContext.ClassMembers: 2579 // We allow semicolons as class elements (as specified by ES6) as long as we're 2580 // not in error recovery. If we're in error recovery, we don't want an errant 2581 // semicolon to be treated as a class member (since they're almost always used 2582 // for statements. 2583 return lookAhead(isClassMemberStart) || (token() === SyntaxKind.SemicolonToken && !inErrorRecovery); 2584 case ParsingContext.AnnotationMembers: 2585 return lookAhead(isAnnotationMemberStart); 2586 case ParsingContext.EnumMembers: 2587 // Include open bracket computed properties. This technically also lets in indexers, 2588 // which would be a candidate for improved error reporting. 2589 return token() === SyntaxKind.OpenBracketToken || isLiteralPropertyName(); 2590 case ParsingContext.ObjectLiteralMembers: 2591 switch (token()) { 2592 case SyntaxKind.OpenBracketToken: 2593 case SyntaxKind.AsteriskToken: 2594 case SyntaxKind.DotDotDotToken: 2595 case SyntaxKind.DotToken: // Not an object literal member, but don't want to close the object (see `tests/cases/fourslash/completionsDotInObjectLiteral.ts`) 2596 return true; 2597 default: 2598 return isLiteralPropertyName(); 2599 } 2600 case ParsingContext.RestProperties: 2601 return isLiteralPropertyName(); 2602 case ParsingContext.ObjectBindingElements: 2603 return token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.DotDotDotToken || isLiteralPropertyName(); 2604 case ParsingContext.AssertEntries: 2605 return isAssertionKey(); 2606 case ParsingContext.HeritageClauseElement: 2607 // If we see `{ ... }` then only consume it as an expression if it is followed by `,` or `{` 2608 // That way we won't consume the body of a class in its heritage clause. 2609 if (token() === SyntaxKind.OpenBraceToken) { 2610 return lookAhead(isValidHeritageClauseObjectLiteral); 2611 } 2612 2613 if (!inErrorRecovery) { 2614 return isStartOfLeftHandSideExpression() && !isHeritageClauseExtendsOrImplementsKeyword(); 2615 } 2616 else { 2617 // If we're in error recovery we tighten up what we're willing to match. 2618 // That way we don't treat something like "this" as a valid heritage clause 2619 // element during recovery. 2620 return isIdentifier() && !isHeritageClauseExtendsOrImplementsKeyword(); 2621 } 2622 case ParsingContext.VariableDeclarations: 2623 return isBindingIdentifierOrPrivateIdentifierOrPattern(); 2624 case ParsingContext.ArrayBindingElements: 2625 return token() === SyntaxKind.CommaToken || token() === SyntaxKind.DotDotDotToken || isBindingIdentifierOrPrivateIdentifierOrPattern(); 2626 case ParsingContext.TypeParameters: 2627 return token() === SyntaxKind.InKeyword || isIdentifier(); 2628 case ParsingContext.ArrayLiteralMembers: 2629 switch (token()) { 2630 case SyntaxKind.CommaToken: 2631 case SyntaxKind.DotToken: // Not an array literal member, but don't want to close the array (see `tests/cases/fourslash/completionsDotInArrayLiteralInObjectLiteral.ts`) 2632 return true; 2633 } 2634 // falls through 2635 case ParsingContext.ArgumentExpressions: 2636 return token() === SyntaxKind.DotDotDotToken || isStartOfExpression(); 2637 case ParsingContext.Parameters: 2638 return isStartOfParameter(/*isJSDocParameter*/ false); 2639 case ParsingContext.JSDocParameters: 2640 return isStartOfParameter(/*isJSDocParameter*/ true); 2641 case ParsingContext.TypeArguments: 2642 case ParsingContext.TupleElementTypes: 2643 return token() === SyntaxKind.CommaToken || isStartOfType(); 2644 case ParsingContext.HeritageClauses: 2645 return isHeritageClause(); 2646 case ParsingContext.ImportOrExportSpecifiers: 2647 return tokenIsIdentifierOrKeyword(token()); 2648 case ParsingContext.JsxAttributes: 2649 return tokenIsIdentifierOrKeyword(token()) || token() === SyntaxKind.OpenBraceToken; 2650 case ParsingContext.JsxChildren: 2651 return true; 2652 } 2653 2654 return Debug.fail("Non-exhaustive case in 'isListElement'."); 2655 } 2656 2657 function isValidHeritageClauseObjectLiteral() { 2658 Debug.assert(token() === SyntaxKind.OpenBraceToken); 2659 if (nextToken() === SyntaxKind.CloseBraceToken) { 2660 // if we see "extends {}" then only treat the {} as what we're extending (and not 2661 // the class body) if we have: 2662 // 2663 // extends {} { 2664 // extends {}, 2665 // extends {} extends 2666 // extends {} implements 2667 2668 const next = nextToken(); 2669 return next === SyntaxKind.CommaToken || next === SyntaxKind.OpenBraceToken || next === SyntaxKind.ExtendsKeyword || next === SyntaxKind.ImplementsKeyword; 2670 } 2671 2672 return true; 2673 } 2674 2675 function nextTokenIsIdentifier() { 2676 nextToken(); 2677 return isIdentifier(); 2678 } 2679 2680 function nextTokenIsIdentifierOrKeyword() { 2681 nextToken(); 2682 return tokenIsIdentifierOrKeyword(token()); 2683 } 2684 2685 function nextTokenIsIdentifierOrKeywordOrGreaterThan() { 2686 nextToken(); 2687 return tokenIsIdentifierOrKeywordOrGreaterThan(token()); 2688 } 2689 2690 function isHeritageClauseExtendsOrImplementsKeyword(): boolean { 2691 if (token() === SyntaxKind.ImplementsKeyword || 2692 token() === SyntaxKind.ExtendsKeyword) { 2693 2694 return lookAhead(nextTokenIsStartOfExpression); 2695 } 2696 2697 return false; 2698 } 2699 2700 function nextTokenIsStartOfExpression() { 2701 nextToken(); 2702 return isStartOfExpression(); 2703 } 2704 2705 function nextTokenIsStartOfType() { 2706 nextToken(); 2707 return isStartOfType(); 2708 } 2709 2710 // True if positioned at a list terminator 2711 function isListTerminator(kind: ParsingContext): boolean { 2712 if (token() === SyntaxKind.EndOfFileToken) { 2713 // Being at the end of the file ends all lists. 2714 return true; 2715 } 2716 2717 switch (kind) { 2718 case ParsingContext.BlockStatements: 2719 case ParsingContext.SwitchClauses: 2720 case ParsingContext.TypeMembers: 2721 case ParsingContext.ClassMembers: 2722 case ParsingContext.AnnotationMembers: 2723 case ParsingContext.EnumMembers: 2724 case ParsingContext.ObjectLiteralMembers: 2725 case ParsingContext.ObjectBindingElements: 2726 case ParsingContext.ImportOrExportSpecifiers: 2727 case ParsingContext.AssertEntries: 2728 return token() === SyntaxKind.CloseBraceToken; 2729 case ParsingContext.SwitchClauseStatements: 2730 return token() === SyntaxKind.CloseBraceToken || token() === SyntaxKind.CaseKeyword || token() === SyntaxKind.DefaultKeyword; 2731 case ParsingContext.HeritageClauseElement: 2732 return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword; 2733 case ParsingContext.VariableDeclarations: 2734 return isVariableDeclaratorListTerminator(); 2735 case ParsingContext.TypeParameters: 2736 // Tokens other than '>' are here for better error recovery 2737 return token() === SyntaxKind.GreaterThanToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword; 2738 case ParsingContext.ArgumentExpressions: 2739 // Tokens other than ')' are here for better error recovery 2740 return token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.SemicolonToken; 2741 case ParsingContext.ArrayLiteralMembers: 2742 case ParsingContext.TupleElementTypes: 2743 case ParsingContext.ArrayBindingElements: 2744 return token() === SyntaxKind.CloseBracketToken; 2745 case ParsingContext.JSDocParameters: 2746 case ParsingContext.Parameters: 2747 case ParsingContext.RestProperties: 2748 // Tokens other than ')' and ']' (the latter for index signatures) are here for better error recovery 2749 return token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.CloseBracketToken /*|| token === SyntaxKind.OpenBraceToken*/; 2750 case ParsingContext.TypeArguments: 2751 // All other tokens should cause the type-argument to terminate except comma token 2752 return token() !== SyntaxKind.CommaToken; 2753 case ParsingContext.HeritageClauses: 2754 return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.CloseBraceToken; 2755 case ParsingContext.JsxAttributes: 2756 return token() === SyntaxKind.GreaterThanToken || token() === SyntaxKind.SlashToken; 2757 case ParsingContext.JsxChildren: 2758 return token() === SyntaxKind.LessThanToken && lookAhead(nextTokenIsSlash); 2759 default: 2760 return false; 2761 } 2762 } 2763 2764 function isVariableDeclaratorListTerminator(): boolean { 2765 // If we can consume a semicolon (either explicitly, or with ASI), then consider us done 2766 // with parsing the list of variable declarators. 2767 if (canParseSemicolon()) { 2768 return true; 2769 } 2770 2771 // in the case where we're parsing the variable declarator of a 'for-in' statement, we 2772 // are done if we see an 'in' keyword in front of us. Same with for-of 2773 if (isInOrOfKeyword(token())) { 2774 return true; 2775 } 2776 2777 // ERROR RECOVERY TWEAK: 2778 // For better error recovery, if we see an '=>' then we just stop immediately. We've got an 2779 // arrow function here and it's going to be very unlikely that we'll resynchronize and get 2780 // another variable declaration. 2781 if (token() === SyntaxKind.EqualsGreaterThanToken) { 2782 return true; 2783 } 2784 2785 // Keep trying to parse out variable declarators. 2786 return false; 2787 } 2788 2789 // True if positioned at element or terminator of the current list or any enclosing list 2790 function isInSomeParsingContext(): boolean { 2791 for (let kind = 0; kind < ParsingContext.Count; kind++) { 2792 if (parsingContext & (1 << kind)) { 2793 if (isListElement(kind, /*inErrorRecovery*/ true) || isListTerminator(kind)) { 2794 return true; 2795 } 2796 } 2797 } 2798 2799 return false; 2800 } 2801 2802 // Parses a list of elements 2803 function parseList<T extends Node>(kind: ParsingContext, parseElement: () => T): NodeArray<T> { 2804 const saveParsingContext = parsingContext; 2805 parsingContext |= 1 << kind; 2806 const list = []; 2807 const listPos = getNodePos(); 2808 2809 while (!isListTerminator(kind)) { 2810 if (isListElement(kind, /*inErrorRecovery*/ false)) { 2811 list.push(parseListElement(kind, parseElement)); 2812 continue; 2813 } 2814 2815 if (abortParsingListOrMoveToNextToken(kind)) { 2816 break; 2817 } 2818 } 2819 2820 parsingContext = saveParsingContext; 2821 return createNodeArray(list, listPos); 2822 } 2823 2824 function parseListElement<T extends Node | undefined>(parsingContext: ParsingContext, parseElement: () => T): T { 2825 const node = currentNode(parsingContext); 2826 if (node) { 2827 return consumeNode(node) as T; 2828 } 2829 2830 return parseElement(); 2831 } 2832 2833 function currentNode(parsingContext: ParsingContext, pos?: number): Node | undefined { 2834 // If we don't have a cursor or the parsing context isn't reusable, there's nothing to reuse. 2835 // 2836 // If there is an outstanding parse error that we've encountered, but not attached to 2837 // some node, then we cannot get a node from the old source tree. This is because we 2838 // want to mark the next node we encounter as being unusable. 2839 // 2840 // Note: This may be too conservative. Perhaps we could reuse the node and set the bit 2841 // on it (or its leftmost child) as having the error. For now though, being conservative 2842 // is nice and likely won't ever affect perf. 2843 if (!syntaxCursor || !isReusableParsingContext(parsingContext) || parseErrorBeforeNextFinishedNode) { 2844 return undefined; 2845 } 2846 2847 const node = syntaxCursor.currentNode(pos ?? scanner.getStartPos()); 2848 2849 // Can't reuse a missing node. 2850 // Can't reuse a node that intersected the change range. 2851 // Can't reuse a node that contains a parse error. This is necessary so that we 2852 // produce the same set of errors again. 2853 if (nodeIsMissing(node) || node.intersectsChange || containsParseError(node)) { 2854 return undefined; 2855 } 2856 2857 // We can only reuse a node if it was parsed under the same strict mode that we're 2858 // currently in. i.e. if we originally parsed a node in non-strict mode, but then 2859 // the user added 'using strict' at the top of the file, then we can't use that node 2860 // again as the presence of strict mode may cause us to parse the tokens in the file 2861 // differently. 2862 // 2863 // Note: we *can* reuse tokens when the strict mode changes. That's because tokens 2864 // are unaffected by strict mode. It's just the parser will decide what to do with it 2865 // differently depending on what mode it is in. 2866 // 2867 // This also applies to all our other context flags as well. 2868 const nodeContextFlags = node.flags & NodeFlags.ContextFlags; 2869 if (nodeContextFlags !== contextFlags) { 2870 return undefined; 2871 } 2872 2873 // Ok, we have a node that looks like it could be reused. Now verify that it is valid 2874 // in the current list parsing context that we're currently at. 2875 if (!canReuseNode(node, parsingContext)) { 2876 return undefined; 2877 } 2878 2879 if ((node as JSDocContainer).jsDocCache) { 2880 // jsDocCache may include tags from parent nodes, which might have been modified. 2881 (node as JSDocContainer).jsDocCache = undefined; 2882 } 2883 2884 return node; 2885 } 2886 2887 function consumeNode(node: Node) { 2888 // Move the scanner so it is after the node we just consumed. 2889 scanner.setTextPos(node.end); 2890 nextToken(); 2891 return node; 2892 } 2893 2894 function isReusableParsingContext(parsingContext: ParsingContext): boolean { 2895 switch (parsingContext) { 2896 case ParsingContext.ClassMembers: 2897 case ParsingContext.SwitchClauses: 2898 case ParsingContext.SourceElements: 2899 case ParsingContext.BlockStatements: 2900 case ParsingContext.SwitchClauseStatements: 2901 case ParsingContext.EnumMembers: 2902 case ParsingContext.TypeMembers: 2903 case ParsingContext.VariableDeclarations: 2904 case ParsingContext.JSDocParameters: 2905 case ParsingContext.Parameters: 2906 return true; 2907 } 2908 return false; 2909 } 2910 2911 function canReuseNode(node: Node, parsingContext: ParsingContext): boolean { 2912 switch (parsingContext) { 2913 case ParsingContext.ClassMembers: 2914 return isReusableClassMember(node); 2915 2916 case ParsingContext.SwitchClauses: 2917 return isReusableSwitchClause(node); 2918 2919 case ParsingContext.SourceElements: 2920 case ParsingContext.BlockStatements: 2921 case ParsingContext.SwitchClauseStatements: 2922 return isReusableStatement(node); 2923 2924 case ParsingContext.EnumMembers: 2925 return isReusableEnumMember(node); 2926 2927 case ParsingContext.TypeMembers: 2928 return isReusableTypeMember(node); 2929 2930 case ParsingContext.VariableDeclarations: 2931 return isReusableVariableDeclaration(node); 2932 2933 case ParsingContext.JSDocParameters: 2934 case ParsingContext.Parameters: 2935 return isReusableParameter(node); 2936 2937 // Any other lists we do not care about reusing nodes in. But feel free to add if 2938 // you can do so safely. Danger areas involve nodes that may involve speculative 2939 // parsing. If speculative parsing is involved with the node, then the range the 2940 // parser reached while looking ahead might be in the edited range (see the example 2941 // in canReuseVariableDeclaratorNode for a good case of this). 2942 2943 // case ParsingContext.HeritageClauses: 2944 // This would probably be safe to reuse. There is no speculative parsing with 2945 // heritage clauses. 2946 2947 // case ParsingContext.TypeParameters: 2948 // This would probably be safe to reuse. There is no speculative parsing with 2949 // type parameters. Note that that's because type *parameters* only occur in 2950 // unambiguous *type* contexts. While type *arguments* occur in very ambiguous 2951 // *expression* contexts. 2952 2953 // case ParsingContext.TupleElementTypes: 2954 // This would probably be safe to reuse. There is no speculative parsing with 2955 // tuple types. 2956 2957 // Technically, type argument list types are probably safe to reuse. While 2958 // speculative parsing is involved with them (since type argument lists are only 2959 // produced from speculative parsing a < as a type argument list), we only have 2960 // the types because speculative parsing succeeded. Thus, the lookahead never 2961 // went past the end of the list and rewound. 2962 // case ParsingContext.TypeArguments: 2963 2964 // Note: these are almost certainly not safe to ever reuse. Expressions commonly 2965 // need a large amount of lookahead, and we should not reuse them as they may 2966 // have actually intersected the edit. 2967 // case ParsingContext.ArgumentExpressions: 2968 2969 // This is not safe to reuse for the same reason as the 'AssignmentExpression' 2970 // cases. i.e. a property assignment may end with an expression, and thus might 2971 // have lookahead far beyond it's old node. 2972 // case ParsingContext.ObjectLiteralMembers: 2973 2974 // This is probably not safe to reuse. There can be speculative parsing with 2975 // type names in a heritage clause. There can be generic names in the type 2976 // name list, and there can be left hand side expressions (which can have type 2977 // arguments.) 2978 // case ParsingContext.HeritageClauseElement: 2979 2980 // Perhaps safe to reuse, but it's unlikely we'd see more than a dozen attributes 2981 // on any given element. Same for children. 2982 // case ParsingContext.JsxAttributes: 2983 // case ParsingContext.JsxChildren: 2984 2985 } 2986 2987 return false; 2988 } 2989 2990 function isReusableClassMember(node: Node) { 2991 if (node) { 2992 switch (node.kind) { 2993 case SyntaxKind.Constructor: 2994 case SyntaxKind.IndexSignature: 2995 case SyntaxKind.GetAccessor: 2996 case SyntaxKind.SetAccessor: 2997 case SyntaxKind.SemicolonClassElement: 2998 return true; 2999 case SyntaxKind.PropertyDeclaration: 3000 return !inStructContext(); 3001 case SyntaxKind.MethodDeclaration: 3002 // Method declarations are not necessarily reusable. An object-literal 3003 // may have a method calls "constructor(...)" and we must reparse that 3004 // into an actual .ConstructorDeclaration. 3005 const methodDeclaration = node as MethodDeclaration; 3006 const nameIsConstructor = methodDeclaration.name.kind === SyntaxKind.Identifier && 3007 methodDeclaration.name.originalKeywordKind === SyntaxKind.ConstructorKeyword; 3008 3009 return !nameIsConstructor; 3010 } 3011 } 3012 3013 return false; 3014 } 3015 3016 function isReusableSwitchClause(node: Node) { 3017 if (node) { 3018 switch (node.kind) { 3019 case SyntaxKind.CaseClause: 3020 case SyntaxKind.DefaultClause: 3021 return true; 3022 } 3023 } 3024 3025 return false; 3026 } 3027 3028 function isReusableStatement(node: Node) { 3029 if (node) { 3030 switch (node.kind) { 3031 case SyntaxKind.FunctionDeclaration: 3032 case SyntaxKind.VariableStatement: 3033 case SyntaxKind.Block: 3034 case SyntaxKind.IfStatement: 3035 case SyntaxKind.ExpressionStatement: 3036 case SyntaxKind.ThrowStatement: 3037 case SyntaxKind.ReturnStatement: 3038 case SyntaxKind.SwitchStatement: 3039 case SyntaxKind.BreakStatement: 3040 case SyntaxKind.ContinueStatement: 3041 case SyntaxKind.ForInStatement: 3042 case SyntaxKind.ForOfStatement: 3043 case SyntaxKind.ForStatement: 3044 case SyntaxKind.WhileStatement: 3045 case SyntaxKind.WithStatement: 3046 case SyntaxKind.EmptyStatement: 3047 case SyntaxKind.TryStatement: 3048 case SyntaxKind.LabeledStatement: 3049 case SyntaxKind.DoStatement: 3050 case SyntaxKind.DebuggerStatement: 3051 case SyntaxKind.ImportDeclaration: 3052 case SyntaxKind.ImportEqualsDeclaration: 3053 case SyntaxKind.ExportDeclaration: 3054 case SyntaxKind.ExportAssignment: 3055 case SyntaxKind.ModuleDeclaration: 3056 case SyntaxKind.ClassDeclaration: 3057 case SyntaxKind.StructDeclaration: 3058 case SyntaxKind.InterfaceDeclaration: 3059 case SyntaxKind.EnumDeclaration: 3060 case SyntaxKind.TypeAliasDeclaration: 3061 return true; 3062 } 3063 } 3064 3065 return false; 3066 } 3067 3068 function isReusableEnumMember(node: Node) { 3069 return node.kind === SyntaxKind.EnumMember; 3070 } 3071 3072 function isReusableTypeMember(node: Node) { 3073 if (node) { 3074 switch (node.kind) { 3075 case SyntaxKind.ConstructSignature: 3076 case SyntaxKind.MethodSignature: 3077 case SyntaxKind.IndexSignature: 3078 case SyntaxKind.PropertySignature: 3079 case SyntaxKind.CallSignature: 3080 return true; 3081 } 3082 } 3083 3084 return false; 3085 } 3086 3087 function isReusableVariableDeclaration(node: Node) { 3088 if (node.kind !== SyntaxKind.VariableDeclaration) { 3089 return false; 3090 } 3091 3092 // Very subtle incremental parsing bug. Consider the following code: 3093 // 3094 // let v = new List < A, B 3095 // 3096 // This is actually legal code. It's a list of variable declarators "v = new List<A" 3097 // on one side and "B" on the other. If you then change that to: 3098 // 3099 // let v = new List < A, B >() 3100 // 3101 // then we have a problem. "v = new List<A" doesn't intersect the change range, so we 3102 // start reparsing at "B" and we completely fail to handle this properly. 3103 // 3104 // In order to prevent this, we do not allow a variable declarator to be reused if it 3105 // has an initializer. 3106 const variableDeclarator = node as VariableDeclaration; 3107 return variableDeclarator.initializer === undefined; 3108 } 3109 3110 function isReusableParameter(node: Node) { 3111 if (node.kind !== SyntaxKind.Parameter) { 3112 return false; 3113 } 3114 3115 // See the comment in isReusableVariableDeclaration for why we do this. 3116 const parameter = node as ParameterDeclaration; 3117 return parameter.initializer === undefined; 3118 } 3119 3120 // Returns true if we should abort parsing. 3121 function abortParsingListOrMoveToNextToken(kind: ParsingContext) { 3122 parsingContextErrors(kind); 3123 if (isInSomeParsingContext()) { 3124 return true; 3125 } 3126 3127 nextToken(); 3128 return false; 3129 } 3130 3131 function parsingContextErrors(context: ParsingContext) { 3132 switch (context) { 3133 case ParsingContext.SourceElements: 3134 return token() === SyntaxKind.DefaultKeyword 3135 ? parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.ExportKeyword)) 3136 : parseErrorAtCurrentToken(Diagnostics.Declaration_or_statement_expected); 3137 case ParsingContext.BlockStatements: return parseErrorAtCurrentToken(Diagnostics.Declaration_or_statement_expected); 3138 case ParsingContext.SwitchClauses: return parseErrorAtCurrentToken(Diagnostics.case_or_default_expected); 3139 case ParsingContext.SwitchClauseStatements: return parseErrorAtCurrentToken(Diagnostics.Statement_expected); 3140 case ParsingContext.RestProperties: // fallthrough 3141 case ParsingContext.TypeMembers: return parseErrorAtCurrentToken(Diagnostics.Property_or_signature_expected); 3142 case ParsingContext.ClassMembers: return parseErrorAtCurrentToken(Diagnostics.Unexpected_token_A_constructor_method_accessor_or_property_was_expected); 3143 case ParsingContext.AnnotationMembers: return parseErrorAtCurrentToken(Diagnostics.Unexpected_token_An_annotation_property_was_expected); 3144 case ParsingContext.EnumMembers: return parseErrorAtCurrentToken(Diagnostics.Enum_member_expected); 3145 case ParsingContext.HeritageClauseElement: return parseErrorAtCurrentToken(Diagnostics.Expression_expected); 3146 case ParsingContext.VariableDeclarations: 3147 return isKeyword(token()) 3148 ? parseErrorAtCurrentToken(Diagnostics._0_is_not_allowed_as_a_variable_declaration_name, tokenToString(token())) 3149 : parseErrorAtCurrentToken(Diagnostics.Variable_declaration_expected); 3150 case ParsingContext.ObjectBindingElements: return parseErrorAtCurrentToken(Diagnostics.Property_destructuring_pattern_expected); 3151 case ParsingContext.ArrayBindingElements: return parseErrorAtCurrentToken(Diagnostics.Array_element_destructuring_pattern_expected); 3152 case ParsingContext.ArgumentExpressions: return parseErrorAtCurrentToken(Diagnostics.Argument_expression_expected); 3153 case ParsingContext.ObjectLiteralMembers: return parseErrorAtCurrentToken(Diagnostics.Property_assignment_expected); 3154 case ParsingContext.ArrayLiteralMembers: return parseErrorAtCurrentToken(Diagnostics.Expression_or_comma_expected); 3155 case ParsingContext.JSDocParameters: return parseErrorAtCurrentToken(Diagnostics.Parameter_declaration_expected); 3156 case ParsingContext.Parameters: 3157 return isKeyword(token()) 3158 ? parseErrorAtCurrentToken(Diagnostics._0_is_not_allowed_as_a_parameter_name, tokenToString(token())) 3159 : parseErrorAtCurrentToken(Diagnostics.Parameter_declaration_expected); 3160 case ParsingContext.TypeParameters: return parseErrorAtCurrentToken(Diagnostics.Type_parameter_declaration_expected); 3161 case ParsingContext.TypeArguments: return parseErrorAtCurrentToken(Diagnostics.Type_argument_expected); 3162 case ParsingContext.TupleElementTypes: return parseErrorAtCurrentToken(Diagnostics.Type_expected); 3163 case ParsingContext.HeritageClauses: return parseErrorAtCurrentToken(Diagnostics.Unexpected_token_expected); 3164 case ParsingContext.ImportOrExportSpecifiers: return parseErrorAtCurrentToken(Diagnostics.Identifier_expected); 3165 case ParsingContext.JsxAttributes: return parseErrorAtCurrentToken(Diagnostics.Identifier_expected); 3166 case ParsingContext.JsxChildren: return parseErrorAtCurrentToken(Diagnostics.Identifier_expected); 3167 case ParsingContext.AssertEntries: return parseErrorAtCurrentToken(Diagnostics.Identifier_or_string_literal_expected); // AssertionKey. 3168 case ParsingContext.Count: return Debug.fail("ParsingContext.Count used as a context"); // Not a real context, only a marker. 3169 default: Debug.assertNever(context); 3170 } 3171 } 3172 3173 // Parses a comma-delimited list of elements 3174 function parseDelimitedList<T extends Node>(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimiter?: boolean): NodeArray<T>; 3175 function parseDelimitedList<T extends Node | undefined>(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimiter?: boolean): NodeArray<NonNullable<T>> | undefined; 3176 function parseDelimitedList<T extends Node | undefined>(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimiter?: boolean): NodeArray<NonNullable<T>> | undefined { 3177 const saveParsingContext = parsingContext; 3178 parsingContext |= 1 << kind; 3179 const list: NonNullable<T>[] = []; 3180 const listPos = getNodePos(); 3181 3182 let commaStart = -1; // Meaning the previous token was not a comma 3183 while (true) { 3184 if (isListElement(kind, /*inErrorRecovery*/ false)) { 3185 const startPos = scanner.getStartPos(); 3186 const result = parseListElement(kind, parseElement); 3187 if (!result) { 3188 parsingContext = saveParsingContext; 3189 return undefined; 3190 } 3191 list.push(result); 3192 commaStart = scanner.getTokenPos(); 3193 3194 if (parseOptional(SyntaxKind.CommaToken)) { 3195 // No need to check for a zero length node since we know we parsed a comma 3196 continue; 3197 } 3198 3199 commaStart = -1; // Back to the state where the last token was not a comma 3200 if (isListTerminator(kind)) { 3201 break; 3202 } 3203 3204 // We didn't get a comma, and the list wasn't terminated, explicitly parse 3205 // out a comma so we give a good error message. 3206 parseExpected(SyntaxKind.CommaToken, getExpectedCommaDiagnostic(kind)); 3207 3208 // If the token was a semicolon, and the caller allows that, then skip it and 3209 // continue. This ensures we get back on track and don't result in tons of 3210 // parse errors. For example, this can happen when people do things like use 3211 // a semicolon to delimit object literal members. Note: we'll have already 3212 // reported an error when we called parseExpected above. 3213 if (considerSemicolonAsDelimiter && token() === SyntaxKind.SemicolonToken && !scanner.hasPrecedingLineBreak()) { 3214 nextToken(); 3215 } 3216 if (startPos === scanner.getStartPos()) { 3217 // What we're parsing isn't actually remotely recognizable as a element and we've consumed no tokens whatsoever 3218 // Consume a token to advance the parser in some way and avoid an infinite loop 3219 // This can happen when we're speculatively parsing parenthesized expressions which we think may be arrow functions, 3220 // or when a modifier keyword which is disallowed as a parameter name (ie, `static` in strict mode) is supplied 3221 nextToken(); 3222 } 3223 continue; 3224 } 3225 3226 if (isListTerminator(kind)) { 3227 break; 3228 } 3229 3230 if (abortParsingListOrMoveToNextToken(kind)) { 3231 break; 3232 } 3233 } 3234 3235 parsingContext = saveParsingContext; 3236 // Recording the trailing comma is deliberately done after the previous 3237 // loop, and not just if we see a list terminator. This is because the list 3238 // may have ended incorrectly, but it is still important to know if there 3239 // was a trailing comma. 3240 // Check if the last token was a comma. 3241 // Always preserve a trailing comma by marking it on the NodeArray 3242 return createNodeArray(list, listPos, /*end*/ undefined, commaStart >= 0); 3243 } 3244 3245 function getExpectedCommaDiagnostic(kind: ParsingContext) { 3246 return kind === ParsingContext.EnumMembers ? Diagnostics.An_enum_member_name_must_be_followed_by_a_or : undefined; 3247 } 3248 3249 interface MissingList<T extends Node> extends NodeArray<T> { 3250 isMissingList: true; 3251 } 3252 3253 function createMissingList<T extends Node>(): MissingList<T> { 3254 const list = createNodeArray<T>([], getNodePos()) as MissingList<T>; 3255 list.isMissingList = true; 3256 return list; 3257 } 3258 3259 function isMissingList(arr: NodeArray<Node>): boolean { 3260 return !!(arr as MissingList<Node>).isMissingList; 3261 } 3262 3263 function parseBracketedList<T extends Node>(kind: ParsingContext, parseElement: () => T, open: SyntaxKind, close: SyntaxKind): NodeArray<T> { 3264 if (parseExpected(open)) { 3265 const result = parseDelimitedList(kind, parseElement); 3266 parseExpected(close); 3267 return result; 3268 } 3269 3270 return createMissingList<T>(); 3271 } 3272 3273 function parseEntityName(allowReservedWords: boolean, diagnosticMessage?: DiagnosticMessage): EntityName { 3274 const pos = getNodePos(); 3275 let entity: EntityName = allowReservedWords ? parseIdentifierName(diagnosticMessage) : parseIdentifier(diagnosticMessage); 3276 let dotPos = getNodePos(); 3277 while (parseOptional(SyntaxKind.DotToken)) { 3278 if (token() === SyntaxKind.LessThanToken) { 3279 // the entity is part of a JSDoc-style generic, so record the trailing dot for later error reporting 3280 entity.jsdocDotPos = dotPos; 3281 break; 3282 } 3283 dotPos = getNodePos(); 3284 entity = finishNode( 3285 factory.createQualifiedName( 3286 entity, 3287 parseRightSideOfDot(allowReservedWords, /* allowPrivateIdentifiers */ false) as Identifier 3288 ), 3289 pos 3290 ); 3291 } 3292 return entity; 3293 } 3294 3295 function createQualifiedName(entity: EntityName, name: Identifier): QualifiedName { 3296 return finishNode(factory.createQualifiedName(entity, name), entity.pos); 3297 } 3298 3299 function parseRightSideOfDot(allowIdentifierNames: boolean, allowPrivateIdentifiers: boolean): Identifier | PrivateIdentifier { 3300 // Technically a keyword is valid here as all identifiers and keywords are identifier names. 3301 // However, often we'll encounter this in error situations when the identifier or keyword 3302 // is actually starting another valid construct. 3303 // 3304 // So, we check for the following specific case: 3305 // 3306 // name. 3307 // identifierOrKeyword identifierNameOrKeyword 3308 // 3309 // Note: the newlines are important here. For example, if that above code 3310 // were rewritten into: 3311 // 3312 // name.identifierOrKeyword 3313 // identifierNameOrKeyword 3314 // 3315 // Then we would consider it valid. That's because ASI would take effect and 3316 // the code would be implicitly: "name.identifierOrKeyword; identifierNameOrKeyword". 3317 // In the first case though, ASI will not take effect because there is not a 3318 // line terminator after the identifier or keyword. 3319 if (scanner.hasPrecedingLineBreak() && tokenIsIdentifierOrKeyword(token())) { 3320 const matchesPattern = lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine); 3321 3322 if (matchesPattern) { 3323 // Report that we need an identifier. However, report it right after the dot, 3324 // and not on the next token. This is because the next token might actually 3325 // be an identifier and the error would be quite confusing. 3326 return createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Identifier_expected); 3327 } 3328 } 3329 3330 if (token() === SyntaxKind.PrivateIdentifier) { 3331 const node = parsePrivateIdentifier(); 3332 return allowPrivateIdentifiers ? node : createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Identifier_expected); 3333 } 3334 3335 return allowIdentifierNames ? parseIdentifierName() : parseIdentifier(); 3336 } 3337 3338 function parseTemplateSpans(isTaggedTemplate: boolean) { 3339 const pos = getNodePos(); 3340 const list = []; 3341 let node: TemplateSpan; 3342 do { 3343 node = parseTemplateSpan(isTaggedTemplate); 3344 list.push(node); 3345 } 3346 while (node.literal.kind === SyntaxKind.TemplateMiddle); 3347 return createNodeArray(list, pos); 3348 } 3349 3350 function parseTemplateExpression(isTaggedTemplate: boolean): TemplateExpression { 3351 const pos = getNodePos(); 3352 return finishNode( 3353 factory.createTemplateExpression( 3354 parseTemplateHead(isTaggedTemplate), 3355 parseTemplateSpans(isTaggedTemplate) 3356 ), 3357 pos 3358 ); 3359 } 3360 3361 function parseTemplateType(): TemplateLiteralTypeNode { 3362 const pos = getNodePos(); 3363 return finishNode( 3364 factory.createTemplateLiteralType( 3365 parseTemplateHead(/*isTaggedTemplate*/ false), 3366 parseTemplateTypeSpans() 3367 ), 3368 pos 3369 ); 3370 } 3371 3372 function parseTemplateTypeSpans() { 3373 const pos = getNodePos(); 3374 const list = []; 3375 let node: TemplateLiteralTypeSpan; 3376 do { 3377 node = parseTemplateTypeSpan(); 3378 list.push(node); 3379 } 3380 while (node.literal.kind === SyntaxKind.TemplateMiddle); 3381 return createNodeArray(list, pos); 3382 } 3383 3384 function parseTemplateTypeSpan(): TemplateLiteralTypeSpan { 3385 const pos = getNodePos(); 3386 return finishNode( 3387 factory.createTemplateLiteralTypeSpan( 3388 parseType(), 3389 parseLiteralOfTemplateSpan(/*isTaggedTemplate*/ false) 3390 ), 3391 pos 3392 ); 3393 } 3394 3395 function parseLiteralOfTemplateSpan(isTaggedTemplate: boolean) { 3396 if (token() === SyntaxKind.CloseBraceToken) { 3397 reScanTemplateToken(isTaggedTemplate); 3398 return parseTemplateMiddleOrTemplateTail(); 3399 } 3400 else { 3401 // TODO(rbuckton): Do we need to call `parseExpectedToken` or can we just call `createMissingNode` directly? 3402 return parseExpectedToken(SyntaxKind.TemplateTail, Diagnostics._0_expected, tokenToString(SyntaxKind.CloseBraceToken)) as TemplateTail; 3403 } 3404 } 3405 3406 function parseTemplateSpan(isTaggedTemplate: boolean): TemplateSpan { 3407 const pos = getNodePos(); 3408 return finishNode( 3409 factory.createTemplateSpan( 3410 allowInAnd(parseExpression), 3411 parseLiteralOfTemplateSpan(isTaggedTemplate) 3412 ), 3413 pos 3414 ); 3415 } 3416 3417 function parseLiteralNode(): LiteralExpression { 3418 return parseLiteralLikeNode(token()) as LiteralExpression; 3419 } 3420 3421 function parseTemplateHead(isTaggedTemplate: boolean): TemplateHead { 3422 if (isTaggedTemplate) { 3423 reScanTemplateHeadOrNoSubstitutionTemplate(); 3424 } 3425 const fragment = parseLiteralLikeNode(token()); 3426 Debug.assert(fragment.kind === SyntaxKind.TemplateHead, "Template head has wrong token kind"); 3427 return fragment as TemplateHead; 3428 } 3429 3430 function parseTemplateMiddleOrTemplateTail(): TemplateMiddle | TemplateTail { 3431 const fragment = parseLiteralLikeNode(token()); 3432 Debug.assert(fragment.kind === SyntaxKind.TemplateMiddle || fragment.kind === SyntaxKind.TemplateTail, "Template fragment has wrong token kind"); 3433 return fragment as TemplateMiddle | TemplateTail; 3434 } 3435 3436 function getTemplateLiteralRawText(kind: TemplateLiteralToken["kind"]) { 3437 const isLast = kind === SyntaxKind.NoSubstitutionTemplateLiteral || kind === SyntaxKind.TemplateTail; 3438 const tokenText = scanner.getTokenText(); 3439 return tokenText.substring(1, tokenText.length - (scanner.isUnterminated() ? 0 : isLast ? 1 : 2)); 3440 } 3441 3442 function parseLiteralLikeNode(kind: SyntaxKind): LiteralLikeNode { 3443 const pos = getNodePos(); 3444 const node = 3445 isTemplateLiteralKind(kind) ? factory.createTemplateLiteralLikeNode(kind, scanner.getTokenValue(), getTemplateLiteralRawText(kind), scanner.getTokenFlags() & TokenFlags.TemplateLiteralLikeFlags) : 3446 // Octal literals are not allowed in strict mode or ES5 3447 // Note that theoretically the following condition would hold true literals like 009, 3448 // which is not octal. But because of how the scanner separates the tokens, we would 3449 // never get a token like this. Instead, we would get 00 and 9 as two separate tokens. 3450 // We also do not need to check for negatives because any prefix operator would be part of a 3451 // parent unary expression. 3452 kind === SyntaxKind.NumericLiteral ? factory.createNumericLiteral(scanner.getTokenValue(), scanner.getNumericLiteralFlags()) : 3453 kind === SyntaxKind.StringLiteral ? factory.createStringLiteral(scanner.getTokenValue(), /*isSingleQuote*/ undefined, scanner.hasExtendedUnicodeEscape()) : 3454 isLiteralKind(kind) ? factory.createLiteralLikeNode(kind, scanner.getTokenValue()) : 3455 Debug.fail(); 3456 3457 if (scanner.hasExtendedUnicodeEscape()) { 3458 node.hasExtendedUnicodeEscape = true; 3459 } 3460 3461 if (scanner.isUnterminated()) { 3462 node.isUnterminated = true; 3463 } 3464 3465 nextToken(); 3466 return finishNode(node, pos); 3467 } 3468 3469 // TYPES 3470 3471 function parseEntityNameOfTypeReference() { 3472 return parseEntityName(/*allowReservedWords*/ true, Diagnostics.Type_expected); 3473 } 3474 3475 function parseTypeArgumentsOfTypeReference() { 3476 if (!scanner.hasPrecedingLineBreak() && reScanLessThanToken() === SyntaxKind.LessThanToken) { 3477 return parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken); 3478 } 3479 } 3480 3481 function parseTypeReference(): TypeReferenceNode { 3482 const pos = getNodePos(); 3483 return finishNode( 3484 factory.createTypeReferenceNode( 3485 parseEntityNameOfTypeReference(), 3486 parseTypeArgumentsOfTypeReference() 3487 ), 3488 pos 3489 ); 3490 } 3491 3492 // If true, we should abort parsing an error function. 3493 function typeHasArrowFunctionBlockingParseError(node: TypeNode): boolean { 3494 switch (node.kind) { 3495 case SyntaxKind.TypeReference: 3496 return nodeIsMissing((node as TypeReferenceNode).typeName); 3497 case SyntaxKind.FunctionType: 3498 case SyntaxKind.ConstructorType: { 3499 const { parameters, type } = node as FunctionOrConstructorTypeNode; 3500 return isMissingList(parameters) || typeHasArrowFunctionBlockingParseError(type); 3501 } 3502 case SyntaxKind.ParenthesizedType: 3503 return typeHasArrowFunctionBlockingParseError((node as ParenthesizedTypeNode).type); 3504 default: 3505 return false; 3506 } 3507 } 3508 3509 function parseThisTypePredicate(lhs: ThisTypeNode): TypePredicateNode { 3510 nextToken(); 3511 return finishNode(factory.createTypePredicateNode(/*assertsModifier*/ undefined, lhs, parseType()), lhs.pos); 3512 } 3513 3514 function parseThisTypeNode(): ThisTypeNode { 3515 const pos = getNodePos(); 3516 nextToken(); 3517 return finishNode(factory.createThisTypeNode(), pos); 3518 } 3519 3520 function parseJSDocAllType(): JSDocAllType | JSDocOptionalType { 3521 const pos = getNodePos(); 3522 nextToken(); 3523 return finishNode(factory.createJSDocAllType(), pos); 3524 } 3525 3526 function parseJSDocNonNullableType(): TypeNode { 3527 const pos = getNodePos(); 3528 nextToken(); 3529 return finishNode(factory.createJSDocNonNullableType(parseNonArrayType(), /*postfix*/ false), pos); 3530 } 3531 3532 function parseJSDocUnknownOrNullableType(): JSDocUnknownType | JSDocNullableType { 3533 const pos = getNodePos(); 3534 // skip the ? 3535 nextToken(); 3536 3537 // Need to lookahead to decide if this is a nullable or unknown type. 3538 3539 // Here are cases where we'll pick the unknown type: 3540 // 3541 // Foo(?, 3542 // { a: ? } 3543 // Foo(?) 3544 // Foo<?> 3545 // Foo(?= 3546 // (?| 3547 if (token() === SyntaxKind.CommaToken || 3548 token() === SyntaxKind.CloseBraceToken || 3549 token() === SyntaxKind.CloseParenToken || 3550 token() === SyntaxKind.GreaterThanToken || 3551 token() === SyntaxKind.EqualsToken || 3552 token() === SyntaxKind.BarToken) { 3553 return finishNode(factory.createJSDocUnknownType(), pos); 3554 } 3555 else { 3556 return finishNode(factory.createJSDocNullableType(parseType(), /*postfix*/ false), pos); 3557 } 3558 } 3559 3560 function parseJSDocFunctionType(): JSDocFunctionType | TypeReferenceNode { 3561 const pos = getNodePos(); 3562 const hasJSDoc = hasPrecedingJSDocComment(); 3563 if (lookAhead(nextTokenIsOpenParen)) { 3564 nextToken(); 3565 const parameters = parseParameters(SignatureFlags.Type | SignatureFlags.JSDoc); 3566 const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false); 3567 return withJSDoc(finishNode(factory.createJSDocFunctionType(parameters, type), pos), hasJSDoc); 3568 } 3569 return finishNode(factory.createTypeReferenceNode(parseIdentifierName(), /*typeArguments*/ undefined), pos); 3570 } 3571 3572 function parseJSDocParameter(): ParameterDeclaration { 3573 const pos = getNodePos(); 3574 let name: Identifier | undefined; 3575 if (token() === SyntaxKind.ThisKeyword || token() === SyntaxKind.NewKeyword) { 3576 name = parseIdentifierName(); 3577 parseExpected(SyntaxKind.ColonToken); 3578 } 3579 return finishNode( 3580 factory.createParameterDeclaration( 3581 /*modifiers*/ undefined, 3582 /*dotDotDotToken*/ undefined, 3583 // TODO(rbuckton): JSDoc parameters don't have names (except `this`/`new`), should we manufacture an empty identifier? 3584 name!, 3585 /*questionToken*/ undefined, 3586 parseJSDocType(), 3587 /*initializer*/ undefined 3588 ), 3589 pos 3590 ); 3591 } 3592 3593 function parseJSDocType(): TypeNode { 3594 scanner.setInJSDocType(true); 3595 const pos = getNodePos(); 3596 if (parseOptional(SyntaxKind.ModuleKeyword)) { 3597 // TODO(rbuckton): We never set the type for a JSDocNamepathType. What should we put here? 3598 const moduleTag = factory.createJSDocNamepathType(/*type*/ undefined!); 3599 terminate: while (true) { 3600 switch (token()) { 3601 case SyntaxKind.CloseBraceToken: 3602 case SyntaxKind.EndOfFileToken: 3603 case SyntaxKind.CommaToken: 3604 case SyntaxKind.WhitespaceTrivia: 3605 break terminate; 3606 default: 3607 nextTokenJSDoc(); 3608 } 3609 } 3610 3611 scanner.setInJSDocType(false); 3612 return finishNode(moduleTag, pos); 3613 } 3614 3615 const hasDotDotDot = parseOptional(SyntaxKind.DotDotDotToken); 3616 let type = parseTypeOrTypePredicate(); 3617 scanner.setInJSDocType(false); 3618 if (hasDotDotDot) { 3619 type = finishNode(factory.createJSDocVariadicType(type), pos); 3620 } 3621 if (token() === SyntaxKind.EqualsToken) { 3622 nextToken(); 3623 return finishNode(factory.createJSDocOptionalType(type), pos); 3624 } 3625 return type; 3626 } 3627 3628 function parseTypeQuery(): TypeQueryNode { 3629 const pos = getNodePos(); 3630 parseExpected(SyntaxKind.TypeOfKeyword); 3631 const entityName = parseEntityName(/*allowReservedWords*/ true); 3632 // Make sure we perform ASI to prevent parsing the next line's type arguments as part of an instantiation expression. 3633 const typeArguments = !scanner.hasPrecedingLineBreak() ? tryParseTypeArguments() : undefined; 3634 return finishNode(factory.createTypeQueryNode(entityName, typeArguments), pos); 3635 } 3636 3637 function parseTypeParameter(position?: number): TypeParameterDeclaration { 3638 const pos = getNodePos(); 3639 const modifiers = parseModifiers(); 3640 const name = position !== undefined ? parseEtsIdentifier(position) : parseIdentifier(); 3641 let constraint: TypeNode | undefined; 3642 let expression: Expression | undefined; 3643 if (parseOptional(SyntaxKind.ExtendsKeyword)) { 3644 // It's not uncommon for people to write improper constraints to a generic. If the 3645 // user writes a constraint that is an expression and not an actual type, then parse 3646 // it out as an expression (so we can recover well), but report that a type is needed 3647 // instead. 3648 if (isStartOfType() || !isStartOfExpression()) { 3649 constraint = parseType(); 3650 } 3651 else { 3652 // It was not a type, and it looked like an expression. Parse out an expression 3653 // here so we recover well. Note: it is important that we call parseUnaryExpression 3654 // and not parseExpression here. If the user has: 3655 // 3656 // <T extends ""> 3657 // 3658 // We do *not* want to consume the `>` as we're consuming the expression for "". 3659 expression = parseUnaryExpressionOrHigher(); 3660 } 3661 } 3662 3663 const defaultType = parseOptional(SyntaxKind.EqualsToken) ? parseType() : undefined; 3664 const node = factory.createTypeParameterDeclaration(modifiers, name, constraint, defaultType); 3665 node.expression = expression; 3666 return position !== undefined ? finishVirtualNode(node, position, position) : finishNode(node, pos); 3667 } 3668 3669 function parseTypeParameters(): NodeArray<TypeParameterDeclaration> | undefined { 3670 if (token() === SyntaxKind.LessThanToken) { 3671 return parseBracketedList(ParsingContext.TypeParameters, parseTypeParameter, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken); 3672 } 3673 } 3674 3675 function parseEtsTypeParameters(pos: number): NodeArray<TypeParameterDeclaration> | undefined { 3676 return createNodeArray([parseTypeParameter(pos)], getNodePos()); 3677 } 3678 3679 function parseEtsTypeArguments(pos: number, name: string): NodeArray<TypeNode> | undefined { 3680 if ((contextFlags & NodeFlags.JavaScriptFile) !== 0) { 3681 // TypeArguments must not be parsed in JavaScript files to avoid ambiguity with binary operators. 3682 return undefined; 3683 } 3684 3685 return createNodeArray([parseEtsType(pos, name)], getNodePos()); 3686 } 3687 3688 function isStartOfParameter(isJSDocParameter: boolean): boolean { 3689 return token() === SyntaxKind.DotDotDotToken || 3690 isBindingIdentifierOrPrivateIdentifierOrPattern() || 3691 isModifierKind(token()) || 3692 token() === SyntaxKind.AtToken || 3693 isStartOfType(/*inStartOfParameter*/ !isJSDocParameter); 3694 } 3695 3696 function parseNameOfParameter(modifiers: NodeArray<ModifierLike> | undefined) { 3697 // FormalParameter [Yield,Await]: 3698 // BindingElement[?Yield,?Await] 3699 const name = parseIdentifierOrPattern(Diagnostics.Private_identifiers_cannot_be_used_as_parameters); 3700 if (getFullWidth(name) === 0 && !some(modifiers) && isModifierKind(token())) { 3701 // in cases like 3702 // 'use strict' 3703 // function foo(static) 3704 // isParameter('static') === true, because of isModifier('static') 3705 // however 'static' is not a legal identifier in a strict mode. 3706 // so result of this function will be ParameterDeclaration (flags = 0, name = missing, type = undefined, initializer = undefined) 3707 // and current token will not change => parsing of the enclosing parameter list will last till the end of time (or OOM) 3708 // to avoid this we'll advance cursor to the next token. 3709 nextToken(); 3710 } 3711 return name; 3712 } 3713 3714 function isParameterNameStart() { 3715 // Be permissive about await and yield by calling isBindingIdentifier instead of isIdentifier; disallowing 3716 // them during a speculative parse leads to many more follow-on errors than allowing the function to parse then later 3717 // complaining about the use of the keywords. 3718 return isBindingIdentifier() || token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.OpenBraceToken; 3719 } 3720 3721 function parseParameter(inOuterAwaitContext: boolean): ParameterDeclaration { 3722 return parseParameterWorker(inOuterAwaitContext); 3723 } 3724 3725 function parseParameterForSpeculation(inOuterAwaitContext: boolean): ParameterDeclaration | undefined { 3726 return parseParameterWorker(inOuterAwaitContext, /*allowAmbiguity*/ false); 3727 } 3728 3729 function parseParameterWorker(inOuterAwaitContext: boolean): ParameterDeclaration; 3730 function parseParameterWorker(inOuterAwaitContext: boolean, allowAmbiguity: false): ParameterDeclaration | undefined; 3731 function parseParameterWorker(inOuterAwaitContext: boolean, allowAmbiguity = true): ParameterDeclaration | undefined { 3732 const pos = getNodePos(); 3733 const hasJSDoc = hasPrecedingJSDocComment(); 3734 3735 // FormalParameter [Yield,Await]: 3736 // BindingElement[?Yield,?Await] 3737 3738 // Decorators are parsed in the outer [Await] context, the rest of the parameter is parsed in the function's [Await] context. 3739 const decorators = inOuterAwaitContext ? doInAwaitContext(parseDecorators) : doOutsideOfAwaitContext(parseDecorators); 3740 3741 if (token() === SyntaxKind.ThisKeyword) { 3742 const node = factory.createParameterDeclaration( 3743 decorators, 3744 /*dotDotDotToken*/ undefined, 3745 createIdentifier(/*isIdentifier*/ true), 3746 /*questionToken*/ undefined, 3747 parseTypeAnnotation(), 3748 /*initializer*/ undefined 3749 ); 3750 3751 if (decorators) { 3752 parseErrorAtRange(decorators[0], Diagnostics.Decorators_may_not_be_applied_to_this_parameters); 3753 } 3754 3755 return withJSDoc(finishNode(node, pos), hasJSDoc); 3756 } 3757 3758 const savedTopLevel = topLevel; 3759 topLevel = false; 3760 3761 const modifiers = combineDecoratorsAndModifiers(decorators, parseModifiers()); 3762 const dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); 3763 3764 if (!allowAmbiguity && !isParameterNameStart()) { 3765 return undefined; 3766 } 3767 3768 const node = withJSDoc( 3769 finishNode( 3770 factory.createParameterDeclaration( 3771 modifiers, 3772 dotDotDotToken, 3773 parseNameOfParameter(modifiers), 3774 parseOptionalToken(SyntaxKind.QuestionToken), 3775 parseTypeAnnotation(), 3776 parseInitializer() 3777 ), 3778 pos 3779 ), 3780 hasJSDoc 3781 ); 3782 topLevel = savedTopLevel; 3783 return node; 3784 } 3785 3786 function parseReturnType(returnToken: SyntaxKind.EqualsGreaterThanToken, isType: boolean): TypeNode; 3787 function parseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean): TypeNode | undefined; 3788 function parseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean) { 3789 if (shouldParseReturnType(returnToken, isType)) { 3790 return allowConditionalTypesAnd(parseTypeOrTypePredicate); 3791 } 3792 } 3793 3794 function shouldParseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean): boolean { 3795 if (returnToken === SyntaxKind.EqualsGreaterThanToken) { 3796 parseExpected(returnToken); 3797 return true; 3798 } 3799 else if (parseOptional(SyntaxKind.ColonToken)) { 3800 return true; 3801 } 3802 else if (isType && token() === SyntaxKind.EqualsGreaterThanToken) { 3803 // This is easy to get backward, especially in type contexts, so parse the type anyway 3804 parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.ColonToken)); 3805 nextToken(); 3806 return true; 3807 } 3808 return false; 3809 } 3810 3811 function parseParametersWorker(flags: SignatureFlags, allowAmbiguity: true): NodeArray<ParameterDeclaration>; 3812 function parseParametersWorker(flags: SignatureFlags, allowAmbiguity: false): NodeArray<ParameterDeclaration> | undefined; 3813 function parseParametersWorker(flags: SignatureFlags, allowAmbiguity: boolean): NodeArray<ParameterDeclaration> | undefined { 3814 // FormalParameters [Yield,Await]: (modified) 3815 // [empty] 3816 // FormalParameterList[?Yield,Await] 3817 // 3818 // FormalParameter[Yield,Await]: (modified) 3819 // BindingElement[?Yield,Await] 3820 // 3821 // BindingElement [Yield,Await]: (modified) 3822 // SingleNameBinding[?Yield,?Await] 3823 // BindingPattern[?Yield,?Await]Initializer [In, ?Yield,?Await] opt 3824 // 3825 // SingleNameBinding [Yield,Await]: 3826 // BindingIdentifier[?Yield,?Await]Initializer [In, ?Yield,?Await] opt 3827 const savedYieldContext = inYieldContext(); 3828 const savedAwaitContext = inAwaitContext(); 3829 3830 setYieldContext(!!(flags & SignatureFlags.Yield)); 3831 setAwaitContext(!!(flags & SignatureFlags.Await)); 3832 3833 const parameters = flags & SignatureFlags.JSDoc ? 3834 parseDelimitedList(ParsingContext.JSDocParameters, parseJSDocParameter) : 3835 parseDelimitedList(ParsingContext.Parameters, () => allowAmbiguity ? parseParameter(savedAwaitContext) : parseParameterForSpeculation(savedAwaitContext)); 3836 3837 setYieldContext(savedYieldContext); 3838 setAwaitContext(savedAwaitContext); 3839 3840 return parameters; 3841 } 3842 3843 function parseParameters(flags: SignatureFlags): NodeArray<ParameterDeclaration> { 3844 // FormalParameters [Yield,Await]: (modified) 3845 // [empty] 3846 // FormalParameterList[?Yield,Await] 3847 // 3848 // FormalParameter[Yield,Await]: (modified) 3849 // BindingElement[?Yield,Await] 3850 // 3851 // BindingElement [Yield,Await]: (modified) 3852 // SingleNameBinding[?Yield,?Await] 3853 // BindingPattern[?Yield,?Await]Initializer [In, ?Yield,?Await] opt 3854 // 3855 // SingleNameBinding [Yield,Await]: 3856 // BindingIdentifier[?Yield,?Await]Initializer [In, ?Yield,?Await] opt 3857 if (!parseExpected(SyntaxKind.OpenParenToken)) { 3858 return createMissingList<ParameterDeclaration>(); 3859 } 3860 3861 const parameters = parseParametersWorker(flags, /*allowAmbiguity*/ true); 3862 parseExpected(SyntaxKind.CloseParenToken); 3863 return parameters; 3864 } 3865 3866 function parseTypeMemberSemicolon() { 3867 // We allow type members to be separated by commas or (possibly ASI) semicolons. 3868 // First check if it was a comma. If so, we're done with the member. 3869 if (parseOptional(SyntaxKind.CommaToken)) { 3870 return; 3871 } 3872 3873 // Didn't have a comma. We must have a (possible ASI) semicolon. 3874 parseSemicolon(); 3875 } 3876 3877 function parseSignatureMember(kind: SyntaxKind.CallSignature | SyntaxKind.ConstructSignature): CallSignatureDeclaration | ConstructSignatureDeclaration { 3878 const pos = getNodePos(); 3879 const hasJSDoc = hasPrecedingJSDocComment(); 3880 if (kind === SyntaxKind.ConstructSignature) { 3881 parseExpected(SyntaxKind.NewKeyword); 3882 } 3883 3884 const typeParameters = parseTypeParameters(); 3885 const parameters = parseParameters(SignatureFlags.Type); 3886 const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ true); 3887 parseTypeMemberSemicolon(); 3888 const node = kind === SyntaxKind.CallSignature 3889 ? factory.createCallSignature(typeParameters, parameters, type) 3890 : factory.createConstructSignature(typeParameters, parameters, type); 3891 return withJSDoc(finishNode(node, pos), hasJSDoc); 3892 } 3893 3894 function isIndexSignature(): boolean { 3895 return token() === SyntaxKind.OpenBracketToken && lookAhead(isUnambiguouslyIndexSignature); 3896 } 3897 3898 function isUnambiguouslyIndexSignature() { 3899 // The only allowed sequence is: 3900 // 3901 // [id: 3902 // 3903 // However, for error recovery, we also check the following cases: 3904 // 3905 // [... 3906 // [id, 3907 // [id?, 3908 // [id?: 3909 // [id?] 3910 // [public id 3911 // [private id 3912 // [protected id 3913 // [] 3914 // 3915 nextToken(); 3916 if (token() === SyntaxKind.DotDotDotToken || token() === SyntaxKind.CloseBracketToken) { 3917 return true; 3918 } 3919 3920 if (isModifierKind(token())) { 3921 nextToken(); 3922 if (isIdentifier()) { 3923 return true; 3924 } 3925 } 3926 else if (!isIdentifier()) { 3927 return false; 3928 } 3929 else { 3930 // Skip the identifier 3931 nextToken(); 3932 } 3933 3934 // A colon signifies a well formed indexer 3935 // A comma should be a badly formed indexer because comma expressions are not allowed 3936 // in computed properties. 3937 if (token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken) { 3938 return true; 3939 } 3940 3941 // Question mark could be an indexer with an optional property, 3942 // or it could be a conditional expression in a computed property. 3943 if (token() !== SyntaxKind.QuestionToken) { 3944 return false; 3945 } 3946 3947 // If any of the following tokens are after the question mark, it cannot 3948 // be a conditional expression, so treat it as an indexer. 3949 nextToken(); 3950 return token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken || token() === SyntaxKind.CloseBracketToken; 3951 } 3952 3953 function parseIndexSignatureDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): IndexSignatureDeclaration { 3954 const parameters = parseBracketedList<ParameterDeclaration>(ParsingContext.Parameters, () => parseParameter(/*inOuterAwaitContext*/ false), SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken); 3955 const type = parseTypeAnnotation(); 3956 parseTypeMemberSemicolon(); 3957 const node = factory.createIndexSignature(modifiers, parameters, type); 3958 (node as Mutable<IndexSignatureDeclaration>).illegalDecorators = decorators; 3959 return withJSDoc(finishNode(node, pos), hasJSDoc); 3960 } 3961 3962 function parsePropertyOrMethodSignature(pos: number, hasJSDoc: boolean, modifiers: NodeArray<Modifier> | undefined): PropertySignature | MethodSignature { 3963 const name = parsePropertyName(); 3964 const questionToken = parseOptionalToken(SyntaxKind.QuestionToken); 3965 let node: PropertySignature | MethodSignature; 3966 if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) { 3967 // Method signatures don't exist in expression contexts. So they have neither 3968 // [Yield] nor [Await] 3969 const typeParameters = parseTypeParameters(); 3970 const parameters = parseParameters(SignatureFlags.Type); 3971 const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ true); 3972 node = factory.createMethodSignature(modifiers, name, questionToken, typeParameters, parameters, type); 3973 } 3974 else { 3975 const type = parseTypeAnnotation(); 3976 node = factory.createPropertySignature(modifiers, name, questionToken, type); 3977 // Although type literal properties cannot not have initializers, we attempt 3978 // to parse an initializer so we can report in the checker that an interface 3979 // property or type literal property cannot have an initializer. 3980 if (token() === SyntaxKind.EqualsToken) (node as Mutable<PropertySignature>).initializer = parseInitializer(); 3981 } 3982 parseTypeMemberSemicolon(); 3983 return withJSDoc(finishNode(node, pos), hasJSDoc); 3984 } 3985 3986 function isTypeMemberStart(): boolean { 3987 // Return true if we have the start of a signature member 3988 if (token() === SyntaxKind.OpenParenToken || 3989 token() === SyntaxKind.LessThanToken || 3990 token() === SyntaxKind.GetKeyword || 3991 token() === SyntaxKind.SetKeyword) { 3992 return true; 3993 } 3994 let idToken = false; 3995 // Eat up all modifiers, but hold on to the last one in case it is actually an identifier 3996 while (isModifierKind(token())) { 3997 idToken = true; 3998 nextToken(); 3999 } 4000 // Index signatures and computed property names are type members 4001 if (token() === SyntaxKind.OpenBracketToken) { 4002 return true; 4003 } 4004 // Try to get the first property-like token following all modifiers 4005 if (isLiteralPropertyName()) { 4006 idToken = true; 4007 nextToken(); 4008 } 4009 // If we were able to get any potential identifier, check that it is 4010 // the start of a member declaration 4011 if (idToken) { 4012 return token() === SyntaxKind.OpenParenToken || 4013 token() === SyntaxKind.LessThanToken || 4014 token() === SyntaxKind.QuestionToken || 4015 token() === SyntaxKind.ColonToken || 4016 token() === SyntaxKind.CommaToken || 4017 canParseSemicolon(); 4018 } 4019 return false; 4020 } 4021 4022 function parseTypeMember(): TypeElement { 4023 if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) { 4024 return parseSignatureMember(SyntaxKind.CallSignature); 4025 } 4026 if (token() === SyntaxKind.NewKeyword && lookAhead(nextTokenIsOpenParenOrLessThan)) { 4027 return parseSignatureMember(SyntaxKind.ConstructSignature); 4028 } 4029 const pos = getNodePos(); 4030 const hasJSDoc = hasPrecedingJSDocComment(); 4031 const modifiers = parseModifiers(); 4032 if (parseContextualModifier(SyntaxKind.GetKeyword)) { 4033 return parseAccessorDeclaration(pos, hasJSDoc, /*decorators*/ undefined, modifiers, SyntaxKind.GetAccessor, SignatureFlags.Type); 4034 } 4035 4036 if (parseContextualModifier(SyntaxKind.SetKeyword)) { 4037 return parseAccessorDeclaration(pos, hasJSDoc, /*decorators*/ undefined, modifiers, SyntaxKind.SetAccessor, SignatureFlags.Type); 4038 } 4039 4040 if (isIndexSignature()) { 4041 return parseIndexSignatureDeclaration(pos, hasJSDoc, /*decorators*/ undefined, modifiers); 4042 } 4043 return parsePropertyOrMethodSignature(pos, hasJSDoc, modifiers); 4044 } 4045 4046 function nextTokenIsOpenParenOrLessThan() { 4047 nextToken(); 4048 return token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken; 4049 } 4050 4051 function nextTokenIsDot() { 4052 return nextToken() === SyntaxKind.DotToken; 4053 } 4054 4055 function nextTokenIsOpenParenOrLessThanOrDot() { 4056 switch (nextToken()) { 4057 case SyntaxKind.OpenParenToken: 4058 case SyntaxKind.LessThanToken: 4059 case SyntaxKind.DotToken: 4060 return true; 4061 } 4062 return false; 4063 } 4064 4065 function parseTypeLiteral(): TypeLiteralNode { 4066 const pos = getNodePos(); 4067 return finishNode(factory.createTypeLiteralNode(parseObjectTypeMembers()), pos); 4068 } 4069 4070 function parseObjectTypeMembers(): NodeArray<TypeElement> { 4071 let members: NodeArray<TypeElement>; 4072 if (parseExpected(SyntaxKind.OpenBraceToken)) { 4073 members = parseList(ParsingContext.TypeMembers, parseTypeMember); 4074 parseExpected(SyntaxKind.CloseBraceToken); 4075 } 4076 else { 4077 members = createMissingList<TypeElement>(); 4078 } 4079 4080 return members; 4081 } 4082 4083 function isStartOfMappedType() { 4084 nextToken(); 4085 if (token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) { 4086 return nextToken() === SyntaxKind.ReadonlyKeyword; 4087 } 4088 if (token() === SyntaxKind.ReadonlyKeyword) { 4089 nextToken(); 4090 } 4091 return token() === SyntaxKind.OpenBracketToken && nextTokenIsIdentifier() && nextToken() === SyntaxKind.InKeyword; 4092 } 4093 4094 function parseMappedTypeParameter() { 4095 const pos = getNodePos(); 4096 const name = parseIdentifierName(); 4097 parseExpected(SyntaxKind.InKeyword); 4098 const type = parseType(); 4099 return finishNode(factory.createTypeParameterDeclaration(/*modifiers*/ undefined, name, type, /*defaultType*/ undefined), pos); 4100 } 4101 4102 function parseMappedType() { 4103 const pos = getNodePos(); 4104 parseExpected(SyntaxKind.OpenBraceToken); 4105 let readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined; 4106 if (token() === SyntaxKind.ReadonlyKeyword || token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) { 4107 readonlyToken = parseTokenNode<ReadonlyKeyword | PlusToken | MinusToken>(); 4108 if (readonlyToken.kind !== SyntaxKind.ReadonlyKeyword) { 4109 parseExpected(SyntaxKind.ReadonlyKeyword); 4110 } 4111 } 4112 parseExpected(SyntaxKind.OpenBracketToken); 4113 const typeParameter = parseMappedTypeParameter(); 4114 const nameType = parseOptional(SyntaxKind.AsKeyword) ? parseType() : undefined; 4115 parseExpected(SyntaxKind.CloseBracketToken); 4116 let questionToken: QuestionToken | PlusToken | MinusToken | undefined; 4117 if (token() === SyntaxKind.QuestionToken || token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) { 4118 questionToken = parseTokenNode<QuestionToken | PlusToken | MinusToken>(); 4119 if (questionToken.kind !== SyntaxKind.QuestionToken) { 4120 parseExpected(SyntaxKind.QuestionToken); 4121 } 4122 } 4123 const type = parseTypeAnnotation(); 4124 parseSemicolon(); 4125 const members = parseList(ParsingContext.TypeMembers, parseTypeMember); 4126 parseExpected(SyntaxKind.CloseBraceToken); 4127 return finishNode(factory.createMappedTypeNode(readonlyToken, typeParameter, nameType, questionToken, type, members), pos); 4128 } 4129 4130 function parseTupleElementType() { 4131 const pos = getNodePos(); 4132 if (parseOptional(SyntaxKind.DotDotDotToken)) { 4133 return finishNode(factory.createRestTypeNode(parseType()), pos); 4134 } 4135 const type = parseType(); 4136 if (isJSDocNullableType(type) && type.pos === type.type.pos) { 4137 const node = factory.createOptionalTypeNode(type.type); 4138 setTextRange(node, type); 4139 (node as Mutable<Node>).flags = type.flags; 4140 return node; 4141 } 4142 return type; 4143 } 4144 4145 function isNextTokenColonOrQuestionColon() { 4146 return nextToken() === SyntaxKind.ColonToken || (token() === SyntaxKind.QuestionToken && nextToken() === SyntaxKind.ColonToken); 4147 } 4148 4149 function isTupleElementName() { 4150 if (token() === SyntaxKind.DotDotDotToken) { 4151 return tokenIsIdentifierOrKeyword(nextToken()) && isNextTokenColonOrQuestionColon(); 4152 } 4153 return tokenIsIdentifierOrKeyword(token()) && isNextTokenColonOrQuestionColon(); 4154 } 4155 4156 function parseTupleElementNameOrTupleElementType() { 4157 if (lookAhead(isTupleElementName)) { 4158 const pos = getNodePos(); 4159 const hasJSDoc = hasPrecedingJSDocComment(); 4160 const dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); 4161 const name = parseIdentifierName(); 4162 const questionToken = parseOptionalToken(SyntaxKind.QuestionToken); 4163 parseExpected(SyntaxKind.ColonToken); 4164 const type = parseTupleElementType(); 4165 const node = factory.createNamedTupleMember(dotDotDotToken, name, questionToken, type); 4166 return withJSDoc(finishNode(node, pos), hasJSDoc); 4167 } 4168 return parseTupleElementType(); 4169 } 4170 4171 function parseTupleType(): TupleTypeNode { 4172 const pos = getNodePos(); 4173 return finishNode( 4174 factory.createTupleTypeNode( 4175 parseBracketedList(ParsingContext.TupleElementTypes, parseTupleElementNameOrTupleElementType, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken) 4176 ), 4177 pos 4178 ); 4179 } 4180 4181 function parseParenthesizedType(): TypeNode { 4182 const pos = getNodePos(); 4183 parseExpected(SyntaxKind.OpenParenToken); 4184 const type = parseType(); 4185 parseExpected(SyntaxKind.CloseParenToken); 4186 return finishNode(factory.createParenthesizedType(type), pos); 4187 } 4188 4189 function parseModifiersForConstructorType(): NodeArray<Modifier> | undefined { 4190 let modifiers: NodeArray<Modifier> | undefined; 4191 if (token() === SyntaxKind.AbstractKeyword) { 4192 const pos = getNodePos(); 4193 nextToken(); 4194 const modifier = finishNode(factory.createToken(SyntaxKind.AbstractKeyword), pos); 4195 modifiers = createNodeArray<Modifier>([modifier], pos); 4196 } 4197 return modifiers; 4198 } 4199 4200 function parseFunctionOrConstructorType(): TypeNode { 4201 const pos = getNodePos(); 4202 const hasJSDoc = hasPrecedingJSDocComment(); 4203 const modifiers = parseModifiersForConstructorType(); 4204 const isConstructorType = parseOptional(SyntaxKind.NewKeyword); 4205 const typeParameters = parseTypeParameters(); 4206 const parameters = parseParameters(SignatureFlags.Type); 4207 const type = parseReturnType(SyntaxKind.EqualsGreaterThanToken, /*isType*/ false); 4208 const node = isConstructorType 4209 ? factory.createConstructorTypeNode(modifiers, typeParameters, parameters, type) 4210 : factory.createFunctionTypeNode(typeParameters, parameters, type); 4211 if (!isConstructorType) (node as Mutable<FunctionTypeNode>).modifiers = modifiers; 4212 return withJSDoc(finishNode(node, pos), hasJSDoc); 4213 } 4214 4215 function parseKeywordAndNoDot(): TypeNode | undefined { 4216 const node = parseTokenNode<TypeNode>(); 4217 return token() === SyntaxKind.DotToken ? undefined : node; 4218 } 4219 4220 function parseLiteralTypeNode(negative?: boolean): LiteralTypeNode { 4221 const pos = getNodePos(); 4222 if (negative) { 4223 nextToken(); 4224 } 4225 let expression: BooleanLiteral | NullLiteral | LiteralExpression | PrefixUnaryExpression = 4226 token() === SyntaxKind.TrueKeyword || token() === SyntaxKind.FalseKeyword || token() === SyntaxKind.NullKeyword ? 4227 parseTokenNode<BooleanLiteral | NullLiteral>() : 4228 parseLiteralLikeNode(token()) as LiteralExpression; 4229 if (negative) { 4230 expression = finishNode(factory.createPrefixUnaryExpression(SyntaxKind.MinusToken, expression), pos); 4231 } 4232 return finishNode(factory.createLiteralTypeNode(expression), pos); 4233 } 4234 4235 function isStartOfTypeOfImportType() { 4236 nextToken(); 4237 return token() === SyntaxKind.ImportKeyword; 4238 } 4239 4240 function parseImportTypeAssertions(): ImportTypeAssertionContainer { 4241 const pos = getNodePos(); 4242 const openBracePosition = scanner.getTokenPos(); 4243 parseExpected(SyntaxKind.OpenBraceToken); 4244 const multiLine = scanner.hasPrecedingLineBreak(); 4245 parseExpected(SyntaxKind.AssertKeyword); 4246 parseExpected(SyntaxKind.ColonToken); 4247 const clause = parseAssertClause(/*skipAssertKeyword*/ true); 4248 if (!parseExpected(SyntaxKind.CloseBraceToken)) { 4249 const lastError = lastOrUndefined(parseDiagnostics); 4250 if (lastError && lastError.code === Diagnostics._0_expected.code) { 4251 addRelatedInfo( 4252 lastError, 4253 createDetachedDiagnostic(fileName, openBracePosition, 1, Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, "{", "}") 4254 ); 4255 } 4256 } 4257 return finishNode(factory.createImportTypeAssertionContainer(clause, multiLine), pos); 4258 } 4259 4260 function parseImportType(): ImportTypeNode { 4261 sourceFlags |= NodeFlags.PossiblyContainsDynamicImport; 4262 const pos = getNodePos(); 4263 const isTypeOf = parseOptional(SyntaxKind.TypeOfKeyword); 4264 parseExpected(SyntaxKind.ImportKeyword); 4265 parseExpected(SyntaxKind.OpenParenToken); 4266 const type = parseType(); 4267 let assertions: ImportTypeAssertionContainer | undefined; 4268 if (parseOptional(SyntaxKind.CommaToken)) { 4269 assertions = parseImportTypeAssertions(); 4270 } 4271 parseExpected(SyntaxKind.CloseParenToken); 4272 const qualifier = parseOptional(SyntaxKind.DotToken) ? parseEntityNameOfTypeReference() : undefined; 4273 const typeArguments = parseTypeArgumentsOfTypeReference(); 4274 return finishNode(factory.createImportTypeNode(type, assertions, qualifier, typeArguments, isTypeOf), pos); 4275 } 4276 4277 function nextTokenIsNumericOrBigIntLiteral() { 4278 nextToken(); 4279 return token() === SyntaxKind.NumericLiteral || token() === SyntaxKind.BigIntLiteral; 4280 } 4281 4282 function parseNonArrayType(): TypeNode { 4283 switch (token()) { 4284 case SyntaxKind.AnyKeyword: 4285 case SyntaxKind.UnknownKeyword: 4286 case SyntaxKind.StringKeyword: 4287 case SyntaxKind.NumberKeyword: 4288 case SyntaxKind.BigIntKeyword: 4289 case SyntaxKind.SymbolKeyword: 4290 case SyntaxKind.BooleanKeyword: 4291 case SyntaxKind.UndefinedKeyword: 4292 case SyntaxKind.NeverKeyword: 4293 case SyntaxKind.ObjectKeyword: 4294 // If these are followed by a dot, then parse these out as a dotted type reference instead. 4295 return tryParse(parseKeywordAndNoDot) || parseTypeReference(); 4296 case SyntaxKind.AsteriskEqualsToken: 4297 // If there is '*=', treat it as * followed by postfix = 4298 scanner.reScanAsteriskEqualsToken(); 4299 // falls through 4300 case SyntaxKind.AsteriskToken: 4301 return parseJSDocAllType(); 4302 case SyntaxKind.QuestionQuestionToken: 4303 // If there is '??', treat it as prefix-'?' in JSDoc type. 4304 scanner.reScanQuestionToken(); 4305 // falls through 4306 case SyntaxKind.QuestionToken: 4307 return parseJSDocUnknownOrNullableType(); 4308 case SyntaxKind.FunctionKeyword: 4309 return parseJSDocFunctionType(); 4310 case SyntaxKind.ExclamationToken: 4311 return parseJSDocNonNullableType(); 4312 case SyntaxKind.NoSubstitutionTemplateLiteral: 4313 case SyntaxKind.StringLiteral: 4314 case SyntaxKind.NumericLiteral: 4315 case SyntaxKind.BigIntLiteral: 4316 case SyntaxKind.TrueKeyword: 4317 case SyntaxKind.FalseKeyword: 4318 case SyntaxKind.NullKeyword: 4319 return parseLiteralTypeNode(); 4320 case SyntaxKind.MinusToken: 4321 return lookAhead(nextTokenIsNumericOrBigIntLiteral) ? parseLiteralTypeNode(/*negative*/ true) : parseTypeReference(); 4322 case SyntaxKind.VoidKeyword: 4323 return parseTokenNode<TypeNode>(); 4324 case SyntaxKind.ThisKeyword: { 4325 const thisKeyword = parseThisTypeNode(); 4326 if (token() === SyntaxKind.IsKeyword && !scanner.hasPrecedingLineBreak()) { 4327 return parseThisTypePredicate(thisKeyword); 4328 } 4329 else { 4330 return thisKeyword; 4331 } 4332 } 4333 case SyntaxKind.TypeOfKeyword: 4334 return lookAhead(isStartOfTypeOfImportType) ? parseImportType() : parseTypeQuery(); 4335 case SyntaxKind.OpenBraceToken: 4336 return lookAhead(isStartOfMappedType) ? parseMappedType() : parseTypeLiteral(); 4337 case SyntaxKind.OpenBracketToken: 4338 return parseTupleType(); 4339 case SyntaxKind.OpenParenToken: 4340 return parseParenthesizedType(); 4341 case SyntaxKind.ImportKeyword: 4342 return parseImportType(); 4343 case SyntaxKind.AssertsKeyword: 4344 return lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine) ? parseAssertsTypePredicate() : parseTypeReference(); 4345 case SyntaxKind.TemplateHead: 4346 return parseTemplateType(); 4347 default: 4348 return parseTypeReference(); 4349 } 4350 } 4351 4352 function isStartOfType(inStartOfParameter?: boolean): boolean { 4353 switch (token()) { 4354 case SyntaxKind.AnyKeyword: 4355 case SyntaxKind.UnknownKeyword: 4356 case SyntaxKind.StringKeyword: 4357 case SyntaxKind.NumberKeyword: 4358 case SyntaxKind.BigIntKeyword: 4359 case SyntaxKind.BooleanKeyword: 4360 case SyntaxKind.ReadonlyKeyword: 4361 case SyntaxKind.SymbolKeyword: 4362 case SyntaxKind.UniqueKeyword: 4363 case SyntaxKind.VoidKeyword: 4364 case SyntaxKind.UndefinedKeyword: 4365 case SyntaxKind.NullKeyword: 4366 case SyntaxKind.ThisKeyword: 4367 case SyntaxKind.TypeOfKeyword: 4368 case SyntaxKind.NeverKeyword: 4369 case SyntaxKind.OpenBraceToken: 4370 case SyntaxKind.OpenBracketToken: 4371 case SyntaxKind.LessThanToken: 4372 case SyntaxKind.BarToken: 4373 case SyntaxKind.AmpersandToken: 4374 case SyntaxKind.NewKeyword: 4375 case SyntaxKind.StringLiteral: 4376 case SyntaxKind.NumericLiteral: 4377 case SyntaxKind.BigIntLiteral: 4378 case SyntaxKind.TrueKeyword: 4379 case SyntaxKind.FalseKeyword: 4380 case SyntaxKind.ObjectKeyword: 4381 case SyntaxKind.AsteriskToken: 4382 case SyntaxKind.QuestionToken: 4383 case SyntaxKind.ExclamationToken: 4384 case SyntaxKind.DotDotDotToken: 4385 case SyntaxKind.InferKeyword: 4386 case SyntaxKind.ImportKeyword: 4387 case SyntaxKind.AssertsKeyword: 4388 case SyntaxKind.NoSubstitutionTemplateLiteral: 4389 case SyntaxKind.TemplateHead: 4390 return true; 4391 case SyntaxKind.FunctionKeyword: 4392 return !inStartOfParameter; 4393 case SyntaxKind.MinusToken: 4394 return !inStartOfParameter && lookAhead(nextTokenIsNumericOrBigIntLiteral); 4395 case SyntaxKind.OpenParenToken: 4396 // Only consider '(' the start of a type if followed by ')', '...', an identifier, a modifier, 4397 // or something that starts a type. We don't want to consider things like '(1)' a type. 4398 return !inStartOfParameter && lookAhead(isStartOfParenthesizedOrFunctionType); 4399 default: 4400 return isIdentifier(); 4401 } 4402 } 4403 4404 function isStartOfParenthesizedOrFunctionType() { 4405 nextToken(); 4406 return token() === SyntaxKind.CloseParenToken || isStartOfParameter(/*isJSDocParameter*/ false) || isStartOfType(); 4407 } 4408 4409 function parsePostfixTypeOrHigher(): TypeNode { 4410 const pos = getNodePos(); 4411 let type = parseNonArrayType(); 4412 while (!scanner.hasPrecedingLineBreak()) { 4413 switch (token()) { 4414 case SyntaxKind.ExclamationToken: 4415 nextToken(); 4416 type = finishNode(factory.createJSDocNonNullableType(type, /*postfix*/ true), pos); 4417 break; 4418 case SyntaxKind.QuestionToken: 4419 // If next token is start of a type we have a conditional type 4420 if (lookAhead(nextTokenIsStartOfType)) { 4421 return type; 4422 } 4423 nextToken(); 4424 type = finishNode(factory.createJSDocNullableType(type, /*postfix*/ true), pos); 4425 break; 4426 case SyntaxKind.OpenBracketToken: 4427 parseExpected(SyntaxKind.OpenBracketToken); 4428 if (isStartOfType()) { 4429 const indexType = parseType(); 4430 parseExpected(SyntaxKind.CloseBracketToken); 4431 type = finishNode(factory.createIndexedAccessTypeNode(type, indexType), pos); 4432 } 4433 else { 4434 parseExpected(SyntaxKind.CloseBracketToken); 4435 type = finishNode(factory.createArrayTypeNode(type), pos); 4436 } 4437 break; 4438 default: 4439 return type; 4440 } 4441 } 4442 return type; 4443 } 4444 4445 function parseTypeOperator(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword) { 4446 const pos = getNodePos(); 4447 parseExpected(operator); 4448 return finishNode(factory.createTypeOperatorNode(operator, parseTypeOperatorOrHigher()), pos); 4449 } 4450 4451 function tryParseConstraintOfInferType() { 4452 if (parseOptional(SyntaxKind.ExtendsKeyword)) { 4453 const constraint = disallowConditionalTypesAnd(parseType); 4454 if (inDisallowConditionalTypesContext() || token() !== SyntaxKind.QuestionToken) { 4455 return constraint; 4456 } 4457 } 4458 } 4459 4460 function parseTypeParameterOfInferType(): TypeParameterDeclaration { 4461 const pos = getNodePos(); 4462 const name = parseIdentifier(); 4463 const constraint = tryParse(tryParseConstraintOfInferType); 4464 const node = factory.createTypeParameterDeclaration(/*modifiers*/ undefined, name, constraint); 4465 return finishNode(node, pos); 4466 } 4467 4468 function parseInferType(): InferTypeNode { 4469 const pos = getNodePos(); 4470 parseExpected(SyntaxKind.InferKeyword); 4471 return finishNode(factory.createInferTypeNode(parseTypeParameterOfInferType()), pos); 4472 } 4473 4474 function parseTypeOperatorOrHigher(): TypeNode { 4475 const operator = token(); 4476 switch (operator) { 4477 case SyntaxKind.KeyOfKeyword: 4478 case SyntaxKind.UniqueKeyword: 4479 case SyntaxKind.ReadonlyKeyword: 4480 return parseTypeOperator(operator); 4481 case SyntaxKind.InferKeyword: 4482 return parseInferType(); 4483 } 4484 return allowConditionalTypesAnd(parsePostfixTypeOrHigher); 4485 } 4486 4487 function parseFunctionOrConstructorTypeToError( 4488 isInUnionType: boolean 4489 ): TypeNode | undefined { 4490 // the function type and constructor type shorthand notation 4491 // are not allowed directly in unions and intersections, but we'll 4492 // try to parse them gracefully and issue a helpful message. 4493 if (isStartOfFunctionTypeOrConstructorType()) { 4494 const type = parseFunctionOrConstructorType(); 4495 let diagnostic: DiagnosticMessage; 4496 if (isFunctionTypeNode(type)) { 4497 diagnostic = isInUnionType 4498 ? Diagnostics.Function_type_notation_must_be_parenthesized_when_used_in_a_union_type 4499 : Diagnostics.Function_type_notation_must_be_parenthesized_when_used_in_an_intersection_type; 4500 } 4501 else { 4502 diagnostic = isInUnionType 4503 ? Diagnostics.Constructor_type_notation_must_be_parenthesized_when_used_in_a_union_type 4504 : Diagnostics.Constructor_type_notation_must_be_parenthesized_when_used_in_an_intersection_type; 4505 4506 } 4507 parseErrorAtRange(type, diagnostic); 4508 return type; 4509 } 4510 return undefined; 4511 } 4512 4513 function parseUnionOrIntersectionType( 4514 operator: SyntaxKind.BarToken | SyntaxKind.AmpersandToken, 4515 parseConstituentType: () => TypeNode, 4516 createTypeNode: (types: NodeArray<TypeNode>) => UnionOrIntersectionTypeNode 4517 ): TypeNode { 4518 const pos = getNodePos(); 4519 const isUnionType = operator === SyntaxKind.BarToken; 4520 const hasLeadingOperator = parseOptional(operator); 4521 let type = hasLeadingOperator && parseFunctionOrConstructorTypeToError(isUnionType) 4522 || parseConstituentType(); 4523 if (token() === operator || hasLeadingOperator) { 4524 const types = [type]; 4525 while (parseOptional(operator)) { 4526 types.push(parseFunctionOrConstructorTypeToError(isUnionType) || parseConstituentType()); 4527 } 4528 type = finishNode(createTypeNode(createNodeArray(types, pos)), pos); 4529 } 4530 return type; 4531 } 4532 4533 function parseIntersectionTypeOrHigher(): TypeNode { 4534 return parseUnionOrIntersectionType(SyntaxKind.AmpersandToken, parseTypeOperatorOrHigher, factory.createIntersectionTypeNode); 4535 } 4536 4537 function parseUnionTypeOrHigher(): TypeNode { 4538 return parseUnionOrIntersectionType(SyntaxKind.BarToken, parseIntersectionTypeOrHigher, factory.createUnionTypeNode); 4539 } 4540 4541 function nextTokenIsNewKeyword(): boolean { 4542 nextToken(); 4543 return token() === SyntaxKind.NewKeyword; 4544 } 4545 4546 function isStartOfFunctionTypeOrConstructorType(): boolean { 4547 if (token() === SyntaxKind.LessThanToken) { 4548 return true; 4549 } 4550 if (token() === SyntaxKind.OpenParenToken && lookAhead(isUnambiguouslyStartOfFunctionType)) { 4551 return true; 4552 } 4553 return token() === SyntaxKind.NewKeyword || 4554 token() === SyntaxKind.AbstractKeyword && lookAhead(nextTokenIsNewKeyword); 4555 } 4556 4557 function skipParameterStart(): boolean { 4558 if (isModifierKind(token())) { 4559 // Skip modifiers 4560 parseModifiers(); 4561 } 4562 if (isIdentifier() || token() === SyntaxKind.ThisKeyword) { 4563 nextToken(); 4564 return true; 4565 } 4566 if (token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.OpenBraceToken) { 4567 // Return true if we can parse an array or object binding pattern with no errors 4568 const previousErrorCount = parseDiagnostics.length; 4569 parseIdentifierOrPattern(); 4570 return previousErrorCount === parseDiagnostics.length; 4571 } 4572 return false; 4573 } 4574 4575 function isUnambiguouslyStartOfFunctionType() { 4576 nextToken(); 4577 if (token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.DotDotDotToken) { 4578 // ( ) 4579 // ( ... 4580 return true; 4581 } 4582 if (skipParameterStart()) { 4583 // We successfully skipped modifiers (if any) and an identifier or binding pattern, 4584 // now see if we have something that indicates a parameter declaration 4585 if (token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken || 4586 token() === SyntaxKind.QuestionToken || token() === SyntaxKind.EqualsToken) { 4587 // ( xxx : 4588 // ( xxx , 4589 // ( xxx ? 4590 // ( xxx = 4591 return true; 4592 } 4593 if (token() === SyntaxKind.CloseParenToken) { 4594 nextToken(); 4595 if (token() === SyntaxKind.EqualsGreaterThanToken) { 4596 // ( xxx ) => 4597 return true; 4598 } 4599 } 4600 } 4601 return false; 4602 } 4603 4604 function parseTypeOrTypePredicate(): TypeNode { 4605 const pos = getNodePos(); 4606 const typePredicateVariable = isIdentifier() && tryParse(parseTypePredicatePrefix); 4607 const type = parseType(); 4608 if (typePredicateVariable) { 4609 return finishNode(factory.createTypePredicateNode(/*assertsModifier*/ undefined, typePredicateVariable, type), pos); 4610 } 4611 else { 4612 return type; 4613 } 4614 } 4615 4616 function parseTypePredicatePrefix() { 4617 const id = parseIdentifier(); 4618 if (token() === SyntaxKind.IsKeyword && !scanner.hasPrecedingLineBreak()) { 4619 nextToken(); 4620 return id; 4621 } 4622 } 4623 4624 function parseAssertsTypePredicate(): TypeNode { 4625 const pos = getNodePos(); 4626 const assertsModifier = parseExpectedToken(SyntaxKind.AssertsKeyword); 4627 const parameterName = token() === SyntaxKind.ThisKeyword ? parseThisTypeNode() : parseIdentifier(); 4628 const type = parseOptional(SyntaxKind.IsKeyword) ? parseType() : undefined; 4629 return finishNode(factory.createTypePredicateNode(assertsModifier, parameterName, type), pos); 4630 } 4631 4632 function parseType(): TypeNode { 4633 if (contextFlags & NodeFlags.TypeExcludesFlags) { 4634 return doOutsideOfContext(NodeFlags.TypeExcludesFlags, parseType); 4635 } 4636 4637 if (isStartOfFunctionTypeOrConstructorType()) { 4638 return parseFunctionOrConstructorType(); 4639 } 4640 const pos = getNodePos(); 4641 const type = parseUnionTypeOrHigher(); 4642 if (!inDisallowConditionalTypesContext() && !scanner.hasPrecedingLineBreak() && parseOptional(SyntaxKind.ExtendsKeyword)) { 4643 // The type following 'extends' is not permitted to be another conditional type 4644 const extendsType = disallowConditionalTypesAnd(parseType); 4645 parseExpected(SyntaxKind.QuestionToken); 4646 const trueType = allowConditionalTypesAnd(parseType); 4647 parseExpected(SyntaxKind.ColonToken); 4648 const falseType = allowConditionalTypesAnd(parseType); 4649 return finishNode(factory.createConditionalTypeNode(type, extendsType, trueType, falseType), pos); 4650 } 4651 return type; 4652 } 4653 4654 function parseEtsType(pos: number, name: string): TypeNode { 4655 const contextFlagsToClear = NodeFlags.TypeExcludesFlags & contextFlags; 4656 if (contextFlagsToClear) { 4657 // clear the requested context flags 4658 setContextFlag(/*val*/ false, contextFlagsToClear); 4659 const result = parseEtsTypeReferenceWorker(pos, name); 4660 // restore the context flags we just cleared 4661 setContextFlag(/*val*/ true, contextFlagsToClear); 4662 return result; 4663 } 4664 4665 return parseEtsTypeReferenceWorker(pos, name); 4666 } 4667 4668 function parseEtsTypeReferenceWorker(pos: number, name: string): TypeNode { 4669 return finishVirtualNode( 4670 factory.createTypeReferenceNode( 4671 finishVirtualNode(factory.createIdentifier(name), pos, pos) 4672 ), 4673 pos, pos 4674 ); 4675 } 4676 4677 function parseTypeAnnotation(): TypeNode | undefined { 4678 return parseOptional(SyntaxKind.ColonToken) ? parseType() : undefined; 4679 } 4680 4681 // EXPRESSIONS 4682 function isStartOfLeftHandSideExpression(): boolean { 4683 switch (token()) { 4684 case SyntaxKind.ThisKeyword: 4685 case SyntaxKind.SuperKeyword: 4686 case SyntaxKind.NullKeyword: 4687 case SyntaxKind.TrueKeyword: 4688 case SyntaxKind.FalseKeyword: 4689 case SyntaxKind.NumericLiteral: 4690 case SyntaxKind.BigIntLiteral: 4691 case SyntaxKind.StringLiteral: 4692 case SyntaxKind.NoSubstitutionTemplateLiteral: 4693 case SyntaxKind.TemplateHead: 4694 case SyntaxKind.OpenParenToken: 4695 case SyntaxKind.OpenBracketToken: 4696 case SyntaxKind.OpenBraceToken: 4697 case SyntaxKind.FunctionKeyword: 4698 case SyntaxKind.ClassKeyword: 4699 case SyntaxKind.NewKeyword: 4700 case SyntaxKind.SlashToken: 4701 case SyntaxKind.SlashEqualsToken: 4702 case SyntaxKind.Identifier: 4703 return true; 4704 case SyntaxKind.StructKeyword: 4705 return inEtsContext(); 4706 case SyntaxKind.ImportKeyword: 4707 return lookAhead(nextTokenIsOpenParenOrLessThanOrDot); 4708 default: 4709 return isIdentifier(); 4710 } 4711 } 4712 4713 function isStartOfExpression(): boolean { 4714 if (isStartOfLeftHandSideExpression()) { 4715 return true; 4716 } 4717 4718 switch (token()) { 4719 case SyntaxKind.PlusToken: 4720 case SyntaxKind.MinusToken: 4721 case SyntaxKind.TildeToken: 4722 case SyntaxKind.ExclamationToken: 4723 case SyntaxKind.DeleteKeyword: 4724 case SyntaxKind.TypeOfKeyword: 4725 case SyntaxKind.VoidKeyword: 4726 case SyntaxKind.PlusPlusToken: 4727 case SyntaxKind.MinusMinusToken: 4728 case SyntaxKind.LessThanToken: 4729 case SyntaxKind.AwaitKeyword: 4730 case SyntaxKind.YieldKeyword: 4731 case SyntaxKind.PrivateIdentifier: 4732 // Yield/await always starts an expression. Either it is an identifier (in which case 4733 // it is definitely an expression). Or it's a keyword (either because we're in 4734 // a generator or async function, or in strict mode (or both)) and it started a yield or await expression. 4735 return true; 4736 case SyntaxKind.DotToken: 4737 return isValidExtendOrStylesContext(); 4738 default: 4739 // Error tolerance. If we see the start of some binary operator, we consider 4740 // that the start of an expression. That way we'll parse out a missing identifier, 4741 // give a good message about an identifier being missing, and then consume the 4742 // rest of the binary expression. 4743 if (isBinaryOperator()) { 4744 return true; 4745 } 4746 4747 return isIdentifier(); 4748 } 4749 } 4750 4751 function isValidExtendOrStylesContext(): boolean { 4752 return (inEtsExtendComponentsContext() && !!extendEtsComponentDeclaration) || 4753 (inEtsStylesComponentsContext() && !!stylesEtsComponentDeclaration); 4754 } 4755 4756 function isStartOfExpressionStatement(): boolean { 4757 // As per the grammar, none of '{' or 'function' or 'class' can start an expression statement. 4758 return token() !== SyntaxKind.OpenBraceToken && 4759 token() !== SyntaxKind.FunctionKeyword && 4760 token() !== SyntaxKind.ClassKeyword && 4761 (!inEtsContext() || token() !== SyntaxKind.StructKeyword) && 4762 token() !== SyntaxKind.AtToken && 4763 isStartOfExpression(); 4764 } 4765 4766 function parseExpression(): Expression { 4767 // Expression[in]: 4768 // AssignmentExpression[in] 4769 // Expression[in] , AssignmentExpression[in] 4770 4771 // clear the decorator context when parsing Expression, as it should be unambiguous when parsing a decorator 4772 const saveDecoratorContext = inDecoratorContext(); 4773 if (saveDecoratorContext) { 4774 setDecoratorContext(/*val*/ false); 4775 } 4776 4777 const pos = getNodePos(); 4778 let expr = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true); 4779 let operatorToken: BinaryOperatorToken; 4780 while ((operatorToken = parseOptionalToken(SyntaxKind.CommaToken))) { 4781 expr = makeBinaryExpression(expr, operatorToken, parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true), pos); 4782 } 4783 4784 if (saveDecoratorContext) { 4785 setDecoratorContext(/*val*/ true); 4786 } 4787 return expr; 4788 } 4789 4790 function parseInitializer(): Expression | undefined { 4791 return parseOptional(SyntaxKind.EqualsToken) ? parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true) : undefined; 4792 } 4793 4794 function parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction: boolean): Expression { 4795 // AssignmentExpression[in,yield]: 4796 // 1) ConditionalExpression[?in,?yield] 4797 // 2) LeftHandSideExpression = AssignmentExpression[?in,?yield] 4798 // 3) LeftHandSideExpression AssignmentOperator AssignmentExpression[?in,?yield] 4799 // 4) ArrowFunctionExpression[?in,?yield] 4800 // 5) AsyncArrowFunctionExpression[in,yield,await] 4801 // 6) [+Yield] YieldExpression[?In] 4802 // 4803 // Note: for ease of implementation we treat productions '2' and '3' as the same thing. 4804 // (i.e. they're both BinaryExpressions with an assignment operator in it). 4805 4806 // First, do the simple check if we have a YieldExpression (production '6'). 4807 if (isYieldExpression()) { 4808 return parseYieldExpression(); 4809 } 4810 4811 // Then, check if we have an arrow function (production '4' and '5') that starts with a parenthesized 4812 // parameter list or is an async arrow function. 4813 // AsyncArrowFunctionExpression: 4814 // 1) async[no LineTerminator here]AsyncArrowBindingIdentifier[?Yield][no LineTerminator here]=>AsyncConciseBody[?In] 4815 // 2) CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await][no LineTerminator here]=>AsyncConciseBody[?In] 4816 // Production (1) of AsyncArrowFunctionExpression is parsed in "tryParseAsyncSimpleArrowFunctionExpression". 4817 // And production (2) is parsed in "tryParseParenthesizedArrowFunctionExpression". 4818 // 4819 // If we do successfully parse arrow-function, we must *not* recurse for productions 1, 2 or 3. An ArrowFunction is 4820 // not a LeftHandSideExpression, nor does it start a ConditionalExpression. So we are done 4821 // with AssignmentExpression if we see one. 4822 const arrowExpression = tryParseParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction) || tryParseAsyncSimpleArrowFunctionExpression(allowReturnTypeInArrowFunction); 4823 if (arrowExpression) { 4824 return arrowExpression; 4825 } 4826 4827 // Now try to see if we're in production '1', '2' or '3'. A conditional expression can 4828 // start with a LogicalOrExpression, while the assignment productions can only start with 4829 // LeftHandSideExpressions. 4830 // 4831 // So, first, we try to just parse out a BinaryExpression. If we get something that is a 4832 // LeftHandSide or higher, then we can try to parse out the assignment expression part. 4833 // Otherwise, we try to parse out the conditional expression bit. We want to allow any 4834 // binary expression here, so we pass in the 'lowest' precedence here so that it matches 4835 // and consumes anything. 4836 const pos = getNodePos(); 4837 const expr = parseBinaryExpressionOrHigher(OperatorPrecedence.Lowest); 4838 4839 // To avoid a look-ahead, we did not handle the case of an arrow function with a single un-parenthesized 4840 // parameter ('x => ...') above. We handle it here by checking if the parsed expression was a single 4841 // identifier and the current token is an arrow. 4842 if (expr.kind === SyntaxKind.Identifier && token() === SyntaxKind.EqualsGreaterThanToken) { 4843 return parseSimpleArrowFunctionExpression(pos, expr as Identifier, allowReturnTypeInArrowFunction, /*asyncModifier*/ undefined); 4844 } 4845 4846 // Now see if we might be in cases '2' or '3'. 4847 // If the expression was a LHS expression, and we have an assignment operator, then 4848 // we're in '2' or '3'. Consume the assignment and return. 4849 // 4850 // Note: we call reScanGreaterToken so that we get an appropriately merged token 4851 // for cases like `> > =` becoming `>>=` 4852 if (isLeftHandSideExpression(expr) && isAssignmentOperator(reScanGreaterToken())) { 4853 return makeBinaryExpression(expr, parseTokenNode(), parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction), pos); 4854 } 4855 4856 // It's a CallExpression with open brace followed, therefore, we think it's an EtsComponentExpression 4857 if ((inBuildContext() || inBuilderContext()) && inUICallbackContext() && ts.isCallExpression(expr) && token() === SyntaxKind.OpenBraceToken) { 4858 return makeEtsComponentExpression(expr, pos); 4859 } 4860 4861 // It wasn't an assignment or a lambda. This is a conditional expression: 4862 return parseConditionalExpressionRest(expr, pos, allowReturnTypeInArrowFunction); 4863 } 4864 4865 function makeEtsComponentExpression(expression: Expression, pos: number): EtsComponentExpression { 4866 const name = (<CallExpression>expression).expression; 4867 const body = parseFunctionBlock(SignatureFlags.None); 4868 return finishNode(factory.createEtsComponentExpression(<Identifier>name, (<CallExpression>expression).arguments, body), pos); 4869 } 4870 4871 function isYieldExpression(): boolean { 4872 if (token() === SyntaxKind.YieldKeyword) { 4873 // If we have a 'yield' keyword, and this is a context where yield expressions are 4874 // allowed, then definitely parse out a yield expression. 4875 if (inYieldContext()) { 4876 return true; 4877 } 4878 4879 // We're in a context where 'yield expr' is not allowed. However, if we can 4880 // definitely tell that the user was trying to parse a 'yield expr' and not 4881 // just a normal expr that start with a 'yield' identifier, then parse out 4882 // a 'yield expr'. We can then report an error later that they are only 4883 // allowed in generator expressions. 4884 // 4885 // for example, if we see 'yield(foo)', then we'll have to treat that as an 4886 // invocation expression of something called 'yield'. However, if we have 4887 // 'yield foo' then that is not legal as a normal expression, so we can 4888 // definitely recognize this as a yield expression. 4889 // 4890 // for now we just check if the next token is an identifier. More heuristics 4891 // can be added here later as necessary. We just need to make sure that we 4892 // don't accidentally consume something legal. 4893 return lookAhead(nextTokenIsIdentifierOrKeywordOrLiteralOnSameLine); 4894 } 4895 4896 return false; 4897 } 4898 4899 function nextTokenIsIdentifierOnSameLine() { 4900 nextToken(); 4901 return !scanner.hasPrecedingLineBreak() && isIdentifier(); 4902 } 4903 4904 function parseYieldExpression(): YieldExpression { 4905 const pos = getNodePos(); 4906 4907 // YieldExpression[In] : 4908 // yield 4909 // yield [no LineTerminator here] [Lexical goal InputElementRegExp]AssignmentExpression[?In, Yield] 4910 // yield [no LineTerminator here] * [Lexical goal InputElementRegExp]AssignmentExpression[?In, Yield] 4911 nextToken(); 4912 4913 if (!scanner.hasPrecedingLineBreak() && 4914 (token() === SyntaxKind.AsteriskToken || isStartOfExpression())) { 4915 return finishNode( 4916 factory.createYieldExpression( 4917 parseOptionalToken(SyntaxKind.AsteriskToken), 4918 parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true) 4919 ), 4920 pos 4921 ); 4922 } 4923 else { 4924 // if the next token is not on the same line as yield. or we don't have an '*' or 4925 // the start of an expression, then this is just a simple "yield" expression. 4926 return finishNode(factory.createYieldExpression(/*asteriskToken*/ undefined, /*expression*/ undefined), pos); 4927 } 4928 } 4929 4930 function parseSimpleArrowFunctionExpression(pos: number, identifier: Identifier, allowReturnTypeInArrowFunction: boolean, asyncModifier?: NodeArray<Modifier> | undefined): ArrowFunction { 4931 Debug.assert(token() === SyntaxKind.EqualsGreaterThanToken, "parseSimpleArrowFunctionExpression should only have been called if we had a =>"); 4932 const parameter = factory.createParameterDeclaration( 4933 /*modifiers*/ undefined, 4934 /*dotDotDotToken*/ undefined, 4935 identifier, 4936 /*questionToken*/ undefined, 4937 /*type*/ undefined, 4938 /*initializer*/ undefined 4939 ); 4940 finishNode(parameter, identifier.pos); 4941 4942 const parameters = createNodeArray<ParameterDeclaration>([parameter], parameter.pos, parameter.end); 4943 const equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken); 4944 const body = parseArrowFunctionExpressionBody(/*isAsync*/ !!asyncModifier, allowReturnTypeInArrowFunction); 4945 const node = factory.createArrowFunction(asyncModifier, /*typeParameters*/ undefined, parameters, /*type*/ undefined, equalsGreaterThanToken, body); 4946 return addJSDocComment(finishNode(node, pos)); 4947 } 4948 4949 function tryParseParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction: boolean): Expression | undefined { 4950 const triState = isParenthesizedArrowFunctionExpression(); 4951 if (triState === Tristate.False) { 4952 // It's definitely not a parenthesized arrow function expression. 4953 return undefined; 4954 } 4955 4956 // If we definitely have an arrow function, then we can just parse one, not requiring a 4957 // following => or { token. Otherwise, we *might* have an arrow function. Try to parse 4958 // it out, but don't allow any ambiguity, and return 'undefined' if this could be an 4959 // expression instead. 4960 return triState === Tristate.True ? 4961 parseParenthesizedArrowFunctionExpression(/*allowAmbiguity*/ true, /*allowReturnTypeInArrowFunction*/ true) : 4962 tryParse(() => parsePossibleParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction)); 4963 } 4964 4965 // True -> We definitely expect a parenthesized arrow function here. 4966 // False -> There *cannot* be a parenthesized arrow function here. 4967 // Unknown -> There *might* be a parenthesized arrow function here. 4968 // Speculatively look ahead to be sure, and rollback if not. 4969 function isParenthesizedArrowFunctionExpression(): Tristate { 4970 if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken || token() === SyntaxKind.AsyncKeyword) { 4971 return lookAhead(isParenthesizedArrowFunctionExpressionWorker); 4972 } 4973 4974 if (token() === SyntaxKind.EqualsGreaterThanToken) { 4975 // ERROR RECOVERY TWEAK: 4976 // If we see a standalone => try to parse it as an arrow function expression as that's 4977 // likely what the user intended to write. 4978 return Tristate.True; 4979 } 4980 // Definitely not a parenthesized arrow function. 4981 return Tristate.False; 4982 } 4983 4984 function isParenthesizedArrowFunctionExpressionWorker() { 4985 if (token() === SyntaxKind.AsyncKeyword) { 4986 nextToken(); 4987 if (scanner.hasPrecedingLineBreak()) { 4988 return Tristate.False; 4989 } 4990 if (token() !== SyntaxKind.OpenParenToken && token() !== SyntaxKind.LessThanToken) { 4991 return Tristate.False; 4992 } 4993 } 4994 4995 const first = token(); 4996 const second = nextToken(); 4997 4998 if (first === SyntaxKind.OpenParenToken) { 4999 if (second === SyntaxKind.CloseParenToken) { 5000 // Simple cases: "() =>", "(): ", and "() {". 5001 // This is an arrow function with no parameters. 5002 // The last one is not actually an arrow function, 5003 // but this is probably what the user intended. 5004 const third = nextToken(); 5005 switch (third) { 5006 case SyntaxKind.EqualsGreaterThanToken: 5007 case SyntaxKind.ColonToken: 5008 case SyntaxKind.OpenBraceToken: 5009 return Tristate.True; 5010 default: 5011 return Tristate.False; 5012 } 5013 } 5014 5015 // If encounter "([" or "({", this could be the start of a binding pattern. 5016 // Examples: 5017 // ([ x ]) => { } 5018 // ({ x }) => { } 5019 // ([ x ]) 5020 // ({ x }) 5021 if (second === SyntaxKind.OpenBracketToken || second === SyntaxKind.OpenBraceToken) { 5022 return Tristate.Unknown; 5023 } 5024 5025 // Simple case: "(..." 5026 // This is an arrow function with a rest parameter. 5027 if (second === SyntaxKind.DotDotDotToken) { 5028 return Tristate.True; 5029 } 5030 5031 // Check for "(xxx yyy", where xxx is a modifier and yyy is an identifier. This 5032 // isn't actually allowed, but we want to treat it as a lambda so we can provide 5033 // a good error message. 5034 if (isModifierKind(second) && second !== SyntaxKind.AsyncKeyword && lookAhead(nextTokenIsIdentifier)) { 5035 if (nextToken() === SyntaxKind.AsKeyword) { 5036 // https://github.com/microsoft/TypeScript/issues/44466 5037 return Tristate.False; 5038 } 5039 return Tristate.True; 5040 } 5041 5042 // If we had "(" followed by something that's not an identifier, 5043 // then this definitely doesn't look like a lambda. "this" is not 5044 // valid, but we want to parse it and then give a semantic error. 5045 if (!isIdentifier() && second !== SyntaxKind.ThisKeyword) { 5046 return Tristate.False; 5047 } 5048 5049 switch (nextToken()) { 5050 case SyntaxKind.ColonToken: 5051 // If we have something like "(a:", then we must have a 5052 // type-annotated parameter in an arrow function expression. 5053 return Tristate.True; 5054 case SyntaxKind.QuestionToken: 5055 nextToken(); 5056 // If we have "(a?:" or "(a?," or "(a?=" or "(a?)" then it is definitely a lambda. 5057 if (token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken || token() === SyntaxKind.EqualsToken || token() === SyntaxKind.CloseParenToken) { 5058 return Tristate.True; 5059 } 5060 // Otherwise it is definitely not a lambda. 5061 return Tristate.False; 5062 case SyntaxKind.CommaToken: 5063 case SyntaxKind.EqualsToken: 5064 case SyntaxKind.CloseParenToken: 5065 // If we have "(a," or "(a=" or "(a)" this *could* be an arrow function 5066 return Tristate.Unknown; 5067 } 5068 // It is definitely not an arrow function 5069 return Tristate.False; 5070 } 5071 else { 5072 Debug.assert(first === SyntaxKind.LessThanToken); 5073 5074 // If we have "<" not followed by an identifier, 5075 // then this definitely is not an arrow function. 5076 if (!isIdentifier()) { 5077 return Tristate.False; 5078 } 5079 5080 // JSX overrides 5081 if (languageVariant === LanguageVariant.JSX) { 5082 const isArrowFunctionInJsx = lookAhead(() => { 5083 const third = nextToken(); 5084 if (third === SyntaxKind.ExtendsKeyword) { 5085 const fourth = nextToken(); 5086 switch (fourth) { 5087 case SyntaxKind.EqualsToken: 5088 case SyntaxKind.GreaterThanToken: 5089 return false; 5090 default: 5091 return true; 5092 } 5093 } 5094 else if (third === SyntaxKind.CommaToken || third === SyntaxKind.EqualsToken) { 5095 return true; 5096 } 5097 return false; 5098 }); 5099 5100 if (isArrowFunctionInJsx) { 5101 return Tristate.True; 5102 } 5103 5104 return Tristate.False; 5105 } 5106 5107 // This *could* be a parenthesized arrow function. 5108 return Tristate.Unknown; 5109 } 5110 } 5111 5112 function parsePossibleParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction: boolean): ArrowFunction | undefined { 5113 const tokenPos = scanner.getTokenPos(); 5114 if (notParenthesizedArrow?.has(tokenPos)) { 5115 return undefined; 5116 } 5117 5118 const result = parseParenthesizedArrowFunctionExpression(/*allowAmbiguity*/ false, allowReturnTypeInArrowFunction); 5119 if (!result) { 5120 (notParenthesizedArrow || (notParenthesizedArrow = new Set())).add(tokenPos); 5121 } 5122 5123 return result; 5124 } 5125 5126 function tryParseAsyncSimpleArrowFunctionExpression(allowReturnTypeInArrowFunction: boolean): ArrowFunction | undefined { 5127 // We do a check here so that we won't be doing unnecessarily call to "lookAhead" 5128 if (token() === SyntaxKind.AsyncKeyword) { 5129 if (lookAhead(isUnParenthesizedAsyncArrowFunctionWorker) === Tristate.True) { 5130 const pos = getNodePos(); 5131 const asyncModifier = parseModifiersForArrowFunction(); 5132 const expr = parseBinaryExpressionOrHigher(OperatorPrecedence.Lowest); 5133 return parseSimpleArrowFunctionExpression(pos, expr as Identifier, allowReturnTypeInArrowFunction, asyncModifier); 5134 } 5135 } 5136 return undefined; 5137 } 5138 5139 function isUnParenthesizedAsyncArrowFunctionWorker(): Tristate { 5140 // AsyncArrowFunctionExpression: 5141 // 1) async[no LineTerminator here]AsyncArrowBindingIdentifier[?Yield][no LineTerminator here]=>AsyncConciseBody[?In] 5142 // 2) CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await][no LineTerminator here]=>AsyncConciseBody[?In] 5143 if (token() === SyntaxKind.AsyncKeyword) { 5144 nextToken(); 5145 // If the "async" is followed by "=>" token then it is not a beginning of an async arrow-function 5146 // but instead a simple arrow-function which will be parsed inside "parseAssignmentExpressionOrHigher" 5147 if (scanner.hasPrecedingLineBreak() || token() === SyntaxKind.EqualsGreaterThanToken) { 5148 return Tristate.False; 5149 } 5150 // Check for un-parenthesized AsyncArrowFunction 5151 const expr = parseBinaryExpressionOrHigher(OperatorPrecedence.Lowest); 5152 if (!scanner.hasPrecedingLineBreak() && expr.kind === SyntaxKind.Identifier && token() === SyntaxKind.EqualsGreaterThanToken) { 5153 return Tristate.True; 5154 } 5155 } 5156 5157 return Tristate.False; 5158 } 5159 5160 function parseParenthesizedArrowFunctionExpression(allowAmbiguity: boolean, allowReturnTypeInArrowFunction: boolean): ArrowFunction | undefined { 5161 const pos = getNodePos(); 5162 const hasJSDoc = hasPrecedingJSDocComment(); 5163 const modifiers = parseModifiersForArrowFunction(); 5164 const isAsync = some(modifiers, isAsyncModifier) ? SignatureFlags.Await : SignatureFlags.None; 5165 // Arrow functions are never generators. 5166 // 5167 // If we're speculatively parsing a signature for a parenthesized arrow function, then 5168 // we have to have a complete parameter list. Otherwise we might see something like 5169 // a => (b => c) 5170 // And think that "(b =>" was actually a parenthesized arrow function with a missing 5171 // close paren. 5172 const typeParameters = parseTypeParameters(); 5173 5174 let parameters: NodeArray<ParameterDeclaration>; 5175 if (!parseExpected(SyntaxKind.OpenParenToken)) { 5176 if (!allowAmbiguity) { 5177 return undefined; 5178 } 5179 parameters = createMissingList<ParameterDeclaration>(); 5180 } 5181 else { 5182 if (!allowAmbiguity) { 5183 const maybeParameters = parseParametersWorker(isAsync, allowAmbiguity); 5184 if (!maybeParameters) { 5185 return undefined; 5186 } 5187 parameters = maybeParameters; 5188 } 5189 else { 5190 parameters = parseParametersWorker(isAsync, allowAmbiguity); 5191 } 5192 if (!parseExpected(SyntaxKind.CloseParenToken) && !allowAmbiguity) { 5193 return undefined; 5194 } 5195 } 5196 5197 const hasReturnColon = token() === SyntaxKind.ColonToken; 5198 const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false); 5199 if (type && !allowAmbiguity && typeHasArrowFunctionBlockingParseError(type)) { 5200 return undefined; 5201 } 5202 5203 // Parsing a signature isn't enough. 5204 // Parenthesized arrow signatures often look like other valid expressions. 5205 // For instance: 5206 // - "(x = 10)" is an assignment expression parsed as a signature with a default parameter value. 5207 // - "(x,y)" is a comma expression parsed as a signature with two parameters. 5208 // - "a ? (b): c" will have "(b):" parsed as a signature with a return type annotation. 5209 // - "a ? (b): function() {}" will too, since function() is a valid JSDoc function type. 5210 // - "a ? (b): (function() {})" as well, but inside of a parenthesized type with an arbitrary amount of nesting. 5211 // 5212 // So we need just a bit of lookahead to ensure that it can only be a signature. 5213 5214 let unwrappedType = type; 5215 while (unwrappedType?.kind === SyntaxKind.ParenthesizedType) { 5216 unwrappedType = (unwrappedType as ParenthesizedTypeNode).type; // Skip parens if need be 5217 } 5218 5219 const hasJSDocFunctionType = unwrappedType && isJSDocFunctionType(unwrappedType); 5220 if (!allowAmbiguity && token() !== SyntaxKind.EqualsGreaterThanToken && (hasJSDocFunctionType || token() !== SyntaxKind.OpenBraceToken)) { 5221 // Returning undefined here will cause our caller to rewind to where we started from. 5222 return undefined; 5223 } 5224 5225 // If we have an arrow, then try to parse the body. Even if not, try to parse if we 5226 // have an opening brace, just in case we're in an error state. 5227 const lastToken = token(); 5228 const equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken); 5229 let originUIContextFlag = inUICallbackContext() 5230 setUICallbackContext(inSyntaxComponentContext() ? true : false); 5231 setSyntaxComponentContext(false); 5232 const body = (lastToken === SyntaxKind.EqualsGreaterThanToken || lastToken === SyntaxKind.OpenBraceToken) 5233 ? parseArrowFunctionExpressionBody(some(modifiers, isAsyncModifier), allowReturnTypeInArrowFunction) 5234 : parseIdentifier(); 5235 setUICallbackContext(originUIContextFlag); 5236 // Given: 5237 // x ? y => ({ y }) : z => ({ z }) 5238 // We try to parse the body of the first arrow function by looking at: 5239 // ({ y }) : z => ({ z }) 5240 // This is a valid arrow function with "z" as the return type. 5241 // 5242 // But, if we're in the true side of a conditional expression, this colon 5243 // terminates the expression, so we cannot allow a return type if we aren't 5244 // certain whether or not the preceding text was parsed as a parameter list. 5245 // 5246 // For example, 5247 // a() ? (b: number, c?: string): void => d() : e 5248 // is determined by isParenthesizedArrowFunctionExpression to unambiguously 5249 // be an arrow expression, so we allow a return type. 5250 if (!allowReturnTypeInArrowFunction && hasReturnColon) { 5251 // However, if the arrow function we were able to parse is followed by another colon 5252 // as in: 5253 // a ? (x): string => x : null 5254 // Then allow the arrow function, and treat the second colon as terminating 5255 // the conditional expression. It's okay to do this because this code would 5256 // be a syntax error in JavaScript (as the second colon shouldn't be there). 5257 if (token() !== SyntaxKind.ColonToken) { 5258 return undefined; 5259 } 5260 } 5261 5262 const node = factory.createArrowFunction(modifiers, typeParameters, parameters, type, equalsGreaterThanToken, body); 5263 return withJSDoc(finishNode(node, pos), hasJSDoc); 5264 } 5265 5266 function parseArrowFunctionExpressionBody(isAsync: boolean, allowReturnTypeInArrowFunction: boolean): Block | Expression { 5267 if (token() === SyntaxKind.OpenBraceToken) { 5268 return parseFunctionBlock(isAsync ? SignatureFlags.Await : SignatureFlags.None); 5269 } 5270 5271 if (token() !== SyntaxKind.SemicolonToken && 5272 token() !== SyntaxKind.FunctionKeyword && 5273 token() !== SyntaxKind.ClassKeyword && 5274 (!inEtsContext() || token() !== SyntaxKind.StructKeyword) && 5275 isStartOfStatement() && 5276 !isStartOfExpressionStatement()) { 5277 // Check if we got a plain statement (i.e. no expression-statements, no function/class expressions/declarations) 5278 // 5279 // Here we try to recover from a potential error situation in the case where the 5280 // user meant to supply a block. For example, if the user wrote: 5281 // 5282 // a => 5283 // let v = 0; 5284 // } 5285 // 5286 // they may be missing an open brace. Check to see if that's the case so we can 5287 // try to recover better. If we don't do this, then the next close curly we see may end 5288 // up preemptively closing the containing construct. 5289 // 5290 // Note: even when 'IgnoreMissingOpenBrace' is passed, parseBody will still error. 5291 return parseFunctionBlock(SignatureFlags.IgnoreMissingOpenBrace | (isAsync ? SignatureFlags.Await : SignatureFlags.None)); 5292 } 5293 5294 const savedTopLevel = topLevel; 5295 topLevel = false; 5296 const node = isAsync 5297 ? doInAwaitContext(() => parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction)) 5298 : doOutsideOfAwaitContext(() => parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction)); 5299 topLevel = savedTopLevel; 5300 return node; 5301 } 5302 5303 function parseConditionalExpressionRest(leftOperand: Expression, pos: number, allowReturnTypeInArrowFunction: boolean): Expression { 5304 // Note: we are passed in an expression which was produced from parseBinaryExpressionOrHigher. 5305 const questionToken = parseOptionalToken(SyntaxKind.QuestionToken); 5306 if (!questionToken) { 5307 return leftOperand; 5308 } 5309 5310 // Note: we explicitly 'allowIn' in the whenTrue part of the condition expression, and 5311 // we do not that for the 'whenFalse' part. 5312 let colonToken; 5313 return finishNode( 5314 factory.createConditionalExpression( 5315 leftOperand, 5316 questionToken, 5317 doOutsideOfContext(disallowInAndDecoratorContext, () => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ false)), 5318 colonToken = parseExpectedToken(SyntaxKind.ColonToken), 5319 nodeIsPresent(colonToken) 5320 ? parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction) 5321 : createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, tokenToString(SyntaxKind.ColonToken)) 5322 ), 5323 pos 5324 ); 5325 } 5326 5327 function parseBinaryExpressionOrHigher(precedence: OperatorPrecedence): Expression { 5328 const pos = getNodePos(); 5329 const leftOperand = parseUnaryExpressionOrHigher(); 5330 return parseBinaryExpressionRest(precedence, leftOperand, pos); 5331 } 5332 5333 function isInOrOfKeyword(t: SyntaxKind) { 5334 return t === SyntaxKind.InKeyword || t === SyntaxKind.OfKeyword; 5335 } 5336 5337 function parseBinaryExpressionRest(precedence: OperatorPrecedence, leftOperand: Expression, pos: number): Expression { 5338 while (true) { 5339 // We either have a binary operator here, or we're finished. We call 5340 // reScanGreaterToken so that we merge token sequences like > and = into >= 5341 5342 reScanGreaterToken(); 5343 const newPrecedence = getBinaryOperatorPrecedence(token()); 5344 5345 // Check the precedence to see if we should "take" this operator 5346 // - For left associative operator (all operator but **), consume the operator, 5347 // recursively call the function below, and parse binaryExpression as a rightOperand 5348 // of the caller if the new precedence of the operator is greater then or equal to the current precedence. 5349 // For example: 5350 // a - b - c; 5351 // ^token; leftOperand = b. Return b to the caller as a rightOperand 5352 // a * b - c 5353 // ^token; leftOperand = b. Return b to the caller as a rightOperand 5354 // a - b * c; 5355 // ^token; leftOperand = b. Return b * c to the caller as a rightOperand 5356 // - For right associative operator (**), consume the operator, recursively call the function 5357 // and parse binaryExpression as a rightOperand of the caller if the new precedence of 5358 // the operator is strictly grater than the current precedence 5359 // For example: 5360 // a ** b ** c; 5361 // ^^token; leftOperand = b. Return b ** c to the caller as a rightOperand 5362 // a - b ** c; 5363 // ^^token; leftOperand = b. Return b ** c to the caller as a rightOperand 5364 // a ** b - c 5365 // ^token; leftOperand = b. Return b to the caller as a rightOperand 5366 const consumeCurrentOperator = token() === SyntaxKind.AsteriskAsteriskToken ? 5367 newPrecedence >= precedence : 5368 newPrecedence > precedence; 5369 5370 if (!consumeCurrentOperator) { 5371 break; 5372 } 5373 5374 if (token() === SyntaxKind.InKeyword && inDisallowInContext()) { 5375 break; 5376 } 5377 5378 if (token() === SyntaxKind.AsKeyword || token() === SyntaxKind.SatisfiesKeyword) { 5379 // Make sure we *do* perform ASI for constructs like this: 5380 // var x = foo 5381 // as (Bar) 5382 // This should be parsed as an initialized variable, followed 5383 // by a function call to 'as' with the argument 'Bar' 5384 if (scanner.hasPrecedingLineBreak()) { 5385 break; 5386 } 5387 else { 5388 const keywordKind = token(); 5389 nextToken(); 5390 leftOperand = keywordKind === SyntaxKind.SatisfiesKeyword ? makeSatisfiesExpression(leftOperand, parseType()) : 5391 makeAsExpression(leftOperand, parseType()); 5392 } 5393 } 5394 else { 5395 leftOperand = makeBinaryExpression(leftOperand, parseTokenNode(), parseBinaryExpressionOrHigher(newPrecedence), pos); 5396 } 5397 } 5398 5399 return leftOperand; 5400 } 5401 5402 function isBinaryOperator() { 5403 if (inDisallowInContext() && token() === SyntaxKind.InKeyword) { 5404 return false; 5405 } 5406 5407 return getBinaryOperatorPrecedence(token()) > 0; 5408 } 5409 5410 function makeSatisfiesExpression(left: Expression, right: TypeNode): SatisfiesExpression { 5411 return finishNode(factory.createSatisfiesExpression(left, right), left.pos); 5412 } 5413 5414 function makeBinaryExpression(left: Expression, operatorToken: BinaryOperatorToken, right: Expression, pos: number): BinaryExpression { 5415 return finishNode(factory.createBinaryExpression(left, operatorToken, right), pos); 5416 } 5417 5418 function makeAsExpression(left: Expression, right: TypeNode): AsExpression { 5419 return finishNode(factory.createAsExpression(left, right), left.pos); 5420 } 5421 5422 function parsePrefixUnaryExpression() { 5423 const pos = getNodePos(); 5424 return finishNode(factory.createPrefixUnaryExpression(token() as PrefixUnaryOperator, nextTokenAnd(parseSimpleUnaryExpression)), pos); 5425 } 5426 5427 function parseDeleteExpression() { 5428 const pos = getNodePos(); 5429 return finishNode(factory.createDeleteExpression(nextTokenAnd(parseSimpleUnaryExpression)), pos); 5430 } 5431 5432 function parseTypeOfExpression() { 5433 const pos = getNodePos(); 5434 return finishNode(factory.createTypeOfExpression(nextTokenAnd(parseSimpleUnaryExpression)), pos); 5435 } 5436 5437 function parseVoidExpression() { 5438 const pos = getNodePos(); 5439 return finishNode(factory.createVoidExpression(nextTokenAnd(parseSimpleUnaryExpression)), pos); 5440 } 5441 5442 function isAwaitExpression(): boolean { 5443 if (token() === SyntaxKind.AwaitKeyword) { 5444 if (inAwaitContext()) { 5445 return true; 5446 } 5447 5448 // here we are using similar heuristics as 'isYieldExpression' 5449 return lookAhead(nextTokenIsIdentifierOrKeywordOrLiteralOnSameLine); 5450 } 5451 5452 return false; 5453 } 5454 5455 function parseAwaitExpression() { 5456 const pos = getNodePos(); 5457 return finishNode(factory.createAwaitExpression(nextTokenAnd(parseSimpleUnaryExpression)), pos); 5458 } 5459 5460 /** 5461 * Parse ES7 exponential expression and await expression 5462 * 5463 * ES7 ExponentiationExpression: 5464 * 1) UnaryExpression[?Yield] 5465 * 2) UpdateExpression[?Yield] ** ExponentiationExpression[?Yield] 5466 * 5467 */ 5468 function parseUnaryExpressionOrHigher(): UnaryExpression | BinaryExpression { 5469 /** 5470 * ES7 UpdateExpression: 5471 * 1) LeftHandSideExpression[?Yield] 5472 * 2) LeftHandSideExpression[?Yield][no LineTerminator here]++ 5473 * 3) LeftHandSideExpression[?Yield][no LineTerminator here]-- 5474 * 4) ++UnaryExpression[?Yield] 5475 * 5) --UnaryExpression[?Yield] 5476 */ 5477 if (isUpdateExpression()) { 5478 const pos = getNodePos(); 5479 const updateExpression = parseUpdateExpression(); 5480 return token() === SyntaxKind.AsteriskAsteriskToken ? 5481 parseBinaryExpressionRest(getBinaryOperatorPrecedence(token()), updateExpression, pos) as BinaryExpression : 5482 updateExpression; 5483 } 5484 5485 /** 5486 * ES7 UnaryExpression: 5487 * 1) UpdateExpression[?yield] 5488 * 2) delete UpdateExpression[?yield] 5489 * 3) void UpdateExpression[?yield] 5490 * 4) typeof UpdateExpression[?yield] 5491 * 5) + UpdateExpression[?yield] 5492 * 6) - UpdateExpression[?yield] 5493 * 7) ~ UpdateExpression[?yield] 5494 * 8) ! UpdateExpression[?yield] 5495 */ 5496 const unaryOperator = token(); 5497 const simpleUnaryExpression = parseSimpleUnaryExpression(); 5498 if (token() === SyntaxKind.AsteriskAsteriskToken) { 5499 const pos = skipTrivia(sourceText, simpleUnaryExpression.pos); 5500 const { end } = simpleUnaryExpression; 5501 if (simpleUnaryExpression.kind === SyntaxKind.TypeAssertionExpression) { 5502 parseErrorAt(pos, end, Diagnostics.A_type_assertion_expression_is_not_allowed_in_the_left_hand_side_of_an_exponentiation_expression_Consider_enclosing_the_expression_in_parentheses); 5503 } 5504 else { 5505 parseErrorAt(pos, end, Diagnostics.An_unary_expression_with_the_0_operator_is_not_allowed_in_the_left_hand_side_of_an_exponentiation_expression_Consider_enclosing_the_expression_in_parentheses, tokenToString(unaryOperator)); 5506 } 5507 } 5508 return simpleUnaryExpression; 5509 } 5510 5511 /** 5512 * Parse ES7 simple-unary expression or higher: 5513 * 5514 * ES7 UnaryExpression: 5515 * 1) UpdateExpression[?yield] 5516 * 2) delete UnaryExpression[?yield] 5517 * 3) void UnaryExpression[?yield] 5518 * 4) typeof UnaryExpression[?yield] 5519 * 5) + UnaryExpression[?yield] 5520 * 6) - UnaryExpression[?yield] 5521 * 7) ~ UnaryExpression[?yield] 5522 * 8) ! UnaryExpression[?yield] 5523 * 9) [+Await] await UnaryExpression[?yield] 5524 */ 5525 function parseSimpleUnaryExpression(): UnaryExpression { 5526 switch (token()) { 5527 case SyntaxKind.PlusToken: 5528 case SyntaxKind.MinusToken: 5529 case SyntaxKind.TildeToken: 5530 case SyntaxKind.ExclamationToken: 5531 return parsePrefixUnaryExpression(); 5532 case SyntaxKind.DeleteKeyword: 5533 return parseDeleteExpression(); 5534 case SyntaxKind.TypeOfKeyword: 5535 return parseTypeOfExpression(); 5536 case SyntaxKind.VoidKeyword: 5537 return parseVoidExpression(); 5538 case SyntaxKind.LessThanToken: 5539 // This is modified UnaryExpression grammar in TypeScript 5540 // UnaryExpression (modified): 5541 // < type > UnaryExpression 5542 return parseTypeAssertion(); 5543 case SyntaxKind.AwaitKeyword: 5544 if (isAwaitExpression()) { 5545 return parseAwaitExpression(); 5546 } 5547 // falls through 5548 default: 5549 return parseUpdateExpression(); 5550 } 5551 } 5552 5553 /** 5554 * Check if the current token can possibly be an ES7 increment expression. 5555 * 5556 * ES7 UpdateExpression: 5557 * LeftHandSideExpression[?Yield] 5558 * LeftHandSideExpression[?Yield][no LineTerminator here]++ 5559 * LeftHandSideExpression[?Yield][no LineTerminator here]-- 5560 * ++LeftHandSideExpression[?Yield] 5561 * --LeftHandSideExpression[?Yield] 5562 */ 5563 function isUpdateExpression(): boolean { 5564 // This function is called inside parseUnaryExpression to decide 5565 // whether to call parseSimpleUnaryExpression or call parseUpdateExpression directly 5566 switch (token()) { 5567 case SyntaxKind.PlusToken: 5568 case SyntaxKind.MinusToken: 5569 case SyntaxKind.TildeToken: 5570 case SyntaxKind.ExclamationToken: 5571 case SyntaxKind.DeleteKeyword: 5572 case SyntaxKind.TypeOfKeyword: 5573 case SyntaxKind.VoidKeyword: 5574 case SyntaxKind.AwaitKeyword: 5575 return false; 5576 case SyntaxKind.LessThanToken: 5577 // If we are not in JSX context, we are parsing TypeAssertion which is an UnaryExpression 5578 if (languageVariant !== LanguageVariant.JSX) { 5579 return false; 5580 } 5581 // We are in JSX context and the token is part of JSXElement. 5582 // falls through 5583 default: 5584 return true; 5585 } 5586 } 5587 5588 /** 5589 * Parse ES7 UpdateExpression. UpdateExpression is used instead of ES6's PostFixExpression. 5590 * 5591 * ES7 UpdateExpression[yield]: 5592 * 1) LeftHandSideExpression[?yield] 5593 * 2) LeftHandSideExpression[?yield] [[no LineTerminator here]]++ 5594 * 3) LeftHandSideExpression[?yield] [[no LineTerminator here]]-- 5595 * 4) ++LeftHandSideExpression[?yield] 5596 * 5) --LeftHandSideExpression[?yield] 5597 * In TypeScript (2), (3) are parsed as PostfixUnaryExpression. (4), (5) are parsed as PrefixUnaryExpression 5598 */ 5599 function parseUpdateExpression(): UpdateExpression { 5600 if (token() === SyntaxKind.PlusPlusToken || token() === SyntaxKind.MinusMinusToken) { 5601 const pos = getNodePos(); 5602 return finishNode(factory.createPrefixUnaryExpression(token() as PrefixUnaryOperator, nextTokenAnd(parseLeftHandSideExpressionOrHigher)), pos); 5603 } 5604 else if (languageVariant === LanguageVariant.JSX && token() === SyntaxKind.LessThanToken && lookAhead(nextTokenIsIdentifierOrKeywordOrGreaterThan)) { 5605 // JSXElement is part of primaryExpression 5606 return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true); 5607 } 5608 5609 const expression = parseLeftHandSideExpressionOrHigher(); 5610 5611 Debug.assert(isLeftHandSideExpression(expression)); 5612 if ((token() === SyntaxKind.PlusPlusToken || token() === SyntaxKind.MinusMinusToken) && !scanner.hasPrecedingLineBreak()) { 5613 const operator = token() as PostfixUnaryOperator; 5614 nextToken(); 5615 return finishNode(factory.createPostfixUnaryExpression(expression, operator), expression.pos); 5616 } 5617 5618 return expression; 5619 } 5620 5621 function parseLeftHandSideExpressionOrHigher(): LeftHandSideExpression { 5622 // Original Ecma: 5623 // LeftHandSideExpression: See 11.2 5624 // NewExpression 5625 // CallExpression 5626 // 5627 // Our simplification: 5628 // 5629 // LeftHandSideExpression: See 11.2 5630 // MemberExpression 5631 // CallExpression 5632 // 5633 // See comment in parseMemberExpressionOrHigher on how we replaced NewExpression with 5634 // MemberExpression to make our lives easier. 5635 // 5636 // to best understand the below code, it's important to see how CallExpression expands 5637 // out into its own productions: 5638 // 5639 // CallExpression: 5640 // MemberExpression Arguments 5641 // CallExpression Arguments 5642 // CallExpression[Expression] 5643 // CallExpression.IdentifierName 5644 // import (AssignmentExpression) 5645 // super Arguments 5646 // super.IdentifierName 5647 // 5648 // Because of the recursion in these calls, we need to bottom out first. There are three 5649 // bottom out states we can run into: 1) We see 'super' which must start either of 5650 // the last two CallExpression productions. 2) We see 'import' which must start import call. 5651 // 3)we have a MemberExpression which either completes the LeftHandSideExpression, 5652 // or starts the beginning of the first four CallExpression productions. 5653 const pos = getNodePos(); 5654 let expression: MemberExpression; 5655 if (token() === SyntaxKind.ImportKeyword) { 5656 if (lookAhead(nextTokenIsOpenParenOrLessThan)) { 5657 // We don't want to eagerly consume all import keyword as import call expression so we look ahead to find "(" 5658 // For example: 5659 // var foo3 = require("subfolder 5660 // import * as foo1 from "module-from-node 5661 // We want this import to be a statement rather than import call expression 5662 sourceFlags |= NodeFlags.PossiblyContainsDynamicImport; 5663 expression = parseTokenNode<PrimaryExpression>(); 5664 } 5665 else if (lookAhead(nextTokenIsDot)) { 5666 // This is an 'import.*' metaproperty (i.e. 'import.meta') 5667 nextToken(); // advance past the 'import' 5668 nextToken(); // advance past the dot 5669 expression = finishNode(factory.createMetaProperty(SyntaxKind.ImportKeyword, parseIdentifierName()), pos); 5670 sourceFlags |= NodeFlags.PossiblyContainsImportMeta; 5671 } 5672 else { 5673 expression = parseMemberExpressionOrHigher(); 5674 } 5675 } 5676 else { 5677 expression = token() === SyntaxKind.SuperKeyword ? parseSuperExpression() : parseMemberExpressionOrHigher(); 5678 } 5679 5680 // Now, we *may* be complete. However, we might have consumed the start of a 5681 // CallExpression or OptionalExpression. As such, we need to consume the rest 5682 // of it here to be complete. 5683 return parseCallExpressionRest(pos, expression); 5684 } 5685 5686 function parseMemberExpressionOrHigher(): MemberExpression { 5687 // Note: to make our lives simpler, we decompose the NewExpression productions and 5688 // place ObjectCreationExpression and FunctionExpression into PrimaryExpression. 5689 // like so: 5690 // 5691 // PrimaryExpression : See 11.1 5692 // this 5693 // Identifier 5694 // Literal 5695 // ArrayLiteral 5696 // ObjectLiteral 5697 // (Expression) 5698 // FunctionExpression 5699 // new MemberExpression Arguments? 5700 // 5701 // MemberExpression : See 11.2 5702 // PrimaryExpression 5703 // MemberExpression[Expression] 5704 // MemberExpression.IdentifierName 5705 // 5706 // CallExpression : See 11.2 5707 // MemberExpression 5708 // CallExpression Arguments 5709 // CallExpression[Expression] 5710 // CallExpression.IdentifierName 5711 // 5712 // Technically this is ambiguous. i.e. CallExpression defines: 5713 // 5714 // CallExpression: 5715 // CallExpression Arguments 5716 // 5717 // If you see: "new Foo()" 5718 // 5719 // Then that could be treated as a single ObjectCreationExpression, or it could be 5720 // treated as the invocation of "new Foo". We disambiguate that in code (to match 5721 // the original grammar) by making sure that if we see an ObjectCreationExpression 5722 // we always consume arguments if they are there. So we treat "new Foo()" as an 5723 // object creation only, and not at all as an invocation. Another way to think 5724 // about this is that for every "new" that we see, we will consume an argument list if 5725 // it is there as part of the *associated* object creation node. Any additional 5726 // argument lists we see, will become invocation expressions. 5727 // 5728 // Because there are no other places in the grammar now that refer to FunctionExpression 5729 // or ObjectCreationExpression, it is safe to push down into the PrimaryExpression 5730 // production. 5731 // 5732 // Because CallExpression and MemberExpression are left recursive, we need to bottom out 5733 // of the recursion immediately. So we parse out a primary expression to start with. 5734 const pos = getNodePos(); 5735 let expression; 5736 5737 if (inEtsExtendComponentsContext() && extendEtsComponentDeclaration && token() === SyntaxKind.DotToken) { 5738 expression = finishVirtualNode(factory.createIdentifier(extendEtsComponentDeclaration.instance, /*typeArguments*/ undefined, SyntaxKind.Identifier), pos, pos); 5739 } 5740 else if (inEtsStylesComponentsContext() && stylesEtsComponentDeclaration && token() === SyntaxKind.DotToken) { 5741 expression = finishVirtualNode(factory.createIdentifier(stylesEtsComponentDeclaration.instance, /*typeArguments*/ undefined, SyntaxKind.Identifier), pos, pos); 5742 } 5743 else if (inEtsStateStylesContext() && stateStylesRootNode && token() === SyntaxKind.DotToken) { 5744 expression = finishVirtualNode(factory.createIdentifier(`${stateStylesRootNode}Instance`, /*typeArguments*/ undefined, SyntaxKind.Identifier), pos, pos); 5745 } 5746 else { 5747 expression = parsePrimaryExpression(); 5748 } 5749 return parseMemberExpressionRest(pos, expression, /*allowOptionalChain*/ true); 5750 } 5751 5752 function parseSuperExpression(): MemberExpression { 5753 const pos = getNodePos(); 5754 let expression = parseTokenNode<MemberExpression>(); 5755 if (token() === SyntaxKind.LessThanToken) { 5756 const startPos = getNodePos(); 5757 const typeArguments = tryParse(parseTypeArgumentsInExpression); 5758 if (typeArguments !== undefined) { 5759 parseErrorAt(startPos, getNodePos(), Diagnostics.super_may_not_use_type_arguments); 5760 if (!isTemplateStartOfTaggedTemplate()) { 5761 expression = factory.createExpressionWithTypeArguments(expression, typeArguments); 5762 } 5763 } 5764 } 5765 5766 if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.DotToken || token() === SyntaxKind.OpenBracketToken) { 5767 return expression; 5768 } 5769 5770 // If we have seen "super" it must be followed by '(' or '.'. 5771 // If it wasn't then just try to parse out a '.' and report an error. 5772 parseExpectedToken(SyntaxKind.DotToken, Diagnostics.super_must_be_followed_by_an_argument_list_or_member_access); 5773 // private names will never work with `super` (`super.#foo`), but that's a semantic error, not syntactic 5774 return finishNode(factory.createPropertyAccessExpression(expression, parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ true)), pos); 5775 } 5776 5777 function parseJsxElementOrSelfClosingElementOrFragment(inExpressionContext: boolean, topInvalidNodePosition?: number, openingTag?: JsxOpeningElement | JsxOpeningFragment): JsxElement | JsxSelfClosingElement | JsxFragment { 5778 const pos = getNodePos(); 5779 const opening = parseJsxOpeningOrSelfClosingElementOrOpeningFragment(inExpressionContext); 5780 let result: JsxElement | JsxSelfClosingElement | JsxFragment; 5781 if (opening.kind === SyntaxKind.JsxOpeningElement) { 5782 let children = parseJsxChildren(opening); 5783 let closingElement: JsxClosingElement; 5784 5785 const lastChild: JsxChild | undefined = children[children.length - 1]; 5786 if (lastChild?.kind === SyntaxKind.JsxElement 5787 && !tagNamesAreEquivalent(lastChild.openingElement.tagName, lastChild.closingElement.tagName) 5788 && tagNamesAreEquivalent(opening.tagName, lastChild.closingElement.tagName)) { 5789 // when an unclosed JsxOpeningElement incorrectly parses its parent's JsxClosingElement, 5790 // restructure (<div>(...<span>...</div>)) --> (<div>(...<span>...</>)</div>) 5791 // (no need to error; the parent will error) 5792 const end = lastChild.children.end; 5793 const newLast = finishNode(factory.createJsxElement( 5794 lastChild.openingElement, 5795 lastChild.children, 5796 finishNode(factory.createJsxClosingElement(finishNode(factory.createIdentifier(""), end, end)), end, end)), 5797 lastChild.openingElement.pos, 5798 end); 5799 5800 children = createNodeArray([...children.slice(0, children.length - 1), newLast], children.pos, end); 5801 closingElement = lastChild.closingElement; 5802 } 5803 else { 5804 closingElement = parseJsxClosingElement(opening, inExpressionContext); 5805 if (!tagNamesAreEquivalent(opening.tagName, closingElement.tagName)) { 5806 if (openingTag && isJsxOpeningElement(openingTag) && tagNamesAreEquivalent(closingElement.tagName, openingTag.tagName)) { 5807 // opening incorrectly matched with its parent's closing -- put error on opening 5808 parseErrorAtRange(opening.tagName, Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, getTextOfNodeFromSourceText(sourceText, opening.tagName)); 5809 } 5810 else { 5811 // other opening/closing mismatches -- put error on closing 5812 parseErrorAtRange(closingElement.tagName, Diagnostics.Expected_corresponding_JSX_closing_tag_for_0, getTextOfNodeFromSourceText(sourceText, opening.tagName)); 5813 } 5814 } 5815 } 5816 result = finishNode(factory.createJsxElement(opening, children, closingElement), pos); 5817 } 5818 else if (opening.kind === SyntaxKind.JsxOpeningFragment) { 5819 result = finishNode(factory.createJsxFragment(opening, parseJsxChildren(opening), parseJsxClosingFragment(inExpressionContext)), pos); 5820 } 5821 else { 5822 Debug.assert(opening.kind === SyntaxKind.JsxSelfClosingElement); 5823 // Nothing else to do for self-closing elements 5824 result = opening; 5825 } 5826 5827 // If the user writes the invalid code '<div></div><div></div>' in an expression context (i.e. not wrapped in 5828 // an enclosing tag), we'll naively try to parse ^ this as a 'less than' operator and the remainder of the tag 5829 // as garbage, which will cause the formatter to badly mangle the JSX. Perform a speculative parse of a JSX 5830 // element if we see a < token so that we can wrap it in a synthetic binary expression so the formatter 5831 // does less damage and we can report a better error. 5832 // Since JSX elements are invalid < operands anyway, this lookahead parse will only occur in error scenarios 5833 // of one sort or another. 5834 if (inExpressionContext && token() === SyntaxKind.LessThanToken) { 5835 const topBadPos = typeof topInvalidNodePosition === "undefined" ? result.pos : topInvalidNodePosition; 5836 const invalidElement = tryParse(() => parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true, topBadPos)); 5837 if (invalidElement) { 5838 const operatorToken = createMissingNode(SyntaxKind.CommaToken, /*reportAtCurrentPosition*/ false); 5839 setTextRangePosWidth(operatorToken, invalidElement.pos, 0); 5840 parseErrorAt(skipTrivia(sourceText, topBadPos), invalidElement.end, Diagnostics.JSX_expressions_must_have_one_parent_element); 5841 return finishNode(factory.createBinaryExpression(result, operatorToken as Token<SyntaxKind.CommaToken>, invalidElement), pos) as Node as JsxElement; 5842 } 5843 } 5844 5845 return result; 5846 } 5847 5848 function parseJsxText(): JsxText { 5849 const pos = getNodePos(); 5850 const node = factory.createJsxText(scanner.getTokenValue(), currentToken === SyntaxKind.JsxTextAllWhiteSpaces); 5851 currentToken = scanner.scanJsxToken(); 5852 return finishNode(node, pos); 5853 } 5854 5855 function parseJsxChild(openingTag: JsxOpeningElement | JsxOpeningFragment, token: JsxTokenSyntaxKind): JsxChild | undefined { 5856 switch (token) { 5857 case SyntaxKind.EndOfFileToken: 5858 // If we hit EOF, issue the error at the tag that lacks the closing element 5859 // rather than at the end of the file (which is useless) 5860 if (isJsxOpeningFragment(openingTag)) { 5861 parseErrorAtRange(openingTag, Diagnostics.JSX_fragment_has_no_corresponding_closing_tag); 5862 } 5863 else { 5864 // We want the error span to cover only 'Foo.Bar' in < Foo.Bar > 5865 // or to cover only 'Foo' in < Foo > 5866 const tag = openingTag.tagName; 5867 const start = skipTrivia(sourceText, tag.pos); 5868 parseErrorAt(start, tag.end, Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, getTextOfNodeFromSourceText(sourceText, openingTag.tagName)); 5869 } 5870 return undefined; 5871 case SyntaxKind.LessThanSlashToken: 5872 case SyntaxKind.ConflictMarkerTrivia: 5873 return undefined; 5874 case SyntaxKind.JsxText: 5875 case SyntaxKind.JsxTextAllWhiteSpaces: 5876 return parseJsxText(); 5877 case SyntaxKind.OpenBraceToken: 5878 return parseJsxExpression(/*inExpressionContext*/ false); 5879 case SyntaxKind.LessThanToken: 5880 return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ false, /*topInvalidNodePosition*/ undefined, openingTag); 5881 default: 5882 return Debug.assertNever(token); 5883 } 5884 } 5885 5886 function parseJsxChildren(openingTag: JsxOpeningElement | JsxOpeningFragment): NodeArray<JsxChild> { 5887 const list = []; 5888 const listPos = getNodePos(); 5889 const saveParsingContext = parsingContext; 5890 parsingContext |= 1 << ParsingContext.JsxChildren; 5891 5892 while (true) { 5893 const child = parseJsxChild(openingTag, currentToken = scanner.reScanJsxToken()); 5894 if (!child) break; 5895 list.push(child); 5896 if (isJsxOpeningElement(openingTag) 5897 && child?.kind === SyntaxKind.JsxElement 5898 && !tagNamesAreEquivalent(child.openingElement.tagName, child.closingElement.tagName) 5899 && tagNamesAreEquivalent(openingTag.tagName, child.closingElement.tagName)) { 5900 // stop after parsing a mismatched child like <div>...(<span></div>) in order to reattach the </div> higher 5901 break; 5902 } 5903 } 5904 5905 parsingContext = saveParsingContext; 5906 return createNodeArray(list, listPos); 5907 } 5908 5909 function parseJsxAttributes(): JsxAttributes { 5910 const pos = getNodePos(); 5911 return finishNode(factory.createJsxAttributes(parseList(ParsingContext.JsxAttributes, parseJsxAttribute)), pos); 5912 } 5913 5914 function parseJsxOpeningOrSelfClosingElementOrOpeningFragment(inExpressionContext: boolean): JsxOpeningElement | JsxSelfClosingElement | JsxOpeningFragment { 5915 const pos = getNodePos(); 5916 5917 parseExpected(SyntaxKind.LessThanToken); 5918 5919 if (token() === SyntaxKind.GreaterThanToken) { 5920 // See below for explanation of scanJsxText 5921 scanJsxText(); 5922 return finishNode(factory.createJsxOpeningFragment(), pos); 5923 } 5924 const tagName = parseJsxElementName(); 5925 const typeArguments = (contextFlags & NodeFlags.JavaScriptFile) === 0 ? tryParseTypeArguments() : undefined; 5926 const attributes = parseJsxAttributes(); 5927 5928 let node: JsxOpeningLikeElement; 5929 5930 if (token() === SyntaxKind.GreaterThanToken) { 5931 // Closing tag, so scan the immediately-following text with the JSX scanning instead 5932 // of regular scanning to avoid treating illegal characters (e.g. '#') as immediate 5933 // scanning errors 5934 scanJsxText(); 5935 node = factory.createJsxOpeningElement(tagName, typeArguments, attributes); 5936 } 5937 else { 5938 parseExpected(SyntaxKind.SlashToken); 5939 if (parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*shouldAdvance*/ false)) { 5940 // manually advance the scanner in order to look for jsx text inside jsx 5941 if (inExpressionContext) { 5942 nextToken(); 5943 } 5944 else { 5945 scanJsxText(); 5946 } 5947 } 5948 node = factory.createJsxSelfClosingElement(tagName, typeArguments, attributes); 5949 } 5950 5951 return finishNode(node, pos); 5952 } 5953 5954 function parseJsxElementName(): JsxTagNameExpression { 5955 const pos = getNodePos(); 5956 scanJsxIdentifier(); 5957 // JsxElement can have name in the form of 5958 // propertyAccessExpression 5959 // primaryExpression in the form of an identifier and "this" keyword 5960 // We can't just simply use parseLeftHandSideExpressionOrHigher because then we will start consider class,function etc as a keyword 5961 // We only want to consider "this" as a primaryExpression 5962 let expression: JsxTagNameExpression = token() === SyntaxKind.ThisKeyword ? 5963 parseTokenNode<ThisExpression>() : parseIdentifierName(); 5964 while (parseOptional(SyntaxKind.DotToken)) { 5965 expression = finishNode(factory.createPropertyAccessExpression(expression, parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ false)), pos) as JsxTagNamePropertyAccess; 5966 } 5967 return expression; 5968 } 5969 5970 function parseJsxExpression(inExpressionContext: boolean): JsxExpression | undefined { 5971 const pos = getNodePos(); 5972 if (!parseExpected(SyntaxKind.OpenBraceToken)) { 5973 return undefined; 5974 } 5975 5976 let dotDotDotToken: DotDotDotToken | undefined; 5977 let expression: Expression | undefined; 5978 if (token() !== SyntaxKind.CloseBraceToken) { 5979 dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); 5980 // Only an AssignmentExpression is valid here per the JSX spec, 5981 // but we can unambiguously parse a comma sequence and provide 5982 // a better error message in grammar checking. 5983 expression = parseExpression(); 5984 } 5985 if (inExpressionContext) { 5986 parseExpected(SyntaxKind.CloseBraceToken); 5987 } 5988 else { 5989 if (parseExpected(SyntaxKind.CloseBraceToken, /*message*/ undefined, /*shouldAdvance*/ false)) { 5990 scanJsxText(); 5991 } 5992 } 5993 5994 return finishNode(factory.createJsxExpression(dotDotDotToken, expression), pos); 5995 } 5996 5997 function parseJsxAttribute(): JsxAttribute | JsxSpreadAttribute { 5998 if (token() === SyntaxKind.OpenBraceToken) { 5999 return parseJsxSpreadAttribute(); 6000 } 6001 6002 scanJsxIdentifier(); 6003 const pos = getNodePos(); 6004 return finishNode(factory.createJsxAttribute(parseIdentifierName(), parseJsxAttributeValue()), pos); 6005 } 6006 6007 function parseJsxAttributeValue(): JsxAttributeValue | undefined { 6008 if (token() === SyntaxKind.EqualsToken) { 6009 if (scanJsxAttributeValue() === SyntaxKind.StringLiteral) { 6010 return parseLiteralNode() as StringLiteral; 6011 } 6012 if (token() === SyntaxKind.OpenBraceToken) { 6013 return parseJsxExpression(/*inExpressionContext*/ true); 6014 } 6015 if (token() === SyntaxKind.LessThanToken) { 6016 return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true); 6017 } 6018 parseErrorAtCurrentToken(Diagnostics.or_JSX_element_expected); 6019 } 6020 return undefined; 6021 } 6022 6023 function parseJsxSpreadAttribute(): JsxSpreadAttribute { 6024 const pos = getNodePos(); 6025 parseExpected(SyntaxKind.OpenBraceToken); 6026 parseExpected(SyntaxKind.DotDotDotToken); 6027 const expression = parseExpression(); 6028 parseExpected(SyntaxKind.CloseBraceToken); 6029 return finishNode(factory.createJsxSpreadAttribute(expression), pos); 6030 } 6031 6032 function parseJsxClosingElement(open: JsxOpeningElement, inExpressionContext: boolean): JsxClosingElement { 6033 const pos = getNodePos(); 6034 parseExpected(SyntaxKind.LessThanSlashToken); 6035 const tagName = parseJsxElementName(); 6036 if (parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*shouldAdvance*/ false)) { 6037 // manually advance the scanner in order to look for jsx text inside jsx 6038 if (inExpressionContext || !tagNamesAreEquivalent(open.tagName, tagName)) { 6039 nextToken(); 6040 } 6041 else { 6042 scanJsxText(); 6043 } 6044 } 6045 return finishNode(factory.createJsxClosingElement(tagName), pos); 6046 } 6047 6048 function parseJsxClosingFragment(inExpressionContext: boolean): JsxClosingFragment { 6049 const pos = getNodePos(); 6050 parseExpected(SyntaxKind.LessThanSlashToken); 6051 if (tokenIsIdentifierOrKeyword(token())) { 6052 parseErrorAtRange(parseJsxElementName(), Diagnostics.Expected_corresponding_closing_tag_for_JSX_fragment); 6053 } 6054 if (parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*shouldAdvance*/ false)) { 6055 // manually advance the scanner in order to look for jsx text inside jsx 6056 if (inExpressionContext) { 6057 nextToken(); 6058 } 6059 else { 6060 scanJsxText(); 6061 } 6062 } 6063 return finishNode(factory.createJsxJsxClosingFragment(), pos); 6064 } 6065 6066 function parseTypeAssertion(): TypeAssertion { 6067 const pos = getNodePos(); 6068 parseExpected(SyntaxKind.LessThanToken); 6069 const type = parseType(); 6070 parseExpected(SyntaxKind.GreaterThanToken); 6071 const expression = parseSimpleUnaryExpression(); 6072 return finishNode(factory.createTypeAssertion(type, expression), pos); 6073 } 6074 6075 function nextTokenIsIdentifierOrKeywordOrOpenBracketOrTemplate() { 6076 nextToken(); 6077 return tokenIsIdentifierOrKeyword(token()) 6078 || token() === SyntaxKind.OpenBracketToken 6079 || isTemplateStartOfTaggedTemplate(); 6080 } 6081 6082 function isStartOfOptionalPropertyOrElementAccessChain() { 6083 return token() === SyntaxKind.QuestionDotToken 6084 && lookAhead(nextTokenIsIdentifierOrKeywordOrOpenBracketOrTemplate); 6085 } 6086 6087 function tryReparseOptionalChain(node: Expression) { 6088 if (node.flags & NodeFlags.OptionalChain) { 6089 return true; 6090 } 6091 // check for an optional chain in a non-null expression 6092 if (isNonNullExpression(node)) { 6093 let expr = node.expression; 6094 while (isNonNullExpression(expr) && !(expr.flags & NodeFlags.OptionalChain)) { 6095 expr = expr.expression; 6096 } 6097 if (expr.flags & NodeFlags.OptionalChain) { 6098 // this is part of an optional chain. Walk down from `node` to `expression` and set the flag. 6099 while (isNonNullExpression(node)) { 6100 (node as Mutable<NonNullExpression>).flags |= NodeFlags.OptionalChain; 6101 node = node.expression; 6102 } 6103 return true; 6104 } 6105 } 6106 return false; 6107 } 6108 6109 function parsePropertyAccessExpressionRest(pos: number, expression: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined) { 6110 const name = parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ true); 6111 const isOptionalChain = questionDotToken || tryReparseOptionalChain(expression); 6112 const propertyAccess = isOptionalChain ? 6113 factory.createPropertyAccessChain(expression, questionDotToken, name) : 6114 factory.createPropertyAccessExpression(expression, name); 6115 if (isOptionalChain && isPrivateIdentifier(propertyAccess.name)) { 6116 parseErrorAtRange(propertyAccess.name, Diagnostics.An_optional_chain_cannot_contain_private_identifiers); 6117 } 6118 if (isExpressionWithTypeArguments(expression) && expression.typeArguments) { 6119 const pos = expression.typeArguments.pos - 1; 6120 const end = skipTrivia(sourceText, expression.typeArguments.end) + 1; 6121 parseErrorAt(pos, end, Diagnostics.An_instantiation_expression_cannot_be_followed_by_a_property_access); 6122 } 6123 return finishNode(propertyAccess, pos); 6124 } 6125 6126 function parseElementAccessExpressionRest(pos: number, expression: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined) { 6127 let argumentExpression: Expression; 6128 if (token() === SyntaxKind.CloseBracketToken) { 6129 argumentExpression = createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.An_element_access_expression_should_take_an_argument); 6130 } 6131 else { 6132 const argument = allowInAnd(parseExpression); 6133 if (isStringOrNumericLiteralLike(argument)) { 6134 argument.text = internIdentifier(argument.text); 6135 } 6136 argumentExpression = argument; 6137 } 6138 6139 parseExpected(SyntaxKind.CloseBracketToken); 6140 6141 const indexedAccess = questionDotToken || tryReparseOptionalChain(expression) ? 6142 factory.createElementAccessChain(expression, questionDotToken, argumentExpression) : 6143 factory.createElementAccessExpression(expression, argumentExpression); 6144 return finishNode(indexedAccess, pos); 6145 } 6146 6147 function parseMemberExpressionRest(pos: number, expression: LeftHandSideExpression, allowOptionalChain: boolean): MemberExpression { 6148 while (true) { 6149 let questionDotToken: QuestionDotToken | undefined; 6150 let isPropertyAccess = false; 6151 if (allowOptionalChain && isStartOfOptionalPropertyOrElementAccessChain()) { 6152 questionDotToken = parseExpectedToken(SyntaxKind.QuestionDotToken); 6153 isPropertyAccess = tokenIsIdentifierOrKeyword(token()); 6154 } 6155 else { 6156 isPropertyAccess = parseOptional(SyntaxKind.DotToken); 6157 } 6158 6159 if (isPropertyAccess) { 6160 expression = parsePropertyAccessExpressionRest(pos, expression, questionDotToken); 6161 continue; 6162 } 6163 6164 // when in the [Decorator] context, we do not parse ElementAccess as it could be part of a ComputedPropertyName 6165 if ((questionDotToken || !inDecoratorContext()) && parseOptional(SyntaxKind.OpenBracketToken)) { 6166 expression = parseElementAccessExpressionRest(pos, expression, questionDotToken); 6167 continue; 6168 } 6169 6170 if (isTemplateStartOfTaggedTemplate()) { 6171 // Absorb type arguments into TemplateExpression when preceding expression is ExpressionWithTypeArguments 6172 expression = !questionDotToken && expression.kind === SyntaxKind.ExpressionWithTypeArguments ? 6173 parseTaggedTemplateRest(pos, (expression as ExpressionWithTypeArguments).expression, questionDotToken, (expression as ExpressionWithTypeArguments).typeArguments) : 6174 parseTaggedTemplateRest(pos, expression, questionDotToken, /*typeArguments*/ undefined); 6175 continue; 6176 } 6177 6178 if (!questionDotToken) { 6179 if (token() === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak()) { 6180 nextToken(); 6181 expression = finishNode(factory.createNonNullExpression(expression), pos); 6182 continue; 6183 } 6184 const typeArguments = tryParse(parseTypeArgumentsInExpression); 6185 if (typeArguments) { 6186 expression = finishNode(factory.createExpressionWithTypeArguments(expression, typeArguments), pos); 6187 continue; 6188 } 6189 } 6190 6191 return expression as MemberExpression; 6192 } 6193 } 6194 6195 function isTemplateStartOfTaggedTemplate() { 6196 return token() === SyntaxKind.NoSubstitutionTemplateLiteral || token() === SyntaxKind.TemplateHead; 6197 } 6198 6199 function parseTaggedTemplateRest(pos: number, tag: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined, typeArguments: NodeArray<TypeNode> | undefined) { 6200 const tagExpression = factory.createTaggedTemplateExpression( 6201 tag, 6202 typeArguments, 6203 token() === SyntaxKind.NoSubstitutionTemplateLiteral ? 6204 (reScanTemplateHeadOrNoSubstitutionTemplate(), parseLiteralNode() as NoSubstitutionTemplateLiteral) : 6205 parseTemplateExpression(/*isTaggedTemplate*/ true) 6206 ); 6207 if (questionDotToken || tag.flags & NodeFlags.OptionalChain) { 6208 (tagExpression as Mutable<Node>).flags |= NodeFlags.OptionalChain; 6209 } 6210 tagExpression.questionDotToken = questionDotToken; 6211 return finishNode(tagExpression, pos); 6212 } 6213 6214 function parseCallExpressionRest(pos: number, expression: LeftHandSideExpression): LeftHandSideExpression { 6215 let currentNodeName: string | undefined; 6216 while (true) { 6217 expression = parseMemberExpressionRest(pos, expression, /*allowOptionalChain*/ true); 6218 let typeArguments: NodeArray<TypeNode> | undefined; 6219 const questionDotToken = parseOptionalToken(SyntaxKind.QuestionDotToken); 6220 if (questionDotToken) { 6221 typeArguments = tryParse(parseTypeArgumentsInExpression); 6222 if (isTemplateStartOfTaggedTemplate()) { 6223 expression = parseTaggedTemplateRest(pos, expression, questionDotToken, typeArguments); 6224 continue; 6225 } 6226 } 6227 if (typeArguments || token() === SyntaxKind.OpenParenToken) { 6228 // Absorb type arguments into CallExpression when preceding expression is ExpressionWithTypeArguments 6229 if (!questionDotToken && expression.kind === SyntaxKind.ExpressionWithTypeArguments) { 6230 typeArguments = (expression as ExpressionWithTypeArguments).typeArguments; 6231 expression = (expression as ExpressionWithTypeArguments).expression; 6232 } 6233 6234 if (isValidVirtualTypeArgumentsContext() && isPropertyAccessExpression(expression)) { 6235 const [rootNode, type] = getRootComponent(expression, sourceFileCompilerOptions); 6236 if (rootNode && type) { 6237 let rootNodeName = ''; 6238 if (type === 'otherType') { 6239 rootNodeName = 'Common'; 6240 } else { 6241 rootNodeName = (<Identifier>(rootNode.expression)).escapedText.toString(); 6242 } 6243 currentNodeName = getTextOfPropertyName(expression.name).toString(); 6244 if (currentNodeName === sourceFileCompilerOptions?.ets?.styles?.property) { 6245 setEtsStateStylesContext(true); 6246 stateStylesRootNode = rootNodeName; 6247 } 6248 else { 6249 setEtsStateStylesContext(false); 6250 stateStylesRootNode = undefined; 6251 } 6252 const syntaxComponents = sourceFileCompilerOptions?.ets?.syntaxComponents?.attrUICallback?.filter( 6253 (item: any) => item.name === rootNodeName); 6254 if (type === 'callExpressionComponentType' && syntaxComponents && syntaxComponents.length && 6255 syntaxComponents[0]?.attributes?.includes(currentNodeName)) { 6256 setSyntaxComponentContext(true); 6257 } else if (type === 'etsComponentType') { 6258 typeArguments = parseEtsTypeArguments(pos, `${rootNodeName}Attribute`); 6259 } 6260 } 6261 else if (inEtsStateStylesContext() && stateStylesRootNode) { 6262 typeArguments = parseEtsTypeArguments(pos, `${stateStylesRootNode}Attribute`); 6263 } else if (inEtsStylesComponentsContext() || inEtsExtendComponentsContext()) { 6264 const virtualNode = getVirtualEtsComponent(expression); 6265 if (virtualNode) { 6266 let rootNodeName = (<Identifier>(virtualNode.expression)).escapedText.toString(); 6267 currentNodeName = getTextOfPropertyName(expression.name).toString(); 6268 if (currentNodeName === sourceFileCompilerOptions?.ets?.styles?.property) { 6269 setEtsStateStylesContext(true); 6270 rootNodeName = rootNodeName.replace("Instance", ""); 6271 stateStylesRootNode = rootNodeName; 6272 typeArguments = parseEtsTypeArguments(pos, `${rootNodeName}Attribute`); 6273 } 6274 } 6275 } 6276 } 6277 if (isValidVirtualTypeArgumentsContext() && ts.isIdentifier(expression) && 6278 sourceFileCompilerOptions?.ets?.syntaxComponents?.paramsUICallback?.includes(expression.escapedText.toString())) { 6279 setSyntaxComponentContext(true); 6280 } 6281 const argumentList = parseArgumentList(); 6282 const callExpr = questionDotToken || tryReparseOptionalChain(expression) ? 6283 factory.createCallChain(expression, questionDotToken, typeArguments, argumentList) : 6284 factory.createCallExpression(expression, typeArguments, argumentList); 6285 expression = finishNode(callExpr, pos); 6286 continue; 6287 } 6288 if (questionDotToken) { 6289 // We parsed `?.` but then failed to parse anything, so report a missing identifier here. 6290 const name = createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ false, Diagnostics.Identifier_expected); 6291 expression = finishNode(factory.createPropertyAccessChain(expression, questionDotToken, name), pos); 6292 } 6293 break; 6294 } 6295 if (currentNodeName === sourceFileCompilerOptions?.ets?.styles?.property) { 6296 setEtsStateStylesContext(false); 6297 stateStylesRootNode = undefined; 6298 } 6299 return expression; 6300 } 6301 6302 function isValidVirtualTypeArgumentsContext(): boolean { 6303 return inBuildContext() || inBuilderContext() || inEtsStylesComponentsContext() || inEtsExtendComponentsContext(); 6304 } 6305 6306 function parseArgumentList() { 6307 parseExpected(SyntaxKind.OpenParenToken); 6308 const result = parseDelimitedList(ParsingContext.ArgumentExpressions, parseArgumentExpression); 6309 parseExpected(SyntaxKind.CloseParenToken); 6310 return result; 6311 } 6312 6313 function parseTypeArgumentsInExpression() { 6314 if ((contextFlags & NodeFlags.JavaScriptFile) !== 0) { 6315 // TypeArguments must not be parsed in JavaScript files to avoid ambiguity with binary operators. 6316 return undefined; 6317 } 6318 6319 if (reScanLessThanToken() !== SyntaxKind.LessThanToken) { 6320 return undefined; 6321 } 6322 nextToken(); 6323 6324 const typeArguments = parseDelimitedList(ParsingContext.TypeArguments, parseType); 6325 if (reScanGreaterToken() !== SyntaxKind.GreaterThanToken) { 6326 // If it doesn't have the closing `>` then it's definitely not an type argument list. 6327 return undefined; 6328 } 6329 nextToken(); 6330 6331 // We successfully parsed a type argument list. The next token determines whether we want to 6332 // treat it as such. If the type argument list is followed by `(` or a template literal, as in 6333 // `f<number>(42)`, we favor the type argument interpretation even though JavaScript would view 6334 // it as a relational expression. 6335 return typeArguments && canFollowTypeArgumentsInExpression() ? typeArguments : undefined; 6336 } 6337 6338 function canFollowTypeArgumentsInExpression(): boolean { 6339 switch (token()) { 6340 // These tokens can follow a type argument list in a call expression. 6341 case SyntaxKind.OpenParenToken: // foo<x>( 6342 case SyntaxKind.NoSubstitutionTemplateLiteral: // foo<T> `...` 6343 case SyntaxKind.TemplateHead: // foo<T> `...${100}...` 6344 return true; 6345 // A type argument list followed by `<` never makes sense, and a type argument list followed 6346 // by `>` is ambiguous with a (re-scanned) `>>` operator, so we disqualify both. Also, in 6347 // this context, `+` and `-` are unary operators, not binary operators. 6348 case SyntaxKind.LessThanToken: 6349 case SyntaxKind.GreaterThanToken: 6350 case SyntaxKind.PlusToken: 6351 case SyntaxKind.MinusToken: 6352 return false; 6353 } 6354 // We favor the type argument list interpretation when it is immediately followed by 6355 // a line break, a binary operator, or something that can't start an expression. 6356 return scanner.hasPrecedingLineBreak() || isBinaryOperator() || !isStartOfExpression(); 6357 } 6358 6359 function isCurrentTokenAnEtsComponentExpression(): boolean { 6360 if (!inEtsComponentsContext()) { 6361 return false; 6362 } 6363 const components = sourceFileCompilerOptions.ets?.components ?? []; 6364 return components.includes(scanner.getTokenText()); 6365 } 6366 6367 function parseEtsComponentExpression(): EtsComponentExpression { 6368 const pos = getNodePos(); 6369 const name = parseBindingIdentifier(); 6370 const argumentList = parseArgumentList(); 6371 const body = token() === SyntaxKind.OpenBraceToken ? parseFunctionBlock(SignatureFlags.None) : undefined; 6372 const node = factory.createEtsComponentExpression(name, argumentList, body); 6373 return finishNode(node, pos); 6374 } 6375 6376 function parsePrimaryExpression(): PrimaryExpression { 6377 switch (token()) { 6378 case SyntaxKind.NumericLiteral: 6379 case SyntaxKind.BigIntLiteral: 6380 case SyntaxKind.StringLiteral: 6381 case SyntaxKind.NoSubstitutionTemplateLiteral: 6382 return parseLiteralNode(); 6383 case SyntaxKind.ThisKeyword: 6384 case SyntaxKind.SuperKeyword: 6385 case SyntaxKind.NullKeyword: 6386 case SyntaxKind.TrueKeyword: 6387 case SyntaxKind.FalseKeyword: 6388 return parseTokenNode<PrimaryExpression>(); 6389 case SyntaxKind.OpenParenToken: 6390 return parseParenthesizedExpression(); 6391 case SyntaxKind.OpenBracketToken: 6392 return parseArrayLiteralExpression(); 6393 case SyntaxKind.OpenBraceToken: 6394 return parseObjectLiteralExpression(); 6395 case SyntaxKind.AsyncKeyword: 6396 // Async arrow functions are parsed earlier in parseAssignmentExpressionOrHigher. 6397 // If we encounter `async [no LineTerminator here] function` then this is an async 6398 // function; otherwise, its an identifier. 6399 if (!lookAhead(nextTokenIsFunctionKeywordOnSameLine)) { 6400 break; 6401 } 6402 6403 return parseFunctionExpression(); 6404 case SyntaxKind.ClassKeyword: 6405 return parseClassExpression(); 6406 case SyntaxKind.FunctionKeyword: 6407 return parseFunctionExpression(); 6408 case SyntaxKind.NewKeyword: 6409 return parseNewExpressionOrNewDotTarget(); 6410 case SyntaxKind.SlashToken: 6411 case SyntaxKind.SlashEqualsToken: 6412 if (reScanSlashToken() === SyntaxKind.RegularExpressionLiteral) { 6413 return parseLiteralNode(); 6414 } 6415 break; 6416 case SyntaxKind.TemplateHead: 6417 return parseTemplateExpression(/* isTaggedTemplate */ false); 6418 case SyntaxKind.PrivateIdentifier: 6419 return parsePrivateIdentifier(); 6420 } 6421 6422 if(isCurrentTokenAnEtsComponentExpression() && !inEtsNewExpressionContext()){ 6423 return parseEtsComponentExpression(); 6424 } 6425 6426 return parseIdentifier(Diagnostics.Expression_expected); 6427 } 6428 6429 function parseParenthesizedExpression(): ParenthesizedExpression { 6430 const pos = getNodePos(); 6431 const hasJSDoc = hasPrecedingJSDocComment(); 6432 parseExpected(SyntaxKind.OpenParenToken); 6433 const expression = allowInAnd(parseExpression); 6434 parseExpected(SyntaxKind.CloseParenToken); 6435 return withJSDoc(finishNode(factory.createParenthesizedExpression(expression), pos), hasJSDoc); 6436 } 6437 6438 function parseSpreadElement(): Expression { 6439 const pos = getNodePos(); 6440 parseExpected(SyntaxKind.DotDotDotToken); 6441 const expression = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true); 6442 return finishNode(factory.createSpreadElement(expression), pos); 6443 } 6444 6445 function parseArgumentOrArrayLiteralElement(): Expression { 6446 return token() === SyntaxKind.DotDotDotToken ? parseSpreadElement() : 6447 token() === SyntaxKind.CommaToken ? finishNode(factory.createOmittedExpression(), getNodePos()) : 6448 parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true); 6449 } 6450 6451 function parseArgumentExpression(): Expression { 6452 return doOutsideOfContext(disallowInAndDecoratorContext, parseArgumentOrArrayLiteralElement); 6453 } 6454 6455 function parseArrayLiteralExpression(): ArrayLiteralExpression { 6456 const pos = getNodePos(); 6457 const openBracketPosition = scanner.getTokenPos(); 6458 const openBracketParsed = parseExpected(SyntaxKind.OpenBracketToken); 6459 const multiLine = scanner.hasPrecedingLineBreak(); 6460 const elements = parseDelimitedList(ParsingContext.ArrayLiteralMembers, parseArgumentOrArrayLiteralElement); 6461 parseExpectedMatchingBrackets(SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken, openBracketParsed, openBracketPosition); 6462 return finishNode(factory.createArrayLiteralExpression(elements, multiLine), pos); 6463 } 6464 6465 function parseObjectLiteralElement(): ObjectLiteralElementLike { 6466 const pos = getNodePos(); 6467 const hasJSDoc = hasPrecedingJSDocComment(); 6468 6469 if (parseOptionalToken(SyntaxKind.DotDotDotToken)) { 6470 const expression = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true); 6471 return withJSDoc(finishNode(factory.createSpreadAssignment(expression), pos), hasJSDoc); 6472 } 6473 6474 const decorators = parseDecorators(); 6475 const modifiers = parseModifiers(); 6476 6477 if (parseContextualModifier(SyntaxKind.GetKeyword)) { 6478 return parseAccessorDeclaration(pos, hasJSDoc, decorators, modifiers, SyntaxKind.GetAccessor, SignatureFlags.None); 6479 } 6480 if (parseContextualModifier(SyntaxKind.SetKeyword)) { 6481 return parseAccessorDeclaration(pos, hasJSDoc, decorators, modifiers, SyntaxKind.SetAccessor, SignatureFlags.None); 6482 } 6483 6484 const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); 6485 const tokenIsIdentifier = isIdentifier(); 6486 const name = parsePropertyName(); 6487 6488 // Disallowing of optional property assignments and definite assignment assertion happens in the grammar checker. 6489 const questionToken = parseOptionalToken(SyntaxKind.QuestionToken); 6490 const exclamationToken = parseOptionalToken(SyntaxKind.ExclamationToken); 6491 6492 if (asteriskToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) { 6493 return parseMethodDeclaration(pos, hasJSDoc, decorators, modifiers, asteriskToken, name, questionToken, exclamationToken); 6494 } 6495 6496 // check if it is short-hand property assignment or normal property assignment 6497 // NOTE: if token is EqualsToken it is interpreted as CoverInitializedName production 6498 // CoverInitializedName[Yield] : 6499 // IdentifierReference[?Yield] Initializer[In, ?Yield] 6500 // this is necessary because ObjectLiteral productions are also used to cover grammar for ObjectAssignmentPattern 6501 let node: Mutable<ShorthandPropertyAssignment | PropertyAssignment>; 6502 const isShorthandPropertyAssignment = tokenIsIdentifier && (token() !== SyntaxKind.ColonToken); 6503 if (isShorthandPropertyAssignment) { 6504 const equalsToken = parseOptionalToken(SyntaxKind.EqualsToken); 6505 const objectAssignmentInitializer = equalsToken ? allowInAnd(() => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true)) : undefined; 6506 node = factory.createShorthandPropertyAssignment(name as Identifier, objectAssignmentInitializer); 6507 // Save equals token for error reporting. 6508 // TODO(rbuckton): Consider manufacturing this when we need to report an error as it is otherwise not useful. 6509 node.equalsToken = equalsToken; 6510 } 6511 else { 6512 parseExpected(SyntaxKind.ColonToken); 6513 const initializer = allowInAnd(() => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true)); 6514 node = factory.createPropertyAssignment(name, initializer); 6515 } 6516 // Decorators, Modifiers, questionToken, and exclamationToken are not supported by property assignments and are reported in the grammar checker 6517 node.illegalDecorators = decorators; 6518 node.modifiers = modifiers; 6519 node.questionToken = questionToken; 6520 node.exclamationToken = exclamationToken; 6521 return withJSDoc(finishNode(node, pos), hasJSDoc); 6522 } 6523 6524 function parseObjectLiteralExpression(): ObjectLiteralExpression { 6525 const pos = getNodePos(); 6526 const openBracePosition = scanner.getTokenPos(); 6527 const openBraceParsed = parseExpected(SyntaxKind.OpenBraceToken); 6528 const multiLine = scanner.hasPrecedingLineBreak(); 6529 const properties = parseDelimitedList(ParsingContext.ObjectLiteralMembers, parseObjectLiteralElement, /*considerSemicolonAsDelimiter*/ true); 6530 parseExpectedMatchingBrackets(SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, openBraceParsed, openBracePosition); 6531 return finishNode(factory.createObjectLiteralExpression(properties, multiLine), pos); 6532 } 6533 6534 function parseFunctionExpression(): FunctionExpression { 6535 // GeneratorExpression: 6536 // function* BindingIdentifier [Yield][opt](FormalParameters[Yield]){ GeneratorBody } 6537 // 6538 // FunctionExpression: 6539 // function BindingIdentifier[opt](FormalParameters){ FunctionBody } 6540 const savedDecoratorContext = inDecoratorContext(); 6541 setDecoratorContext(/*val*/ false); 6542 6543 const pos = getNodePos(); 6544 const hasJSDoc = hasPrecedingJSDocComment(); 6545 const modifiers = parseModifiers(); 6546 parseExpected(SyntaxKind.FunctionKeyword); 6547 const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); 6548 const isGenerator = asteriskToken ? SignatureFlags.Yield : SignatureFlags.None; 6549 const isAsync = some(modifiers, isAsyncModifier) ? SignatureFlags.Await : SignatureFlags.None; 6550 const name = isGenerator && isAsync ? doInYieldAndAwaitContext(parseOptionalBindingIdentifier) : 6551 isGenerator ? doInYieldContext(parseOptionalBindingIdentifier) : 6552 isAsync ? doInAwaitContext(parseOptionalBindingIdentifier) : 6553 parseOptionalBindingIdentifier(); 6554 6555 const typeParameters = parseTypeParameters(); 6556 const parameters = parseParameters(isGenerator | isAsync); 6557 const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false); 6558 const body = parseFunctionBlock(isGenerator | isAsync); 6559 6560 setDecoratorContext(savedDecoratorContext); 6561 6562 const node = factory.createFunctionExpression(modifiers, asteriskToken, name, typeParameters, parameters, type, body); 6563 return withJSDoc(finishNode(node, pos), hasJSDoc); 6564 } 6565 6566 function parseOptionalBindingIdentifier(): Identifier | undefined { 6567 return isBindingIdentifier() ? parseBindingIdentifier() : undefined; 6568 } 6569 6570 function parseNewExpressionOrNewDotTarget(): NewExpression | MetaProperty { 6571 setEtsNewExpressionContext(inEtsComponentsContext()); 6572 const pos = getNodePos(); 6573 parseExpected(SyntaxKind.NewKeyword); 6574 if (parseOptional(SyntaxKind.DotToken)) { 6575 const name = parseIdentifierName(); 6576 return finishNode(factory.createMetaProperty(SyntaxKind.NewKeyword, name), pos); 6577 } 6578 const expressionPos = getNodePos(); 6579 let expression: LeftHandSideExpression = parseMemberExpressionRest(expressionPos, parsePrimaryExpression(), /*allowOptionalChain*/ false); 6580 let typeArguments: NodeArray<TypeNode> | undefined; 6581 // Absorb type arguments into NewExpression when preceding expression is ExpressionWithTypeArguments 6582 if (expression.kind === SyntaxKind.ExpressionWithTypeArguments) { 6583 typeArguments = (expression as ExpressionWithTypeArguments).typeArguments; 6584 expression = (expression as ExpressionWithTypeArguments).expression; 6585 } 6586 if (token() === SyntaxKind.QuestionDotToken) { 6587 parseErrorAtCurrentToken(Diagnostics.Invalid_optional_chain_from_new_expression_Did_you_mean_to_call_0, getTextOfNodeFromSourceText(sourceText, expression)); 6588 } 6589 const argumentList = token() === SyntaxKind.OpenParenToken ? parseArgumentList() : undefined; 6590 setEtsNewExpressionContext(false); 6591 return finishNode(factory.createNewExpression(expression, typeArguments, argumentList), pos); 6592 } 6593 6594 // STATEMENTS 6595 function parseBlock(ignoreMissingOpenBrace: boolean, diagnosticMessage?: DiagnosticMessage): Block { 6596 const pos = getNodePos(); 6597 const hasJSDoc = hasPrecedingJSDocComment(); 6598 const openBracePosition = scanner.getTokenPos(); 6599 const openBraceParsed = parseExpected(SyntaxKind.OpenBraceToken, diagnosticMessage); 6600 if (openBraceParsed || ignoreMissingOpenBrace) { 6601 const multiLine = scanner.hasPrecedingLineBreak(); 6602 const statements = parseList(ParsingContext.BlockStatements, parseStatement); 6603 parseExpectedMatchingBrackets(SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, openBraceParsed, openBracePosition); 6604 const result = withJSDoc(finishNode(factory.createBlock(statements, multiLine), pos), hasJSDoc); 6605 if (token() === SyntaxKind.EqualsToken) { 6606 parseErrorAtCurrentToken(Diagnostics.Declaration_or_statement_expected_This_follows_a_block_of_statements_so_if_you_intended_to_write_a_destructuring_assignment_you_might_need_to_wrap_the_the_whole_assignment_in_parentheses); 6607 nextToken(); 6608 } 6609 6610 return result; 6611 } 6612 else { 6613 const statements = createMissingList<Statement>(); 6614 return withJSDoc(finishNode(factory.createBlock(statements, /*multiLine*/ undefined), pos), hasJSDoc); 6615 } 6616 } 6617 6618 function parseFunctionBlock(flags: SignatureFlags, diagnosticMessage?: DiagnosticMessage): Block { 6619 const savedYieldContext = inYieldContext(); 6620 setYieldContext(!!(flags & SignatureFlags.Yield)); 6621 6622 const savedAwaitContext = inAwaitContext(); 6623 setAwaitContext(!!(flags & SignatureFlags.Await)); 6624 6625 const savedTopLevel = topLevel; 6626 topLevel = false; 6627 6628 // We may be in a [Decorator] context when parsing a function expression or 6629 // arrow function. The body of the function is not in [Decorator] context. 6630 const saveDecoratorContext = inDecoratorContext(); 6631 if (saveDecoratorContext) { 6632 setDecoratorContext(/*val*/ false); 6633 } 6634 6635 const block = parseBlock(!!(flags & SignatureFlags.IgnoreMissingOpenBrace), diagnosticMessage); 6636 6637 if (saveDecoratorContext) { 6638 setDecoratorContext(/*val*/ true); 6639 } 6640 6641 topLevel = savedTopLevel; 6642 setYieldContext(savedYieldContext); 6643 setAwaitContext(savedAwaitContext); 6644 6645 return block; 6646 } 6647 6648 function parseEmptyStatement(): Statement { 6649 const pos = getNodePos(); 6650 const hasJSDoc = hasPrecedingJSDocComment(); 6651 parseExpected(SyntaxKind.SemicolonToken); 6652 return withJSDoc(finishNode(factory.createEmptyStatement(), pos), hasJSDoc); 6653 } 6654 6655 function parseIfStatement(): IfStatement { 6656 const pos = getNodePos(); 6657 const hasJSDoc = hasPrecedingJSDocComment(); 6658 parseExpected(SyntaxKind.IfKeyword); 6659 const openParenPosition = scanner.getTokenPos(); 6660 const openParenParsed = parseExpected(SyntaxKind.OpenParenToken); 6661 const expression = allowInAnd(parseExpression); 6662 parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition); 6663 const thenStatement = parseStatement(); 6664 const elseStatement = parseOptional(SyntaxKind.ElseKeyword) ? parseStatement() : undefined; 6665 return withJSDoc(finishNode(factory.createIfStatement(expression, thenStatement, elseStatement), pos), hasJSDoc); 6666 } 6667 6668 function parseDoStatement(): DoStatement { 6669 const pos = getNodePos(); 6670 const hasJSDoc = hasPrecedingJSDocComment(); 6671 parseExpected(SyntaxKind.DoKeyword); 6672 const statement = parseStatement(); 6673 parseExpected(SyntaxKind.WhileKeyword); 6674 const openParenPosition = scanner.getTokenPos(); 6675 const openParenParsed = parseExpected(SyntaxKind.OpenParenToken); 6676 const expression = allowInAnd(parseExpression); 6677 parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition); 6678 6679 // From: https://mail.mozilla.org/pipermail/es-discuss/2011-August/016188.html 6680 // 157 min --- All allen at wirfs-brock.com CONF --- "do{;}while(false)false" prohibited in 6681 // spec but allowed in consensus reality. Approved -- this is the de-facto standard whereby 6682 // do;while(0)x will have a semicolon inserted before x. 6683 parseOptional(SyntaxKind.SemicolonToken); 6684 return withJSDoc(finishNode(factory.createDoStatement(statement, expression), pos), hasJSDoc); 6685 } 6686 6687 function parseWhileStatement(): WhileStatement { 6688 const pos = getNodePos(); 6689 const hasJSDoc = hasPrecedingJSDocComment(); 6690 parseExpected(SyntaxKind.WhileKeyword); 6691 const openParenPosition = scanner.getTokenPos(); 6692 const openParenParsed = parseExpected(SyntaxKind.OpenParenToken); 6693 const expression = allowInAnd(parseExpression); 6694 parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition); 6695 const statement = parseStatement(); 6696 return withJSDoc(finishNode(factory.createWhileStatement(expression, statement), pos), hasJSDoc); 6697 } 6698 6699 function parseForOrForInOrForOfStatement(): Statement { 6700 const pos = getNodePos(); 6701 const hasJSDoc = hasPrecedingJSDocComment(); 6702 parseExpected(SyntaxKind.ForKeyword); 6703 const awaitToken = parseOptionalToken(SyntaxKind.AwaitKeyword); 6704 parseExpected(SyntaxKind.OpenParenToken); 6705 6706 let initializer!: VariableDeclarationList | Expression; 6707 if (token() !== SyntaxKind.SemicolonToken) { 6708 if (token() === SyntaxKind.VarKeyword || token() === SyntaxKind.LetKeyword || token() === SyntaxKind.ConstKeyword) { 6709 initializer = parseVariableDeclarationList(/*inForStatementInitializer*/ true); 6710 } 6711 else { 6712 initializer = disallowInAnd(parseExpression); 6713 } 6714 } 6715 6716 let node: IterationStatement; 6717 if (awaitToken ? parseExpected(SyntaxKind.OfKeyword) : parseOptional(SyntaxKind.OfKeyword)) { 6718 const expression = allowInAnd(() => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true)); 6719 parseExpected(SyntaxKind.CloseParenToken); 6720 node = factory.createForOfStatement(awaitToken, initializer, expression, parseStatement()); 6721 } 6722 else if (parseOptional(SyntaxKind.InKeyword)) { 6723 const expression = allowInAnd(parseExpression); 6724 parseExpected(SyntaxKind.CloseParenToken); 6725 node = factory.createForInStatement(initializer, expression, parseStatement()); 6726 } 6727 else { 6728 parseExpected(SyntaxKind.SemicolonToken); 6729 const condition = token() !== SyntaxKind.SemicolonToken && token() !== SyntaxKind.CloseParenToken 6730 ? allowInAnd(parseExpression) 6731 : undefined; 6732 parseExpected(SyntaxKind.SemicolonToken); 6733 const incrementor = token() !== SyntaxKind.CloseParenToken 6734 ? allowInAnd(parseExpression) 6735 : undefined; 6736 parseExpected(SyntaxKind.CloseParenToken); 6737 node = factory.createForStatement(initializer, condition, incrementor, parseStatement()); 6738 } 6739 6740 return withJSDoc(finishNode(node, pos) as ForStatement | ForInOrOfStatement, hasJSDoc); 6741 } 6742 6743 function parseBreakOrContinueStatement(kind: SyntaxKind): BreakOrContinueStatement { 6744 const pos = getNodePos(); 6745 const hasJSDoc = hasPrecedingJSDocComment(); 6746 6747 parseExpected(kind === SyntaxKind.BreakStatement ? SyntaxKind.BreakKeyword : SyntaxKind.ContinueKeyword); 6748 const label = canParseSemicolon() ? undefined : parseIdentifier(); 6749 6750 parseSemicolon(); 6751 const node = kind === SyntaxKind.BreakStatement 6752 ? factory.createBreakStatement(label) 6753 : factory.createContinueStatement(label); 6754 return withJSDoc(finishNode(node, pos), hasJSDoc); 6755 } 6756 6757 function parseReturnStatement(): ReturnStatement { 6758 const pos = getNodePos(); 6759 const hasJSDoc = hasPrecedingJSDocComment(); 6760 parseExpected(SyntaxKind.ReturnKeyword); 6761 const expression = canParseSemicolon() ? undefined : allowInAnd(parseExpression); 6762 parseSemicolon(); 6763 return withJSDoc(finishNode(factory.createReturnStatement(expression), pos), hasJSDoc); 6764 } 6765 6766 function parseWithStatement(): WithStatement { 6767 const pos = getNodePos(); 6768 const hasJSDoc = hasPrecedingJSDocComment(); 6769 parseExpected(SyntaxKind.WithKeyword); 6770 const openParenPosition = scanner.getTokenPos(); 6771 const openParenParsed = parseExpected(SyntaxKind.OpenParenToken); 6772 const expression = allowInAnd(parseExpression); 6773 parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition); 6774 const statement = doInsideOfContext(NodeFlags.InWithStatement, parseStatement); 6775 return withJSDoc(finishNode(factory.createWithStatement(expression, statement), pos), hasJSDoc); 6776 } 6777 6778 function parseCaseClause(): CaseClause { 6779 const pos = getNodePos(); 6780 const hasJSDoc = hasPrecedingJSDocComment(); 6781 parseExpected(SyntaxKind.CaseKeyword); 6782 const expression = allowInAnd(parseExpression); 6783 parseExpected(SyntaxKind.ColonToken); 6784 const statements = parseList(ParsingContext.SwitchClauseStatements, parseStatement); 6785 return withJSDoc(finishNode(factory.createCaseClause(expression, statements), pos), hasJSDoc); 6786 } 6787 6788 function parseDefaultClause(): DefaultClause { 6789 const pos = getNodePos(); 6790 parseExpected(SyntaxKind.DefaultKeyword); 6791 parseExpected(SyntaxKind.ColonToken); 6792 const statements = parseList(ParsingContext.SwitchClauseStatements, parseStatement); 6793 return finishNode(factory.createDefaultClause(statements), pos); 6794 } 6795 6796 function parseCaseOrDefaultClause(): CaseOrDefaultClause { 6797 return token() === SyntaxKind.CaseKeyword ? parseCaseClause() : parseDefaultClause(); 6798 } 6799 6800 function parseCaseBlock(): CaseBlock { 6801 const pos = getNodePos(); 6802 parseExpected(SyntaxKind.OpenBraceToken); 6803 const clauses = parseList(ParsingContext.SwitchClauses, parseCaseOrDefaultClause); 6804 parseExpected(SyntaxKind.CloseBraceToken); 6805 return finishNode(factory.createCaseBlock(clauses), pos); 6806 } 6807 6808 function parseSwitchStatement(): SwitchStatement { 6809 const pos = getNodePos(); 6810 const hasJSDoc = hasPrecedingJSDocComment(); 6811 parseExpected(SyntaxKind.SwitchKeyword); 6812 parseExpected(SyntaxKind.OpenParenToken); 6813 const expression = allowInAnd(parseExpression); 6814 parseExpected(SyntaxKind.CloseParenToken); 6815 const caseBlock = parseCaseBlock(); 6816 return withJSDoc(finishNode(factory.createSwitchStatement(expression, caseBlock), pos), hasJSDoc); 6817 } 6818 6819 function parseThrowStatement(): ThrowStatement { 6820 // ThrowStatement[Yield] : 6821 // throw [no LineTerminator here]Expression[In, ?Yield]; 6822 6823 const pos = getNodePos(); 6824 const hasJSDoc = hasPrecedingJSDocComment(); 6825 parseExpected(SyntaxKind.ThrowKeyword); 6826 6827 // Because of automatic semicolon insertion, we need to report error if this 6828 // throw could be terminated with a semicolon. Note: we can't call 'parseExpression' 6829 // directly as that might consume an expression on the following line. 6830 // Instead, we create a "missing" identifier, but don't report an error. The actual error 6831 // will be reported in the grammar walker. 6832 let expression = scanner.hasPrecedingLineBreak() ? undefined : allowInAnd(parseExpression); 6833 if (expression === undefined) { 6834 identifierCount++; 6835 expression = finishNode(factory.createIdentifier(""), getNodePos()); 6836 } 6837 if (!tryParseSemicolon()) { 6838 parseErrorForMissingSemicolonAfter(expression); 6839 } 6840 return withJSDoc(finishNode(factory.createThrowStatement(expression), pos), hasJSDoc); 6841 } 6842 6843 // TODO: Review for error recovery 6844 function parseTryStatement(): TryStatement { 6845 const pos = getNodePos(); 6846 const hasJSDoc = hasPrecedingJSDocComment(); 6847 6848 parseExpected(SyntaxKind.TryKeyword); 6849 const tryBlock = parseBlock(/*ignoreMissingOpenBrace*/ false); 6850 const catchClause = token() === SyntaxKind.CatchKeyword ? parseCatchClause() : undefined; 6851 6852 // If we don't have a catch clause, then we must have a finally clause. Try to parse 6853 // one out no matter what. 6854 let finallyBlock: Block | undefined; 6855 if (!catchClause || token() === SyntaxKind.FinallyKeyword) { 6856 parseExpected(SyntaxKind.FinallyKeyword, Diagnostics.catch_or_finally_expected); 6857 finallyBlock = parseBlock(/*ignoreMissingOpenBrace*/ false); 6858 } 6859 6860 return withJSDoc(finishNode(factory.createTryStatement(tryBlock, catchClause, finallyBlock), pos), hasJSDoc); 6861 } 6862 6863 function parseCatchClause(): CatchClause { 6864 const pos = getNodePos(); 6865 parseExpected(SyntaxKind.CatchKeyword); 6866 6867 let variableDeclaration; 6868 if (parseOptional(SyntaxKind.OpenParenToken)) { 6869 variableDeclaration = parseVariableDeclaration(); 6870 parseExpected(SyntaxKind.CloseParenToken); 6871 } 6872 else { 6873 // Keep shape of node to avoid degrading performance. 6874 variableDeclaration = undefined; 6875 } 6876 6877 const block = parseBlock(/*ignoreMissingOpenBrace*/ false); 6878 return finishNode(factory.createCatchClause(variableDeclaration, block), pos); 6879 } 6880 6881 function parseDebuggerStatement(): Statement { 6882 const pos = getNodePos(); 6883 const hasJSDoc = hasPrecedingJSDocComment(); 6884 parseExpected(SyntaxKind.DebuggerKeyword); 6885 parseSemicolon(); 6886 return withJSDoc(finishNode(factory.createDebuggerStatement(), pos), hasJSDoc); 6887 } 6888 6889 function parseExpressionOrLabeledStatement(): ExpressionStatement | LabeledStatement { 6890 // Avoiding having to do the lookahead for a labeled statement by just trying to parse 6891 // out an expression, seeing if it is identifier and then seeing if it is followed by 6892 // a colon. 6893 const pos = getNodePos(); 6894 let hasJSDoc = hasPrecedingJSDocComment(); 6895 let node: ExpressionStatement | LabeledStatement; 6896 const hasParen = token() === SyntaxKind.OpenParenToken; 6897 const expression = allowInAnd(parseExpression); 6898 if (ts.isIdentifier(expression) && parseOptional(SyntaxKind.ColonToken)) { 6899 node = factory.createLabeledStatement(expression, parseStatement()); 6900 } 6901 else { 6902 if (!tryParseSemicolon()) { 6903 parseErrorForMissingSemicolonAfter(expression); 6904 } 6905 node = factory.createExpressionStatement(expression); 6906 if (hasParen) { 6907 // do not parse the same jsdoc twice 6908 hasJSDoc = false; 6909 } 6910 } 6911 return withJSDoc(finishNode(node, pos), hasJSDoc); 6912 } 6913 6914 function nextTokenIsIdentifierOrKeywordOnSameLine() { 6915 nextToken(); 6916 return tokenIsIdentifierOrKeyword(token()) && !scanner.hasPrecedingLineBreak(); 6917 } 6918 6919 function nextTokenIsClassKeywordOnSameLine() { 6920 nextToken(); 6921 return token() === SyntaxKind.ClassKeyword && !scanner.hasPrecedingLineBreak(); 6922 } 6923 6924 function nextTokenIsFunctionKeywordOnSameLine() { 6925 nextToken(); 6926 return token() === SyntaxKind.FunctionKeyword && !scanner.hasPrecedingLineBreak(); 6927 } 6928 6929 function nextTokenIsIdentifierOrKeywordOrLiteralOnSameLine() { 6930 nextToken(); 6931 return (tokenIsIdentifierOrKeyword(token()) || token() === SyntaxKind.NumericLiteral || token() === SyntaxKind.BigIntLiteral || token() === SyntaxKind.StringLiteral) && !scanner.hasPrecedingLineBreak(); 6932 } 6933 6934 function isDeclaration(): boolean { 6935 while (true) { 6936 switch (token()) { 6937 case SyntaxKind.VarKeyword: 6938 case SyntaxKind.LetKeyword: 6939 case SyntaxKind.ConstKeyword: 6940 case SyntaxKind.FunctionKeyword: 6941 case SyntaxKind.ClassKeyword: 6942 case SyntaxKind.EnumKeyword: 6943 return true; 6944 case SyntaxKind.StructKeyword: 6945 return inEtsContext(); 6946 case SyntaxKind.AtToken: 6947 return inEtsAnnotationContext() && nextToken() === SyntaxKind.InterfaceKeyword; 6948 // 'declare', 'module', 'namespace', 'interface'* and 'type' are all legal JavaScript identifiers; 6949 // however, an identifier cannot be followed by another identifier on the same line. This is what we 6950 // count on to parse out the respective declarations. For instance, we exploit this to say that 6951 // 6952 // namespace n 6953 // 6954 // can be none other than the beginning of a namespace declaration, but need to respect that JavaScript sees 6955 // 6956 // namespace 6957 // n 6958 // 6959 // as the identifier 'namespace' on one line followed by the identifier 'n' on another. 6960 // We need to look one token ahead to see if it permissible to try parsing a declaration. 6961 // 6962 // *Note*: 'interface' is actually a strict mode reserved word. So while 6963 // 6964 // "use strict" 6965 // interface 6966 // I {} 6967 // 6968 // could be legal, it would add complexity for very little gain. 6969 case SyntaxKind.InterfaceKeyword: 6970 case SyntaxKind.TypeKeyword: 6971 return nextTokenIsIdentifierOnSameLine(); 6972 case SyntaxKind.ModuleKeyword: 6973 case SyntaxKind.NamespaceKeyword: 6974 return nextTokenIsIdentifierOrStringLiteralOnSameLine(); 6975 case SyntaxKind.AbstractKeyword: 6976 case SyntaxKind.AccessorKeyword: 6977 case SyntaxKind.AsyncKeyword: 6978 case SyntaxKind.DeclareKeyword: 6979 case SyntaxKind.PrivateKeyword: 6980 case SyntaxKind.ProtectedKeyword: 6981 case SyntaxKind.PublicKeyword: 6982 case SyntaxKind.ReadonlyKeyword: 6983 nextToken(); 6984 // ASI takes effect for this modifier. 6985 if (scanner.hasPrecedingLineBreak()) { 6986 return false; 6987 } 6988 continue; 6989 6990 case SyntaxKind.GlobalKeyword: 6991 nextToken(); 6992 return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.Identifier || token() === SyntaxKind.ExportKeyword; 6993 6994 case SyntaxKind.ImportKeyword: 6995 nextToken(); 6996 return token() === SyntaxKind.StringLiteral || token() === SyntaxKind.AsteriskToken || 6997 token() === SyntaxKind.OpenBraceToken || tokenIsIdentifierOrKeyword(token()); 6998 case SyntaxKind.ExportKeyword: 6999 let currentToken = nextToken(); 7000 if (currentToken === SyntaxKind.TypeKeyword) { 7001 currentToken = lookAhead(nextToken); 7002 } 7003 if (currentToken === SyntaxKind.EqualsToken || currentToken === SyntaxKind.AsteriskToken || 7004 currentToken === SyntaxKind.OpenBraceToken || currentToken === SyntaxKind.DefaultKeyword || 7005 currentToken === SyntaxKind.AsKeyword) { 7006 return true; 7007 } 7008 continue; 7009 7010 case SyntaxKind.StaticKeyword: 7011 nextToken(); 7012 continue; 7013 default: 7014 return false; 7015 } 7016 } 7017 } 7018 7019 function isStartOfDeclaration(): boolean { 7020 return lookAhead(isDeclaration); 7021 } 7022 7023 function isStartOfStatement(): boolean { 7024 switch (token()) { 7025 case SyntaxKind.AtToken: 7026 case SyntaxKind.SemicolonToken: 7027 case SyntaxKind.OpenBraceToken: 7028 case SyntaxKind.VarKeyword: 7029 case SyntaxKind.LetKeyword: 7030 case SyntaxKind.FunctionKeyword: 7031 case SyntaxKind.ClassKeyword: 7032 case SyntaxKind.EnumKeyword: 7033 case SyntaxKind.IfKeyword: 7034 case SyntaxKind.DoKeyword: 7035 case SyntaxKind.WhileKeyword: 7036 case SyntaxKind.ForKeyword: 7037 case SyntaxKind.ContinueKeyword: 7038 case SyntaxKind.BreakKeyword: 7039 case SyntaxKind.ReturnKeyword: 7040 case SyntaxKind.WithKeyword: 7041 case SyntaxKind.SwitchKeyword: 7042 case SyntaxKind.ThrowKeyword: 7043 case SyntaxKind.TryKeyword: 7044 case SyntaxKind.DebuggerKeyword: 7045 // 'catch' and 'finally' do not actually indicate that the code is part of a statement, 7046 // however, we say they are here so that we may gracefully parse them and error later. 7047 // falls through 7048 case SyntaxKind.CatchKeyword: 7049 case SyntaxKind.FinallyKeyword: 7050 return true; 7051 case SyntaxKind.StructKeyword: 7052 return inEtsContext(); 7053 7054 case SyntaxKind.ImportKeyword: 7055 return isStartOfDeclaration() || lookAhead(nextTokenIsOpenParenOrLessThanOrDot); 7056 7057 case SyntaxKind.ConstKeyword: 7058 case SyntaxKind.ExportKeyword: 7059 return isStartOfDeclaration(); 7060 7061 case SyntaxKind.AsyncKeyword: 7062 case SyntaxKind.DeclareKeyword: 7063 case SyntaxKind.InterfaceKeyword: 7064 case SyntaxKind.ModuleKeyword: 7065 case SyntaxKind.NamespaceKeyword: 7066 case SyntaxKind.TypeKeyword: 7067 case SyntaxKind.GlobalKeyword: 7068 // When these don't start a declaration, they're an identifier in an expression statement 7069 return true; 7070 7071 case SyntaxKind.AccessorKeyword: 7072 case SyntaxKind.PublicKeyword: 7073 case SyntaxKind.PrivateKeyword: 7074 case SyntaxKind.ProtectedKeyword: 7075 case SyntaxKind.StaticKeyword: 7076 case SyntaxKind.ReadonlyKeyword: 7077 // When these don't start a declaration, they may be the start of a class member if an identifier 7078 // immediately follows. Otherwise they're an identifier in an expression statement. 7079 return isStartOfDeclaration() || !lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine); 7080 7081 default: 7082 return isStartOfExpression(); 7083 } 7084 } 7085 7086 function nextTokenIsBindingIdentifierOrStartOfDestructuring() { 7087 nextToken(); 7088 return isBindingIdentifier() || token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.OpenBracketToken; 7089 } 7090 7091 function isLetDeclaration() { 7092 // In ES6 'let' always starts a lexical declaration if followed by an identifier or { 7093 // or [. 7094 return lookAhead(nextTokenIsBindingIdentifierOrStartOfDestructuring); 7095 } 7096 7097 function parseStatement(): Statement { 7098 switch (token()) { 7099 case SyntaxKind.SemicolonToken: 7100 return parseEmptyStatement(); 7101 case SyntaxKind.OpenBraceToken: 7102 return parseBlock(/*ignoreMissingOpenBrace*/ false); 7103 case SyntaxKind.VarKeyword: 7104 return parseVariableStatement(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined); 7105 case SyntaxKind.LetKeyword: 7106 if (isLetDeclaration()) { 7107 return parseVariableStatement(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined); 7108 } 7109 break; 7110 case SyntaxKind.FunctionKeyword: 7111 return parseFunctionDeclaration(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined); 7112 case SyntaxKind.StructKeyword: 7113 if (inEtsContext()) { 7114 return parseStructDeclaration(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined); 7115 } 7116 break; 7117 case SyntaxKind.ClassKeyword: 7118 return parseClassDeclaration(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined); 7119 case SyntaxKind.IfKeyword: 7120 return parseIfStatement(); 7121 case SyntaxKind.DoKeyword: 7122 return parseDoStatement(); 7123 case SyntaxKind.WhileKeyword: 7124 return parseWhileStatement(); 7125 case SyntaxKind.ForKeyword: 7126 return parseForOrForInOrForOfStatement(); 7127 case SyntaxKind.ContinueKeyword: 7128 return parseBreakOrContinueStatement(SyntaxKind.ContinueStatement); 7129 case SyntaxKind.BreakKeyword: 7130 return parseBreakOrContinueStatement(SyntaxKind.BreakStatement); 7131 case SyntaxKind.ReturnKeyword: 7132 return parseReturnStatement(); 7133 case SyntaxKind.WithKeyword: 7134 return parseWithStatement(); 7135 case SyntaxKind.SwitchKeyword: 7136 return parseSwitchStatement(); 7137 case SyntaxKind.ThrowKeyword: 7138 return parseThrowStatement(); 7139 case SyntaxKind.TryKeyword: 7140 // Include 'catch' and 'finally' for error recovery. 7141 // falls through 7142 case SyntaxKind.CatchKeyword: 7143 case SyntaxKind.FinallyKeyword: 7144 return parseTryStatement(); 7145 case SyntaxKind.DebuggerKeyword: 7146 return parseDebuggerStatement(); 7147 case SyntaxKind.AtToken: 7148 return parseDeclaration(); 7149 case SyntaxKind.AsyncKeyword: 7150 case SyntaxKind.InterfaceKeyword: 7151 case SyntaxKind.TypeKeyword: 7152 case SyntaxKind.ModuleKeyword: 7153 case SyntaxKind.NamespaceKeyword: 7154 case SyntaxKind.DeclareKeyword: 7155 case SyntaxKind.ConstKeyword: 7156 case SyntaxKind.EnumKeyword: 7157 case SyntaxKind.ExportKeyword: 7158 case SyntaxKind.ImportKeyword: 7159 case SyntaxKind.PrivateKeyword: 7160 case SyntaxKind.ProtectedKeyword: 7161 case SyntaxKind.PublicKeyword: 7162 case SyntaxKind.AbstractKeyword: 7163 case SyntaxKind.AccessorKeyword: 7164 case SyntaxKind.StaticKeyword: 7165 case SyntaxKind.ReadonlyKeyword: 7166 case SyntaxKind.GlobalKeyword: 7167 if (isStartOfDeclaration()) { 7168 return parseDeclaration(); 7169 } 7170 break; 7171 } 7172 return parseExpressionOrLabeledStatement(); 7173 } 7174 7175 function isDeclareModifier(modifier: Modifier) { 7176 return modifier.kind === SyntaxKind.DeclareKeyword; 7177 } 7178 7179 function parseAnnotationDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): AnnotationDeclaration { 7180 const atTokenPos = scanner.getTokenPos(); 7181 parseExpected(SyntaxKind.AtToken); 7182 const interfaceTokenPos = scanner.getTokenPos(); 7183 parseExpected(SyntaxKind.InterfaceKeyword); 7184 7185 // Prevent any tokens between '@' and 'interface' 7186 if (interfaceTokenPos - atTokenPos > 1) { 7187 parseErrorAt(atTokenPos + 1, interfaceTokenPos, Diagnostics.In_annotation_declaration_any_symbols_between_and_interface_are_forbidden); 7188 } 7189 7190 const name = createIdentifier(isBindingIdentifier()); 7191 let members; 7192 if (parseExpected(SyntaxKind.OpenBraceToken)) { 7193 members = parseAnnotationMembers(); 7194 parseExpected(SyntaxKind.CloseBraceToken); 7195 } 7196 else { 7197 members = createMissingList<AnnotationElement>(); 7198 } 7199 const node = factory.createAnnotationDeclaration(combineDecoratorsAndModifiers(decorators, modifiers), name, members); 7200 return withJSDoc(finishNode(node, pos), hasJSDoc); 7201 } 7202 7203 function parseDeclaration(): Statement { 7204 // `parseListElement` attempted to get the reused node at this position, 7205 // but the ambient context flag was not yet set, so the node appeared 7206 // not reusable in that context. 7207 const pos = getNodePos(); 7208 const hasJSDoc = hasPrecedingJSDocComment(); 7209 const decorators = parseDecorators(); 7210 7211 if (token() === SyntaxKind.FunctionKeyword || token() === SyntaxKind.ExportKeyword) { 7212 if (hasEtsExtendDecoratorNames(decorators, sourceFileCompilerOptions)) { 7213 const extendEtsComponentDecoratorNames = getEtsExtendDecoratorsComponentNames(decorators, sourceFileCompilerOptions); 7214 if (extendEtsComponentDecoratorNames.length > 0) { 7215 sourceFileCompilerOptions.ets?.extend.components.forEach(({ name, type, instance }) => { 7216 if (name === last(extendEtsComponentDecoratorNames)) { 7217 extendEtsComponentDeclaration = { name, type, instance }; 7218 } 7219 }); 7220 } 7221 setEtsExtendComponentsContext(!!extendEtsComponentDeclaration); 7222 } 7223 else if (hasEtsStylesDecoratorNames(decorators, sourceFileCompilerOptions)) { 7224 const stylesEtsComponentDecoratorNames = getEtsStylesDecoratorComponentNames(decorators, sourceFileCompilerOptions); 7225 if (stylesEtsComponentDecoratorNames.length > 0) { 7226 stylesEtsComponentDeclaration = sourceFileCompilerOptions.ets?.styles.component; 7227 } 7228 setEtsStylesComponentsContext(!!stylesEtsComponentDeclaration); 7229 } 7230 else { 7231 setEtsComponentsContext(isTokenInsideBuilder(decorators, sourceFileCompilerOptions)); 7232 } 7233 } 7234 7235 const modifiers = parseModifiers(); 7236 const isAmbient = some(modifiers, isDeclareModifier); 7237 if (isAmbient) { 7238 const node = tryReuseAmbientDeclaration(pos); 7239 if (node) { 7240 return node; 7241 } 7242 7243 for (const m of modifiers!) { 7244 (m as Mutable<Node>).flags |= NodeFlags.Ambient; 7245 } 7246 return doInsideOfContext(NodeFlags.Ambient, () => parseDeclarationWorker(pos, hasJSDoc, decorators, modifiers)); 7247 } 7248 else { 7249 return parseDeclarationWorker(pos, hasJSDoc, decorators, modifiers); 7250 } 7251 } 7252 7253 function tryReuseAmbientDeclaration(pos: number): Statement | undefined { 7254 return doInsideOfContext(NodeFlags.Ambient, () => { 7255 const node = currentNode(parsingContext, pos); 7256 if (node) { 7257 return consumeNode(node) as Statement; 7258 } 7259 }); 7260 } 7261 7262 function parseDeclarationWorker(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): Statement { 7263 switch (token()) { 7264 case SyntaxKind.VarKeyword: 7265 case SyntaxKind.LetKeyword: 7266 case SyntaxKind.ConstKeyword: 7267 return parseVariableStatement(pos, hasJSDoc, decorators, modifiers); 7268 case SyntaxKind.FunctionKeyword: 7269 return parseFunctionDeclaration(pos, hasJSDoc, decorators, modifiers); 7270 case SyntaxKind.ClassKeyword: 7271 return parseClassDeclaration(pos, hasJSDoc, decorators, modifiers); 7272 case SyntaxKind.StructKeyword: 7273 if (inEtsContext()) { 7274 return parseStructDeclaration(pos, hasJSDoc, decorators, modifiers); 7275 } 7276 return parseDeclarationDefault(pos,decorators, modifiers); 7277 case SyntaxKind.AtToken: 7278 if (inEtsAnnotationContext() && 7279 lookAhead(() => nextToken() === SyntaxKind.InterfaceKeyword)) { 7280 return parseAnnotationDeclaration(pos, hasJSDoc, decorators, modifiers); 7281 } 7282 return parseDeclarationDefault(pos,decorators, modifiers); 7283 case SyntaxKind.InterfaceKeyword: 7284 return parseInterfaceDeclaration(pos, hasJSDoc, decorators, modifiers); 7285 case SyntaxKind.TypeKeyword: 7286 return parseTypeAliasDeclaration(pos, hasJSDoc, decorators, modifiers); 7287 case SyntaxKind.EnumKeyword: 7288 return parseEnumDeclaration(pos, hasJSDoc, decorators, modifiers); 7289 case SyntaxKind.GlobalKeyword: 7290 case SyntaxKind.ModuleKeyword: 7291 case SyntaxKind.NamespaceKeyword: 7292 return parseModuleDeclaration(pos, hasJSDoc, decorators, modifiers); 7293 case SyntaxKind.ImportKeyword: 7294 return parseImportDeclarationOrImportEqualsDeclaration(pos, hasJSDoc, decorators, modifiers); 7295 case SyntaxKind.ExportKeyword: 7296 nextToken(); 7297 switch (token()) { 7298 case SyntaxKind.DefaultKeyword: 7299 case SyntaxKind.EqualsToken: 7300 return parseExportAssignment(pos, hasJSDoc, decorators, modifiers); 7301 case SyntaxKind.AsKeyword: 7302 return parseNamespaceExportDeclaration(pos, hasJSDoc, decorators, modifiers); 7303 default: 7304 return parseExportDeclaration(pos, hasJSDoc, decorators, modifiers); 7305 } 7306 default: 7307 return parseDeclarationDefault(pos,decorators, modifiers); 7308 } 7309 } 7310 7311 function parseDeclarationDefault(pos: number,decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): Statement { 7312 if (decorators || modifiers) { 7313 // We reached this point because we encountered decorators and/or modifiers and assumed a declaration 7314 // would follow. For recovery and error reporting purposes, return an incomplete declaration. 7315 const missing = createMissingNode<MissingDeclaration>(SyntaxKind.MissingDeclaration, /*reportAtCurrentPosition*/ true, Diagnostics.Declaration_expected); 7316 setTextRangePos(missing, pos); 7317 missing.illegalDecorators = decorators; 7318 missing.modifiers = modifiers; 7319 return missing; 7320 } 7321 return undefined!; // TODO: GH#18217 7322 } 7323 7324 function nextTokenIsIdentifierOrStringLiteralOnSameLine() { 7325 nextToken(); 7326 return !scanner.hasPrecedingLineBreak() && (isIdentifier() || token() === SyntaxKind.StringLiteral); 7327 } 7328 7329 function parseFunctionBlockOrSemicolon(flags: SignatureFlags, diagnosticMessage?: DiagnosticMessage): Block | undefined { 7330 if (token() !== SyntaxKind.OpenBraceToken) { 7331 if (flags & SignatureFlags.Type) { 7332 parseTypeMemberSemicolon(); 7333 return; 7334 } 7335 if (canParseSemicolon()) { 7336 parseSemicolon(); 7337 return; 7338 } 7339 } 7340 return parseFunctionBlock(flags, diagnosticMessage); 7341 } 7342 7343 // DECLARATIONS 7344 7345 function parseArrayBindingElement(): ArrayBindingElement { 7346 const pos = getNodePos(); 7347 if (token() === SyntaxKind.CommaToken) { 7348 return finishNode(factory.createOmittedExpression(), pos); 7349 } 7350 const dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); 7351 const name = parseIdentifierOrPattern(); 7352 const initializer = parseInitializer(); 7353 return finishNode(factory.createBindingElement(dotDotDotToken, /*propertyName*/ undefined, name, initializer), pos); 7354 } 7355 7356 function parseObjectBindingElement(): BindingElement { 7357 const pos = getNodePos(); 7358 const dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); 7359 const tokenIsIdentifier = isBindingIdentifier(); 7360 let propertyName: PropertyName | undefined = parsePropertyName(); 7361 let name: BindingName; 7362 if (tokenIsIdentifier && token() !== SyntaxKind.ColonToken) { 7363 name = propertyName as Identifier; 7364 propertyName = undefined; 7365 } 7366 else { 7367 parseExpected(SyntaxKind.ColonToken); 7368 name = parseIdentifierOrPattern(); 7369 } 7370 const initializer = parseInitializer(); 7371 return finishNode(factory.createBindingElement(dotDotDotToken, propertyName, name, initializer), pos); 7372 } 7373 7374 function parseObjectBindingPattern(): ObjectBindingPattern { 7375 const pos = getNodePos(); 7376 parseExpected(SyntaxKind.OpenBraceToken); 7377 const elements = parseDelimitedList(ParsingContext.ObjectBindingElements, parseObjectBindingElement); 7378 parseExpected(SyntaxKind.CloseBraceToken); 7379 return finishNode(factory.createObjectBindingPattern(elements), pos); 7380 } 7381 7382 function parseArrayBindingPattern(): ArrayBindingPattern { 7383 const pos = getNodePos(); 7384 parseExpected(SyntaxKind.OpenBracketToken); 7385 const elements = parseDelimitedList(ParsingContext.ArrayBindingElements, parseArrayBindingElement); 7386 parseExpected(SyntaxKind.CloseBracketToken); 7387 return finishNode(factory.createArrayBindingPattern(elements), pos); 7388 } 7389 7390 function isBindingIdentifierOrPrivateIdentifierOrPattern() { 7391 return token() === SyntaxKind.OpenBraceToken 7392 || token() === SyntaxKind.OpenBracketToken 7393 || token() === SyntaxKind.PrivateIdentifier 7394 || isBindingIdentifier(); 7395 } 7396 7397 function parseIdentifierOrPattern(privateIdentifierDiagnosticMessage?: DiagnosticMessage): Identifier | BindingPattern { 7398 if (token() === SyntaxKind.OpenBracketToken) { 7399 return parseArrayBindingPattern(); 7400 } 7401 if (token() === SyntaxKind.OpenBraceToken) { 7402 return parseObjectBindingPattern(); 7403 } 7404 return parseBindingIdentifier(privateIdentifierDiagnosticMessage); 7405 } 7406 7407 function parseVariableDeclarationAllowExclamation() { 7408 return parseVariableDeclaration(/*allowExclamation*/ true); 7409 } 7410 7411 function parseVariableDeclaration(allowExclamation?: boolean): VariableDeclaration { 7412 const pos = getNodePos(); 7413 const hasJSDoc = hasPrecedingJSDocComment(); 7414 const name = parseIdentifierOrPattern(Diagnostics.Private_identifiers_are_not_allowed_in_variable_declarations); 7415 let exclamationToken: ExclamationToken | undefined; 7416 if (allowExclamation && name.kind === SyntaxKind.Identifier && 7417 token() === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak()) { 7418 exclamationToken = parseTokenNode<Token<SyntaxKind.ExclamationToken>>(); 7419 } 7420 const type = parseTypeAnnotation(); 7421 const initializer = isInOrOfKeyword(token()) ? undefined : parseInitializer(); 7422 const node = factory.createVariableDeclaration(name, exclamationToken, type, initializer); 7423 return withJSDoc(finishNode(node, pos), hasJSDoc); 7424 } 7425 7426 function parseVariableDeclarationList(inForStatementInitializer: boolean): VariableDeclarationList { 7427 const pos = getNodePos(); 7428 7429 let flags: NodeFlags = 0; 7430 switch (token()) { 7431 case SyntaxKind.VarKeyword: 7432 break; 7433 case SyntaxKind.LetKeyword: 7434 flags |= NodeFlags.Let; 7435 break; 7436 case SyntaxKind.ConstKeyword: 7437 flags |= NodeFlags.Const; 7438 break; 7439 default: 7440 Debug.fail(); 7441 } 7442 7443 nextToken(); 7444 7445 // The user may have written the following: 7446 // 7447 // for (let of X) { } 7448 // 7449 // In this case, we want to parse an empty declaration list, and then parse 'of' 7450 // as a keyword. The reason this is not automatic is that 'of' is a valid identifier. 7451 // So we need to look ahead to determine if 'of' should be treated as a keyword in 7452 // this context. 7453 // The checker will then give an error that there is an empty declaration list. 7454 let declarations: readonly VariableDeclaration[]; 7455 if (token() === SyntaxKind.OfKeyword && lookAhead(canFollowContextualOfKeyword)) { 7456 declarations = createMissingList<VariableDeclaration>(); 7457 } 7458 else { 7459 const savedDisallowIn = inDisallowInContext(); 7460 setDisallowInContext(inForStatementInitializer); 7461 7462 declarations = parseDelimitedList(ParsingContext.VariableDeclarations, 7463 inForStatementInitializer ? parseVariableDeclaration : parseVariableDeclarationAllowExclamation); 7464 7465 setDisallowInContext(savedDisallowIn); 7466 } 7467 7468 return finishNode(factory.createVariableDeclarationList(declarations, flags), pos); 7469 } 7470 7471 function canFollowContextualOfKeyword(): boolean { 7472 return nextTokenIsIdentifier() && nextToken() === SyntaxKind.CloseParenToken; 7473 } 7474 7475 function parseVariableStatement(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): VariableStatement { 7476 const declarationList = parseVariableDeclarationList(/*inForStatementInitializer*/ false); 7477 parseSemicolon(); 7478 const node = factory.createVariableStatement(modifiers, declarationList); 7479 // Decorators are not allowed on a variable statement, so we keep track of them to report them in the grammar checker. 7480 node.illegalDecorators = decorators; 7481 return withJSDoc(finishNode(node, pos), hasJSDoc); 7482 } 7483 7484 function parseFunctionDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): FunctionDeclaration { 7485 const savedAwaitContext = inAwaitContext(); 7486 7487 const modifierFlags = modifiersToFlags(modifiers); 7488 parseExpected(SyntaxKind.FunctionKeyword); 7489 const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); 7490 // We don't parse the name here in await context, instead we will report a grammar error in the checker. 7491 const name = modifierFlags & ModifierFlags.Default ? parseOptionalBindingIdentifier() : parseBindingIdentifier(); 7492 if(name && hasEtsStylesDecoratorNames(decorators, sourceFileCompilerOptions)) { 7493 fileStylesComponents.set(name.escapedText.toString(), SyntaxKind.FunctionDeclaration); 7494 } 7495 const originalUICallbackContext = inUICallbackContext(); 7496 setEtsBuilderContext(hasEtsBuilderDecoratorNames(decorators, sourceFileCompilerOptions)); 7497 setUICallbackContext(inBuilderContext()); 7498 const isGenerator = asteriskToken ? SignatureFlags.Yield : SignatureFlags.None; 7499 const isAsync = modifierFlags & ModifierFlags.Async ? SignatureFlags.Await : SignatureFlags.None; 7500 const typeParameters = inEtsStylesComponentsContext() && stylesEtsComponentDeclaration ? parseEtsTypeParameters(scanner.getStartPos()) : parseTypeParameters(); 7501 if (modifierFlags & ModifierFlags.Export) setAwaitContext(/*value*/ true); 7502 const parameters = parseParameters(isGenerator | isAsync); 7503 const typeStartPos = scanner.getStartPos(); 7504 const type = getFunctionDeclarationReturnType(); 7505 const body = parseFunctionBlockOrSemicolon(isGenerator | isAsync, Diagnostics.or_expected); 7506 setEtsBuilderContext(false); 7507 setUICallbackContext(originalUICallbackContext); 7508 setEtsExtendComponentsContext(false); 7509 extendEtsComponentDeclaration = undefined; 7510 setEtsStylesComponentsContext(false); 7511 stylesEtsComponentDeclaration = undefined; 7512 setEtsComponentsContext(inBuildContext()); 7513 setAwaitContext(savedAwaitContext); 7514 const node = factory.createFunctionDeclaration(modifiers, asteriskToken, name, typeParameters, parameters, type, body); 7515 (node as Mutable<FunctionDeclaration>).illegalDecorators = decorators; 7516 return withJSDoc(finishNode(node, pos), hasJSDoc); 7517 7518 function getFunctionDeclarationReturnType(): TypeNode | undefined { 7519 let returnType = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false); 7520 // If function decorated by Extend and type is not defined, then will use Ets Extend Components Type 7521 if (!returnType && extendEtsComponentDeclaration && inEtsExtendComponentsContext()) { 7522 returnType = finishVirtualNode(factory.createTypeReferenceNode( 7523 finishVirtualNode(factory.createIdentifier(extendEtsComponentDeclaration.type), typeStartPos, typeStartPos)), 7524 typeStartPos, typeStartPos); 7525 } 7526 // If function decorated by Styles and type is not defined, then will use Ets Styles Components Type 7527 if (!returnType && stylesEtsComponentDeclaration && inEtsStylesComponentsContext()) { 7528 returnType = finishVirtualNode(factory.createTypeReferenceNode( 7529 finishVirtualNode(factory.createIdentifier(stylesEtsComponentDeclaration.type), typeStartPos, typeStartPos)), 7530 typeStartPos, typeStartPos); 7531 } 7532 return returnType; 7533 } 7534 } 7535 7536 function parseConstructorName() { 7537 if (token() === SyntaxKind.ConstructorKeyword) { 7538 return parseExpected(SyntaxKind.ConstructorKeyword); 7539 } 7540 if (token() === SyntaxKind.StringLiteral && lookAhead(nextToken) === SyntaxKind.OpenParenToken) { 7541 return tryParse(() => { 7542 const literalNode = parseLiteralNode(); 7543 return literalNode.text === "constructor" ? literalNode : undefined; 7544 }); 7545 } 7546 } 7547 7548 function tryParseConstructorDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ConstructorDeclaration | undefined { 7549 return tryParse(() => { 7550 if (parseConstructorName()) { 7551 const typeParameters = parseTypeParameters(); 7552 const parameters = parseParameters(SignatureFlags.None); 7553 const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false); 7554 const body = parseFunctionBlockOrSemicolon(SignatureFlags.None, Diagnostics.or_expected); 7555 const node = factory.createConstructorDeclaration(modifiers, parameters, body); 7556 7557 // Attach invalid nodes if they exist so that we can report them in the grammar checker. 7558 (node as Mutable<ConstructorDeclaration>).illegalDecorators = decorators; 7559 (node as Mutable<ConstructorDeclaration>).typeParameters = typeParameters; 7560 (node as Mutable<ConstructorDeclaration>).type = type; 7561 return withJSDoc(finishNode(node, pos), hasJSDoc); 7562 } 7563 }); 7564 } 7565 7566 7567 function isTokenInsideStructBuild(methodName: PropertyName): boolean { 7568 const renderMethod = sourceFileCompilerOptions.ets?.render?.method?.find(render => render === "build") ?? "build"; 7569 7570 if (methodName.kind === SyntaxKind.Identifier && methodName.escapedText === renderMethod) { 7571 return true; 7572 } 7573 return false; 7574 } 7575 7576 function isTokenInsideStructBuilder(decorators: NodeArray<Decorator> | undefined): boolean { 7577 return isTokenInsideBuilder(decorators, sourceFileCompilerOptions); 7578 } 7579 7580 function isTokenInsideStructPageTransition(methodName: PropertyName): boolean { 7581 const renderMethod = sourceFileCompilerOptions.ets?.render?.method?.find(render => render === "pageTransition") ?? "pageTransition"; 7582 7583 if (methodName.kind === SyntaxKind.Identifier && methodName.escapedText === renderMethod) { 7584 return true; 7585 } 7586 return false; 7587 } 7588 7589 function parseMethodDeclaration( 7590 pos: number, 7591 hasJSDoc: boolean, 7592 decorators: NodeArray<Decorator> | undefined, 7593 modifiers: NodeArray<Modifier> | undefined, 7594 asteriskToken: AsteriskToken | undefined, 7595 name: PropertyName, 7596 questionToken: QuestionToken | undefined, 7597 exclamationToken: ExclamationToken | undefined, 7598 diagnosticMessage?: DiagnosticMessage 7599 ): MethodDeclaration { 7600 const methodName = getPropertyNameForPropertyNameNode(name)?.toString(); 7601 const orignalEtsBuildContext = inBuildContext(); 7602 const orignalEtsBuilderContext = inBuilderContext(); 7603 const orignalUICallbackContext = inUICallbackContext(); 7604 setEtsBuildContext(methodName === sourceFileCompilerOptions?.ets?.render?.method?.find(render => render === "build")); 7605 setEtsBuilderContext(hasEtsBuilderDecoratorNames(decorators, sourceFileCompilerOptions)); 7606 setUICallbackContext(inBuildContext() || inBuilderContext()); 7607 if (inStructContext() && hasEtsStylesDecoratorNames(decorators, sourceFileCompilerOptions)) { 7608 if (methodName && currentStructName) { 7609 structStylesComponents.set(methodName, { structName: currentStructName, kind: SyntaxKind.MethodDeclaration }); 7610 } 7611 const stylesEtsComponentDecoratorNames = getEtsStylesDecoratorComponentNames(decorators, sourceFileCompilerOptions); 7612 if (stylesEtsComponentDecoratorNames.length > 0) { 7613 stylesEtsComponentDeclaration = sourceFileCompilerOptions.ets?.styles.component; 7614 } 7615 setEtsStylesComponentsContext(!!stylesEtsComponentDeclaration); 7616 } 7617 const orignalEtsComponentsContext: boolean = inEtsComponentsContext(); 7618 setEtsComponentsContext(inStructContext() && (isTokenInsideStructBuild(name) || isTokenInsideStructBuilder(decorators) || 7619 isTokenInsideStructPageTransition(name))); 7620 const isGenerator = asteriskToken ? SignatureFlags.Yield : SignatureFlags.None; 7621 const isAsync = some(modifiers, isAsyncModifier) ? SignatureFlags.Await : SignatureFlags.None; 7622 const typeParameters = inEtsStylesComponentsContext() && stylesEtsComponentDeclaration ? parseEtsTypeParameters(pos) : parseTypeParameters(); 7623 const parameters = parseParameters(isGenerator | isAsync); 7624 const typeStartPos = scanner.getStartPos(); 7625 const type = getMethodDeclarationReturnType(); 7626 const body = parseFunctionBlockOrSemicolon(isGenerator | isAsync, diagnosticMessage); 7627 const node = factory.createMethodDeclaration( 7628 combineDecoratorsAndModifiers(decorators, modifiers), 7629 asteriskToken, 7630 name, 7631 questionToken, 7632 typeParameters, 7633 parameters, 7634 type, 7635 body 7636 ); 7637 7638 // An exclamation token on a method is invalid syntax and will be handled by the grammar checker 7639 (node as Mutable<MethodDeclaration>).exclamationToken = exclamationToken; 7640 setEtsBuildContext(orignalEtsBuildContext); 7641 setEtsBuilderContext(orignalEtsBuilderContext); 7642 setUICallbackContext(orignalUICallbackContext); 7643 setEtsStylesComponentsContext(false); 7644 stylesEtsComponentDeclaration = undefined; 7645 setEtsComponentsContext(orignalEtsComponentsContext); 7646 return withJSDoc(finishNode(node, pos), hasJSDoc); 7647 7648 function getMethodDeclarationReturnType(): TypeNode | undefined { 7649 let returnType = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false); 7650 // If function decorated by Styles and type is not defined, then will use Ets Styles Components Type 7651 if (!returnType && stylesEtsComponentDeclaration && inEtsStylesComponentsContext()) { 7652 returnType = finishVirtualNode(factory.createTypeReferenceNode( 7653 finishVirtualNode(factory.createIdentifier(stylesEtsComponentDeclaration.type), typeStartPos, typeStartPos)), 7654 typeStartPos, typeStartPos); 7655 } 7656 return returnType; 7657 } 7658 } 7659 7660 function parseAnnotationPropertyDeclaration( 7661 pos: number, 7662 hasJSDoc: boolean, 7663 name: PropertyName 7664 ): AnnotationPropertyDeclaration { 7665 const type = parseTypeAnnotation(); 7666 const initializer = doOutsideOfContext(NodeFlags.YieldContext | NodeFlags.AwaitContext | NodeFlags.DisallowInContext, parseInitializer); 7667 parseSemicolonAfterPropertyName(name, type, initializer); 7668 const node = factory.createAnnotationPropertyDeclaration( 7669 name, 7670 type, 7671 initializer); 7672 return withJSDoc(finishNode(node, pos), hasJSDoc); 7673 } 7674 7675 function parsePropertyDeclaration( 7676 pos: number, 7677 hasJSDoc: boolean, 7678 decorators: NodeArray<Decorator> | undefined, 7679 modifiers: NodeArray<Modifier> | undefined, 7680 name: PropertyName, 7681 questionToken: QuestionToken | undefined 7682 ): PropertyDeclaration { 7683 const exclamationToken = !questionToken && !scanner.hasPrecedingLineBreak() ? parseOptionalToken(SyntaxKind.ExclamationToken) : undefined; 7684 const type = parseTypeAnnotation(); 7685 const initializer = doOutsideOfContext(NodeFlags.YieldContext | NodeFlags.AwaitContext | NodeFlags.DisallowInContext, parseInitializer); 7686 parseSemicolonAfterPropertyName(name, type, initializer); 7687 const node = factory.createPropertyDeclaration( 7688 combineDecoratorsAndModifiers(decorators, modifiers), 7689 name, 7690 questionToken || exclamationToken, 7691 type, 7692 initializer); 7693 return withJSDoc(finishNode(node, pos), hasJSDoc); 7694 } 7695 7696 function parsePropertyOrMethodDeclaration( 7697 pos: number, 7698 hasJSDoc: boolean, 7699 decorators: NodeArray<Decorator> | undefined, 7700 modifiers: NodeArray<Modifier> | undefined 7701 ): PropertyDeclaration | MethodDeclaration { 7702 const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); 7703 const name = parsePropertyName(); 7704 // Note: this is not legal as per the grammar. But we allow it in the parser and 7705 // report an error in the grammar checker. 7706 const questionToken = parseOptionalToken(SyntaxKind.QuestionToken); 7707 if (asteriskToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) { 7708 return parseMethodDeclaration(pos, hasJSDoc, decorators, modifiers, asteriskToken, name, questionToken, /*exclamationToken*/ undefined, Diagnostics.or_expected); 7709 } 7710 return parsePropertyDeclaration(pos, hasJSDoc, decorators, modifiers, name, questionToken); 7711 } 7712 7713 function parseAccessorDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined, kind: AccessorDeclaration["kind"], flags: SignatureFlags): AccessorDeclaration { 7714 const name = parsePropertyName(); 7715 const typeParameters = parseTypeParameters(); 7716 const parameters = parseParameters(SignatureFlags.None); 7717 const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false); 7718 const body = parseFunctionBlockOrSemicolon(flags); 7719 const node = kind === SyntaxKind.GetAccessor 7720 ? factory.createGetAccessorDeclaration(combineDecoratorsAndModifiers(decorators, modifiers), name, parameters, type, body) 7721 : factory.createSetAccessorDeclaration(combineDecoratorsAndModifiers(decorators, modifiers), name, parameters, body); 7722 // Keep track of `typeParameters` (for both) and `type` (for setters) if they were parsed those indicate grammar errors 7723 (node as Mutable<AccessorDeclaration>).typeParameters = typeParameters; 7724 if (isSetAccessorDeclaration(node)) (node as Mutable<SetAccessorDeclaration>).type = type; 7725 return withJSDoc(finishNode(node, pos), hasJSDoc); 7726 } 7727 7728 function isAnnotationMemberStart(): boolean { 7729 let idToken: SyntaxKind | undefined; 7730 7731 if (token() === SyntaxKind.AtToken) { 7732 return false; 7733 } 7734 7735 if (isModifierKind(token())) { 7736 return false; 7737 } 7738 7739 if (token() === SyntaxKind.AsteriskToken) { 7740 return false ; 7741 } 7742 7743 // Try to get the first property-like token following all modifiers. 7744 // This can either be an identifier or the 'get' or 'set' keywords. 7745 if (isLiteralPropertyName()) { 7746 idToken = token(); 7747 nextToken(); 7748 } 7749 7750 // Index signatures and computed properties are prohibited for annotations 7751 if (token() === SyntaxKind.OpenBracketToken) { 7752 return false; 7753 } 7754 7755 // If we were able to get any potential identifier... 7756 if (idToken !== undefined) { 7757 // If we have a non-keyword identifier, or if we have an accessor, then we no need to parse. 7758 if (isKeyword(idToken)) { 7759 return false; 7760 } 7761 7762 // If it *is* a keyword, but not an accessor, check a little farther along 7763 // to see if it should actually be parsed as a class member. 7764 switch (token()) { 7765 case SyntaxKind.ColonToken: // Type Annotation for declaration 7766 case SyntaxKind.EqualsToken: // Initializer for declaration 7767 return true; 7768 default: 7769 // Covers 7770 // - Semicolons (declaration termination) 7771 // - Closing braces (end-of-class, must be declaration) 7772 // - End-of-files (not valid, but permitted so that it gets caught later on) 7773 // - Line-breaks (enabling *automatic semicolon insertion*) 7774 return canParseSemicolon(); 7775 } 7776 } 7777 return false; 7778 } 7779 7780 function isClassMemberStart(): boolean { 7781 let idToken: SyntaxKind | undefined; 7782 7783 if (token() === SyntaxKind.AtToken) { 7784 if (inEtsAnnotationContext() && lookAhead(() => nextToken() === SyntaxKind.InterfaceKeyword)) { 7785 return false; 7786 } 7787 return true; 7788 } 7789 7790 // Eat up all modifiers, but hold on to the last one in case it is actually an identifier. 7791 while (isModifierKind(token())) { 7792 idToken = token(); 7793 // If the idToken is a class modifier (protected, private, public, and static), it is 7794 // certain that we are starting to parse class member. This allows better error recovery 7795 // Example: 7796 // public foo() ... // true 7797 // public @dec blah ... // true; we will then report an error later 7798 // export public ... // true; we will then report an error later 7799 if (isClassMemberModifier(idToken)) { 7800 return true; 7801 } 7802 7803 nextToken(); 7804 } 7805 7806 if (token() === SyntaxKind.AsteriskToken) { 7807 return true; 7808 } 7809 7810 // Try to get the first property-like token following all modifiers. 7811 // This can either be an identifier or the 'get' or 'set' keywords. 7812 if (isLiteralPropertyName()) { 7813 idToken = token(); 7814 nextToken(); 7815 } 7816 7817 // Index signatures and computed properties are class members; we can parse. 7818 if (token() === SyntaxKind.OpenBracketToken) { 7819 return true; 7820 } 7821 7822 // If we were able to get any potential identifier... 7823 if (idToken !== undefined) { 7824 // If we have a non-keyword identifier, or if we have an accessor, then it's safe to parse. 7825 if (!isKeyword(idToken) || idToken === SyntaxKind.SetKeyword || idToken === SyntaxKind.GetKeyword) { 7826 return true; 7827 } 7828 7829 // If it *is* a keyword, but not an accessor, check a little farther along 7830 // to see if it should actually be parsed as a class member. 7831 switch (token()) { 7832 case SyntaxKind.OpenParenToken: // Method declaration 7833 case SyntaxKind.LessThanToken: // Generic Method declaration 7834 case SyntaxKind.ExclamationToken: // Non-null assertion on property name 7835 case SyntaxKind.ColonToken: // Type Annotation for declaration 7836 case SyntaxKind.EqualsToken: // Initializer for declaration 7837 case SyntaxKind.QuestionToken: // Not valid, but permitted so that it gets caught later on. 7838 return true; 7839 default: 7840 // Covers 7841 // - Semicolons (declaration termination) 7842 // - Closing braces (end-of-class, must be declaration) 7843 // - End-of-files (not valid, but permitted so that it gets caught later on) 7844 // - Line-breaks (enabling *automatic semicolon insertion*) 7845 return canParseSemicolon(); 7846 } 7847 } 7848 return false; 7849 } 7850 7851 function parseClassStaticBlockDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: ModifiersArray | undefined): ClassStaticBlockDeclaration { 7852 parseExpectedToken(SyntaxKind.StaticKeyword); 7853 const body = parseClassStaticBlockBody(); 7854 const node = withJSDoc(finishNode(factory.createClassStaticBlockDeclaration(body), pos), hasJSDoc); 7855 (node as Mutable<ClassStaticBlockDeclaration>).illegalDecorators = decorators; 7856 (node as Mutable<ClassStaticBlockDeclaration>).modifiers = modifiers; 7857 return node; 7858 } 7859 7860 function parseClassStaticBlockBody() { 7861 const savedYieldContext = inYieldContext(); 7862 const savedAwaitContext = inAwaitContext(); 7863 7864 setYieldContext(false); 7865 setAwaitContext(true); 7866 7867 const body = parseBlock(/*ignoreMissingOpenBrace*/ false); 7868 7869 setYieldContext(savedYieldContext); 7870 setAwaitContext(savedAwaitContext); 7871 7872 return body; 7873 } 7874 7875 function parseDecoratorExpression() { 7876 if (inAwaitContext() && token() === SyntaxKind.AwaitKeyword) { 7877 // `@await` is is disallowed in an [Await] context, but can cause parsing to go off the rails 7878 // This simply parses the missing identifier and moves on. 7879 const pos = getNodePos(); 7880 const awaitExpression = parseIdentifier(Diagnostics.Expression_expected); 7881 nextToken(); 7882 const memberExpression = parseMemberExpressionRest(pos, awaitExpression, /*allowOptionalChain*/ true); 7883 return parseCallExpressionRest(pos, memberExpression); 7884 } 7885 return parseLeftHandSideExpressionOrHigher(); 7886 } 7887 7888 function tryParseDecorator(): Decorator | undefined { 7889 const pos = getNodePos(); 7890 if (inEtsAnnotationContext() && token() === SyntaxKind.AtToken 7891 && lookAhead(() => nextToken() === SyntaxKind.InterfaceKeyword)) { 7892 return undefined; 7893 } 7894 if (!parseOptional(SyntaxKind.AtToken)) { 7895 return undefined; 7896 } 7897 const expression = doInDecoratorContext(parseDecoratorExpression); 7898 return finishNode(factory.createDecorator(expression), pos); 7899 } 7900 7901 function parseDecorators(): NodeArray<Decorator> | undefined { 7902 const pos = getNodePos(); 7903 let list, decorator; 7904 while (decorator = tryParseDecorator()) { 7905 list = append(list, decorator); 7906 } 7907 return list && createNodeArray(list, pos); 7908 } 7909 7910 function tryParseModifier(permitInvalidConstAsModifier?: boolean, stopOnStartOfClassStaticBlock?: boolean, hasSeenStaticModifier?: boolean): Modifier | undefined { 7911 const pos = getNodePos(); 7912 const kind = token(); 7913 7914 if (token() === SyntaxKind.ConstKeyword && permitInvalidConstAsModifier) { 7915 // We need to ensure that any subsequent modifiers appear on the same line 7916 // so that when 'const' is a standalone declaration, we don't issue an error. 7917 if (!tryParse(nextTokenIsOnSameLineAndCanFollowModifier)) { 7918 return undefined; 7919 } 7920 } 7921 else if (stopOnStartOfClassStaticBlock && token() === SyntaxKind.StaticKeyword && lookAhead(nextTokenIsOpenBrace)) { 7922 return undefined; 7923 } 7924 else if (hasSeenStaticModifier && token() === SyntaxKind.StaticKeyword) { 7925 return undefined; 7926 } 7927 else { 7928 if (!parseAnyContextualModifier()) { 7929 return undefined; 7930 } 7931 } 7932 7933 return finishNode(factory.createToken(kind as Modifier["kind"]), pos); 7934 } 7935 7936 function combineDecoratorsAndModifiers(decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): NodeArray<ModifierLike> | undefined { 7937 if (!decorators) return modifiers; 7938 if (!modifiers) return decorators; 7939 const decoratorsAndModifiers = factory.createNodeArray(concatenate<ModifierLike>(decorators, modifiers)); 7940 setTextRangePosEnd(decoratorsAndModifiers, decorators.pos, modifiers.end); 7941 return decoratorsAndModifiers; 7942 } 7943 7944 function hasParamAndNoOnceDecorator(decorators: NodeArray<Decorator> | undefined): boolean { 7945 let hasParamDecorator = false; 7946 let hasOnceDecorator = false; 7947 decorators?.forEach((decorator) => { 7948 if (!ts.isIdentifier(decorator.expression)) { 7949 return; 7950 } 7951 if (decorator.expression.escapedText === 'Param') { 7952 hasParamDecorator = true; 7953 } 7954 else if (decorator.expression.escapedText === 'Once') { 7955 hasOnceDecorator = true; 7956 } 7957 }); 7958 return (hasParamDecorator && !hasOnceDecorator); 7959 } 7960 /* 7961 * There are situations in which a modifier like 'const' will appear unexpectedly, such as on a class member. 7962 * In those situations, if we are entirely sure that 'const' is not valid on its own (such as when ASI takes effect 7963 * and turns it into a standalone declaration), then it is better to parse it and report an error later. 7964 * 7965 * In such situations, 'permitInvalidConstAsModifier' should be set to true. 7966 */ 7967 function parseModifiers( 7968 permitInvalidConstAsModifier?: boolean, 7969 stopOnStartOfClassStaticBlock?: boolean, 7970 shouldAddReadonly?: boolean 7971 ): NodeArray<Modifier> | undefined { 7972 const pos = getNodePos(); 7973 let list, modifier, hasSeenStatic = false; 7974 let hasReadonly = false; 7975 while (modifier = tryParseModifier(permitInvalidConstAsModifier, stopOnStartOfClassStaticBlock, hasSeenStatic)) { 7976 if (modifier.kind === SyntaxKind.StaticKeyword) hasSeenStatic = true; 7977 if (modifier.kind === SyntaxKind.ReadonlyKeyword) { 7978 hasReadonly = true; 7979 } 7980 list = append(list, modifier); 7981 } 7982 if (shouldAddReadonly && !hasReadonly) { 7983 const readonlyModifier = finishVirtualNode(factory.createToken(SyntaxKind.ReadonlyKeyword)); 7984 list = append(list, readonlyModifier); 7985 } 7986 return list && createNodeArray(list, pos); 7987 } 7988 7989 function parseModifiersForArrowFunction(): NodeArray<Modifier> | undefined { 7990 let modifiers: NodeArray<Modifier> | undefined; 7991 if (token() === SyntaxKind.AsyncKeyword) { 7992 const pos = getNodePos(); 7993 nextToken(); 7994 const modifier = finishNode(factory.createToken(SyntaxKind.AsyncKeyword), pos); 7995 modifiers = createNodeArray<Modifier>([modifier], pos); 7996 } 7997 return modifiers; 7998 } 7999 8000 function parseClassElement(): ClassElement { 8001 const pos = getNodePos(); 8002 if (token() === SyntaxKind.SemicolonToken) { 8003 nextToken(); 8004 return finishNode(factory.createSemicolonClassElement(), pos); 8005 } 8006 8007 const hasJSDoc = hasPrecedingJSDocComment(); 8008 const decorators = parseDecorators(); 8009 /* 8010 * shouldAddReadonly adds readonly modifier when the element in struct has the Param decorator 8011 * and doesn't have Once decorator. 8012 */ 8013 const shouldAddReadonly = inStructContext() && hasParamAndNoOnceDecorator(decorators); 8014 const modifiers = parseModifiers(/*permitInvalidConstAsModifier*/ true, /*stopOnStartOfClassStaticBlock*/ true, shouldAddReadonly); 8015 if (token() === SyntaxKind.StaticKeyword && lookAhead(nextTokenIsOpenBrace)) { 8016 return parseClassStaticBlockDeclaration(pos, hasJSDoc, decorators, modifiers); 8017 } 8018 8019 if (parseContextualModifier(SyntaxKind.GetKeyword)) { 8020 return parseAccessorDeclaration(pos, hasJSDoc, decorators, modifiers, SyntaxKind.GetAccessor, SignatureFlags.None); 8021 } 8022 8023 if (parseContextualModifier(SyntaxKind.SetKeyword)) { 8024 return parseAccessorDeclaration(pos, hasJSDoc, decorators, modifiers, SyntaxKind.SetAccessor, SignatureFlags.None); 8025 } 8026 8027 if (token() === SyntaxKind.ConstructorKeyword || token() === SyntaxKind.StringLiteral) { 8028 const constructorDeclaration = tryParseConstructorDeclaration(pos, hasJSDoc, decorators, modifiers); 8029 if (constructorDeclaration) { 8030 return constructorDeclaration; 8031 } 8032 } 8033 8034 if (isIndexSignature()) { 8035 return parseIndexSignatureDeclaration(pos, hasJSDoc, decorators, modifiers); 8036 } 8037 8038 // It is very important that we check this *after* checking indexers because 8039 // the [ token can start an index signature or a computed property name 8040 if (tokenIsIdentifierOrKeyword(token()) || 8041 token() === SyntaxKind.StringLiteral || 8042 token() === SyntaxKind.NumericLiteral || 8043 token() === SyntaxKind.AsteriskToken || 8044 token() === SyntaxKind.OpenBracketToken) { 8045 const isAmbient = some(modifiers, isDeclareModifier); 8046 if (isAmbient) { 8047 for (const m of modifiers!) { 8048 (m as Mutable<Node>).flags |= NodeFlags.Ambient; 8049 } 8050 return doInsideOfContext(NodeFlags.Ambient, () => parsePropertyOrMethodDeclaration(pos, hasJSDoc, decorators, modifiers)); 8051 } 8052 else { 8053 return parsePropertyOrMethodDeclaration(pos, hasJSDoc, decorators, modifiers); 8054 } 8055 } 8056 8057 if (decorators || modifiers) { 8058 // treat this as a property declaration with a missing name. 8059 const name = createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Declaration_expected); 8060 return parsePropertyDeclaration(pos, hasJSDoc, decorators, modifiers, name, /*questionToken*/ undefined); 8061 } 8062 8063 // 'isClassMemberStart' should have hinted not to attempt parsing. 8064 return Debug.fail("Should not have attempted to parse class member declaration."); 8065 } 8066 8067 function parseAnnotationElement(): AnnotationElement { 8068 const pos = getNodePos(); 8069 if (token() === SyntaxKind.SemicolonToken) { 8070 parseErrorAt(pos, pos, Diagnostics.Unexpected_keyword_or_identifier); 8071 } 8072 8073 const hasJSDoc = hasPrecedingJSDocComment(); 8074 if (token() === SyntaxKind.StaticKeyword && lookAhead(nextTokenIsOpenBrace)) { 8075 return createMissingNode<AnnotationElement>(SyntaxKind.AnnotationPropertyDeclaration, /*reportAtCurrentPosition*/ true, Diagnostics.Unexpected_keyword_or_identifier); 8076 } 8077 8078 if (parseContextualModifier(SyntaxKind.GetKeyword)) { 8079 return createMissingNode<AnnotationElement>(SyntaxKind.AnnotationPropertyDeclaration, /*reportAtCurrentPosition*/ true, Diagnostics.Unexpected_keyword_or_identifier); 8080 } 8081 8082 if (parseContextualModifier(SyntaxKind.SetKeyword)) { 8083 return createMissingNode<AnnotationElement>(SyntaxKind.AnnotationPropertyDeclaration, /*reportAtCurrentPosition*/ true, Diagnostics.Unexpected_keyword_or_identifier); 8084 } 8085 8086 if (token() === SyntaxKind.ConstructorKeyword || token() === SyntaxKind.StringLiteral) { 8087 return createMissingNode<AnnotationElement>(SyntaxKind.AnnotationPropertyDeclaration, /*reportAtCurrentPosition*/ true, Diagnostics.Unexpected_keyword_or_identifier); 8088 } 8089 8090 if (isIndexSignature()) { 8091 return createMissingNode<AnnotationElement>(SyntaxKind.AnnotationPropertyDeclaration, /*reportAtCurrentPosition*/ true, Diagnostics.Unexpected_keyword_or_identifier); 8092 } 8093 8094 if (tokenIsIdentifierOrKeyword(token())) { 8095 const name = parsePropertyName(); 8096 return parseAnnotationPropertyDeclaration(pos, hasJSDoc, name); 8097 } 8098 8099 // 'isAnnotationMemberStart' should have hinted not to attempt parsing. 8100 return Debug.fail("Should not have attempted to parse annotation member declaration."); 8101 } 8102 8103 function parseClassExpression(): ClassExpression { 8104 return parseClassDeclarationOrExpression(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined, SyntaxKind.ClassExpression) as ClassExpression; 8105 } 8106 8107 function parseClassDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ClassDeclaration { 8108 return parseClassDeclarationOrExpression(pos, hasJSDoc, decorators, modifiers, SyntaxKind.ClassDeclaration) as ClassDeclaration; 8109 } 8110 8111 function parseStructDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): StructDeclaration { 8112 return parseStructDeclarationOrExpression(pos, hasJSDoc, decorators, modifiers); 8113 } 8114 8115 function parseClassDeclarationOrExpression(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined, kind: ClassLikeDeclaration["kind"]): ClassLikeDeclaration { 8116 const savedAwaitContext = inAwaitContext(); 8117 parseExpected(SyntaxKind.ClassKeyword); 8118 8119 // We don't parse the name here in await context, instead we will report a grammar error in the checker. 8120 const name = parseNameOfClassDeclarationOrExpression(); 8121 const typeParameters = parseTypeParameters(); 8122 if (some(modifiers, isExportModifier)) setAwaitContext(/*value*/ true); 8123 const heritageClauses = parseHeritageClauses(); 8124 8125 let members; 8126 if (parseExpected(SyntaxKind.OpenBraceToken)) { 8127 // ClassTail[Yield,Await] : (Modified) See 14.5 8128 // ClassHeritage[?Yield,?Await]opt { ClassBody[?Yield,?Await]opt } 8129 members = parseClassMembers(); 8130 parseExpected(SyntaxKind.CloseBraceToken); 8131 } 8132 else { 8133 members = createMissingList<ClassElement>(); 8134 } 8135 setAwaitContext(savedAwaitContext); 8136 const node = kind === SyntaxKind.ClassDeclaration 8137 ? factory.createClassDeclaration(combineDecoratorsAndModifiers(decorators, modifiers), name, typeParameters, heritageClauses, members) 8138 : factory.createClassExpression(combineDecoratorsAndModifiers(decorators, modifiers), name, typeParameters, heritageClauses, members); 8139 return withJSDoc(finishNode(node, pos), hasJSDoc); 8140 } 8141 8142 function parseStructDeclarationOrExpression(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): StructDeclaration { 8143 const savedAwaitContext = inAwaitContext(); 8144 parseExpected(SyntaxKind.StructKeyword); 8145 setStructContext(true); 8146 // We don't parse the name here in await context, instead we will report a grammar error in the checker. 8147 // struct Identifier logic is same to class Identifier 8148 const name = parseNameOfClassDeclarationOrExpression(); 8149 const typeParameters = parseTypeParameters(); 8150 if (some(modifiers, isExportModifier)) setAwaitContext(/*value*/ true); 8151 let heritageClauses = parseHeritageClauses(); 8152 const customComponent = sourceFileCompilerOptions.ets?.customComponent; 8153 if (!heritageClauses && customComponent) { 8154 heritageClauses = createVirtualHeritageClauses(customComponent); 8155 } 8156 let members; 8157 if (parseExpected(SyntaxKind.OpenBraceToken)) { 8158 // ClassTail[Yield,Await] : (Modified) See 14.5 8159 // ClassHeritage[?Yield,?Await]opt { ClassBody[?Yield,?Await]opt } 8160 members = parseStructMembers(pos); 8161 parseExpected(SyntaxKind.CloseBraceToken); 8162 } 8163 else { 8164 members = createMissingList<ClassElement>(); 8165 } 8166 setAwaitContext(savedAwaitContext); 8167 const node = factory.createStructDeclaration(combineDecoratorsAndModifiers(decorators, modifiers), name, typeParameters, heritageClauses, members); 8168 structStylesComponents.clear(); 8169 setStructContext(false); 8170 return withJSDoc(finishNode(node, pos), hasJSDoc); 8171 } 8172 8173 function createVirtualHeritageClauses(customComponent: string): NodeArray<HeritageClause> { 8174 const curPos = getNodePos(); 8175 const clause = factory.createHeritageClause( 8176 SyntaxKind.ExtendsKeyword, 8177 createNodeArray([finishNode(factory.createExpressionWithTypeArguments( 8178 finishNode(factory.createIdentifier(/*text*/ customComponent), curPos, /*end*/ undefined, /*virtual*/ true), 8179 /*typeArguments*/ undefined 8180 ), curPos)], curPos, /*end*/ undefined, /*hasTrailingComma*/ false) 8181 ); 8182 return createNodeArray([finishNode(clause, curPos, /*end*/ undefined, /*virtual*/ true)], curPos, /*end*/ undefined, /*hasTrailingComma*/ false); 8183 } 8184 8185 function parseNameOfClassDeclarationOrExpression(): Identifier | undefined { 8186 // implements is a future reserved word so 8187 // 'class implements' might mean either 8188 // - class expression with omitted name, 'implements' starts heritage clause 8189 // - class with name 'implements' 8190 // 'isImplementsClause' helps to disambiguate between these two cases 8191 return isBindingIdentifier() && !isImplementsClause() 8192 ? createIdentifier(isBindingIdentifier()) 8193 : undefined; 8194 } 8195 8196 function isImplementsClause() { 8197 return token() === SyntaxKind.ImplementsKeyword && lookAhead(nextTokenIsIdentifierOrKeyword); 8198 } 8199 8200 function parseHeritageClauses(): NodeArray<HeritageClause> | undefined { 8201 // ClassTail[Yield,Await] : (Modified) See 14.5 8202 // ClassHeritage[?Yield,?Await]opt { ClassBody[?Yield,?Await]opt } 8203 8204 if (isHeritageClause()) { 8205 return parseList(ParsingContext.HeritageClauses, parseHeritageClause); 8206 } 8207 8208 return undefined; 8209 } 8210 8211 function parseHeritageClause(): HeritageClause { 8212 const pos = getNodePos(); 8213 const tok = token(); 8214 Debug.assert(tok === SyntaxKind.ExtendsKeyword || tok === SyntaxKind.ImplementsKeyword); // isListElement() should ensure this. 8215 nextToken(); 8216 const types = parseDelimitedList(ParsingContext.HeritageClauseElement, parseExpressionWithTypeArguments); 8217 return finishNode(factory.createHeritageClause(tok, types), pos); 8218 } 8219 8220 function parseExpressionWithTypeArguments(): ExpressionWithTypeArguments { 8221 const pos = getNodePos(); 8222 const expression = parseLeftHandSideExpressionOrHigher(); 8223 if (expression.kind === SyntaxKind.ExpressionWithTypeArguments) { 8224 return expression as ExpressionWithTypeArguments; 8225 } 8226 const typeArguments = tryParseTypeArguments(); 8227 return finishNode(factory.createExpressionWithTypeArguments(expression, typeArguments), pos); 8228 } 8229 8230 function tryParseTypeArguments(): NodeArray<TypeNode> | undefined { 8231 return token() === SyntaxKind.LessThanToken ? 8232 parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken) : undefined; 8233 } 8234 8235 function isHeritageClause(): boolean { 8236 return token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword; 8237 } 8238 8239 function parseClassMembers(): NodeArray<ClassElement> { 8240 return parseList(ParsingContext.ClassMembers, parseClassElement); 8241 } 8242 8243 function parseAnnotationMembers(): NodeArray<AnnotationElement> { 8244 return parseList(ParsingContext.AnnotationMembers, parseAnnotationElement); 8245 } 8246 8247 function parseStructMembers(pos: number): NodeArray<ClassElement> { 8248 const structMembers = parseList(ParsingContext.ClassMembers, parseClassElement); 8249 8250 const virtualStructMembers: ClassElement[] = []; 8251 // create constructor function argument object properties 8252 const virtualParameterProperties: TypeElement[] = []; 8253 structMembers.forEach(member => { 8254 virtualStructMembers.push(member); 8255 if (member.kind === SyntaxKind.PropertyDeclaration) { 8256 const property = <PropertyDeclaration>member; 8257 virtualParameterProperties.push( 8258 finishVirtualNode( 8259 factory.createPropertySignature(getModifiers(property), property.name, factory.createToken(SyntaxKind.QuestionToken), property.type) 8260 ) 8261 ); 8262 } 8263 }); 8264 const parameters: ParameterDeclaration[] = []; 8265 if (virtualParameterProperties.length) { 8266 const type = finishVirtualNode(factory.createTypeLiteralNode(createNodeArray(virtualParameterProperties, 0, 0))); 8267 parameters.push( 8268 finishVirtualNode( 8269 factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, 8270 finishVirtualNode(factory.createIdentifier("value")), factory.createToken(SyntaxKind.QuestionToken), type 8271 ) 8272 ) 8273 ); 8274 } 8275 // Add parameter ##storage?: LocalStorage to struct constructor. 8276 parameters.push( 8277 finishVirtualNode( 8278 factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, 8279 finishVirtualNode(factory.createIdentifier("##storage")), factory.createToken(SyntaxKind.QuestionToken), 8280 finishVirtualNode(factory.createTypeReferenceNode(finishVirtualNode(factory.createIdentifier("LocalStorage")))) 8281 ) 8282 ) 8283 ); 8284 const emptyBody = finishVirtualNode(factory.createBlock(createNodeArray([], 0, 0))); 8285 const virtualConstructor = factory.createConstructorDeclaration(/*modifier*/ undefined, createNodeArray(parameters, 0, 0), emptyBody); 8286 8287 virtualStructMembers.unshift(finishVirtualNode(virtualConstructor, pos, pos)); 8288 8289 return createNodeArray(virtualStructMembers, structMembers.pos); 8290 } 8291 8292 function finishVirtualNode<T extends Node>(node: T, start = 0, end = 0) { 8293 return finishNode(node, start, end, /*virtual*/ true); 8294 } 8295 8296 function parseInterfaceDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): InterfaceDeclaration { 8297 parseExpected(SyntaxKind.InterfaceKeyword); 8298 const name = parseIdentifier(); 8299 const typeParameters = parseTypeParameters(); 8300 const heritageClauses = parseHeritageClauses(); 8301 const members = parseObjectTypeMembers(); 8302 const node = factory.createInterfaceDeclaration(modifiers, name, typeParameters, heritageClauses, members); 8303 (node as Mutable<InterfaceDeclaration>).illegalDecorators = decorators; 8304 return withJSDoc(finishNode(node, pos), hasJSDoc); 8305 } 8306 8307 function parseTypeAliasDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): TypeAliasDeclaration { 8308 parseExpected(SyntaxKind.TypeKeyword); 8309 const name = parseIdentifier(); 8310 const typeParameters = parseTypeParameters(); 8311 parseExpected(SyntaxKind.EqualsToken); 8312 const type = token() === SyntaxKind.IntrinsicKeyword && tryParse(parseKeywordAndNoDot) || parseType(); 8313 parseSemicolon(); 8314 const node = factory.createTypeAliasDeclaration(modifiers, name, typeParameters, type); 8315 (node as Mutable<TypeAliasDeclaration>).illegalDecorators = decorators; 8316 return withJSDoc(finishNode(node, pos), hasJSDoc); 8317 } 8318 8319 // In an ambient declaration, the grammar only allows integer literals as initializers. 8320 // In a non-ambient declaration, the grammar allows uninitialized members only in a 8321 // ConstantEnumMemberSection, which starts at the beginning of an enum declaration 8322 // or any time an integer literal initializer is encountered. 8323 function parseEnumMember(): EnumMember { 8324 const pos = getNodePos(); 8325 const hasJSDoc = hasPrecedingJSDocComment(); 8326 const name = parsePropertyName(); 8327 const initializer = allowInAnd(parseInitializer); 8328 return withJSDoc(finishNode(factory.createEnumMember(name, initializer), pos), hasJSDoc); 8329 } 8330 8331 function parseEnumDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): EnumDeclaration { 8332 parseExpected(SyntaxKind.EnumKeyword); 8333 const name = parseIdentifier(); 8334 let members; 8335 if (parseExpected(SyntaxKind.OpenBraceToken)) { 8336 members = doOutsideOfYieldAndAwaitContext(() => parseDelimitedList(ParsingContext.EnumMembers, parseEnumMember)); 8337 parseExpected(SyntaxKind.CloseBraceToken); 8338 } 8339 else { 8340 members = createMissingList<EnumMember>(); 8341 } 8342 const node = factory.createEnumDeclaration(modifiers, name, members); 8343 (node as Mutable<EnumDeclaration>).illegalDecorators = decorators; 8344 return withJSDoc(finishNode(node, pos), hasJSDoc); 8345 } 8346 8347 function parseModuleBlock(): ModuleBlock { 8348 const pos = getNodePos(); 8349 let statements; 8350 if (parseExpected(SyntaxKind.OpenBraceToken)) { 8351 statements = parseList(ParsingContext.BlockStatements, parseStatement); 8352 parseExpected(SyntaxKind.CloseBraceToken); 8353 } 8354 else { 8355 statements = createMissingList<Statement>(); 8356 } 8357 return finishNode(factory.createModuleBlock(statements), pos); 8358 } 8359 8360 function parseModuleOrNamespaceDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined, flags: NodeFlags): ModuleDeclaration { 8361 // If we are parsing a dotted namespace name, we want to 8362 // propagate the 'Namespace' flag across the names if set. 8363 const namespaceFlag = flags & NodeFlags.Namespace; 8364 const name = parseIdentifier(); 8365 const body = parseOptional(SyntaxKind.DotToken) 8366 ? parseModuleOrNamespaceDeclaration(getNodePos(), /*hasJSDoc*/ false, /*decorators*/ undefined, /*modifiers*/ undefined, NodeFlags.NestedNamespace | namespaceFlag) as NamespaceDeclaration 8367 : parseModuleBlock(); 8368 const node = factory.createModuleDeclaration(modifiers, name, body, flags); 8369 (node as Mutable<ModuleDeclaration>).illegalDecorators = decorators; 8370 return withJSDoc(finishNode(node, pos), hasJSDoc); 8371 } 8372 8373 function parseAmbientExternalModuleDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ModuleDeclaration { 8374 let flags: NodeFlags = 0; 8375 let name; 8376 if (token() === SyntaxKind.GlobalKeyword) { 8377 // parse 'global' as name of global scope augmentation 8378 name = parseIdentifier(); 8379 flags |= NodeFlags.GlobalAugmentation; 8380 } 8381 else { 8382 name = parseLiteralNode() as StringLiteral; 8383 name.text = internIdentifier(name.text); 8384 } 8385 let body: ModuleBlock | undefined; 8386 if (token() === SyntaxKind.OpenBraceToken) { 8387 body = parseModuleBlock(); 8388 } 8389 else { 8390 parseSemicolon(); 8391 } 8392 const node = factory.createModuleDeclaration(modifiers, name, body, flags); 8393 (node as Mutable<ModuleDeclaration>).illegalDecorators = decorators; 8394 return withJSDoc(finishNode(node, pos), hasJSDoc); 8395 } 8396 8397 function parseModuleDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ModuleDeclaration { 8398 let flags: NodeFlags = 0; 8399 if (token() === SyntaxKind.GlobalKeyword) { 8400 // global augmentation 8401 return parseAmbientExternalModuleDeclaration(pos, hasJSDoc, decorators, modifiers); 8402 } 8403 else if (parseOptional(SyntaxKind.NamespaceKeyword)) { 8404 flags |= NodeFlags.Namespace; 8405 } 8406 else { 8407 parseExpected(SyntaxKind.ModuleKeyword); 8408 if (token() === SyntaxKind.StringLiteral) { 8409 return parseAmbientExternalModuleDeclaration(pos, hasJSDoc, decorators, modifiers); 8410 } 8411 } 8412 return parseModuleOrNamespaceDeclaration(pos, hasJSDoc, decorators, modifiers, flags); 8413 } 8414 8415 function isExternalModuleReference() { 8416 return token() === SyntaxKind.RequireKeyword && 8417 lookAhead(nextTokenIsOpenParen); 8418 } 8419 8420 function nextTokenIsOpenParen() { 8421 return nextToken() === SyntaxKind.OpenParenToken; 8422 } 8423 8424 function nextTokenIsOpenBrace() { 8425 return nextToken() === SyntaxKind.OpenBraceToken; 8426 } 8427 8428 function nextTokenIsSlash() { 8429 return nextToken() === SyntaxKind.SlashToken; 8430 } 8431 8432 function parseNamespaceExportDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): NamespaceExportDeclaration { 8433 parseExpected(SyntaxKind.AsKeyword); 8434 parseExpected(SyntaxKind.NamespaceKeyword); 8435 const name = parseIdentifier(); 8436 parseSemicolon(); 8437 const node = factory.createNamespaceExportDeclaration(name); 8438 // NamespaceExportDeclaration nodes cannot have decorators or modifiers, so we attach them here so we can report them in the grammar checker 8439 (node as Mutable<NamespaceExportDeclaration>).illegalDecorators = decorators; 8440 (node as Mutable<NamespaceExportDeclaration>).modifiers = modifiers; 8441 return withJSDoc(finishNode(node, pos), hasJSDoc); 8442 } 8443 8444 function parseImportDeclarationOrImportEqualsDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ImportEqualsDeclaration | ImportDeclaration { 8445 parseExpected(SyntaxKind.ImportKeyword); 8446 8447 const afterImportPos = scanner.getStartPos(); 8448 8449 // We don't parse the identifier here in await context, instead we will report a grammar error in the checker. 8450 let identifier: Identifier | undefined; 8451 if (isIdentifier()) { 8452 identifier = parseIdentifier(); 8453 } 8454 8455 let isTypeOnly = false; 8456 let isLazy = false; 8457 if (token() !== SyntaxKind.FromKeyword && 8458 identifier?.escapedText === "type" && 8459 (isIdentifier() || tokenAfterImportDefinitelyProducesImportDeclaration()) 8460 ) { 8461 isTypeOnly = true; 8462 identifier = isIdentifier() ? parseIdentifier() : undefined; 8463 } 8464 else if (isSetLazy(identifier)) { 8465 isLazy = true; 8466 identifier = isIdentifier() ? parseIdentifier() : undefined; 8467 } 8468 8469 if (identifier && !tokenAfterImportedIdentifierDefinitelyProducesImportDeclaration()) { 8470 return parseImportEqualsDeclaration(pos, hasJSDoc, decorators, modifiers, identifier, isTypeOnly); 8471 } 8472 8473 // ImportDeclaration: 8474 // import ImportClause from ModuleSpecifier; 8475 // import ModuleSpecifier; 8476 let importClause: ImportClause | undefined; 8477 if (identifier || // import id 8478 token() === SyntaxKind.AsteriskToken || // import * 8479 token() === SyntaxKind.OpenBraceToken // import { 8480 ) { 8481 importClause = parseImportClause(identifier, afterImportPos, isTypeOnly); 8482 (importClause as Mutable<ImportClause>).isLazy = isLazy; 8483 parseExpected(SyntaxKind.FromKeyword); 8484 } 8485 const moduleSpecifier = parseModuleSpecifier(); 8486 8487 let assertClause: AssertClause | undefined; 8488 if (token() === SyntaxKind.AssertKeyword && !scanner.hasPrecedingLineBreak()) { 8489 assertClause = parseAssertClause(); 8490 } 8491 8492 parseSemicolon(); 8493 const node = factory.createImportDeclaration(modifiers, importClause, moduleSpecifier, assertClause); 8494 (node as Mutable<ImportDeclaration>).illegalDecorators = decorators; 8495 return withJSDoc(finishNode(node, pos), hasJSDoc); 8496 } 8497 8498 function isSetLazy(identifier: Identifier | undefined): boolean { 8499 // 1. import lazy { export } from "mod"; 8500 // 2. import lazy defaultExport from "mod"; 8501 // 3. import lazy defaultExport, { export, /* ... */ } from "mod"; 8502 return identifier?.escapedText === 'lazy' && 8503 (token() === SyntaxKind.OpenBraceToken || 8504 (isIdentifier() && lookAhead(() => nextToken() === SyntaxKind.FromKeyword)) || 8505 (isIdentifier() && lookAhead(() => nextToken() === SyntaxKind.CommaToken && nextToken() === SyntaxKind.OpenBraceToken))); 8506 } 8507 8508 function parseAssertEntry() { 8509 const pos = getNodePos(); 8510 const name = tokenIsIdentifierOrKeyword(token()) ? parseIdentifierName() : parseLiteralLikeNode(SyntaxKind.StringLiteral) as StringLiteral; 8511 parseExpected(SyntaxKind.ColonToken); 8512 const value = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true); 8513 return finishNode(factory.createAssertEntry(name, value), pos); 8514 } 8515 8516 function parseAssertClause(skipAssertKeyword?: true) { 8517 const pos = getNodePos(); 8518 if (!skipAssertKeyword) { 8519 parseExpected(SyntaxKind.AssertKeyword); 8520 } 8521 const openBracePosition = scanner.getTokenPos(); 8522 if (parseExpected(SyntaxKind.OpenBraceToken)) { 8523 const multiLine = scanner.hasPrecedingLineBreak(); 8524 const elements = parseDelimitedList(ParsingContext.AssertEntries, parseAssertEntry, /*considerSemicolonAsDelimiter*/ true); 8525 if (!parseExpected(SyntaxKind.CloseBraceToken)) { 8526 const lastError = lastOrUndefined(parseDiagnostics); 8527 if (lastError && lastError.code === Diagnostics._0_expected.code) { 8528 addRelatedInfo( 8529 lastError, 8530 createDetachedDiagnostic(fileName, openBracePosition, 1, Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, "{", "}") 8531 ); 8532 } 8533 } 8534 return finishNode(factory.createAssertClause(elements, multiLine), pos); 8535 } 8536 else { 8537 const elements = createNodeArray([], getNodePos(), /*end*/ undefined, /*hasTrailingComma*/ false); 8538 return finishNode(factory.createAssertClause(elements, /*multiLine*/ false), pos); 8539 } 8540 } 8541 8542 function tokenAfterImportDefinitelyProducesImportDeclaration() { 8543 return token() === SyntaxKind.AsteriskToken || token() === SyntaxKind.OpenBraceToken; 8544 } 8545 8546 function tokenAfterImportedIdentifierDefinitelyProducesImportDeclaration() { 8547 // In `import id ___`, the current token decides whether to produce 8548 // an ImportDeclaration or ImportEqualsDeclaration. 8549 return token() === SyntaxKind.CommaToken || token() === SyntaxKind.FromKeyword; 8550 } 8551 8552 function parseImportEqualsDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined, identifier: Identifier, isTypeOnly: boolean): ImportEqualsDeclaration { 8553 parseExpected(SyntaxKind.EqualsToken); 8554 const moduleReference = parseModuleReference(); 8555 parseSemicolon(); 8556 const node = factory.createImportEqualsDeclaration(modifiers, isTypeOnly, identifier, moduleReference); 8557 (node as Mutable<ImportEqualsDeclaration>).illegalDecorators = decorators; 8558 const finished = withJSDoc(finishNode(node, pos), hasJSDoc); 8559 return finished; 8560 } 8561 8562 function parseImportClause(identifier: Identifier | undefined, pos: number, isTypeOnly: boolean) { 8563 // ImportClause: 8564 // ImportedDefaultBinding 8565 // NameSpaceImport 8566 // NamedImports 8567 // ImportedDefaultBinding, NameSpaceImport 8568 // ImportedDefaultBinding, NamedImports 8569 8570 // If there was no default import or if there is comma token after default import 8571 // parse namespace or named imports 8572 let namedBindings: NamespaceImport | NamedImports | undefined; 8573 if (!identifier || 8574 parseOptional(SyntaxKind.CommaToken)) { 8575 namedBindings = token() === SyntaxKind.AsteriskToken ? parseNamespaceImport() : parseNamedImportsOrExports(SyntaxKind.NamedImports); 8576 } 8577 8578 return finishNode(factory.createImportClause(isTypeOnly, identifier, namedBindings), pos); 8579 } 8580 8581 function parseModuleReference() { 8582 return isExternalModuleReference() 8583 ? parseExternalModuleReference() 8584 : parseEntityName(/*allowReservedWords*/ false); 8585 } 8586 8587 function parseExternalModuleReference() { 8588 const pos = getNodePos(); 8589 parseExpected(SyntaxKind.RequireKeyword); 8590 parseExpected(SyntaxKind.OpenParenToken); 8591 const expression = parseModuleSpecifier(); 8592 parseExpected(SyntaxKind.CloseParenToken); 8593 return finishNode(factory.createExternalModuleReference(expression), pos); 8594 } 8595 8596 function parseModuleSpecifier(): Expression { 8597 if (token() === SyntaxKind.StringLiteral) { 8598 const result = parseLiteralNode(); 8599 result.text = internIdentifier(result.text); 8600 return result; 8601 } 8602 else { 8603 // We allow arbitrary expressions here, even though the grammar only allows string 8604 // literals. We check to ensure that it is only a string literal later in the grammar 8605 // check pass. 8606 return parseExpression(); 8607 } 8608 } 8609 8610 function parseNamespaceImport(): NamespaceImport { 8611 // NameSpaceImport: 8612 // * as ImportedBinding 8613 const pos = getNodePos(); 8614 parseExpected(SyntaxKind.AsteriskToken); 8615 parseExpected(SyntaxKind.AsKeyword); 8616 const name = parseIdentifier(); 8617 return finishNode(factory.createNamespaceImport(name), pos); 8618 } 8619 8620 function parseNamedImportsOrExports(kind: SyntaxKind.NamedImports): NamedImports; 8621 function parseNamedImportsOrExports(kind: SyntaxKind.NamedExports): NamedExports; 8622 function parseNamedImportsOrExports(kind: SyntaxKind): NamedImportsOrExports { 8623 const pos = getNodePos(); 8624 8625 // NamedImports: 8626 // { } 8627 // { ImportsList } 8628 // { ImportsList, } 8629 8630 // ImportsList: 8631 // ImportSpecifier 8632 // ImportsList, ImportSpecifier 8633 const node = kind === SyntaxKind.NamedImports 8634 ? factory.createNamedImports(parseBracketedList(ParsingContext.ImportOrExportSpecifiers, parseImportSpecifier, SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken)) 8635 : factory.createNamedExports(parseBracketedList(ParsingContext.ImportOrExportSpecifiers, parseExportSpecifier, SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken)); 8636 return finishNode(node, pos); 8637 } 8638 8639 function parseExportSpecifier() { 8640 const hasJSDoc = hasPrecedingJSDocComment(); 8641 return withJSDoc(parseImportOrExportSpecifier(SyntaxKind.ExportSpecifier) as ExportSpecifier, hasJSDoc); 8642 } 8643 8644 function parseImportSpecifier() { 8645 return parseImportOrExportSpecifier(SyntaxKind.ImportSpecifier) as ImportSpecifier; 8646 } 8647 8648 function parseImportOrExportSpecifier(kind: SyntaxKind): ImportOrExportSpecifier { 8649 const pos = getNodePos(); 8650 // ImportSpecifier: 8651 // BindingIdentifier 8652 // IdentifierName as BindingIdentifier 8653 // ExportSpecifier: 8654 // IdentifierName 8655 // IdentifierName as IdentifierName 8656 let checkIdentifierIsKeyword = isKeyword(token()) && !isIdentifier(); 8657 let checkIdentifierStart = scanner.getTokenPos(); 8658 let checkIdentifierEnd = scanner.getTextPos(); 8659 let isTypeOnly = false; 8660 let propertyName: Identifier | undefined; 8661 let canParseAsKeyword = true; 8662 let name = parseIdentifierName(); 8663 if (name.escapedText === "type") { 8664 // If the first token of an import specifier is 'type', there are a lot of possibilities, 8665 // especially if we see 'as' afterwards: 8666 // 8667 // import { type } from "mod"; - isTypeOnly: false, name: type 8668 // import { type as } from "mod"; - isTypeOnly: true, name: as 8669 // import { type as as } from "mod"; - isTypeOnly: false, name: as, propertyName: type 8670 // import { type as as as } from "mod"; - isTypeOnly: true, name: as, propertyName: as 8671 if (token() === SyntaxKind.AsKeyword) { 8672 // { type as ...? } 8673 const firstAs = parseIdentifierName(); 8674 if (token() === SyntaxKind.AsKeyword) { 8675 // { type as as ...? } 8676 const secondAs = parseIdentifierName(); 8677 if (tokenIsIdentifierOrKeyword(token())) { 8678 // { type as as something } 8679 isTypeOnly = true; 8680 propertyName = firstAs; 8681 name = parseNameWithKeywordCheck(); 8682 canParseAsKeyword = false; 8683 } 8684 else { 8685 // { type as as } 8686 propertyName = name; 8687 name = secondAs; 8688 canParseAsKeyword = false; 8689 } 8690 } 8691 else if (tokenIsIdentifierOrKeyword(token())) { 8692 // { type as something } 8693 propertyName = name; 8694 canParseAsKeyword = false; 8695 name = parseNameWithKeywordCheck(); 8696 } 8697 else { 8698 // { type as } 8699 isTypeOnly = true; 8700 name = firstAs; 8701 } 8702 } 8703 else if (tokenIsIdentifierOrKeyword(token())) { 8704 // { type something ...? } 8705 isTypeOnly = true; 8706 name = parseNameWithKeywordCheck(); 8707 } 8708 } 8709 8710 if (canParseAsKeyword && token() === SyntaxKind.AsKeyword) { 8711 propertyName = name; 8712 parseExpected(SyntaxKind.AsKeyword); 8713 name = parseNameWithKeywordCheck(); 8714 } 8715 if (kind === SyntaxKind.ImportSpecifier && checkIdentifierIsKeyword) { 8716 parseErrorAt(checkIdentifierStart, checkIdentifierEnd, Diagnostics.Identifier_expected); 8717 } 8718 const node = kind === SyntaxKind.ImportSpecifier 8719 ? factory.createImportSpecifier(isTypeOnly, propertyName, name) 8720 : factory.createExportSpecifier(isTypeOnly, propertyName, name); 8721 return finishNode(node, pos); 8722 8723 function parseNameWithKeywordCheck() { 8724 checkIdentifierIsKeyword = isKeyword(token()) && !isIdentifier(); 8725 checkIdentifierStart = scanner.getTokenPos(); 8726 checkIdentifierEnd = scanner.getTextPos(); 8727 return parseIdentifierName(); 8728 } 8729 } 8730 8731 function parseNamespaceExport(pos: number): NamespaceExport { 8732 return finishNode(factory.createNamespaceExport(parseIdentifierName()), pos); 8733 } 8734 8735 function parseExportDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ExportDeclaration { 8736 const savedAwaitContext = inAwaitContext(); 8737 setAwaitContext(/*value*/ true); 8738 let exportClause: NamedExportBindings | undefined; 8739 let moduleSpecifier: Expression | undefined; 8740 let assertClause: AssertClause | undefined; 8741 const isTypeOnly = parseOptional(SyntaxKind.TypeKeyword); 8742 const namespaceExportPos = getNodePos(); 8743 if (parseOptional(SyntaxKind.AsteriskToken)) { 8744 if (parseOptional(SyntaxKind.AsKeyword)) { 8745 exportClause = parseNamespaceExport(namespaceExportPos); 8746 } 8747 parseExpected(SyntaxKind.FromKeyword); 8748 moduleSpecifier = parseModuleSpecifier(); 8749 } 8750 else { 8751 exportClause = parseNamedImportsOrExports(SyntaxKind.NamedExports); 8752 // It is not uncommon to accidentally omit the 'from' keyword. Additionally, in editing scenarios, 8753 // the 'from' keyword can be parsed as a named export when the export clause is unterminated (i.e. `export { from "moduleName";`) 8754 // If we don't have a 'from' keyword, see if we have a string literal such that ASI won't take effect. 8755 if (token() === SyntaxKind.FromKeyword || (token() === SyntaxKind.StringLiteral && !scanner.hasPrecedingLineBreak())) { 8756 parseExpected(SyntaxKind.FromKeyword); 8757 moduleSpecifier = parseModuleSpecifier(); 8758 } 8759 } 8760 if (moduleSpecifier && token() === SyntaxKind.AssertKeyword && !scanner.hasPrecedingLineBreak()) { 8761 assertClause = parseAssertClause(); 8762 } 8763 parseSemicolon(); 8764 setAwaitContext(savedAwaitContext); 8765 const node = factory.createExportDeclaration(modifiers, isTypeOnly, exportClause, moduleSpecifier, assertClause); 8766 (node as Mutable<ExportDeclaration>).illegalDecorators = decorators; 8767 return withJSDoc(finishNode(node, pos), hasJSDoc); 8768 } 8769 8770 function parseExportAssignment(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ExportAssignment { 8771 const savedAwaitContext = inAwaitContext(); 8772 setAwaitContext(/*value*/ true); 8773 let isExportEquals: boolean | undefined; 8774 if (parseOptional(SyntaxKind.EqualsToken)) { 8775 isExportEquals = true; 8776 } 8777 else { 8778 parseExpected(SyntaxKind.DefaultKeyword); 8779 } 8780 const expression = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true); 8781 parseSemicolon(); 8782 setAwaitContext(savedAwaitContext); 8783 const node = factory.createExportAssignment(modifiers, isExportEquals, expression); 8784 (node as Mutable<ExportAssignment>).illegalDecorators = decorators; 8785 return withJSDoc(finishNode(node, pos), hasJSDoc); 8786 } 8787 8788 const enum ParsingContext { 8789 SourceElements, // Elements in source file 8790 BlockStatements, // Statements in block 8791 SwitchClauses, // Clauses in switch statement 8792 SwitchClauseStatements, // Statements in switch clause 8793 TypeMembers, // Members in interface or type literal 8794 ClassMembers, // Members in class declaration 8795 AnnotationMembers, // Members in annotation declaration 8796 EnumMembers, // Members in enum declaration 8797 HeritageClauseElement, // Elements in a heritage clause 8798 VariableDeclarations, // Variable declarations in variable statement 8799 ObjectBindingElements, // Binding elements in object binding list 8800 ArrayBindingElements, // Binding elements in array binding list 8801 ArgumentExpressions, // Expressions in argument list 8802 ObjectLiteralMembers, // Members in object literal 8803 JsxAttributes, // Attributes in jsx element 8804 JsxChildren, // Things between opening and closing JSX tags 8805 ArrayLiteralMembers, // Members in array literal 8806 Parameters, // Parameters in parameter list 8807 JSDocParameters, // JSDoc parameters in parameter list of JSDoc function type 8808 RestProperties, // Property names in a rest type list 8809 TypeParameters, // Type parameters in type parameter list 8810 TypeArguments, // Type arguments in type argument list 8811 TupleElementTypes, // Element types in tuple element type list 8812 HeritageClauses, // Heritage clauses for a class or interface declaration. 8813 ImportOrExportSpecifiers, // Named import clause's import specifier list, 8814 AssertEntries, // Import entries list. 8815 Count // Number of parsing contexts 8816 } 8817 8818 const enum Tristate { 8819 False, 8820 True, 8821 Unknown 8822 } 8823 8824 export namespace JSDocParser { 8825 export function parseJSDocTypeExpressionForTests(content: string, start: number | undefined, length: number | undefined): { jsDocTypeExpression: JSDocTypeExpression, diagnostics: Diagnostic[] } | undefined { 8826 initializeState("file.js", content, ScriptTarget.Latest, /*_syntaxCursor:*/ undefined, ScriptKind.JS); 8827 scanner.setText(content, start, length); 8828 currentToken = scanner.scan(); 8829 const jsDocTypeExpression = parseJSDocTypeExpression(); 8830 8831 const sourceFile = createSourceFile("file.js", ScriptTarget.Latest, ScriptKind.JS, /*isDeclarationFile*/ false, [], factory.createToken(SyntaxKind.EndOfFileToken), NodeFlags.None, noop); 8832 const diagnostics = attachFileToDiagnostics(parseDiagnostics, sourceFile); 8833 if (jsDocDiagnostics) { 8834 sourceFile.jsDocDiagnostics = attachFileToDiagnostics(jsDocDiagnostics, sourceFile); 8835 } 8836 8837 clearState(); 8838 8839 return jsDocTypeExpression ? { jsDocTypeExpression, diagnostics } : undefined; 8840 } 8841 8842 // Parses out a JSDoc type expression. 8843 export function parseJSDocTypeExpression(mayOmitBraces?: boolean): JSDocTypeExpression { 8844 const pos = getNodePos(); 8845 const hasBrace = (mayOmitBraces ? parseOptional : parseExpected)(SyntaxKind.OpenBraceToken); 8846 const type = doInsideOfContext(NodeFlags.JSDoc, parseJSDocType); 8847 if (!mayOmitBraces || hasBrace) { 8848 parseExpectedJSDoc(SyntaxKind.CloseBraceToken); 8849 } 8850 8851 const result = factory.createJSDocTypeExpression(type); 8852 fixupParentReferences(result); 8853 return finishNode(result, pos); 8854 } 8855 8856 export function parseJSDocNameReference(): JSDocNameReference { 8857 const pos = getNodePos(); 8858 const hasBrace = parseOptional(SyntaxKind.OpenBraceToken); 8859 const p2 = getNodePos(); 8860 let entityName: EntityName | JSDocMemberName = parseEntityName(/* allowReservedWords*/ false); 8861 while (token() === SyntaxKind.PrivateIdentifier) { 8862 reScanHashToken(); // rescan #id as # id 8863 nextTokenJSDoc(); // then skip the # 8864 entityName = finishNode(factory.createJSDocMemberName(entityName, parseIdentifier()), p2); 8865 } 8866 if (hasBrace) { 8867 parseExpectedJSDoc(SyntaxKind.CloseBraceToken); 8868 } 8869 8870 const result = factory.createJSDocNameReference(entityName); 8871 fixupParentReferences(result); 8872 return finishNode(result, pos); 8873 } 8874 8875 export function parseIsolatedJSDocComment(content: string, start: number | undefined, length: number | undefined): { jsDoc: JSDoc, diagnostics: Diagnostic[] } | undefined { 8876 initializeState("", content, ScriptTarget.Latest, /*_syntaxCursor:*/ undefined, ScriptKind.JS); 8877 const jsDoc = doInsideOfContext(NodeFlags.JSDoc, () => parseJSDocCommentWorker(start, length)); 8878 8879 const sourceFile = { languageVariant: LanguageVariant.Standard, text: content } as SourceFile; 8880 const diagnostics = attachFileToDiagnostics(parseDiagnostics, sourceFile); 8881 clearState(); 8882 8883 return jsDoc ? { jsDoc, diagnostics } : undefined; 8884 } 8885 8886 export function parseJSDocComment(parent: HasJSDoc, start: number, length: number): JSDoc | undefined { 8887 const saveToken = currentToken; 8888 const saveParseDiagnosticsLength = parseDiagnostics.length; 8889 const saveParseErrorBeforeNextFinishedNode = parseErrorBeforeNextFinishedNode; 8890 8891 const comment = doInsideOfContext(NodeFlags.JSDoc, () => parseJSDocCommentWorker(start, length)); 8892 setParent(comment, parent); 8893 8894 if (contextFlags & NodeFlags.JavaScriptFile) { 8895 if (!jsDocDiagnostics) { 8896 jsDocDiagnostics = []; 8897 } 8898 jsDocDiagnostics.push(...parseDiagnostics); 8899 } 8900 currentToken = saveToken; 8901 parseDiagnostics.length = saveParseDiagnosticsLength; 8902 parseErrorBeforeNextFinishedNode = saveParseErrorBeforeNextFinishedNode; 8903 return comment; 8904 } 8905 8906 const enum JSDocState { 8907 BeginningOfLine, 8908 SawAsterisk, 8909 SavingComments, 8910 SavingBackticks, // NOTE: Only used when parsing tag comments 8911 } 8912 8913 const enum PropertyLikeParse { 8914 Property = 1 << 0, 8915 Parameter = 1 << 1, 8916 CallbackParameter = 1 << 2, 8917 } 8918 8919 function parseJSDocCommentWorker(start = 0, length: number | undefined): JSDoc | undefined { 8920 const content = sourceText; 8921 const end = length === undefined ? content.length : start + length; 8922 length = end - start; 8923 8924 Debug.assert(start >= 0); 8925 Debug.assert(start <= end); 8926 Debug.assert(end <= content.length); 8927 8928 // Check for /** (JSDoc opening part) 8929 if (!isJSDocLikeText(content, start)) { 8930 return undefined; 8931 } 8932 8933 let tags: JSDocTag[]; 8934 let tagsPos: number; 8935 let tagsEnd: number; 8936 let linkEnd: number; 8937 let commentsPos: number | undefined; 8938 let comments: string[] = []; 8939 const parts: JSDocComment[] = []; 8940 8941 // + 3 for leading /**, - 5 in total for /** */ 8942 return scanner.scanRange(start + 3, length - 5, () => { 8943 // Initially we can parse out a tag. We also have seen a starting asterisk. 8944 // This is so that /** * @type */ doesn't parse. 8945 let state = JSDocState.SawAsterisk; 8946 let margin: number | undefined; 8947 // + 4 for leading '/** ' 8948 // + 1 because the last index of \n is always one index before the first character in the line and coincidentally, if there is no \n before start, it is -1, which is also one index before the first character 8949 let indent = start - (content.lastIndexOf("\n", start) + 1) + 4; 8950 function pushComment(text: string) { 8951 if (!margin) { 8952 margin = indent; 8953 } 8954 comments.push(text); 8955 indent += text.length; 8956 } 8957 8958 nextTokenJSDoc(); 8959 while (parseOptionalJsdoc(SyntaxKind.WhitespaceTrivia)); 8960 if (parseOptionalJsdoc(SyntaxKind.NewLineTrivia)) { 8961 state = JSDocState.BeginningOfLine; 8962 indent = 0; 8963 } 8964 loop: while (true) { 8965 switch (token()) { 8966 case SyntaxKind.AtToken: 8967 if (state === JSDocState.BeginningOfLine || state === JSDocState.SawAsterisk) { 8968 removeTrailingWhitespace(comments); 8969 if (!commentsPos) commentsPos = getNodePos(); 8970 addTag(parseTag(indent)); 8971 // NOTE: According to usejsdoc.org, a tag goes to end of line, except the last tag. 8972 // Real-world comments may break this rule, so "BeginningOfLine" will not be a real line beginning 8973 // for malformed examples like `/** @param {string} x @returns {number} the length */` 8974 state = JSDocState.BeginningOfLine; 8975 margin = undefined; 8976 } 8977 else { 8978 pushComment(scanner.getTokenText()); 8979 } 8980 break; 8981 case SyntaxKind.NewLineTrivia: 8982 comments.push(scanner.getTokenText()); 8983 state = JSDocState.BeginningOfLine; 8984 indent = 0; 8985 break; 8986 case SyntaxKind.AsteriskToken: 8987 const asterisk = scanner.getTokenText(); 8988 if (state === JSDocState.SawAsterisk || state === JSDocState.SavingComments) { 8989 // If we've already seen an asterisk, then we can no longer parse a tag on this line 8990 state = JSDocState.SavingComments; 8991 pushComment(asterisk); 8992 } 8993 else { 8994 // Ignore the first asterisk on a line 8995 state = JSDocState.SawAsterisk; 8996 indent += asterisk.length; 8997 } 8998 break; 8999 case SyntaxKind.WhitespaceTrivia: 9000 // only collect whitespace if we're already saving comments or have just crossed the comment indent margin 9001 const whitespace = scanner.getTokenText(); 9002 if (state === JSDocState.SavingComments) { 9003 comments.push(whitespace); 9004 } 9005 else if (margin !== undefined && indent + whitespace.length > margin) { 9006 comments.push(whitespace.slice(margin - indent)); 9007 } 9008 indent += whitespace.length; 9009 break; 9010 case SyntaxKind.EndOfFileToken: 9011 break loop; 9012 case SyntaxKind.OpenBraceToken: 9013 state = JSDocState.SavingComments; 9014 const commentEnd = scanner.getStartPos(); 9015 const linkStart = scanner.getTextPos() - 1; 9016 const link = parseJSDocLink(linkStart); 9017 if (link) { 9018 if (!linkEnd) { 9019 removeLeadingNewlines(comments); 9020 } 9021 parts.push(finishNode(factory.createJSDocText(comments.join("")), linkEnd ?? start, commentEnd)); 9022 parts.push(link); 9023 comments = []; 9024 linkEnd = scanner.getTextPos(); 9025 break; 9026 } 9027 // fallthrough if it's not a {@link sequence 9028 default: 9029 // Anything else is doc comment text. We just save it. Because it 9030 // wasn't a tag, we can no longer parse a tag on this line until we hit the next 9031 // line break. 9032 state = JSDocState.SavingComments; 9033 pushComment(scanner.getTokenText()); 9034 break; 9035 } 9036 nextTokenJSDoc(); 9037 } 9038 removeTrailingWhitespace(comments); 9039 if (parts.length && comments.length) { 9040 parts.push(finishNode(factory.createJSDocText(comments.join("")), linkEnd ?? start, commentsPos)); 9041 } 9042 if (parts.length && tags) Debug.assertIsDefined(commentsPos, "having parsed tags implies that the end of the comment span should be set"); 9043 const tagsArray = tags && createNodeArray(tags, tagsPos, tagsEnd); 9044 return finishNode(factory.createJSDocComment(parts.length ? createNodeArray(parts, start, commentsPos) : comments.length ? comments.join("") : undefined, tagsArray), start, end); 9045 }); 9046 9047 function removeLeadingNewlines(comments: string[]) { 9048 while (comments.length && (comments[0] === "\n" || comments[0] === "\r")) { 9049 comments.shift(); 9050 } 9051 } 9052 9053 function removeTrailingWhitespace(comments: string[]) { 9054 while (comments.length && comments[comments.length - 1].trim() === "") { 9055 comments.pop(); 9056 } 9057 } 9058 9059 function isNextNonwhitespaceTokenEndOfFile(): boolean { 9060 // We must use infinite lookahead, as there could be any number of newlines :( 9061 while (true) { 9062 nextTokenJSDoc(); 9063 if (token() === SyntaxKind.EndOfFileToken) { 9064 return true; 9065 } 9066 if (!(token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia)) { 9067 return false; 9068 } 9069 } 9070 } 9071 9072 function skipWhitespace(): void { 9073 if (token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) { 9074 if (lookAhead(isNextNonwhitespaceTokenEndOfFile)) { 9075 return; // Don't skip whitespace prior to EoF (or end of comment) - that shouldn't be included in any node's range 9076 } 9077 } 9078 while (token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) { 9079 nextTokenJSDoc(); 9080 } 9081 } 9082 9083 function skipWhitespaceOrAsterisk(): string { 9084 if (token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) { 9085 if (lookAhead(isNextNonwhitespaceTokenEndOfFile)) { 9086 return ""; // Don't skip whitespace prior to EoF (or end of comment) - that shouldn't be included in any node's range 9087 } 9088 } 9089 9090 let precedingLineBreak = scanner.hasPrecedingLineBreak(); 9091 let seenLineBreak = false; 9092 let indentText = ""; 9093 while ((precedingLineBreak && token() === SyntaxKind.AsteriskToken) || token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) { 9094 indentText += scanner.getTokenText(); 9095 if (token() === SyntaxKind.NewLineTrivia) { 9096 precedingLineBreak = true; 9097 seenLineBreak = true; 9098 indentText = ""; 9099 } 9100 else if (token() === SyntaxKind.AsteriskToken) { 9101 precedingLineBreak = false; 9102 } 9103 nextTokenJSDoc(); 9104 } 9105 return seenLineBreak ? indentText : ""; 9106 } 9107 9108 function parseTag(margin: number) { 9109 Debug.assert(token() === SyntaxKind.AtToken); 9110 const start = scanner.getTokenPos(); 9111 nextTokenJSDoc(); 9112 9113 const tagName = parseJSDocIdentifierName(/*message*/ undefined); 9114 const indentText = skipWhitespaceOrAsterisk(); 9115 9116 let tag: JSDocTag | undefined; 9117 switch (tagName.escapedText) { 9118 case "author": 9119 tag = parseAuthorTag(start, tagName, margin, indentText); 9120 break; 9121 case "implements": 9122 tag = parseImplementsTag(start, tagName, margin, indentText); 9123 break; 9124 case "augments": 9125 case "extends": 9126 tag = parseAugmentsTag(start, tagName, margin, indentText); 9127 break; 9128 case "class": 9129 case "constructor": 9130 tag = parseSimpleTag(start, factory.createJSDocClassTag, tagName, margin, indentText); 9131 break; 9132 case "public": 9133 tag = parseSimpleTag(start, factory.createJSDocPublicTag, tagName, margin, indentText); 9134 break; 9135 case "private": 9136 tag = parseSimpleTag(start, factory.createJSDocPrivateTag, tagName, margin, indentText); 9137 break; 9138 case "protected": 9139 tag = parseSimpleTag(start, factory.createJSDocProtectedTag, tagName, margin, indentText); 9140 break; 9141 case "readonly": 9142 tag = parseSimpleTag(start, factory.createJSDocReadonlyTag, tagName, margin, indentText); 9143 break; 9144 case "override": 9145 tag = parseSimpleTag(start, factory.createJSDocOverrideTag, tagName, margin, indentText); 9146 break; 9147 case "deprecated": 9148 hasDeprecatedTag = true; 9149 tag = parseSimpleTag(start, factory.createJSDocDeprecatedTag, tagName, margin, indentText); 9150 break; 9151 case "this": 9152 tag = parseThisTag(start, tagName, margin, indentText); 9153 break; 9154 case "enum": 9155 tag = parseEnumTag(start, tagName, margin, indentText); 9156 break; 9157 case "arg": 9158 case "argument": 9159 case "param": 9160 return parseParameterOrPropertyTag(start, tagName, PropertyLikeParse.Parameter, margin); 9161 case "return": 9162 case "returns": 9163 tag = parseReturnTag(start, tagName, margin, indentText); 9164 break; 9165 case "template": 9166 tag = parseTemplateTag(start, tagName, margin, indentText); 9167 break; 9168 case "type": 9169 tag = parseTypeTag(start, tagName, margin, indentText); 9170 break; 9171 case "typedef": 9172 tag = parseTypedefTag(start, tagName, margin, indentText); 9173 break; 9174 case "callback": 9175 tag = parseCallbackTag(start, tagName, margin, indentText); 9176 break; 9177 case "see": 9178 tag = parseSeeTag(start, tagName, margin, indentText); 9179 break; 9180 default: 9181 tag = parseUnknownTag(start, tagName, margin, indentText); 9182 break; 9183 } 9184 return tag; 9185 } 9186 9187 function parseTrailingTagComments(pos: number, end: number, margin: number, indentText: string) { 9188 // some tags, like typedef and callback, have already parsed their comments earlier 9189 if (!indentText) { 9190 margin += end - pos; 9191 } 9192 return parseTagComments(margin, indentText.slice(margin)); 9193 } 9194 9195 function parseTagComments(indent: number, initialMargin?: string): string | NodeArray<JSDocComment> | undefined { 9196 const commentsPos = getNodePos(); 9197 let comments: string[] = []; 9198 const parts: JSDocComment[] = []; 9199 let linkEnd; 9200 let state = JSDocState.BeginningOfLine; 9201 let previousWhitespace = true; 9202 let margin: number | undefined; 9203 function pushComment(text: string) { 9204 if (!margin) { 9205 margin = indent; 9206 } 9207 comments.push(text); 9208 indent += text.length; 9209 } 9210 if (initialMargin !== undefined) { 9211 // jump straight to saving comments if there is some initial indentation 9212 if (initialMargin !== "") { 9213 pushComment(initialMargin); 9214 } 9215 state = JSDocState.SawAsterisk; 9216 } 9217 let tok = token() as JSDocSyntaxKind; 9218 loop: while (true) { 9219 switch (tok) { 9220 case SyntaxKind.NewLineTrivia: 9221 state = JSDocState.BeginningOfLine; 9222 // don't use pushComment here because we want to keep the margin unchanged 9223 comments.push(scanner.getTokenText()); 9224 indent = 0; 9225 break; 9226 case SyntaxKind.AtToken: 9227 if (state === JSDocState.SavingBackticks 9228 || state === JSDocState.SavingComments && (!previousWhitespace || lookAhead(isNextJSDocTokenWhitespace))) { 9229 // @ doesn't start a new tag inside ``, and inside a comment, only after whitespace or not before whitespace 9230 comments.push(scanner.getTokenText()); 9231 break; 9232 } 9233 scanner.setTextPos(scanner.getTextPos() - 1); 9234 // falls through 9235 case SyntaxKind.EndOfFileToken: 9236 // Done 9237 break loop; 9238 case SyntaxKind.WhitespaceTrivia: 9239 if (state === JSDocState.SavingComments || state === JSDocState.SavingBackticks) { 9240 pushComment(scanner.getTokenText()); 9241 } 9242 else { 9243 const whitespace = scanner.getTokenText(); 9244 // if the whitespace crosses the margin, take only the whitespace that passes the margin 9245 if (margin !== undefined && indent + whitespace.length > margin) { 9246 comments.push(whitespace.slice(margin - indent)); 9247 } 9248 indent += whitespace.length; 9249 } 9250 break; 9251 case SyntaxKind.OpenBraceToken: 9252 state = JSDocState.SavingComments; 9253 const commentEnd = scanner.getStartPos(); 9254 const linkStart = scanner.getTextPos() - 1; 9255 const link = parseJSDocLink(linkStart); 9256 if (link) { 9257 parts.push(finishNode(factory.createJSDocText(comments.join("")), linkEnd ?? commentsPos, commentEnd)); 9258 parts.push(link); 9259 comments = []; 9260 linkEnd = scanner.getTextPos(); 9261 } 9262 else { 9263 pushComment(scanner.getTokenText()); 9264 } 9265 break; 9266 case SyntaxKind.BacktickToken: 9267 if (state === JSDocState.SavingBackticks) { 9268 state = JSDocState.SavingComments; 9269 } 9270 else { 9271 state = JSDocState.SavingBackticks; 9272 } 9273 pushComment(scanner.getTokenText()); 9274 break; 9275 case SyntaxKind.AsteriskToken: 9276 if (state === JSDocState.BeginningOfLine) { 9277 // leading asterisks start recording on the *next* (non-whitespace) token 9278 state = JSDocState.SawAsterisk; 9279 indent += 1; 9280 break; 9281 } 9282 // record the * as a comment 9283 // falls through 9284 default: 9285 if (state !== JSDocState.SavingBackticks) { 9286 state = JSDocState.SavingComments; // leading identifiers start recording as well 9287 } 9288 pushComment(scanner.getTokenText()); 9289 break; 9290 } 9291 previousWhitespace = token() === SyntaxKind.WhitespaceTrivia; 9292 tok = nextTokenJSDoc(); 9293 } 9294 9295 removeLeadingNewlines(comments); 9296 removeTrailingWhitespace(comments); 9297 if (parts.length) { 9298 if (comments.length) { 9299 parts.push(finishNode(factory.createJSDocText(comments.join("")), linkEnd ?? commentsPos)); 9300 } 9301 return createNodeArray(parts, commentsPos, scanner.getTextPos()); 9302 } 9303 else if (comments.length) { 9304 return comments.join(""); 9305 } 9306 } 9307 9308 function isNextJSDocTokenWhitespace() { 9309 const next = nextTokenJSDoc(); 9310 return next === SyntaxKind.WhitespaceTrivia || next === SyntaxKind.NewLineTrivia; 9311 } 9312 9313 function parseJSDocLink(start: number) { 9314 const linkType = tryParse(parseJSDocLinkPrefix); 9315 if (!linkType) { 9316 return undefined; 9317 } 9318 nextTokenJSDoc(); // start at token after link, then skip any whitespace 9319 skipWhitespace(); 9320 // parseEntityName logs an error for non-identifier, so create a MissingNode ourselves to avoid the error 9321 const p2 = getNodePos(); 9322 let name: EntityName | JSDocMemberName | undefined = tokenIsIdentifierOrKeyword(token()) 9323 ? parseEntityName(/*allowReservedWords*/ true) 9324 : undefined; 9325 if (name) { 9326 while (token() === SyntaxKind.PrivateIdentifier) { 9327 reScanHashToken(); // rescan #id as # id 9328 nextTokenJSDoc(); // then skip the # 9329 name = finishNode(factory.createJSDocMemberName(name, parseIdentifier()), p2); 9330 } 9331 } 9332 const text = []; 9333 while (token() !== SyntaxKind.CloseBraceToken && token() !== SyntaxKind.NewLineTrivia && token() !== SyntaxKind.EndOfFileToken) { 9334 text.push(scanner.getTokenText()); 9335 nextTokenJSDoc(); 9336 } 9337 const create = linkType === "link" ? factory.createJSDocLink 9338 : linkType === "linkcode" ? factory.createJSDocLinkCode 9339 : factory.createJSDocLinkPlain; 9340 return finishNode(create(name, text.join("")), start, scanner.getTextPos()); 9341 } 9342 9343 function parseJSDocLinkPrefix() { 9344 skipWhitespaceOrAsterisk(); 9345 if (token() === SyntaxKind.OpenBraceToken 9346 && nextTokenJSDoc() === SyntaxKind.AtToken 9347 && tokenIsIdentifierOrKeyword(nextTokenJSDoc())) { 9348 const kind = scanner.getTokenValue(); 9349 if (isJSDocLinkTag(kind)) return kind; 9350 } 9351 } 9352 9353 function isJSDocLinkTag(kind: string) { 9354 return kind === "link" || kind === "linkcode" || kind === "linkplain"; 9355 } 9356 9357 function parseUnknownTag(start: number, tagName: Identifier, indent: number, indentText: string) { 9358 return finishNode(factory.createJSDocUnknownTag(tagName, parseTrailingTagComments(start, getNodePos(), indent, indentText)), start); 9359 } 9360 9361 function addTag(tag: JSDocTag | undefined): void { 9362 if (!tag) { 9363 return; 9364 } 9365 if (!tags) { 9366 tags = [tag]; 9367 tagsPos = tag.pos; 9368 } 9369 else { 9370 tags.push(tag); 9371 } 9372 tagsEnd = tag.end; 9373 } 9374 9375 function tryParseTypeExpression(): JSDocTypeExpression | undefined { 9376 skipWhitespaceOrAsterisk(); 9377 return token() === SyntaxKind.OpenBraceToken ? parseJSDocTypeExpression() : undefined; 9378 } 9379 9380 function parseBracketNameInPropertyAndParamTag(): { name: EntityName, isBracketed: boolean } { 9381 // Looking for something like '[foo]', 'foo', '[foo.bar]' or 'foo.bar' 9382 const isBracketed = parseOptionalJsdoc(SyntaxKind.OpenBracketToken); 9383 if (isBracketed) { 9384 skipWhitespace(); 9385 } 9386 // a markdown-quoted name: `arg` is not legal jsdoc, but occurs in the wild 9387 const isBackquoted = parseOptionalJsdoc(SyntaxKind.BacktickToken); 9388 const name = parseJSDocEntityName(); 9389 if (isBackquoted) { 9390 parseExpectedTokenJSDoc(SyntaxKind.BacktickToken); 9391 } 9392 if (isBracketed) { 9393 skipWhitespace(); 9394 // May have an optional default, e.g. '[foo = 42]' 9395 if (parseOptionalToken(SyntaxKind.EqualsToken)) { 9396 parseExpression(); 9397 } 9398 9399 parseExpected(SyntaxKind.CloseBracketToken); 9400 } 9401 9402 return { name, isBracketed }; 9403 } 9404 9405 function isObjectOrObjectArrayTypeReference(node: TypeNode): boolean { 9406 switch (node.kind) { 9407 case SyntaxKind.ObjectKeyword: 9408 return true; 9409 case SyntaxKind.ArrayType: 9410 return isObjectOrObjectArrayTypeReference((node as ArrayTypeNode).elementType); 9411 default: 9412 return isTypeReferenceNode(node) && ts.isIdentifier(node.typeName) && node.typeName.escapedText === "Object" && !node.typeArguments; 9413 } 9414 } 9415 9416 function parseParameterOrPropertyTag(start: number, tagName: Identifier, target: PropertyLikeParse, indent: number): JSDocParameterTag | JSDocPropertyTag { 9417 let typeExpression = tryParseTypeExpression(); 9418 let isNameFirst = !typeExpression; 9419 skipWhitespaceOrAsterisk(); 9420 9421 const { name, isBracketed } = parseBracketNameInPropertyAndParamTag(); 9422 const indentText = skipWhitespaceOrAsterisk(); 9423 9424 if (isNameFirst && !lookAhead(parseJSDocLinkPrefix)) { 9425 typeExpression = tryParseTypeExpression(); 9426 } 9427 9428 const comment = parseTrailingTagComments(start, getNodePos(), indent, indentText); 9429 9430 const nestedTypeLiteral = target !== PropertyLikeParse.CallbackParameter && parseNestedTypeLiteral(typeExpression, name, target, indent); 9431 if (nestedTypeLiteral) { 9432 typeExpression = nestedTypeLiteral; 9433 isNameFirst = true; 9434 } 9435 const result = target === PropertyLikeParse.Property 9436 ? factory.createJSDocPropertyTag(tagName, name, isBracketed, typeExpression, isNameFirst, comment) 9437 : factory.createJSDocParameterTag(tagName, name, isBracketed, typeExpression, isNameFirst, comment); 9438 return finishNode(result, start); 9439 } 9440 9441 function parseNestedTypeLiteral(typeExpression: JSDocTypeExpression | undefined, name: EntityName, target: PropertyLikeParse, indent: number) { 9442 if (typeExpression && isObjectOrObjectArrayTypeReference(typeExpression.type)) { 9443 const pos = getNodePos(); 9444 let child: JSDocPropertyLikeTag | JSDocTypeTag | false; 9445 let children: JSDocPropertyLikeTag[] | undefined; 9446 while (child = tryParse(() => parseChildParameterOrPropertyTag(target, indent, name))) { 9447 if (child.kind === SyntaxKind.JSDocParameterTag || child.kind === SyntaxKind.JSDocPropertyTag) { 9448 children = append(children, child); 9449 } 9450 } 9451 if (children) { 9452 const literal = finishNode(factory.createJSDocTypeLiteral(children, typeExpression.type.kind === SyntaxKind.ArrayType), pos); 9453 return finishNode(factory.createJSDocTypeExpression(literal), pos); 9454 } 9455 } 9456 } 9457 9458 function parseReturnTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocReturnTag { 9459 if (some(tags, isJSDocReturnTag)) { 9460 parseErrorAt(tagName.pos, scanner.getTokenPos(), Diagnostics._0_tag_already_specified, tagName.escapedText); 9461 } 9462 9463 const typeExpression = tryParseTypeExpression(); 9464 return finishNode(factory.createJSDocReturnTag(tagName, typeExpression, parseTrailingTagComments(start, getNodePos(), indent, indentText)), start); 9465 } 9466 9467 function parseTypeTag(start: number, tagName: Identifier, indent?: number, indentText?: string): JSDocTypeTag { 9468 if (some(tags, isJSDocTypeTag)) { 9469 parseErrorAt(tagName.pos, scanner.getTokenPos(), Diagnostics._0_tag_already_specified, tagName.escapedText); 9470 } 9471 9472 const typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true); 9473 const comments = indent !== undefined && indentText !== undefined ? parseTrailingTagComments(start, getNodePos(), indent, indentText) : undefined; 9474 return finishNode(factory.createJSDocTypeTag(tagName, typeExpression, comments), start); 9475 } 9476 9477 function parseSeeTag(start: number, tagName: Identifier, indent?: number, indentText?: string): JSDocSeeTag { 9478 const isMarkdownOrJSDocLink = token() === SyntaxKind.OpenBracketToken 9479 || lookAhead(() => nextTokenJSDoc() === SyntaxKind.AtToken && tokenIsIdentifierOrKeyword(nextTokenJSDoc()) && isJSDocLinkTag(scanner.getTokenValue())); 9480 const nameExpression = isMarkdownOrJSDocLink ? undefined : parseJSDocNameReference(); 9481 const comments = indent !== undefined && indentText !== undefined ? parseTrailingTagComments(start, getNodePos(), indent, indentText) : undefined; 9482 return finishNode(factory.createJSDocSeeTag(tagName, nameExpression, comments), start); 9483 } 9484 9485 function parseAuthorTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocAuthorTag { 9486 const commentStart = getNodePos(); 9487 const textOnly = parseAuthorNameAndEmail(); 9488 let commentEnd = scanner.getStartPos(); 9489 const comments = parseTrailingTagComments(start, commentEnd, indent, indentText); 9490 if (!comments) { 9491 commentEnd = scanner.getStartPos(); 9492 } 9493 const allParts = typeof comments !== "string" 9494 ? createNodeArray(concatenate([finishNode(textOnly, commentStart, commentEnd)], comments) as JSDocComment[], commentStart) // cast away readonly 9495 : textOnly.text + comments; 9496 return finishNode(factory.createJSDocAuthorTag(tagName, allParts), start); 9497 } 9498 9499 function parseAuthorNameAndEmail(): JSDocText { 9500 const comments: string[] = []; 9501 let inEmail = false; 9502 let token = scanner.getToken(); 9503 while (token !== SyntaxKind.EndOfFileToken && token !== SyntaxKind.NewLineTrivia) { 9504 if (token === SyntaxKind.LessThanToken) { 9505 inEmail = true; 9506 } 9507 else if (token === SyntaxKind.AtToken && !inEmail) { 9508 break; 9509 } 9510 else if (token === SyntaxKind.GreaterThanToken && inEmail) { 9511 comments.push(scanner.getTokenText()); 9512 scanner.setTextPos(scanner.getTokenPos() + 1); 9513 break; 9514 } 9515 comments.push(scanner.getTokenText()); 9516 token = nextTokenJSDoc(); 9517 } 9518 9519 return factory.createJSDocText(comments.join("")); 9520 } 9521 9522 function parseImplementsTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocImplementsTag { 9523 const className = parseExpressionWithTypeArgumentsForAugments(); 9524 return finishNode(factory.createJSDocImplementsTag(tagName, className, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start); 9525 } 9526 9527 function parseAugmentsTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocAugmentsTag { 9528 const className = parseExpressionWithTypeArgumentsForAugments(); 9529 return finishNode(factory.createJSDocAugmentsTag(tagName, className, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start); 9530 } 9531 9532 function parseExpressionWithTypeArgumentsForAugments(): ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression } { 9533 const usedBrace = parseOptional(SyntaxKind.OpenBraceToken); 9534 const pos = getNodePos(); 9535 const expression = parsePropertyAccessEntityNameExpression(); 9536 const typeArguments = tryParseTypeArguments(); 9537 const node = factory.createExpressionWithTypeArguments(expression, typeArguments) as ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression }; 9538 const res = finishNode(node, pos); 9539 if (usedBrace) { 9540 parseExpected(SyntaxKind.CloseBraceToken); 9541 } 9542 return res; 9543 } 9544 9545 function parsePropertyAccessEntityNameExpression() { 9546 const pos = getNodePos(); 9547 let node: Identifier | PropertyAccessEntityNameExpression = parseJSDocIdentifierName(); 9548 while (parseOptional(SyntaxKind.DotToken)) { 9549 const name = parseJSDocIdentifierName(); 9550 node = finishNode(factory.createPropertyAccessExpression(node, name), pos) as PropertyAccessEntityNameExpression; 9551 } 9552 return node; 9553 } 9554 9555 function parseSimpleTag(start: number, createTag: (tagName: Identifier | undefined, comment?: string | NodeArray<JSDocComment>) => JSDocTag, tagName: Identifier, margin: number, indentText: string): JSDocTag { 9556 return finishNode(createTag(tagName, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start); 9557 } 9558 9559 function parseThisTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocThisTag { 9560 const typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true); 9561 skipWhitespace(); 9562 return finishNode(factory.createJSDocThisTag(tagName, typeExpression, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start); 9563 } 9564 9565 function parseEnumTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocEnumTag { 9566 const typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true); 9567 skipWhitespace(); 9568 return finishNode(factory.createJSDocEnumTag(tagName, typeExpression, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start); 9569 } 9570 9571 function parseTypedefTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocTypedefTag { 9572 let typeExpression: JSDocTypeExpression | JSDocTypeLiteral | undefined = tryParseTypeExpression(); 9573 skipWhitespaceOrAsterisk(); 9574 9575 const fullName = parseJSDocTypeNameWithNamespace(); 9576 skipWhitespace(); 9577 let comment = parseTagComments(indent); 9578 9579 let end: number | undefined; 9580 if (!typeExpression || isObjectOrObjectArrayTypeReference(typeExpression.type)) { 9581 let child: JSDocTypeTag | JSDocPropertyTag | false; 9582 let childTypeTag: JSDocTypeTag | undefined; 9583 let jsDocPropertyTags: JSDocPropertyTag[] | undefined; 9584 let hasChildren = false; 9585 while (child = tryParse(() => parseChildPropertyTag(indent))) { 9586 hasChildren = true; 9587 if (child.kind === SyntaxKind.JSDocTypeTag) { 9588 if (childTypeTag) { 9589 const lastError = parseErrorAtCurrentToken(Diagnostics.A_JSDoc_typedef_comment_may_not_contain_multiple_type_tags); 9590 if (lastError) { 9591 addRelatedInfo(lastError, createDetachedDiagnostic(fileName, 0, 0, Diagnostics.The_tag_was_first_specified_here)); 9592 } 9593 break; 9594 } 9595 else { 9596 childTypeTag = child; 9597 } 9598 } 9599 else { 9600 jsDocPropertyTags = append(jsDocPropertyTags, child); 9601 } 9602 } 9603 if (hasChildren) { 9604 const isArrayType = typeExpression && typeExpression.type.kind === SyntaxKind.ArrayType; 9605 const jsdocTypeLiteral = factory.createJSDocTypeLiteral(jsDocPropertyTags, isArrayType); 9606 typeExpression = childTypeTag && childTypeTag.typeExpression && !isObjectOrObjectArrayTypeReference(childTypeTag.typeExpression.type) ? 9607 childTypeTag.typeExpression : 9608 finishNode(jsdocTypeLiteral, start); 9609 end = typeExpression.end; 9610 } 9611 } 9612 9613 // Only include the characters between the name end and the next token if a comment was actually parsed out - otherwise it's just whitespace 9614 end = end || comment !== undefined ? 9615 getNodePos() : 9616 (fullName ?? typeExpression ?? tagName).end; 9617 9618 if (!comment) { 9619 comment = parseTrailingTagComments(start, end, indent, indentText); 9620 } 9621 9622 const typedefTag = factory.createJSDocTypedefTag(tagName, typeExpression, fullName, comment); 9623 return finishNode(typedefTag, start, end); 9624 } 9625 9626 function parseJSDocTypeNameWithNamespace(nested?: boolean) { 9627 const pos = scanner.getTokenPos(); 9628 if (!tokenIsIdentifierOrKeyword(token())) { 9629 return undefined; 9630 } 9631 const typeNameOrNamespaceName = parseJSDocIdentifierName(); 9632 if (parseOptional(SyntaxKind.DotToken)) { 9633 const body = parseJSDocTypeNameWithNamespace(/*nested*/ true); 9634 const jsDocNamespaceNode = factory.createModuleDeclaration( 9635 /*modifiers*/ undefined, 9636 typeNameOrNamespaceName, 9637 body, 9638 nested ? NodeFlags.NestedNamespace : undefined 9639 ) as JSDocNamespaceDeclaration; 9640 return finishNode(jsDocNamespaceNode, pos); 9641 } 9642 9643 if (nested) { 9644 typeNameOrNamespaceName.isInJSDocNamespace = true; 9645 } 9646 return typeNameOrNamespaceName; 9647 } 9648 9649 9650 function parseCallbackTagParameters(indent: number) { 9651 const pos = getNodePos(); 9652 let child: JSDocParameterTag | false; 9653 let parameters; 9654 while (child = tryParse(() => parseChildParameterOrPropertyTag(PropertyLikeParse.CallbackParameter, indent) as JSDocParameterTag)) { 9655 parameters = append(parameters, child); 9656 } 9657 return createNodeArray(parameters || [], pos); 9658 } 9659 9660 function parseCallbackTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocCallbackTag { 9661 const fullName = parseJSDocTypeNameWithNamespace(); 9662 skipWhitespace(); 9663 let comment = parseTagComments(indent); 9664 const parameters = parseCallbackTagParameters(indent); 9665 const returnTag = tryParse(() => { 9666 if (parseOptionalJsdoc(SyntaxKind.AtToken)) { 9667 const tag = parseTag(indent); 9668 if (tag && tag.kind === SyntaxKind.JSDocReturnTag) { 9669 return tag as JSDocReturnTag; 9670 } 9671 } 9672 }); 9673 const typeExpression = finishNode(factory.createJSDocSignature(/*typeParameters*/ undefined, parameters, returnTag), start); 9674 if (!comment) { 9675 comment = parseTrailingTagComments(start, getNodePos(), indent, indentText); 9676 } 9677 const end = comment !== undefined ? getNodePos() : typeExpression.end; 9678 return finishNode(factory.createJSDocCallbackTag(tagName, typeExpression, fullName, comment), start, end); 9679 } 9680 9681 function escapedTextsEqual(a: EntityName, b: EntityName): boolean { 9682 while (!ts.isIdentifier(a) || !ts.isIdentifier(b)) { 9683 if (!ts.isIdentifier(a) && !ts.isIdentifier(b) && a.right.escapedText === b.right.escapedText) { 9684 a = a.left; 9685 b = b.left; 9686 } 9687 else { 9688 return false; 9689 } 9690 } 9691 return a.escapedText === b.escapedText; 9692 } 9693 9694 function parseChildPropertyTag(indent: number) { 9695 return parseChildParameterOrPropertyTag(PropertyLikeParse.Property, indent) as JSDocTypeTag | JSDocPropertyTag | false; 9696 } 9697 9698 function parseChildParameterOrPropertyTag(target: PropertyLikeParse, indent: number, name?: EntityName): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false { 9699 let canParseTag = true; 9700 let seenAsterisk = false; 9701 while (true) { 9702 switch (nextTokenJSDoc()) { 9703 case SyntaxKind.AtToken: 9704 if (canParseTag) { 9705 const child = tryParseChildTag(target, indent); 9706 if (child && (child.kind === SyntaxKind.JSDocParameterTag || child.kind === SyntaxKind.JSDocPropertyTag) && 9707 target !== PropertyLikeParse.CallbackParameter && 9708 name && (ts.isIdentifier(child.name) || !escapedTextsEqual(name, child.name.left))) { 9709 return false; 9710 } 9711 return child; 9712 } 9713 seenAsterisk = false; 9714 break; 9715 case SyntaxKind.NewLineTrivia: 9716 canParseTag = true; 9717 seenAsterisk = false; 9718 break; 9719 case SyntaxKind.AsteriskToken: 9720 if (seenAsterisk) { 9721 canParseTag = false; 9722 } 9723 seenAsterisk = true; 9724 break; 9725 case SyntaxKind.Identifier: 9726 canParseTag = false; 9727 break; 9728 case SyntaxKind.EndOfFileToken: 9729 return false; 9730 } 9731 } 9732 } 9733 9734 function tryParseChildTag(target: PropertyLikeParse, indent: number): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false { 9735 Debug.assert(token() === SyntaxKind.AtToken); 9736 const start = scanner.getStartPos(); 9737 nextTokenJSDoc(); 9738 9739 const tagName = parseJSDocIdentifierName(); 9740 skipWhitespace(); 9741 let t: PropertyLikeParse; 9742 switch (tagName.escapedText) { 9743 case "type": 9744 return target === PropertyLikeParse.Property && parseTypeTag(start, tagName); 9745 case "prop": 9746 case "property": 9747 t = PropertyLikeParse.Property; 9748 break; 9749 case "arg": 9750 case "argument": 9751 case "param": 9752 t = PropertyLikeParse.Parameter | PropertyLikeParse.CallbackParameter; 9753 break; 9754 default: 9755 return false; 9756 } 9757 if (!(target & t)) { 9758 return false; 9759 } 9760 return parseParameterOrPropertyTag(start, tagName, target, indent); 9761 } 9762 9763 function parseTemplateTagTypeParameter() { 9764 const typeParameterPos = getNodePos(); 9765 const isBracketed = parseOptionalJsdoc(SyntaxKind.OpenBracketToken); 9766 if (isBracketed) { 9767 skipWhitespace(); 9768 } 9769 const name = parseJSDocIdentifierName(Diagnostics.Unexpected_token_A_type_parameter_name_was_expected_without_curly_braces); 9770 9771 let defaultType: TypeNode | undefined; 9772 if (isBracketed) { 9773 skipWhitespace(); 9774 parseExpected(SyntaxKind.EqualsToken); 9775 defaultType = doInsideOfContext(NodeFlags.JSDoc, parseJSDocType); 9776 parseExpected(SyntaxKind.CloseBracketToken); 9777 } 9778 9779 if (nodeIsMissing(name)) { 9780 return undefined; 9781 } 9782 return finishNode(factory.createTypeParameterDeclaration(/*modifiers*/ undefined, name, /*constraint*/ undefined, defaultType), typeParameterPos); 9783 } 9784 9785 function parseTemplateTagTypeParameters() { 9786 const pos = getNodePos(); 9787 const typeParameters = []; 9788 do { 9789 skipWhitespace(); 9790 const node = parseTemplateTagTypeParameter(); 9791 if (node !== undefined) { 9792 typeParameters.push(node); 9793 } 9794 skipWhitespaceOrAsterisk(); 9795 } while (parseOptionalJsdoc(SyntaxKind.CommaToken)); 9796 return createNodeArray(typeParameters, pos); 9797 } 9798 9799 function parseTemplateTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocTemplateTag { 9800 // The template tag looks like one of the following: 9801 // @template T,U,V 9802 // @template {Constraint} T 9803 // 9804 // According to the [closure docs](https://github.com/google/closure-compiler/wiki/Generic-Types#multiple-bounded-template-types): 9805 // > Multiple bounded generics cannot be declared on the same line. For the sake of clarity, if multiple templates share the same 9806 // > type bound they must be declared on separate lines. 9807 // 9808 // TODO: Determine whether we should enforce this in the checker. 9809 // TODO: Consider moving the `constraint` to the first type parameter as we could then remove `getEffectiveConstraintOfTypeParameter`. 9810 // TODO: Consider only parsing a single type parameter if there is a constraint. 9811 const constraint = token() === SyntaxKind.OpenBraceToken ? parseJSDocTypeExpression() : undefined; 9812 const typeParameters = parseTemplateTagTypeParameters(); 9813 return finishNode(factory.createJSDocTemplateTag(tagName, constraint, typeParameters, parseTrailingTagComments(start, getNodePos(), indent, indentText)), start); 9814 } 9815 9816 function parseOptionalJsdoc(t: JSDocSyntaxKind): boolean { 9817 if (token() === t) { 9818 nextTokenJSDoc(); 9819 return true; 9820 } 9821 return false; 9822 } 9823 9824 function parseJSDocEntityName(): EntityName { 9825 let entity: EntityName = parseJSDocIdentifierName(); 9826 if (parseOptional(SyntaxKind.OpenBracketToken)) { 9827 parseExpected(SyntaxKind.CloseBracketToken); 9828 // Note that y[] is accepted as an entity name, but the postfix brackets are not saved for checking. 9829 // Technically usejsdoc.org requires them for specifying a property of a type equivalent to Array<{ x: ...}> 9830 // but it's not worth it to enforce that restriction. 9831 } 9832 while (parseOptional(SyntaxKind.DotToken)) { 9833 const name = parseJSDocIdentifierName(); 9834 if (parseOptional(SyntaxKind.OpenBracketToken)) { 9835 parseExpected(SyntaxKind.CloseBracketToken); 9836 } 9837 entity = createQualifiedName(entity, name); 9838 } 9839 return entity; 9840 } 9841 9842 function parseJSDocIdentifierName(message?: DiagnosticMessage): Identifier { 9843 if (!tokenIsIdentifierOrKeyword(token())) { 9844 return createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ !message, message || Diagnostics.Identifier_expected); 9845 } 9846 9847 identifierCount++; 9848 const pos = scanner.getTokenPos(); 9849 const end = scanner.getTextPos(); 9850 const originalKeywordKind = token(); 9851 const text = internIdentifier(scanner.getTokenValue()); 9852 const result = finishNode(factory.createIdentifier(text, /*typeArguments*/ undefined, originalKeywordKind), pos, end); 9853 nextTokenJSDoc(); 9854 return result; 9855 } 9856 } 9857 } 9858 } 9859 9860 namespace IncrementalParser { 9861 export function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks: boolean): SourceFile { 9862 aggressiveChecks = aggressiveChecks || Debug.shouldAssert(AssertionLevel.Aggressive); 9863 9864 checkChangeRange(sourceFile, newText, textChangeRange, aggressiveChecks); 9865 if (textChangeRangeIsUnchanged(textChangeRange)) { 9866 // if the text didn't change, then we can just return our current source file as-is. 9867 return sourceFile; 9868 } 9869 9870 if (sourceFile.statements.length === 0) { 9871 // If we don't have any statements in the current source file, then there's no real 9872 // way to incrementally parse. So just do a full parse instead. 9873 return Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, /*syntaxCursor*/ undefined, /*setParentNodes*/ true, sourceFile.scriptKind, sourceFile.setExternalModuleIndicator); 9874 } 9875 9876 // Make sure we're not trying to incrementally update a source file more than once. Once 9877 // we do an update the original source file is considered unusable from that point onwards. 9878 // 9879 // This is because we do incremental parsing in-place. i.e. we take nodes from the old 9880 // tree and give them new positions and parents. From that point on, trusting the old 9881 // tree at all is not possible as far too much of it may violate invariants. 9882 const incrementalSourceFile = sourceFile as Node as IncrementalNode; 9883 Debug.assert(!incrementalSourceFile.hasBeenIncrementallyParsed); 9884 incrementalSourceFile.hasBeenIncrementallyParsed = true; 9885 Parser.fixupParentReferences(incrementalSourceFile); 9886 const oldText = sourceFile.text; 9887 const syntaxCursor = createSyntaxCursor(sourceFile); 9888 9889 // Make the actual change larger so that we know to reparse anything whose lookahead 9890 // might have intersected the change. 9891 const changeRange = extendToAffectedRange(sourceFile, textChangeRange); 9892 checkChangeRange(sourceFile, newText, changeRange, aggressiveChecks); 9893 9894 // Ensure that extending the affected range only moved the start of the change range 9895 // earlier in the file. 9896 Debug.assert(changeRange.span.start <= textChangeRange.span.start); 9897 Debug.assert(textSpanEnd(changeRange.span) === textSpanEnd(textChangeRange.span)); 9898 Debug.assert(textSpanEnd(textChangeRangeNewSpan(changeRange)) === textSpanEnd(textChangeRangeNewSpan(textChangeRange))); 9899 9900 // The is the amount the nodes after the edit range need to be adjusted. It can be 9901 // positive (if the edit added characters), negative (if the edit deleted characters) 9902 // or zero (if this was a pure overwrite with nothing added/removed). 9903 const delta = textChangeRangeNewSpan(changeRange).length - changeRange.span.length; 9904 9905 // If we added or removed characters during the edit, then we need to go and adjust all 9906 // the nodes after the edit. Those nodes may move forward (if we inserted chars) or they 9907 // may move backward (if we deleted chars). 9908 // 9909 // Doing this helps us out in two ways. First, it means that any nodes/tokens we want 9910 // to reuse are already at the appropriate position in the new text. That way when we 9911 // reuse them, we don't have to figure out if they need to be adjusted. Second, it makes 9912 // it very easy to determine if we can reuse a node. If the node's position is at where 9913 // we are in the text, then we can reuse it. Otherwise we can't. If the node's position 9914 // is ahead of us, then we'll need to rescan tokens. If the node's position is behind 9915 // us, then we'll need to skip it or crumble it as appropriate 9916 // 9917 // We will also adjust the positions of nodes that intersect the change range as well. 9918 // By doing this, we ensure that all the positions in the old tree are consistent, not 9919 // just the positions of nodes entirely before/after the change range. By being 9920 // consistent, we can then easily map from positions to nodes in the old tree easily. 9921 // 9922 // Also, mark any syntax elements that intersect the changed span. We know, up front, 9923 // that we cannot reuse these elements. 9924 updateTokenPositionsAndMarkElements(incrementalSourceFile, 9925 changeRange.span.start, textSpanEnd(changeRange.span), textSpanEnd(textChangeRangeNewSpan(changeRange)), delta, oldText, newText, aggressiveChecks); 9926 9927 // Now that we've set up our internal incremental state just proceed and parse the 9928 // source file in the normal fashion. When possible the parser will retrieve and 9929 // reuse nodes from the old tree. 9930 // 9931 // Note: passing in 'true' for setNodeParents is very important. When incrementally 9932 // parsing, we will be reusing nodes from the old tree, and placing it into new 9933 // parents. If we don't set the parents now, we'll end up with an observably 9934 // inconsistent tree. Setting the parents on the new tree should be very fast. We 9935 // will immediately bail out of walking any subtrees when we can see that their parents 9936 // are already correct. 9937 const result = Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, syntaxCursor, /*setParentNodes*/ true, sourceFile.scriptKind, sourceFile.setExternalModuleIndicator); 9938 result.commentDirectives = getNewCommentDirectives( 9939 sourceFile.commentDirectives, 9940 result.commentDirectives, 9941 changeRange.span.start, 9942 textSpanEnd(changeRange.span), 9943 delta, 9944 oldText, 9945 newText, 9946 aggressiveChecks 9947 ); 9948 result.impliedNodeFormat = sourceFile.impliedNodeFormat; 9949 return result; 9950 } 9951 9952 function getNewCommentDirectives( 9953 oldDirectives: CommentDirective[] | undefined, 9954 newDirectives: CommentDirective[] | undefined, 9955 changeStart: number, 9956 changeRangeOldEnd: number, 9957 delta: number, 9958 oldText: string, 9959 newText: string, 9960 aggressiveChecks: boolean 9961 ): CommentDirective[] | undefined { 9962 if (!oldDirectives) return newDirectives; 9963 let commentDirectives: CommentDirective[] | undefined; 9964 let addedNewlyScannedDirectives = false; 9965 for (const directive of oldDirectives) { 9966 const { range, type } = directive; 9967 // Range before the change 9968 if (range.end < changeStart) { 9969 commentDirectives = append(commentDirectives, directive); 9970 } 9971 else if (range.pos > changeRangeOldEnd) { 9972 addNewlyScannedDirectives(); 9973 // Node is entirely past the change range. We need to move both its pos and 9974 // end, forward or backward appropriately. 9975 const updatedDirective: CommentDirective = { 9976 range: { pos: range.pos + delta, end: range.end + delta }, 9977 type 9978 }; 9979 commentDirectives = append(commentDirectives, updatedDirective); 9980 if (aggressiveChecks) { 9981 Debug.assert(oldText.substring(range.pos, range.end) === newText.substring(updatedDirective.range.pos, updatedDirective.range.end)); 9982 } 9983 } 9984 // Ignore ranges that fall in change range 9985 } 9986 addNewlyScannedDirectives(); 9987 return commentDirectives; 9988 9989 function addNewlyScannedDirectives() { 9990 if (addedNewlyScannedDirectives) return; 9991 addedNewlyScannedDirectives = true; 9992 if (!commentDirectives) { 9993 commentDirectives = newDirectives; 9994 } 9995 else if (newDirectives) { 9996 commentDirectives.push(...newDirectives); 9997 } 9998 } 9999 } 10000 10001 function moveElementEntirelyPastChangeRange(element: IncrementalElement, isArray: boolean, delta: number, oldText: string, newText: string, aggressiveChecks: boolean) { 10002 if (isArray) { 10003 visitArray(element as IncrementalNodeArray); 10004 } 10005 else { 10006 visitNode(element as IncrementalNode); 10007 } 10008 return; 10009 10010 function visitNode(node: IncrementalNode) { 10011 let text = ""; 10012 if (aggressiveChecks && shouldCheckNode(node)) { 10013 text = oldText.substring(node.pos, node.end); 10014 } 10015 10016 // Ditch any existing LS children we may have created. This way we can avoid 10017 // moving them forward. 10018 if (node._children) { 10019 node._children = undefined; 10020 } 10021 10022 setTextRangePosEnd(node, node.pos + delta, node.end + delta); 10023 10024 if (aggressiveChecks && shouldCheckNode(node)) { 10025 Debug.assert(text === newText.substring(node.pos, node.end)); 10026 } 10027 10028 forEachChild(node, visitNode, visitArray); 10029 if (hasJSDocNodes(node)) { 10030 for (const jsDocComment of node.jsDoc!) { 10031 visitNode(jsDocComment as Node as IncrementalNode); 10032 } 10033 } 10034 checkNodePositions(node, aggressiveChecks); 10035 } 10036 10037 function visitArray(array: IncrementalNodeArray) { 10038 array._children = undefined; 10039 setTextRangePosEnd(array, array.pos + delta, array.end + delta); 10040 10041 for (const node of array) { 10042 visitNode(node); 10043 } 10044 } 10045 } 10046 10047 function shouldCheckNode(node: Node) { 10048 switch (node.kind) { 10049 case SyntaxKind.StringLiteral: 10050 case SyntaxKind.NumericLiteral: 10051 case SyntaxKind.Identifier: 10052 return true; 10053 } 10054 10055 return false; 10056 } 10057 10058 function adjustIntersectingElement(element: IncrementalElement, changeStart: number, changeRangeOldEnd: number, changeRangeNewEnd: number, delta: number) { 10059 Debug.assert(element.end >= changeStart, "Adjusting an element that was entirely before the change range"); 10060 Debug.assert(element.pos <= changeRangeOldEnd, "Adjusting an element that was entirely after the change range"); 10061 Debug.assert(element.pos <= element.end); 10062 10063 // We have an element that intersects the change range in some way. It may have its 10064 // start, or its end (or both) in the changed range. We want to adjust any part 10065 // that intersects such that the final tree is in a consistent state. i.e. all 10066 // children have spans within the span of their parent, and all siblings are ordered 10067 // properly. 10068 10069 // We may need to update both the 'pos' and the 'end' of the element. 10070 10071 // If the 'pos' is before the start of the change, then we don't need to touch it. 10072 // If it isn't, then the 'pos' must be inside the change. How we update it will 10073 // depend if delta is positive or negative. If delta is positive then we have 10074 // something like: 10075 // 10076 // -------------------AAA----------------- 10077 // -------------------BBBCCCCCCC----------------- 10078 // 10079 // In this case, we consider any node that started in the change range to still be 10080 // starting at the same position. 10081 // 10082 // however, if the delta is negative, then we instead have something like this: 10083 // 10084 // -------------------XXXYYYYYYY----------------- 10085 // -------------------ZZZ----------------- 10086 // 10087 // In this case, any element that started in the 'X' range will keep its position. 10088 // However any element that started after that will have their pos adjusted to be 10089 // at the end of the new range. i.e. any node that started in the 'Y' range will 10090 // be adjusted to have their start at the end of the 'Z' range. 10091 // 10092 // The element will keep its position if possible. Or Move backward to the new-end 10093 // if it's in the 'Y' range. 10094 const pos = Math.min(element.pos, changeRangeNewEnd); 10095 10096 // If the 'end' is after the change range, then we always adjust it by the delta 10097 // amount. However, if the end is in the change range, then how we adjust it 10098 // will depend on if delta is positive or negative. If delta is positive then we 10099 // have something like: 10100 // 10101 // -------------------AAA----------------- 10102 // -------------------BBBCCCCCCC----------------- 10103 // 10104 // In this case, we consider any node that ended inside the change range to keep its 10105 // end position. 10106 // 10107 // however, if the delta is negative, then we instead have something like this: 10108 // 10109 // -------------------XXXYYYYYYY----------------- 10110 // -------------------ZZZ----------------- 10111 // 10112 // In this case, any element that ended in the 'X' range will keep its position. 10113 // However any element that ended after that will have their pos adjusted to be 10114 // at the end of the new range. i.e. any node that ended in the 'Y' range will 10115 // be adjusted to have their end at the end of the 'Z' range. 10116 const end = element.end >= changeRangeOldEnd ? 10117 // Element ends after the change range. Always adjust the end pos. 10118 element.end + delta : 10119 // Element ends in the change range. The element will keep its position if 10120 // possible. Or Move backward to the new-end if it's in the 'Y' range. 10121 Math.min(element.end, changeRangeNewEnd); 10122 10123 Debug.assert(pos <= end); 10124 if (element.parent) { 10125 Debug.assertGreaterThanOrEqual(pos, element.parent.pos); 10126 Debug.assertLessThanOrEqual(end, element.parent.end); 10127 } 10128 10129 setTextRangePosEnd(element, pos, end); 10130 } 10131 10132 function checkNodePositions(node: Node, aggressiveChecks: boolean) { 10133 if (aggressiveChecks) { 10134 let pos = node.pos; 10135 const visitNode = (child: Node) => { 10136 Debug.assert(child.pos >= pos); 10137 pos = child.end; 10138 }; 10139 if (hasJSDocNodes(node)) { 10140 for (const jsDocComment of node.jsDoc!) { 10141 visitNode(jsDocComment); 10142 } 10143 } 10144 forEachChild(node, visitNode); 10145 Debug.assert(pos <= node.end); 10146 } 10147 } 10148 10149 function updateTokenPositionsAndMarkElements( 10150 sourceFile: IncrementalNode, 10151 changeStart: number, 10152 changeRangeOldEnd: number, 10153 changeRangeNewEnd: number, 10154 delta: number, 10155 oldText: string, 10156 newText: string, 10157 aggressiveChecks: boolean): void { 10158 10159 visitNode(sourceFile); 10160 return; 10161 10162 function visitNode(child: IncrementalNode) { 10163 Debug.assert(child.pos <= child.end); 10164 if (child.pos > changeRangeOldEnd) { 10165 // Node is entirely past the change range. We need to move both its pos and 10166 // end, forward or backward appropriately. 10167 moveElementEntirelyPastChangeRange(child, /*isArray*/ false, delta, oldText, newText, aggressiveChecks); 10168 return; 10169 } 10170 10171 // Check if the element intersects the change range. If it does, then it is not 10172 // reusable. Also, we'll need to recurse to see what constituent portions we may 10173 // be able to use. 10174 const fullEnd = child.end; 10175 if (fullEnd >= changeStart) { 10176 child.intersectsChange = true; 10177 child._children = undefined; 10178 10179 // Adjust the pos or end (or both) of the intersecting element accordingly. 10180 adjustIntersectingElement(child, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta); 10181 forEachChild(child, visitNode, visitArray); 10182 if (hasJSDocNodes(child)) { 10183 for (const jsDocComment of child.jsDoc!) { 10184 visitNode(jsDocComment as Node as IncrementalNode); 10185 } 10186 } 10187 checkNodePositions(child, aggressiveChecks); 10188 return; 10189 } 10190 10191 // Otherwise, the node is entirely before the change range. No need to do anything with it. 10192 Debug.assert(fullEnd < changeStart); 10193 } 10194 10195 function visitArray(array: IncrementalNodeArray) { 10196 Debug.assert(array.pos <= array.end); 10197 if (array.pos > changeRangeOldEnd) { 10198 // Array is entirely after the change range. We need to move it, and move any of 10199 // its children. 10200 moveElementEntirelyPastChangeRange(array, /*isArray*/ true, delta, oldText, newText, aggressiveChecks); 10201 return; 10202 } 10203 10204 // Check if the element intersects the change range. If it does, then it is not 10205 // reusable. Also, we'll need to recurse to see what constituent portions we may 10206 // be able to use. 10207 const fullEnd = array.end; 10208 if (fullEnd >= changeStart) { 10209 array.intersectsChange = true; 10210 array._children = undefined; 10211 10212 // Adjust the pos or end (or both) of the intersecting array accordingly. 10213 adjustIntersectingElement(array, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta); 10214 for (const node of array) { 10215 if (!node.virtual) { 10216 visitNode(node); 10217 } 10218 } 10219 return; 10220 } 10221 10222 // Otherwise, the array is entirely before the change range. No need to do anything with it. 10223 Debug.assert(fullEnd < changeStart); 10224 } 10225 } 10226 10227 function extendToAffectedRange(sourceFile: SourceFile, changeRange: TextChangeRange): TextChangeRange { 10228 // Consider the following code: 10229 // void foo() { /; } 10230 // 10231 // If the text changes with an insertion of / just before the semicolon then we end up with: 10232 // void foo() { //; } 10233 // 10234 // If we were to just use the changeRange a is, then we would not rescan the { token 10235 // (as it does not intersect the actual original change range). Because an edit may 10236 // change the token touching it, we actually need to look back *at least* one token so 10237 // that the prior token sees that change. 10238 const maxLookahead = 1; 10239 10240 let start = changeRange.span.start; 10241 10242 // the first iteration aligns us with the change start. subsequent iteration move us to 10243 // the left by maxLookahead tokens. We only need to do this as long as we're not at the 10244 // start of the tree. 10245 for (let i = 0; start > 0 && i <= maxLookahead; i++) { 10246 const nearestNode = findNearestNodeStartingBeforeOrAtPosition(sourceFile, start); 10247 Debug.assert(nearestNode.pos <= start); 10248 const position = nearestNode.pos; 10249 10250 start = Math.max(0, position - 1); 10251 } 10252 10253 const finalSpan = createTextSpanFromBounds(start, textSpanEnd(changeRange.span)); 10254 const finalLength = changeRange.newLength + (changeRange.span.start - start); 10255 10256 return createTextChangeRange(finalSpan, finalLength); 10257 } 10258 10259 function findNearestNodeStartingBeforeOrAtPosition(sourceFile: SourceFile, position: number): Node { 10260 let bestResult: Node = sourceFile; 10261 let lastNodeEntirelyBeforePosition: Node | undefined; 10262 10263 forEachChild(sourceFile, visit); 10264 10265 if (lastNodeEntirelyBeforePosition) { 10266 const lastChildOfLastEntireNodeBeforePosition = getLastDescendant(lastNodeEntirelyBeforePosition); 10267 if (lastChildOfLastEntireNodeBeforePosition.pos > bestResult.pos) { 10268 bestResult = lastChildOfLastEntireNodeBeforePosition; 10269 } 10270 } 10271 10272 return bestResult; 10273 10274 function getLastDescendant(node: Node): Node { 10275 while (true) { 10276 const lastChild = getLastChild(node); 10277 if (lastChild) { 10278 node = lastChild; 10279 } 10280 else { 10281 return node; 10282 } 10283 } 10284 } 10285 10286 function visit(child: Node) { 10287 if (nodeIsMissing(child)) { 10288 // Missing nodes are effectively invisible to us. We never even consider them 10289 // When trying to find the nearest node before us. 10290 return; 10291 } 10292 10293 // If the child intersects this position, then this node is currently the nearest 10294 // node that starts before the position. 10295 if (child.pos <= position) { 10296 if (child.pos >= bestResult.pos) { 10297 // This node starts before the position, and is closer to the position than 10298 // the previous best node we found. It is now the new best node. 10299 bestResult = child; 10300 } 10301 10302 // Now, the node may overlap the position, or it may end entirely before the 10303 // position. If it overlaps with the position, then either it, or one of its 10304 // children must be the nearest node before the position. So we can just 10305 // recurse into this child to see if we can find something better. 10306 if (position < child.end) { 10307 // The nearest node is either this child, or one of the children inside 10308 // of it. We've already marked this child as the best so far. Recurse 10309 // in case one of the children is better. 10310 forEachChild(child, visit); 10311 10312 // Once we look at the children of this node, then there's no need to 10313 // continue any further. 10314 return true; 10315 } 10316 else { 10317 Debug.assert(child.end <= position); 10318 // The child ends entirely before this position. Say you have the following 10319 // (where $ is the position) 10320 // 10321 // <complex expr 1> ? <complex expr 2> $ : <...> <...> 10322 // 10323 // We would want to find the nearest preceding node in "complex expr 2". 10324 // To support that, we keep track of this node, and once we're done searching 10325 // for a best node, we recurse down this node to see if we can find a good 10326 // result in it. 10327 // 10328 // This approach allows us to quickly skip over nodes that are entirely 10329 // before the position, while still allowing us to find any nodes in the 10330 // last one that might be what we want. 10331 lastNodeEntirelyBeforePosition = child; 10332 } 10333 } 10334 else { 10335 Debug.assert(child.pos > position); 10336 // We're now at a node that is entirely past the position we're searching for. 10337 // This node (and all following nodes) could never contribute to the result, 10338 // so just skip them by returning 'true' here. 10339 return true; 10340 } 10341 } 10342 } 10343 10344 function checkChangeRange(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks: boolean) { 10345 const oldText = sourceFile.text; 10346 if (textChangeRange) { 10347 Debug.assert((oldText.length - textChangeRange.span.length + textChangeRange.newLength) === newText.length); 10348 10349 if (aggressiveChecks || Debug.shouldAssert(AssertionLevel.VeryAggressive)) { 10350 const oldTextPrefix = oldText.substr(0, textChangeRange.span.start); 10351 const newTextPrefix = newText.substr(0, textChangeRange.span.start); 10352 Debug.assert(oldTextPrefix === newTextPrefix); 10353 10354 const oldTextSuffix = oldText.substring(textSpanEnd(textChangeRange.span), oldText.length); 10355 const newTextSuffix = newText.substring(textSpanEnd(textChangeRangeNewSpan(textChangeRange)), newText.length); 10356 Debug.assert(oldTextSuffix === newTextSuffix); 10357 } 10358 } 10359 } 10360 10361 interface IncrementalElement extends ReadonlyTextRange { 10362 readonly parent: Node; 10363 intersectsChange: boolean; 10364 length?: number; 10365 _children: Node[] | undefined; 10366 } 10367 10368 export interface IncrementalNode extends Node, IncrementalElement { 10369 hasBeenIncrementallyParsed: boolean; 10370 } 10371 10372 interface IncrementalNodeArray extends NodeArray<IncrementalNode>, IncrementalElement { 10373 length: number; 10374 } 10375 10376 // Allows finding nodes in the source file at a certain position in an efficient manner. 10377 // The implementation takes advantage of the calling pattern it knows the parser will 10378 // make in order to optimize finding nodes as quickly as possible. 10379 export interface SyntaxCursor { 10380 currentNode(position: number): IncrementalNode; 10381 } 10382 10383 export function createSyntaxCursor(sourceFile: SourceFile): SyntaxCursor { 10384 let currentArray: NodeArray<Node> = sourceFile.statements; 10385 let currentArrayIndex = 0; 10386 10387 Debug.assert(currentArrayIndex < currentArray.length); 10388 let current = currentArray[currentArrayIndex]; 10389 let lastQueriedPosition = InvalidPosition.Value; 10390 10391 return { 10392 currentNode(position: number) { 10393 // Only compute the current node if the position is different than the last time 10394 // we were asked. The parser commonly asks for the node at the same position 10395 // twice. Once to know if can read an appropriate list element at a certain point, 10396 // and then to actually read and consume the node. 10397 if (position !== lastQueriedPosition) { 10398 // Much of the time the parser will need the very next node in the array that 10399 // we just returned a node from.So just simply check for that case and move 10400 // forward in the array instead of searching for the node again. 10401 if (current && current.end === position && currentArrayIndex < (currentArray.length - 1)) { 10402 currentArrayIndex++; 10403 current = currentArray[currentArrayIndex]; 10404 } 10405 10406 // If we don't have a node, or the node we have isn't in the right position, 10407 // then try to find a viable node at the position requested. 10408 if (!current || current.pos !== position) { 10409 findHighestListElementThatStartsAtPosition(position); 10410 } 10411 } 10412 10413 // Cache this query so that we don't do any extra work if the parser calls back 10414 // into us. Note: this is very common as the parser will make pairs of calls like 10415 // 'isListElement -> parseListElement'. If we were unable to find a node when 10416 // called with 'isListElement', we don't want to redo the work when parseListElement 10417 // is called immediately after. 10418 lastQueriedPosition = position; 10419 10420 // Either we don'd have a node, or we have a node at the position being asked for. 10421 Debug.assert(!current || current.pos === position); 10422 return current as IncrementalNode; 10423 } 10424 }; 10425 10426 // Finds the highest element in the tree we can find that starts at the provided position. 10427 // The element must be a direct child of some node list in the tree. This way after we 10428 // return it, we can easily return its next sibling in the list. 10429 function findHighestListElementThatStartsAtPosition(position: number) { 10430 // Clear out any cached state about the last node we found. 10431 currentArray = undefined!; 10432 currentArrayIndex = InvalidPosition.Value; 10433 current = undefined!; 10434 10435 // Recurse into the source file to find the highest node at this position. 10436 forEachChild(sourceFile, visitNode, visitArray); 10437 return; 10438 10439 function visitNode(node: Node) { 10440 if (position >= node.pos && position < node.end) { 10441 // Position was within this node. Keep searching deeper to find the node. 10442 forEachChild(node, visitNode, visitArray); 10443 10444 // don't proceed any further in the search. 10445 return true; 10446 } 10447 10448 // position wasn't in this node, have to keep searching. 10449 return false; 10450 } 10451 10452 function visitArray(array: NodeArray<Node>) { 10453 if (position >= array.pos && position < array.end) { 10454 // position was in this array. Search through this array to see if we find a 10455 // viable element. 10456 for (let i = 0; i < array.length; i++) { 10457 const child = array[i]; 10458 if (child) { 10459 if (child.pos === position) { 10460 // Found the right node. We're done. 10461 currentArray = array; 10462 currentArrayIndex = i; 10463 current = child; 10464 return true; 10465 } 10466 else { 10467 if (child.pos < position && position < child.end) { 10468 // Position in somewhere within this child. Search in it and 10469 // stop searching in this array. 10470 forEachChild(child, visitNode, visitArray); 10471 return true; 10472 } 10473 } 10474 } 10475 } 10476 } 10477 10478 // position wasn't in this array, have to keep searching. 10479 return false; 10480 } 10481 } 10482 } 10483 10484 const enum InvalidPosition { 10485 Value = -1 10486 } 10487 } 10488 10489 /** @internal */ 10490 export function isDeclarationFileName(fileName: string): boolean { 10491 return fileExtensionIsOneOf(fileName, supportedDeclarationExtensions); 10492 } 10493 10494 /*@internal*/ 10495 export interface PragmaContext { 10496 languageVersion: ScriptTarget; 10497 pragmas?: PragmaMap; 10498 checkJsDirective?: CheckJsDirective; 10499 referencedFiles: FileReference[]; 10500 typeReferenceDirectives: FileReference[]; 10501 libReferenceDirectives: FileReference[]; 10502 amdDependencies: AmdDependency[]; 10503 hasNoDefaultLib?: boolean; 10504 moduleName?: string; 10505 } 10506 10507 function parseResolutionMode(mode: string | undefined, pos: number, end: number, reportDiagnostic: PragmaDiagnosticReporter): ModuleKind.ESNext | ModuleKind.CommonJS | undefined { 10508 if (!mode) { 10509 return undefined; 10510 } 10511 if (mode === "import") { 10512 return ModuleKind.ESNext; 10513 } 10514 if (mode === "require") { 10515 return ModuleKind.CommonJS; 10516 } 10517 reportDiagnostic(pos, end - pos, Diagnostics.resolution_mode_should_be_either_require_or_import); 10518 return undefined; 10519 } 10520 10521 /*@internal*/ 10522 export function processCommentPragmas(context: PragmaContext, sourceText: string): void { 10523 const pragmas: PragmaPseudoMapEntry[] = []; 10524 10525 for (const range of getLeadingCommentRanges(sourceText, 0) || emptyArray) { 10526 const comment = sourceText.substring(range.pos, range.end); 10527 extractPragmas(pragmas, range, comment); 10528 } 10529 10530 context.pragmas = new Map() as PragmaMap; 10531 for (const pragma of pragmas) { 10532 if (context.pragmas.has(pragma.name)) { 10533 const currentValue = context.pragmas.get(pragma.name); 10534 if (currentValue instanceof Array) { 10535 currentValue.push(pragma.args); 10536 } 10537 else { 10538 context.pragmas.set(pragma.name, [currentValue, pragma.args]); 10539 } 10540 continue; 10541 } 10542 context.pragmas.set(pragma.name, pragma.args); 10543 } 10544 } 10545 10546 /*@internal*/ 10547 type PragmaDiagnosticReporter = (pos: number, length: number, message: DiagnosticMessage) => void; 10548 10549 /*@internal*/ 10550 export function processPragmasIntoFields(context: PragmaContext, reportDiagnostic: PragmaDiagnosticReporter): void { 10551 context.checkJsDirective = undefined; 10552 context.referencedFiles = []; 10553 context.typeReferenceDirectives = []; 10554 context.libReferenceDirectives = []; 10555 context.amdDependencies = []; 10556 context.hasNoDefaultLib = false; 10557 context.pragmas!.forEach((entryOrList, key) => { // TODO: GH#18217 10558 // TODO: The below should be strongly type-guarded and not need casts/explicit annotations, since entryOrList is related to 10559 // key and key is constrained to a union; but it's not (see GH#21483 for at least partial fix) :( 10560 switch (key) { 10561 case "reference": { 10562 const referencedFiles = context.referencedFiles; 10563 const typeReferenceDirectives = context.typeReferenceDirectives; 10564 const libReferenceDirectives = context.libReferenceDirectives; 10565 forEach(toArray(entryOrList) as PragmaPseudoMap["reference"][], arg => { 10566 const { types, lib, path, ["resolution-mode"]: res } = arg.arguments; 10567 if (arg.arguments["no-default-lib"]) { 10568 context.hasNoDefaultLib = true; 10569 } 10570 else if (types) { 10571 const parsed = parseResolutionMode(res, types.pos, types.end, reportDiagnostic); 10572 typeReferenceDirectives.push({ pos: types.pos, end: types.end, fileName: types.value, ...(parsed ? { resolutionMode: parsed } : {}) }); 10573 } 10574 else if (lib) { 10575 libReferenceDirectives.push({ pos: lib.pos, end: lib.end, fileName: lib.value }); 10576 } 10577 else if (path) { 10578 referencedFiles.push({ pos: path.pos, end: path.end, fileName: path.value }); 10579 } 10580 else { 10581 reportDiagnostic(arg.range.pos, arg.range.end - arg.range.pos, Diagnostics.Invalid_reference_directive_syntax); 10582 } 10583 }); 10584 break; 10585 } 10586 case "amd-dependency": { 10587 context.amdDependencies = map( 10588 toArray(entryOrList) as PragmaPseudoMap["amd-dependency"][], 10589 x => ({ name: x.arguments.name, path: x.arguments.path })); 10590 break; 10591 } 10592 case "amd-module": { 10593 if (entryOrList instanceof Array) { 10594 for (const entry of entryOrList) { 10595 if (context.moduleName) { 10596 // TODO: It's probably fine to issue this diagnostic on all instances of the pragma 10597 reportDiagnostic(entry.range.pos, entry.range.end - entry.range.pos, Diagnostics.An_AMD_module_cannot_have_multiple_name_assignments); 10598 } 10599 context.moduleName = (entry as PragmaPseudoMap["amd-module"]).arguments.name; 10600 } 10601 } 10602 else { 10603 context.moduleName = (entryOrList as PragmaPseudoMap["amd-module"]).arguments.name; 10604 } 10605 break; 10606 } 10607 case "ts-nocheck": 10608 case "ts-check": { 10609 // _last_ of either nocheck or check in a file is the "winner" 10610 forEach(toArray(entryOrList), entry => { 10611 if (!context.checkJsDirective || entry.range.pos > context.checkJsDirective.pos) { 10612 context.checkJsDirective = { 10613 enabled: key === "ts-check", 10614 end: entry.range.end, 10615 pos: entry.range.pos 10616 }; 10617 } 10618 }); 10619 break; 10620 } 10621 case "jsx": 10622 case "jsxfrag": 10623 case "jsximportsource": 10624 case "jsxruntime": 10625 return; // Accessed directly 10626 default: Debug.fail("Unhandled pragma kind"); // Can this be made into an assertNever in the future? 10627 } 10628 }); 10629 } 10630 10631 const namedArgRegExCache = new Map<string, RegExp>(); 10632 function getNamedArgRegEx(name: string): RegExp { 10633 if (namedArgRegExCache.has(name)) { 10634 return namedArgRegExCache.get(name)!; 10635 } 10636 const result = new RegExp(`(\\s${name}\\s*=\\s*)(?:(?:'([^']*)')|(?:"([^"]*)"))`, "im"); 10637 namedArgRegExCache.set(name, result); 10638 return result; 10639 } 10640 10641 const tripleSlashXMLCommentStartRegEx = /^\/\/\/\s*<(\S+)\s.*?\/>/im; 10642 const singleLinePragmaRegEx = /^\/\/\/?\s*@(\S+)\s*(.*)\s*$/im; 10643 function extractPragmas(pragmas: PragmaPseudoMapEntry[], range: CommentRange, text: string) { 10644 const tripleSlash = range.kind === SyntaxKind.SingleLineCommentTrivia && tripleSlashXMLCommentStartRegEx.exec(text); 10645 if (tripleSlash) { 10646 const name = tripleSlash[1].toLowerCase() as keyof PragmaPseudoMap; // Technically unsafe cast, but we do it so the below check to make it safe typechecks 10647 const pragma = commentPragmas[name] as PragmaDefinition; 10648 if (!pragma || !(pragma.kind! & PragmaKindFlags.TripleSlashXML)) { 10649 return; 10650 } 10651 if (pragma.args) { 10652 const argument: {[index: string]: string | {value: string, pos: number, end: number}} = {}; 10653 for (const arg of pragma.args) { 10654 const matcher = getNamedArgRegEx(arg.name); 10655 const matchResult = matcher.exec(text); 10656 if (!matchResult && !arg.optional) { 10657 return; // Missing required argument, don't parse 10658 } 10659 else if (matchResult) { 10660 const value = matchResult[2] || matchResult[3]; 10661 if (arg.captureSpan) { 10662 const startPos = range.pos + matchResult.index + matchResult[1].length + 1; 10663 argument[arg.name] = { 10664 value, 10665 pos: startPos, 10666 end: startPos + value.length 10667 }; 10668 } 10669 else { 10670 argument[arg.name] = value; 10671 } 10672 } 10673 } 10674 pragmas.push({ name, args: { arguments: argument, range } } as PragmaPseudoMapEntry); 10675 } 10676 else { 10677 pragmas.push({ name, args: { arguments: {}, range } } as PragmaPseudoMapEntry); 10678 } 10679 return; 10680 } 10681 10682 const singleLine = range.kind === SyntaxKind.SingleLineCommentTrivia && singleLinePragmaRegEx.exec(text); 10683 if (singleLine) { 10684 return addPragmaForMatch(pragmas, range, PragmaKindFlags.SingleLine, singleLine); 10685 } 10686 10687 if (range.kind === SyntaxKind.MultiLineCommentTrivia) { 10688 const multiLinePragmaRegEx = /@(\S+)(\s+.*)?$/gim; // Defined inline since it uses the "g" flag, which keeps a persistent index (for iterating) 10689 let multiLineMatch: RegExpExecArray | null; 10690 while (multiLineMatch = multiLinePragmaRegEx.exec(text)) { 10691 addPragmaForMatch(pragmas, range, PragmaKindFlags.MultiLine, multiLineMatch); 10692 } 10693 } 10694 } 10695 10696 function addPragmaForMatch(pragmas: PragmaPseudoMapEntry[], range: CommentRange, kind: PragmaKindFlags, match: RegExpExecArray) { 10697 if (!match) return; 10698 const name = match[1].toLowerCase() as keyof PragmaPseudoMap; // Technically unsafe cast, but we do it so they below check to make it safe typechecks 10699 const pragma = commentPragmas[name] as PragmaDefinition; 10700 if (!pragma || !(pragma.kind! & kind)) { 10701 return; 10702 } 10703 const args = match[2]; // Split on spaces and match up positionally with definition 10704 const argument = getNamedPragmaArguments(pragma, args); 10705 if (argument === "fail") return; // Missing required argument, fail to parse it 10706 pragmas.push({ name, args: { arguments: argument, range } } as PragmaPseudoMapEntry); 10707 return; 10708 } 10709 10710 function getNamedPragmaArguments(pragma: PragmaDefinition, text: string | undefined): {[index: string]: string} | "fail" { 10711 if (!text) return {}; 10712 if (!pragma.args) return {}; 10713 const args = trimString(text).split(/\s+/); 10714 const argMap: {[index: string]: string} = {}; 10715 for (let i = 0; i < pragma.args.length; i++) { 10716 const argument = pragma.args[i]; 10717 if (!args[i] && !argument.optional) { 10718 return "fail"; 10719 } 10720 if (argument.captureSpan) { 10721 return Debug.fail("Capture spans not yet implemented for non-xml pragmas"); 10722 } 10723 argMap[argument.name] = args[i]; 10724 } 10725 return argMap; 10726 } 10727 10728 /** @internal */ 10729 export function tagNamesAreEquivalent(lhs: JsxTagNameExpression, rhs: JsxTagNameExpression): boolean { 10730 if (lhs.kind !== rhs.kind) { 10731 return false; 10732 } 10733 10734 if (lhs.kind === SyntaxKind.Identifier) { 10735 return lhs.escapedText === (rhs as Identifier).escapedText; 10736 } 10737 10738 if (lhs.kind === SyntaxKind.ThisKeyword) { 10739 return true; 10740 } 10741 10742 // If we are at this statement then we must have PropertyAccessExpression and because tag name in Jsx element can only 10743 // take forms of JsxTagNameExpression which includes an identifier, "this" expression, or another propertyAccessExpression 10744 // it is safe to case the expression property as such. See parseJsxElementName for how we parse tag name in Jsx element 10745 return (lhs as PropertyAccessExpression).name.escapedText === (rhs as PropertyAccessExpression).name.escapedText && 10746 tagNamesAreEquivalent((lhs as PropertyAccessExpression).expression as JsxTagNameExpression, (rhs as PropertyAccessExpression).expression as JsxTagNameExpression); 10747 } 10748} 10749