1import * as ts from "./_namespaces/ts"; 2import { 3 AccessorDeclaration, 4 addRange, 5 addRelatedInfo, 6 AmdDependency, 7 AnnotationDeclaration, 8 AnnotationElement, 9 AnnotationPropertyDeclaration, 10 append, 11 ArrayBindingElement, 12 ArrayBindingPattern, 13 ArrayLiteralExpression, 14 ArrayTypeNode, 15 ArrowFunction, 16 AsExpression, 17 AssertClause, 18 AssertEntry, 19 AssertionLevel, 20 AsteriskToken, 21 attachFileToDiagnostics, 22 AwaitExpression, 23 BaseNodeFactory, 24 BinaryExpression, 25 BinaryOperatorToken, 26 BindingElement, 27 BindingName, 28 BindingPattern, 29 Block, 30 BooleanLiteral, 31 BreakOrContinueStatement, 32 BreakStatement, 33 CallExpression, 34 CallSignatureDeclaration, 35 canHaveModifiers, 36 CaseBlock, 37 CaseClause, 38 CaseOrDefaultClause, 39 CatchClause, 40 CharacterCodes, 41 CheckJsDirective, 42 ClassDeclaration, 43 ClassElement, 44 ClassExpression, 45 ClassLikeDeclaration, 46 ClassStaticBlockDeclaration, 47 CommaListExpression, 48 CommentDirective, 49 commentPragmas, 50 CommentRange, 51 CompilerOptions, 52 ComputedPropertyName, 53 concatenate, 54 ConditionalExpression, 55 ConditionalTypeNode, 56 ConstructorDeclaration, 57 ConstructorTypeNode, 58 ConstructSignatureDeclaration, 59 containsParseError, 60 ContinueStatement, 61 convertToObjectWorker, 62 createDetachedDiagnostic, 63 createNodeFactory, 64 createScanner, 65 createTextChangeRange, 66 createTextSpanFromBounds, 67 Debug, 68 Decorator, 69 DefaultClause, 70 defaultInitCompilerOptions, 71 DeleteExpression, 72 Diagnostic, 73 DiagnosticMessage, 74 Diagnostics, 75 DiagnosticWithDetachedLocation, 76 DoStatement, 77 DotDotDotToken, 78 ElementAccessExpression, 79 emptyArray, 80 emptyMap, 81 EndOfFileToken, 82 ensureScriptKind, 83 EntityName, 84 EnumDeclaration, 85 EnumMember, 86 ESMap, 87 EtsComponentExpression, 88 EtsFlags, 89 ExclamationToken, 90 ExportAssignment, 91 ExportDeclaration, 92 ExportSpecifier, 93 Expression, 94 ExpressionStatement, 95 ExpressionWithTypeArguments, 96 Extension, 97 ExternalModuleReference, 98 fileExtensionIsOneOf, 99 FileReference, 100 findIndex, 101 forEach, 102 ForEachChildNodes, 103 ForInOrOfStatement, 104 ForInStatement, 105 ForOfStatement, 106 ForStatement, 107 FunctionDeclaration, 108 FunctionExpression, 109 FunctionOrConstructorTypeNode, 110 FunctionTypeNode, 111 GetAccessorDeclaration, 112 getBinaryOperatorPrecedence, 113 getEtsExtendDecoratorsComponentNames, 114 getEtsStylesDecoratorComponentNames, 115 getFullWidth, 116 getJSDocCommentRanges, 117 getLanguageVariant, 118 getLastChild, 119 getLeadingCommentRanges, 120 getModifiers, 121 getPropertyNameForPropertyNameNode, 122 getRootComponent, 123 getSdkPath, 124 getSpellingSuggestion, 125 getTextOfNodeFromSourceText, 126 getTextOfPropertyName, 127 getVirtualEtsComponent, 128 hasEtsBuilderDecoratorNames, 129 hasEtsExtendDecoratorNames, 130 hasEtsStylesDecoratorNames, 131 HasJSDoc, 132 hasJSDocNodes, 133 HasModifiers, 134 HeritageClause, 135 Identifier, 136 idText, 137 IfStatement, 138 ImportClause, 139 ImportDeclaration, 140 ImportEqualsDeclaration, 141 ImportOrExportSpecifier, 142 ImportSpecifier, 143 ImportTypeAssertionContainer, 144 ImportTypeNode, 145 IndexedAccessTypeNode, 146 IndexSignatureDeclaration, 147 InferTypeNode, 148 InterfaceDeclaration, 149 IntersectionTypeNode, 150 isArray, 151 isAssignmentOperator, 152 isAsyncModifier, 153 isCallExpression, 154 isClassMemberModifier, 155 isExportAssignment, 156 isExportDeclaration, 157 isExportModifier, 158 isExpressionWithTypeArguments, 159 isExternalModuleReference, 160 isFunctionTypeNode, 161 isIdentifierText, 162 isImportDeclaration, 163 isImportEqualsDeclaration, 164 isJSDocFunctionType, 165 isJSDocNullableType, 166 isJSDocReturnTag, 167 isJSDocTypeTag, 168 isJsxOpeningElement, 169 isJsxOpeningFragment, 170 isKeyword, 171 isLeftHandSideExpression, 172 isLiteralKind, 173 isMetaProperty, 174 isModifierKind, 175 isNonNullExpression, 176 isPrivateIdentifier, 177 isPropertyAccessExpression, 178 isSetAccessorDeclaration, 179 isStringOrNumericLiteralLike, 180 isTaggedTemplateExpression, 181 isTemplateLiteralKind, 182 isTokenInsideBuilder, 183 isTypeReferenceNode, 184 IterationStatement, 185 JSDoc, 186 JSDocAllType, 187 JSDocAugmentsTag, 188 JSDocAuthorTag, 189 JSDocCallbackTag, 190 JSDocClassTag, 191 JSDocComment, 192 JSDocContainer, 193 JSDocDeprecatedTag, 194 JSDocEnumTag, 195 JSDocFunctionType, 196 JSDocImplementsTag, 197 JSDocLink, 198 JSDocLinkCode, 199 JSDocLinkPlain, 200 JSDocMemberName, 201 JSDocNameReference, 202 JSDocNamespaceDeclaration, 203 JSDocNonNullableType, 204 JSDocNullableType, 205 JSDocOptionalType, 206 JSDocOverrideTag, 207 JSDocParameterTag, 208 JSDocPrivateTag, 209 JSDocPropertyLikeTag, 210 JSDocPropertyTag, 211 JSDocProtectedTag, 212 JSDocPublicTag, 213 JSDocReadonlyTag, 214 JSDocReturnTag, 215 JSDocSeeTag, 216 JSDocSignature, 217 JSDocSyntaxKind, 218 JSDocTag, 219 JSDocTemplateTag, 220 JSDocText, 221 JSDocThisTag, 222 JSDocTypedefTag, 223 JSDocTypeExpression, 224 JSDocTypeLiteral, 225 JSDocTypeTag, 226 JSDocUnknownTag, 227 JSDocUnknownType, 228 JSDocVariadicType, 229 JsonMinusNumericLiteral, 230 JsonObjectExpressionStatement, 231 JsonSourceFile, 232 JsxAttribute, 233 JsxAttributes, 234 JsxAttributeValue, 235 JsxChild, 236 JsxClosingElement, 237 JsxClosingFragment, 238 JsxElement, 239 JsxExpression, 240 JsxFragment, 241 JsxOpeningElement, 242 JsxOpeningFragment, 243 JsxOpeningLikeElement, 244 JsxSelfClosingElement, 245 JsxSpreadAttribute, 246 JsxTagNameExpression, 247 JsxTagNamePropertyAccess, 248 JsxText, 249 JsxTokenSyntaxKind, 250 LabeledStatement, 251 LanguageVariant, 252 last, 253 lastOrUndefined, 254 LeftHandSideExpression, 255 LiteralExpression, 256 LiteralLikeNode, 257 LiteralTypeNode, 258 map, 259 Map, 260 mapDefined, 261 MappedTypeNode, 262 MemberExpression, 263 MemoryDotting, 264 MetaProperty, 265 MethodDeclaration, 266 MethodSignature, 267 MinusToken, 268 MissingDeclaration, 269 Modifier, 270 ModifierFlags, 271 ModifierLike, 272 ModifiersArray, 273 modifiersToFlags, 274 ModuleBlock, 275 ModuleDeclaration, 276 ModuleKind, 277 Mutable, 278 NamedExportBindings, 279 NamedExports, 280 NamedImports, 281 NamedImportsOrExports, 282 NamedTupleMember, 283 NamespaceDeclaration, 284 NamespaceExport, 285 NamespaceExportDeclaration, 286 NamespaceImport, 287 NewExpression, 288 Node, 289 NodeArray, 290 NodeFactoryFlags, 291 NodeFlags, 292 nodeIsMissing, 293 nodeIsPresent, 294 NonNullExpression, 295 noop, 296 normalizePath, 297 NoSubstitutionTemplateLiteral, 298 NullLiteral, 299 NumericLiteral, 300 objectAllocator, 301 ObjectBindingPattern, 302 ObjectLiteralElementLike, 303 ObjectLiteralExpression, 304 OperatorPrecedence, 305 OptionalTypeNode, 306 PackageJsonInfo, 307 ParameterDeclaration, 308 ParenthesizedExpression, 309 ParenthesizedTypeNode, 310 PartiallyEmittedExpression, 311 perfLogger, 312 PlusToken, 313 PostfixUnaryExpression, 314 PostfixUnaryOperator, 315 PragmaDefinition, 316 PragmaKindFlags, 317 PragmaMap, 318 PragmaPseudoMap, 319 PragmaPseudoMapEntry, 320 PrefixUnaryExpression, 321 PrefixUnaryOperator, 322 PrimaryExpression, 323 PrivateIdentifier, 324 processKit, 325 PropertyAccessEntityNameExpression, 326 PropertyAccessExpression, 327 PropertyAssignment, 328 PropertyDeclaration, 329 PropertyName, 330 PropertySignature, 331 QualifiedName, 332 QuestionDotToken, 333 QuestionToken, 334 ReadonlyKeyword, 335 ReadonlyPragmaMap, 336 ReadonlyTextRange, 337 RestTypeNode, 338 ReturnStatement, 339 SatisfiesExpression, 340 ScriptKind, 341 ScriptTarget, 342 Set, 343 SetAccessorDeclaration, 344 setParent, 345 setParentRecursive, 346 setTextRange, 347 setTextRangePos, 348 setTextRangePosEnd, 349 setTextRangePosWidth, 350 ShorthandPropertyAssignment, 351 skipTrivia, 352 some, 353 SourceFile, 354 SpreadAssignment, 355 SpreadElement, 356 startsWith, 357 Statement, 358 StringLiteral, 359 StructDeclaration, 360 supportedDeclarationExtensions, 361 SwitchStatement, 362 SyntaxKind, 363 TaggedTemplateExpression, 364 TemplateExpression, 365 TemplateHead, 366 TemplateLiteralToken, 367 TemplateLiteralTypeNode, 368 TemplateLiteralTypeSpan, 369 TemplateMiddle, 370 TemplateSpan, 371 TemplateTail, 372 TextChangeRange, 373 textChangeRangeIsUnchanged, 374 textChangeRangeNewSpan, 375 TextRange, 376 textSpanEnd, 377 textToKeywordObj, 378 ThisExpression, 379 ThisTypeNode, 380 ThrowStatement, 381 toArray, 382 Token, 383 TokenFlags, 384 tokenIsIdentifierOrKeyword, 385 tokenIsIdentifierOrKeywordOrGreaterThan, 386 tokenToString, 387 tracing, 388 TransformFlags, 389 trimString, 390 TryStatement, 391 TupleTypeNode, 392 TypeAliasDeclaration, 393 TypeAssertion, 394 TypeElement, 395 TypeLiteralNode, 396 TypeNode, 397 TypeOfExpression, 398 TypeOperatorNode, 399 TypeParameterDeclaration, 400 TypePredicateNode, 401 TypeQueryNode, 402 TypeReferenceNode, 403 UnaryExpression, 404 UnionOrIntersectionTypeNode, 405 UnionTypeNode, 406 UpdateExpression, 407 VariableDeclaration, 408 VariableDeclarationList, 409 VariableStatement, 410 VoidExpression, 411 WhileStatement, 412 WithStatement, 413 YieldExpression, 414} from "./_namespaces/ts"; 415import * as performance from "./_namespaces/ts.performance"; 416 417const enum SignatureFlags { 418 None = 0, 419 Yield = 1 << 0, 420 Await = 1 << 1, 421 Type = 1 << 2, 422 IgnoreMissingOpenBrace = 1 << 4, 423 JSDoc = 1 << 5, 424} 425 426const enum SpeculationKind { 427 TryParse, 428 Lookahead, 429 Reparse 430} 431 432let NodeConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node; 433let TokenConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node; 434let IdentifierConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node; 435let PrivateIdentifierConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node; 436let SourceFileConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node; 437 438/** 439 * NOTE: You should not use this, it is only exported to support `createNode` in `~/src/deprecatedCompat/deprecations.ts`. 440 * 441 * @internal 442 */ 443export const parseBaseNodeFactory: BaseNodeFactory = { 444 createBaseSourceFileNode: kind => new (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))(kind, -1, -1), 445 createBaseIdentifierNode: kind => new (IdentifierConstructor || (IdentifierConstructor = objectAllocator.getIdentifierConstructor()))(kind, -1, -1), 446 createBasePrivateIdentifierNode: kind => new (PrivateIdentifierConstructor || (PrivateIdentifierConstructor = objectAllocator.getPrivateIdentifierConstructor()))(kind, -1, -1), 447 createBaseTokenNode: kind => new (TokenConstructor || (TokenConstructor = objectAllocator.getTokenConstructor()))(kind, -1, -1), 448 createBaseNode: kind => new (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor()))(kind, -1, -1), 449}; 450 451/** @internal */ 452export const parseNodeFactory = createNodeFactory(NodeFactoryFlags.NoParenthesizerRules, parseBaseNodeFactory); 453 454function visitNode<T>(cbNode: (node: Node) => T, node: Node | undefined): T | undefined { 455 return node && cbNode(node); 456} 457 458function visitNodes<T>(cbNode: (node: Node) => T, cbNodes: ((node: NodeArray<Node>) => T | undefined) | undefined, nodes: NodeArray<Node> | undefined): T | undefined { 459 if (nodes) { 460 if (cbNodes) { 461 return cbNodes(nodes); 462 } 463 for (const node of nodes) { 464 const result = cbNode(node); 465 if (result) { 466 return result; 467 } 468 } 469 } 470} 471 472/** @internal */ 473export function isJSDocLikeText(text: string, start: number) { 474 return text.charCodeAt(start + 1) === CharacterCodes.asterisk && 475 text.charCodeAt(start + 2) === CharacterCodes.asterisk && 476 text.charCodeAt(start + 3) !== CharacterCodes.slash; 477} 478 479/** @internal */ 480export function isFileProbablyExternalModule(sourceFile: SourceFile) { 481 // Try to use the first top-level import/export when available, then 482 // fall back to looking for an 'import.meta' somewhere in the tree if necessary. 483 return forEach(sourceFile.statements, isAnExternalModuleIndicatorNode) || 484 getImportMetaIfNecessary(sourceFile); 485} 486 487function isAnExternalModuleIndicatorNode(node: Node) { 488 return canHaveModifiers(node) && hasModifierOfKind(node, SyntaxKind.ExportKeyword) 489 || isImportEqualsDeclaration(node) && isExternalModuleReference(node.moduleReference) 490 || isImportDeclaration(node) 491 || isExportAssignment(node) 492 || isExportDeclaration(node) ? node : undefined; 493} 494 495function getImportMetaIfNecessary(sourceFile: SourceFile) { 496 return sourceFile.flags & NodeFlags.PossiblyContainsImportMeta ? 497 walkTreeForImportMeta(sourceFile) : 498 undefined; 499} 500 501function walkTreeForImportMeta(node: Node): Node | undefined { 502 return isImportMeta(node) ? node : forEachChild(node, walkTreeForImportMeta); 503} 504 505/** Do not use hasModifier inside the parser; it relies on parent pointers. Use this instead. */ 506function hasModifierOfKind(node: HasModifiers, kind: SyntaxKind) { 507 return some(node.modifiers, m => m.kind === kind); 508} 509 510function isImportMeta(node: Node): boolean { 511 return isMetaProperty(node) && node.keywordToken === SyntaxKind.ImportKeyword && node.name.escapedText === "meta"; 512} 513 514type ForEachChildFunction<TNode> = <T>(node: TNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined) => T | undefined; 515type ForEachChildTable = { [TNode in ForEachChildNodes as TNode["kind"]]: ForEachChildFunction<TNode> }; 516const forEachChildTable: ForEachChildTable = { 517 [SyntaxKind.QualifiedName]: function forEachChildInQualifiedName<T>(node: QualifiedName, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 518 return visitNode(cbNode, node.left) || 519 visitNode(cbNode, node.right); 520 }, 521 [SyntaxKind.TypeParameter]: function forEachChildInTypeParameter<T>(node: TypeParameterDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 522 return visitNodes(cbNode, cbNodes, node.modifiers) || 523 visitNode(cbNode, node.name) || 524 visitNode(cbNode, node.constraint) || 525 visitNode(cbNode, node.default) || 526 visitNode(cbNode, node.expression); 527 }, 528 [SyntaxKind.ShorthandPropertyAssignment]: function forEachChildInShorthandPropertyAssignment<T>(node: ShorthandPropertyAssignment, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 529 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 530 visitNodes(cbNode, cbNodes, node.modifiers) || 531 visitNode(cbNode, node.name) || 532 visitNode(cbNode, node.questionToken) || 533 visitNode(cbNode, node.exclamationToken) || 534 visitNode(cbNode, node.equalsToken) || 535 visitNode(cbNode, node.objectAssignmentInitializer); 536 }, 537 [SyntaxKind.SpreadAssignment]: function forEachChildInSpreadAssignment<T>(node: SpreadAssignment, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 538 return visitNode(cbNode, node.expression); 539 }, 540 [SyntaxKind.Parameter]: function forEachChildInParameter<T>(node: ParameterDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 541 return visitNodes(cbNode, cbNodes, node.modifiers) || 542 visitNode(cbNode, node.dotDotDotToken) || 543 visitNode(cbNode, node.name) || 544 visitNode(cbNode, node.questionToken) || 545 visitNode(cbNode, node.type) || 546 visitNode(cbNode, node.initializer); 547 }, 548 [SyntaxKind.PropertyDeclaration]: function forEachChildInPropertyDeclaration<T>(node: PropertyDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 549 return visitNodes(cbNode, cbNodes, node.modifiers) || 550 visitNode(cbNode, node.name) || 551 visitNode(cbNode, node.questionToken) || 552 visitNode(cbNode, node.exclamationToken) || 553 visitNode(cbNode, node.type) || 554 visitNode(cbNode, node.initializer); 555 }, 556 [SyntaxKind.AnnotationPropertyDeclaration]: function forEachChildInAnnotationPropertyDeclaration<T>(node: AnnotationPropertyDeclaration, 557 cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 558 return visitNode(cbNode, node.name) || 559 visitNode(cbNode, node.type) || 560 visitNode(cbNode, node.initializer); 561 }, 562 [SyntaxKind.PropertySignature]: function forEachChildInPropertySignature<T>(node: PropertySignature, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 563 return visitNodes(cbNode, cbNodes, node.modifiers) || 564 visitNode(cbNode, node.name) || 565 visitNode(cbNode, node.questionToken) || 566 visitNode(cbNode, node.type) || 567 visitNode(cbNode, node.initializer); 568 }, 569 [SyntaxKind.PropertyAssignment]: function forEachChildInPropertyAssignment<T>(node: PropertyAssignment, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 570 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 571 visitNodes(cbNode, cbNodes, node.modifiers) || 572 visitNode(cbNode, node.name) || 573 visitNode(cbNode, node.questionToken) || 574 visitNode(cbNode, node.exclamationToken) || 575 visitNode(cbNode, node.initializer); 576 }, 577 [SyntaxKind.VariableDeclaration]: function forEachChildInVariableDeclaration<T>(node: VariableDeclaration, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 578 return visitNode(cbNode, node.name) || 579 visitNode(cbNode, node.exclamationToken) || 580 visitNode(cbNode, node.type) || 581 visitNode(cbNode, node.initializer); 582 }, 583 [SyntaxKind.BindingElement]: function forEachChildInBindingElement<T>(node: BindingElement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 584 return visitNode(cbNode, node.dotDotDotToken) || 585 visitNode(cbNode, node.propertyName) || 586 visitNode(cbNode, node.name) || 587 visitNode(cbNode, node.initializer); 588 }, 589 [SyntaxKind.IndexSignature]: function forEachChildInIndexSignature<T>(node: IndexSignatureDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 590 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 591 visitNodes(cbNode, cbNodes, node.modifiers) || 592 visitNodes(cbNode, cbNodes, node.typeParameters) || 593 visitNodes(cbNode, cbNodes, node.parameters) || 594 visitNode(cbNode, node.type); 595 }, 596 [SyntaxKind.ConstructorType]: function forEachChildInConstructorType<T>(node: ConstructorTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 597 return visitNodes(cbNode, cbNodes, node.modifiers) || 598 visitNodes(cbNode, cbNodes, node.typeParameters) || 599 visitNodes(cbNode, cbNodes, node.parameters) || 600 visitNode(cbNode, node.type); 601 }, 602 [SyntaxKind.FunctionType]: function forEachChildInFunctionType<T>(node: FunctionTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 603 return visitNodes(cbNode, cbNodes, node.modifiers) || 604 visitNodes(cbNode, cbNodes, node.typeParameters) || 605 visitNodes(cbNode, cbNodes, node.parameters) || 606 visitNode(cbNode, node.type); 607 }, 608 [SyntaxKind.CallSignature]: forEachChildInCallOrConstructSignature, 609 [SyntaxKind.ConstructSignature]: forEachChildInCallOrConstructSignature, 610 [SyntaxKind.EtsComponentExpression]: function forEachChildInEtsComponentExpression<T>(node: EtsComponentExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 611 return visitNode(cbNode, node.expression) || 612 visitNodes(cbNode, cbNodes, node.arguments) || 613 visitNode(cbNode, node.body); 614 }, 615 [SyntaxKind.MethodDeclaration]: function forEachChildInMethodDeclaration<T>(node: MethodDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 616 return visitNodes(cbNode, cbNodes, node.modifiers) || 617 visitNode(cbNode, node.asteriskToken) || 618 visitNode(cbNode, node.name) || 619 visitNode(cbNode, node.questionToken) || 620 visitNode(cbNode, node.exclamationToken) || 621 visitNodes(cbNode, cbNodes, node.typeParameters) || 622 visitNodes(cbNode, cbNodes, node.parameters) || 623 visitNode(cbNode, node.type) || 624 visitNode(cbNode, node.body); 625 }, 626 [SyntaxKind.MethodSignature]: function forEachChildInMethodSignature<T>(node: MethodSignature, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 627 return visitNodes(cbNode, cbNodes, node.modifiers) || 628 visitNode(cbNode, node.name) || 629 visitNode(cbNode, node.questionToken) || 630 visitNodes(cbNode, cbNodes, node.typeParameters) || 631 visitNodes(cbNode, cbNodes, node.parameters) || 632 visitNode(cbNode, node.type); 633 }, 634 [SyntaxKind.Constructor]: function forEachChildInConstructor<T>(node: ConstructorDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 635 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 636 visitNodes(cbNode, cbNodes, node.modifiers) || 637 visitNode(cbNode, node.name) || 638 visitNodes(cbNode, cbNodes, node.typeParameters) || 639 visitNodes(cbNode, cbNodes, node.parameters) || 640 visitNode(cbNode, node.type) || 641 visitNode(cbNode, node.body); 642 }, 643 [SyntaxKind.GetAccessor]: function forEachChildInGetAccessor<T>(node: GetAccessorDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 644 return visitNodes(cbNode, cbNodes, node.modifiers) || 645 visitNode(cbNode, node.name) || 646 visitNodes(cbNode, cbNodes, node.typeParameters) || 647 visitNodes(cbNode, cbNodes, node.parameters) || 648 visitNode(cbNode, node.type) || 649 visitNode(cbNode, node.body); 650 }, 651 [SyntaxKind.SetAccessor]: function forEachChildInSetAccessor<T>(node: SetAccessorDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 652 return visitNodes(cbNode, cbNodes, node.modifiers) || 653 visitNode(cbNode, node.name) || 654 visitNodes(cbNode, cbNodes, node.typeParameters) || 655 visitNodes(cbNode, cbNodes, node.parameters) || 656 visitNode(cbNode, node.type) || 657 visitNode(cbNode, node.body); 658 }, 659 [SyntaxKind.FunctionDeclaration]: function forEachChildInFunctionDeclaration<T>(node: FunctionDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 660 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 661 visitNodes(cbNode, cbNodes, node.modifiers) || 662 visitNode(cbNode, node.asteriskToken) || 663 visitNode(cbNode, node.name) || 664 visitNodes(cbNode, cbNodes, node.typeParameters) || 665 visitNodes(cbNode, cbNodes, node.parameters) || 666 visitNode(cbNode, node.type) || 667 visitNode(cbNode, node.body); 668 }, 669 [SyntaxKind.FunctionExpression]: function forEachChildInFunctionExpression<T>(node: FunctionExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 670 return visitNodes(cbNode, cbNodes, node.modifiers) || 671 visitNode(cbNode, node.asteriskToken) || 672 visitNode(cbNode, node.name) || 673 visitNodes(cbNode, cbNodes, node.typeParameters) || 674 visitNodes(cbNode, cbNodes, node.parameters) || 675 visitNode(cbNode, node.type) || 676 visitNode(cbNode, node.body); 677 }, 678 [SyntaxKind.ArrowFunction]: function forEachChildInArrowFunction<T>(node: ArrowFunction, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 679 return visitNodes(cbNode, cbNodes, node.modifiers) || 680 visitNodes(cbNode, cbNodes, node.typeParameters) || 681 visitNodes(cbNode, cbNodes, node.parameters) || 682 visitNode(cbNode, node.type) || 683 visitNode(cbNode, node.equalsGreaterThanToken) || 684 visitNode(cbNode, node.body); 685 }, 686 [SyntaxKind.ClassStaticBlockDeclaration]: function forEachChildInClassStaticBlockDeclaration<T>(node: ClassStaticBlockDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 687 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 688 visitNodes(cbNode, cbNodes, node.modifiers) || 689 visitNode(cbNode, node.body); 690 }, 691 [SyntaxKind.TypeReference]: function forEachChildInTypeReference<T>(node: TypeReferenceNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 692 return visitNode(cbNode, node.typeName) || 693 visitNodes(cbNode, cbNodes, node.typeArguments); 694 }, 695 [SyntaxKind.TypePredicate]: function forEachChildInTypePredicate<T>(node: TypePredicateNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 696 return visitNode(cbNode, node.assertsModifier) || 697 visitNode(cbNode, node.parameterName) || 698 visitNode(cbNode, node.type); 699 }, 700 [SyntaxKind.TypeQuery]: function forEachChildInTypeQuery<T>(node: TypeQueryNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 701 return visitNode(cbNode, node.exprName) || 702 visitNodes(cbNode, cbNodes, node.typeArguments); 703 }, 704 [SyntaxKind.TypeLiteral]: function forEachChildInTypeLiteral<T>(node: TypeLiteralNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 705 return visitNodes(cbNode, cbNodes, node.members); 706 }, 707 [SyntaxKind.ArrayType]: function forEachChildInArrayType<T>(node: ArrayTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 708 return visitNode(cbNode, node.elementType); 709 }, 710 [SyntaxKind.TupleType]: function forEachChildInTupleType<T>(node: TupleTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 711 return visitNodes(cbNode, cbNodes, node.elements); 712 }, 713 [SyntaxKind.UnionType]: forEachChildInUnionOrIntersectionType, 714 [SyntaxKind.IntersectionType]: forEachChildInUnionOrIntersectionType, 715 [SyntaxKind.ConditionalType]: function forEachChildInConditionalType<T>(node: ConditionalTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 716 return visitNode(cbNode, node.checkType) || 717 visitNode(cbNode, node.extendsType) || 718 visitNode(cbNode, node.trueType) || 719 visitNode(cbNode, node.falseType); 720 }, 721 [SyntaxKind.InferType]: function forEachChildInInferType<T>(node: InferTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 722 return visitNode(cbNode, node.typeParameter); 723 }, 724 [SyntaxKind.ImportType]: function forEachChildInImportType<T>(node: ImportTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 725 return visitNode(cbNode, node.argument) || 726 visitNode(cbNode, node.assertions) || 727 visitNode(cbNode, node.qualifier) || 728 visitNodes(cbNode, cbNodes, node.typeArguments); 729 }, 730 [SyntaxKind.ImportTypeAssertionContainer]: function forEachChildInImportTypeAssertionContainer<T>(node: ImportTypeAssertionContainer, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 731 return visitNode(cbNode, node.assertClause); 732 }, 733 [SyntaxKind.ParenthesizedType]: forEachChildInParenthesizedTypeOrTypeOperator, 734 [SyntaxKind.TypeOperator]: forEachChildInParenthesizedTypeOrTypeOperator, 735 [SyntaxKind.IndexedAccessType]: function forEachChildInIndexedAccessType<T>(node: IndexedAccessTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 736 return visitNode(cbNode, node.objectType) || 737 visitNode(cbNode, node.indexType); 738 }, 739 [SyntaxKind.MappedType]: function forEachChildInMappedType<T>(node: MappedTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 740 return visitNode(cbNode, node.readonlyToken) || 741 visitNode(cbNode, node.typeParameter) || 742 visitNode(cbNode, node.nameType) || 743 visitNode(cbNode, node.questionToken) || 744 visitNode(cbNode, node.type) || 745 visitNodes(cbNode, cbNodes, node.members); 746 }, 747 [SyntaxKind.LiteralType]: function forEachChildInLiteralType<T>(node: LiteralTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 748 return visitNode(cbNode, node.literal); 749 }, 750 [SyntaxKind.NamedTupleMember]: function forEachChildInNamedTupleMember<T>(node: NamedTupleMember, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 751 return visitNode(cbNode, node.dotDotDotToken) || 752 visitNode(cbNode, node.name) || 753 visitNode(cbNode, node.questionToken) || 754 visitNode(cbNode, node.type); 755 }, 756 [SyntaxKind.ObjectBindingPattern]: forEachChildInObjectOrArrayBindingPattern, 757 [SyntaxKind.ArrayBindingPattern]: forEachChildInObjectOrArrayBindingPattern, 758 [SyntaxKind.ArrayLiteralExpression]: function forEachChildInArrayLiteralExpression<T>(node: ArrayLiteralExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 759 return visitNodes(cbNode, cbNodes, node.elements); 760 }, 761 [SyntaxKind.ObjectLiteralExpression]: function forEachChildInObjectLiteralExpression<T>(node: ObjectLiteralExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 762 return visitNodes(cbNode, cbNodes, node.properties); 763 }, 764 [SyntaxKind.PropertyAccessExpression]: function forEachChildInPropertyAccessExpression<T>(node: PropertyAccessExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 765 return visitNode(cbNode, node.expression) || 766 visitNode(cbNode, node.questionDotToken) || 767 visitNode(cbNode, node.name); 768 }, 769 [SyntaxKind.ElementAccessExpression]: function forEachChildInElementAccessExpression<T>(node: ElementAccessExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 770 return visitNode(cbNode, node.expression) || 771 visitNode(cbNode, node.questionDotToken) || 772 visitNode(cbNode, node.argumentExpression); 773 }, 774 [SyntaxKind.CallExpression]: forEachChildInCallOrNewExpression, 775 [SyntaxKind.NewExpression]: forEachChildInCallOrNewExpression, 776 [SyntaxKind.TaggedTemplateExpression]: function forEachChildInTaggedTemplateExpression<T>(node: TaggedTemplateExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 777 return visitNode(cbNode, node.tag) || 778 visitNode(cbNode, node.questionDotToken) || 779 visitNodes(cbNode, cbNodes, node.typeArguments) || 780 visitNode(cbNode, node.template); 781 }, 782 [SyntaxKind.TypeAssertionExpression]: function forEachChildInTypeAssertionExpression<T>(node: TypeAssertion, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 783 return visitNode(cbNode, node.type) || 784 visitNode(cbNode, node.expression); 785 }, 786 [SyntaxKind.ParenthesizedExpression]: function forEachChildInParenthesizedExpression<T>(node: ParenthesizedExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 787 return visitNode(cbNode, node.expression); 788 }, 789 [SyntaxKind.DeleteExpression]: function forEachChildInDeleteExpression<T>(node: DeleteExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 790 return visitNode(cbNode, node.expression); 791 }, 792 [SyntaxKind.TypeOfExpression]: function forEachChildInTypeOfExpression<T>(node: TypeOfExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 793 return visitNode(cbNode, node.expression); 794 }, 795 [SyntaxKind.VoidExpression]: function forEachChildInVoidExpression<T>(node: VoidExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 796 return visitNode(cbNode, node.expression); 797 }, 798 [SyntaxKind.PrefixUnaryExpression]: function forEachChildInPrefixUnaryExpression<T>(node: PrefixUnaryExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 799 return visitNode(cbNode, node.operand); 800 }, 801 [SyntaxKind.YieldExpression]: function forEachChildInYieldExpression<T>(node: YieldExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 802 return visitNode(cbNode, node.asteriskToken) || 803 visitNode(cbNode, node.expression); 804 }, 805 [SyntaxKind.AwaitExpression]: function forEachChildInAwaitExpression<T>(node: AwaitExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 806 return visitNode(cbNode, node.expression); 807 }, 808 [SyntaxKind.PostfixUnaryExpression]: function forEachChildInPostfixUnaryExpression<T>(node: PostfixUnaryExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 809 return visitNode(cbNode, node.operand); 810 }, 811 [SyntaxKind.BinaryExpression]: function forEachChildInBinaryExpression<T>(node: BinaryExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 812 return visitNode(cbNode, node.left) || 813 visitNode(cbNode, node.operatorToken) || 814 visitNode(cbNode, node.right); 815 }, 816 [SyntaxKind.AsExpression]: function forEachChildInAsExpression<T>(node: AsExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 817 return visitNode(cbNode, node.expression) || 818 visitNode(cbNode, node.type); 819 }, 820 [SyntaxKind.NonNullExpression]: function forEachChildInNonNullExpression<T>(node: NonNullExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 821 return visitNode(cbNode, node.expression); 822 }, 823 [SyntaxKind.SatisfiesExpression]: function forEachChildInSatisfiesExpression<T>(node: SatisfiesExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 824 return visitNode(cbNode, node.expression) || visitNode(cbNode, node.type); 825 }, 826 [SyntaxKind.MetaProperty]: function forEachChildInMetaProperty<T>(node: MetaProperty, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 827 return visitNode(cbNode, node.name); 828 }, 829 [SyntaxKind.ConditionalExpression]: function forEachChildInConditionalExpression<T>(node: ConditionalExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 830 return visitNode(cbNode, node.condition) || 831 visitNode(cbNode, node.questionToken) || 832 visitNode(cbNode, node.whenTrue) || 833 visitNode(cbNode, node.colonToken) || 834 visitNode(cbNode, node.whenFalse); 835 }, 836 [SyntaxKind.SpreadElement]: function forEachChildInSpreadElement<T>(node: SpreadElement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 837 return visitNode(cbNode, node.expression); 838 }, 839 [SyntaxKind.Block]: forEachChildInBlock, 840 [SyntaxKind.ModuleBlock]: forEachChildInBlock, 841 [SyntaxKind.SourceFile]: function forEachChildInSourceFile<T>(node: SourceFile, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 842 return visitNodes(cbNode, cbNodes, node.statements) || 843 visitNode(cbNode, node.endOfFileToken); 844 }, 845 [SyntaxKind.VariableStatement]: function forEachChildInVariableStatement<T>(node: VariableStatement, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 846 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 847 visitNodes(cbNode, cbNodes, node.modifiers) || 848 visitNode(cbNode, node.declarationList); 849 }, 850 [SyntaxKind.VariableDeclarationList]: function forEachChildInVariableDeclarationList<T>(node: VariableDeclarationList, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 851 return visitNodes(cbNode, cbNodes, node.declarations); 852 }, 853 [SyntaxKind.ExpressionStatement]: function forEachChildInExpressionStatement<T>(node: ExpressionStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 854 return visitNode(cbNode, node.expression); 855 }, 856 [SyntaxKind.IfStatement]: function forEachChildInIfStatement<T>(node: IfStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 857 return visitNode(cbNode, node.expression) || 858 visitNode(cbNode, node.thenStatement) || 859 visitNode(cbNode, node.elseStatement); 860 }, 861 [SyntaxKind.DoStatement]: function forEachChildInDoStatement<T>(node: DoStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 862 return visitNode(cbNode, node.statement) || 863 visitNode(cbNode, node.expression); 864 }, 865 [SyntaxKind.WhileStatement]: function forEachChildInWhileStatement<T>(node: WhileStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 866 return visitNode(cbNode, node.expression) || 867 visitNode(cbNode, node.statement); 868 }, 869 [SyntaxKind.ForStatement]: function forEachChildInForStatement<T>(node: ForStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 870 return visitNode(cbNode, node.initializer) || 871 visitNode(cbNode, node.condition) || 872 visitNode(cbNode, node.incrementor) || 873 visitNode(cbNode, node.statement); 874 }, 875 [SyntaxKind.ForInStatement]: function forEachChildInForInStatement<T>(node: ForInStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 876 return visitNode(cbNode, node.initializer) || 877 visitNode(cbNode, node.expression) || 878 visitNode(cbNode, node.statement); 879 }, 880 [SyntaxKind.ForOfStatement]: function forEachChildInForOfStatement<T>(node: ForOfStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 881 return visitNode(cbNode, node.awaitModifier) || 882 visitNode(cbNode, node.initializer) || 883 visitNode(cbNode, node.expression) || 884 visitNode(cbNode, node.statement); 885 }, 886 [SyntaxKind.ContinueStatement]: forEachChildInContinueOrBreakStatement, 887 [SyntaxKind.BreakStatement]: forEachChildInContinueOrBreakStatement, 888 [SyntaxKind.ReturnStatement]: function forEachChildInReturnStatement<T>(node: ReturnStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 889 return visitNode(cbNode, node.expression); 890 }, 891 [SyntaxKind.WithStatement]: function forEachChildInWithStatement<T>(node: WithStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 892 return visitNode(cbNode, node.expression) || 893 visitNode(cbNode, node.statement); 894 }, 895 [SyntaxKind.SwitchStatement]: function forEachChildInSwitchStatement<T>(node: SwitchStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 896 return visitNode(cbNode, node.expression) || 897 visitNode(cbNode, node.caseBlock); 898 }, 899 [SyntaxKind.CaseBlock]: function forEachChildInCaseBlock<T>(node: CaseBlock, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 900 return visitNodes(cbNode, cbNodes, node.clauses); 901 }, 902 [SyntaxKind.CaseClause]: function forEachChildInCaseClause<T>(node: CaseClause, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 903 return visitNode(cbNode, node.expression) || 904 visitNodes(cbNode, cbNodes, node.statements); 905 }, 906 [SyntaxKind.DefaultClause]: function forEachChildInDefaultClause<T>(node: DefaultClause, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 907 return visitNodes(cbNode, cbNodes, node.statements); 908 }, 909 [SyntaxKind.LabeledStatement]: function forEachChildInLabeledStatement<T>(node: LabeledStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 910 return visitNode(cbNode, node.label) || 911 visitNode(cbNode, node.statement); 912 }, 913 [SyntaxKind.ThrowStatement]: function forEachChildInThrowStatement<T>(node: ThrowStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 914 return visitNode(cbNode, node.expression); 915 }, 916 [SyntaxKind.TryStatement]: function forEachChildInTryStatement<T>(node: TryStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 917 return visitNode(cbNode, node.tryBlock) || 918 visitNode(cbNode, node.catchClause) || 919 visitNode(cbNode, node.finallyBlock); 920 }, 921 [SyntaxKind.CatchClause]: function forEachChildInCatchClause<T>(node: CatchClause, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 922 return visitNode(cbNode, node.variableDeclaration) || 923 visitNode(cbNode, node.block); 924 }, 925 [SyntaxKind.Decorator]: function forEachChildInDecorator<T>(node: Decorator, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 926 return visitNode(cbNode, node.expression); 927 }, 928 [SyntaxKind.ClassDeclaration]: forEachChildInClassDeclarationOrExpression, 929 [SyntaxKind.ClassExpression]: forEachChildInClassDeclarationOrExpression, 930 [SyntaxKind.StructDeclaration]: forEachChildInClassDeclarationOrExpression, 931 [SyntaxKind.AnnotationDeclaration]: forEachChildInAnnotationDeclaration, 932 [SyntaxKind.InterfaceDeclaration]: function forEachChildInInterfaceDeclaration<T>(node: InterfaceDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 933 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 934 visitNodes(cbNode, cbNodes, node.modifiers) || 935 visitNode(cbNode, node.name) || 936 visitNodes(cbNode, cbNodes, node.typeParameters) || 937 visitNodes(cbNode, cbNodes, node.heritageClauses) || 938 visitNodes(cbNode, cbNodes, node.members); 939 }, 940 [SyntaxKind.TypeAliasDeclaration]: function forEachChildInTypeAliasDeclaration<T>(node: TypeAliasDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 941 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 942 visitNodes(cbNode, cbNodes, node.modifiers) || 943 visitNode(cbNode, node.name) || 944 visitNodes(cbNode, cbNodes, node.typeParameters) || 945 visitNode(cbNode, node.type); 946 }, 947 [SyntaxKind.EnumDeclaration]: function forEachChildInEnumDeclaration<T>(node: EnumDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 948 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 949 visitNodes(cbNode, cbNodes, node.modifiers) || 950 visitNode(cbNode, node.name) || 951 visitNodes(cbNode, cbNodes, node.members); 952 }, 953 [SyntaxKind.EnumMember]: function forEachChildInEnumMember<T>(node: EnumMember, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 954 return visitNode(cbNode, node.name) || 955 visitNode(cbNode, node.initializer); 956 }, 957 [SyntaxKind.ModuleDeclaration]: function forEachChildInModuleDeclaration<T>(node: ModuleDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 958 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 959 visitNodes(cbNode, cbNodes, node.modifiers) || 960 visitNode(cbNode, node.name) || 961 visitNode(cbNode, node.body); 962 }, 963 [SyntaxKind.ImportEqualsDeclaration]: function forEachChildInImportEqualsDeclaration<T>(node: ImportEqualsDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 964 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 965 visitNodes(cbNode, cbNodes, node.modifiers) || 966 visitNode(cbNode, node.name) || 967 visitNode(cbNode, node.moduleReference); 968 }, 969 [SyntaxKind.ImportDeclaration]: function forEachChildInImportDeclaration<T>(node: ImportDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 970 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 971 visitNodes(cbNode, cbNodes, node.modifiers) || 972 visitNode(cbNode, node.importClause) || 973 visitNode(cbNode, node.moduleSpecifier) || 974 visitNode(cbNode, node.assertClause); 975 }, 976 [SyntaxKind.ImportClause]: function forEachChildInImportClause<T>(node: ImportClause, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 977 return visitNode(cbNode, node.name) || 978 visitNode(cbNode, node.namedBindings); 979 }, 980 [SyntaxKind.AssertClause]: function forEachChildInAssertClause<T>(node: AssertClause, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 981 return visitNodes(cbNode, cbNodes, node.elements); 982 }, 983 [SyntaxKind.AssertEntry]: function forEachChildInAssertEntry<T>(node: AssertEntry, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 984 return visitNode(cbNode, node.name) || 985 visitNode(cbNode, node.value); 986 }, 987 [SyntaxKind.NamespaceExportDeclaration]: function forEachChildInNamespaceExportDeclaration<T>(node: NamespaceExportDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 988 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 989 visitNode(cbNode, node.name); 990 }, 991 [SyntaxKind.NamespaceImport]: function forEachChildInNamespaceImport<T>(node: NamespaceImport, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 992 return visitNode(cbNode, node.name); 993 }, 994 [SyntaxKind.NamespaceExport]: function forEachChildInNamespaceExport<T>(node: NamespaceExport, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 995 return visitNode(cbNode, node.name); 996 }, 997 [SyntaxKind.NamedImports]: forEachChildInNamedImportsOrExports, 998 [SyntaxKind.NamedExports]: forEachChildInNamedImportsOrExports, 999 [SyntaxKind.ExportDeclaration]: function forEachChildInExportDeclaration<T>(node: ExportDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1000 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 1001 visitNodes(cbNode, cbNodes, node.modifiers) || 1002 visitNode(cbNode, node.exportClause) || 1003 visitNode(cbNode, node.moduleSpecifier) || 1004 visitNode(cbNode, node.assertClause); 1005 }, 1006 [SyntaxKind.ImportSpecifier]: forEachChildInImportOrExportSpecifier, 1007 [SyntaxKind.ExportSpecifier]: forEachChildInImportOrExportSpecifier, 1008 [SyntaxKind.ExportAssignment]: function forEachChildInExportAssignment<T>(node: ExportAssignment, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1009 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 1010 visitNodes(cbNode, cbNodes, node.modifiers) || 1011 visitNode(cbNode, node.expression); 1012 }, 1013 [SyntaxKind.TemplateExpression]: function forEachChildInTemplateExpression<T>(node: TemplateExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1014 return visitNode(cbNode, node.head) || 1015 visitNodes(cbNode, cbNodes, node.templateSpans); 1016 }, 1017 [SyntaxKind.TemplateSpan]: function forEachChildInTemplateSpan<T>(node: TemplateSpan, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1018 return visitNode(cbNode, node.expression) || 1019 visitNode(cbNode, node.literal); 1020 }, 1021 [SyntaxKind.TemplateLiteralType]: function forEachChildInTemplateLiteralType<T>(node: TemplateLiteralTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1022 return visitNode(cbNode, node.head) || 1023 visitNodes(cbNode, cbNodes, node.templateSpans); 1024 }, 1025 [SyntaxKind.TemplateLiteralTypeSpan]: function forEachChildInTemplateLiteralTypeSpan<T>(node: TemplateLiteralTypeSpan, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1026 return visitNode(cbNode, node.type) || 1027 visitNode(cbNode, node.literal); 1028 }, 1029 [SyntaxKind.ComputedPropertyName]: function forEachChildInComputedPropertyName<T>(node: ComputedPropertyName, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1030 return visitNode(cbNode, node.expression); 1031 }, 1032 [SyntaxKind.HeritageClause]: function forEachChildInHeritageClause<T>(node: HeritageClause, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1033 return visitNodes(cbNode, cbNodes, node.types); 1034 }, 1035 [SyntaxKind.ExpressionWithTypeArguments]: function forEachChildInExpressionWithTypeArguments<T>(node: ExpressionWithTypeArguments, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1036 return visitNode(cbNode, node.expression) || 1037 visitNodes(cbNode, cbNodes, node.typeArguments); 1038 }, 1039 [SyntaxKind.ExternalModuleReference]: function forEachChildInExternalModuleReference<T>(node: ExternalModuleReference, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1040 return visitNode(cbNode, node.expression); 1041 }, 1042 [SyntaxKind.MissingDeclaration]: function forEachChildInMissingDeclaration<T>(node: MissingDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1043 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 1044 visitNodes(cbNode, cbNodes, node.modifiers); 1045 }, 1046 [SyntaxKind.CommaListExpression]: function forEachChildInCommaListExpression<T>(node: CommaListExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1047 return visitNodes(cbNode, cbNodes, node.elements); 1048 }, 1049 [SyntaxKind.JsxElement]: function forEachChildInJsxElement<T>(node: JsxElement, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1050 return visitNode(cbNode, node.openingElement) || 1051 visitNodes(cbNode, cbNodes, node.children) || 1052 visitNode(cbNode, node.closingElement); 1053 }, 1054 [SyntaxKind.JsxFragment]: function forEachChildInJsxFragment<T>(node: JsxFragment, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1055 return visitNode(cbNode, node.openingFragment) || 1056 visitNodes(cbNode, cbNodes, node.children) || 1057 visitNode(cbNode, node.closingFragment); 1058 }, 1059 [SyntaxKind.JsxSelfClosingElement]: forEachChildInJsxOpeningOrSelfClosingElement, 1060 [SyntaxKind.JsxOpeningElement]: forEachChildInJsxOpeningOrSelfClosingElement, 1061 [SyntaxKind.JsxAttributes]: function forEachChildInJsxAttributes<T>(node: JsxAttributes, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1062 return visitNodes(cbNode, cbNodes, node.properties); 1063 }, 1064 [SyntaxKind.JsxAttribute]: function forEachChildInJsxAttribute<T>(node: JsxAttribute, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1065 return visitNode(cbNode, node.name) || 1066 visitNode(cbNode, node.initializer); 1067 }, 1068 [SyntaxKind.JsxSpreadAttribute]: function forEachChildInJsxSpreadAttribute<T>(node: JsxSpreadAttribute, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1069 return visitNode(cbNode, node.expression); 1070 }, 1071 [SyntaxKind.JsxExpression]: function forEachChildInJsxExpression<T>(node: JsxExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1072 return visitNode(cbNode, node.dotDotDotToken) || 1073 visitNode(cbNode, node.expression); 1074 }, 1075 [SyntaxKind.JsxClosingElement]: function forEachChildInJsxClosingElement<T>(node: JsxClosingElement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1076 return visitNode(cbNode, node.tagName); 1077 }, 1078 [SyntaxKind.OptionalType]: forEachChildInOptionalRestOrJSDocParameterModifier, 1079 [SyntaxKind.RestType]: forEachChildInOptionalRestOrJSDocParameterModifier, 1080 [SyntaxKind.JSDocTypeExpression]: forEachChildInOptionalRestOrJSDocParameterModifier, 1081 [SyntaxKind.JSDocNonNullableType]: forEachChildInOptionalRestOrJSDocParameterModifier, 1082 [SyntaxKind.JSDocNullableType]: forEachChildInOptionalRestOrJSDocParameterModifier, 1083 [SyntaxKind.JSDocOptionalType]: forEachChildInOptionalRestOrJSDocParameterModifier, 1084 [SyntaxKind.JSDocVariadicType]: forEachChildInOptionalRestOrJSDocParameterModifier, 1085 [SyntaxKind.JSDocFunctionType]: function forEachChildInJSDocFunctionType<T>(node: JSDocFunctionType, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1086 return visitNodes(cbNode, cbNodes, node.parameters) || 1087 visitNode(cbNode, node.type); 1088 }, 1089 [SyntaxKind.JSDoc]: function forEachChildInJSDoc<T>(node: JSDoc, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1090 return (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)) 1091 || visitNodes(cbNode, cbNodes, node.tags); 1092 }, 1093 [SyntaxKind.JSDocSeeTag]: function forEachChildInJSDocSeeTag<T>(node: JSDocSeeTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1094 return visitNode(cbNode, node.tagName) || 1095 visitNode(cbNode, node.name) || 1096 (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); 1097 }, 1098 [SyntaxKind.JSDocNameReference]: function forEachChildInJSDocNameReference<T>(node: JSDocNameReference, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1099 return visitNode(cbNode, node.name); 1100 }, 1101 [SyntaxKind.JSDocMemberName]: function forEachChildInJSDocMemberName<T>(node: JSDocMemberName, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1102 return visitNode(cbNode, node.left) || 1103 visitNode(cbNode, node.right); 1104 }, 1105 [SyntaxKind.JSDocParameterTag]: forEachChildInJSDocParameterOrPropertyTag, 1106 [SyntaxKind.JSDocPropertyTag]: forEachChildInJSDocParameterOrPropertyTag, 1107 [SyntaxKind.JSDocAuthorTag]: function forEachChildInJSDocAuthorTag<T>(node: JSDocAuthorTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1108 return visitNode(cbNode, node.tagName) || 1109 (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); 1110 }, 1111 [SyntaxKind.JSDocImplementsTag]: function forEachChildInJSDocImplementsTag<T>(node: JSDocImplementsTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1112 return visitNode(cbNode, node.tagName) || 1113 visitNode(cbNode, node.class) || 1114 (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); 1115 }, 1116 [SyntaxKind.JSDocAugmentsTag]: function forEachChildInJSDocAugmentsTag<T>(node: JSDocAugmentsTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1117 return visitNode(cbNode, node.tagName) || 1118 visitNode(cbNode, node.class) || 1119 (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); 1120 }, 1121 [SyntaxKind.JSDocTemplateTag]: function forEachChildInJSDocTemplateTag<T>(node: JSDocTemplateTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1122 return visitNode(cbNode, node.tagName) || 1123 visitNode(cbNode, node.constraint) || 1124 visitNodes(cbNode, cbNodes, node.typeParameters) || 1125 (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); 1126 }, 1127 [SyntaxKind.JSDocTypedefTag]: function forEachChildInJSDocTypedefTag<T>(node: JSDocTypedefTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1128 return visitNode(cbNode, node.tagName) || 1129 (node.typeExpression && 1130 node.typeExpression.kind === SyntaxKind.JSDocTypeExpression 1131 ? visitNode(cbNode, node.typeExpression) || 1132 visitNode(cbNode, node.fullName) || 1133 (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)) 1134 : visitNode(cbNode, node.fullName) || 1135 visitNode(cbNode, node.typeExpression) || 1136 (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment))); 1137 }, 1138 [SyntaxKind.JSDocCallbackTag]: function forEachChildInJSDocCallbackTag<T>(node: JSDocCallbackTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1139 return visitNode(cbNode, node.tagName) || 1140 visitNode(cbNode, node.fullName) || 1141 visitNode(cbNode, node.typeExpression) || 1142 (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); 1143 }, 1144 [SyntaxKind.JSDocReturnTag]: forEachChildInJSDocReturnTag, 1145 [SyntaxKind.JSDocTypeTag]: forEachChildInJSDocReturnTag, 1146 [SyntaxKind.JSDocThisTag]: forEachChildInJSDocReturnTag, 1147 [SyntaxKind.JSDocEnumTag]: forEachChildInJSDocReturnTag, 1148 [SyntaxKind.JSDocSignature]: function forEachChildInJSDocSignature<T>(node: JSDocSignature, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1149 return forEach(node.typeParameters, cbNode) || 1150 forEach(node.parameters, cbNode) || 1151 visitNode(cbNode, node.type); 1152 }, 1153 [SyntaxKind.JSDocLink]: forEachChildInJSDocLinkCodeOrPlain, 1154 [SyntaxKind.JSDocLinkCode]: forEachChildInJSDocLinkCodeOrPlain, 1155 [SyntaxKind.JSDocLinkPlain]: forEachChildInJSDocLinkCodeOrPlain, 1156 [SyntaxKind.JSDocTypeLiteral]: function forEachChildInJSDocTypeLiteral<T>(node: JSDocTypeLiteral, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1157 return forEach(node.jsDocPropertyTags, cbNode); 1158 }, 1159 [SyntaxKind.JSDocTag]: forEachChildInJSDocTag, 1160 [SyntaxKind.JSDocClassTag]: forEachChildInJSDocTag, 1161 [SyntaxKind.JSDocPublicTag]: forEachChildInJSDocTag, 1162 [SyntaxKind.JSDocPrivateTag]: forEachChildInJSDocTag, 1163 [SyntaxKind.JSDocProtectedTag]: forEachChildInJSDocTag, 1164 [SyntaxKind.JSDocReadonlyTag]: forEachChildInJSDocTag, 1165 [SyntaxKind.JSDocDeprecatedTag]: forEachChildInJSDocTag, 1166 [SyntaxKind.JSDocOverrideTag]: forEachChildInJSDocTag, 1167 [SyntaxKind.PartiallyEmittedExpression]: forEachChildInPartiallyEmittedExpression, 1168}; 1169 1170// shared 1171 1172function forEachChildInCallOrConstructSignature<T>(node: CallSignatureDeclaration | ConstructSignatureDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1173 return visitNodes(cbNode, cbNodes, node.typeParameters) || 1174 visitNodes(cbNode, cbNodes, node.parameters) || 1175 visitNode(cbNode, node.type); 1176} 1177 1178function forEachChildInUnionOrIntersectionType<T>(node: UnionTypeNode | IntersectionTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1179 return visitNodes(cbNode, cbNodes, node.types); 1180} 1181 1182function forEachChildInParenthesizedTypeOrTypeOperator<T>(node: ParenthesizedTypeNode | TypeOperatorNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1183 return visitNode(cbNode, node.type); 1184} 1185 1186function forEachChildInObjectOrArrayBindingPattern<T>(node: BindingPattern, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1187 return visitNodes(cbNode, cbNodes, node.elements); 1188} 1189 1190function forEachChildInCallOrNewExpression<T>(node: CallExpression | NewExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1191 return visitNode(cbNode, node.expression) || 1192 // TODO: should we separate these branches out? 1193 visitNode(cbNode, (node as CallExpression).questionDotToken) || 1194 visitNodes(cbNode, cbNodes, node.typeArguments) || 1195 visitNodes(cbNode, cbNodes, node.arguments); 1196} 1197 1198function forEachChildInBlock<T>(node: Block | ModuleBlock, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1199 return visitNodes(cbNode, cbNodes, node.statements); 1200} 1201 1202function forEachChildInContinueOrBreakStatement<T>(node: ContinueStatement | BreakStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1203 return visitNode(cbNode, node.label); 1204} 1205 1206function forEachChildInClassDeclarationOrExpression<T>(node: ClassDeclaration | ClassExpression | StructDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1207 return visitNodes(cbNode, cbNodes, node.modifiers) || 1208 visitNode(cbNode, node.name) || 1209 visitNodes(cbNode, cbNodes, node.typeParameters) || 1210 visitNodes(cbNode, cbNodes, node.heritageClauses) || 1211 visitNodes(cbNode, cbNodes, node.members); 1212} 1213 1214function forEachChildInAnnotationDeclaration<T>(node: AnnotationDeclaration, cbNode: (node: Node) => T | undefined, 1215 cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1216 return visitNodes(cbNode, cbNodes, node.modifiers) || 1217 visitNode(cbNode, node.name) || 1218 visitNodes(cbNode, cbNodes, node.members); 1219} 1220 1221function forEachChildInNamedImportsOrExports<T>(node: NamedImports | NamedExports, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1222 return visitNodes(cbNode, cbNodes, node.elements); 1223} 1224 1225function forEachChildInImportOrExportSpecifier<T>(node: ImportSpecifier | ExportSpecifier, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1226 return visitNode(cbNode, node.propertyName) || 1227 visitNode(cbNode, node.name); 1228} 1229 1230function forEachChildInJsxOpeningOrSelfClosingElement<T>(node: JsxOpeningLikeElement, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1231 return visitNode(cbNode, node.tagName) || 1232 visitNodes(cbNode, cbNodes, node.typeArguments) || 1233 visitNode(cbNode, node.attributes); 1234} 1235 1236function forEachChildInOptionalRestOrJSDocParameterModifier<T>(node: OptionalTypeNode | RestTypeNode | JSDocTypeExpression | JSDocNullableType | JSDocNonNullableType | JSDocOptionalType | JSDocVariadicType, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1237 return visitNode(cbNode, node.type); 1238} 1239 1240function forEachChildInJSDocParameterOrPropertyTag<T>(node: JSDocParameterTag | JSDocPropertyTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1241 return visitNode(cbNode, node.tagName) || 1242 (node.isNameFirst 1243 ? visitNode(cbNode, node.name) || visitNode(cbNode, node.typeExpression) 1244 : visitNode(cbNode, node.typeExpression) || visitNode(cbNode, node.name)) || 1245 (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); 1246} 1247 1248function forEachChildInJSDocReturnTag<T>(node: JSDocReturnTag | JSDocTypeTag | JSDocThisTag | JSDocEnumTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1249 return visitNode(cbNode, node.tagName) || 1250 visitNode(cbNode, node.typeExpression) || 1251 (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); 1252} 1253 1254function forEachChildInJSDocLinkCodeOrPlain<T>(node: JSDocLink | JSDocLinkCode | JSDocLinkPlain, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1255 return visitNode(cbNode, node.name); 1256} 1257 1258function forEachChildInJSDocTag<T>(node: JSDocUnknownTag | JSDocClassTag | JSDocPublicTag | JSDocPrivateTag | JSDocProtectedTag | JSDocReadonlyTag | JSDocDeprecatedTag | JSDocOverrideTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1259 return visitNode(cbNode, node.tagName) 1260 || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); 1261} 1262 1263function forEachChildInPartiallyEmittedExpression<T>(node: PartiallyEmittedExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1264 return visitNode(cbNode, node.expression); 1265} 1266 1267/** 1268 * Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes 1269 * stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; otherwise, 1270 * embedded arrays are flattened and the 'cbNode' callback is invoked for each element. If a callback returns 1271 * a truthy value, iteration stops and that value is returned. Otherwise, undefined is returned. 1272 * 1273 * @param node a given node to visit its children 1274 * @param cbNode a callback to be invoked for all child nodes 1275 * @param cbNodes a callback to be invoked for embedded array 1276 * 1277 * @remarks `forEachChild` must visit the children of a node in the order 1278 * that they appear in the source code. The language service depends on this property to locate nodes by position. 1279 */ 1280export function forEachChild<T>(node: Node, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 1281 if (node === undefined || node.kind <= SyntaxKind.LastToken) { 1282 return; 1283 } 1284 const fn = (forEachChildTable as Record<SyntaxKind, ForEachChildFunction<any>>)[node.kind]; 1285 return fn === undefined ? undefined : fn(node, cbNode, cbNodes); 1286} 1287 1288/** 1289 * Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes 1290 * stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; additionally, 1291 * unlike `forEachChild`, embedded arrays are flattened and the 'cbNode' callback is invoked for each element. 1292 * If a callback returns a truthy value, iteration stops and that value is returned. Otherwise, undefined is returned. 1293 * 1294 * @param node a given node to visit its children 1295 * @param cbNode a callback to be invoked for all child nodes 1296 * @param cbNodes a callback to be invoked for embedded array 1297 * 1298 * @remarks Unlike `forEachChild`, `forEachChildRecursively` handles recursively invoking the traversal on each child node found, 1299 * and while doing so, handles traversing the structure without relying on the callstack to encode the tree structure. 1300 * @internal 1301 */ 1302export function forEachChildRecursively<T>(rootNode: Node, cbNode: (node: Node, parent: Node) => T | "skip" | undefined, cbNodes?: (nodes: NodeArray<Node>, parent: Node) => T | "skip" | undefined): T | undefined { 1303 const queue: (Node | NodeArray<Node>)[] = gatherPossibleChildren(rootNode); 1304 const parents: Node[] = []; // tracks parent references for elements in queue 1305 while (parents.length < queue.length) { 1306 parents.push(rootNode); 1307 } 1308 while (queue.length !== 0) { 1309 const current = queue.pop()!; 1310 const parent = parents.pop()!; 1311 if (isArray(current)) { 1312 if (cbNodes) { 1313 const res = cbNodes(current, parent); 1314 if (res) { 1315 if (res === "skip") continue; 1316 return res; 1317 } 1318 } 1319 for (let i = current.length - 1; i >= 0; --i) { 1320 queue.push(current[i]); 1321 parents.push(parent); 1322 } 1323 } 1324 else { 1325 const res = cbNode(current, parent); 1326 if (res) { 1327 if (res === "skip") continue; 1328 return res; 1329 } 1330 if (current.kind >= SyntaxKind.FirstNode) { 1331 // add children in reverse order to the queue, so popping gives the first child 1332 for (const child of gatherPossibleChildren(current)) { 1333 queue.push(child); 1334 parents.push(current); 1335 } 1336 } 1337 } 1338 } 1339} 1340 1341function gatherPossibleChildren(node: Node) { 1342 const children: (Node | NodeArray<Node>)[] = []; 1343 forEachChild(node, addWorkItem, addWorkItem); // By using a stack above and `unshift` here, we emulate a depth-first preorder traversal 1344 return children; 1345 1346 function addWorkItem(n: Node | NodeArray<Node>) { 1347 children.unshift(n); 1348 } 1349} 1350 1351export interface CreateSourceFileOptions { 1352 languageVersion: ScriptTarget; 1353 /** 1354 * Controls the format the file is detected as - this can be derived from only the path 1355 * and files on disk, but needs to be done with a module resolution cache in scope to be performant. 1356 * This is usually `undefined` for compilations that do not have `moduleResolution` values of `node16` or `nodenext`. 1357 */ 1358 impliedNodeFormat?: ModuleKind.ESNext | ModuleKind.CommonJS; 1359 /** 1360 * Controls how module-y-ness is set for the given file. Usually the result of calling 1361 * `getSetExternalModuleIndicator` on a valid `CompilerOptions` object. If not present, the default 1362 * check specified by `isFileProbablyExternalModule` will be used to set the field. 1363 */ 1364 setExternalModuleIndicator?: (file: SourceFile) => void; 1365 /** @internal */ packageJsonLocations?: readonly string[]; 1366 /** @internal */ packageJsonScope?: PackageJsonInfo; 1367} 1368 1369function setExternalModuleIndicator(sourceFile: SourceFile) { 1370 sourceFile.externalModuleIndicator = isFileProbablyExternalModule(sourceFile); 1371} 1372 1373let sourceFileCompilerOptions: CompilerOptions; 1374let isArkguardInputSourceFile: boolean = false; 1375export function createSourceFile(fileName: string, sourceText: string, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, setParentNodes = false, scriptKind?: ScriptKind, options?: CompilerOptions, isArkguardInput?: boolean): SourceFile { 1376 tracing?.push(tracing.Phase.Parse, "createSourceFile", { path: fileName }, /*separateBeginAndEnd*/ true); 1377 const recordInfo = MemoryDotting.recordStage(MemoryDotting.CREATE_SORUCE_FILE_PARSE); 1378 performance.mark("beforeParse"); 1379 let result: SourceFile; 1380 sourceFileCompilerOptions = options ?? defaultInitCompilerOptions; 1381 isArkguardInputSourceFile = isArkguardInput ?? false; 1382 perfLogger.logStartParseSourceFile(fileName); 1383 const { 1384 languageVersion, 1385 setExternalModuleIndicator: overrideSetExternalModuleIndicator, 1386 impliedNodeFormat: format 1387 } = typeof languageVersionOrOptions === "object" ? languageVersionOrOptions : ({ languageVersion: languageVersionOrOptions } as CreateSourceFileOptions); 1388 if (languageVersion === ScriptTarget.JSON) { 1389 result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, ScriptKind.JSON, noop); 1390 } 1391 else { 1392 const setIndicator = format === undefined ? overrideSetExternalModuleIndicator : (file: SourceFile) => { 1393 file.impliedNodeFormat = format; 1394 return (overrideSetExternalModuleIndicator || setExternalModuleIndicator)(file); 1395 }; 1396 result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, scriptKind, setIndicator); 1397 } 1398 perfLogger.logStopParseSourceFile(); 1399 1400 performance.mark("afterParse"); 1401 MemoryDotting.stopRecordStage(recordInfo); 1402 performance.measure("Parse", "beforeParse", "afterParse"); 1403 tracing?.pop(); 1404 return result; 1405} 1406 1407export function parseIsolatedEntityName(text: string, languageVersion: ScriptTarget): EntityName | undefined { 1408 return Parser.parseIsolatedEntityName(text, languageVersion); 1409} 1410 1411/** 1412 * Parse json text into SyntaxTree and return node and parse errors if any 1413 * @param fileName 1414 * @param sourceText 1415 */ 1416export function parseJsonText(fileName: string, sourceText: string): JsonSourceFile { 1417 return Parser.parseJsonText(fileName, sourceText); 1418} 1419 1420// See also `isExternalOrCommonJsModule` in utilities.ts 1421export function isExternalModule(file: SourceFile): boolean { 1422 return file.externalModuleIndicator !== undefined; 1423} 1424 1425// Produces a new SourceFile for the 'newText' provided. The 'textChangeRange' parameter 1426// indicates what changed between the 'text' that this SourceFile has and the 'newText'. 1427// The SourceFile will be created with the compiler attempting to reuse as many nodes from 1428// this file as possible. 1429// 1430// Note: this function mutates nodes from this SourceFile. That means any existing nodes 1431// from this SourceFile that are being held onto may change as a result (including 1432// becoming detached from any SourceFile). It is recommended that this SourceFile not 1433// be used once 'update' is called on it. 1434export function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks = false, option?: CompilerOptions): SourceFile { 1435 sourceFileCompilerOptions = option ?? defaultInitCompilerOptions; 1436 const newSourceFile = IncrementalParser.updateSourceFile(sourceFile, newText, textChangeRange, aggressiveChecks); 1437 // 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. 1438 // We will manually port the flag to the new source file. 1439 (newSourceFile as Mutable<SourceFile>).flags |= (sourceFile.flags & NodeFlags.PermanentlySetIncrementalFlags); 1440 return newSourceFile; 1441} 1442 1443/** @internal */ 1444export function parseIsolatedJSDocComment(content: string, start?: number, length?: number) { 1445 const result = Parser.JSDocParser.parseIsolatedJSDocComment(content, start, length); 1446 if (result && result.jsDoc) { 1447 // because the jsDocComment was parsed out of the source file, it might 1448 // not be covered by the fixupParentReferences. 1449 Parser.fixupParentReferences(result.jsDoc); 1450 } 1451 1452 return result; 1453} 1454 1455/** @internal */ 1456// Exposed only for testing. 1457export function parseJSDocTypeExpressionForTests(content: string, start?: number, length?: number) { 1458 return Parser.JSDocParser.parseJSDocTypeExpressionForTests(content, start, length); 1459} 1460 1461// Set language version: ArkTS 1.1、1.2 1462let languageVersionCallBack: ((filePath: string) => boolean) | undefined; 1463export function setLanguageVersionByFilePath(getLanguageVersion: ((filePath: string) => boolean) | undefined): void { 1464 languageVersionCallBack = getLanguageVersion; 1465} 1466 1467// Implement the parser as a singleton module. We do this for perf reasons because creating 1468// parser instances can actually be expensive enough to impact us on projects with many source 1469// files. 1470namespace Parser { 1471 /* eslint-disable no-var */ 1472 1473 // Share a single scanner across all calls to parse a source file. This helps speed things 1474 // up by avoiding the cost of creating/compiling scanners over and over again. 1475 var scanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ true); 1476 1477 var disallowInAndDecoratorContext = NodeFlags.DisallowInContext | NodeFlags.DecoratorContext; 1478 1479 // capture constructors in 'initializeState' to avoid null checks 1480 var NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; 1481 var TokenConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; 1482 var IdentifierConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; 1483 var PrivateIdentifierConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; 1484 var SourceFileConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; 1485 1486 function countNode(node: Node) { 1487 nodeCount++; 1488 return node; 1489 } 1490 1491 // Rather than using `createBaseNodeFactory` here, we establish a `BaseNodeFactory` that closes over the 1492 // constructors above, which are reset each time `initializeState` is called. 1493 var baseNodeFactory: BaseNodeFactory = { 1494 createBaseSourceFileNode: kind => countNode(new SourceFileConstructor(kind, /*pos*/ 0, /*end*/ 0)), 1495 createBaseIdentifierNode: kind => countNode(new IdentifierConstructor(kind, /*pos*/ 0, /*end*/ 0)), 1496 createBasePrivateIdentifierNode: kind => countNode(new PrivateIdentifierConstructor(kind, /*pos*/ 0, /*end*/ 0)), 1497 createBaseTokenNode: kind => countNode(new TokenConstructor(kind, /*pos*/ 0, /*end*/ 0)), 1498 createBaseNode: kind => countNode(new NodeConstructor(kind, /*pos*/ 0, /*end*/ 0)) 1499 }; 1500 1501 var factory = createNodeFactory(NodeFactoryFlags.NoParenthesizerRules | NodeFactoryFlags.NoNodeConverters | NodeFactoryFlags.NoOriginalNode, baseNodeFactory); 1502 1503 var fileName: string; 1504 var sourceFlags: NodeFlags; 1505 var sourceText: string; 1506 var languageVersion: ScriptTarget; 1507 var scriptKind: ScriptKind; 1508 var languageVariant: LanguageVariant; 1509 var parseDiagnostics: DiagnosticWithDetachedLocation[]; 1510 var jsDocDiagnostics: DiagnosticWithDetachedLocation[]; 1511 var syntaxCursor: IncrementalParser.SyntaxCursor | undefined; 1512 1513 var currentToken: SyntaxKind; 1514 var nodeCount: number; 1515 var identifiers: ESMap<string, string>; 1516 var privateIdentifiers: ESMap<string, string>; 1517 var identifierCount: number; 1518 1519 var parsingContext: ParsingContext; 1520 1521 var notParenthesizedArrow: Set<number> | undefined; 1522 1523 // Flags that dictate what parsing context we're in. For example: 1524 // Whether or not we are in strict parsing mode. All that changes in strict parsing mode is 1525 // that some tokens that would be considered identifiers may be considered keywords. 1526 // 1527 // When adding more parser context flags, consider which is the more common case that the 1528 // flag will be in. This should be the 'false' state for that flag. The reason for this is 1529 // that we don't store data in our nodes unless the value is in the *non-default* state. So, 1530 // for example, more often than code 'allows-in' (or doesn't 'disallow-in'). We opt for 1531 // 'disallow-in' set to 'false'. Otherwise, if we had 'allowsIn' set to 'true', then almost 1532 // all nodes would need extra state on them to store this info. 1533 // 1534 // Note: 'allowIn' and 'allowYield' track 1:1 with the [in] and [yield] concepts in the ES6 1535 // grammar specification. 1536 // 1537 // An important thing about these context concepts. By default they are effectively inherited 1538 // while parsing through every grammar production. i.e. if you don't change them, then when 1539 // you parse a sub-production, it will have the same context values as the parent production. 1540 // This is great most of the time. After all, consider all the 'expression' grammar productions 1541 // and how nearly all of them pass along the 'in' and 'yield' context values: 1542 // 1543 // EqualityExpression[In, Yield] : 1544 // RelationalExpression[?In, ?Yield] 1545 // EqualityExpression[?In, ?Yield] == RelationalExpression[?In, ?Yield] 1546 // EqualityExpression[?In, ?Yield] != RelationalExpression[?In, ?Yield] 1547 // EqualityExpression[?In, ?Yield] === RelationalExpression[?In, ?Yield] 1548 // EqualityExpression[?In, ?Yield] !== RelationalExpression[?In, ?Yield] 1549 // 1550 // Where you have to be careful is then understanding what the points are in the grammar 1551 // where the values are *not* passed along. For example: 1552 // 1553 // SingleNameBinding[Yield,GeneratorParameter] 1554 // [+GeneratorParameter]BindingIdentifier[Yield] Initializer[In]opt 1555 // [~GeneratorParameter]BindingIdentifier[?Yield]Initializer[In, ?Yield]opt 1556 // 1557 // Here this is saying that if the GeneratorParameter context flag is set, that we should 1558 // explicitly set the 'yield' context flag to false before calling into the BindingIdentifier 1559 // and we should explicitly unset the 'yield' context flag before calling into the Initializer. 1560 // production. Conversely, if the GeneratorParameter context flag is not set, then we 1561 // should leave the 'yield' context flag alone. 1562 // 1563 // Getting this all correct is tricky and requires careful reading of the grammar to 1564 // understand when these values should be changed versus when they should be inherited. 1565 // 1566 // Note: it should not be necessary to save/restore these flags during speculative/lookahead 1567 // parsing. These context flags are naturally stored and restored through normal recursive 1568 // descent parsing and unwinding. 1569 var contextFlags: NodeFlags; 1570 1571 var etsFlags: EtsFlags; 1572 1573 // Indicates whether we are currently parsing top-level statements. 1574 var topLevel = true; 1575 1576 // Whether or not we've had a parse error since creating the last AST node. If we have 1577 // encountered an error, it will be stored on the next AST node we create. Parse errors 1578 // can be broken down into three categories: 1579 // 1580 // 1) An error that occurred during scanning. For example, an unterminated literal, or a 1581 // character that was completely not understood. 1582 // 1583 // 2) A token was expected, but was not present. This type of error is commonly produced 1584 // by the 'parseExpected' function. 1585 // 1586 // 3) A token was present that no parsing function was able to consume. This type of error 1587 // only occurs in the 'abortParsingListOrMoveToNextToken' function when the parser 1588 // decides to skip the token. 1589 // 1590 // In all of these cases, we want to mark the next node as having had an error before it. 1591 // With this mark, we can know in incremental settings if this node can be reused, or if 1592 // we have to reparse it. If we don't keep this information around, we may just reuse the 1593 // node. in that event we would then not produce the same errors as we did before, causing 1594 // significant confusion problems. 1595 // 1596 // Note: it is necessary that this value be saved/restored during speculative/lookahead 1597 // parsing. During lookahead parsing, we will often create a node. That node will have 1598 // this value attached, and then this value will be set back to 'false'. If we decide to 1599 // rewind, we must get back to the same value we had prior to the lookahead. 1600 // 1601 // Note: any errors at the end of the file that do not precede a regular node, should get 1602 // attached to the EOF token. 1603 var parseErrorBeforeNextFinishedNode = false; 1604 1605 var extendEtsComponentDeclaration: { name: string, type: string, instance: string } | undefined; 1606 1607 var stylesEtsComponentDeclaration: { name: string, type: string, instance: string } | undefined; 1608 1609 // A map to record file scope '@styles' function name 1610 var fileStylesComponents = new Map<string, SyntaxKind>(); 1611 1612 var currentStructName: string | undefined; 1613 1614 var stateStylesRootNode: string | undefined; 1615 1616 // A map to record struct scope '@styles' method name 1617 var structStylesComponents = new Map<string, { structName: string, kind: SyntaxKind }>(); 1618 /* eslint-enable no-var */ 1619 1620 export function parseSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, syntaxCursor: IncrementalParser.SyntaxCursor | undefined, setParentNodes = false, scriptKind?: ScriptKind, setExternalModuleIndicatorOverride?: (file: SourceFile) => void): SourceFile { 1621 scriptKind = ensureScriptKind(fileName, scriptKind); 1622 if (scriptKind === ScriptKind.JSON) { 1623 const result = parseJsonText(fileName, sourceText, languageVersion, syntaxCursor, setParentNodes); 1624 convertToObjectWorker(result, result.statements[0]?.expression, result.parseDiagnostics, /*returnValue*/ false, /*knownRootOptions*/ undefined, /*jsonConversionNotifier*/ undefined); 1625 result.referencedFiles = emptyArray; 1626 result.typeReferenceDirectives = emptyArray; 1627 result.libReferenceDirectives = emptyArray; 1628 result.amdDependencies = emptyArray; 1629 result.hasNoDefaultLib = false; 1630 result.pragmas = emptyMap as ReadonlyPragmaMap; 1631 return result; 1632 } 1633 1634 initializeState(fileName, sourceText, languageVersion, syntaxCursor, scriptKind); 1635 1636 const result = parseSourceFileWorker(languageVersion, setParentNodes, scriptKind, setExternalModuleIndicatorOverride || setExternalModuleIndicator); 1637 1638 clearState(); 1639 1640 return result; 1641 } 1642 1643 export function parseIsolatedEntityName(content: string, languageVersion: ScriptTarget): EntityName | undefined { 1644 // Choice of `isDeclarationFile` should be arbitrary 1645 initializeState("", content, languageVersion, /*syntaxCursor*/ undefined, ScriptKind.JS); 1646 // Prime the scanner. 1647 nextToken(); 1648 const entityName = parseEntityName(/*allowReservedWords*/ true); 1649 const isInvalid = token() === SyntaxKind.EndOfFileToken && !parseDiagnostics.length; 1650 clearState(); 1651 return isInvalid ? entityName : undefined; 1652 } 1653 1654 export function parseJsonText(fileName: string, sourceText: string, languageVersion: ScriptTarget = ScriptTarget.ES2015, syntaxCursor?: IncrementalParser.SyntaxCursor, setParentNodes = false): JsonSourceFile { 1655 initializeState(fileName, sourceText, languageVersion, syntaxCursor, ScriptKind.JSON); 1656 sourceFlags = contextFlags; 1657 1658 // Prime the scanner. 1659 nextToken(); 1660 const pos = getNodePos(); 1661 let statements, endOfFileToken; 1662 if (token() === SyntaxKind.EndOfFileToken) { 1663 statements = createNodeArray([], pos, pos); 1664 endOfFileToken = parseTokenNode<EndOfFileToken>(); 1665 } 1666 else { 1667 // Loop and synthesize an ArrayLiteralExpression if there are more than 1668 // one top-level expressions to ensure all input text is consumed. 1669 let expressions: Expression[] | Expression | undefined; 1670 while (token() !== SyntaxKind.EndOfFileToken) { 1671 let expression; 1672 switch (token()) { 1673 case SyntaxKind.OpenBracketToken: 1674 expression = parseArrayLiteralExpression(); 1675 break; 1676 case SyntaxKind.TrueKeyword: 1677 case SyntaxKind.FalseKeyword: 1678 case SyntaxKind.NullKeyword: 1679 expression = parseTokenNode<BooleanLiteral | NullLiteral>(); 1680 break; 1681 case SyntaxKind.MinusToken: 1682 if (lookAhead(() => nextToken() === SyntaxKind.NumericLiteral && nextToken() !== SyntaxKind.ColonToken)) { 1683 expression = parsePrefixUnaryExpression() as JsonMinusNumericLiteral; 1684 } 1685 else { 1686 expression = parseObjectLiteralExpression(); 1687 } 1688 break; 1689 case SyntaxKind.NumericLiteral: 1690 case SyntaxKind.StringLiteral: 1691 if (lookAhead(() => nextToken() !== SyntaxKind.ColonToken)) { 1692 expression = parseLiteralNode() as StringLiteral | NumericLiteral; 1693 break; 1694 } 1695 // falls through 1696 default: 1697 expression = parseObjectLiteralExpression(); 1698 break; 1699 } 1700 1701 // Error recovery: collect multiple top-level expressions 1702 if (expressions && isArray(expressions)) { 1703 expressions.push(expression); 1704 } 1705 else if (expressions) { 1706 expressions = [expressions, expression]; 1707 } 1708 else { 1709 expressions = expression; 1710 if (token() !== SyntaxKind.EndOfFileToken) { 1711 parseErrorAtCurrentToken(Diagnostics.Unexpected_token); 1712 } 1713 } 1714 } 1715 1716 const expression = isArray(expressions) ? finishNode(factory.createArrayLiteralExpression(expressions), pos) : Debug.checkDefined(expressions); 1717 const statement = factory.createExpressionStatement(expression) as JsonObjectExpressionStatement; 1718 finishNode(statement, pos); 1719 statements = createNodeArray([statement], pos); 1720 endOfFileToken = parseExpectedToken(SyntaxKind.EndOfFileToken, Diagnostics.Unexpected_token); 1721 } 1722 1723 // Set source file so that errors will be reported with this file name 1724 const sourceFile = createSourceFile(fileName, ScriptTarget.ES2015, ScriptKind.JSON, /*isDeclaration*/ false, statements, endOfFileToken, sourceFlags, noop); 1725 1726 if (setParentNodes) { 1727 fixupParentReferences(sourceFile); 1728 } 1729 1730 sourceFile.nodeCount = nodeCount; 1731 sourceFile.identifierCount = identifierCount; 1732 sourceFile.identifiers = identifiers; 1733 sourceFile.parseDiagnostics = attachFileToDiagnostics(parseDiagnostics, sourceFile); 1734 if (jsDocDiagnostics) { 1735 sourceFile.jsDocDiagnostics = attachFileToDiagnostics(jsDocDiagnostics, sourceFile); 1736 } 1737 1738 const result = sourceFile as JsonSourceFile; 1739 clearState(); 1740 return result; 1741 } 1742 1743 function initializeState(_fileName: string, _sourceText: string, _languageVersion: ScriptTarget, _syntaxCursor: IncrementalParser.SyntaxCursor | undefined, _scriptKind: ScriptKind) { 1744 NodeConstructor = objectAllocator.getNodeConstructor(); 1745 TokenConstructor = objectAllocator.getTokenConstructor(); 1746 IdentifierConstructor = objectAllocator.getIdentifierConstructor(); 1747 PrivateIdentifierConstructor = objectAllocator.getPrivateIdentifierConstructor(); 1748 SourceFileConstructor = objectAllocator.getSourceFileConstructor(); 1749 1750 fileName = normalizePath(_fileName); 1751 sourceText = _sourceText; 1752 languageVersion = _languageVersion; 1753 syntaxCursor = _syntaxCursor; 1754 scriptKind = _scriptKind; 1755 languageVariant = getLanguageVariant(_scriptKind); 1756 1757 parseDiagnostics = []; 1758 parsingContext = 0; 1759 identifiers = new Map<string, string>(); 1760 privateIdentifiers = new Map<string, string>(); 1761 identifierCount = 0; 1762 nodeCount = 0; 1763 sourceFlags = 0; 1764 topLevel = true; 1765 1766 switch (scriptKind) { 1767 case ScriptKind.JS: 1768 case ScriptKind.JSX: 1769 contextFlags = NodeFlags.JavaScriptFile; 1770 break; 1771 case ScriptKind.JSON: 1772 contextFlags = NodeFlags.JavaScriptFile | NodeFlags.JsonFile; 1773 break; 1774 case ScriptKind.ETS: 1775 contextFlags = NodeFlags.EtsContext; 1776 break; 1777 default: 1778 contextFlags = NodeFlags.None; 1779 break; 1780 } 1781 if (fileName.endsWith(Extension.Ets)) { 1782 contextFlags = NodeFlags.EtsContext; 1783 } 1784 parseErrorBeforeNextFinishedNode = false; 1785 1786 // Initialize and prime the scanner before parsing the source elements. 1787 scanner.setText(sourceText); 1788 scanner.setOnError(scanError); 1789 scanner.setScriptTarget(languageVersion); 1790 scanner.setLanguageVariant(languageVariant); 1791 scanner.setEtsContext(inEtsContext()); 1792 } 1793 1794 function clearState() { 1795 // Clear out the text the scanner is pointing at, so it doesn't keep anything alive unnecessarily. 1796 scanner.clearCommentDirectives(); 1797 scanner.setText(""); 1798 scanner.setOnError(undefined); 1799 scanner.setEtsContext(false); 1800 // Clear any data. We don't want to accidentally hold onto it for too long. 1801 sourceText = undefined!; 1802 languageVersion = undefined!; 1803 syntaxCursor = undefined; 1804 scriptKind = undefined!; 1805 languageVariant = undefined!; 1806 sourceFlags = 0; 1807 parseDiagnostics = undefined!; 1808 jsDocDiagnostics = undefined!; 1809 parsingContext = 0; 1810 identifiers = undefined!; 1811 notParenthesizedArrow = undefined; 1812 topLevel = true; 1813 extendEtsComponentDeclaration = undefined; 1814 stylesEtsComponentDeclaration = undefined; 1815 stateStylesRootNode = undefined; 1816 fileStylesComponents.clear(); 1817 structStylesComponents.clear(); 1818 } 1819 1820 function parseSourceFileWorker(languageVersion: ScriptTarget, setParentNodes: boolean, scriptKind: ScriptKind, setExternalModuleIndicator: (file: SourceFile) => void): SourceFile { 1821 const isDeclarationFile = isDeclarationFileName(fileName); 1822 if (isDeclarationFile) { 1823 contextFlags |= NodeFlags.Ambient; 1824 } 1825 1826 sourceFlags = contextFlags; 1827 1828 // Prime the scanner. 1829 nextToken(); 1830 1831 let statements = parseList(ParsingContext.SourceElements, parseStatement); 1832 const markedkitImportRanges = new Array<TextRange>(); 1833 const sdkPath = getSdkPath(sourceFileCompilerOptions); 1834 // When the language version is 1.2, skip processKit 1835 statements = (!!sourceFileCompilerOptions.noTransformedKitInParser || !sdkPath || parseDiagnostics.length || languageVersionCallBack?.(fileName)) ? 1836 statements : 1837 createNodeArray(processKit(factory, statements, sdkPath, markedkitImportRanges, inEtsContext(), sourceFileCompilerOptions), statements.pos); 1838 Debug.assert(token() === SyntaxKind.EndOfFileToken); 1839 const endOfFileToken = addJSDocComment(parseTokenNode<EndOfFileToken>()); 1840 1841 const sourceFile = createSourceFile(fileName, languageVersion, scriptKind, isDeclarationFile, statements, endOfFileToken, sourceFlags, setExternalModuleIndicator); 1842 if (markedkitImportRanges.length > 0) { 1843 sourceFile.markedKitImportRange = markedkitImportRanges; 1844 } 1845 1846 // 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 1847 processCommentPragmas(sourceFile as {} as PragmaContext, sourceText); 1848 processPragmasIntoFields(sourceFile as {} as PragmaContext, reportPragmaDiagnostic); 1849 1850 sourceFile.commentDirectives = scanner.getCommentDirectives(); 1851 sourceFile.nodeCount = nodeCount; 1852 sourceFile.identifierCount = identifierCount; 1853 sourceFile.identifiers = identifiers; 1854 sourceFile.parseDiagnostics = attachFileToDiagnostics(parseDiagnostics, sourceFile); 1855 if (jsDocDiagnostics) { 1856 sourceFile.jsDocDiagnostics = attachFileToDiagnostics(jsDocDiagnostics, sourceFile); 1857 } 1858 1859 if (setParentNodes) { 1860 fixupParentReferences(sourceFile); 1861 } 1862 1863 return sourceFile; 1864 1865 function reportPragmaDiagnostic(pos: number, end: number, diagnostic: DiagnosticMessage) { 1866 parseDiagnostics.push(createDetachedDiagnostic(fileName, pos, end, diagnostic)); 1867 } 1868 } 1869 1870 function withJSDoc<T extends HasJSDoc>(node: T, hasJSDoc: boolean): T { 1871 return hasJSDoc ? addJSDocComment(node) : node; 1872 } 1873 1874 let hasDeprecatedTag = false; 1875 function addJSDocComment<T extends HasJSDoc>(node: T): T { 1876 Debug.assert(!node.jsDoc); // Should only be called once per node 1877 const jsDoc = mapDefined(getJSDocCommentRanges(node, sourceText), comment => JSDocParser.parseJSDocComment(node, comment.pos, comment.end - comment.pos)); 1878 if (jsDoc.length) node.jsDoc = jsDoc; 1879 if (hasDeprecatedTag) { 1880 hasDeprecatedTag = false; 1881 (node as Mutable<T>).flags |= NodeFlags.Deprecated; 1882 } 1883 return node; 1884 } 1885 1886 function reparseTopLevelAwait(sourceFile: SourceFile) { 1887 const savedSyntaxCursor = syntaxCursor; 1888 const baseSyntaxCursor = IncrementalParser.createSyntaxCursor(sourceFile); 1889 syntaxCursor = { currentNode }; 1890 1891 const statements: Statement[] = []; 1892 const savedParseDiagnostics = parseDiagnostics; 1893 1894 parseDiagnostics = []; 1895 1896 let pos = 0; 1897 let start = findNextStatementWithAwait(sourceFile.statements, 0); 1898 while (start !== -1) { 1899 // append all statements between pos and start 1900 const prevStatement = sourceFile.statements[pos]; 1901 const nextStatement = sourceFile.statements[start]; 1902 addRange(statements, sourceFile.statements, pos, start); 1903 pos = findNextStatementWithoutAwait(sourceFile.statements, start); 1904 1905 // append all diagnostics associated with the copied range 1906 const diagnosticStart = findIndex(savedParseDiagnostics, diagnostic => diagnostic.start >= prevStatement.pos); 1907 const diagnosticEnd = diagnosticStart >= 0 ? findIndex(savedParseDiagnostics, diagnostic => diagnostic.start >= nextStatement.pos, diagnosticStart) : -1; 1908 if (diagnosticStart >= 0) { 1909 addRange(parseDiagnostics, savedParseDiagnostics, diagnosticStart, diagnosticEnd >= 0 ? diagnosticEnd : undefined); 1910 } 1911 1912 // reparse all statements between start and pos. We skip existing diagnostics for the same range and allow the parser to generate new ones. 1913 speculationHelper(() => { 1914 const savedContextFlags = contextFlags; 1915 contextFlags |= NodeFlags.AwaitContext; 1916 scanner.setTextPos(nextStatement.pos); 1917 nextToken(); 1918 1919 while (token() !== SyntaxKind.EndOfFileToken) { 1920 const startPos = scanner.getStartPos(); 1921 const statement = parseListElement(ParsingContext.SourceElements, parseStatement); 1922 statements.push(statement); 1923 if (startPos === scanner.getStartPos()) { 1924 nextToken(); 1925 } 1926 1927 if (pos >= 0) { 1928 const nonAwaitStatement = sourceFile.statements[pos]; 1929 if (statement.end === nonAwaitStatement.pos) { 1930 // done reparsing this section 1931 break; 1932 } 1933 if (statement.end > nonAwaitStatement.pos) { 1934 // we ate into the next statement, so we must reparse it. 1935 pos = findNextStatementWithoutAwait(sourceFile.statements, pos + 1); 1936 } 1937 } 1938 } 1939 1940 contextFlags = savedContextFlags; 1941 }, SpeculationKind.Reparse); 1942 1943 // find the next statement containing an `await` 1944 start = pos >= 0 ? findNextStatementWithAwait(sourceFile.statements, pos) : -1; 1945 } 1946 1947 // append all statements between pos and the end of the list 1948 if (pos >= 0) { 1949 const prevStatement = sourceFile.statements[pos]; 1950 addRange(statements, sourceFile.statements, pos); 1951 1952 // append all diagnostics associated with the copied range 1953 const diagnosticStart = findIndex(savedParseDiagnostics, diagnostic => diagnostic.start >= prevStatement.pos); 1954 if (diagnosticStart >= 0) { 1955 addRange(parseDiagnostics, savedParseDiagnostics, diagnosticStart); 1956 } 1957 } 1958 1959 syntaxCursor = savedSyntaxCursor; 1960 return factory.updateSourceFile(sourceFile, setTextRange(factory.createNodeArray(statements), sourceFile.statements)); 1961 1962 function containsPossibleTopLevelAwait(node: Node) { 1963 return !(node.flags & NodeFlags.AwaitContext) 1964 && !!(node.transformFlags & TransformFlags.ContainsPossibleTopLevelAwait); 1965 } 1966 1967 function findNextStatementWithAwait(statements: NodeArray<Statement>, start: number) { 1968 for (let i = start; i < statements.length; i++) { 1969 if (containsPossibleTopLevelAwait(statements[i])) { 1970 return i; 1971 } 1972 } 1973 return -1; 1974 } 1975 1976 function findNextStatementWithoutAwait(statements: NodeArray<Statement>, start: number) { 1977 for (let i = start; i < statements.length; i++) { 1978 if (!containsPossibleTopLevelAwait(statements[i])) { 1979 return i; 1980 } 1981 } 1982 return -1; 1983 } 1984 1985 function currentNode(position: number) { 1986 const node = baseSyntaxCursor.currentNode(position); 1987 if (topLevel && node && containsPossibleTopLevelAwait(node)) { 1988 node.intersectsChange = true; 1989 } 1990 return node; 1991 } 1992 1993 } 1994 1995 export function fixupParentReferences(rootNode: Node) { 1996 // normally parent references are set during binding. However, for clients that only need 1997 // a syntax tree, and no semantic features, then the binding process is an unnecessary 1998 // overhead. This functions allows us to set all the parents, without all the expense of 1999 // binding. 2000 setParentRecursive(rootNode, /*incremental*/ true); 2001 } 2002 2003 function createSourceFile( 2004 fileName: string, 2005 languageVersion: ScriptTarget, 2006 scriptKind: ScriptKind, 2007 isDeclarationFile: boolean, 2008 statements: readonly Statement[], 2009 endOfFileToken: EndOfFileToken, 2010 flags: NodeFlags, 2011 setExternalModuleIndicator: (sourceFile: SourceFile) => void): SourceFile { 2012 // code from createNode is inlined here so createNode won't have to deal with special case of creating source files 2013 // this is quite rare comparing to other nodes and createNode should be as fast as possible 2014 let sourceFile = factory.createSourceFile(statements, endOfFileToken, flags); 2015 setTextRangePosWidth(sourceFile, 0, sourceText.length); 2016 setFields(sourceFile); 2017 2018 // If we parsed this as an external module, it may contain top-level await 2019 if (!isDeclarationFile && isExternalModule(sourceFile) && sourceFile.transformFlags & TransformFlags.ContainsPossibleTopLevelAwait) { 2020 sourceFile = reparseTopLevelAwait(sourceFile); 2021 setFields(sourceFile); 2022 } 2023 2024 return sourceFile; 2025 2026 function setFields(sourceFile: SourceFile) { 2027 sourceFile.text = sourceText; 2028 sourceFile.bindDiagnostics = []; 2029 sourceFile.bindSuggestionDiagnostics = undefined; 2030 sourceFile.languageVersion = languageVersion; 2031 sourceFile.fileName = fileName; 2032 sourceFile.languageVariant = getLanguageVariant(scriptKind); 2033 sourceFile.isDeclarationFile = isDeclarationFile; 2034 sourceFile.scriptKind = scriptKind; 2035 2036 setExternalModuleIndicator(sourceFile); 2037 sourceFile.setExternalModuleIndicator = setExternalModuleIndicator; 2038 } 2039 } 2040 2041 function setContextFlag(val: boolean, flag: NodeFlags) { 2042 if (val) { 2043 contextFlags |= flag; 2044 } 2045 else { 2046 contextFlags &= ~flag; 2047 } 2048 } 2049 2050 function setEtsFlag(val: boolean, flag: EtsFlags) { 2051 if (val) { 2052 etsFlags |= flag; 2053 } 2054 else { 2055 etsFlags &= ~flag; 2056 } 2057 } 2058 2059 function setDisallowInContext(val: boolean) { 2060 setContextFlag(val, NodeFlags.DisallowInContext); 2061 } 2062 2063 function setYieldContext(val: boolean) { 2064 setContextFlag(val, NodeFlags.YieldContext); 2065 } 2066 2067 function setDecoratorContext(val: boolean) { 2068 setContextFlag(val, NodeFlags.DecoratorContext); 2069 } 2070 2071 function setAwaitContext(val: boolean) { 2072 setContextFlag(val, NodeFlags.AwaitContext); 2073 } 2074 2075 function setStructContext(val: boolean) { 2076 setEtsFlag(val, EtsFlags.StructContext); 2077 } 2078 2079 function setEtsComponentsContext(val: boolean) { 2080 setEtsFlag(val, EtsFlags.EtsComponentsContext); 2081 } 2082 2083 function setEtsNewExpressionContext(val: boolean) { 2084 setEtsFlag(val, EtsFlags.EtsNewExpressionContext); 2085 } 2086 2087 function setEtsExtendComponentsContext(val: boolean) { 2088 setEtsFlag(val, EtsFlags.EtsExtendComponentsContext); 2089 } 2090 2091 function setEtsStylesComponentsContext(val: boolean) { 2092 setEtsFlag(val, EtsFlags.EtsStylesComponentsContext); 2093 } 2094 2095 function setEtsBuildContext(val: boolean) { 2096 setEtsFlag(val, EtsFlags.EtsBuildContext); 2097 } 2098 2099 function setEtsBuilderContext(val: boolean) { 2100 setEtsFlag(val, EtsFlags.EtsBuilderContext); 2101 } 2102 2103 function setEtsStateStylesContext(val: boolean) { 2104 setEtsFlag(val, EtsFlags.EtsStateStylesContext); 2105 } 2106 2107 function setUICallbackContext(val: boolean) { 2108 setEtsFlag(val, EtsFlags.UICallbackContext); 2109 } 2110 2111 function setSyntaxComponentContext(val: boolean) { 2112 setEtsFlag(val, EtsFlags.SyntaxComponentContext); 2113 } 2114 2115 function setSyntaxDataSourceContext(val: boolean) { 2116 setEtsFlag(val, EtsFlags.SyntaxDataSourceContext); 2117 } 2118 2119 function setNoEtsComponentContext(val: boolean) { 2120 setEtsFlag(val, EtsFlags.NoEtsComponentContext); 2121 } 2122 2123 let firstArgumentExpression: boolean = false; 2124 2125 function setFirstArgumentExpression(val: boolean): void { 2126 firstArgumentExpression = val; 2127 } 2128 2129 function getFirstArgumentExpression(): boolean { 2130 return firstArgumentExpression; 2131 } 2132 2133 let repeatEachRest: boolean = false; 2134 2135 function setRepeatEachRest(val: boolean): void { 2136 repeatEachRest = val; 2137 } 2138 2139 function getRepeatEachRest(): boolean { 2140 return repeatEachRest; 2141 } 2142 2143 function doOutsideOfContext<T>(context: NodeFlags, func: () => T): T { 2144 // contextFlagsToClear will contain only the context flags that are 2145 // currently set that we need to temporarily clear 2146 // We don't just blindly reset to the previous flags to ensure 2147 // that we do not mutate cached flags for the incremental 2148 // parser (ThisNodeHasError, ThisNodeOrAnySubNodesHasError, and 2149 // HasAggregatedChildData). 2150 const contextFlagsToClear = context & contextFlags; 2151 if (contextFlagsToClear) { 2152 // clear the requested context flags 2153 setContextFlag(/*val*/ false, contextFlagsToClear); 2154 const result = func(); 2155 // restore the context flags we just cleared 2156 setContextFlag(/*val*/ true, contextFlagsToClear); 2157 return result; 2158 } 2159 2160 // no need to do anything special as we are not in any of the requested contexts 2161 return func(); 2162 } 2163 2164 function doInsideOfContext<T>(context: NodeFlags, func: () => T): T { 2165 // contextFlagsToSet will contain only the context flags that 2166 // are not currently set that we need to temporarily enable. 2167 // We don't just blindly reset to the previous flags to ensure 2168 // that we do not mutate cached flags for the incremental 2169 // parser (ThisNodeHasError, ThisNodeOrAnySubNodesHasError, and 2170 // HasAggregatedChildData). 2171 const contextFlagsToSet = context & ~contextFlags; 2172 if (contextFlagsToSet) { 2173 // set the requested context flags 2174 setContextFlag(/*val*/ true, contextFlagsToSet); 2175 const result = func(); 2176 // reset the context flags we just set 2177 setContextFlag(/*val*/ false, contextFlagsToSet); 2178 return result; 2179 } 2180 2181 // no need to do anything special as we are already in all of the requested contexts 2182 return func(); 2183 } 2184 2185 function allowInAnd<T>(func: () => T): T { 2186 return doOutsideOfContext(NodeFlags.DisallowInContext, func); 2187 } 2188 2189 function disallowInAnd<T>(func: () => T): T { 2190 return doInsideOfContext(NodeFlags.DisallowInContext, func); 2191 } 2192 2193 function allowConditionalTypesAnd<T>(func: () => T): T { 2194 return doOutsideOfContext(NodeFlags.DisallowConditionalTypesContext, func); 2195 } 2196 2197 function disallowConditionalTypesAnd<T>(func: () => T): T { 2198 return doInsideOfContext(NodeFlags.DisallowConditionalTypesContext, func); 2199 } 2200 2201 function doInYieldContext<T>(func: () => T): T { 2202 return doInsideOfContext(NodeFlags.YieldContext, func); 2203 } 2204 2205 function doInDecoratorContext<T>(func: () => T): T { 2206 // setting Ets Extend Components 2207 const extendDecorator = sourceFileCompilerOptions.ets?.extend?.decorator ?? "Extend"; 2208 if (token() === SyntaxKind.Identifier && scanner.getTokenText() === extendDecorator) { 2209 setEtsFlag(true, EtsFlags.EtsExtendComponentsContext); 2210 } 2211 // setting Ets Styles Components 2212 const stylesDecorator = sourceFileCompilerOptions.ets?.styles?.decorator ?? "Styles"; 2213 if (token() === SyntaxKind.Identifier && scanner.getTokenText() === stylesDecorator) { 2214 setEtsFlag(true, EtsFlags.EtsStylesComponentsContext); 2215 } 2216 return doInsideOfContext(NodeFlags.DecoratorContext, func); 2217 } 2218 2219 function doInAwaitContext<T>(func: () => T): T { 2220 return doInsideOfContext(NodeFlags.AwaitContext, func); 2221 } 2222 2223 function doOutsideOfAwaitContext<T>(func: () => T): T { 2224 return doOutsideOfContext(NodeFlags.AwaitContext, func); 2225 } 2226 2227 function doInYieldAndAwaitContext<T>(func: () => T): T { 2228 return doInsideOfContext(NodeFlags.YieldContext | NodeFlags.AwaitContext, func); 2229 } 2230 2231 function doOutsideOfYieldAndAwaitContext<T>(func: () => T): T { 2232 return doOutsideOfContext(NodeFlags.YieldContext | NodeFlags.AwaitContext, func); 2233 } 2234 2235 function inContext(flags: NodeFlags) { 2236 return (contextFlags & flags) !== 0; 2237 } 2238 2239 function inEtsFlagsContext(flags: EtsFlags) { 2240 return (etsFlags & flags) !== 0; 2241 } 2242 2243 function inYieldContext() { 2244 return inContext(NodeFlags.YieldContext); 2245 } 2246 2247 function inDisallowInContext() { 2248 return inContext(NodeFlags.DisallowInContext); 2249 } 2250 2251 function inDisallowConditionalTypesContext() { 2252 return inContext(NodeFlags.DisallowConditionalTypesContext); 2253 } 2254 2255 function inDecoratorContext() { 2256 return inContext(NodeFlags.DecoratorContext); 2257 } 2258 2259 function inAwaitContext() { 2260 return inContext(NodeFlags.AwaitContext); 2261 } 2262 2263 function parseErrorAtCurrentToken(message: DiagnosticMessage, arg0?: any): DiagnosticWithDetachedLocation | undefined { 2264 return parseErrorAt(scanner.getTokenPos(), scanner.getTextPos(), message, arg0); 2265 } 2266 2267 function inEtsContext() { 2268 return inContext(NodeFlags.EtsContext); 2269 } 2270 2271 function inStructContext() { 2272 return inEtsContext() && inEtsFlagsContext(EtsFlags.StructContext); 2273 } 2274 2275 function inEtsComponentsContext() { 2276 return inEtsContext() && inEtsFlagsContext(EtsFlags.EtsComponentsContext); 2277 } 2278 2279 function inEtsNewExpressionContext() { 2280 return inEtsContext() && inEtsFlagsContext(EtsFlags.EtsNewExpressionContext); 2281 } 2282 2283 function inEtsExtendComponentsContext() { 2284 return inEtsContext() && inEtsFlagsContext(EtsFlags.EtsExtendComponentsContext); 2285 } 2286 2287 function inEtsStylesComponentsContext() { 2288 return inEtsContext() && inEtsFlagsContext(EtsFlags.EtsStylesComponentsContext); 2289 } 2290 2291 function inBuildContext() { 2292 return inEtsContext() && inStructContext() && inEtsFlagsContext(EtsFlags.EtsBuildContext); 2293 } 2294 2295 function inBuilderContext() { 2296 return inEtsContext() && inEtsFlagsContext(EtsFlags.EtsBuilderContext); 2297 } 2298 2299 function inEtsStateStylesContext() { 2300 return inEtsContext() && (inBuildContext() || inBuilderContext() || inEtsExtendComponentsContext() || inEtsStylesComponentsContext()) && inEtsFlagsContext(EtsFlags.EtsStateStylesContext); 2301 } 2302 2303 function inUICallbackContext() { 2304 return inEtsContext() && (inBuildContext() || inBuilderContext()) && inEtsFlagsContext(EtsFlags.UICallbackContext); 2305 } 2306 2307 function inSyntaxComponentContext() { 2308 return inEtsContext() && (inBuildContext() || inBuilderContext()) && inEtsFlagsContext(EtsFlags.SyntaxComponentContext); 2309 } 2310 2311 function inSyntaxDataSourceContext() { 2312 return inEtsContext() && (inBuildContext() || inBuilderContext()) && inEtsFlagsContext(EtsFlags.SyntaxDataSourceContext); 2313 } 2314 2315 function inNoEtsComponentContext() { 2316 return inEtsContext() && (inBuildContext() || inBuilderContext()) && inEtsFlagsContext(EtsFlags.NoEtsComponentContext); 2317 } 2318 2319 function inAllowAnnotationContext() { 2320 return (inEtsContext() || isArkguardInputSourceFile) && sourceFileCompilerOptions?.etsAnnotationsEnable === true; 2321 } 2322 2323 function parseErrorAtPosition(start: number, length: number, message: DiagnosticMessage, arg0?: any): DiagnosticWithDetachedLocation | undefined { 2324 // Don't report another error if it would just be at the same position as the last error. 2325 const lastError = lastOrUndefined(parseDiagnostics); 2326 let result: DiagnosticWithDetachedLocation | undefined; 2327 if (!lastError || start !== lastError.start) { 2328 result = createDetachedDiagnostic(fileName, start, length, message, arg0); 2329 parseDiagnostics.push(result); 2330 } 2331 2332 // Mark that we've encountered an error. We'll set an appropriate bit on the next 2333 // node we finish so that it can't be reused incrementally. 2334 parseErrorBeforeNextFinishedNode = true; 2335 return result; 2336 } 2337 2338 function parseErrorAt(start: number, end: number, message: DiagnosticMessage, arg0?: any): DiagnosticWithDetachedLocation | undefined { 2339 return parseErrorAtPosition(start, end - start, message, arg0); 2340 } 2341 2342 function parseErrorAtRange(range: TextRange, message: DiagnosticMessage, arg0?: any): void { 2343 parseErrorAt(range.pos, range.end, message, arg0); 2344 } 2345 2346 function scanError(message: DiagnosticMessage, length: number): void { 2347 parseErrorAtPosition(scanner.getTextPos(), length, message); 2348 } 2349 2350 function getNodePos(): number { 2351 return scanner.getStartPos(); 2352 } 2353 2354 function hasPrecedingJSDocComment() { 2355 return scanner.hasPrecedingJSDocComment(); 2356 } 2357 2358 // Use this function to access the current token instead of reading the currentToken 2359 // variable. Since function results aren't narrowed in control flow analysis, this ensures 2360 // that the type checker doesn't make wrong assumptions about the type of the current 2361 // token (e.g. a call to nextToken() changes the current token but the checker doesn't 2362 // reason about this side effect). Mainstream VMs inline simple functions like this, so 2363 // there is no performance penalty. 2364 function token(): SyntaxKind { 2365 return currentToken; 2366 } 2367 2368 function nextTokenWithoutCheck() { 2369 return currentToken = scanner.scan(); 2370 } 2371 2372 function nextTokenAnd<T>(func: () => T): T { 2373 nextToken(); 2374 return func(); 2375 } 2376 2377 function nextToken(): SyntaxKind { 2378 // if the keyword had an escape 2379 if (isKeyword(currentToken) && (scanner.hasUnicodeEscape() || scanner.hasExtendedUnicodeEscape())) { 2380 // issue a parse error for the escape 2381 parseErrorAt(scanner.getTokenPos(), scanner.getTextPos(), Diagnostics.Keywords_cannot_contain_escape_characters); 2382 } 2383 return nextTokenWithoutCheck(); 2384 } 2385 2386 function nextTokenJSDoc(): JSDocSyntaxKind { 2387 return currentToken = scanner.scanJsDocToken(); 2388 } 2389 2390 function reScanGreaterToken(): SyntaxKind { 2391 return currentToken = scanner.reScanGreaterToken(); 2392 } 2393 2394 function reScanSlashToken(): SyntaxKind { 2395 return currentToken = scanner.reScanSlashToken(); 2396 } 2397 2398 function reScanTemplateToken(isTaggedTemplate: boolean): SyntaxKind { 2399 return currentToken = scanner.reScanTemplateToken(isTaggedTemplate); 2400 } 2401 2402 function reScanTemplateHeadOrNoSubstitutionTemplate(): SyntaxKind { 2403 return currentToken = scanner.reScanTemplateHeadOrNoSubstitutionTemplate(); 2404 } 2405 2406 function reScanLessThanToken(): SyntaxKind { 2407 return currentToken = scanner.reScanLessThanToken(); 2408 } 2409 2410 function reScanHashToken(): SyntaxKind { 2411 return currentToken = scanner.reScanHashToken(); 2412 } 2413 2414 function scanJsxIdentifier(): SyntaxKind { 2415 return currentToken = scanner.scanJsxIdentifier(); 2416 } 2417 2418 function scanJsxText(): SyntaxKind { 2419 return currentToken = scanner.scanJsxToken(); 2420 } 2421 2422 function scanJsxAttributeValue(): SyntaxKind { 2423 return currentToken = scanner.scanJsxAttributeValue(); 2424 } 2425 2426 function speculationHelper<T>(callback: () => T, speculationKind: SpeculationKind): T { 2427 // Keep track of the state we'll need to rollback to if lookahead fails (or if the 2428 // caller asked us to always reset our state). 2429 const saveToken = currentToken; 2430 const saveParseDiagnosticsLength = parseDiagnostics.length; 2431 const saveParseErrorBeforeNextFinishedNode = parseErrorBeforeNextFinishedNode; 2432 2433 // Note: it is not actually necessary to save/restore the context flags here. That's 2434 // because the saving/restoring of these flags happens naturally through the recursive 2435 // descent nature of our parser. However, we still store this here just so we can 2436 // assert that invariant holds. 2437 const saveContextFlags = contextFlags; 2438 2439 // If we're only looking ahead, then tell the scanner to only lookahead as well. 2440 // Otherwise, if we're actually speculatively parsing, then tell the scanner to do the 2441 // same. 2442 const result = speculationKind !== SpeculationKind.TryParse 2443 ? scanner.lookAhead(callback) 2444 : scanner.tryScan(callback); 2445 2446 Debug.assert(saveContextFlags === contextFlags); 2447 2448 // If our callback returned something 'falsy' or we're just looking ahead, 2449 // then unconditionally restore us to where we were. 2450 if (!result || speculationKind !== SpeculationKind.TryParse) { 2451 currentToken = saveToken; 2452 if (speculationKind !== SpeculationKind.Reparse) { 2453 parseDiagnostics.length = saveParseDiagnosticsLength; 2454 } 2455 parseErrorBeforeNextFinishedNode = saveParseErrorBeforeNextFinishedNode; 2456 } 2457 2458 return result; 2459 } 2460 2461 /** Invokes the provided callback then unconditionally restores the parser to the state it 2462 * was in immediately prior to invoking the callback. The result of invoking the callback 2463 * is returned from this function. 2464 */ 2465 function lookAhead<T>(callback: () => T): T { 2466 return speculationHelper(callback, SpeculationKind.Lookahead); 2467 } 2468 2469 /** Invokes the provided callback. If the callback returns something falsy, then it restores 2470 * the parser to the state it was in immediately prior to invoking the callback. If the 2471 * callback returns something truthy, then the parser state is not rolled back. The result 2472 * of invoking the callback is returned from this function. 2473 */ 2474 function tryParse<T>(callback: () => T): T { 2475 return speculationHelper(callback, SpeculationKind.TryParse); 2476 } 2477 2478 function isBindingIdentifier(): boolean { 2479 if (token() === SyntaxKind.Identifier) { 2480 return true; 2481 } 2482 2483 // `let await`/`let yield` in [Yield] or [Await] are allowed here and disallowed in the binder. 2484 return token() > SyntaxKind.LastReservedWord; 2485 } 2486 2487 // Ignore strict mode flag because we will report an error in type checker instead. 2488 function isIdentifier(): boolean { 2489 if (token() === SyntaxKind.Identifier) { 2490 return true; 2491 } 2492 2493 // If we have a 'yield' keyword, and we're in the [yield] context, then 'yield' is 2494 // considered a keyword and is not an identifier. 2495 if (token() === SyntaxKind.YieldKeyword && inYieldContext()) { 2496 return false; 2497 } 2498 2499 // If we have a 'await' keyword, and we're in the [Await] context, then 'await' is 2500 // considered a keyword and is not an identifier. 2501 if (token() === SyntaxKind.AwaitKeyword && inAwaitContext()) { 2502 return false; 2503 } 2504 2505 return token() > SyntaxKind.LastReservedWord; 2506 } 2507 2508 function parseExpected(kind: SyntaxKind, diagnosticMessage?: DiagnosticMessage, shouldAdvance = true): boolean { 2509 if (token() === kind) { 2510 if (shouldAdvance) { 2511 nextToken(); 2512 } 2513 return true; 2514 } 2515 2516 if (token() !== kind && stateStylesRootNode && inEtsStateStylesContext()) { 2517 return true; 2518 } 2519 2520 // Report specific message if provided with one. Otherwise, report generic fallback message. 2521 if (diagnosticMessage) { 2522 parseErrorAtCurrentToken(diagnosticMessage); 2523 } 2524 else { 2525 parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(kind)); 2526 } 2527 return false; 2528 } 2529 2530 const viableKeywordSuggestions = Object.keys(textToKeywordObj).filter(keyword => keyword.length > 2); 2531 2532 /** 2533 * Provides a better error message than the generic "';' expected" if possible for 2534 * known common variants of a missing semicolon, such as from a mispelled names. 2535 * 2536 * @param node Node preceding the expected semicolon location. 2537 */ 2538 function parseErrorForMissingSemicolonAfter(node: Expression | PropertyName): void { 2539 // Tagged template literals are sometimes used in places where only simple strings are allowed, i.e.: 2540 // module `M1` { 2541 // ^^^^^^^^^^^ This block is parsed as a template literal like module`M1`. 2542 if (isTaggedTemplateExpression(node)) { 2543 parseErrorAt(skipTrivia(sourceText, node.template.pos), node.template.end, Diagnostics.Module_declaration_names_may_only_use_or_quoted_strings); 2544 return; 2545 } 2546 2547 // Otherwise, if this isn't a well-known keyword-like identifier, give the generic fallback message. 2548 const expressionText = ts.isIdentifier(node) ? idText(node) : undefined; 2549 if (!expressionText || !isIdentifierText(expressionText, languageVersion)) { 2550 parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.SemicolonToken)); 2551 return; 2552 } 2553 2554 const pos = skipTrivia(sourceText, node.pos); 2555 2556 // Some known keywords are likely signs of syntax being used improperly. 2557 switch (expressionText) { 2558 case "const": 2559 case "let": 2560 case "var": 2561 parseErrorAt(pos, node.end, Diagnostics.Variable_declaration_not_allowed_at_this_location); 2562 return; 2563 2564 case "declare": 2565 // If a declared node failed to parse, it would have emitted a diagnostic already. 2566 return; 2567 2568 case "interface": 2569 parseErrorForInvalidName(Diagnostics.Interface_name_cannot_be_0, Diagnostics.Interface_must_be_given_a_name, SyntaxKind.OpenBraceToken); 2570 return; 2571 2572 case "is": 2573 parseErrorAt(pos, scanner.getTextPos(), Diagnostics.A_type_predicate_is_only_allowed_in_return_type_position_for_functions_and_methods); 2574 return; 2575 2576 case "module": 2577 case "namespace": 2578 parseErrorForInvalidName(Diagnostics.Namespace_name_cannot_be_0, Diagnostics.Namespace_must_be_given_a_name, SyntaxKind.OpenBraceToken); 2579 return; 2580 2581 case "type": 2582 parseErrorForInvalidName(Diagnostics.Type_alias_name_cannot_be_0, Diagnostics.Type_alias_must_be_given_a_name, SyntaxKind.EqualsToken); 2583 return; 2584 } 2585 2586 // The user alternatively might have misspelled or forgotten to add a space after a common keyword. 2587 const suggestion = getSpellingSuggestion(expressionText, viableKeywordSuggestions, n => n) ?? getSpaceSuggestion(expressionText); 2588 if (suggestion) { 2589 parseErrorAt(pos, node.end, Diagnostics.Unknown_keyword_or_identifier_Did_you_mean_0, suggestion); 2590 return; 2591 } 2592 2593 // Unknown tokens are handled with their own errors in the scanner 2594 if (token() === SyntaxKind.Unknown) { 2595 return; 2596 } 2597 2598 // Otherwise, we know this some kind of unknown word, not just a missing expected semicolon. 2599 parseErrorAt(pos, node.end, Diagnostics.Unexpected_keyword_or_identifier); 2600 } 2601 2602 /** 2603 * Reports a diagnostic error for the current token being an invalid name. 2604 * 2605 * @param blankDiagnostic Diagnostic to report for the case of the name being blank (matched tokenIfBlankName). 2606 * @param nameDiagnostic Diagnostic to report for all other cases. 2607 * @param tokenIfBlankName Current token if the name was invalid for being blank (not provided / skipped). 2608 */ 2609 function parseErrorForInvalidName(nameDiagnostic: DiagnosticMessage, blankDiagnostic: DiagnosticMessage, tokenIfBlankName: SyntaxKind) { 2610 if (token() === tokenIfBlankName) { 2611 parseErrorAtCurrentToken(blankDiagnostic); 2612 } 2613 else { 2614 parseErrorAtCurrentToken(nameDiagnostic, scanner.getTokenValue()); 2615 } 2616 } 2617 2618 function getSpaceSuggestion(expressionText: string) { 2619 for (const keyword of viableKeywordSuggestions) { 2620 if (expressionText.length > keyword.length + 2 && startsWith(expressionText, keyword)) { 2621 return `${keyword} ${expressionText.slice(keyword.length)}`; 2622 } 2623 } 2624 2625 return undefined; 2626 } 2627 2628 function parseSemicolonAfterPropertyName(name: PropertyName, type: TypeNode | undefined, initializer: Expression | undefined) { 2629 if (token() === SyntaxKind.AtToken && !scanner.hasPrecedingLineBreak()) { 2630 parseErrorAtCurrentToken(Diagnostics.Decorators_must_precede_the_name_and_all_keywords_of_property_declarations); 2631 return; 2632 } 2633 2634 if (token() === SyntaxKind.OpenParenToken) { 2635 parseErrorAtCurrentToken(Diagnostics.Cannot_start_a_function_call_in_a_type_annotation); 2636 nextToken(); 2637 return; 2638 } 2639 2640 if (type && !canParseSemicolon()) { 2641 if (initializer) { 2642 parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.SemicolonToken)); 2643 } 2644 else { 2645 parseErrorAtCurrentToken(Diagnostics.Expected_for_property_initializer); 2646 } 2647 return; 2648 } 2649 2650 if (tryParseSemicolon()) { 2651 return; 2652 } 2653 2654 if (initializer) { 2655 parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.SemicolonToken)); 2656 return; 2657 } 2658 2659 parseErrorForMissingSemicolonAfter(name); 2660 } 2661 2662 function parseExpectedJSDoc(kind: JSDocSyntaxKind) { 2663 if (token() === kind) { 2664 nextTokenJSDoc(); 2665 return true; 2666 } 2667 parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(kind)); 2668 return false; 2669 } 2670 2671 function parseExpectedMatchingBrackets(openKind: SyntaxKind, closeKind: SyntaxKind, openParsed: boolean, openPosition: number) { 2672 if (token() === closeKind) { 2673 nextToken(); 2674 return; 2675 } 2676 const lastError = parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(closeKind)); 2677 if (!openParsed) { 2678 return; 2679 } 2680 if (lastError) { 2681 addRelatedInfo( 2682 lastError, 2683 createDetachedDiagnostic(fileName, openPosition, 1, Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, tokenToString(openKind), tokenToString(closeKind)) 2684 ); 2685 } 2686 } 2687 2688 function parseOptional(t: SyntaxKind): boolean { 2689 if (token() === t) { 2690 nextToken(); 2691 return true; 2692 } 2693 return false; 2694 } 2695 2696 function parseOptionalToken<TKind extends SyntaxKind>(t: TKind): Token<TKind>; 2697 function parseOptionalToken(t: SyntaxKind): Node | undefined { 2698 if (token() === t) { 2699 return parseTokenNode(); 2700 } 2701 return undefined; 2702 } 2703 2704 function parseOptionalTokenJSDoc<TKind extends JSDocSyntaxKind>(t: TKind): Token<TKind>; 2705 function parseOptionalTokenJSDoc(t: JSDocSyntaxKind): Node | undefined { 2706 if (token() === t) { 2707 return parseTokenNodeJSDoc(); 2708 } 2709 return undefined; 2710 } 2711 2712 function parseExpectedToken<TKind extends SyntaxKind>(t: TKind, diagnosticMessage?: DiagnosticMessage, arg0?: any): Token<TKind>; 2713 function parseExpectedToken(t: SyntaxKind, diagnosticMessage?: DiagnosticMessage, arg0?: any): Node { 2714 return parseOptionalToken(t) || 2715 createMissingNode(t, /*reportAtCurrentPosition*/ false, diagnosticMessage || Diagnostics._0_expected, arg0 || tokenToString(t)); 2716 } 2717 2718 function parseExpectedTokenJSDoc<TKind extends JSDocSyntaxKind>(t: TKind): Token<TKind>; 2719 function parseExpectedTokenJSDoc(t: JSDocSyntaxKind): Node { 2720 return parseOptionalTokenJSDoc(t) || 2721 createMissingNode(t, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, tokenToString(t)); 2722 } 2723 2724 function parseTokenNode<T extends Node>(): T { 2725 const pos = getNodePos(); 2726 const kind = token(); 2727 nextToken(); 2728 return finishNode(factory.createToken(kind), pos) as T; 2729 } 2730 2731 function parseTokenNodeJSDoc<T extends Node>(): T { 2732 const pos = getNodePos(); 2733 const kind = token(); 2734 nextTokenJSDoc(); 2735 return finishNode(factory.createToken(kind), pos) as T; 2736 } 2737 2738 function canParseSemicolon() { 2739 // If there's a real semicolon, then we can always parse it out. 2740 if (token() === SyntaxKind.SemicolonToken) { 2741 return true; 2742 } 2743 2744 // We can parse out an optional semicolon in ASI cases in the following cases. 2745 return token() === SyntaxKind.CloseBraceToken || token() === SyntaxKind.EndOfFileToken || scanner.hasPrecedingLineBreak(); 2746 } 2747 2748 function tryParseSemicolon() { 2749 if (!canParseSemicolon()) { 2750 return false; 2751 } 2752 2753 if (token() === SyntaxKind.SemicolonToken) { 2754 // consume the semicolon if it was explicitly provided. 2755 nextToken(); 2756 } 2757 2758 return true; 2759 } 2760 2761 function parseSemicolon(): boolean { 2762 return tryParseSemicolon() || parseExpected(SyntaxKind.SemicolonToken); 2763 } 2764 2765 function createNodeArray<T extends Node>(elements: T[], pos: number, end?: number, hasTrailingComma?: boolean): NodeArray<T> { 2766 const array = factory.createNodeArray(elements, hasTrailingComma); 2767 setTextRangePosEnd(array, pos, end ?? scanner.getStartPos()); 2768 return array; 2769 } 2770 2771 function finishNode<T extends Node>(node: T, pos: number, end?: number, virtual?: boolean): T { 2772 setTextRangePosEnd(node, pos, end ?? scanner.getStartPos()); 2773 if (contextFlags) { 2774 (node as Mutable<T>).flags |= contextFlags; 2775 } 2776 2777 // Keep track on the node if we encountered an error while parsing it. If we did, then 2778 // we cannot reuse the node incrementally. Once we've marked this node, clear out the 2779 // flag so that we don't mark any subsequent nodes. 2780 if (parseErrorBeforeNextFinishedNode) { 2781 parseErrorBeforeNextFinishedNode = false; 2782 (node as Mutable<T>).flags |= NodeFlags.ThisNodeHasError; 2783 } 2784 2785 if (virtual) { 2786 node.virtual = true; 2787 } 2788 2789 return node; 2790 } 2791 2792 function createMissingNode<T extends Node>(kind: T["kind"], reportAtCurrentPosition: false, diagnosticMessage?: DiagnosticMessage, arg0?: any): T; 2793 function createMissingNode<T extends Node>(kind: T["kind"], reportAtCurrentPosition: boolean, diagnosticMessage: DiagnosticMessage, arg0?: any): T; 2794 function createMissingNode<T extends Node>(kind: T["kind"], reportAtCurrentPosition: boolean, diagnosticMessage: DiagnosticMessage, arg0?: any): T { 2795 if (reportAtCurrentPosition) { 2796 parseErrorAtPosition(scanner.getStartPos(), 0, diagnosticMessage, arg0); 2797 } 2798 else if (diagnosticMessage) { 2799 parseErrorAtCurrentToken(diagnosticMessage, arg0); 2800 } 2801 2802 const pos = getNodePos(); 2803 const result = 2804 kind === SyntaxKind.Identifier ? factory.createIdentifier("", /*typeArguments*/ undefined, /*originalKeywordKind*/ undefined) : 2805 isTemplateLiteralKind(kind) ? factory.createTemplateLiteralLikeNode(kind, "", "", /*templateFlags*/ undefined) : 2806 kind === SyntaxKind.NumericLiteral ? factory.createNumericLiteral("", /*numericLiteralFlags*/ undefined) : 2807 kind === SyntaxKind.StringLiteral ? factory.createStringLiteral("", /*isSingleQuote*/ undefined) : 2808 kind === SyntaxKind.MissingDeclaration ? factory.createMissingDeclaration() : 2809 factory.createToken(kind); 2810 return finishNode(result, pos) as T; 2811 } 2812 2813 function internIdentifier(text: string): string { 2814 let identifier = identifiers.get(text); 2815 if (identifier === undefined) { 2816 identifiers.set(text, identifier = text); 2817 } 2818 return identifier; 2819 } 2820 2821 // An identifier that starts with two underscores has an extra underscore character prepended to it to avoid issues 2822 // with magic property names like '__proto__'. The 'identifiers' object is used to share a single string instance for 2823 // each identifier in order to reduce memory consumption. 2824 function createIdentifier(isIdentifier: boolean, diagnosticMessage?: DiagnosticMessage, privateIdentifierDiagnosticMessage?: DiagnosticMessage): Identifier { 2825 if (isIdentifier) { 2826 identifierCount++; 2827 const pos = getNodePos(); 2828 // Store original token kind if it is not just an Identifier so we can report appropriate error later in type checker 2829 const originalKeywordKind = token(); 2830 const text = internIdentifier(scanner.getTokenValue()); 2831 const hasExtendedUnicodeEscape = scanner.hasExtendedUnicodeEscape(); 2832 nextTokenWithoutCheck(); 2833 return finishNode(factory.createIdentifier(text, /*typeArguments*/ undefined, originalKeywordKind, hasExtendedUnicodeEscape), pos); 2834 } 2835 2836 if (token() === SyntaxKind.PrivateIdentifier) { 2837 parseErrorAtCurrentToken(privateIdentifierDiagnosticMessage || Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies); 2838 return createIdentifier(/*isIdentifier*/ true); 2839 } 2840 2841 if (token() === SyntaxKind.Unknown && scanner.tryScan(() => scanner.reScanInvalidIdentifier() === SyntaxKind.Identifier)) { 2842 // Scanner has already recorded an 'Invalid character' error, so no need to add another from the parser. 2843 return createIdentifier(/*isIdentifier*/ true); 2844 } 2845 2846 if (stateStylesRootNode && inEtsStateStylesContext() && token() === SyntaxKind.DotToken) { 2847 identifierCount++; 2848 const pos = getNodePos(); 2849 return finishVirtualNode( 2850 factory.createIdentifier(`${stateStylesRootNode}Instance`, /*typeArguments*/ undefined, SyntaxKind.Identifier), 2851 pos, 2852 pos 2853 ); 2854 } 2855 2856 identifierCount++; 2857 // Only for end of file because the error gets reported incorrectly on embedded script tags. 2858 const reportAtCurrentPosition = token() === SyntaxKind.EndOfFileToken; 2859 2860 const isReservedWord = scanner.isReservedWord(); 2861 const msgArg = scanner.getTokenText(); 2862 2863 const defaultMessage = isReservedWord ? 2864 Diagnostics.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here : 2865 Diagnostics.Identifier_expected; 2866 2867 return createMissingNode<Identifier>(SyntaxKind.Identifier, reportAtCurrentPosition, diagnosticMessage || defaultMessage, msgArg); 2868 } 2869 2870 function parseBindingIdentifier(privateIdentifierDiagnosticMessage?: DiagnosticMessage) { 2871 return createIdentifier(isBindingIdentifier(), /*diagnosticMessage*/ undefined, privateIdentifierDiagnosticMessage); 2872 } 2873 2874 function parseIdentifier(diagnosticMessage?: DiagnosticMessage, privateIdentifierDiagnosticMessage?: DiagnosticMessage): Identifier { 2875 return createIdentifier(isIdentifier(), diagnosticMessage, privateIdentifierDiagnosticMessage); 2876 } 2877 2878 function parseEtsIdentifier(pos: number): Identifier { 2879 identifierCount++; 2880 const text = internIdentifier(stylesEtsComponentDeclaration!.type); 2881 return finishVirtualNode(factory.createIdentifier(text), pos, pos); 2882 } 2883 2884 function parseIdentifierName(diagnosticMessage?: DiagnosticMessage): Identifier { 2885 return createIdentifier(tokenIsIdentifierOrKeyword(token()), diagnosticMessage); 2886 } 2887 2888 function isLiteralPropertyName(): boolean { 2889 return tokenIsIdentifierOrKeyword(token()) || 2890 token() === SyntaxKind.StringLiteral || 2891 token() === SyntaxKind.NumericLiteral; 2892 } 2893 2894 function isAssertionKey(): boolean { 2895 return tokenIsIdentifierOrKeyword(token()) || 2896 token() === SyntaxKind.StringLiteral; 2897 } 2898 2899 function parsePropertyNameWorker(allowComputedPropertyNames: boolean): PropertyName { 2900 if (token() === SyntaxKind.StringLiteral || token() === SyntaxKind.NumericLiteral) { 2901 const node = parseLiteralNode() as StringLiteral | NumericLiteral; 2902 node.text = internIdentifier(node.text); 2903 return node; 2904 } 2905 if (allowComputedPropertyNames && token() === SyntaxKind.OpenBracketToken) { 2906 return parseComputedPropertyName(); 2907 } 2908 if (token() === SyntaxKind.PrivateIdentifier) { 2909 return parsePrivateIdentifier(); 2910 } 2911 return parseIdentifierName(); 2912 } 2913 2914 function parsePropertyName(): PropertyName { 2915 return parsePropertyNameWorker(/*allowComputedPropertyNames*/ true); 2916 } 2917 2918 function parseComputedPropertyName(): ComputedPropertyName { 2919 // PropertyName [Yield]: 2920 // LiteralPropertyName 2921 // ComputedPropertyName[?Yield] 2922 const pos = getNodePos(); 2923 parseExpected(SyntaxKind.OpenBracketToken); 2924 // We parse any expression (including a comma expression). But the grammar 2925 // says that only an assignment expression is allowed, so the grammar checker 2926 // will error if it sees a comma expression. 2927 const expression = allowInAnd(parseExpression); 2928 parseExpected(SyntaxKind.CloseBracketToken); 2929 return finishNode(factory.createComputedPropertyName(expression), pos); 2930 } 2931 2932 function internPrivateIdentifier(text: string): string { 2933 let privateIdentifier = privateIdentifiers.get(text); 2934 if (privateIdentifier === undefined) { 2935 privateIdentifiers.set(text, privateIdentifier = text); 2936 } 2937 return privateIdentifier; 2938 } 2939 2940 function parsePrivateIdentifier(): PrivateIdentifier { 2941 const pos = getNodePos(); 2942 const node = factory.createPrivateIdentifier(internPrivateIdentifier(scanner.getTokenValue())); 2943 nextToken(); 2944 return finishNode(node, pos); 2945 } 2946 2947 function parseContextualModifier(t: SyntaxKind): boolean { 2948 return token() === t && tryParse(nextTokenCanFollowModifier); 2949 } 2950 2951 function nextTokenIsOnSameLineAndCanFollowModifier() { 2952 nextToken(); 2953 if (scanner.hasPrecedingLineBreak()) { 2954 return false; 2955 } 2956 return canFollowModifier(); 2957 } 2958 2959 function nextTokenCanFollowModifier() { 2960 switch (token()) { 2961 case SyntaxKind.ConstKeyword: 2962 // 'const' is only a modifier if followed by 'enum'. 2963 return nextToken() === SyntaxKind.EnumKeyword; 2964 case SyntaxKind.ExportKeyword: 2965 nextToken(); 2966 if (token() === SyntaxKind.DefaultKeyword) { 2967 return lookAhead(nextTokenCanFollowDefaultKeyword); 2968 } 2969 if (token() === SyntaxKind.TypeKeyword) { 2970 return lookAhead(nextTokenCanFollowExportModifier); 2971 } 2972 if (inAllowAnnotationContext() && token() === SyntaxKind.AtToken) { 2973 return lookAhead(() => nextToken() === SyntaxKind.InterfaceKeyword); 2974 } 2975 return canFollowExportModifier(); 2976 case SyntaxKind.DefaultKeyword: 2977 return nextTokenCanFollowDefaultKeyword(); 2978 case SyntaxKind.AccessorKeyword: 2979 case SyntaxKind.StaticKeyword: 2980 case SyntaxKind.GetKeyword: 2981 case SyntaxKind.SetKeyword: 2982 nextToken(); 2983 return canFollowModifier(); 2984 default: 2985 return nextTokenIsOnSameLineAndCanFollowModifier(); 2986 } 2987 } 2988 2989 function canFollowExportModifier(): boolean { 2990 return token() !== SyntaxKind.AsteriskToken 2991 && token() !== SyntaxKind.AsKeyword 2992 && token() !== SyntaxKind.OpenBraceToken 2993 && canFollowModifier(); 2994 } 2995 2996 function nextTokenCanFollowExportModifier(): boolean { 2997 nextToken(); 2998 return canFollowExportModifier(); 2999 } 3000 3001 function parseAnyContextualModifier(): boolean { 3002 return isModifierKind(token()) && tryParse(nextTokenCanFollowModifier); 3003 } 3004 3005 function canFollowModifier(): boolean { 3006 return token() === SyntaxKind.OpenBracketToken 3007 || token() === SyntaxKind.OpenBraceToken 3008 || token() === SyntaxKind.AsteriskToken 3009 || token() === SyntaxKind.DotDotDotToken 3010 || token() === SyntaxKind.AtToken && inAllowAnnotationContext() && lookAhead(() => nextToken() === SyntaxKind.InterfaceKeyword) 3011 || isLiteralPropertyName(); 3012 } 3013 3014 function nextTokenCanFollowDefaultKeyword(): boolean { 3015 nextToken(); 3016 return token() === SyntaxKind.ClassKeyword || (inEtsContext() && token() === SyntaxKind.StructKeyword) || 3017 token() === SyntaxKind.FunctionKeyword || token() === SyntaxKind.InterfaceKeyword || 3018 (token() === SyntaxKind.AbstractKeyword && lookAhead(nextTokenIsClassKeywordOnSameLine)) || 3019 (token() === SyntaxKind.AsyncKeyword && lookAhead(nextTokenIsFunctionKeywordOnSameLine)); 3020 } 3021 3022 // True if positioned at the start of a list element 3023 function isListElement(parsingContext: ParsingContext, inErrorRecovery: boolean): boolean { 3024 const node = currentNode(parsingContext); 3025 if (node) { 3026 return true; 3027 } 3028 3029 switch (parsingContext) { 3030 case ParsingContext.SourceElements: 3031 case ParsingContext.BlockStatements: 3032 case ParsingContext.SwitchClauseStatements: 3033 // If we're in error recovery, then we don't want to treat ';' as an empty statement. 3034 // The problem is that ';' can show up in far too many contexts, and if we see one 3035 // and assume it's a statement, then we may bail out inappropriately from whatever 3036 // we're parsing. For example, if we have a semicolon in the middle of a class, then 3037 // we really don't want to assume the class is over and we're on a statement in the 3038 // outer module. We just want to consume and move on. 3039 return !(token() === SyntaxKind.SemicolonToken && inErrorRecovery) && isStartOfStatement(); 3040 case ParsingContext.SwitchClauses: 3041 return token() === SyntaxKind.CaseKeyword || token() === SyntaxKind.DefaultKeyword; 3042 case ParsingContext.TypeMembers: 3043 return lookAhead(isTypeMemberStart); 3044 case ParsingContext.ClassMembers: 3045 // We allow semicolons as class elements (as specified by ES6) as long as we're 3046 // not in error recovery. If we're in error recovery, we don't want an errant 3047 // semicolon to be treated as a class member (since they're almost always used 3048 // for statements. 3049 return lookAhead(isClassMemberStart) || (token() === SyntaxKind.SemicolonToken && !inErrorRecovery); 3050 case ParsingContext.AnnotationMembers: 3051 return lookAhead(isAnnotationMemberStart); 3052 case ParsingContext.EnumMembers: 3053 // Include open bracket computed properties. This technically also lets in indexers, 3054 // which would be a candidate for improved error reporting. 3055 return token() === SyntaxKind.OpenBracketToken || isLiteralPropertyName(); 3056 case ParsingContext.ObjectLiteralMembers: 3057 switch (token()) { 3058 case SyntaxKind.OpenBracketToken: 3059 case SyntaxKind.AsteriskToken: 3060 case SyntaxKind.DotDotDotToken: 3061 case SyntaxKind.DotToken: // Not an object literal member, but don't want to close the object (see `tests/cases/fourslash/completionsDotInObjectLiteral.ts`) 3062 return true; 3063 default: 3064 return isLiteralPropertyName(); 3065 } 3066 case ParsingContext.RestProperties: 3067 return isLiteralPropertyName(); 3068 case ParsingContext.ObjectBindingElements: 3069 return token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.DotDotDotToken || isLiteralPropertyName(); 3070 case ParsingContext.AssertEntries: 3071 return isAssertionKey(); 3072 case ParsingContext.HeritageClauseElement: 3073 // If we see `{ ... }` then only consume it as an expression if it is followed by `,` or `{` 3074 // That way we won't consume the body of a class in its heritage clause. 3075 if (token() === SyntaxKind.OpenBraceToken) { 3076 return lookAhead(isValidHeritageClauseObjectLiteral); 3077 } 3078 3079 if (!inErrorRecovery) { 3080 return isStartOfLeftHandSideExpression() && !isHeritageClauseExtendsOrImplementsKeyword(); 3081 } 3082 else { 3083 // If we're in error recovery we tighten up what we're willing to match. 3084 // That way we don't treat something like "this" as a valid heritage clause 3085 // element during recovery. 3086 return isIdentifier() && !isHeritageClauseExtendsOrImplementsKeyword(); 3087 } 3088 case ParsingContext.VariableDeclarations: 3089 return isBindingIdentifierOrPrivateIdentifierOrPattern(); 3090 case ParsingContext.ArrayBindingElements: 3091 return token() === SyntaxKind.CommaToken || token() === SyntaxKind.DotDotDotToken || isBindingIdentifierOrPrivateIdentifierOrPattern(); 3092 case ParsingContext.TypeParameters: 3093 return token() === SyntaxKind.InKeyword || isIdentifier(); 3094 case ParsingContext.ArrayLiteralMembers: 3095 switch (token()) { 3096 case SyntaxKind.CommaToken: 3097 case SyntaxKind.DotToken: // Not an array literal member, but don't want to close the array (see `tests/cases/fourslash/completionsDotInArrayLiteralInObjectLiteral.ts`) 3098 return true; 3099 } 3100 // falls through 3101 case ParsingContext.ArgumentExpressions: 3102 return token() === SyntaxKind.DotDotDotToken || isStartOfExpression(); 3103 case ParsingContext.Parameters: 3104 return isStartOfParameter(/*isJSDocParameter*/ false); 3105 case ParsingContext.JSDocParameters: 3106 return isStartOfParameter(/*isJSDocParameter*/ true); 3107 case ParsingContext.TypeArguments: 3108 case ParsingContext.TupleElementTypes: 3109 return token() === SyntaxKind.CommaToken || isStartOfType(); 3110 case ParsingContext.HeritageClauses: 3111 return isHeritageClause(); 3112 case ParsingContext.ImportOrExportSpecifiers: 3113 return tokenIsIdentifierOrKeyword(token()); 3114 case ParsingContext.JsxAttributes: 3115 return tokenIsIdentifierOrKeyword(token()) || token() === SyntaxKind.OpenBraceToken; 3116 case ParsingContext.JsxChildren: 3117 return true; 3118 } 3119 3120 return Debug.fail("Non-exhaustive case in 'isListElement'."); 3121 } 3122 3123 function isValidHeritageClauseObjectLiteral() { 3124 Debug.assert(token() === SyntaxKind.OpenBraceToken); 3125 if (nextToken() === SyntaxKind.CloseBraceToken) { 3126 // if we see "extends {}" then only treat the {} as what we're extending (and not 3127 // the class body) if we have: 3128 // 3129 // extends {} { 3130 // extends {}, 3131 // extends {} extends 3132 // extends {} implements 3133 3134 const next = nextToken(); 3135 return next === SyntaxKind.CommaToken || next === SyntaxKind.OpenBraceToken || next === SyntaxKind.ExtendsKeyword || next === SyntaxKind.ImplementsKeyword; 3136 } 3137 3138 return true; 3139 } 3140 3141 function nextTokenIsIdentifier() { 3142 nextToken(); 3143 return isIdentifier(); 3144 } 3145 3146 function nextTokenIsIdentifierOrKeyword() { 3147 nextToken(); 3148 return tokenIsIdentifierOrKeyword(token()); 3149 } 3150 3151 function nextTokenIsIdentifierOrKeywordOrGreaterThan() { 3152 nextToken(); 3153 return tokenIsIdentifierOrKeywordOrGreaterThan(token()); 3154 } 3155 3156 function isHeritageClauseExtendsOrImplementsKeyword(): boolean { 3157 if (token() === SyntaxKind.ImplementsKeyword || 3158 token() === SyntaxKind.ExtendsKeyword) { 3159 3160 return lookAhead(nextTokenIsStartOfExpression); 3161 } 3162 3163 return false; 3164 } 3165 3166 function nextTokenIsStartOfExpression() { 3167 nextToken(); 3168 return isStartOfExpression(); 3169 } 3170 3171 function nextTokenIsStartOfType() { 3172 nextToken(); 3173 return isStartOfType(); 3174 } 3175 3176 // True if positioned at a list terminator 3177 function isListTerminator(kind: ParsingContext): boolean { 3178 if (token() === SyntaxKind.EndOfFileToken) { 3179 // Being at the end of the file ends all lists. 3180 return true; 3181 } 3182 3183 switch (kind) { 3184 case ParsingContext.BlockStatements: 3185 case ParsingContext.SwitchClauses: 3186 case ParsingContext.TypeMembers: 3187 case ParsingContext.ClassMembers: 3188 case ParsingContext.AnnotationMembers: 3189 case ParsingContext.EnumMembers: 3190 case ParsingContext.ObjectLiteralMembers: 3191 case ParsingContext.ObjectBindingElements: 3192 case ParsingContext.ImportOrExportSpecifiers: 3193 case ParsingContext.AssertEntries: 3194 return token() === SyntaxKind.CloseBraceToken; 3195 case ParsingContext.SwitchClauseStatements: 3196 return token() === SyntaxKind.CloseBraceToken || token() === SyntaxKind.CaseKeyword || token() === SyntaxKind.DefaultKeyword; 3197 case ParsingContext.HeritageClauseElement: 3198 return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword; 3199 case ParsingContext.VariableDeclarations: 3200 return isVariableDeclaratorListTerminator(); 3201 case ParsingContext.TypeParameters: 3202 // Tokens other than '>' are here for better error recovery 3203 return token() === SyntaxKind.GreaterThanToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword; 3204 case ParsingContext.ArgumentExpressions: 3205 // Tokens other than ')' are here for better error recovery 3206 return token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.SemicolonToken; 3207 case ParsingContext.ArrayLiteralMembers: 3208 case ParsingContext.TupleElementTypes: 3209 case ParsingContext.ArrayBindingElements: 3210 return token() === SyntaxKind.CloseBracketToken; 3211 case ParsingContext.JSDocParameters: 3212 case ParsingContext.Parameters: 3213 case ParsingContext.RestProperties: 3214 // Tokens other than ')' and ']' (the latter for index signatures) are here for better error recovery 3215 return token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.CloseBracketToken /*|| token === SyntaxKind.OpenBraceToken*/; 3216 case ParsingContext.TypeArguments: 3217 // All other tokens should cause the type-argument to terminate except comma token 3218 return token() !== SyntaxKind.CommaToken; 3219 case ParsingContext.HeritageClauses: 3220 return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.CloseBraceToken; 3221 case ParsingContext.JsxAttributes: 3222 return token() === SyntaxKind.GreaterThanToken || token() === SyntaxKind.SlashToken; 3223 case ParsingContext.JsxChildren: 3224 return token() === SyntaxKind.LessThanToken && lookAhead(nextTokenIsSlash); 3225 default: 3226 return false; 3227 } 3228 } 3229 3230 function isVariableDeclaratorListTerminator(): boolean { 3231 // If we can consume a semicolon (either explicitly, or with ASI), then consider us done 3232 // with parsing the list of variable declarators. 3233 if (canParseSemicolon()) { 3234 return true; 3235 } 3236 3237 // in the case where we're parsing the variable declarator of a 'for-in' statement, we 3238 // are done if we see an 'in' keyword in front of us. Same with for-of 3239 if (isInOrOfKeyword(token())) { 3240 return true; 3241 } 3242 3243 // ERROR RECOVERY TWEAK: 3244 // For better error recovery, if we see an '=>' then we just stop immediately. We've got an 3245 // arrow function here and it's going to be very unlikely that we'll resynchronize and get 3246 // another variable declaration. 3247 if (token() === SyntaxKind.EqualsGreaterThanToken) { 3248 return true; 3249 } 3250 3251 // Keep trying to parse out variable declarators. 3252 return false; 3253 } 3254 3255 // True if positioned at element or terminator of the current list or any enclosing list 3256 function isInSomeParsingContext(): boolean { 3257 for (let kind = 0; kind < ParsingContext.Count; kind++) { 3258 if (parsingContext & (1 << kind)) { 3259 if (isListElement(kind, /*inErrorRecovery*/ true) || isListTerminator(kind)) { 3260 return true; 3261 } 3262 } 3263 } 3264 3265 return false; 3266 } 3267 3268 // Parses a list of elements 3269 function parseList<T extends Node>(kind: ParsingContext, parseElement: () => T): NodeArray<T> { 3270 const saveParsingContext = parsingContext; 3271 parsingContext |= 1 << kind; 3272 const list = []; 3273 const listPos = getNodePos(); 3274 3275 while (!isListTerminator(kind)) { 3276 if (isListElement(kind, /*inErrorRecovery*/ false)) { 3277 list.push(parseListElement(kind, parseElement)); 3278 continue; 3279 } 3280 3281 if (abortParsingListOrMoveToNextToken(kind)) { 3282 break; 3283 } 3284 } 3285 3286 parsingContext = saveParsingContext; 3287 return createNodeArray(list, listPos); 3288 } 3289 3290 function parseListElement<T extends Node | undefined>(parsingContext: ParsingContext, parseElement: () => T): T { 3291 const node = currentNode(parsingContext); 3292 if (node) { 3293 return consumeNode(node) as T; 3294 } 3295 3296 return parseElement(); 3297 } 3298 3299 function currentNode(parsingContext: ParsingContext, pos?: number): Node | undefined { 3300 // If we don't have a cursor or the parsing context isn't reusable, there's nothing to reuse. 3301 // 3302 // If there is an outstanding parse error that we've encountered, but not attached to 3303 // some node, then we cannot get a node from the old source tree. This is because we 3304 // want to mark the next node we encounter as being unusable. 3305 // 3306 // Note: This may be too conservative. Perhaps we could reuse the node and set the bit 3307 // on it (or its leftmost child) as having the error. For now though, being conservative 3308 // is nice and likely won't ever affect perf. 3309 if (!syntaxCursor || !isReusableParsingContext(parsingContext) || parseErrorBeforeNextFinishedNode) { 3310 return undefined; 3311 } 3312 3313 const node = syntaxCursor.currentNode(pos ?? scanner.getStartPos()); 3314 3315 // Can't reuse a missing node. 3316 // Can't reuse a node that intersected the change range. 3317 // Can't reuse a node that contains a parse error. This is necessary so that we 3318 // produce the same set of errors again. 3319 if (nodeIsMissing(node) || node.intersectsChange || containsParseError(node)) { 3320 return undefined; 3321 } 3322 3323 // We can only reuse a node if it was parsed under the same strict mode that we're 3324 // currently in. i.e. if we originally parsed a node in non-strict mode, but then 3325 // the user added 'using strict' at the top of the file, then we can't use that node 3326 // again as the presence of strict mode may cause us to parse the tokens in the file 3327 // differently. 3328 // 3329 // Note: we *can* reuse tokens when the strict mode changes. That's because tokens 3330 // are unaffected by strict mode. It's just the parser will decide what to do with it 3331 // differently depending on what mode it is in. 3332 // 3333 // This also applies to all our other context flags as well. 3334 const nodeContextFlags = node.flags & NodeFlags.ContextFlags; 3335 if (nodeContextFlags !== contextFlags) { 3336 return undefined; 3337 } 3338 3339 // Ok, we have a node that looks like it could be reused. Now verify that it is valid 3340 // in the current list parsing context that we're currently at. 3341 if (!canReuseNode(node, parsingContext)) { 3342 return undefined; 3343 } 3344 3345 if ((node as JSDocContainer).jsDocCache) { 3346 // jsDocCache may include tags from parent nodes, which might have been modified. 3347 (node as JSDocContainer).jsDocCache = undefined; 3348 } 3349 3350 return node; 3351 } 3352 3353 function consumeNode(node: Node) { 3354 // Move the scanner so it is after the node we just consumed. 3355 scanner.setTextPos(node.end); 3356 nextToken(); 3357 return node; 3358 } 3359 3360 function isReusableParsingContext(parsingContext: ParsingContext): boolean { 3361 switch (parsingContext) { 3362 case ParsingContext.ClassMembers: 3363 case ParsingContext.SwitchClauses: 3364 case ParsingContext.SourceElements: 3365 case ParsingContext.BlockStatements: 3366 case ParsingContext.SwitchClauseStatements: 3367 case ParsingContext.EnumMembers: 3368 case ParsingContext.TypeMembers: 3369 case ParsingContext.VariableDeclarations: 3370 case ParsingContext.JSDocParameters: 3371 case ParsingContext.Parameters: 3372 return true; 3373 } 3374 return false; 3375 } 3376 3377 function canReuseNode(node: Node, parsingContext: ParsingContext): boolean { 3378 switch (parsingContext) { 3379 case ParsingContext.ClassMembers: 3380 return isReusableClassMember(node); 3381 3382 case ParsingContext.SwitchClauses: 3383 return isReusableSwitchClause(node); 3384 3385 case ParsingContext.SourceElements: 3386 case ParsingContext.BlockStatements: 3387 case ParsingContext.SwitchClauseStatements: 3388 return isReusableStatement(node); 3389 3390 case ParsingContext.EnumMembers: 3391 return isReusableEnumMember(node); 3392 3393 case ParsingContext.TypeMembers: 3394 return isReusableTypeMember(node); 3395 3396 case ParsingContext.VariableDeclarations: 3397 return isReusableVariableDeclaration(node); 3398 3399 case ParsingContext.JSDocParameters: 3400 case ParsingContext.Parameters: 3401 return isReusableParameter(node); 3402 3403 // Any other lists we do not care about reusing nodes in. But feel free to add if 3404 // you can do so safely. Danger areas involve nodes that may involve speculative 3405 // parsing. If speculative parsing is involved with the node, then the range the 3406 // parser reached while looking ahead might be in the edited range (see the example 3407 // in canReuseVariableDeclaratorNode for a good case of this). 3408 3409 // case ParsingContext.HeritageClauses: 3410 // This would probably be safe to reuse. There is no speculative parsing with 3411 // heritage clauses. 3412 3413 // case ParsingContext.TypeParameters: 3414 // This would probably be safe to reuse. There is no speculative parsing with 3415 // type parameters. Note that that's because type *parameters* only occur in 3416 // unambiguous *type* contexts. While type *arguments* occur in very ambiguous 3417 // *expression* contexts. 3418 3419 // case ParsingContext.TupleElementTypes: 3420 // This would probably be safe to reuse. There is no speculative parsing with 3421 // tuple types. 3422 3423 // Technically, type argument list types are probably safe to reuse. While 3424 // speculative parsing is involved with them (since type argument lists are only 3425 // produced from speculative parsing a < as a type argument list), we only have 3426 // the types because speculative parsing succeeded. Thus, the lookahead never 3427 // went past the end of the list and rewound. 3428 // case ParsingContext.TypeArguments: 3429 3430 // Note: these are almost certainly not safe to ever reuse. Expressions commonly 3431 // need a large amount of lookahead, and we should not reuse them as they may 3432 // have actually intersected the edit. 3433 // case ParsingContext.ArgumentExpressions: 3434 3435 // This is not safe to reuse for the same reason as the 'AssignmentExpression' 3436 // cases. i.e. a property assignment may end with an expression, and thus might 3437 // have lookahead far beyond it's old node. 3438 // case ParsingContext.ObjectLiteralMembers: 3439 3440 // This is probably not safe to reuse. There can be speculative parsing with 3441 // type names in a heritage clause. There can be generic names in the type 3442 // name list, and there can be left hand side expressions (which can have type 3443 // arguments.) 3444 // case ParsingContext.HeritageClauseElement: 3445 3446 // Perhaps safe to reuse, but it's unlikely we'd see more than a dozen attributes 3447 // on any given element. Same for children. 3448 // case ParsingContext.JsxAttributes: 3449 // case ParsingContext.JsxChildren: 3450 3451 } 3452 3453 return false; 3454 } 3455 3456 function isReusableClassMember(node: Node) { 3457 if (node) { 3458 switch (node.kind) { 3459 case SyntaxKind.Constructor: 3460 case SyntaxKind.IndexSignature: 3461 case SyntaxKind.GetAccessor: 3462 case SyntaxKind.SetAccessor: 3463 case SyntaxKind.SemicolonClassElement: 3464 return true; 3465 case SyntaxKind.PropertyDeclaration: 3466 return !inStructContext(); 3467 case SyntaxKind.MethodDeclaration: 3468 // Method declarations are not necessarily reusable. An object-literal 3469 // may have a method calls "constructor(...)" and we must reparse that 3470 // into an actual .ConstructorDeclaration. 3471 const methodDeclaration = node as MethodDeclaration; 3472 const nameIsConstructor = methodDeclaration.name.kind === SyntaxKind.Identifier && 3473 methodDeclaration.name.originalKeywordKind === SyntaxKind.ConstructorKeyword; 3474 3475 return !nameIsConstructor; 3476 } 3477 } 3478 3479 return false; 3480 } 3481 3482 function isReusableSwitchClause(node: Node) { 3483 if (node) { 3484 switch (node.kind) { 3485 case SyntaxKind.CaseClause: 3486 case SyntaxKind.DefaultClause: 3487 return true; 3488 } 3489 } 3490 3491 return false; 3492 } 3493 3494 function isReusableStatement(node: Node) { 3495 if (node) { 3496 switch (node.kind) { 3497 case SyntaxKind.FunctionDeclaration: 3498 case SyntaxKind.VariableStatement: 3499 case SyntaxKind.Block: 3500 case SyntaxKind.IfStatement: 3501 case SyntaxKind.ExpressionStatement: 3502 case SyntaxKind.ThrowStatement: 3503 case SyntaxKind.ReturnStatement: 3504 case SyntaxKind.SwitchStatement: 3505 case SyntaxKind.BreakStatement: 3506 case SyntaxKind.ContinueStatement: 3507 case SyntaxKind.ForInStatement: 3508 case SyntaxKind.ForOfStatement: 3509 case SyntaxKind.ForStatement: 3510 case SyntaxKind.WhileStatement: 3511 case SyntaxKind.WithStatement: 3512 case SyntaxKind.EmptyStatement: 3513 case SyntaxKind.TryStatement: 3514 case SyntaxKind.LabeledStatement: 3515 case SyntaxKind.DoStatement: 3516 case SyntaxKind.DebuggerStatement: 3517 case SyntaxKind.ImportDeclaration: 3518 case SyntaxKind.ImportEqualsDeclaration: 3519 case SyntaxKind.ExportDeclaration: 3520 case SyntaxKind.ExportAssignment: 3521 case SyntaxKind.ModuleDeclaration: 3522 case SyntaxKind.ClassDeclaration: 3523 case SyntaxKind.StructDeclaration: 3524 case SyntaxKind.InterfaceDeclaration: 3525 case SyntaxKind.EnumDeclaration: 3526 case SyntaxKind.TypeAliasDeclaration: 3527 return true; 3528 } 3529 } 3530 3531 return false; 3532 } 3533 3534 function isReusableEnumMember(node: Node) { 3535 return node.kind === SyntaxKind.EnumMember; 3536 } 3537 3538 function isReusableTypeMember(node: Node) { 3539 if (node) { 3540 switch (node.kind) { 3541 case SyntaxKind.ConstructSignature: 3542 case SyntaxKind.MethodSignature: 3543 case SyntaxKind.IndexSignature: 3544 case SyntaxKind.PropertySignature: 3545 case SyntaxKind.CallSignature: 3546 return true; 3547 } 3548 } 3549 3550 return false; 3551 } 3552 3553 function isReusableVariableDeclaration(node: Node) { 3554 if (node.kind !== SyntaxKind.VariableDeclaration) { 3555 return false; 3556 } 3557 3558 // Very subtle incremental parsing bug. Consider the following code: 3559 // 3560 // let v = new List < A, B 3561 // 3562 // This is actually legal code. It's a list of variable declarators "v = new List<A" 3563 // on one side and "B" on the other. If you then change that to: 3564 // 3565 // let v = new List < A, B >() 3566 // 3567 // then we have a problem. "v = new List<A" doesn't intersect the change range, so we 3568 // start reparsing at "B" and we completely fail to handle this properly. 3569 // 3570 // In order to prevent this, we do not allow a variable declarator to be reused if it 3571 // has an initializer. 3572 const variableDeclarator = node as VariableDeclaration; 3573 return variableDeclarator.initializer === undefined; 3574 } 3575 3576 function isReusableParameter(node: Node) { 3577 if (node.kind !== SyntaxKind.Parameter) { 3578 return false; 3579 } 3580 3581 // See the comment in isReusableVariableDeclaration for why we do this. 3582 const parameter = node as ParameterDeclaration; 3583 return parameter.initializer === undefined; 3584 } 3585 3586 // Returns true if we should abort parsing. 3587 function abortParsingListOrMoveToNextToken(kind: ParsingContext) { 3588 parsingContextErrors(kind); 3589 if (isInSomeParsingContext()) { 3590 return true; 3591 } 3592 3593 nextToken(); 3594 return false; 3595 } 3596 3597 function parsingContextErrors(context: ParsingContext) { 3598 switch (context) { 3599 case ParsingContext.SourceElements: 3600 return token() === SyntaxKind.DefaultKeyword 3601 ? parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.ExportKeyword)) 3602 : parseErrorAtCurrentToken(Diagnostics.Declaration_or_statement_expected); 3603 case ParsingContext.BlockStatements: return parseErrorAtCurrentToken(Diagnostics.Declaration_or_statement_expected); 3604 case ParsingContext.SwitchClauses: return parseErrorAtCurrentToken(Diagnostics.case_or_default_expected); 3605 case ParsingContext.SwitchClauseStatements: return parseErrorAtCurrentToken(Diagnostics.Statement_expected); 3606 case ParsingContext.RestProperties: // fallthrough 3607 case ParsingContext.TypeMembers: return parseErrorAtCurrentToken(Diagnostics.Property_or_signature_expected); 3608 case ParsingContext.ClassMembers: return parseErrorAtCurrentToken(Diagnostics.Unexpected_token_A_constructor_method_accessor_or_property_was_expected); 3609 case ParsingContext.AnnotationMembers: return parseErrorAtCurrentToken(Diagnostics.Unexpected_token_An_annotation_property_was_expected); 3610 case ParsingContext.EnumMembers: return parseErrorAtCurrentToken(Diagnostics.Enum_member_expected); 3611 case ParsingContext.HeritageClauseElement: return parseErrorAtCurrentToken(Diagnostics.Expression_expected); 3612 case ParsingContext.VariableDeclarations: 3613 return isKeyword(token()) 3614 ? parseErrorAtCurrentToken(Diagnostics._0_is_not_allowed_as_a_variable_declaration_name, tokenToString(token())) 3615 : parseErrorAtCurrentToken(Diagnostics.Variable_declaration_expected); 3616 case ParsingContext.ObjectBindingElements: return parseErrorAtCurrentToken(Diagnostics.Property_destructuring_pattern_expected); 3617 case ParsingContext.ArrayBindingElements: return parseErrorAtCurrentToken(Diagnostics.Array_element_destructuring_pattern_expected); 3618 case ParsingContext.ArgumentExpressions: return parseErrorAtCurrentToken(Diagnostics.Argument_expression_expected); 3619 case ParsingContext.ObjectLiteralMembers: return parseErrorAtCurrentToken(Diagnostics.Property_assignment_expected); 3620 case ParsingContext.ArrayLiteralMembers: return parseErrorAtCurrentToken(Diagnostics.Expression_or_comma_expected); 3621 case ParsingContext.JSDocParameters: return parseErrorAtCurrentToken(Diagnostics.Parameter_declaration_expected); 3622 case ParsingContext.Parameters: 3623 return isKeyword(token()) 3624 ? parseErrorAtCurrentToken(Diagnostics._0_is_not_allowed_as_a_parameter_name, tokenToString(token())) 3625 : parseErrorAtCurrentToken(Diagnostics.Parameter_declaration_expected); 3626 case ParsingContext.TypeParameters: return parseErrorAtCurrentToken(Diagnostics.Type_parameter_declaration_expected); 3627 case ParsingContext.TypeArguments: return parseErrorAtCurrentToken(Diagnostics.Type_argument_expected); 3628 case ParsingContext.TupleElementTypes: return parseErrorAtCurrentToken(Diagnostics.Type_expected); 3629 case ParsingContext.HeritageClauses: return parseErrorAtCurrentToken(Diagnostics.Unexpected_token_expected); 3630 case ParsingContext.ImportOrExportSpecifiers: return parseErrorAtCurrentToken(Diagnostics.Identifier_expected); 3631 case ParsingContext.JsxAttributes: return parseErrorAtCurrentToken(Diagnostics.Identifier_expected); 3632 case ParsingContext.JsxChildren: return parseErrorAtCurrentToken(Diagnostics.Identifier_expected); 3633 case ParsingContext.AssertEntries: return parseErrorAtCurrentToken(Diagnostics.Identifier_or_string_literal_expected); // AssertionKey. 3634 case ParsingContext.Count: return Debug.fail("ParsingContext.Count used as a context"); // Not a real context, only a marker. 3635 default: Debug.assertNever(context); 3636 } 3637 } 3638 3639 // Parses a comma-delimited list of elements 3640 function parseDelimitedList<T extends Node>(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimiter?: boolean): NodeArray<T>; 3641 function parseDelimitedList<T extends Node | undefined>(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimiter?: boolean): NodeArray<NonNullable<T>> | undefined; 3642 function parseDelimitedList<T extends Node | undefined>(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimiter?: boolean): NodeArray<NonNullable<T>> | undefined { 3643 const saveParsingContext = parsingContext; 3644 parsingContext |= 1 << kind; 3645 const list: NonNullable<T>[] = []; 3646 const listPos = getNodePos(); 3647 3648 let commaStart = -1; // Meaning the previous token was not a comma 3649 while (true) { 3650 if (isListElement(kind, /*inErrorRecovery*/ false)) { 3651 const startPos = scanner.getStartPos(); 3652 const result = parseListElement(kind, parseElement); 3653 if (!result) { 3654 parsingContext = saveParsingContext; 3655 return undefined; 3656 } 3657 list.push(result); 3658 commaStart = scanner.getTokenPos(); 3659 3660 if (parseOptional(SyntaxKind.CommaToken)) { 3661 // No need to check for a zero length node since we know we parsed a comma 3662 continue; 3663 } 3664 3665 commaStart = -1; // Back to the state where the last token was not a comma 3666 if (isListTerminator(kind)) { 3667 break; 3668 } 3669 3670 // We didn't get a comma, and the list wasn't terminated, explicitly parse 3671 // out a comma so we give a good error message. 3672 parseExpected(SyntaxKind.CommaToken, getExpectedCommaDiagnostic(kind)); 3673 3674 // If the token was a semicolon, and the caller allows that, then skip it and 3675 // continue. This ensures we get back on track and don't result in tons of 3676 // parse errors. For example, this can happen when people do things like use 3677 // a semicolon to delimit object literal members. Note: we'll have already 3678 // reported an error when we called parseExpected above. 3679 if (considerSemicolonAsDelimiter && token() === SyntaxKind.SemicolonToken && !scanner.hasPrecedingLineBreak()) { 3680 nextToken(); 3681 } 3682 if (startPos === scanner.getStartPos()) { 3683 // What we're parsing isn't actually remotely recognizable as a element and we've consumed no tokens whatsoever 3684 // Consume a token to advance the parser in some way and avoid an infinite loop 3685 // This can happen when we're speculatively parsing parenthesized expressions which we think may be arrow functions, 3686 // or when a modifier keyword which is disallowed as a parameter name (ie, `static` in strict mode) is supplied 3687 nextToken(); 3688 } 3689 continue; 3690 } 3691 3692 if (isListTerminator(kind)) { 3693 break; 3694 } 3695 3696 if (abortParsingListOrMoveToNextToken(kind)) { 3697 break; 3698 } 3699 } 3700 3701 parsingContext = saveParsingContext; 3702 // Recording the trailing comma is deliberately done after the previous 3703 // loop, and not just if we see a list terminator. This is because the list 3704 // may have ended incorrectly, but it is still important to know if there 3705 // was a trailing comma. 3706 // Check if the last token was a comma. 3707 // Always preserve a trailing comma by marking it on the NodeArray 3708 return createNodeArray(list, listPos, /*end*/ undefined, commaStart >= 0); 3709 } 3710 3711 function getExpectedCommaDiagnostic(kind: ParsingContext) { 3712 return kind === ParsingContext.EnumMembers ? Diagnostics.An_enum_member_name_must_be_followed_by_a_or : undefined; 3713 } 3714 3715 interface MissingList<T extends Node> extends NodeArray<T> { 3716 isMissingList: true; 3717 } 3718 3719 function createMissingList<T extends Node>(): MissingList<T> { 3720 const list = createNodeArray<T>([], getNodePos()) as MissingList<T>; 3721 list.isMissingList = true; 3722 return list; 3723 } 3724 3725 function isMissingList(arr: NodeArray<Node>): boolean { 3726 return !!(arr as MissingList<Node>).isMissingList; 3727 } 3728 3729 function parseBracketedList<T extends Node>(kind: ParsingContext, parseElement: () => T, open: SyntaxKind, close: SyntaxKind): NodeArray<T> { 3730 if (parseExpected(open)) { 3731 const result = parseDelimitedList(kind, parseElement); 3732 parseExpected(close); 3733 return result; 3734 } 3735 3736 return createMissingList<T>(); 3737 } 3738 3739 function parseEntityName(allowReservedWords: boolean, diagnosticMessage?: DiagnosticMessage): EntityName { 3740 const pos = getNodePos(); 3741 let entity: EntityName = allowReservedWords ? parseIdentifierName(diagnosticMessage) : parseIdentifier(diagnosticMessage); 3742 let dotPos = getNodePos(); 3743 while (parseOptional(SyntaxKind.DotToken)) { 3744 if (token() === SyntaxKind.LessThanToken) { 3745 // the entity is part of a JSDoc-style generic, so record the trailing dot for later error reporting 3746 entity.jsdocDotPos = dotPos; 3747 break; 3748 } 3749 dotPos = getNodePos(); 3750 entity = finishNode( 3751 factory.createQualifiedName( 3752 entity, 3753 parseRightSideOfDot(allowReservedWords, /* allowPrivateIdentifiers */ false) as Identifier 3754 ), 3755 pos 3756 ); 3757 } 3758 return entity; 3759 } 3760 3761 function createQualifiedName(entity: EntityName, name: Identifier): QualifiedName { 3762 return finishNode(factory.createQualifiedName(entity, name), entity.pos); 3763 } 3764 3765 function parseRightSideOfDot(allowIdentifierNames: boolean, allowPrivateIdentifiers: boolean): Identifier | PrivateIdentifier { 3766 // Technically a keyword is valid here as all identifiers and keywords are identifier names. 3767 // However, often we'll encounter this in error situations when the identifier or keyword 3768 // is actually starting another valid construct. 3769 // 3770 // So, we check for the following specific case: 3771 // 3772 // name. 3773 // identifierOrKeyword identifierNameOrKeyword 3774 // 3775 // Note: the newlines are important here. For example, if that above code 3776 // were rewritten into: 3777 // 3778 // name.identifierOrKeyword 3779 // identifierNameOrKeyword 3780 // 3781 // Then we would consider it valid. That's because ASI would take effect and 3782 // the code would be implicitly: "name.identifierOrKeyword; identifierNameOrKeyword". 3783 // In the first case though, ASI will not take effect because there is not a 3784 // line terminator after the identifier or keyword. 3785 if (scanner.hasPrecedingLineBreak() && tokenIsIdentifierOrKeyword(token())) { 3786 const matchesPattern = lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine); 3787 3788 if (matchesPattern) { 3789 // Report that we need an identifier. However, report it right after the dot, 3790 // and not on the next token. This is because the next token might actually 3791 // be an identifier and the error would be quite confusing. 3792 return createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Identifier_expected); 3793 } 3794 } 3795 3796 if (token() === SyntaxKind.PrivateIdentifier) { 3797 const node = parsePrivateIdentifier(); 3798 return allowPrivateIdentifiers ? node : createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Identifier_expected); 3799 } 3800 3801 return allowIdentifierNames ? parseIdentifierName() : parseIdentifier(); 3802 } 3803 3804 function parseTemplateSpans(isTaggedTemplate: boolean) { 3805 const pos = getNodePos(); 3806 const list = []; 3807 let node: TemplateSpan; 3808 do { 3809 node = parseTemplateSpan(isTaggedTemplate); 3810 list.push(node); 3811 } 3812 while (node.literal.kind === SyntaxKind.TemplateMiddle); 3813 return createNodeArray(list, pos); 3814 } 3815 3816 function parseTemplateExpression(isTaggedTemplate: boolean): TemplateExpression { 3817 const pos = getNodePos(); 3818 return finishNode( 3819 factory.createTemplateExpression( 3820 parseTemplateHead(isTaggedTemplate), 3821 parseTemplateSpans(isTaggedTemplate) 3822 ), 3823 pos 3824 ); 3825 } 3826 3827 function parseTemplateType(): TemplateLiteralTypeNode { 3828 const pos = getNodePos(); 3829 return finishNode( 3830 factory.createTemplateLiteralType( 3831 parseTemplateHead(/*isTaggedTemplate*/ false), 3832 parseTemplateTypeSpans() 3833 ), 3834 pos 3835 ); 3836 } 3837 3838 function parseTemplateTypeSpans() { 3839 const pos = getNodePos(); 3840 const list = []; 3841 let node: TemplateLiteralTypeSpan; 3842 do { 3843 node = parseTemplateTypeSpan(); 3844 list.push(node); 3845 } 3846 while (node.literal.kind === SyntaxKind.TemplateMiddle); 3847 return createNodeArray(list, pos); 3848 } 3849 3850 function parseTemplateTypeSpan(): TemplateLiteralTypeSpan { 3851 const pos = getNodePos(); 3852 return finishNode( 3853 factory.createTemplateLiteralTypeSpan( 3854 parseType(), 3855 parseLiteralOfTemplateSpan(/*isTaggedTemplate*/ false) 3856 ), 3857 pos 3858 ); 3859 } 3860 3861 function parseLiteralOfTemplateSpan(isTaggedTemplate: boolean) { 3862 if (token() === SyntaxKind.CloseBraceToken) { 3863 reScanTemplateToken(isTaggedTemplate); 3864 return parseTemplateMiddleOrTemplateTail(); 3865 } 3866 else { 3867 // TODO(rbuckton): Do we need to call `parseExpectedToken` or can we just call `createMissingNode` directly? 3868 return parseExpectedToken(SyntaxKind.TemplateTail, Diagnostics._0_expected, tokenToString(SyntaxKind.CloseBraceToken)) as TemplateTail; 3869 } 3870 } 3871 3872 function parseTemplateSpan(isTaggedTemplate: boolean): TemplateSpan { 3873 const pos = getNodePos(); 3874 return finishNode( 3875 factory.createTemplateSpan( 3876 allowInAnd(parseExpression), 3877 parseLiteralOfTemplateSpan(isTaggedTemplate) 3878 ), 3879 pos 3880 ); 3881 } 3882 3883 function parseLiteralNode(): LiteralExpression { 3884 return parseLiteralLikeNode(token()) as LiteralExpression; 3885 } 3886 3887 function parseTemplateHead(isTaggedTemplate: boolean): TemplateHead { 3888 if (isTaggedTemplate) { 3889 reScanTemplateHeadOrNoSubstitutionTemplate(); 3890 } 3891 const fragment = parseLiteralLikeNode(token()); 3892 Debug.assert(fragment.kind === SyntaxKind.TemplateHead, "Template head has wrong token kind"); 3893 return fragment as TemplateHead; 3894 } 3895 3896 function parseTemplateMiddleOrTemplateTail(): TemplateMiddle | TemplateTail { 3897 const fragment = parseLiteralLikeNode(token()); 3898 Debug.assert(fragment.kind === SyntaxKind.TemplateMiddle || fragment.kind === SyntaxKind.TemplateTail, "Template fragment has wrong token kind"); 3899 return fragment as TemplateMiddle | TemplateTail; 3900 } 3901 3902 function getTemplateLiteralRawText(kind: TemplateLiteralToken["kind"]) { 3903 const isLast = kind === SyntaxKind.NoSubstitutionTemplateLiteral || kind === SyntaxKind.TemplateTail; 3904 const tokenText = scanner.getTokenText(); 3905 return tokenText.substring(1, tokenText.length - (scanner.isUnterminated() ? 0 : isLast ? 1 : 2)); 3906 } 3907 3908 function parseLiteralLikeNode(kind: SyntaxKind): LiteralLikeNode { 3909 const pos = getNodePos(); 3910 const node = 3911 isTemplateLiteralKind(kind) ? factory.createTemplateLiteralLikeNode(kind, scanner.getTokenValue(), getTemplateLiteralRawText(kind), scanner.getTokenFlags() & TokenFlags.TemplateLiteralLikeFlags) : 3912 // Octal literals are not allowed in strict mode or ES5 3913 // Note that theoretically the following condition would hold true literals like 009, 3914 // which is not octal. But because of how the scanner separates the tokens, we would 3915 // never get a token like this. Instead, we would get 00 and 9 as two separate tokens. 3916 // We also do not need to check for negatives because any prefix operator would be part of a 3917 // parent unary expression. 3918 kind === SyntaxKind.NumericLiteral ? factory.createNumericLiteral(scanner.getTokenValue(), scanner.getNumericLiteralFlags()) : 3919 kind === SyntaxKind.StringLiteral ? factory.createStringLiteral(scanner.getTokenValue(), /*isSingleQuote*/ undefined, scanner.hasExtendedUnicodeEscape()) : 3920 isLiteralKind(kind) ? factory.createLiteralLikeNode(kind, scanner.getTokenValue()) : 3921 Debug.fail(); 3922 3923 if (scanner.hasExtendedUnicodeEscape()) { 3924 node.hasExtendedUnicodeEscape = true; 3925 } 3926 3927 if (scanner.isUnterminated()) { 3928 node.isUnterminated = true; 3929 } 3930 3931 nextToken(); 3932 return finishNode(node, pos); 3933 } 3934 3935 // TYPES 3936 3937 function parseEntityNameOfTypeReference() { 3938 return parseEntityName(/*allowReservedWords*/ true, Diagnostics.Type_expected); 3939 } 3940 3941 function parseTypeArgumentsOfTypeReference() { 3942 if (!scanner.hasPrecedingLineBreak() && reScanLessThanToken() === SyntaxKind.LessThanToken) { 3943 return parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken); 3944 } 3945 } 3946 3947 function parseTypeReference(): TypeReferenceNode { 3948 const pos = getNodePos(); 3949 return finishNode( 3950 factory.createTypeReferenceNode( 3951 parseEntityNameOfTypeReference(), 3952 parseTypeArgumentsOfTypeReference() 3953 ), 3954 pos 3955 ); 3956 } 3957 3958 // If true, we should abort parsing an error function. 3959 function typeHasArrowFunctionBlockingParseError(node: TypeNode): boolean { 3960 switch (node.kind) { 3961 case SyntaxKind.TypeReference: 3962 return nodeIsMissing((node as TypeReferenceNode).typeName); 3963 case SyntaxKind.FunctionType: 3964 case SyntaxKind.ConstructorType: { 3965 const { parameters, type } = node as FunctionOrConstructorTypeNode; 3966 return isMissingList(parameters) || typeHasArrowFunctionBlockingParseError(type); 3967 } 3968 case SyntaxKind.ParenthesizedType: 3969 return typeHasArrowFunctionBlockingParseError((node as ParenthesizedTypeNode).type); 3970 default: 3971 return false; 3972 } 3973 } 3974 3975 function parseThisTypePredicate(lhs: ThisTypeNode): TypePredicateNode { 3976 nextToken(); 3977 return finishNode(factory.createTypePredicateNode(/*assertsModifier*/ undefined, lhs, parseType()), lhs.pos); 3978 } 3979 3980 function parseThisTypeNode(): ThisTypeNode { 3981 const pos = getNodePos(); 3982 nextToken(); 3983 return finishNode(factory.createThisTypeNode(), pos); 3984 } 3985 3986 function parseJSDocAllType(): JSDocAllType | JSDocOptionalType { 3987 const pos = getNodePos(); 3988 nextToken(); 3989 return finishNode(factory.createJSDocAllType(), pos); 3990 } 3991 3992 function parseJSDocNonNullableType(): TypeNode { 3993 const pos = getNodePos(); 3994 nextToken(); 3995 return finishNode(factory.createJSDocNonNullableType(parseNonArrayType(), /*postfix*/ false), pos); 3996 } 3997 3998 function parseJSDocUnknownOrNullableType(): JSDocUnknownType | JSDocNullableType { 3999 const pos = getNodePos(); 4000 // skip the ? 4001 nextToken(); 4002 4003 // Need to lookahead to decide if this is a nullable or unknown type. 4004 4005 // Here are cases where we'll pick the unknown type: 4006 // 4007 // Foo(?, 4008 // { a: ? } 4009 // Foo(?) 4010 // Foo<?> 4011 // Foo(?= 4012 // (?| 4013 if (token() === SyntaxKind.CommaToken || 4014 token() === SyntaxKind.CloseBraceToken || 4015 token() === SyntaxKind.CloseParenToken || 4016 token() === SyntaxKind.GreaterThanToken || 4017 token() === SyntaxKind.EqualsToken || 4018 token() === SyntaxKind.BarToken) { 4019 return finishNode(factory.createJSDocUnknownType(), pos); 4020 } 4021 else { 4022 return finishNode(factory.createJSDocNullableType(parseType(), /*postfix*/ false), pos); 4023 } 4024 } 4025 4026 function parseJSDocFunctionType(): JSDocFunctionType | TypeReferenceNode { 4027 const pos = getNodePos(); 4028 const hasJSDoc = hasPrecedingJSDocComment(); 4029 if (lookAhead(nextTokenIsOpenParen)) { 4030 nextToken(); 4031 const parameters = parseParameters(SignatureFlags.Type | SignatureFlags.JSDoc); 4032 const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false); 4033 return withJSDoc(finishNode(factory.createJSDocFunctionType(parameters, type), pos), hasJSDoc); 4034 } 4035 return finishNode(factory.createTypeReferenceNode(parseIdentifierName(), /*typeArguments*/ undefined), pos); 4036 } 4037 4038 function parseJSDocParameter(): ParameterDeclaration { 4039 const pos = getNodePos(); 4040 let name: Identifier | undefined; 4041 if (token() === SyntaxKind.ThisKeyword || token() === SyntaxKind.NewKeyword) { 4042 name = parseIdentifierName(); 4043 parseExpected(SyntaxKind.ColonToken); 4044 } 4045 return finishNode( 4046 factory.createParameterDeclaration( 4047 /*modifiers*/ undefined, 4048 /*dotDotDotToken*/ undefined, 4049 // TODO(rbuckton): JSDoc parameters don't have names (except `this`/`new`), should we manufacture an empty identifier? 4050 name!, 4051 /*questionToken*/ undefined, 4052 parseJSDocType(), 4053 /*initializer*/ undefined 4054 ), 4055 pos 4056 ); 4057 } 4058 4059 function parseJSDocType(): TypeNode { 4060 scanner.setInJSDocType(true); 4061 const pos = getNodePos(); 4062 if (parseOptional(SyntaxKind.ModuleKeyword)) { 4063 // TODO(rbuckton): We never set the type for a JSDocNamepathType. What should we put here? 4064 const moduleTag = factory.createJSDocNamepathType(/*type*/ undefined!); 4065 terminate: while (true) { 4066 switch (token()) { 4067 case SyntaxKind.CloseBraceToken: 4068 case SyntaxKind.EndOfFileToken: 4069 case SyntaxKind.CommaToken: 4070 case SyntaxKind.WhitespaceTrivia: 4071 break terminate; 4072 default: 4073 nextTokenJSDoc(); 4074 } 4075 } 4076 4077 scanner.setInJSDocType(false); 4078 return finishNode(moduleTag, pos); 4079 } 4080 4081 const hasDotDotDot = parseOptional(SyntaxKind.DotDotDotToken); 4082 let type = parseTypeOrTypePredicate(); 4083 scanner.setInJSDocType(false); 4084 if (hasDotDotDot) { 4085 type = finishNode(factory.createJSDocVariadicType(type), pos); 4086 } 4087 if (token() === SyntaxKind.EqualsToken) { 4088 nextToken(); 4089 return finishNode(factory.createJSDocOptionalType(type), pos); 4090 } 4091 return type; 4092 } 4093 4094 function parseTypeQuery(): TypeQueryNode { 4095 const pos = getNodePos(); 4096 parseExpected(SyntaxKind.TypeOfKeyword); 4097 const entityName = parseEntityName(/*allowReservedWords*/ true); 4098 // Make sure we perform ASI to prevent parsing the next line's type arguments as part of an instantiation expression. 4099 const typeArguments = !scanner.hasPrecedingLineBreak() ? tryParseTypeArguments() : undefined; 4100 return finishNode(factory.createTypeQueryNode(entityName, typeArguments), pos); 4101 } 4102 4103 function parseTypeParameter(position?: number): TypeParameterDeclaration { 4104 const pos = getNodePos(); 4105 const modifiers = parseModifiers(); 4106 const name = position !== undefined ? parseEtsIdentifier(position) : parseIdentifier(); 4107 let constraint: TypeNode | undefined; 4108 let expression: Expression | undefined; 4109 if (parseOptional(SyntaxKind.ExtendsKeyword)) { 4110 // It's not uncommon for people to write improper constraints to a generic. If the 4111 // user writes a constraint that is an expression and not an actual type, then parse 4112 // it out as an expression (so we can recover well), but report that a type is needed 4113 // instead. 4114 if (isStartOfType() || !isStartOfExpression()) { 4115 constraint = parseType(); 4116 } 4117 else { 4118 // It was not a type, and it looked like an expression. Parse out an expression 4119 // here so we recover well. Note: it is important that we call parseUnaryExpression 4120 // and not parseExpression here. If the user has: 4121 // 4122 // <T extends ""> 4123 // 4124 // We do *not* want to consume the `>` as we're consuming the expression for "". 4125 expression = parseUnaryExpressionOrHigher(); 4126 } 4127 } 4128 4129 const defaultType = parseOptional(SyntaxKind.EqualsToken) ? parseType() : undefined; 4130 const node = factory.createTypeParameterDeclaration(modifiers, name, constraint, defaultType); 4131 node.expression = expression; 4132 return position !== undefined ? finishVirtualNode(node, position, position) : finishNode(node, pos); 4133 } 4134 4135 function parseTypeParameters(): NodeArray<TypeParameterDeclaration> | undefined { 4136 if (token() === SyntaxKind.LessThanToken) { 4137 return parseBracketedList(ParsingContext.TypeParameters, parseTypeParameter, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken); 4138 } 4139 } 4140 4141 function parseEtsTypeParameters(pos: number): NodeArray<TypeParameterDeclaration> | undefined { 4142 return createNodeArray([parseTypeParameter(pos)], getNodePos()); 4143 } 4144 4145 function parseEtsTypeArguments(pos: number, name: string): NodeArray<TypeNode> | undefined { 4146 if ((contextFlags & NodeFlags.JavaScriptFile) !== 0) { 4147 // TypeArguments must not be parsed in JavaScript files to avoid ambiguity with binary operators. 4148 return undefined; 4149 } 4150 4151 return createNodeArray([parseEtsType(pos, name)], getNodePos()); 4152 } 4153 4154 function isStartOfParameter(isJSDocParameter: boolean): boolean { 4155 return token() === SyntaxKind.DotDotDotToken || 4156 isBindingIdentifierOrPrivateIdentifierOrPattern() || 4157 isModifierKind(token()) || 4158 token() === SyntaxKind.AtToken || 4159 isStartOfType(/*inStartOfParameter*/ !isJSDocParameter); 4160 } 4161 4162 function parseNameOfParameter(modifiers: NodeArray<ModifierLike> | undefined) { 4163 // FormalParameter [Yield,Await]: 4164 // BindingElement[?Yield,?Await] 4165 const name = parseIdentifierOrPattern(Diagnostics.Private_identifiers_cannot_be_used_as_parameters); 4166 if (getFullWidth(name) === 0 && !some(modifiers) && isModifierKind(token())) { 4167 // in cases like 4168 // 'use strict' 4169 // function foo(static) 4170 // isParameter('static') === true, because of isModifier('static') 4171 // however 'static' is not a legal identifier in a strict mode. 4172 // so result of this function will be ParameterDeclaration (flags = 0, name = missing, type = undefined, initializer = undefined) 4173 // and current token will not change => parsing of the enclosing parameter list will last till the end of time (or OOM) 4174 // to avoid this we'll advance cursor to the next token. 4175 nextToken(); 4176 } 4177 return name; 4178 } 4179 4180 function isParameterNameStart() { 4181 // Be permissive about await and yield by calling isBindingIdentifier instead of isIdentifier; disallowing 4182 // them during a speculative parse leads to many more follow-on errors than allowing the function to parse then later 4183 // complaining about the use of the keywords. 4184 return isBindingIdentifier() || token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.OpenBraceToken; 4185 } 4186 4187 function parseParameter(inOuterAwaitContext: boolean): ParameterDeclaration { 4188 return parseParameterWorker(inOuterAwaitContext); 4189 } 4190 4191 function parseParameterForSpeculation(inOuterAwaitContext: boolean): ParameterDeclaration | undefined { 4192 return parseParameterWorker(inOuterAwaitContext, /*allowAmbiguity*/ false); 4193 } 4194 4195 function parseParameterWorker(inOuterAwaitContext: boolean): ParameterDeclaration; 4196 function parseParameterWorker(inOuterAwaitContext: boolean, allowAmbiguity: false): ParameterDeclaration | undefined; 4197 function parseParameterWorker(inOuterAwaitContext: boolean, allowAmbiguity = true): ParameterDeclaration | undefined { 4198 const pos = getNodePos(); 4199 const hasJSDoc = hasPrecedingJSDocComment(); 4200 4201 // FormalParameter [Yield,Await]: 4202 // BindingElement[?Yield,?Await] 4203 4204 // Decorators are parsed in the outer [Await] context, the rest of the parameter is parsed in the function's [Await] context. 4205 const decorators = inOuterAwaitContext ? doInAwaitContext(parseDecorators) : doOutsideOfAwaitContext(parseDecorators); 4206 4207 if (token() === SyntaxKind.ThisKeyword) { 4208 const node = factory.createParameterDeclaration( 4209 decorators, 4210 /*dotDotDotToken*/ undefined, 4211 createIdentifier(/*isIdentifier*/ true), 4212 /*questionToken*/ undefined, 4213 parseTypeAnnotation(), 4214 /*initializer*/ undefined 4215 ); 4216 4217 if (decorators) { 4218 parseErrorAtRange(decorators[0], Diagnostics.Decorators_may_not_be_applied_to_this_parameters); 4219 } 4220 4221 return withJSDoc(finishNode(node, pos), hasJSDoc); 4222 } 4223 4224 const savedTopLevel = topLevel; 4225 topLevel = false; 4226 4227 const modifiers = combineDecoratorsAndModifiers(decorators, parseModifiers()); 4228 const dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); 4229 4230 if (!allowAmbiguity && !isParameterNameStart()) { 4231 return undefined; 4232 } 4233 4234 const node = withJSDoc( 4235 finishNode( 4236 factory.createParameterDeclaration( 4237 modifiers, 4238 dotDotDotToken, 4239 parseNameOfParameter(modifiers), 4240 parseOptionalToken(SyntaxKind.QuestionToken), 4241 parseTypeAnnotation(), 4242 parseInitializer() 4243 ), 4244 pos 4245 ), 4246 hasJSDoc 4247 ); 4248 topLevel = savedTopLevel; 4249 return node; 4250 } 4251 4252 function parseReturnType(returnToken: SyntaxKind.EqualsGreaterThanToken, isType: boolean): TypeNode; 4253 function parseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean): TypeNode | undefined; 4254 function parseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean) { 4255 if (shouldParseReturnType(returnToken, isType)) { 4256 return allowConditionalTypesAnd(parseTypeOrTypePredicate); 4257 } 4258 } 4259 4260 function shouldParseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean): boolean { 4261 if (returnToken === SyntaxKind.EqualsGreaterThanToken) { 4262 parseExpected(returnToken); 4263 return true; 4264 } 4265 else if (parseOptional(SyntaxKind.ColonToken)) { 4266 return true; 4267 } 4268 else if (isType && token() === SyntaxKind.EqualsGreaterThanToken) { 4269 // This is easy to get backward, especially in type contexts, so parse the type anyway 4270 parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.ColonToken)); 4271 nextToken(); 4272 return true; 4273 } 4274 return false; 4275 } 4276 4277 function parseParametersWorker(flags: SignatureFlags, allowAmbiguity: true): NodeArray<ParameterDeclaration>; 4278 function parseParametersWorker(flags: SignatureFlags, allowAmbiguity: false): NodeArray<ParameterDeclaration> | undefined; 4279 function parseParametersWorker(flags: SignatureFlags, allowAmbiguity: boolean): NodeArray<ParameterDeclaration> | undefined { 4280 // FormalParameters [Yield,Await]: (modified) 4281 // [empty] 4282 // FormalParameterList[?Yield,Await] 4283 // 4284 // FormalParameter[Yield,Await]: (modified) 4285 // BindingElement[?Yield,Await] 4286 // 4287 // BindingElement [Yield,Await]: (modified) 4288 // SingleNameBinding[?Yield,?Await] 4289 // BindingPattern[?Yield,?Await]Initializer [In, ?Yield,?Await] opt 4290 // 4291 // SingleNameBinding [Yield,Await]: 4292 // BindingIdentifier[?Yield,?Await]Initializer [In, ?Yield,?Await] opt 4293 const savedYieldContext = inYieldContext(); 4294 const savedAwaitContext = inAwaitContext(); 4295 4296 setYieldContext(!!(flags & SignatureFlags.Yield)); 4297 setAwaitContext(!!(flags & SignatureFlags.Await)); 4298 4299 const parameters = flags & SignatureFlags.JSDoc ? 4300 parseDelimitedList(ParsingContext.JSDocParameters, parseJSDocParameter) : 4301 parseDelimitedList(ParsingContext.Parameters, () => allowAmbiguity ? parseParameter(savedAwaitContext) : parseParameterForSpeculation(savedAwaitContext)); 4302 4303 setYieldContext(savedYieldContext); 4304 setAwaitContext(savedAwaitContext); 4305 4306 return parameters; 4307 } 4308 4309 function parseParameters(flags: SignatureFlags): NodeArray<ParameterDeclaration> { 4310 // FormalParameters [Yield,Await]: (modified) 4311 // [empty] 4312 // FormalParameterList[?Yield,Await] 4313 // 4314 // FormalParameter[Yield,Await]: (modified) 4315 // BindingElement[?Yield,Await] 4316 // 4317 // BindingElement [Yield,Await]: (modified) 4318 // SingleNameBinding[?Yield,?Await] 4319 // BindingPattern[?Yield,?Await]Initializer [In, ?Yield,?Await] opt 4320 // 4321 // SingleNameBinding [Yield,Await]: 4322 // BindingIdentifier[?Yield,?Await]Initializer [In, ?Yield,?Await] opt 4323 if (!parseExpected(SyntaxKind.OpenParenToken)) { 4324 return createMissingList<ParameterDeclaration>(); 4325 } 4326 4327 const parameters = parseParametersWorker(flags, /*allowAmbiguity*/ true); 4328 parseExpected(SyntaxKind.CloseParenToken); 4329 return parameters; 4330 } 4331 4332 function parseTypeMemberSemicolon() { 4333 // We allow type members to be separated by commas or (possibly ASI) semicolons. 4334 // First check if it was a comma. If so, we're done with the member. 4335 if (parseOptional(SyntaxKind.CommaToken)) { 4336 return; 4337 } 4338 4339 // Didn't have a comma. We must have a (possible ASI) semicolon. 4340 parseSemicolon(); 4341 } 4342 4343 function parseSignatureMember(kind: SyntaxKind.CallSignature | SyntaxKind.ConstructSignature): CallSignatureDeclaration | ConstructSignatureDeclaration { 4344 const pos = getNodePos(); 4345 const hasJSDoc = hasPrecedingJSDocComment(); 4346 if (kind === SyntaxKind.ConstructSignature) { 4347 parseExpected(SyntaxKind.NewKeyword); 4348 } 4349 4350 const typeParameters = parseTypeParameters(); 4351 const parameters = parseParameters(SignatureFlags.Type); 4352 const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ true); 4353 parseTypeMemberSemicolon(); 4354 const node = kind === SyntaxKind.CallSignature 4355 ? factory.createCallSignature(typeParameters, parameters, type) 4356 : factory.createConstructSignature(typeParameters, parameters, type); 4357 return withJSDoc(finishNode(node, pos), hasJSDoc); 4358 } 4359 4360 function isIndexSignature(): boolean { 4361 return token() === SyntaxKind.OpenBracketToken && lookAhead(isUnambiguouslyIndexSignature); 4362 } 4363 4364 function isUnambiguouslyIndexSignature() { 4365 // The only allowed sequence is: 4366 // 4367 // [id: 4368 // 4369 // However, for error recovery, we also check the following cases: 4370 // 4371 // [... 4372 // [id, 4373 // [id?, 4374 // [id?: 4375 // [id?] 4376 // [public id 4377 // [private id 4378 // [protected id 4379 // [] 4380 // 4381 nextToken(); 4382 if (token() === SyntaxKind.DotDotDotToken || token() === SyntaxKind.CloseBracketToken) { 4383 return true; 4384 } 4385 4386 if (isModifierKind(token())) { 4387 nextToken(); 4388 if (isIdentifier()) { 4389 return true; 4390 } 4391 } 4392 else if (!isIdentifier()) { 4393 return false; 4394 } 4395 else { 4396 // Skip the identifier 4397 nextToken(); 4398 } 4399 4400 // A colon signifies a well formed indexer 4401 // A comma should be a badly formed indexer because comma expressions are not allowed 4402 // in computed properties. 4403 if (token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken) { 4404 return true; 4405 } 4406 4407 // Question mark could be an indexer with an optional property, 4408 // or it could be a conditional expression in a computed property. 4409 if (token() !== SyntaxKind.QuestionToken) { 4410 return false; 4411 } 4412 4413 // If any of the following tokens are after the question mark, it cannot 4414 // be a conditional expression, so treat it as an indexer. 4415 nextToken(); 4416 return token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken || token() === SyntaxKind.CloseBracketToken; 4417 } 4418 4419 function parseIndexSignatureDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): IndexSignatureDeclaration { 4420 const parameters = parseBracketedList<ParameterDeclaration>(ParsingContext.Parameters, () => parseParameter(/*inOuterAwaitContext*/ false), SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken); 4421 const type = parseTypeAnnotation(); 4422 parseTypeMemberSemicolon(); 4423 const node = factory.createIndexSignature(modifiers, parameters, type); 4424 (node as Mutable<IndexSignatureDeclaration>).illegalDecorators = decorators; 4425 return withJSDoc(finishNode(node, pos), hasJSDoc); 4426 } 4427 4428 function parsePropertyOrMethodSignature(pos: number, hasJSDoc: boolean, modifiers: NodeArray<Modifier> | undefined): PropertySignature | MethodSignature { 4429 const name = parsePropertyName(); 4430 const questionToken = parseOptionalToken(SyntaxKind.QuestionToken); 4431 let node: PropertySignature | MethodSignature; 4432 if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) { 4433 // Method signatures don't exist in expression contexts. So they have neither 4434 // [Yield] nor [Await] 4435 const typeParameters = parseTypeParameters(); 4436 const parameters = parseParameters(SignatureFlags.Type); 4437 const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ true); 4438 node = factory.createMethodSignature(modifiers, name, questionToken, typeParameters, parameters, type); 4439 } 4440 else { 4441 const type = parseTypeAnnotation(); 4442 node = factory.createPropertySignature(modifiers, name, questionToken, type); 4443 // Although type literal properties cannot not have initializers, we attempt 4444 // to parse an initializer so we can report in the checker that an interface 4445 // property or type literal property cannot have an initializer. 4446 if (token() === SyntaxKind.EqualsToken) (node as Mutable<PropertySignature>).initializer = parseInitializer(); 4447 } 4448 parseTypeMemberSemicolon(); 4449 return withJSDoc(finishNode(node, pos), hasJSDoc); 4450 } 4451 4452 function isTypeMemberStart(): boolean { 4453 // Return true if we have the start of a signature member 4454 if (token() === SyntaxKind.OpenParenToken || 4455 token() === SyntaxKind.LessThanToken || 4456 token() === SyntaxKind.GetKeyword || 4457 token() === SyntaxKind.SetKeyword) { 4458 return true; 4459 } 4460 let idToken = false; 4461 // Eat up all modifiers, but hold on to the last one in case it is actually an identifier 4462 while (isModifierKind(token())) { 4463 idToken = true; 4464 nextToken(); 4465 } 4466 // Index signatures and computed property names are type members 4467 if (token() === SyntaxKind.OpenBracketToken) { 4468 return true; 4469 } 4470 // Try to get the first property-like token following all modifiers 4471 if (isLiteralPropertyName()) { 4472 idToken = true; 4473 nextToken(); 4474 } 4475 // If we were able to get any potential identifier, check that it is 4476 // the start of a member declaration 4477 if (idToken) { 4478 return token() === SyntaxKind.OpenParenToken || 4479 token() === SyntaxKind.LessThanToken || 4480 token() === SyntaxKind.QuestionToken || 4481 token() === SyntaxKind.ColonToken || 4482 token() === SyntaxKind.CommaToken || 4483 canParseSemicolon(); 4484 } 4485 return false; 4486 } 4487 4488 function parseTypeMember(): TypeElement { 4489 if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) { 4490 return parseSignatureMember(SyntaxKind.CallSignature); 4491 } 4492 if (token() === SyntaxKind.NewKeyword && lookAhead(nextTokenIsOpenParenOrLessThan)) { 4493 return parseSignatureMember(SyntaxKind.ConstructSignature); 4494 } 4495 const pos = getNodePos(); 4496 const hasJSDoc = hasPrecedingJSDocComment(); 4497 const modifiers = parseModifiers(); 4498 if (parseContextualModifier(SyntaxKind.GetKeyword)) { 4499 return parseAccessorDeclaration(pos, hasJSDoc, /*decorators*/ undefined, modifiers, SyntaxKind.GetAccessor, SignatureFlags.Type); 4500 } 4501 4502 if (parseContextualModifier(SyntaxKind.SetKeyword)) { 4503 return parseAccessorDeclaration(pos, hasJSDoc, /*decorators*/ undefined, modifiers, SyntaxKind.SetAccessor, SignatureFlags.Type); 4504 } 4505 4506 if (isIndexSignature()) { 4507 return parseIndexSignatureDeclaration(pos, hasJSDoc, /*decorators*/ undefined, modifiers); 4508 } 4509 return parsePropertyOrMethodSignature(pos, hasJSDoc, modifiers); 4510 } 4511 4512 function nextTokenIsOpenParenOrLessThan() { 4513 nextToken(); 4514 return token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken; 4515 } 4516 4517 function nextTokenIsDot() { 4518 return nextToken() === SyntaxKind.DotToken; 4519 } 4520 4521 function nextTokenIsOpenParenOrLessThanOrDot() { 4522 switch (nextToken()) { 4523 case SyntaxKind.OpenParenToken: 4524 case SyntaxKind.LessThanToken: 4525 case SyntaxKind.DotToken: 4526 return true; 4527 } 4528 return false; 4529 } 4530 4531 function parseTypeLiteral(): TypeLiteralNode { 4532 const pos = getNodePos(); 4533 return finishNode(factory.createTypeLiteralNode(parseObjectTypeMembers()), pos); 4534 } 4535 4536 function parseObjectTypeMembers(): NodeArray<TypeElement> { 4537 let members: NodeArray<TypeElement>; 4538 if (parseExpected(SyntaxKind.OpenBraceToken)) { 4539 members = parseList(ParsingContext.TypeMembers, parseTypeMember); 4540 parseExpected(SyntaxKind.CloseBraceToken); 4541 } 4542 else { 4543 members = createMissingList<TypeElement>(); 4544 } 4545 4546 return members; 4547 } 4548 4549 function isStartOfMappedType() { 4550 nextToken(); 4551 if (token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) { 4552 return nextToken() === SyntaxKind.ReadonlyKeyword; 4553 } 4554 if (token() === SyntaxKind.ReadonlyKeyword) { 4555 nextToken(); 4556 } 4557 return token() === SyntaxKind.OpenBracketToken && nextTokenIsIdentifier() && nextToken() === SyntaxKind.InKeyword; 4558 } 4559 4560 function parseMappedTypeParameter() { 4561 const pos = getNodePos(); 4562 const name = parseIdentifierName(); 4563 parseExpected(SyntaxKind.InKeyword); 4564 const type = parseType(); 4565 return finishNode(factory.createTypeParameterDeclaration(/*modifiers*/ undefined, name, type, /*defaultType*/ undefined), pos); 4566 } 4567 4568 function parseMappedType() { 4569 const pos = getNodePos(); 4570 parseExpected(SyntaxKind.OpenBraceToken); 4571 let readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined; 4572 if (token() === SyntaxKind.ReadonlyKeyword || token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) { 4573 readonlyToken = parseTokenNode<ReadonlyKeyword | PlusToken | MinusToken>(); 4574 if (readonlyToken.kind !== SyntaxKind.ReadonlyKeyword) { 4575 parseExpected(SyntaxKind.ReadonlyKeyword); 4576 } 4577 } 4578 parseExpected(SyntaxKind.OpenBracketToken); 4579 const typeParameter = parseMappedTypeParameter(); 4580 const nameType = parseOptional(SyntaxKind.AsKeyword) ? parseType() : undefined; 4581 parseExpected(SyntaxKind.CloseBracketToken); 4582 let questionToken: QuestionToken | PlusToken | MinusToken | undefined; 4583 if (token() === SyntaxKind.QuestionToken || token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) { 4584 questionToken = parseTokenNode<QuestionToken | PlusToken | MinusToken>(); 4585 if (questionToken.kind !== SyntaxKind.QuestionToken) { 4586 parseExpected(SyntaxKind.QuestionToken); 4587 } 4588 } 4589 const type = parseTypeAnnotation(); 4590 parseSemicolon(); 4591 const members = parseList(ParsingContext.TypeMembers, parseTypeMember); 4592 parseExpected(SyntaxKind.CloseBraceToken); 4593 return finishNode(factory.createMappedTypeNode(readonlyToken, typeParameter, nameType, questionToken, type, members), pos); 4594 } 4595 4596 function parseTupleElementType() { 4597 const pos = getNodePos(); 4598 if (parseOptional(SyntaxKind.DotDotDotToken)) { 4599 return finishNode(factory.createRestTypeNode(parseType()), pos); 4600 } 4601 const type = parseType(); 4602 if (isJSDocNullableType(type) && type.pos === type.type.pos) { 4603 const node = factory.createOptionalTypeNode(type.type); 4604 setTextRange(node, type); 4605 (node as Mutable<Node>).flags = type.flags; 4606 return node; 4607 } 4608 return type; 4609 } 4610 4611 function isNextTokenColonOrQuestionColon() { 4612 return nextToken() === SyntaxKind.ColonToken || (token() === SyntaxKind.QuestionToken && nextToken() === SyntaxKind.ColonToken); 4613 } 4614 4615 function isTupleElementName() { 4616 if (token() === SyntaxKind.DotDotDotToken) { 4617 return tokenIsIdentifierOrKeyword(nextToken()) && isNextTokenColonOrQuestionColon(); 4618 } 4619 return tokenIsIdentifierOrKeyword(token()) && isNextTokenColonOrQuestionColon(); 4620 } 4621 4622 function parseTupleElementNameOrTupleElementType() { 4623 if (lookAhead(isTupleElementName)) { 4624 const pos = getNodePos(); 4625 const hasJSDoc = hasPrecedingJSDocComment(); 4626 const dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); 4627 const name = parseIdentifierName(); 4628 const questionToken = parseOptionalToken(SyntaxKind.QuestionToken); 4629 parseExpected(SyntaxKind.ColonToken); 4630 const type = parseTupleElementType(); 4631 const node = factory.createNamedTupleMember(dotDotDotToken, name, questionToken, type); 4632 return withJSDoc(finishNode(node, pos), hasJSDoc); 4633 } 4634 return parseTupleElementType(); 4635 } 4636 4637 function parseTupleType(): TupleTypeNode { 4638 const pos = getNodePos(); 4639 return finishNode( 4640 factory.createTupleTypeNode( 4641 parseBracketedList(ParsingContext.TupleElementTypes, parseTupleElementNameOrTupleElementType, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken) 4642 ), 4643 pos 4644 ); 4645 } 4646 4647 function parseParenthesizedType(): TypeNode { 4648 const pos = getNodePos(); 4649 parseExpected(SyntaxKind.OpenParenToken); 4650 const type = parseType(); 4651 parseExpected(SyntaxKind.CloseParenToken); 4652 return finishNode(factory.createParenthesizedType(type), pos); 4653 } 4654 4655 function parseModifiersForConstructorType(): NodeArray<Modifier> | undefined { 4656 let modifiers: NodeArray<Modifier> | undefined; 4657 if (token() === SyntaxKind.AbstractKeyword) { 4658 const pos = getNodePos(); 4659 nextToken(); 4660 const modifier = finishNode(factory.createToken(SyntaxKind.AbstractKeyword), pos); 4661 modifiers = createNodeArray<Modifier>([modifier], pos); 4662 } 4663 return modifiers; 4664 } 4665 4666 function parseFunctionOrConstructorType(): TypeNode { 4667 const pos = getNodePos(); 4668 const hasJSDoc = hasPrecedingJSDocComment(); 4669 const modifiers = parseModifiersForConstructorType(); 4670 const isConstructorType = parseOptional(SyntaxKind.NewKeyword); 4671 const typeParameters = parseTypeParameters(); 4672 const parameters = parseParameters(SignatureFlags.Type); 4673 const type = parseReturnType(SyntaxKind.EqualsGreaterThanToken, /*isType*/ false); 4674 const node = isConstructorType 4675 ? factory.createConstructorTypeNode(modifiers, typeParameters, parameters, type) 4676 : factory.createFunctionTypeNode(typeParameters, parameters, type); 4677 if (!isConstructorType) (node as Mutable<FunctionTypeNode>).modifiers = modifiers; 4678 return withJSDoc(finishNode(node, pos), hasJSDoc); 4679 } 4680 4681 function parseKeywordAndNoDot(): TypeNode | undefined { 4682 const node = parseTokenNode<TypeNode>(); 4683 return token() === SyntaxKind.DotToken ? undefined : node; 4684 } 4685 4686 function parseLiteralTypeNode(negative?: boolean): LiteralTypeNode { 4687 const pos = getNodePos(); 4688 if (negative) { 4689 nextToken(); 4690 } 4691 let expression: BooleanLiteral | NullLiteral | LiteralExpression | PrefixUnaryExpression = 4692 token() === SyntaxKind.TrueKeyword || token() === SyntaxKind.FalseKeyword || token() === SyntaxKind.NullKeyword ? 4693 parseTokenNode<BooleanLiteral | NullLiteral>() : 4694 parseLiteralLikeNode(token()) as LiteralExpression; 4695 if (negative) { 4696 expression = finishNode(factory.createPrefixUnaryExpression(SyntaxKind.MinusToken, expression), pos); 4697 } 4698 return finishNode(factory.createLiteralTypeNode(expression), pos); 4699 } 4700 4701 function isStartOfTypeOfImportType() { 4702 nextToken(); 4703 return token() === SyntaxKind.ImportKeyword; 4704 } 4705 4706 function parseImportTypeAssertions(): ImportTypeAssertionContainer { 4707 const pos = getNodePos(); 4708 const openBracePosition = scanner.getTokenPos(); 4709 parseExpected(SyntaxKind.OpenBraceToken); 4710 const multiLine = scanner.hasPrecedingLineBreak(); 4711 parseExpected(SyntaxKind.AssertKeyword); 4712 parseExpected(SyntaxKind.ColonToken); 4713 const clause = parseAssertClause(/*skipAssertKeyword*/ true); 4714 if (!parseExpected(SyntaxKind.CloseBraceToken)) { 4715 const lastError = lastOrUndefined(parseDiagnostics); 4716 if (lastError && lastError.code === Diagnostics._0_expected.code) { 4717 addRelatedInfo( 4718 lastError, 4719 createDetachedDiagnostic(fileName, openBracePosition, 1, Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, "{", "}") 4720 ); 4721 } 4722 } 4723 return finishNode(factory.createImportTypeAssertionContainer(clause, multiLine), pos); 4724 } 4725 4726 function parseImportType(): ImportTypeNode { 4727 sourceFlags |= NodeFlags.PossiblyContainsDynamicImport; 4728 const pos = getNodePos(); 4729 const isTypeOf = parseOptional(SyntaxKind.TypeOfKeyword); 4730 parseExpected(SyntaxKind.ImportKeyword); 4731 parseExpected(SyntaxKind.OpenParenToken); 4732 const type = parseType(); 4733 let assertions: ImportTypeAssertionContainer | undefined; 4734 if (parseOptional(SyntaxKind.CommaToken)) { 4735 assertions = parseImportTypeAssertions(); 4736 } 4737 parseExpected(SyntaxKind.CloseParenToken); 4738 const qualifier = parseOptional(SyntaxKind.DotToken) ? parseEntityNameOfTypeReference() : undefined; 4739 const typeArguments = parseTypeArgumentsOfTypeReference(); 4740 return finishNode(factory.createImportTypeNode(type, assertions, qualifier, typeArguments, isTypeOf), pos); 4741 } 4742 4743 function nextTokenIsNumericOrBigIntLiteral() { 4744 nextToken(); 4745 return token() === SyntaxKind.NumericLiteral || token() === SyntaxKind.BigIntLiteral; 4746 } 4747 4748 function parseNonArrayType(): TypeNode { 4749 switch (token()) { 4750 case SyntaxKind.AnyKeyword: 4751 case SyntaxKind.UnknownKeyword: 4752 case SyntaxKind.StringKeyword: 4753 case SyntaxKind.NumberKeyword: 4754 case SyntaxKind.BigIntKeyword: 4755 case SyntaxKind.SymbolKeyword: 4756 case SyntaxKind.BooleanKeyword: 4757 case SyntaxKind.UndefinedKeyword: 4758 case SyntaxKind.NeverKeyword: 4759 case SyntaxKind.ObjectKeyword: 4760 // If these are followed by a dot, then parse these out as a dotted type reference instead. 4761 return tryParse(parseKeywordAndNoDot) || parseTypeReference(); 4762 case SyntaxKind.AsteriskEqualsToken: 4763 // If there is '*=', treat it as * followed by postfix = 4764 scanner.reScanAsteriskEqualsToken(); 4765 // falls through 4766 case SyntaxKind.AsteriskToken: 4767 return parseJSDocAllType(); 4768 case SyntaxKind.QuestionQuestionToken: 4769 // If there is '??', treat it as prefix-'?' in JSDoc type. 4770 scanner.reScanQuestionToken(); 4771 // falls through 4772 case SyntaxKind.QuestionToken: 4773 return parseJSDocUnknownOrNullableType(); 4774 case SyntaxKind.FunctionKeyword: 4775 return parseJSDocFunctionType(); 4776 case SyntaxKind.ExclamationToken: 4777 return parseJSDocNonNullableType(); 4778 case SyntaxKind.NoSubstitutionTemplateLiteral: 4779 case SyntaxKind.StringLiteral: 4780 case SyntaxKind.NumericLiteral: 4781 case SyntaxKind.BigIntLiteral: 4782 case SyntaxKind.TrueKeyword: 4783 case SyntaxKind.FalseKeyword: 4784 case SyntaxKind.NullKeyword: 4785 return parseLiteralTypeNode(); 4786 case SyntaxKind.MinusToken: 4787 return lookAhead(nextTokenIsNumericOrBigIntLiteral) ? parseLiteralTypeNode(/*negative*/ true) : parseTypeReference(); 4788 case SyntaxKind.VoidKeyword: 4789 return parseTokenNode<TypeNode>(); 4790 case SyntaxKind.ThisKeyword: { 4791 const thisKeyword = parseThisTypeNode(); 4792 if (token() === SyntaxKind.IsKeyword && !scanner.hasPrecedingLineBreak()) { 4793 return parseThisTypePredicate(thisKeyword); 4794 } 4795 else { 4796 return thisKeyword; 4797 } 4798 } 4799 case SyntaxKind.TypeOfKeyword: 4800 return lookAhead(isStartOfTypeOfImportType) ? parseImportType() : parseTypeQuery(); 4801 case SyntaxKind.OpenBraceToken: 4802 return lookAhead(isStartOfMappedType) ? parseMappedType() : parseTypeLiteral(); 4803 case SyntaxKind.OpenBracketToken: 4804 return parseTupleType(); 4805 case SyntaxKind.OpenParenToken: 4806 return parseParenthesizedType(); 4807 case SyntaxKind.ImportKeyword: 4808 return parseImportType(); 4809 case SyntaxKind.AssertsKeyword: 4810 return lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine) ? parseAssertsTypePredicate() : parseTypeReference(); 4811 case SyntaxKind.TemplateHead: 4812 return parseTemplateType(); 4813 default: 4814 return parseTypeReference(); 4815 } 4816 } 4817 4818 function isStartOfType(inStartOfParameter?: boolean): boolean { 4819 switch (token()) { 4820 case SyntaxKind.AnyKeyword: 4821 case SyntaxKind.UnknownKeyword: 4822 case SyntaxKind.StringKeyword: 4823 case SyntaxKind.NumberKeyword: 4824 case SyntaxKind.BigIntKeyword: 4825 case SyntaxKind.BooleanKeyword: 4826 case SyntaxKind.ReadonlyKeyword: 4827 case SyntaxKind.SymbolKeyword: 4828 case SyntaxKind.UniqueKeyword: 4829 case SyntaxKind.VoidKeyword: 4830 case SyntaxKind.UndefinedKeyword: 4831 case SyntaxKind.NullKeyword: 4832 case SyntaxKind.ThisKeyword: 4833 case SyntaxKind.TypeOfKeyword: 4834 case SyntaxKind.NeverKeyword: 4835 case SyntaxKind.OpenBraceToken: 4836 case SyntaxKind.OpenBracketToken: 4837 case SyntaxKind.LessThanToken: 4838 case SyntaxKind.BarToken: 4839 case SyntaxKind.AmpersandToken: 4840 case SyntaxKind.NewKeyword: 4841 case SyntaxKind.StringLiteral: 4842 case SyntaxKind.NumericLiteral: 4843 case SyntaxKind.BigIntLiteral: 4844 case SyntaxKind.TrueKeyword: 4845 case SyntaxKind.FalseKeyword: 4846 case SyntaxKind.ObjectKeyword: 4847 case SyntaxKind.AsteriskToken: 4848 case SyntaxKind.QuestionToken: 4849 case SyntaxKind.ExclamationToken: 4850 case SyntaxKind.DotDotDotToken: 4851 case SyntaxKind.InferKeyword: 4852 case SyntaxKind.ImportKeyword: 4853 case SyntaxKind.AssertsKeyword: 4854 case SyntaxKind.NoSubstitutionTemplateLiteral: 4855 case SyntaxKind.TemplateHead: 4856 return true; 4857 case SyntaxKind.FunctionKeyword: 4858 return !inStartOfParameter; 4859 case SyntaxKind.MinusToken: 4860 return !inStartOfParameter && lookAhead(nextTokenIsNumericOrBigIntLiteral); 4861 case SyntaxKind.OpenParenToken: 4862 // Only consider '(' the start of a type if followed by ')', '...', an identifier, a modifier, 4863 // or something that starts a type. We don't want to consider things like '(1)' a type. 4864 return !inStartOfParameter && lookAhead(isStartOfParenthesizedOrFunctionType); 4865 default: 4866 return isIdentifier(); 4867 } 4868 } 4869 4870 function isStartOfParenthesizedOrFunctionType() { 4871 nextToken(); 4872 return token() === SyntaxKind.CloseParenToken || isStartOfParameter(/*isJSDocParameter*/ false) || isStartOfType(); 4873 } 4874 4875 function parsePostfixTypeOrHigher(): TypeNode { 4876 const pos = getNodePos(); 4877 let type = parseNonArrayType(); 4878 while (!scanner.hasPrecedingLineBreak()) { 4879 switch (token()) { 4880 case SyntaxKind.ExclamationToken: 4881 nextToken(); 4882 type = finishNode(factory.createJSDocNonNullableType(type, /*postfix*/ true), pos); 4883 break; 4884 case SyntaxKind.QuestionToken: 4885 // If next token is start of a type we have a conditional type 4886 if (lookAhead(nextTokenIsStartOfType)) { 4887 return type; 4888 } 4889 nextToken(); 4890 type = finishNode(factory.createJSDocNullableType(type, /*postfix*/ true), pos); 4891 break; 4892 case SyntaxKind.OpenBracketToken: 4893 parseExpected(SyntaxKind.OpenBracketToken); 4894 if (isStartOfType()) { 4895 const indexType = parseType(); 4896 parseExpected(SyntaxKind.CloseBracketToken); 4897 type = finishNode(factory.createIndexedAccessTypeNode(type, indexType), pos); 4898 } 4899 else { 4900 parseExpected(SyntaxKind.CloseBracketToken); 4901 type = finishNode(factory.createArrayTypeNode(type), pos); 4902 } 4903 break; 4904 default: 4905 return type; 4906 } 4907 } 4908 return type; 4909 } 4910 4911 function parseTypeOperator(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword) { 4912 const pos = getNodePos(); 4913 parseExpected(operator); 4914 return finishNode(factory.createTypeOperatorNode(operator, parseTypeOperatorOrHigher()), pos); 4915 } 4916 4917 function tryParseConstraintOfInferType() { 4918 if (parseOptional(SyntaxKind.ExtendsKeyword)) { 4919 const constraint = disallowConditionalTypesAnd(parseType); 4920 if (inDisallowConditionalTypesContext() || token() !== SyntaxKind.QuestionToken) { 4921 return constraint; 4922 } 4923 } 4924 } 4925 4926 function parseTypeParameterOfInferType(): TypeParameterDeclaration { 4927 const pos = getNodePos(); 4928 const name = parseIdentifier(); 4929 const constraint = tryParse(tryParseConstraintOfInferType); 4930 const node = factory.createTypeParameterDeclaration(/*modifiers*/ undefined, name, constraint); 4931 return finishNode(node, pos); 4932 } 4933 4934 function parseInferType(): InferTypeNode { 4935 const pos = getNodePos(); 4936 parseExpected(SyntaxKind.InferKeyword); 4937 return finishNode(factory.createInferTypeNode(parseTypeParameterOfInferType()), pos); 4938 } 4939 4940 function parseTypeOperatorOrHigher(): TypeNode { 4941 const operator = token(); 4942 switch (operator) { 4943 case SyntaxKind.KeyOfKeyword: 4944 case SyntaxKind.UniqueKeyword: 4945 case SyntaxKind.ReadonlyKeyword: 4946 return parseTypeOperator(operator); 4947 case SyntaxKind.InferKeyword: 4948 return parseInferType(); 4949 } 4950 return allowConditionalTypesAnd(parsePostfixTypeOrHigher); 4951 } 4952 4953 function parseFunctionOrConstructorTypeToError( 4954 isInUnionType: boolean 4955 ): TypeNode | undefined { 4956 // the function type and constructor type shorthand notation 4957 // are not allowed directly in unions and intersections, but we'll 4958 // try to parse them gracefully and issue a helpful message. 4959 if (isStartOfFunctionTypeOrConstructorType()) { 4960 const type = parseFunctionOrConstructorType(); 4961 let diagnostic: DiagnosticMessage; 4962 if (isFunctionTypeNode(type)) { 4963 diagnostic = isInUnionType 4964 ? Diagnostics.Function_type_notation_must_be_parenthesized_when_used_in_a_union_type 4965 : Diagnostics.Function_type_notation_must_be_parenthesized_when_used_in_an_intersection_type; 4966 } 4967 else { 4968 diagnostic = isInUnionType 4969 ? Diagnostics.Constructor_type_notation_must_be_parenthesized_when_used_in_a_union_type 4970 : Diagnostics.Constructor_type_notation_must_be_parenthesized_when_used_in_an_intersection_type; 4971 4972 } 4973 parseErrorAtRange(type, diagnostic); 4974 return type; 4975 } 4976 return undefined; 4977 } 4978 4979 function parseUnionOrIntersectionType( 4980 operator: SyntaxKind.BarToken | SyntaxKind.AmpersandToken, 4981 parseConstituentType: () => TypeNode, 4982 createTypeNode: (types: NodeArray<TypeNode>) => UnionOrIntersectionTypeNode 4983 ): TypeNode { 4984 const pos = getNodePos(); 4985 const isUnionType = operator === SyntaxKind.BarToken; 4986 const hasLeadingOperator = parseOptional(operator); 4987 let type = hasLeadingOperator && parseFunctionOrConstructorTypeToError(isUnionType) 4988 || parseConstituentType(); 4989 if (token() === operator || hasLeadingOperator) { 4990 const types = [type]; 4991 while (parseOptional(operator)) { 4992 types.push(parseFunctionOrConstructorTypeToError(isUnionType) || parseConstituentType()); 4993 } 4994 type = finishNode(createTypeNode(createNodeArray(types, pos)), pos); 4995 } 4996 return type; 4997 } 4998 4999 function parseIntersectionTypeOrHigher(): TypeNode { 5000 return parseUnionOrIntersectionType(SyntaxKind.AmpersandToken, parseTypeOperatorOrHigher, factory.createIntersectionTypeNode); 5001 } 5002 5003 function parseUnionTypeOrHigher(): TypeNode { 5004 return parseUnionOrIntersectionType(SyntaxKind.BarToken, parseIntersectionTypeOrHigher, factory.createUnionTypeNode); 5005 } 5006 5007 function nextTokenIsNewKeyword(): boolean { 5008 nextToken(); 5009 return token() === SyntaxKind.NewKeyword; 5010 } 5011 5012 function isStartOfFunctionTypeOrConstructorType(): boolean { 5013 if (token() === SyntaxKind.LessThanToken) { 5014 return true; 5015 } 5016 if (token() === SyntaxKind.OpenParenToken && lookAhead(isUnambiguouslyStartOfFunctionType)) { 5017 return true; 5018 } 5019 return token() === SyntaxKind.NewKeyword || 5020 token() === SyntaxKind.AbstractKeyword && lookAhead(nextTokenIsNewKeyword); 5021 } 5022 5023 function skipParameterStart(): boolean { 5024 if (isModifierKind(token())) { 5025 // Skip modifiers 5026 parseModifiers(); 5027 } 5028 if (isIdentifier() || token() === SyntaxKind.ThisKeyword) { 5029 nextToken(); 5030 return true; 5031 } 5032 if (token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.OpenBraceToken) { 5033 // Return true if we can parse an array or object binding pattern with no errors 5034 const previousErrorCount = parseDiagnostics.length; 5035 parseIdentifierOrPattern(); 5036 return previousErrorCount === parseDiagnostics.length; 5037 } 5038 return false; 5039 } 5040 5041 function isUnambiguouslyStartOfFunctionType() { 5042 nextToken(); 5043 if (token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.DotDotDotToken) { 5044 // ( ) 5045 // ( ... 5046 return true; 5047 } 5048 if (skipParameterStart()) { 5049 // We successfully skipped modifiers (if any) and an identifier or binding pattern, 5050 // now see if we have something that indicates a parameter declaration 5051 if (token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken || 5052 token() === SyntaxKind.QuestionToken || token() === SyntaxKind.EqualsToken) { 5053 // ( xxx : 5054 // ( xxx , 5055 // ( xxx ? 5056 // ( xxx = 5057 return true; 5058 } 5059 if (token() === SyntaxKind.CloseParenToken) { 5060 nextToken(); 5061 if (token() === SyntaxKind.EqualsGreaterThanToken) { 5062 // ( xxx ) => 5063 return true; 5064 } 5065 } 5066 } 5067 return false; 5068 } 5069 5070 function parseTypeOrTypePredicate(): TypeNode { 5071 const pos = getNodePos(); 5072 const typePredicateVariable = isIdentifier() && tryParse(parseTypePredicatePrefix); 5073 const type = parseType(); 5074 if (typePredicateVariable) { 5075 return finishNode(factory.createTypePredicateNode(/*assertsModifier*/ undefined, typePredicateVariable, type), pos); 5076 } 5077 else { 5078 return type; 5079 } 5080 } 5081 5082 function parseTypePredicatePrefix() { 5083 const id = parseIdentifier(); 5084 if (token() === SyntaxKind.IsKeyword && !scanner.hasPrecedingLineBreak()) { 5085 nextToken(); 5086 return id; 5087 } 5088 } 5089 5090 function parseAssertsTypePredicate(): TypeNode { 5091 const pos = getNodePos(); 5092 const assertsModifier = parseExpectedToken(SyntaxKind.AssertsKeyword); 5093 const parameterName = token() === SyntaxKind.ThisKeyword ? parseThisTypeNode() : parseIdentifier(); 5094 const type = parseOptional(SyntaxKind.IsKeyword) ? parseType() : undefined; 5095 return finishNode(factory.createTypePredicateNode(assertsModifier, parameterName, type), pos); 5096 } 5097 5098 function parseType(): TypeNode { 5099 if (contextFlags & NodeFlags.TypeExcludesFlags) { 5100 return doOutsideOfContext(NodeFlags.TypeExcludesFlags, parseType); 5101 } 5102 5103 if (isStartOfFunctionTypeOrConstructorType()) { 5104 return parseFunctionOrConstructorType(); 5105 } 5106 const pos = getNodePos(); 5107 const type = parseUnionTypeOrHigher(); 5108 if (!inDisallowConditionalTypesContext() && !scanner.hasPrecedingLineBreak() && parseOptional(SyntaxKind.ExtendsKeyword)) { 5109 // The type following 'extends' is not permitted to be another conditional type 5110 const extendsType = disallowConditionalTypesAnd(parseType); 5111 parseExpected(SyntaxKind.QuestionToken); 5112 const trueType = allowConditionalTypesAnd(parseType); 5113 parseExpected(SyntaxKind.ColonToken); 5114 const falseType = allowConditionalTypesAnd(parseType); 5115 return finishNode(factory.createConditionalTypeNode(type, extendsType, trueType, falseType), pos); 5116 } 5117 return type; 5118 } 5119 5120 function parseEtsType(pos: number, name: string): TypeNode { 5121 const contextFlagsToClear = NodeFlags.TypeExcludesFlags & contextFlags; 5122 if (contextFlagsToClear) { 5123 // clear the requested context flags 5124 setContextFlag(/*val*/ false, contextFlagsToClear); 5125 const result = parseEtsTypeReferenceWorker(pos, name); 5126 // restore the context flags we just cleared 5127 setContextFlag(/*val*/ true, contextFlagsToClear); 5128 return result; 5129 } 5130 5131 return parseEtsTypeReferenceWorker(pos, name); 5132 } 5133 5134 function parseEtsTypeReferenceWorker(pos: number, name: string): TypeNode { 5135 return finishVirtualNode( 5136 factory.createTypeReferenceNode( 5137 finishVirtualNode(factory.createIdentifier(name), pos, pos) 5138 ), 5139 pos, pos 5140 ); 5141 } 5142 5143 function parseTypeAnnotation(): TypeNode | undefined { 5144 return parseOptional(SyntaxKind.ColonToken) ? parseType() : undefined; 5145 } 5146 5147 // EXPRESSIONS 5148 function isStartOfLeftHandSideExpression(): boolean { 5149 switch (token()) { 5150 case SyntaxKind.ThisKeyword: 5151 case SyntaxKind.SuperKeyword: 5152 case SyntaxKind.NullKeyword: 5153 case SyntaxKind.TrueKeyword: 5154 case SyntaxKind.FalseKeyword: 5155 case SyntaxKind.NumericLiteral: 5156 case SyntaxKind.BigIntLiteral: 5157 case SyntaxKind.StringLiteral: 5158 case SyntaxKind.NoSubstitutionTemplateLiteral: 5159 case SyntaxKind.TemplateHead: 5160 case SyntaxKind.OpenParenToken: 5161 case SyntaxKind.OpenBracketToken: 5162 case SyntaxKind.OpenBraceToken: 5163 case SyntaxKind.FunctionKeyword: 5164 case SyntaxKind.ClassKeyword: 5165 case SyntaxKind.NewKeyword: 5166 case SyntaxKind.SlashToken: 5167 case SyntaxKind.SlashEqualsToken: 5168 case SyntaxKind.Identifier: 5169 return true; 5170 case SyntaxKind.StructKeyword: 5171 return inEtsContext(); 5172 case SyntaxKind.ImportKeyword: 5173 return lookAhead(nextTokenIsOpenParenOrLessThanOrDot); 5174 default: 5175 return isIdentifier(); 5176 } 5177 } 5178 5179 function isStartOfExpression(): boolean { 5180 if (isStartOfLeftHandSideExpression()) { 5181 return true; 5182 } 5183 5184 switch (token()) { 5185 case SyntaxKind.PlusToken: 5186 case SyntaxKind.MinusToken: 5187 case SyntaxKind.TildeToken: 5188 case SyntaxKind.ExclamationToken: 5189 case SyntaxKind.DeleteKeyword: 5190 case SyntaxKind.TypeOfKeyword: 5191 case SyntaxKind.VoidKeyword: 5192 case SyntaxKind.PlusPlusToken: 5193 case SyntaxKind.MinusMinusToken: 5194 case SyntaxKind.LessThanToken: 5195 case SyntaxKind.AwaitKeyword: 5196 case SyntaxKind.YieldKeyword: 5197 case SyntaxKind.PrivateIdentifier: 5198 // Yield/await always starts an expression. Either it is an identifier (in which case 5199 // it is definitely an expression). Or it's a keyword (either because we're in 5200 // a generator or async function, or in strict mode (or both)) and it started a yield or await expression. 5201 return true; 5202 case SyntaxKind.DotToken: 5203 return isValidExtendOrStylesContext(); 5204 default: 5205 // Error tolerance. If we see the start of some binary operator, we consider 5206 // that the start of an expression. That way we'll parse out a missing identifier, 5207 // give a good message about an identifier being missing, and then consume the 5208 // rest of the binary expression. 5209 if (isBinaryOperator()) { 5210 return true; 5211 } 5212 5213 return isIdentifier(); 5214 } 5215 } 5216 5217 function isValidExtendOrStylesContext(): boolean { 5218 return (inEtsExtendComponentsContext() && !!extendEtsComponentDeclaration) || 5219 (inEtsStylesComponentsContext() && !!stylesEtsComponentDeclaration); 5220 } 5221 5222 function isStartOfExpressionStatement(): boolean { 5223 // As per the grammar, none of '{' or 'function' or 'class' can start an expression statement. 5224 return token() !== SyntaxKind.OpenBraceToken && 5225 token() !== SyntaxKind.FunctionKeyword && 5226 token() !== SyntaxKind.ClassKeyword && 5227 (!inEtsContext() || token() !== SyntaxKind.StructKeyword) && 5228 token() !== SyntaxKind.AtToken && 5229 isStartOfExpression(); 5230 } 5231 5232 function parseExpression(): Expression { 5233 // Expression[in]: 5234 // AssignmentExpression[in] 5235 // Expression[in] , AssignmentExpression[in] 5236 5237 // clear the decorator context when parsing Expression, as it should be unambiguous when parsing a decorator 5238 const saveDecoratorContext = inDecoratorContext(); 5239 if (saveDecoratorContext) { 5240 setDecoratorContext(/*val*/ false); 5241 } 5242 5243 const pos = getNodePos(); 5244 let expr = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true); 5245 let operatorToken: BinaryOperatorToken; 5246 while ((operatorToken = parseOptionalToken(SyntaxKind.CommaToken))) { 5247 expr = makeBinaryExpression(expr, operatorToken, parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true), pos); 5248 } 5249 5250 if (saveDecoratorContext) { 5251 setDecoratorContext(/*val*/ true); 5252 } 5253 return expr; 5254 } 5255 5256 function parseInitializer(): Expression | undefined { 5257 return parseOptional(SyntaxKind.EqualsToken) ? parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true) : undefined; 5258 } 5259 5260 function parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction: boolean): Expression { 5261 // AssignmentExpression[in,yield]: 5262 // 1) ConditionalExpression[?in,?yield] 5263 // 2) LeftHandSideExpression = AssignmentExpression[?in,?yield] 5264 // 3) LeftHandSideExpression AssignmentOperator AssignmentExpression[?in,?yield] 5265 // 4) ArrowFunctionExpression[?in,?yield] 5266 // 5) AsyncArrowFunctionExpression[in,yield,await] 5267 // 6) [+Yield] YieldExpression[?In] 5268 // 5269 // Note: for ease of implementation we treat productions '2' and '3' as the same thing. 5270 // (i.e. they're both BinaryExpressions with an assignment operator in it). 5271 5272 // First, do the simple check if we have a YieldExpression (production '6'). 5273 if (isYieldExpression()) { 5274 return parseYieldExpression(); 5275 } 5276 5277 // Then, check if we have an arrow function (production '4' and '5') that starts with a parenthesized 5278 // parameter list or is an async arrow function. 5279 // AsyncArrowFunctionExpression: 5280 // 1) async[no LineTerminator here]AsyncArrowBindingIdentifier[?Yield][no LineTerminator here]=>AsyncConciseBody[?In] 5281 // 2) CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await][no LineTerminator here]=>AsyncConciseBody[?In] 5282 // Production (1) of AsyncArrowFunctionExpression is parsed in "tryParseAsyncSimpleArrowFunctionExpression". 5283 // And production (2) is parsed in "tryParseParenthesizedArrowFunctionExpression". 5284 // 5285 // If we do successfully parse arrow-function, we must *not* recurse for productions 1, 2 or 3. An ArrowFunction is 5286 // not a LeftHandSideExpression, nor does it start a ConditionalExpression. So we are done 5287 // with AssignmentExpression if we see one. 5288 const arrowExpression = tryParseParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction) || tryParseAsyncSimpleArrowFunctionExpression(allowReturnTypeInArrowFunction); 5289 if (arrowExpression) { 5290 return arrowExpression; 5291 } 5292 5293 // Now try to see if we're in production '1', '2' or '3'. A conditional expression can 5294 // start with a LogicalOrExpression, while the assignment productions can only start with 5295 // LeftHandSideExpressions. 5296 // 5297 // So, first, we try to just parse out a BinaryExpression. If we get something that is a 5298 // LeftHandSide or higher, then we can try to parse out the assignment expression part. 5299 // Otherwise, we try to parse out the conditional expression bit. We want to allow any 5300 // binary expression here, so we pass in the 'lowest' precedence here so that it matches 5301 // and consumes anything. 5302 const pos = getNodePos(); 5303 const expr = parseBinaryExpressionOrHigher(OperatorPrecedence.Lowest); 5304 5305 // To avoid a look-ahead, we did not handle the case of an arrow function with a single un-parenthesized 5306 // parameter ('x => ...') above. We handle it here by checking if the parsed expression was a single 5307 // identifier and the current token is an arrow. 5308 if (expr.kind === SyntaxKind.Identifier && token() === SyntaxKind.EqualsGreaterThanToken) { 5309 return parseSimpleArrowFunctionExpression(pos, expr as Identifier, allowReturnTypeInArrowFunction, /*asyncModifier*/ undefined); 5310 } 5311 5312 // Now see if we might be in cases '2' or '3'. 5313 // If the expression was a LHS expression, and we have an assignment operator, then 5314 // we're in '2' or '3'. Consume the assignment and return. 5315 // 5316 // Note: we call reScanGreaterToken so that we get an appropriately merged token 5317 // for cases like `> > =` becoming `>>=` 5318 if (isLeftHandSideExpression(expr) && isAssignmentOperator(reScanGreaterToken())) { 5319 return makeBinaryExpression(expr, parseTokenNode(), parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction), pos); 5320 } 5321 5322 // It's a CallExpression with open brace followed, therefore, we think it's an EtsComponentExpression 5323 if ((inBuildContext() || inBuilderContext()) && inUICallbackContext() && isCallExpression(expr) && token() === SyntaxKind.OpenBraceToken) { 5324 return makeEtsComponentExpression(expr, pos); 5325 } 5326 5327 // It wasn't an assignment or a lambda. This is a conditional expression: 5328 return parseConditionalExpressionRest(expr, pos, allowReturnTypeInArrowFunction); 5329 } 5330 5331 function makeEtsComponentExpression(expression: Expression, pos: number): EtsComponentExpression { 5332 const name = (<CallExpression>expression).expression; 5333 const body = parseFunctionBlock(SignatureFlags.None); 5334 return finishNode(factory.createEtsComponentExpression(<Identifier>name, (<CallExpression>expression).arguments, body), pos); 5335 } 5336 5337 function isYieldExpression(): boolean { 5338 if (token() === SyntaxKind.YieldKeyword) { 5339 // If we have a 'yield' keyword, and this is a context where yield expressions are 5340 // allowed, then definitely parse out a yield expression. 5341 if (inYieldContext()) { 5342 return true; 5343 } 5344 5345 // We're in a context where 'yield expr' is not allowed. However, if we can 5346 // definitely tell that the user was trying to parse a 'yield expr' and not 5347 // just a normal expr that start with a 'yield' identifier, then parse out 5348 // a 'yield expr'. We can then report an error later that they are only 5349 // allowed in generator expressions. 5350 // 5351 // for example, if we see 'yield(foo)', then we'll have to treat that as an 5352 // invocation expression of something called 'yield'. However, if we have 5353 // 'yield foo' then that is not legal as a normal expression, so we can 5354 // definitely recognize this as a yield expression. 5355 // 5356 // for now we just check if the next token is an identifier. More heuristics 5357 // can be added here later as necessary. We just need to make sure that we 5358 // don't accidentally consume something legal. 5359 return lookAhead(nextTokenIsIdentifierOrKeywordOrLiteralOnSameLine); 5360 } 5361 5362 return false; 5363 } 5364 5365 function nextTokenIsIdentifierOnSameLine() { 5366 nextToken(); 5367 return !scanner.hasPrecedingLineBreak() && isIdentifier(); 5368 } 5369 5370 function parseYieldExpression(): YieldExpression { 5371 const pos = getNodePos(); 5372 5373 // YieldExpression[In] : 5374 // yield 5375 // yield [no LineTerminator here] [Lexical goal InputElementRegExp]AssignmentExpression[?In, Yield] 5376 // yield [no LineTerminator here] * [Lexical goal InputElementRegExp]AssignmentExpression[?In, Yield] 5377 nextToken(); 5378 5379 if (!scanner.hasPrecedingLineBreak() && 5380 (token() === SyntaxKind.AsteriskToken || isStartOfExpression())) { 5381 return finishNode( 5382 factory.createYieldExpression( 5383 parseOptionalToken(SyntaxKind.AsteriskToken), 5384 parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true) 5385 ), 5386 pos 5387 ); 5388 } 5389 else { 5390 // if the next token is not on the same line as yield. or we don't have an '*' or 5391 // the start of an expression, then this is just a simple "yield" expression. 5392 return finishNode(factory.createYieldExpression(/*asteriskToken*/ undefined, /*expression*/ undefined), pos); 5393 } 5394 } 5395 5396 function parseSimpleArrowFunctionExpression(pos: number, identifier: Identifier, allowReturnTypeInArrowFunction: boolean, asyncModifier?: NodeArray<Modifier> | undefined): ArrowFunction { 5397 Debug.assert(token() === SyntaxKind.EqualsGreaterThanToken, "parseSimpleArrowFunctionExpression should only have been called if we had a =>"); 5398 const parameter = factory.createParameterDeclaration( 5399 /*modifiers*/ undefined, 5400 /*dotDotDotToken*/ undefined, 5401 identifier, 5402 /*questionToken*/ undefined, 5403 /*type*/ undefined, 5404 /*initializer*/ undefined 5405 ); 5406 finishNode(parameter, identifier.pos); 5407 5408 const parameters = createNodeArray<ParameterDeclaration>([parameter], parameter.pos, parameter.end); 5409 const equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken); 5410 let originUIContextFlag = inUICallbackContext(); 5411 let originNoEtsComponentContextFlag = inNoEtsComponentContext(); 5412 setUICallbackContext(inSyntaxComponentContext() && !inSyntaxDataSourceContext()); 5413 if (inSyntaxComponentContext() && !inSyntaxDataSourceContext()) { 5414 setSyntaxComponentContext(false); 5415 } 5416 setNoEtsComponentContext(!inUICallbackContext()); 5417 const body = parseArrowFunctionExpressionBody(/*isAsync*/ !!asyncModifier, allowReturnTypeInArrowFunction); 5418 const node = factory.createArrowFunction(asyncModifier, /*typeParameters*/ undefined, parameters, /*type*/ undefined, equalsGreaterThanToken, body); 5419 setUICallbackContext(originUIContextFlag); 5420 setNoEtsComponentContext(originNoEtsComponentContextFlag); 5421 return addJSDocComment(finishNode(node, pos)); 5422 } 5423 5424 function tryParseParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction: boolean): Expression | undefined { 5425 const triState = isParenthesizedArrowFunctionExpression(); 5426 if (triState === Tristate.False) { 5427 // It's definitely not a parenthesized arrow function expression. 5428 return undefined; 5429 } 5430 5431 // If we definitely have an arrow function, then we can just parse one, not requiring a 5432 // following => or { token. Otherwise, we *might* have an arrow function. Try to parse 5433 // it out, but don't allow any ambiguity, and return 'undefined' if this could be an 5434 // expression instead. 5435 return triState === Tristate.True ? 5436 parseParenthesizedArrowFunctionExpression(/*allowAmbiguity*/ true, /*allowReturnTypeInArrowFunction*/ true) : 5437 tryParse(() => parsePossibleParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction)); 5438 } 5439 5440 // True -> We definitely expect a parenthesized arrow function here. 5441 // False -> There *cannot* be a parenthesized arrow function here. 5442 // Unknown -> There *might* be a parenthesized arrow function here. 5443 // Speculatively look ahead to be sure, and rollback if not. 5444 function isParenthesizedArrowFunctionExpression(): Tristate { 5445 if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken || token() === SyntaxKind.AsyncKeyword) { 5446 return lookAhead(isParenthesizedArrowFunctionExpressionWorker); 5447 } 5448 5449 if (token() === SyntaxKind.EqualsGreaterThanToken) { 5450 // ERROR RECOVERY TWEAK: 5451 // If we see a standalone => try to parse it as an arrow function expression as that's 5452 // likely what the user intended to write. 5453 return Tristate.True; 5454 } 5455 // Definitely not a parenthesized arrow function. 5456 return Tristate.False; 5457 } 5458 5459 function isParenthesizedArrowFunctionExpressionWorker() { 5460 if (token() === SyntaxKind.AsyncKeyword) { 5461 nextToken(); 5462 if (scanner.hasPrecedingLineBreak()) { 5463 return Tristate.False; 5464 } 5465 if (token() !== SyntaxKind.OpenParenToken && token() !== SyntaxKind.LessThanToken) { 5466 return Tristate.False; 5467 } 5468 } 5469 5470 const first = token(); 5471 const second = nextToken(); 5472 5473 if (first === SyntaxKind.OpenParenToken) { 5474 if (second === SyntaxKind.CloseParenToken) { 5475 // Simple cases: "() =>", "(): ", and "() {". 5476 // This is an arrow function with no parameters. 5477 // The last one is not actually an arrow function, 5478 // but this is probably what the user intended. 5479 const third = nextToken(); 5480 switch (third) { 5481 case SyntaxKind.EqualsGreaterThanToken: 5482 case SyntaxKind.ColonToken: 5483 case SyntaxKind.OpenBraceToken: 5484 return Tristate.True; 5485 default: 5486 return Tristate.False; 5487 } 5488 } 5489 5490 // If encounter "([" or "({", this could be the start of a binding pattern. 5491 // Examples: 5492 // ([ x ]) => { } 5493 // ({ x }) => { } 5494 // ([ x ]) 5495 // ({ x }) 5496 if (second === SyntaxKind.OpenBracketToken || second === SyntaxKind.OpenBraceToken) { 5497 return Tristate.Unknown; 5498 } 5499 5500 // Simple case: "(..." 5501 // This is an arrow function with a rest parameter. 5502 if (second === SyntaxKind.DotDotDotToken) { 5503 return Tristate.True; 5504 } 5505 5506 // Check for "(xxx yyy", where xxx is a modifier and yyy is an identifier. This 5507 // isn't actually allowed, but we want to treat it as a lambda so we can provide 5508 // a good error message. 5509 if (isModifierKind(second) && second !== SyntaxKind.AsyncKeyword && lookAhead(nextTokenIsIdentifier)) { 5510 if (nextToken() === SyntaxKind.AsKeyword) { 5511 // https://github.com/microsoft/TypeScript/issues/44466 5512 return Tristate.False; 5513 } 5514 return Tristate.True; 5515 } 5516 5517 // If we had "(" followed by something that's not an identifier, 5518 // then this definitely doesn't look like a lambda. "this" is not 5519 // valid, but we want to parse it and then give a semantic error. 5520 if (!isIdentifier() && second !== SyntaxKind.ThisKeyword) { 5521 return Tristate.False; 5522 } 5523 5524 switch (nextToken()) { 5525 case SyntaxKind.ColonToken: 5526 // If we have something like "(a:", then we must have a 5527 // type-annotated parameter in an arrow function expression. 5528 return Tristate.True; 5529 case SyntaxKind.QuestionToken: 5530 nextToken(); 5531 // If we have "(a?:" or "(a?," or "(a?=" or "(a?)" then it is definitely a lambda. 5532 if (token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken || token() === SyntaxKind.EqualsToken || token() === SyntaxKind.CloseParenToken) { 5533 return Tristate.True; 5534 } 5535 // Otherwise it is definitely not a lambda. 5536 return Tristate.False; 5537 case SyntaxKind.CommaToken: 5538 case SyntaxKind.EqualsToken: 5539 case SyntaxKind.CloseParenToken: 5540 // If we have "(a," or "(a=" or "(a)" this *could* be an arrow function 5541 return Tristate.Unknown; 5542 } 5543 // It is definitely not an arrow function 5544 return Tristate.False; 5545 } 5546 else { 5547 Debug.assert(first === SyntaxKind.LessThanToken); 5548 5549 // If we have "<" not followed by an identifier, 5550 // then this definitely is not an arrow function. 5551 if (!isIdentifier()) { 5552 return Tristate.False; 5553 } 5554 5555 // JSX overrides 5556 if (languageVariant === LanguageVariant.JSX) { 5557 const isArrowFunctionInJsx = lookAhead(() => { 5558 const third = nextToken(); 5559 if (third === SyntaxKind.ExtendsKeyword) { 5560 const fourth = nextToken(); 5561 switch (fourth) { 5562 case SyntaxKind.EqualsToken: 5563 case SyntaxKind.GreaterThanToken: 5564 return false; 5565 default: 5566 return true; 5567 } 5568 } 5569 else if (third === SyntaxKind.CommaToken || third === SyntaxKind.EqualsToken) { 5570 return true; 5571 } 5572 return false; 5573 }); 5574 5575 if (isArrowFunctionInJsx) { 5576 return Tristate.True; 5577 } 5578 5579 return Tristate.False; 5580 } 5581 5582 // This *could* be a parenthesized arrow function. 5583 return Tristate.Unknown; 5584 } 5585 } 5586 5587 function parsePossibleParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction: boolean): ArrowFunction | undefined { 5588 const tokenPos = scanner.getTokenPos(); 5589 if (notParenthesizedArrow?.has(tokenPos)) { 5590 return undefined; 5591 } 5592 5593 const result = parseParenthesizedArrowFunctionExpression(/*allowAmbiguity*/ false, allowReturnTypeInArrowFunction); 5594 if (!result) { 5595 (notParenthesizedArrow || (notParenthesizedArrow = new Set())).add(tokenPos); 5596 } 5597 5598 return result; 5599 } 5600 5601 function tryParseAsyncSimpleArrowFunctionExpression(allowReturnTypeInArrowFunction: boolean): ArrowFunction | undefined { 5602 // We do a check here so that we won't be doing unnecessarily call to "lookAhead" 5603 if (token() === SyntaxKind.AsyncKeyword) { 5604 if (lookAhead(isUnParenthesizedAsyncArrowFunctionWorker) === Tristate.True) { 5605 const pos = getNodePos(); 5606 const asyncModifier = parseModifiersForArrowFunction(); 5607 const expr = parseBinaryExpressionOrHigher(OperatorPrecedence.Lowest); 5608 return parseSimpleArrowFunctionExpression(pos, expr as Identifier, allowReturnTypeInArrowFunction, asyncModifier); 5609 } 5610 } 5611 return undefined; 5612 } 5613 5614 function isUnParenthesizedAsyncArrowFunctionWorker(): Tristate { 5615 // AsyncArrowFunctionExpression: 5616 // 1) async[no LineTerminator here]AsyncArrowBindingIdentifier[?Yield][no LineTerminator here]=>AsyncConciseBody[?In] 5617 // 2) CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await][no LineTerminator here]=>AsyncConciseBody[?In] 5618 if (token() === SyntaxKind.AsyncKeyword) { 5619 nextToken(); 5620 // If the "async" is followed by "=>" token then it is not a beginning of an async arrow-function 5621 // but instead a simple arrow-function which will be parsed inside "parseAssignmentExpressionOrHigher" 5622 if (scanner.hasPrecedingLineBreak() || token() === SyntaxKind.EqualsGreaterThanToken) { 5623 return Tristate.False; 5624 } 5625 // Check for un-parenthesized AsyncArrowFunction 5626 const expr = parseBinaryExpressionOrHigher(OperatorPrecedence.Lowest); 5627 if (!scanner.hasPrecedingLineBreak() && expr.kind === SyntaxKind.Identifier && token() === SyntaxKind.EqualsGreaterThanToken) { 5628 return Tristate.True; 5629 } 5630 } 5631 5632 return Tristate.False; 5633 } 5634 5635 function parseParenthesizedArrowFunctionExpression(allowAmbiguity: boolean, allowReturnTypeInArrowFunction: boolean): ArrowFunction | undefined { 5636 const pos = getNodePos(); 5637 const hasJSDoc = hasPrecedingJSDocComment(); 5638 const modifiers = parseModifiersForArrowFunction(); 5639 const isAsync = some(modifiers, isAsyncModifier) ? SignatureFlags.Await : SignatureFlags.None; 5640 // Arrow functions are never generators. 5641 // 5642 // If we're speculatively parsing a signature for a parenthesized arrow function, then 5643 // we have to have a complete parameter list. Otherwise we might see something like 5644 // a => (b => c) 5645 // And think that "(b =>" was actually a parenthesized arrow function with a missing 5646 // close paren. 5647 const typeParameters = parseTypeParameters(); 5648 5649 let parameters: NodeArray<ParameterDeclaration>; 5650 if (!parseExpected(SyntaxKind.OpenParenToken)) { 5651 if (!allowAmbiguity) { 5652 return undefined; 5653 } 5654 parameters = createMissingList<ParameterDeclaration>(); 5655 } 5656 else { 5657 if (!allowAmbiguity) { 5658 const maybeParameters = parseParametersWorker(isAsync, allowAmbiguity); 5659 if (!maybeParameters) { 5660 return undefined; 5661 } 5662 parameters = maybeParameters; 5663 } 5664 else { 5665 parameters = parseParametersWorker(isAsync, allowAmbiguity); 5666 } 5667 if (!parseExpected(SyntaxKind.CloseParenToken) && !allowAmbiguity) { 5668 return undefined; 5669 } 5670 } 5671 5672 const hasReturnColon = token() === SyntaxKind.ColonToken; 5673 const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false); 5674 if (type && !allowAmbiguity && typeHasArrowFunctionBlockingParseError(type)) { 5675 return undefined; 5676 } 5677 5678 // Parsing a signature isn't enough. 5679 // Parenthesized arrow signatures often look like other valid expressions. 5680 // For instance: 5681 // - "(x = 10)" is an assignment expression parsed as a signature with a default parameter value. 5682 // - "(x,y)" is a comma expression parsed as a signature with two parameters. 5683 // - "a ? (b): c" will have "(b):" parsed as a signature with a return type annotation. 5684 // - "a ? (b): function() {}" will too, since function() is a valid JSDoc function type. 5685 // - "a ? (b): (function() {})" as well, but inside of a parenthesized type with an arbitrary amount of nesting. 5686 // 5687 // So we need just a bit of lookahead to ensure that it can only be a signature. 5688 5689 let unwrappedType = type; 5690 while (unwrappedType?.kind === SyntaxKind.ParenthesizedType) { 5691 unwrappedType = (unwrappedType as ParenthesizedTypeNode).type; // Skip parens if need be 5692 } 5693 5694 const hasJSDocFunctionType = unwrappedType && isJSDocFunctionType(unwrappedType); 5695 if (!allowAmbiguity && token() !== SyntaxKind.EqualsGreaterThanToken && (hasJSDocFunctionType || token() !== SyntaxKind.OpenBraceToken)) { 5696 // Returning undefined here will cause our caller to rewind to where we started from. 5697 return undefined; 5698 } 5699 5700 // If we have an arrow, then try to parse the body. Even if not, try to parse if we 5701 // have an opening brace, just in case we're in an error state. 5702 const lastToken = token(); 5703 const equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken); 5704 let originUIContextFlag = inUICallbackContext(); 5705 let originNoEtsComponentContextFlag = inNoEtsComponentContext(); 5706 setUICallbackContext(inSyntaxComponentContext() && !inSyntaxDataSourceContext()); 5707 if (inSyntaxComponentContext() && !inSyntaxDataSourceContext()) { 5708 setSyntaxComponentContext(false); 5709 } 5710 setNoEtsComponentContext(!inUICallbackContext()); 5711 const body = (lastToken === SyntaxKind.EqualsGreaterThanToken || lastToken === SyntaxKind.OpenBraceToken) 5712 ? parseArrowFunctionExpressionBody(some(modifiers, isAsyncModifier), allowReturnTypeInArrowFunction) 5713 : parseIdentifier(); 5714 setUICallbackContext(originUIContextFlag); 5715 setNoEtsComponentContext(originNoEtsComponentContextFlag); 5716 // Given: 5717 // x ? y => ({ y }) : z => ({ z }) 5718 // We try to parse the body of the first arrow function by looking at: 5719 // ({ y }) : z => ({ z }) 5720 // This is a valid arrow function with "z" as the return type. 5721 // 5722 // But, if we're in the true side of a conditional expression, this colon 5723 // terminates the expression, so we cannot allow a return type if we aren't 5724 // certain whether or not the preceding text was parsed as a parameter list. 5725 // 5726 // For example, 5727 // a() ? (b: number, c?: string): void => d() : e 5728 // is determined by isParenthesizedArrowFunctionExpression to unambiguously 5729 // be an arrow expression, so we allow a return type. 5730 if (!allowReturnTypeInArrowFunction && hasReturnColon) { 5731 // However, if the arrow function we were able to parse is followed by another colon 5732 // as in: 5733 // a ? (x): string => x : null 5734 // Then allow the arrow function, and treat the second colon as terminating 5735 // the conditional expression. It's okay to do this because this code would 5736 // be a syntax error in JavaScript (as the second colon shouldn't be there). 5737 if (token() !== SyntaxKind.ColonToken) { 5738 return undefined; 5739 } 5740 } 5741 5742 const node = factory.createArrowFunction(modifiers, typeParameters, parameters, type, equalsGreaterThanToken, body); 5743 return withJSDoc(finishNode(node, pos), hasJSDoc); 5744 } 5745 5746 function parseArrowFunctionExpressionBody(isAsync: boolean, allowReturnTypeInArrowFunction: boolean): Block | Expression { 5747 if (token() === SyntaxKind.OpenBraceToken) { 5748 return parseFunctionBlock(isAsync ? SignatureFlags.Await : SignatureFlags.None); 5749 } 5750 5751 if (token() !== SyntaxKind.SemicolonToken && 5752 token() !== SyntaxKind.FunctionKeyword && 5753 token() !== SyntaxKind.ClassKeyword && 5754 (!inEtsContext() || token() !== SyntaxKind.StructKeyword) && 5755 isStartOfStatement() && 5756 !isStartOfExpressionStatement()) { 5757 // Check if we got a plain statement (i.e. no expression-statements, no function/class expressions/declarations) 5758 // 5759 // Here we try to recover from a potential error situation in the case where the 5760 // user meant to supply a block. For example, if the user wrote: 5761 // 5762 // a => 5763 // let v = 0; 5764 // } 5765 // 5766 // they may be missing an open brace. Check to see if that's the case so we can 5767 // try to recover better. If we don't do this, then the next close curly we see may end 5768 // up preemptively closing the containing construct. 5769 // 5770 // Note: even when 'IgnoreMissingOpenBrace' is passed, parseBody will still error. 5771 return parseFunctionBlock(SignatureFlags.IgnoreMissingOpenBrace | (isAsync ? SignatureFlags.Await : SignatureFlags.None)); 5772 } 5773 5774 const savedTopLevel = topLevel; 5775 topLevel = false; 5776 const node = isAsync 5777 ? doInAwaitContext(() => parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction)) 5778 : doOutsideOfAwaitContext(() => parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction)); 5779 topLevel = savedTopLevel; 5780 return node; 5781 } 5782 5783 function parseConditionalExpressionRest(leftOperand: Expression, pos: number, allowReturnTypeInArrowFunction: boolean): Expression { 5784 // Note: we are passed in an expression which was produced from parseBinaryExpressionOrHigher. 5785 const questionToken = parseOptionalToken(SyntaxKind.QuestionToken); 5786 if (!questionToken) { 5787 return leftOperand; 5788 } 5789 5790 // Note: we explicitly 'allowIn' in the whenTrue part of the condition expression, and 5791 // we do not that for the 'whenFalse' part. 5792 let colonToken; 5793 return finishNode( 5794 factory.createConditionalExpression( 5795 leftOperand, 5796 questionToken, 5797 doOutsideOfContext(disallowInAndDecoratorContext, () => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ false)), 5798 colonToken = parseExpectedToken(SyntaxKind.ColonToken), 5799 nodeIsPresent(colonToken) 5800 ? parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction) 5801 : createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, tokenToString(SyntaxKind.ColonToken)) 5802 ), 5803 pos 5804 ); 5805 } 5806 5807 function parseBinaryExpressionOrHigher(precedence: OperatorPrecedence): Expression { 5808 const pos = getNodePos(); 5809 const leftOperand = parseUnaryExpressionOrHigher(); 5810 return parseBinaryExpressionRest(precedence, leftOperand, pos); 5811 } 5812 5813 function isInOrOfKeyword(t: SyntaxKind) { 5814 return t === SyntaxKind.InKeyword || t === SyntaxKind.OfKeyword; 5815 } 5816 5817 function parseBinaryExpressionRest(precedence: OperatorPrecedence, leftOperand: Expression, pos: number): Expression { 5818 while (true) { 5819 // We either have a binary operator here, or we're finished. We call 5820 // reScanGreaterToken so that we merge token sequences like > and = into >= 5821 5822 reScanGreaterToken(); 5823 const newPrecedence = getBinaryOperatorPrecedence(token()); 5824 5825 // Check the precedence to see if we should "take" this operator 5826 // - For left associative operator (all operator but **), consume the operator, 5827 // recursively call the function below, and parse binaryExpression as a rightOperand 5828 // of the caller if the new precedence of the operator is greater then or equal to the current precedence. 5829 // For example: 5830 // a - b - c; 5831 // ^token; leftOperand = b. Return b to the caller as a rightOperand 5832 // a * b - c 5833 // ^token; leftOperand = b. Return b to the caller as a rightOperand 5834 // a - b * c; 5835 // ^token; leftOperand = b. Return b * c to the caller as a rightOperand 5836 // - For right associative operator (**), consume the operator, recursively call the function 5837 // and parse binaryExpression as a rightOperand of the caller if the new precedence of 5838 // the operator is strictly grater than the current precedence 5839 // For example: 5840 // a ** b ** c; 5841 // ^^token; leftOperand = b. Return b ** c to the caller as a rightOperand 5842 // a - b ** c; 5843 // ^^token; leftOperand = b. Return b ** c to the caller as a rightOperand 5844 // a ** b - c 5845 // ^token; leftOperand = b. Return b to the caller as a rightOperand 5846 const consumeCurrentOperator = token() === SyntaxKind.AsteriskAsteriskToken ? 5847 newPrecedence >= precedence : 5848 newPrecedence > precedence; 5849 5850 if (!consumeCurrentOperator) { 5851 break; 5852 } 5853 5854 if (token() === SyntaxKind.InKeyword && inDisallowInContext()) { 5855 break; 5856 } 5857 5858 if (token() === SyntaxKind.AsKeyword || token() === SyntaxKind.SatisfiesKeyword) { 5859 // Make sure we *do* perform ASI for constructs like this: 5860 // var x = foo 5861 // as (Bar) 5862 // This should be parsed as an initialized variable, followed 5863 // by a function call to 'as' with the argument 'Bar' 5864 if (scanner.hasPrecedingLineBreak()) { 5865 break; 5866 } 5867 else { 5868 const keywordKind = token(); 5869 nextToken(); 5870 leftOperand = keywordKind === SyntaxKind.SatisfiesKeyword ? makeSatisfiesExpression(leftOperand, parseType()) : 5871 makeAsExpression(leftOperand, parseType()); 5872 } 5873 } 5874 else { 5875 leftOperand = makeBinaryExpression(leftOperand, parseTokenNode(), parseBinaryExpressionOrHigher(newPrecedence), pos); 5876 } 5877 } 5878 5879 return leftOperand; 5880 } 5881 5882 function isBinaryOperator() { 5883 if (inDisallowInContext() && token() === SyntaxKind.InKeyword) { 5884 return false; 5885 } 5886 5887 return getBinaryOperatorPrecedence(token()) > 0; 5888 } 5889 5890 function makeSatisfiesExpression(left: Expression, right: TypeNode): SatisfiesExpression { 5891 return finishNode(factory.createSatisfiesExpression(left, right), left.pos); 5892 } 5893 5894 function makeBinaryExpression(left: Expression, operatorToken: BinaryOperatorToken, right: Expression, pos: number): BinaryExpression { 5895 return finishNode(factory.createBinaryExpression(left, operatorToken, right), pos); 5896 } 5897 5898 function makeAsExpression(left: Expression, right: TypeNode): AsExpression { 5899 return finishNode(factory.createAsExpression(left, right), left.pos); 5900 } 5901 5902 function parsePrefixUnaryExpression() { 5903 const pos = getNodePos(); 5904 return finishNode(factory.createPrefixUnaryExpression(token() as PrefixUnaryOperator, nextTokenAnd(parseSimpleUnaryExpression)), pos); 5905 } 5906 5907 function parseDeleteExpression() { 5908 const pos = getNodePos(); 5909 return finishNode(factory.createDeleteExpression(nextTokenAnd(parseSimpleUnaryExpression)), pos); 5910 } 5911 5912 function parseTypeOfExpression() { 5913 const pos = getNodePos(); 5914 return finishNode(factory.createTypeOfExpression(nextTokenAnd(parseSimpleUnaryExpression)), pos); 5915 } 5916 5917 function parseVoidExpression() { 5918 const pos = getNodePos(); 5919 return finishNode(factory.createVoidExpression(nextTokenAnd(parseSimpleUnaryExpression)), pos); 5920 } 5921 5922 function isAwaitExpression(): boolean { 5923 if (token() === SyntaxKind.AwaitKeyword) { 5924 if (inAwaitContext()) { 5925 return true; 5926 } 5927 5928 // here we are using similar heuristics as 'isYieldExpression' 5929 return lookAhead(nextTokenIsIdentifierOrKeywordOrLiteralOnSameLine); 5930 } 5931 5932 return false; 5933 } 5934 5935 function parseAwaitExpression() { 5936 const pos = getNodePos(); 5937 return finishNode(factory.createAwaitExpression(nextTokenAnd(parseSimpleUnaryExpression)), pos); 5938 } 5939 5940 /** 5941 * Parse ES7 exponential expression and await expression 5942 * 5943 * ES7 ExponentiationExpression: 5944 * 1) UnaryExpression[?Yield] 5945 * 2) UpdateExpression[?Yield] ** ExponentiationExpression[?Yield] 5946 * 5947 */ 5948 function parseUnaryExpressionOrHigher(): UnaryExpression | BinaryExpression { 5949 /** 5950 * ES7 UpdateExpression: 5951 * 1) LeftHandSideExpression[?Yield] 5952 * 2) LeftHandSideExpression[?Yield][no LineTerminator here]++ 5953 * 3) LeftHandSideExpression[?Yield][no LineTerminator here]-- 5954 * 4) ++UnaryExpression[?Yield] 5955 * 5) --UnaryExpression[?Yield] 5956 */ 5957 if (isUpdateExpression()) { 5958 const pos = getNodePos(); 5959 const updateExpression = parseUpdateExpression(); 5960 return token() === SyntaxKind.AsteriskAsteriskToken ? 5961 parseBinaryExpressionRest(getBinaryOperatorPrecedence(token()), updateExpression, pos) as BinaryExpression : 5962 updateExpression; 5963 } 5964 5965 /** 5966 * ES7 UnaryExpression: 5967 * 1) UpdateExpression[?yield] 5968 * 2) delete UpdateExpression[?yield] 5969 * 3) void UpdateExpression[?yield] 5970 * 4) typeof UpdateExpression[?yield] 5971 * 5) + UpdateExpression[?yield] 5972 * 6) - UpdateExpression[?yield] 5973 * 7) ~ UpdateExpression[?yield] 5974 * 8) ! UpdateExpression[?yield] 5975 */ 5976 const unaryOperator = token(); 5977 const simpleUnaryExpression = parseSimpleUnaryExpression(); 5978 if (token() === SyntaxKind.AsteriskAsteriskToken) { 5979 const pos = skipTrivia(sourceText, simpleUnaryExpression.pos); 5980 const { end } = simpleUnaryExpression; 5981 if (simpleUnaryExpression.kind === SyntaxKind.TypeAssertionExpression) { 5982 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); 5983 } 5984 else { 5985 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)); 5986 } 5987 } 5988 return simpleUnaryExpression; 5989 } 5990 5991 /** 5992 * Parse ES7 simple-unary expression or higher: 5993 * 5994 * ES7 UnaryExpression: 5995 * 1) UpdateExpression[?yield] 5996 * 2) delete UnaryExpression[?yield] 5997 * 3) void UnaryExpression[?yield] 5998 * 4) typeof UnaryExpression[?yield] 5999 * 5) + UnaryExpression[?yield] 6000 * 6) - UnaryExpression[?yield] 6001 * 7) ~ UnaryExpression[?yield] 6002 * 8) ! UnaryExpression[?yield] 6003 * 9) [+Await] await UnaryExpression[?yield] 6004 */ 6005 function parseSimpleUnaryExpression(): UnaryExpression { 6006 switch (token()) { 6007 case SyntaxKind.PlusToken: 6008 case SyntaxKind.MinusToken: 6009 case SyntaxKind.TildeToken: 6010 case SyntaxKind.ExclamationToken: 6011 return parsePrefixUnaryExpression(); 6012 case SyntaxKind.DeleteKeyword: 6013 return parseDeleteExpression(); 6014 case SyntaxKind.TypeOfKeyword: 6015 return parseTypeOfExpression(); 6016 case SyntaxKind.VoidKeyword: 6017 return parseVoidExpression(); 6018 case SyntaxKind.LessThanToken: 6019 // This is modified UnaryExpression grammar in TypeScript 6020 // UnaryExpression (modified): 6021 // < type > UnaryExpression 6022 return parseTypeAssertion(); 6023 case SyntaxKind.AwaitKeyword: 6024 if (isAwaitExpression()) { 6025 return parseAwaitExpression(); 6026 } 6027 // falls through 6028 default: 6029 return parseUpdateExpression(); 6030 } 6031 } 6032 6033 /** 6034 * Check if the current token can possibly be an ES7 increment expression. 6035 * 6036 * ES7 UpdateExpression: 6037 * LeftHandSideExpression[?Yield] 6038 * LeftHandSideExpression[?Yield][no LineTerminator here]++ 6039 * LeftHandSideExpression[?Yield][no LineTerminator here]-- 6040 * ++LeftHandSideExpression[?Yield] 6041 * --LeftHandSideExpression[?Yield] 6042 */ 6043 function isUpdateExpression(): boolean { 6044 // This function is called inside parseUnaryExpression to decide 6045 // whether to call parseSimpleUnaryExpression or call parseUpdateExpression directly 6046 switch (token()) { 6047 case SyntaxKind.PlusToken: 6048 case SyntaxKind.MinusToken: 6049 case SyntaxKind.TildeToken: 6050 case SyntaxKind.ExclamationToken: 6051 case SyntaxKind.DeleteKeyword: 6052 case SyntaxKind.TypeOfKeyword: 6053 case SyntaxKind.VoidKeyword: 6054 case SyntaxKind.AwaitKeyword: 6055 return false; 6056 case SyntaxKind.LessThanToken: 6057 // If we are not in JSX context, we are parsing TypeAssertion which is an UnaryExpression 6058 if (languageVariant !== LanguageVariant.JSX) { 6059 return false; 6060 } 6061 // We are in JSX context and the token is part of JSXElement. 6062 // falls through 6063 default: 6064 return true; 6065 } 6066 } 6067 6068 /** 6069 * Parse ES7 UpdateExpression. UpdateExpression is used instead of ES6's PostFixExpression. 6070 * 6071 * ES7 UpdateExpression[yield]: 6072 * 1) LeftHandSideExpression[?yield] 6073 * 2) LeftHandSideExpression[?yield] [[no LineTerminator here]]++ 6074 * 3) LeftHandSideExpression[?yield] [[no LineTerminator here]]-- 6075 * 4) ++LeftHandSideExpression[?yield] 6076 * 5) --LeftHandSideExpression[?yield] 6077 * In TypeScript (2), (3) are parsed as PostfixUnaryExpression. (4), (5) are parsed as PrefixUnaryExpression 6078 */ 6079 function parseUpdateExpression(): UpdateExpression { 6080 if (token() === SyntaxKind.PlusPlusToken || token() === SyntaxKind.MinusMinusToken) { 6081 const pos = getNodePos(); 6082 return finishNode(factory.createPrefixUnaryExpression(token() as PrefixUnaryOperator, nextTokenAnd(parseLeftHandSideExpressionOrHigher)), pos); 6083 } 6084 else if (languageVariant === LanguageVariant.JSX && token() === SyntaxKind.LessThanToken && lookAhead(nextTokenIsIdentifierOrKeywordOrGreaterThan)) { 6085 // JSXElement is part of primaryExpression 6086 return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true); 6087 } 6088 6089 const expression = parseLeftHandSideExpressionOrHigher(); 6090 6091 Debug.assert(isLeftHandSideExpression(expression)); 6092 if ((token() === SyntaxKind.PlusPlusToken || token() === SyntaxKind.MinusMinusToken) && !scanner.hasPrecedingLineBreak()) { 6093 const operator = token() as PostfixUnaryOperator; 6094 nextToken(); 6095 return finishNode(factory.createPostfixUnaryExpression(expression, operator), expression.pos); 6096 } 6097 6098 return expression; 6099 } 6100 6101 function parseLeftHandSideExpressionOrHigher(): LeftHandSideExpression { 6102 // Original Ecma: 6103 // LeftHandSideExpression: See 11.2 6104 // NewExpression 6105 // CallExpression 6106 // 6107 // Our simplification: 6108 // 6109 // LeftHandSideExpression: See 11.2 6110 // MemberExpression 6111 // CallExpression 6112 // 6113 // See comment in parseMemberExpressionOrHigher on how we replaced NewExpression with 6114 // MemberExpression to make our lives easier. 6115 // 6116 // to best understand the below code, it's important to see how CallExpression expands 6117 // out into its own productions: 6118 // 6119 // CallExpression: 6120 // MemberExpression Arguments 6121 // CallExpression Arguments 6122 // CallExpression[Expression] 6123 // CallExpression.IdentifierName 6124 // import (AssignmentExpression) 6125 // super Arguments 6126 // super.IdentifierName 6127 // 6128 // Because of the recursion in these calls, we need to bottom out first. There are three 6129 // bottom out states we can run into: 1) We see 'super' which must start either of 6130 // the last two CallExpression productions. 2) We see 'import' which must start import call. 6131 // 3)we have a MemberExpression which either completes the LeftHandSideExpression, 6132 // or starts the beginning of the first four CallExpression productions. 6133 const pos = getNodePos(); 6134 let expression: MemberExpression; 6135 if (token() === SyntaxKind.ImportKeyword) { 6136 if (lookAhead(nextTokenIsOpenParenOrLessThan)) { 6137 // We don't want to eagerly consume all import keyword as import call expression so we look ahead to find "(" 6138 // For example: 6139 // var foo3 = require("subfolder 6140 // import * as foo1 from "module-from-node 6141 // We want this import to be a statement rather than import call expression 6142 sourceFlags |= NodeFlags.PossiblyContainsDynamicImport; 6143 expression = parseTokenNode<PrimaryExpression>(); 6144 } 6145 else if (lookAhead(nextTokenIsDot)) { 6146 // This is an 'import.*' metaproperty (i.e. 'import.meta') 6147 nextToken(); // advance past the 'import' 6148 nextToken(); // advance past the dot 6149 expression = finishNode(factory.createMetaProperty(SyntaxKind.ImportKeyword, parseIdentifierName()), pos); 6150 sourceFlags |= NodeFlags.PossiblyContainsImportMeta; 6151 } 6152 else { 6153 expression = parseMemberExpressionOrHigher(); 6154 } 6155 } 6156 else { 6157 expression = token() === SyntaxKind.SuperKeyword ? parseSuperExpression() : parseMemberExpressionOrHigher(); 6158 } 6159 6160 // Now, we *may* be complete. However, we might have consumed the start of a 6161 // CallExpression or OptionalExpression. As such, we need to consume the rest 6162 // of it here to be complete. 6163 return parseCallExpressionRest(pos, expression); 6164 } 6165 6166 function parseMemberExpressionOrHigher(): MemberExpression { 6167 // Note: to make our lives simpler, we decompose the NewExpression productions and 6168 // place ObjectCreationExpression and FunctionExpression into PrimaryExpression. 6169 // like so: 6170 // 6171 // PrimaryExpression : See 11.1 6172 // this 6173 // Identifier 6174 // Literal 6175 // ArrayLiteral 6176 // ObjectLiteral 6177 // (Expression) 6178 // FunctionExpression 6179 // new MemberExpression Arguments? 6180 // 6181 // MemberExpression : See 11.2 6182 // PrimaryExpression 6183 // MemberExpression[Expression] 6184 // MemberExpression.IdentifierName 6185 // 6186 // CallExpression : See 11.2 6187 // MemberExpression 6188 // CallExpression Arguments 6189 // CallExpression[Expression] 6190 // CallExpression.IdentifierName 6191 // 6192 // Technically this is ambiguous. i.e. CallExpression defines: 6193 // 6194 // CallExpression: 6195 // CallExpression Arguments 6196 // 6197 // If you see: "new Foo()" 6198 // 6199 // Then that could be treated as a single ObjectCreationExpression, or it could be 6200 // treated as the invocation of "new Foo". We disambiguate that in code (to match 6201 // the original grammar) by making sure that if we see an ObjectCreationExpression 6202 // we always consume arguments if they are there. So we treat "new Foo()" as an 6203 // object creation only, and not at all as an invocation. Another way to think 6204 // about this is that for every "new" that we see, we will consume an argument list if 6205 // it is there as part of the *associated* object creation node. Any additional 6206 // argument lists we see, will become invocation expressions. 6207 // 6208 // Because there are no other places in the grammar now that refer to FunctionExpression 6209 // or ObjectCreationExpression, it is safe to push down into the PrimaryExpression 6210 // production. 6211 // 6212 // Because CallExpression and MemberExpression are left recursive, we need to bottom out 6213 // of the recursion immediately. So we parse out a primary expression to start with. 6214 const pos = getNodePos(); 6215 let expression; 6216 6217 if (inEtsExtendComponentsContext() && extendEtsComponentDeclaration && token() === SyntaxKind.DotToken) { 6218 expression = finishVirtualNode(factory.createIdentifier(extendEtsComponentDeclaration.instance, /*typeArguments*/ undefined, SyntaxKind.Identifier), pos, pos); 6219 } 6220 else if (inEtsStylesComponentsContext() && stylesEtsComponentDeclaration && token() === SyntaxKind.DotToken) { 6221 expression = finishVirtualNode(factory.createIdentifier(stylesEtsComponentDeclaration.instance, /*typeArguments*/ undefined, SyntaxKind.Identifier), pos, pos); 6222 } 6223 else if (inEtsStateStylesContext() && stateStylesRootNode && token() === SyntaxKind.DotToken) { 6224 expression = finishVirtualNode(factory.createIdentifier(`${stateStylesRootNode}Instance`, /*typeArguments*/ undefined, SyntaxKind.Identifier), pos, pos); 6225 } 6226 else { 6227 expression = parsePrimaryExpression(); 6228 } 6229 return parseMemberExpressionRest(pos, expression, /*allowOptionalChain*/ true); 6230 } 6231 6232 function parseSuperExpression(): MemberExpression { 6233 const pos = getNodePos(); 6234 let expression = parseTokenNode<MemberExpression>(); 6235 if (token() === SyntaxKind.LessThanToken) { 6236 const startPos = getNodePos(); 6237 const typeArguments = tryParse(parseTypeArgumentsInExpression); 6238 if (typeArguments !== undefined) { 6239 parseErrorAt(startPos, getNodePos(), Diagnostics.super_may_not_use_type_arguments); 6240 if (!isTemplateStartOfTaggedTemplate()) { 6241 expression = factory.createExpressionWithTypeArguments(expression, typeArguments); 6242 } 6243 } 6244 } 6245 6246 if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.DotToken || token() === SyntaxKind.OpenBracketToken) { 6247 return expression; 6248 } 6249 6250 // If we have seen "super" it must be followed by '(' or '.'. 6251 // If it wasn't then just try to parse out a '.' and report an error. 6252 parseExpectedToken(SyntaxKind.DotToken, Diagnostics.super_must_be_followed_by_an_argument_list_or_member_access); 6253 // private names will never work with `super` (`super.#foo`), but that's a semantic error, not syntactic 6254 return finishNode(factory.createPropertyAccessExpression(expression, parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ true)), pos); 6255 } 6256 6257 function parseJsxElementOrSelfClosingElementOrFragment(inExpressionContext: boolean, topInvalidNodePosition?: number, openingTag?: JsxOpeningElement | JsxOpeningFragment): JsxElement | JsxSelfClosingElement | JsxFragment { 6258 const pos = getNodePos(); 6259 const opening = parseJsxOpeningOrSelfClosingElementOrOpeningFragment(inExpressionContext); 6260 let result: JsxElement | JsxSelfClosingElement | JsxFragment; 6261 if (opening.kind === SyntaxKind.JsxOpeningElement) { 6262 let children = parseJsxChildren(opening); 6263 let closingElement: JsxClosingElement; 6264 6265 const lastChild: JsxChild | undefined = children[children.length - 1]; 6266 if (lastChild?.kind === SyntaxKind.JsxElement 6267 && !tagNamesAreEquivalent(lastChild.openingElement.tagName, lastChild.closingElement.tagName) 6268 && tagNamesAreEquivalent(opening.tagName, lastChild.closingElement.tagName)) { 6269 // when an unclosed JsxOpeningElement incorrectly parses its parent's JsxClosingElement, 6270 // restructure (<div>(...<span>...</div>)) --> (<div>(...<span>...</>)</div>) 6271 // (no need to error; the parent will error) 6272 const end = lastChild.children.end; 6273 const newLast = finishNode(factory.createJsxElement( 6274 lastChild.openingElement, 6275 lastChild.children, 6276 finishNode(factory.createJsxClosingElement(finishNode(factory.createIdentifier(""), end, end)), end, end)), 6277 lastChild.openingElement.pos, 6278 end); 6279 6280 children = createNodeArray([...children.slice(0, children.length - 1), newLast], children.pos, end); 6281 closingElement = lastChild.closingElement; 6282 } 6283 else { 6284 closingElement = parseJsxClosingElement(opening, inExpressionContext); 6285 if (!tagNamesAreEquivalent(opening.tagName, closingElement.tagName)) { 6286 if (openingTag && isJsxOpeningElement(openingTag) && tagNamesAreEquivalent(closingElement.tagName, openingTag.tagName)) { 6287 // opening incorrectly matched with its parent's closing -- put error on opening 6288 parseErrorAtRange(opening.tagName, Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, getTextOfNodeFromSourceText(sourceText, opening.tagName)); 6289 } 6290 else { 6291 // other opening/closing mismatches -- put error on closing 6292 parseErrorAtRange(closingElement.tagName, Diagnostics.Expected_corresponding_JSX_closing_tag_for_0, getTextOfNodeFromSourceText(sourceText, opening.tagName)); 6293 } 6294 } 6295 } 6296 result = finishNode(factory.createJsxElement(opening, children, closingElement), pos); 6297 } 6298 else if (opening.kind === SyntaxKind.JsxOpeningFragment) { 6299 result = finishNode(factory.createJsxFragment(opening, parseJsxChildren(opening), parseJsxClosingFragment(inExpressionContext)), pos); 6300 } 6301 else { 6302 Debug.assert(opening.kind === SyntaxKind.JsxSelfClosingElement); 6303 // Nothing else to do for self-closing elements 6304 result = opening; 6305 } 6306 6307 // If the user writes the invalid code '<div></div><div></div>' in an expression context (i.e. not wrapped in 6308 // an enclosing tag), we'll naively try to parse ^ this as a 'less than' operator and the remainder of the tag 6309 // as garbage, which will cause the formatter to badly mangle the JSX. Perform a speculative parse of a JSX 6310 // element if we see a < token so that we can wrap it in a synthetic binary expression so the formatter 6311 // does less damage and we can report a better error. 6312 // Since JSX elements are invalid < operands anyway, this lookahead parse will only occur in error scenarios 6313 // of one sort or another. 6314 if (inExpressionContext && token() === SyntaxKind.LessThanToken) { 6315 const topBadPos = typeof topInvalidNodePosition === "undefined" ? result.pos : topInvalidNodePosition; 6316 const invalidElement = tryParse(() => parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true, topBadPos)); 6317 if (invalidElement) { 6318 const operatorToken = createMissingNode(SyntaxKind.CommaToken, /*reportAtCurrentPosition*/ false); 6319 setTextRangePosWidth(operatorToken, invalidElement.pos, 0); 6320 parseErrorAt(skipTrivia(sourceText, topBadPos), invalidElement.end, Diagnostics.JSX_expressions_must_have_one_parent_element); 6321 return finishNode(factory.createBinaryExpression(result, operatorToken as Token<SyntaxKind.CommaToken>, invalidElement), pos) as Node as JsxElement; 6322 } 6323 } 6324 6325 return result; 6326 } 6327 6328 function parseJsxText(): JsxText { 6329 const pos = getNodePos(); 6330 const node = factory.createJsxText(scanner.getTokenValue(), currentToken === SyntaxKind.JsxTextAllWhiteSpaces); 6331 currentToken = scanner.scanJsxToken(); 6332 return finishNode(node, pos); 6333 } 6334 6335 function parseJsxChild(openingTag: JsxOpeningElement | JsxOpeningFragment, token: JsxTokenSyntaxKind): JsxChild | undefined { 6336 switch (token) { 6337 case SyntaxKind.EndOfFileToken: 6338 // If we hit EOF, issue the error at the tag that lacks the closing element 6339 // rather than at the end of the file (which is useless) 6340 if (isJsxOpeningFragment(openingTag)) { 6341 parseErrorAtRange(openingTag, Diagnostics.JSX_fragment_has_no_corresponding_closing_tag); 6342 } 6343 else { 6344 // We want the error span to cover only 'Foo.Bar' in < Foo.Bar > 6345 // or to cover only 'Foo' in < Foo > 6346 const tag = openingTag.tagName; 6347 const start = skipTrivia(sourceText, tag.pos); 6348 parseErrorAt(start, tag.end, Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, getTextOfNodeFromSourceText(sourceText, openingTag.tagName)); 6349 } 6350 return undefined; 6351 case SyntaxKind.LessThanSlashToken: 6352 case SyntaxKind.ConflictMarkerTrivia: 6353 return undefined; 6354 case SyntaxKind.JsxText: 6355 case SyntaxKind.JsxTextAllWhiteSpaces: 6356 return parseJsxText(); 6357 case SyntaxKind.OpenBraceToken: 6358 return parseJsxExpression(/*inExpressionContext*/ false); 6359 case SyntaxKind.LessThanToken: 6360 return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ false, /*topInvalidNodePosition*/ undefined, openingTag); 6361 default: 6362 return Debug.assertNever(token); 6363 } 6364 } 6365 6366 function parseJsxChildren(openingTag: JsxOpeningElement | JsxOpeningFragment): NodeArray<JsxChild> { 6367 const list = []; 6368 const listPos = getNodePos(); 6369 const saveParsingContext = parsingContext; 6370 parsingContext |= 1 << ParsingContext.JsxChildren; 6371 6372 while (true) { 6373 const child = parseJsxChild(openingTag, currentToken = scanner.reScanJsxToken()); 6374 if (!child) break; 6375 list.push(child); 6376 if (isJsxOpeningElement(openingTag) 6377 && child?.kind === SyntaxKind.JsxElement 6378 && !tagNamesAreEquivalent(child.openingElement.tagName, child.closingElement.tagName) 6379 && tagNamesAreEquivalent(openingTag.tagName, child.closingElement.tagName)) { 6380 // stop after parsing a mismatched child like <div>...(<span></div>) in order to reattach the </div> higher 6381 break; 6382 } 6383 } 6384 6385 parsingContext = saveParsingContext; 6386 return createNodeArray(list, listPos); 6387 } 6388 6389 function parseJsxAttributes(): JsxAttributes { 6390 const pos = getNodePos(); 6391 return finishNode(factory.createJsxAttributes(parseList(ParsingContext.JsxAttributes, parseJsxAttribute)), pos); 6392 } 6393 6394 function parseJsxOpeningOrSelfClosingElementOrOpeningFragment(inExpressionContext: boolean): JsxOpeningElement | JsxSelfClosingElement | JsxOpeningFragment { 6395 const pos = getNodePos(); 6396 6397 parseExpected(SyntaxKind.LessThanToken); 6398 6399 if (token() === SyntaxKind.GreaterThanToken) { 6400 // See below for explanation of scanJsxText 6401 scanJsxText(); 6402 return finishNode(factory.createJsxOpeningFragment(), pos); 6403 } 6404 const tagName = parseJsxElementName(); 6405 const typeArguments = (contextFlags & NodeFlags.JavaScriptFile) === 0 ? tryParseTypeArguments() : undefined; 6406 const attributes = parseJsxAttributes(); 6407 6408 let node: JsxOpeningLikeElement; 6409 6410 if (token() === SyntaxKind.GreaterThanToken) { 6411 // Closing tag, so scan the immediately-following text with the JSX scanning instead 6412 // of regular scanning to avoid treating illegal characters (e.g. '#') as immediate 6413 // scanning errors 6414 scanJsxText(); 6415 node = factory.createJsxOpeningElement(tagName, typeArguments, attributes); 6416 } 6417 else { 6418 parseExpected(SyntaxKind.SlashToken); 6419 if (parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*shouldAdvance*/ false)) { 6420 // manually advance the scanner in order to look for jsx text inside jsx 6421 if (inExpressionContext) { 6422 nextToken(); 6423 } 6424 else { 6425 scanJsxText(); 6426 } 6427 } 6428 node = factory.createJsxSelfClosingElement(tagName, typeArguments, attributes); 6429 } 6430 6431 return finishNode(node, pos); 6432 } 6433 6434 function parseJsxElementName(): JsxTagNameExpression { 6435 const pos = getNodePos(); 6436 scanJsxIdentifier(); 6437 // JsxElement can have name in the form of 6438 // propertyAccessExpression 6439 // primaryExpression in the form of an identifier and "this" keyword 6440 // We can't just simply use parseLeftHandSideExpressionOrHigher because then we will start consider class,function etc as a keyword 6441 // We only want to consider "this" as a primaryExpression 6442 let expression: JsxTagNameExpression = token() === SyntaxKind.ThisKeyword ? 6443 parseTokenNode<ThisExpression>() : parseIdentifierName(); 6444 while (parseOptional(SyntaxKind.DotToken)) { 6445 expression = finishNode(factory.createPropertyAccessExpression(expression, parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ false)), pos) as JsxTagNamePropertyAccess; 6446 } 6447 return expression; 6448 } 6449 6450 function parseJsxExpression(inExpressionContext: boolean): JsxExpression | undefined { 6451 const pos = getNodePos(); 6452 if (!parseExpected(SyntaxKind.OpenBraceToken)) { 6453 return undefined; 6454 } 6455 6456 let dotDotDotToken: DotDotDotToken | undefined; 6457 let expression: Expression | undefined; 6458 if (token() !== SyntaxKind.CloseBraceToken) { 6459 dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); 6460 // Only an AssignmentExpression is valid here per the JSX spec, 6461 // but we can unambiguously parse a comma sequence and provide 6462 // a better error message in grammar checking. 6463 expression = parseExpression(); 6464 } 6465 if (inExpressionContext) { 6466 parseExpected(SyntaxKind.CloseBraceToken); 6467 } 6468 else { 6469 if (parseExpected(SyntaxKind.CloseBraceToken, /*message*/ undefined, /*shouldAdvance*/ false)) { 6470 scanJsxText(); 6471 } 6472 } 6473 6474 return finishNode(factory.createJsxExpression(dotDotDotToken, expression), pos); 6475 } 6476 6477 function parseJsxAttribute(): JsxAttribute | JsxSpreadAttribute { 6478 if (token() === SyntaxKind.OpenBraceToken) { 6479 return parseJsxSpreadAttribute(); 6480 } 6481 6482 scanJsxIdentifier(); 6483 const pos = getNodePos(); 6484 return finishNode(factory.createJsxAttribute(parseIdentifierName(), parseJsxAttributeValue()), pos); 6485 } 6486 6487 function parseJsxAttributeValue(): JsxAttributeValue | undefined { 6488 if (token() === SyntaxKind.EqualsToken) { 6489 if (scanJsxAttributeValue() === SyntaxKind.StringLiteral) { 6490 return parseLiteralNode() as StringLiteral; 6491 } 6492 if (token() === SyntaxKind.OpenBraceToken) { 6493 return parseJsxExpression(/*inExpressionContext*/ true); 6494 } 6495 if (token() === SyntaxKind.LessThanToken) { 6496 return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true); 6497 } 6498 parseErrorAtCurrentToken(Diagnostics.or_JSX_element_expected); 6499 } 6500 return undefined; 6501 } 6502 6503 function parseJsxSpreadAttribute(): JsxSpreadAttribute { 6504 const pos = getNodePos(); 6505 parseExpected(SyntaxKind.OpenBraceToken); 6506 parseExpected(SyntaxKind.DotDotDotToken); 6507 const expression = parseExpression(); 6508 parseExpected(SyntaxKind.CloseBraceToken); 6509 return finishNode(factory.createJsxSpreadAttribute(expression), pos); 6510 } 6511 6512 function parseJsxClosingElement(open: JsxOpeningElement, inExpressionContext: boolean): JsxClosingElement { 6513 const pos = getNodePos(); 6514 parseExpected(SyntaxKind.LessThanSlashToken); 6515 const tagName = parseJsxElementName(); 6516 if (parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*shouldAdvance*/ false)) { 6517 // manually advance the scanner in order to look for jsx text inside jsx 6518 if (inExpressionContext || !tagNamesAreEquivalent(open.tagName, tagName)) { 6519 nextToken(); 6520 } 6521 else { 6522 scanJsxText(); 6523 } 6524 } 6525 return finishNode(factory.createJsxClosingElement(tagName), pos); 6526 } 6527 6528 function parseJsxClosingFragment(inExpressionContext: boolean): JsxClosingFragment { 6529 const pos = getNodePos(); 6530 parseExpected(SyntaxKind.LessThanSlashToken); 6531 if (tokenIsIdentifierOrKeyword(token())) { 6532 parseErrorAtRange(parseJsxElementName(), Diagnostics.Expected_corresponding_closing_tag_for_JSX_fragment); 6533 } 6534 if (parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*shouldAdvance*/ false)) { 6535 // manually advance the scanner in order to look for jsx text inside jsx 6536 if (inExpressionContext) { 6537 nextToken(); 6538 } 6539 else { 6540 scanJsxText(); 6541 } 6542 } 6543 return finishNode(factory.createJsxJsxClosingFragment(), pos); 6544 } 6545 6546 function parseTypeAssertion(): TypeAssertion { 6547 const pos = getNodePos(); 6548 parseExpected(SyntaxKind.LessThanToken); 6549 const type = parseType(); 6550 parseExpected(SyntaxKind.GreaterThanToken); 6551 const expression = parseSimpleUnaryExpression(); 6552 return finishNode(factory.createTypeAssertion(type, expression), pos); 6553 } 6554 6555 function nextTokenIsIdentifierOrKeywordOrOpenBracketOrTemplate() { 6556 nextToken(); 6557 return tokenIsIdentifierOrKeyword(token()) 6558 || token() === SyntaxKind.OpenBracketToken 6559 || isTemplateStartOfTaggedTemplate(); 6560 } 6561 6562 function isStartOfOptionalPropertyOrElementAccessChain() { 6563 return token() === SyntaxKind.QuestionDotToken 6564 && lookAhead(nextTokenIsIdentifierOrKeywordOrOpenBracketOrTemplate); 6565 } 6566 6567 function tryReparseOptionalChain(node: Expression) { 6568 if (node.flags & NodeFlags.OptionalChain) { 6569 return true; 6570 } 6571 // check for an optional chain in a non-null expression 6572 if (isNonNullExpression(node)) { 6573 let expr = node.expression; 6574 while (isNonNullExpression(expr) && !(expr.flags & NodeFlags.OptionalChain)) { 6575 expr = expr.expression; 6576 } 6577 if (expr.flags & NodeFlags.OptionalChain) { 6578 // this is part of an optional chain. Walk down from `node` to `expression` and set the flag. 6579 while (isNonNullExpression(node)) { 6580 (node as Mutable<NonNullExpression>).flags |= NodeFlags.OptionalChain; 6581 node = node.expression; 6582 } 6583 return true; 6584 } 6585 } 6586 return false; 6587 } 6588 6589 function parsePropertyAccessExpressionRest(pos: number, expression: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined) { 6590 const name = parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ true); 6591 const isOptionalChain = questionDotToken || tryReparseOptionalChain(expression); 6592 const propertyAccess = isOptionalChain ? 6593 factory.createPropertyAccessChain(expression, questionDotToken, name) : 6594 factory.createPropertyAccessExpression(expression, name); 6595 if (isOptionalChain && isPrivateIdentifier(propertyAccess.name)) { 6596 parseErrorAtRange(propertyAccess.name, Diagnostics.An_optional_chain_cannot_contain_private_identifiers); 6597 } 6598 if (isExpressionWithTypeArguments(expression) && expression.typeArguments) { 6599 const pos = expression.typeArguments.pos - 1; 6600 const end = skipTrivia(sourceText, expression.typeArguments.end) + 1; 6601 parseErrorAt(pos, end, Diagnostics.An_instantiation_expression_cannot_be_followed_by_a_property_access); 6602 } 6603 return finishNode(propertyAccess, pos); 6604 } 6605 6606 function parseElementAccessExpressionRest(pos: number, expression: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined) { 6607 let argumentExpression: Expression; 6608 if (token() === SyntaxKind.CloseBracketToken) { 6609 argumentExpression = createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.An_element_access_expression_should_take_an_argument); 6610 } 6611 else { 6612 const argument = allowInAnd(parseExpression); 6613 if (isStringOrNumericLiteralLike(argument)) { 6614 argument.text = internIdentifier(argument.text); 6615 } 6616 argumentExpression = argument; 6617 } 6618 6619 parseExpected(SyntaxKind.CloseBracketToken); 6620 6621 const indexedAccess = questionDotToken || tryReparseOptionalChain(expression) ? 6622 factory.createElementAccessChain(expression, questionDotToken, argumentExpression) : 6623 factory.createElementAccessExpression(expression, argumentExpression); 6624 return finishNode(indexedAccess, pos); 6625 } 6626 6627 function parseMemberExpressionRest(pos: number, expression: LeftHandSideExpression, allowOptionalChain: boolean): MemberExpression { 6628 while (true) { 6629 let questionDotToken: QuestionDotToken | undefined; 6630 let isPropertyAccess = false; 6631 if (allowOptionalChain && isStartOfOptionalPropertyOrElementAccessChain()) { 6632 questionDotToken = parseExpectedToken(SyntaxKind.QuestionDotToken); 6633 isPropertyAccess = tokenIsIdentifierOrKeyword(token()); 6634 } 6635 else { 6636 isPropertyAccess = parseOptional(SyntaxKind.DotToken); 6637 } 6638 6639 if (isPropertyAccess) { 6640 expression = parsePropertyAccessExpressionRest(pos, expression, questionDotToken); 6641 continue; 6642 } 6643 6644 // when in the [Decorator] context, we do not parse ElementAccess as it could be part of a ComputedPropertyName 6645 if ((questionDotToken || !inDecoratorContext()) && parseOptional(SyntaxKind.OpenBracketToken)) { 6646 expression = parseElementAccessExpressionRest(pos, expression, questionDotToken); 6647 continue; 6648 } 6649 6650 if (isTemplateStartOfTaggedTemplate()) { 6651 // Absorb type arguments into TemplateExpression when preceding expression is ExpressionWithTypeArguments 6652 expression = !questionDotToken && expression.kind === SyntaxKind.ExpressionWithTypeArguments ? 6653 parseTaggedTemplateRest(pos, (expression as ExpressionWithTypeArguments).expression, questionDotToken, (expression as ExpressionWithTypeArguments).typeArguments) : 6654 parseTaggedTemplateRest(pos, expression, questionDotToken, /*typeArguments*/ undefined); 6655 continue; 6656 } 6657 6658 if (!questionDotToken) { 6659 if (token() === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak()) { 6660 nextToken(); 6661 expression = finishNode(factory.createNonNullExpression(expression), pos); 6662 continue; 6663 } 6664 const typeArguments = tryParse(parseTypeArgumentsInExpression); 6665 if (typeArguments) { 6666 expression = finishNode(factory.createExpressionWithTypeArguments(expression, typeArguments), pos); 6667 continue; 6668 } 6669 } 6670 6671 return expression as MemberExpression; 6672 } 6673 } 6674 6675 function isTemplateStartOfTaggedTemplate() { 6676 return token() === SyntaxKind.NoSubstitutionTemplateLiteral || token() === SyntaxKind.TemplateHead; 6677 } 6678 6679 function parseTaggedTemplateRest(pos: number, tag: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined, typeArguments: NodeArray<TypeNode> | undefined) { 6680 const tagExpression = factory.createTaggedTemplateExpression( 6681 tag, 6682 typeArguments, 6683 token() === SyntaxKind.NoSubstitutionTemplateLiteral ? 6684 (reScanTemplateHeadOrNoSubstitutionTemplate(), parseLiteralNode() as NoSubstitutionTemplateLiteral) : 6685 parseTemplateExpression(/*isTaggedTemplate*/ true) 6686 ); 6687 if (questionDotToken || tag.flags & NodeFlags.OptionalChain) { 6688 (tagExpression as Mutable<Node>).flags |= NodeFlags.OptionalChain; 6689 } 6690 tagExpression.questionDotToken = questionDotToken; 6691 return finishNode(tagExpression, pos); 6692 } 6693 6694 function parseCallExpressionRest(pos: number, expression: LeftHandSideExpression): LeftHandSideExpression { 6695 let currentNodeName: string | undefined; 6696 while (true) { 6697 expression = parseMemberExpressionRest(pos, expression, /*allowOptionalChain*/ true); 6698 let typeArguments: NodeArray<TypeNode> | undefined; 6699 const questionDotToken = parseOptionalToken(SyntaxKind.QuestionDotToken); 6700 if (questionDotToken) { 6701 typeArguments = tryParse(parseTypeArgumentsInExpression); 6702 if (isTemplateStartOfTaggedTemplate()) { 6703 expression = parseTaggedTemplateRest(pos, expression, questionDotToken, typeArguments); 6704 continue; 6705 } 6706 } 6707 if (typeArguments || token() === SyntaxKind.OpenParenToken) { 6708 // Absorb type arguments into CallExpression when preceding expression is ExpressionWithTypeArguments 6709 if (!questionDotToken && expression.kind === SyntaxKind.ExpressionWithTypeArguments) { 6710 typeArguments = (expression as ExpressionWithTypeArguments).typeArguments; 6711 expression = (expression as ExpressionWithTypeArguments).expression; 6712 } 6713 6714 if (isValidVirtualTypeArgumentsContext() && isPropertyAccessExpression(expression)) { 6715 const [rootNode, type] = getRootComponent(expression, sourceFileCompilerOptions); 6716 if (rootNode && type) { 6717 let rootNodeName = ''; 6718 if (type === 'otherType') { 6719 rootNodeName = 'Common'; 6720 } else { 6721 rootNodeName = (<Identifier>(rootNode.expression)).escapedText.toString(); 6722 } 6723 currentNodeName = getTextOfPropertyName(expression.name).toString(); 6724 if (currentNodeName === sourceFileCompilerOptions?.ets?.styles?.property) { 6725 setEtsStateStylesContext(true); 6726 stateStylesRootNode = rootNodeName; 6727 } 6728 else { 6729 setEtsStateStylesContext(false); 6730 stateStylesRootNode = undefined; 6731 } 6732 const syntaxComponents = sourceFileCompilerOptions?.ets?.syntaxComponents?.attrUICallback?.filter( 6733 (item: any) => item.name === rootNodeName); 6734 if (type === 'callExpressionComponentType' && syntaxComponents && syntaxComponents.length && 6735 syntaxComponents[0]?.attributes?.includes(currentNodeName)) { 6736 setSyntaxComponentContext(true); 6737 setFirstArgumentExpression(true); 6738 if (currentNodeName === 'each') { 6739 setRepeatEachRest(true); 6740 } 6741 } else if (type === 'etsComponentType') { 6742 typeArguments = parseEtsTypeArguments(pos, `${rootNodeName}Attribute`); 6743 } 6744 } 6745 else if (inEtsStateStylesContext() && stateStylesRootNode) { 6746 typeArguments = parseEtsTypeArguments(pos, `${stateStylesRootNode}Attribute`); 6747 } else if (inEtsStylesComponentsContext() || inEtsExtendComponentsContext()) { 6748 const virtualNode = getVirtualEtsComponent(expression); 6749 if (virtualNode) { 6750 let rootNodeName = (<Identifier>(virtualNode.expression)).escapedText.toString(); 6751 currentNodeName = getTextOfPropertyName(expression.name).toString(); 6752 if (currentNodeName === sourceFileCompilerOptions?.ets?.styles?.property) { 6753 setEtsStateStylesContext(true); 6754 rootNodeName = rootNodeName.replace("Instance", ""); 6755 stateStylesRootNode = rootNodeName; 6756 typeArguments = parseEtsTypeArguments(pos, `${rootNodeName}Attribute`); 6757 } 6758 } 6759 } 6760 } 6761 if (isValidVirtualTypeArgumentsContext() && ts.isIdentifier(expression) && 6762 sourceFileCompilerOptions?.ets?.syntaxComponents?.paramsUICallback?.includes(expression.escapedText.toString())) { 6763 setSyntaxComponentContext(true); 6764 setFirstArgumentExpression(true); 6765 } 6766 const argumentList = parseArgumentList(); 6767 const callExpr = questionDotToken || tryReparseOptionalChain(expression) ? 6768 factory.createCallChain(expression, questionDotToken, typeArguments, argumentList) : 6769 factory.createCallExpression(expression, typeArguments, argumentList); 6770 expression = finishNode(callExpr, pos); 6771 continue; 6772 } 6773 if (questionDotToken) { 6774 // We parsed `?.` but then failed to parse anything, so report a missing identifier here. 6775 const name = createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ false, Diagnostics.Identifier_expected); 6776 expression = finishNode(factory.createPropertyAccessChain(expression, questionDotToken, name), pos); 6777 } 6778 break; 6779 } 6780 if (currentNodeName === sourceFileCompilerOptions?.ets?.styles?.property) { 6781 setEtsStateStylesContext(false); 6782 stateStylesRootNode = undefined; 6783 } 6784 return expression; 6785 } 6786 6787 function isValidVirtualTypeArgumentsContext(): boolean { 6788 return inBuildContext() || inBuilderContext() || inEtsStylesComponentsContext() || inEtsExtendComponentsContext(); 6789 } 6790 6791 function parseArgumentList() { 6792 parseExpected(SyntaxKind.OpenParenToken); 6793 const result = parseDelimitedList(ParsingContext.ArgumentExpressions, parseArgumentExpression); 6794 parseExpected(SyntaxKind.CloseParenToken); 6795 return result; 6796 } 6797 6798 function parseTypeArgumentsInExpression() { 6799 if ((contextFlags & NodeFlags.JavaScriptFile) !== 0) { 6800 // TypeArguments must not be parsed in JavaScript files to avoid ambiguity with binary operators. 6801 return undefined; 6802 } 6803 6804 if (reScanLessThanToken() !== SyntaxKind.LessThanToken) { 6805 return undefined; 6806 } 6807 nextToken(); 6808 6809 const typeArguments = parseDelimitedList(ParsingContext.TypeArguments, parseType); 6810 if (reScanGreaterToken() !== SyntaxKind.GreaterThanToken) { 6811 // If it doesn't have the closing `>` then it's definitely not an type argument list. 6812 return undefined; 6813 } 6814 nextToken(); 6815 6816 // We successfully parsed a type argument list. The next token determines whether we want to 6817 // treat it as such. If the type argument list is followed by `(` or a template literal, as in 6818 // `f<number>(42)`, we favor the type argument interpretation even though JavaScript would view 6819 // it as a relational expression. 6820 return typeArguments && canFollowTypeArgumentsInExpression() ? typeArguments : undefined; 6821 } 6822 6823 function canFollowTypeArgumentsInExpression(): boolean { 6824 switch (token()) { 6825 // These tokens can follow a type argument list in a call expression. 6826 case SyntaxKind.OpenParenToken: // foo<x>( 6827 case SyntaxKind.NoSubstitutionTemplateLiteral: // foo<T> `...` 6828 case SyntaxKind.TemplateHead: // foo<T> `...${100}...` 6829 return true; 6830 // A type argument list followed by `<` never makes sense, and a type argument list followed 6831 // by `>` is ambiguous with a (re-scanned) `>>` operator, so we disqualify both. Also, in 6832 // this context, `+` and `-` are unary operators, not binary operators. 6833 case SyntaxKind.LessThanToken: 6834 case SyntaxKind.GreaterThanToken: 6835 case SyntaxKind.PlusToken: 6836 case SyntaxKind.MinusToken: 6837 return false; 6838 } 6839 // We favor the type argument list interpretation when it is immediately followed by 6840 // a line break, a binary operator, or something that can't start an expression. 6841 return scanner.hasPrecedingLineBreak() || isBinaryOperator() || !isStartOfExpression(); 6842 } 6843 6844 function isCurrentTokenAnEtsComponentExpression(): boolean { 6845 if (!inEtsComponentsContext() || inNoEtsComponentContext()) { 6846 return false; 6847 } 6848 const components = sourceFileCompilerOptions.ets?.components ?? []; 6849 return components.includes(scanner.getTokenText()); 6850 } 6851 6852 function parseEtsComponentExpression(): EtsComponentExpression { 6853 const pos = getNodePos(); 6854 const name = parseBindingIdentifier(); 6855 const argumentList = parseArgumentList(); 6856 const body = token() === SyntaxKind.OpenBraceToken ? parseFunctionBlock(SignatureFlags.None) : undefined; 6857 const node = factory.createEtsComponentExpression(name, argumentList, body); 6858 return finishNode(node, pos); 6859 } 6860 6861 function parsePrimaryExpression(): PrimaryExpression { 6862 switch (token()) { 6863 case SyntaxKind.NumericLiteral: 6864 case SyntaxKind.BigIntLiteral: 6865 case SyntaxKind.StringLiteral: 6866 case SyntaxKind.NoSubstitutionTemplateLiteral: 6867 return parseLiteralNode(); 6868 case SyntaxKind.ThisKeyword: 6869 case SyntaxKind.SuperKeyword: 6870 case SyntaxKind.NullKeyword: 6871 case SyntaxKind.TrueKeyword: 6872 case SyntaxKind.FalseKeyword: 6873 return parseTokenNode<PrimaryExpression>(); 6874 case SyntaxKind.OpenParenToken: 6875 return parseParenthesizedExpression(); 6876 case SyntaxKind.OpenBracketToken: 6877 return parseArrayLiteralExpression(); 6878 case SyntaxKind.OpenBraceToken: 6879 return parseObjectLiteralExpression(); 6880 case SyntaxKind.AsyncKeyword: 6881 // Async arrow functions are parsed earlier in parseAssignmentExpressionOrHigher. 6882 // If we encounter `async [no LineTerminator here] function` then this is an async 6883 // function; otherwise, its an identifier. 6884 if (!lookAhead(nextTokenIsFunctionKeywordOnSameLine)) { 6885 break; 6886 } 6887 6888 return parseFunctionExpression(); 6889 case SyntaxKind.ClassKeyword: 6890 return parseClassExpression(); 6891 case SyntaxKind.FunctionKeyword: 6892 return parseFunctionExpression(); 6893 case SyntaxKind.NewKeyword: 6894 return parseNewExpressionOrNewDotTarget(); 6895 case SyntaxKind.SlashToken: 6896 case SyntaxKind.SlashEqualsToken: 6897 if (reScanSlashToken() === SyntaxKind.RegularExpressionLiteral) { 6898 return parseLiteralNode(); 6899 } 6900 break; 6901 case SyntaxKind.TemplateHead: 6902 return parseTemplateExpression(/* isTaggedTemplate */ false); 6903 case SyntaxKind.PrivateIdentifier: 6904 return parsePrivateIdentifier(); 6905 } 6906 6907 if(isCurrentTokenAnEtsComponentExpression() && !inEtsNewExpressionContext()) { 6908 return parseEtsComponentExpression(); 6909 } 6910 6911 return parseIdentifier(Diagnostics.Expression_expected); 6912 } 6913 6914 function parseParenthesizedExpression(): ParenthesizedExpression { 6915 const pos = getNodePos(); 6916 const hasJSDoc = hasPrecedingJSDocComment(); 6917 parseExpected(SyntaxKind.OpenParenToken); 6918 const expression = allowInAnd(parseExpression); 6919 parseExpected(SyntaxKind.CloseParenToken); 6920 return withJSDoc(finishNode(factory.createParenthesizedExpression(expression), pos), hasJSDoc); 6921 } 6922 6923 function parseSpreadElement(): Expression { 6924 const pos = getNodePos(); 6925 parseExpected(SyntaxKind.DotDotDotToken); 6926 const expression = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true); 6927 return finishNode(factory.createSpreadElement(expression), pos); 6928 } 6929 6930 function parseArgumentOrArrayLiteralElement(): Expression { 6931 return token() === SyntaxKind.DotDotDotToken ? parseSpreadElement() : 6932 token() === SyntaxKind.CommaToken ? finishNode(factory.createOmittedExpression(), getNodePos()) : 6933 parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true); 6934 } 6935 6936 function parseArgumentExpression(): Expression { 6937 let resetSyntaxDataSourceContextFlag: boolean = false; 6938 let resetRepeatEachContextFlag: boolean = false; 6939 if (inSyntaxComponentContext() && !inSyntaxDataSourceContext() && getFirstArgumentExpression()) { 6940 setFirstArgumentExpression(false); 6941 if (!getRepeatEachRest()) { 6942 setSyntaxDataSourceContext(true); 6943 resetSyntaxDataSourceContextFlag = true; 6944 } else { 6945 resetRepeatEachContextFlag = true; 6946 } 6947 } 6948 const argumentExpressionResult = doOutsideOfContext(disallowInAndDecoratorContext, parseArgumentOrArrayLiteralElement); 6949 6950 if (resetSyntaxDataSourceContextFlag) { 6951 setSyntaxDataSourceContext(false); 6952 } 6953 6954 if (resetRepeatEachContextFlag) { 6955 setRepeatEachRest(false); 6956 } 6957 6958 return argumentExpressionResult; 6959 } 6960 6961 function parseArrayLiteralExpression(): ArrayLiteralExpression { 6962 const pos = getNodePos(); 6963 const openBracketPosition = scanner.getTokenPos(); 6964 const openBracketParsed = parseExpected(SyntaxKind.OpenBracketToken); 6965 const multiLine = scanner.hasPrecedingLineBreak(); 6966 const elements = parseDelimitedList(ParsingContext.ArrayLiteralMembers, parseArgumentOrArrayLiteralElement); 6967 parseExpectedMatchingBrackets(SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken, openBracketParsed, openBracketPosition); 6968 return finishNode(factory.createArrayLiteralExpression(elements, multiLine), pos); 6969 } 6970 6971 function parseObjectLiteralElement(): ObjectLiteralElementLike { 6972 const pos = getNodePos(); 6973 const hasJSDoc = hasPrecedingJSDocComment(); 6974 6975 if (parseOptionalToken(SyntaxKind.DotDotDotToken)) { 6976 const expression = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true); 6977 return withJSDoc(finishNode(factory.createSpreadAssignment(expression), pos), hasJSDoc); 6978 } 6979 6980 const decorators = parseDecorators(); 6981 const modifiers = parseModifiers(); 6982 6983 if (parseContextualModifier(SyntaxKind.GetKeyword)) { 6984 return parseAccessorDeclaration(pos, hasJSDoc, decorators, modifiers, SyntaxKind.GetAccessor, SignatureFlags.None); 6985 } 6986 if (parseContextualModifier(SyntaxKind.SetKeyword)) { 6987 return parseAccessorDeclaration(pos, hasJSDoc, decorators, modifiers, SyntaxKind.SetAccessor, SignatureFlags.None); 6988 } 6989 6990 const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); 6991 const tokenIsIdentifier = isIdentifier(); 6992 const name = parsePropertyName(); 6993 6994 // Disallowing of optional property assignments and definite assignment assertion happens in the grammar checker. 6995 const questionToken = parseOptionalToken(SyntaxKind.QuestionToken); 6996 const exclamationToken = parseOptionalToken(SyntaxKind.ExclamationToken); 6997 6998 if (asteriskToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) { 6999 return parseMethodDeclaration(pos, hasJSDoc, decorators, modifiers, asteriskToken, name, questionToken, exclamationToken); 7000 } 7001 7002 // check if it is short-hand property assignment or normal property assignment 7003 // NOTE: if token is EqualsToken it is interpreted as CoverInitializedName production 7004 // CoverInitializedName[Yield] : 7005 // IdentifierReference[?Yield] Initializer[In, ?Yield] 7006 // this is necessary because ObjectLiteral productions are also used to cover grammar for ObjectAssignmentPattern 7007 let node: Mutable<ShorthandPropertyAssignment | PropertyAssignment>; 7008 const isShorthandPropertyAssignment = tokenIsIdentifier && (token() !== SyntaxKind.ColonToken); 7009 if (isShorthandPropertyAssignment) { 7010 const equalsToken = parseOptionalToken(SyntaxKind.EqualsToken); 7011 const objectAssignmentInitializer = equalsToken ? allowInAnd(() => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true)) : undefined; 7012 node = factory.createShorthandPropertyAssignment(name as Identifier, objectAssignmentInitializer); 7013 // Save equals token for error reporting. 7014 // TODO(rbuckton): Consider manufacturing this when we need to report an error as it is otherwise not useful. 7015 node.equalsToken = equalsToken; 7016 } 7017 else { 7018 parseExpected(SyntaxKind.ColonToken); 7019 const initializer = allowInAnd(() => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true)); 7020 node = factory.createPropertyAssignment(name, initializer); 7021 } 7022 // Decorators, Modifiers, questionToken, and exclamationToken are not supported by property assignments and are reported in the grammar checker 7023 node.illegalDecorators = decorators; 7024 node.modifiers = modifiers; 7025 node.questionToken = questionToken; 7026 node.exclamationToken = exclamationToken; 7027 return withJSDoc(finishNode(node, pos), hasJSDoc); 7028 } 7029 7030 function parseObjectLiteralExpression(): ObjectLiteralExpression { 7031 const pos = getNodePos(); 7032 const openBracePosition = scanner.getTokenPos(); 7033 const openBraceParsed = parseExpected(SyntaxKind.OpenBraceToken); 7034 const multiLine = scanner.hasPrecedingLineBreak(); 7035 const properties = parseDelimitedList(ParsingContext.ObjectLiteralMembers, parseObjectLiteralElement, /*considerSemicolonAsDelimiter*/ true); 7036 parseExpectedMatchingBrackets(SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, openBraceParsed, openBracePosition); 7037 return finishNode(factory.createObjectLiteralExpression(properties, multiLine), pos); 7038 } 7039 7040 function parseFunctionExpression(): FunctionExpression { 7041 // GeneratorExpression: 7042 // function* BindingIdentifier [Yield][opt](FormalParameters[Yield]) { GeneratorBody } 7043 // 7044 // FunctionExpression: 7045 // function BindingIdentifier[opt](FormalParameters) { FunctionBody } 7046 const savedDecoratorContext = inDecoratorContext(); 7047 setDecoratorContext(/*val*/ false); 7048 7049 const pos = getNodePos(); 7050 const hasJSDoc = hasPrecedingJSDocComment(); 7051 const modifiers = parseModifiers(); 7052 parseExpected(SyntaxKind.FunctionKeyword); 7053 const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); 7054 const isGenerator = asteriskToken ? SignatureFlags.Yield : SignatureFlags.None; 7055 const isAsync = some(modifiers, isAsyncModifier) ? SignatureFlags.Await : SignatureFlags.None; 7056 const name = isGenerator && isAsync ? doInYieldAndAwaitContext(parseOptionalBindingIdentifier) : 7057 isGenerator ? doInYieldContext(parseOptionalBindingIdentifier) : 7058 isAsync ? doInAwaitContext(parseOptionalBindingIdentifier) : 7059 parseOptionalBindingIdentifier(); 7060 7061 const typeParameters = parseTypeParameters(); 7062 const parameters = parseParameters(isGenerator | isAsync); 7063 const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false); 7064 const body = parseFunctionBlock(isGenerator | isAsync); 7065 7066 setDecoratorContext(savedDecoratorContext); 7067 7068 const node = factory.createFunctionExpression(modifiers, asteriskToken, name, typeParameters, parameters, type, body); 7069 return withJSDoc(finishNode(node, pos), hasJSDoc); 7070 } 7071 7072 function parseOptionalBindingIdentifier(): Identifier | undefined { 7073 return isBindingIdentifier() ? parseBindingIdentifier() : undefined; 7074 } 7075 7076 function parseNewExpressionOrNewDotTarget(): NewExpression | MetaProperty { 7077 setEtsNewExpressionContext(inEtsComponentsContext()); 7078 const pos = getNodePos(); 7079 parseExpected(SyntaxKind.NewKeyword); 7080 if (parseOptional(SyntaxKind.DotToken)) { 7081 const name = parseIdentifierName(); 7082 return finishNode(factory.createMetaProperty(SyntaxKind.NewKeyword, name), pos); 7083 } 7084 const expressionPos = getNodePos(); 7085 let expression: LeftHandSideExpression = parseMemberExpressionRest(expressionPos, parsePrimaryExpression(), /*allowOptionalChain*/ false); 7086 let typeArguments: NodeArray<TypeNode> | undefined; 7087 // Absorb type arguments into NewExpression when preceding expression is ExpressionWithTypeArguments 7088 if (expression.kind === SyntaxKind.ExpressionWithTypeArguments) { 7089 typeArguments = (expression as ExpressionWithTypeArguments).typeArguments; 7090 expression = (expression as ExpressionWithTypeArguments).expression; 7091 } 7092 if (token() === SyntaxKind.QuestionDotToken) { 7093 parseErrorAtCurrentToken(Diagnostics.Invalid_optional_chain_from_new_expression_Did_you_mean_to_call_0, getTextOfNodeFromSourceText(sourceText, expression)); 7094 } 7095 const argumentList = token() === SyntaxKind.OpenParenToken ? parseArgumentList() : undefined; 7096 setEtsNewExpressionContext(false); 7097 return finishNode(factory.createNewExpression(expression, typeArguments, argumentList), pos); 7098 } 7099 7100 // STATEMENTS 7101 function parseBlock(ignoreMissingOpenBrace: boolean, diagnosticMessage?: DiagnosticMessage): Block { 7102 const pos = getNodePos(); 7103 const hasJSDoc = hasPrecedingJSDocComment(); 7104 const openBracePosition = scanner.getTokenPos(); 7105 const openBraceParsed = parseExpected(SyntaxKind.OpenBraceToken, diagnosticMessage); 7106 if (openBraceParsed || ignoreMissingOpenBrace) { 7107 const multiLine = scanner.hasPrecedingLineBreak(); 7108 const statements = parseList(ParsingContext.BlockStatements, parseStatement); 7109 parseExpectedMatchingBrackets(SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, openBraceParsed, openBracePosition); 7110 const result = withJSDoc(finishNode(factory.createBlock(statements, multiLine), pos), hasJSDoc); 7111 if (token() === SyntaxKind.EqualsToken) { 7112 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); 7113 nextToken(); 7114 } 7115 7116 return result; 7117 } 7118 else { 7119 const statements = createMissingList<Statement>(); 7120 return withJSDoc(finishNode(factory.createBlock(statements, /*multiLine*/ undefined), pos), hasJSDoc); 7121 } 7122 } 7123 7124 function parseFunctionBlock(flags: SignatureFlags, diagnosticMessage?: DiagnosticMessage): Block { 7125 const savedYieldContext = inYieldContext(); 7126 setYieldContext(!!(flags & SignatureFlags.Yield)); 7127 7128 const savedAwaitContext = inAwaitContext(); 7129 setAwaitContext(!!(flags & SignatureFlags.Await)); 7130 7131 const savedTopLevel = topLevel; 7132 topLevel = false; 7133 7134 // We may be in a [Decorator] context when parsing a function expression or 7135 // arrow function. The body of the function is not in [Decorator] context. 7136 const saveDecoratorContext = inDecoratorContext(); 7137 if (saveDecoratorContext) { 7138 setDecoratorContext(/*val*/ false); 7139 } 7140 7141 const block = parseBlock(!!(flags & SignatureFlags.IgnoreMissingOpenBrace), diagnosticMessage); 7142 7143 if (saveDecoratorContext) { 7144 setDecoratorContext(/*val*/ true); 7145 } 7146 7147 topLevel = savedTopLevel; 7148 setYieldContext(savedYieldContext); 7149 setAwaitContext(savedAwaitContext); 7150 7151 return block; 7152 } 7153 7154 function parseEmptyStatement(): Statement { 7155 const pos = getNodePos(); 7156 const hasJSDoc = hasPrecedingJSDocComment(); 7157 parseExpected(SyntaxKind.SemicolonToken); 7158 return withJSDoc(finishNode(factory.createEmptyStatement(), pos), hasJSDoc); 7159 } 7160 7161 function parseIfStatement(): IfStatement { 7162 const pos = getNodePos(); 7163 const hasJSDoc = hasPrecedingJSDocComment(); 7164 parseExpected(SyntaxKind.IfKeyword); 7165 const openParenPosition = scanner.getTokenPos(); 7166 const openParenParsed = parseExpected(SyntaxKind.OpenParenToken); 7167 const expression = allowInAnd(parseExpression); 7168 parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition); 7169 const thenStatement = parseStatement(); 7170 const elseStatement = parseOptional(SyntaxKind.ElseKeyword) ? parseStatement() : undefined; 7171 return withJSDoc(finishNode(factory.createIfStatement(expression, thenStatement, elseStatement), pos), hasJSDoc); 7172 } 7173 7174 function parseDoStatement(): DoStatement { 7175 const pos = getNodePos(); 7176 const hasJSDoc = hasPrecedingJSDocComment(); 7177 parseExpected(SyntaxKind.DoKeyword); 7178 const statement = parseStatement(); 7179 parseExpected(SyntaxKind.WhileKeyword); 7180 const openParenPosition = scanner.getTokenPos(); 7181 const openParenParsed = parseExpected(SyntaxKind.OpenParenToken); 7182 const expression = allowInAnd(parseExpression); 7183 parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition); 7184 7185 // From: https://mail.mozilla.org/pipermail/es-discuss/2011-August/016188.html 7186 // 157 min --- All allen at wirfs-brock.com CONF --- "do{;}while(false)false" prohibited in 7187 // spec but allowed in consensus reality. Approved -- this is the de-facto standard whereby 7188 // do;while(0)x will have a semicolon inserted before x. 7189 parseOptional(SyntaxKind.SemicolonToken); 7190 return withJSDoc(finishNode(factory.createDoStatement(statement, expression), pos), hasJSDoc); 7191 } 7192 7193 function parseWhileStatement(): WhileStatement { 7194 const pos = getNodePos(); 7195 const hasJSDoc = hasPrecedingJSDocComment(); 7196 parseExpected(SyntaxKind.WhileKeyword); 7197 const openParenPosition = scanner.getTokenPos(); 7198 const openParenParsed = parseExpected(SyntaxKind.OpenParenToken); 7199 const expression = allowInAnd(parseExpression); 7200 parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition); 7201 const statement = parseStatement(); 7202 return withJSDoc(finishNode(factory.createWhileStatement(expression, statement), pos), hasJSDoc); 7203 } 7204 7205 function parseForOrForInOrForOfStatement(): Statement { 7206 const pos = getNodePos(); 7207 const hasJSDoc = hasPrecedingJSDocComment(); 7208 parseExpected(SyntaxKind.ForKeyword); 7209 const awaitToken = parseOptionalToken(SyntaxKind.AwaitKeyword); 7210 parseExpected(SyntaxKind.OpenParenToken); 7211 7212 let initializer!: VariableDeclarationList | Expression; 7213 if (token() !== SyntaxKind.SemicolonToken) { 7214 if (token() === SyntaxKind.VarKeyword || token() === SyntaxKind.LetKeyword || token() === SyntaxKind.ConstKeyword) { 7215 initializer = parseVariableDeclarationList(/*inForStatementInitializer*/ true); 7216 } 7217 else { 7218 initializer = disallowInAnd(parseExpression); 7219 } 7220 } 7221 7222 let node: IterationStatement; 7223 if (awaitToken ? parseExpected(SyntaxKind.OfKeyword) : parseOptional(SyntaxKind.OfKeyword)) { 7224 const expression = allowInAnd(() => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true)); 7225 parseExpected(SyntaxKind.CloseParenToken); 7226 node = factory.createForOfStatement(awaitToken, initializer, expression, parseStatement()); 7227 } 7228 else if (parseOptional(SyntaxKind.InKeyword)) { 7229 const expression = allowInAnd(parseExpression); 7230 parseExpected(SyntaxKind.CloseParenToken); 7231 node = factory.createForInStatement(initializer, expression, parseStatement()); 7232 } 7233 else { 7234 parseExpected(SyntaxKind.SemicolonToken); 7235 const condition = token() !== SyntaxKind.SemicolonToken && token() !== SyntaxKind.CloseParenToken 7236 ? allowInAnd(parseExpression) 7237 : undefined; 7238 parseExpected(SyntaxKind.SemicolonToken); 7239 const incrementor = token() !== SyntaxKind.CloseParenToken 7240 ? allowInAnd(parseExpression) 7241 : undefined; 7242 parseExpected(SyntaxKind.CloseParenToken); 7243 node = factory.createForStatement(initializer, condition, incrementor, parseStatement()); 7244 } 7245 7246 return withJSDoc(finishNode(node, pos) as ForStatement | ForInOrOfStatement, hasJSDoc); 7247 } 7248 7249 function parseBreakOrContinueStatement(kind: SyntaxKind): BreakOrContinueStatement { 7250 const pos = getNodePos(); 7251 const hasJSDoc = hasPrecedingJSDocComment(); 7252 7253 parseExpected(kind === SyntaxKind.BreakStatement ? SyntaxKind.BreakKeyword : SyntaxKind.ContinueKeyword); 7254 const label = canParseSemicolon() ? undefined : parseIdentifier(); 7255 7256 parseSemicolon(); 7257 const node = kind === SyntaxKind.BreakStatement 7258 ? factory.createBreakStatement(label) 7259 : factory.createContinueStatement(label); 7260 return withJSDoc(finishNode(node, pos), hasJSDoc); 7261 } 7262 7263 function parseReturnStatement(): ReturnStatement { 7264 const pos = getNodePos(); 7265 const hasJSDoc = hasPrecedingJSDocComment(); 7266 parseExpected(SyntaxKind.ReturnKeyword); 7267 const expression = canParseSemicolon() ? undefined : allowInAnd(parseExpression); 7268 parseSemicolon(); 7269 return withJSDoc(finishNode(factory.createReturnStatement(expression), pos), hasJSDoc); 7270 } 7271 7272 function parseWithStatement(): WithStatement { 7273 const pos = getNodePos(); 7274 const hasJSDoc = hasPrecedingJSDocComment(); 7275 parseExpected(SyntaxKind.WithKeyword); 7276 const openParenPosition = scanner.getTokenPos(); 7277 const openParenParsed = parseExpected(SyntaxKind.OpenParenToken); 7278 const expression = allowInAnd(parseExpression); 7279 parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition); 7280 const statement = doInsideOfContext(NodeFlags.InWithStatement, parseStatement); 7281 return withJSDoc(finishNode(factory.createWithStatement(expression, statement), pos), hasJSDoc); 7282 } 7283 7284 function parseCaseClause(): CaseClause { 7285 const pos = getNodePos(); 7286 const hasJSDoc = hasPrecedingJSDocComment(); 7287 parseExpected(SyntaxKind.CaseKeyword); 7288 const expression = allowInAnd(parseExpression); 7289 parseExpected(SyntaxKind.ColonToken); 7290 const statements = parseList(ParsingContext.SwitchClauseStatements, parseStatement); 7291 return withJSDoc(finishNode(factory.createCaseClause(expression, statements), pos), hasJSDoc); 7292 } 7293 7294 function parseDefaultClause(): DefaultClause { 7295 const pos = getNodePos(); 7296 parseExpected(SyntaxKind.DefaultKeyword); 7297 parseExpected(SyntaxKind.ColonToken); 7298 const statements = parseList(ParsingContext.SwitchClauseStatements, parseStatement); 7299 return finishNode(factory.createDefaultClause(statements), pos); 7300 } 7301 7302 function parseCaseOrDefaultClause(): CaseOrDefaultClause { 7303 return token() === SyntaxKind.CaseKeyword ? parseCaseClause() : parseDefaultClause(); 7304 } 7305 7306 function parseCaseBlock(): CaseBlock { 7307 const pos = getNodePos(); 7308 parseExpected(SyntaxKind.OpenBraceToken); 7309 const clauses = parseList(ParsingContext.SwitchClauses, parseCaseOrDefaultClause); 7310 parseExpected(SyntaxKind.CloseBraceToken); 7311 return finishNode(factory.createCaseBlock(clauses), pos); 7312 } 7313 7314 function parseSwitchStatement(): SwitchStatement { 7315 const pos = getNodePos(); 7316 const hasJSDoc = hasPrecedingJSDocComment(); 7317 parseExpected(SyntaxKind.SwitchKeyword); 7318 parseExpected(SyntaxKind.OpenParenToken); 7319 const expression = allowInAnd(parseExpression); 7320 parseExpected(SyntaxKind.CloseParenToken); 7321 const caseBlock = parseCaseBlock(); 7322 return withJSDoc(finishNode(factory.createSwitchStatement(expression, caseBlock), pos), hasJSDoc); 7323 } 7324 7325 function parseThrowStatement(): ThrowStatement { 7326 // ThrowStatement[Yield] : 7327 // throw [no LineTerminator here]Expression[In, ?Yield]; 7328 7329 const pos = getNodePos(); 7330 const hasJSDoc = hasPrecedingJSDocComment(); 7331 parseExpected(SyntaxKind.ThrowKeyword); 7332 7333 // Because of automatic semicolon insertion, we need to report error if this 7334 // throw could be terminated with a semicolon. Note: we can't call 'parseExpression' 7335 // directly as that might consume an expression on the following line. 7336 // Instead, we create a "missing" identifier, but don't report an error. The actual error 7337 // will be reported in the grammar walker. 7338 let expression = scanner.hasPrecedingLineBreak() ? undefined : allowInAnd(parseExpression); 7339 if (expression === undefined) { 7340 identifierCount++; 7341 expression = finishNode(factory.createIdentifier(""), getNodePos()); 7342 } 7343 if (!tryParseSemicolon()) { 7344 parseErrorForMissingSemicolonAfter(expression); 7345 } 7346 return withJSDoc(finishNode(factory.createThrowStatement(expression), pos), hasJSDoc); 7347 } 7348 7349 // TODO: Review for error recovery 7350 function parseTryStatement(): TryStatement { 7351 const pos = getNodePos(); 7352 const hasJSDoc = hasPrecedingJSDocComment(); 7353 7354 parseExpected(SyntaxKind.TryKeyword); 7355 const tryBlock = parseBlock(/*ignoreMissingOpenBrace*/ false); 7356 const catchClause = token() === SyntaxKind.CatchKeyword ? parseCatchClause() : undefined; 7357 7358 // If we don't have a catch clause, then we must have a finally clause. Try to parse 7359 // one out no matter what. 7360 let finallyBlock: Block | undefined; 7361 if (!catchClause || token() === SyntaxKind.FinallyKeyword) { 7362 parseExpected(SyntaxKind.FinallyKeyword, Diagnostics.catch_or_finally_expected); 7363 finallyBlock = parseBlock(/*ignoreMissingOpenBrace*/ false); 7364 } 7365 7366 return withJSDoc(finishNode(factory.createTryStatement(tryBlock, catchClause, finallyBlock), pos), hasJSDoc); 7367 } 7368 7369 function parseCatchClause(): CatchClause { 7370 const pos = getNodePos(); 7371 parseExpected(SyntaxKind.CatchKeyword); 7372 7373 let variableDeclaration; 7374 if (parseOptional(SyntaxKind.OpenParenToken)) { 7375 variableDeclaration = parseVariableDeclaration(); 7376 parseExpected(SyntaxKind.CloseParenToken); 7377 } 7378 else { 7379 // Keep shape of node to avoid degrading performance. 7380 variableDeclaration = undefined; 7381 } 7382 7383 const block = parseBlock(/*ignoreMissingOpenBrace*/ false); 7384 return finishNode(factory.createCatchClause(variableDeclaration, block), pos); 7385 } 7386 7387 function parseDebuggerStatement(): Statement { 7388 const pos = getNodePos(); 7389 const hasJSDoc = hasPrecedingJSDocComment(); 7390 parseExpected(SyntaxKind.DebuggerKeyword); 7391 parseSemicolon(); 7392 return withJSDoc(finishNode(factory.createDebuggerStatement(), pos), hasJSDoc); 7393 } 7394 7395 function parseExpressionOrLabeledStatement(): ExpressionStatement | LabeledStatement { 7396 // Avoiding having to do the lookahead for a labeled statement by just trying to parse 7397 // out an expression, seeing if it is identifier and then seeing if it is followed by 7398 // a colon. 7399 const pos = getNodePos(); 7400 let hasJSDoc = hasPrecedingJSDocComment(); 7401 let node: ExpressionStatement | LabeledStatement; 7402 const hasParen = token() === SyntaxKind.OpenParenToken; 7403 const expression = allowInAnd(parseExpression); 7404 if (ts.isIdentifier(expression) && parseOptional(SyntaxKind.ColonToken)) { 7405 node = factory.createLabeledStatement(expression, parseStatement()); 7406 } 7407 else { 7408 if (!tryParseSemicolon()) { 7409 parseErrorForMissingSemicolonAfter(expression); 7410 } 7411 node = factory.createExpressionStatement(expression); 7412 if (hasParen) { 7413 // do not parse the same jsdoc twice 7414 hasJSDoc = false; 7415 } 7416 } 7417 return withJSDoc(finishNode(node, pos), hasJSDoc); 7418 } 7419 7420 function nextTokenIsIdentifierOrKeywordOnSameLine() { 7421 nextToken(); 7422 return tokenIsIdentifierOrKeyword(token()) && !scanner.hasPrecedingLineBreak(); 7423 } 7424 7425 function nextTokenIsClassKeywordOnSameLine() { 7426 nextToken(); 7427 return token() === SyntaxKind.ClassKeyword && !scanner.hasPrecedingLineBreak(); 7428 } 7429 7430 function nextTokenIsFunctionKeywordOnSameLine() { 7431 nextToken(); 7432 return token() === SyntaxKind.FunctionKeyword && !scanner.hasPrecedingLineBreak(); 7433 } 7434 7435 function nextTokenIsIdentifierOrKeywordOrLiteralOnSameLine() { 7436 nextToken(); 7437 return (tokenIsIdentifierOrKeyword(token()) || token() === SyntaxKind.NumericLiteral || token() === SyntaxKind.BigIntLiteral || token() === SyntaxKind.StringLiteral) && !scanner.hasPrecedingLineBreak(); 7438 } 7439 7440 function isDeclaration(): boolean { 7441 while (true) { 7442 switch (token()) { 7443 case SyntaxKind.VarKeyword: 7444 case SyntaxKind.LetKeyword: 7445 case SyntaxKind.ConstKeyword: 7446 case SyntaxKind.FunctionKeyword: 7447 case SyntaxKind.ClassKeyword: 7448 case SyntaxKind.EnumKeyword: 7449 return true; 7450 case SyntaxKind.StructKeyword: 7451 return inEtsContext(); 7452 case SyntaxKind.AtToken: 7453 return inAllowAnnotationContext() && nextToken() === SyntaxKind.InterfaceKeyword; 7454 // 'declare', 'module', 'namespace', 'interface'* and 'type' are all legal JavaScript identifiers; 7455 // however, an identifier cannot be followed by another identifier on the same line. This is what we 7456 // count on to parse out the respective declarations. For instance, we exploit this to say that 7457 // 7458 // namespace n 7459 // 7460 // can be none other than the beginning of a namespace declaration, but need to respect that JavaScript sees 7461 // 7462 // namespace 7463 // n 7464 // 7465 // as the identifier 'namespace' on one line followed by the identifier 'n' on another. 7466 // We need to look one token ahead to see if it permissible to try parsing a declaration. 7467 // 7468 // *Note*: 'interface' is actually a strict mode reserved word. So while 7469 // 7470 // "use strict" 7471 // interface 7472 // I {} 7473 // 7474 // could be legal, it would add complexity for very little gain. 7475 case SyntaxKind.InterfaceKeyword: 7476 case SyntaxKind.TypeKeyword: 7477 return nextTokenIsIdentifierOnSameLine(); 7478 case SyntaxKind.ModuleKeyword: 7479 case SyntaxKind.NamespaceKeyword: 7480 return nextTokenIsIdentifierOrStringLiteralOnSameLine(); 7481 case SyntaxKind.AbstractKeyword: 7482 case SyntaxKind.AccessorKeyword: 7483 case SyntaxKind.AsyncKeyword: 7484 case SyntaxKind.DeclareKeyword: 7485 case SyntaxKind.PrivateKeyword: 7486 case SyntaxKind.ProtectedKeyword: 7487 case SyntaxKind.PublicKeyword: 7488 case SyntaxKind.ReadonlyKeyword: 7489 nextToken(); 7490 // ASI takes effect for this modifier. 7491 if (scanner.hasPrecedingLineBreak()) { 7492 return false; 7493 } 7494 continue; 7495 7496 case SyntaxKind.GlobalKeyword: 7497 nextToken(); 7498 return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.Identifier || token() === SyntaxKind.ExportKeyword; 7499 7500 case SyntaxKind.ImportKeyword: 7501 nextToken(); 7502 return token() === SyntaxKind.StringLiteral || token() === SyntaxKind.AsteriskToken || 7503 token() === SyntaxKind.OpenBraceToken || tokenIsIdentifierOrKeyword(token()); 7504 case SyntaxKind.ExportKeyword: 7505 let currentToken = nextToken(); 7506 if (currentToken === SyntaxKind.TypeKeyword) { 7507 currentToken = lookAhead(nextToken); 7508 } 7509 if (currentToken === SyntaxKind.EqualsToken || currentToken === SyntaxKind.AsteriskToken || 7510 currentToken === SyntaxKind.OpenBraceToken || currentToken === SyntaxKind.DefaultKeyword || 7511 currentToken === SyntaxKind.AsKeyword) { 7512 return true; 7513 } 7514 continue; 7515 7516 case SyntaxKind.StaticKeyword: 7517 nextToken(); 7518 continue; 7519 default: 7520 return false; 7521 } 7522 } 7523 } 7524 7525 function isStartOfDeclaration(): boolean { 7526 return lookAhead(isDeclaration); 7527 } 7528 7529 function isStartOfStatement(): boolean { 7530 switch (token()) { 7531 case SyntaxKind.AtToken: 7532 case SyntaxKind.SemicolonToken: 7533 case SyntaxKind.OpenBraceToken: 7534 case SyntaxKind.VarKeyword: 7535 case SyntaxKind.LetKeyword: 7536 case SyntaxKind.FunctionKeyword: 7537 case SyntaxKind.ClassKeyword: 7538 case SyntaxKind.EnumKeyword: 7539 case SyntaxKind.IfKeyword: 7540 case SyntaxKind.DoKeyword: 7541 case SyntaxKind.WhileKeyword: 7542 case SyntaxKind.ForKeyword: 7543 case SyntaxKind.ContinueKeyword: 7544 case SyntaxKind.BreakKeyword: 7545 case SyntaxKind.ReturnKeyword: 7546 case SyntaxKind.WithKeyword: 7547 case SyntaxKind.SwitchKeyword: 7548 case SyntaxKind.ThrowKeyword: 7549 case SyntaxKind.TryKeyword: 7550 case SyntaxKind.DebuggerKeyword: 7551 // 'catch' and 'finally' do not actually indicate that the code is part of a statement, 7552 // however, we say they are here so that we may gracefully parse them and error later. 7553 // falls through 7554 case SyntaxKind.CatchKeyword: 7555 case SyntaxKind.FinallyKeyword: 7556 return true; 7557 case SyntaxKind.StructKeyword: 7558 return inEtsContext(); 7559 7560 case SyntaxKind.ImportKeyword: 7561 return isStartOfDeclaration() || lookAhead(nextTokenIsOpenParenOrLessThanOrDot); 7562 7563 case SyntaxKind.ConstKeyword: 7564 case SyntaxKind.ExportKeyword: 7565 return isStartOfDeclaration(); 7566 7567 case SyntaxKind.AsyncKeyword: 7568 case SyntaxKind.DeclareKeyword: 7569 case SyntaxKind.InterfaceKeyword: 7570 case SyntaxKind.ModuleKeyword: 7571 case SyntaxKind.NamespaceKeyword: 7572 case SyntaxKind.TypeKeyword: 7573 case SyntaxKind.GlobalKeyword: 7574 // When these don't start a declaration, they're an identifier in an expression statement 7575 return true; 7576 7577 case SyntaxKind.AccessorKeyword: 7578 case SyntaxKind.PublicKeyword: 7579 case SyntaxKind.PrivateKeyword: 7580 case SyntaxKind.ProtectedKeyword: 7581 case SyntaxKind.StaticKeyword: 7582 case SyntaxKind.ReadonlyKeyword: 7583 // When these don't start a declaration, they may be the start of a class member if an identifier 7584 // immediately follows. Otherwise they're an identifier in an expression statement. 7585 return isStartOfDeclaration() || !lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine); 7586 7587 default: 7588 return isStartOfExpression(); 7589 } 7590 } 7591 7592 function nextTokenIsBindingIdentifierOrStartOfDestructuring() { 7593 nextToken(); 7594 return isBindingIdentifier() || token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.OpenBracketToken; 7595 } 7596 7597 function isLetDeclaration() { 7598 // In ES6 'let' always starts a lexical declaration if followed by an identifier or { 7599 // or [. 7600 return lookAhead(nextTokenIsBindingIdentifierOrStartOfDestructuring); 7601 } 7602 7603 function parseStatement(): Statement { 7604 switch (token()) { 7605 case SyntaxKind.SemicolonToken: 7606 return parseEmptyStatement(); 7607 case SyntaxKind.OpenBraceToken: 7608 return parseBlock(/*ignoreMissingOpenBrace*/ false); 7609 case SyntaxKind.VarKeyword: 7610 return parseVariableStatement(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined); 7611 case SyntaxKind.LetKeyword: 7612 if (isLetDeclaration()) { 7613 return parseVariableStatement(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined); 7614 } 7615 break; 7616 case SyntaxKind.FunctionKeyword: 7617 return parseFunctionDeclaration(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined); 7618 case SyntaxKind.StructKeyword: 7619 if (inEtsContext()) { 7620 return parseStructDeclaration(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined); 7621 } 7622 break; 7623 case SyntaxKind.ClassKeyword: 7624 return parseClassDeclaration(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined); 7625 case SyntaxKind.IfKeyword: 7626 return parseIfStatement(); 7627 case SyntaxKind.DoKeyword: 7628 return parseDoStatement(); 7629 case SyntaxKind.WhileKeyword: 7630 return parseWhileStatement(); 7631 case SyntaxKind.ForKeyword: 7632 return parseForOrForInOrForOfStatement(); 7633 case SyntaxKind.ContinueKeyword: 7634 return parseBreakOrContinueStatement(SyntaxKind.ContinueStatement); 7635 case SyntaxKind.BreakKeyword: 7636 return parseBreakOrContinueStatement(SyntaxKind.BreakStatement); 7637 case SyntaxKind.ReturnKeyword: 7638 return parseReturnStatement(); 7639 case SyntaxKind.WithKeyword: 7640 return parseWithStatement(); 7641 case SyntaxKind.SwitchKeyword: 7642 return parseSwitchStatement(); 7643 case SyntaxKind.ThrowKeyword: 7644 return parseThrowStatement(); 7645 case SyntaxKind.TryKeyword: 7646 // Include 'catch' and 'finally' for error recovery. 7647 // falls through 7648 case SyntaxKind.CatchKeyword: 7649 case SyntaxKind.FinallyKeyword: 7650 return parseTryStatement(); 7651 case SyntaxKind.DebuggerKeyword: 7652 return parseDebuggerStatement(); 7653 case SyntaxKind.AtToken: 7654 return parseDeclaration(); 7655 case SyntaxKind.AsyncKeyword: 7656 case SyntaxKind.InterfaceKeyword: 7657 case SyntaxKind.TypeKeyword: 7658 case SyntaxKind.ModuleKeyword: 7659 case SyntaxKind.NamespaceKeyword: 7660 case SyntaxKind.DeclareKeyword: 7661 case SyntaxKind.ConstKeyword: 7662 case SyntaxKind.EnumKeyword: 7663 case SyntaxKind.ExportKeyword: 7664 case SyntaxKind.ImportKeyword: 7665 case SyntaxKind.PrivateKeyword: 7666 case SyntaxKind.ProtectedKeyword: 7667 case SyntaxKind.PublicKeyword: 7668 case SyntaxKind.AbstractKeyword: 7669 case SyntaxKind.AccessorKeyword: 7670 case SyntaxKind.StaticKeyword: 7671 case SyntaxKind.ReadonlyKeyword: 7672 case SyntaxKind.GlobalKeyword: 7673 if (isStartOfDeclaration()) { 7674 return parseDeclaration(); 7675 } 7676 break; 7677 } 7678 return parseExpressionOrLabeledStatement(); 7679 } 7680 7681 function isDeclareModifier(modifier: Modifier) { 7682 return modifier.kind === SyntaxKind.DeclareKeyword; 7683 } 7684 7685 function parseAnnotationDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, 7686 modifiers: NodeArray<Modifier> | undefined): AnnotationDeclaration { 7687 const atTokenPos = scanner.getTokenPos(); 7688 parseExpected(SyntaxKind.AtToken); 7689 const interfaceTokenPos = scanner.getTokenPos(); 7690 parseExpected(SyntaxKind.InterfaceKeyword); 7691 7692 // Prevent any tokens between '@' and 'interface' 7693 if (interfaceTokenPos - atTokenPos > 1) { 7694 parseErrorAt(atTokenPos + 1, interfaceTokenPos, Diagnostics.In_annotation_declaration_any_symbols_between_and_interface_are_forbidden); 7695 } 7696 7697 const name = createIdentifier(isBindingIdentifier()); 7698 let members; 7699 if (parseExpected(SyntaxKind.OpenBraceToken)) { 7700 members = parseAnnotationMembers(); 7701 parseExpected(SyntaxKind.CloseBraceToken); 7702 } 7703 else { 7704 members = createMissingList<AnnotationElement>(); 7705 } 7706 const node = factory.createAnnotationDeclaration(combineDecoratorsAndModifiers(decorators, modifiers), name, members); 7707 return withJSDoc(finishNode(node, pos), hasJSDoc); 7708 } 7709 7710 function parseDeclaration(): Statement { 7711 // `parseListElement` attempted to get the reused node at this position, 7712 // but the ambient context flag was not yet set, so the node appeared 7713 // not reusable in that context. 7714 const pos = getNodePos(); 7715 const hasJSDoc = hasPrecedingJSDocComment(); 7716 const decorators = parseDecorators(); 7717 7718 if (token() === SyntaxKind.FunctionKeyword || token() === SyntaxKind.ExportKeyword) { 7719 if (hasEtsExtendDecoratorNames(decorators, sourceFileCompilerOptions)) { 7720 const extendEtsComponentDecoratorNames = getEtsExtendDecoratorsComponentNames(decorators, sourceFileCompilerOptions); 7721 if (extendEtsComponentDecoratorNames.length > 0) { 7722 sourceFileCompilerOptions.ets?.extend.components.forEach(({ name, type, instance }) => { 7723 if (name === last(extendEtsComponentDecoratorNames)) { 7724 extendEtsComponentDeclaration = { name, type, instance }; 7725 } 7726 }); 7727 } 7728 setEtsExtendComponentsContext(!!extendEtsComponentDeclaration); 7729 } 7730 else if (hasEtsStylesDecoratorNames(decorators, sourceFileCompilerOptions)) { 7731 const stylesEtsComponentDecoratorNames = getEtsStylesDecoratorComponentNames(decorators, sourceFileCompilerOptions); 7732 if (stylesEtsComponentDecoratorNames.length > 0) { 7733 stylesEtsComponentDeclaration = sourceFileCompilerOptions.ets?.styles.component; 7734 } 7735 setEtsStylesComponentsContext(!!stylesEtsComponentDeclaration); 7736 } 7737 else { 7738 setEtsComponentsContext(isTokenInsideBuilder(decorators, sourceFileCompilerOptions)); 7739 } 7740 } 7741 7742 const modifiers = parseModifiers(); 7743 const isAmbient = some(modifiers, isDeclareModifier); 7744 if (isAmbient) { 7745 const node = tryReuseAmbientDeclaration(pos); 7746 if (node) { 7747 return node; 7748 } 7749 7750 for (const m of modifiers!) { 7751 (m as Mutable<Node>).flags |= NodeFlags.Ambient; 7752 } 7753 return doInsideOfContext(NodeFlags.Ambient, () => parseDeclarationWorker(pos, hasJSDoc, decorators, modifiers)); 7754 } 7755 else { 7756 return parseDeclarationWorker(pos, hasJSDoc, decorators, modifiers); 7757 } 7758 } 7759 7760 function tryReuseAmbientDeclaration(pos: number): Statement | undefined { 7761 return doInsideOfContext(NodeFlags.Ambient, () => { 7762 const node = currentNode(parsingContext, pos); 7763 if (node) { 7764 return consumeNode(node) as Statement; 7765 } 7766 }); 7767 } 7768 7769 function parseDeclarationWorker(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): Statement { 7770 switch (token()) { 7771 case SyntaxKind.VarKeyword: 7772 case SyntaxKind.LetKeyword: 7773 case SyntaxKind.ConstKeyword: 7774 return parseVariableStatement(pos, hasJSDoc, decorators, modifiers); 7775 case SyntaxKind.FunctionKeyword: 7776 return parseFunctionDeclaration(pos, hasJSDoc, decorators, modifiers); 7777 case SyntaxKind.ClassKeyword: 7778 return parseClassDeclaration(pos, hasJSDoc, decorators, modifiers); 7779 case SyntaxKind.StructKeyword: 7780 if (inEtsContext()) { 7781 return parseStructDeclaration(pos, hasJSDoc, decorators, modifiers); 7782 } 7783 return parseDeclarationDefault(pos,decorators, modifiers); 7784 case SyntaxKind.AtToken: 7785 if (inAllowAnnotationContext() && 7786 lookAhead(() => nextToken() === SyntaxKind.InterfaceKeyword)) { 7787 return parseAnnotationDeclaration(pos, hasJSDoc, decorators, modifiers); 7788 } 7789 return parseDeclarationDefault(pos, decorators, modifiers); 7790 case SyntaxKind.InterfaceKeyword: 7791 return parseInterfaceDeclaration(pos, hasJSDoc, decorators, modifiers); 7792 case SyntaxKind.TypeKeyword: 7793 return parseTypeAliasDeclaration(pos, hasJSDoc, decorators, modifiers); 7794 case SyntaxKind.EnumKeyword: 7795 return parseEnumDeclaration(pos, hasJSDoc, decorators, modifiers); 7796 case SyntaxKind.GlobalKeyword: 7797 case SyntaxKind.ModuleKeyword: 7798 case SyntaxKind.NamespaceKeyword: 7799 return parseModuleDeclaration(pos, hasJSDoc, decorators, modifiers); 7800 case SyntaxKind.ImportKeyword: 7801 return parseImportDeclarationOrImportEqualsDeclaration(pos, hasJSDoc, decorators, modifiers); 7802 case SyntaxKind.ExportKeyword: 7803 nextToken(); 7804 switch (token()) { 7805 case SyntaxKind.DefaultKeyword: 7806 case SyntaxKind.EqualsToken: 7807 return parseExportAssignment(pos, hasJSDoc, decorators, modifiers); 7808 case SyntaxKind.AsKeyword: 7809 return parseNamespaceExportDeclaration(pos, hasJSDoc, decorators, modifiers); 7810 default: 7811 return parseExportDeclaration(pos, hasJSDoc, decorators, modifiers); 7812 } 7813 default: 7814 return parseDeclarationDefault(pos,decorators, modifiers); 7815 } 7816 } 7817 7818 function parseDeclarationDefault(pos: number,decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): Statement { 7819 if (decorators || modifiers) { 7820 // We reached this point because we encountered decorators and/or modifiers and assumed a declaration 7821 // would follow. For recovery and error reporting purposes, return an incomplete declaration. 7822 const missing = createMissingNode<MissingDeclaration>(SyntaxKind.MissingDeclaration, /*reportAtCurrentPosition*/ true, Diagnostics.Declaration_expected); 7823 setTextRangePos(missing, pos); 7824 missing.illegalDecorators = decorators; 7825 missing.modifiers = modifiers; 7826 return missing; 7827 } 7828 return undefined!; // TODO: GH#18217 7829 } 7830 7831 function nextTokenIsIdentifierOrStringLiteralOnSameLine() { 7832 nextToken(); 7833 return !scanner.hasPrecedingLineBreak() && (isIdentifier() || token() === SyntaxKind.StringLiteral); 7834 } 7835 7836 function parseFunctionBlockOrSemicolon(flags: SignatureFlags, diagnosticMessage?: DiagnosticMessage): Block | undefined { 7837 if (token() !== SyntaxKind.OpenBraceToken) { 7838 if (flags & SignatureFlags.Type) { 7839 parseTypeMemberSemicolon(); 7840 return; 7841 } 7842 if (canParseSemicolon()) { 7843 parseSemicolon(); 7844 return; 7845 } 7846 } 7847 return parseFunctionBlock(flags, diagnosticMessage); 7848 } 7849 7850 // DECLARATIONS 7851 7852 function parseArrayBindingElement(): ArrayBindingElement { 7853 const pos = getNodePos(); 7854 if (token() === SyntaxKind.CommaToken) { 7855 return finishNode(factory.createOmittedExpression(), pos); 7856 } 7857 const dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); 7858 const name = parseIdentifierOrPattern(); 7859 const initializer = parseInitializer(); 7860 return finishNode(factory.createBindingElement(dotDotDotToken, /*propertyName*/ undefined, name, initializer), pos); 7861 } 7862 7863 function parseObjectBindingElement(): BindingElement { 7864 const pos = getNodePos(); 7865 const dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); 7866 const tokenIsIdentifier = isBindingIdentifier(); 7867 let propertyName: PropertyName | undefined = parsePropertyName(); 7868 let name: BindingName; 7869 if (tokenIsIdentifier && token() !== SyntaxKind.ColonToken) { 7870 name = propertyName as Identifier; 7871 propertyName = undefined; 7872 } 7873 else { 7874 parseExpected(SyntaxKind.ColonToken); 7875 name = parseIdentifierOrPattern(); 7876 } 7877 const initializer = parseInitializer(); 7878 return finishNode(factory.createBindingElement(dotDotDotToken, propertyName, name, initializer), pos); 7879 } 7880 7881 function parseObjectBindingPattern(): ObjectBindingPattern { 7882 const pos = getNodePos(); 7883 parseExpected(SyntaxKind.OpenBraceToken); 7884 const elements = parseDelimitedList(ParsingContext.ObjectBindingElements, parseObjectBindingElement); 7885 parseExpected(SyntaxKind.CloseBraceToken); 7886 return finishNode(factory.createObjectBindingPattern(elements), pos); 7887 } 7888 7889 function parseArrayBindingPattern(): ArrayBindingPattern { 7890 const pos = getNodePos(); 7891 parseExpected(SyntaxKind.OpenBracketToken); 7892 const elements = parseDelimitedList(ParsingContext.ArrayBindingElements, parseArrayBindingElement); 7893 parseExpected(SyntaxKind.CloseBracketToken); 7894 return finishNode(factory.createArrayBindingPattern(elements), pos); 7895 } 7896 7897 function isBindingIdentifierOrPrivateIdentifierOrPattern() { 7898 return token() === SyntaxKind.OpenBraceToken 7899 || token() === SyntaxKind.OpenBracketToken 7900 || token() === SyntaxKind.PrivateIdentifier 7901 || isBindingIdentifier(); 7902 } 7903 7904 function parseIdentifierOrPattern(privateIdentifierDiagnosticMessage?: DiagnosticMessage): Identifier | BindingPattern { 7905 if (token() === SyntaxKind.OpenBracketToken) { 7906 return parseArrayBindingPattern(); 7907 } 7908 if (token() === SyntaxKind.OpenBraceToken) { 7909 return parseObjectBindingPattern(); 7910 } 7911 return parseBindingIdentifier(privateIdentifierDiagnosticMessage); 7912 } 7913 7914 function parseVariableDeclarationAllowExclamation() { 7915 return parseVariableDeclaration(/*allowExclamation*/ true); 7916 } 7917 7918 function parseVariableDeclaration(allowExclamation?: boolean): VariableDeclaration { 7919 const pos = getNodePos(); 7920 const hasJSDoc = hasPrecedingJSDocComment(); 7921 const name = parseIdentifierOrPattern(Diagnostics.Private_identifiers_are_not_allowed_in_variable_declarations); 7922 let exclamationToken: ExclamationToken | undefined; 7923 if (allowExclamation && name.kind === SyntaxKind.Identifier && 7924 token() === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak()) { 7925 exclamationToken = parseTokenNode<Token<SyntaxKind.ExclamationToken>>(); 7926 } 7927 const type = parseTypeAnnotation(); 7928 const initializer = isInOrOfKeyword(token()) ? undefined : parseInitializer(); 7929 const node = factory.createVariableDeclaration(name, exclamationToken, type, initializer); 7930 return withJSDoc(finishNode(node, pos), hasJSDoc); 7931 } 7932 7933 function parseVariableDeclarationList(inForStatementInitializer: boolean): VariableDeclarationList { 7934 const pos = getNodePos(); 7935 7936 let flags: NodeFlags = 0; 7937 switch (token()) { 7938 case SyntaxKind.VarKeyword: 7939 break; 7940 case SyntaxKind.LetKeyword: 7941 flags |= NodeFlags.Let; 7942 break; 7943 case SyntaxKind.ConstKeyword: 7944 flags |= NodeFlags.Const; 7945 break; 7946 default: 7947 Debug.fail(); 7948 } 7949 7950 nextToken(); 7951 7952 // The user may have written the following: 7953 // 7954 // for (let of X) { } 7955 // 7956 // In this case, we want to parse an empty declaration list, and then parse 'of' 7957 // as a keyword. The reason this is not automatic is that 'of' is a valid identifier. 7958 // So we need to look ahead to determine if 'of' should be treated as a keyword in 7959 // this context. 7960 // The checker will then give an error that there is an empty declaration list. 7961 let declarations: readonly VariableDeclaration[]; 7962 if (token() === SyntaxKind.OfKeyword && lookAhead(canFollowContextualOfKeyword)) { 7963 declarations = createMissingList<VariableDeclaration>(); 7964 } 7965 else { 7966 const savedDisallowIn = inDisallowInContext(); 7967 setDisallowInContext(inForStatementInitializer); 7968 7969 declarations = parseDelimitedList(ParsingContext.VariableDeclarations, 7970 inForStatementInitializer ? parseVariableDeclaration : parseVariableDeclarationAllowExclamation); 7971 7972 setDisallowInContext(savedDisallowIn); 7973 } 7974 7975 return finishNode(factory.createVariableDeclarationList(declarations, flags), pos); 7976 } 7977 7978 function canFollowContextualOfKeyword(): boolean { 7979 return nextTokenIsIdentifier() && nextToken() === SyntaxKind.CloseParenToken; 7980 } 7981 7982 function parseVariableStatement(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): VariableStatement { 7983 const declarationList = parseVariableDeclarationList(/*inForStatementInitializer*/ false); 7984 parseSemicolon(); 7985 const node = factory.createVariableStatement(modifiers, declarationList); 7986 // Decorators are not allowed on a variable statement, so we keep track of them to report them in the grammar checker. 7987 node.illegalDecorators = decorators; 7988 return withJSDoc(finishNode(node, pos), hasJSDoc); 7989 } 7990 7991 function parseFunctionDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): FunctionDeclaration { 7992 const savedAwaitContext = inAwaitContext(); 7993 7994 const modifierFlags = modifiersToFlags(modifiers); 7995 parseExpected(SyntaxKind.FunctionKeyword); 7996 const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); 7997 // We don't parse the name here in await context, instead we will report a grammar error in the checker. 7998 const name = modifierFlags & ModifierFlags.Default ? parseOptionalBindingIdentifier() : parseBindingIdentifier(); 7999 if(name && hasEtsStylesDecoratorNames(decorators, sourceFileCompilerOptions)) { 8000 fileStylesComponents.set(name.escapedText.toString(), SyntaxKind.FunctionDeclaration); 8001 } 8002 const originalUICallbackContext = inUICallbackContext(); 8003 setEtsBuilderContext(hasEtsBuilderDecoratorNames(decorators, sourceFileCompilerOptions)); 8004 setUICallbackContext(inBuilderContext()); 8005 const isGenerator = asteriskToken ? SignatureFlags.Yield : SignatureFlags.None; 8006 const isAsync = modifierFlags & ModifierFlags.Async ? SignatureFlags.Await : SignatureFlags.None; 8007 const typeParameters = inEtsStylesComponentsContext() && stylesEtsComponentDeclaration ? parseEtsTypeParameters(scanner.getStartPos()) : parseTypeParameters(); 8008 if (modifierFlags & ModifierFlags.Export) setAwaitContext(/*value*/ true); 8009 const parameters = parseParameters(isGenerator | isAsync); 8010 const typeStartPos = scanner.getStartPos(); 8011 const type = getFunctionDeclarationReturnType(); 8012 const body = parseFunctionBlockOrSemicolon(isGenerator | isAsync, Diagnostics.or_expected); 8013 setEtsBuilderContext(false); 8014 setUICallbackContext(originalUICallbackContext); 8015 setEtsExtendComponentsContext(false); 8016 extendEtsComponentDeclaration = undefined; 8017 setEtsStylesComponentsContext(false); 8018 stylesEtsComponentDeclaration = undefined; 8019 setEtsComponentsContext(inBuildContext()); 8020 setAwaitContext(savedAwaitContext); 8021 const node = factory.createFunctionDeclaration(modifiers, asteriskToken, name, typeParameters, parameters, type, body); 8022 (node as Mutable<FunctionDeclaration>).illegalDecorators = decorators; 8023 return withJSDoc(finishNode(node, pos), hasJSDoc); 8024 8025 function getFunctionDeclarationReturnType(): TypeNode | undefined { 8026 let returnType = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false); 8027 // If function decorated by Extend and type is not defined, then will use Ets Extend Components Type 8028 if (!returnType && extendEtsComponentDeclaration && inEtsExtendComponentsContext()) { 8029 returnType = finishVirtualNode(factory.createTypeReferenceNode( 8030 finishVirtualNode(factory.createIdentifier(extendEtsComponentDeclaration.type), typeStartPos, typeStartPos)), 8031 typeStartPos, typeStartPos); 8032 } 8033 // If function decorated by Styles and type is not defined, then will use Ets Styles Components Type 8034 if (!returnType && stylesEtsComponentDeclaration && inEtsStylesComponentsContext()) { 8035 returnType = finishVirtualNode(factory.createTypeReferenceNode( 8036 finishVirtualNode(factory.createIdentifier(stylesEtsComponentDeclaration.type), typeStartPos, typeStartPos)), 8037 typeStartPos, typeStartPos); 8038 } 8039 return returnType; 8040 } 8041 } 8042 8043 function parseConstructorName() { 8044 if (token() === SyntaxKind.ConstructorKeyword) { 8045 return parseExpected(SyntaxKind.ConstructorKeyword); 8046 } 8047 if (token() === SyntaxKind.StringLiteral && lookAhead(nextToken) === SyntaxKind.OpenParenToken) { 8048 return tryParse(() => { 8049 const literalNode = parseLiteralNode(); 8050 return literalNode.text === "constructor" ? literalNode : undefined; 8051 }); 8052 } 8053 } 8054 8055 function tryParseConstructorDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ConstructorDeclaration | undefined { 8056 return tryParse(() => { 8057 if (parseConstructorName()) { 8058 const typeParameters = parseTypeParameters(); 8059 const parameters = parseParameters(SignatureFlags.None); 8060 const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false); 8061 const body = parseFunctionBlockOrSemicolon(SignatureFlags.None, Diagnostics.or_expected); 8062 const node = factory.createConstructorDeclaration(modifiers, parameters, body); 8063 8064 // Attach invalid nodes if they exist so that we can report them in the grammar checker. 8065 (node as Mutable<ConstructorDeclaration>).illegalDecorators = decorators; 8066 (node as Mutable<ConstructorDeclaration>).typeParameters = typeParameters; 8067 (node as Mutable<ConstructorDeclaration>).type = type; 8068 return withJSDoc(finishNode(node, pos), hasJSDoc); 8069 } 8070 }); 8071 } 8072 8073 8074 function isTokenInsideStructBuild(methodName: PropertyName): boolean { 8075 const renderMethod = sourceFileCompilerOptions.ets?.render?.method?.find(render => render === "build") ?? "build"; 8076 8077 if (methodName.kind === SyntaxKind.Identifier && methodName.escapedText === renderMethod) { 8078 return true; 8079 } 8080 return false; 8081 } 8082 8083 function isTokenInsideStructBuilder(decorators: NodeArray<Decorator> | undefined): boolean { 8084 return isTokenInsideBuilder(decorators, sourceFileCompilerOptions); 8085 } 8086 8087 function isTokenInsideStructPageTransition(methodName: PropertyName): boolean { 8088 const renderMethod = sourceFileCompilerOptions.ets?.render?.method?.find(render => render === "pageTransition") ?? "pageTransition"; 8089 8090 if (methodName.kind === SyntaxKind.Identifier && methodName.escapedText === renderMethod) { 8091 return true; 8092 } 8093 return false; 8094 } 8095 8096 function parseMethodDeclaration( 8097 pos: number, 8098 hasJSDoc: boolean, 8099 decorators: NodeArray<Decorator> | undefined, 8100 modifiers: NodeArray<Modifier> | undefined, 8101 asteriskToken: AsteriskToken | undefined, 8102 name: PropertyName, 8103 questionToken: QuestionToken | undefined, 8104 exclamationToken: ExclamationToken | undefined, 8105 diagnosticMessage?: DiagnosticMessage 8106 ): MethodDeclaration { 8107 const methodName = getPropertyNameForPropertyNameNode(name)?.toString(); 8108 const orignalEtsBuildContext = inBuildContext(); 8109 const orignalEtsBuilderContext = inBuilderContext(); 8110 const orignalUICallbackContext = inUICallbackContext(); 8111 setEtsBuildContext(methodName === sourceFileCompilerOptions?.ets?.render?.method?.find(render => render === "build")); 8112 setEtsBuilderContext(hasEtsBuilderDecoratorNames(decorators, sourceFileCompilerOptions)); 8113 setUICallbackContext(inBuildContext() || inBuilderContext()); 8114 if (inStructContext() && hasEtsStylesDecoratorNames(decorators, sourceFileCompilerOptions)) { 8115 if (methodName && currentStructName) { 8116 structStylesComponents.set(methodName, { structName: currentStructName, kind: SyntaxKind.MethodDeclaration }); 8117 } 8118 const stylesEtsComponentDecoratorNames = getEtsStylesDecoratorComponentNames(decorators, sourceFileCompilerOptions); 8119 if (stylesEtsComponentDecoratorNames.length > 0) { 8120 stylesEtsComponentDeclaration = sourceFileCompilerOptions.ets?.styles.component; 8121 } 8122 setEtsStylesComponentsContext(!!stylesEtsComponentDeclaration); 8123 } 8124 const orignalEtsComponentsContext: boolean = inEtsComponentsContext(); 8125 setEtsComponentsContext(inStructContext() && (isTokenInsideStructBuild(name) || isTokenInsideStructBuilder(decorators) || 8126 isTokenInsideStructPageTransition(name))); 8127 const isGenerator = asteriskToken ? SignatureFlags.Yield : SignatureFlags.None; 8128 const isAsync = some(modifiers, isAsyncModifier) ? SignatureFlags.Await : SignatureFlags.None; 8129 const typeParameters = inEtsStylesComponentsContext() && stylesEtsComponentDeclaration ? parseEtsTypeParameters(pos) : parseTypeParameters(); 8130 const parameters = parseParameters(isGenerator | isAsync); 8131 const typeStartPos = scanner.getStartPos(); 8132 const type = getMethodDeclarationReturnType(); 8133 const body = parseFunctionBlockOrSemicolon(isGenerator | isAsync, diagnosticMessage); 8134 const node = factory.createMethodDeclaration( 8135 combineDecoratorsAndModifiers(decorators, modifiers), 8136 asteriskToken, 8137 name, 8138 questionToken, 8139 typeParameters, 8140 parameters, 8141 type, 8142 body 8143 ); 8144 8145 // An exclamation token on a method is invalid syntax and will be handled by the grammar checker 8146 (node as Mutable<MethodDeclaration>).exclamationToken = exclamationToken; 8147 setEtsBuildContext(orignalEtsBuildContext); 8148 setEtsBuilderContext(orignalEtsBuilderContext); 8149 setUICallbackContext(orignalUICallbackContext); 8150 setEtsStylesComponentsContext(false); 8151 stylesEtsComponentDeclaration = undefined; 8152 setEtsComponentsContext(orignalEtsComponentsContext); 8153 return withJSDoc(finishNode(node, pos), hasJSDoc); 8154 8155 function getMethodDeclarationReturnType(): TypeNode | undefined { 8156 let returnType = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false); 8157 // If function decorated by Styles and type is not defined, then will use Ets Styles Components Type 8158 if (!returnType && stylesEtsComponentDeclaration && inEtsStylesComponentsContext()) { 8159 returnType = finishVirtualNode(factory.createTypeReferenceNode( 8160 finishVirtualNode(factory.createIdentifier(stylesEtsComponentDeclaration.type), typeStartPos, typeStartPos)), 8161 typeStartPos, typeStartPos); 8162 } 8163 return returnType; 8164 } 8165 } 8166 8167 function parseAnnotationPropertyDeclaration( 8168 pos: number, 8169 hasJSDoc: boolean, 8170 name: PropertyName 8171 ): AnnotationPropertyDeclaration { 8172 const type = parseTypeAnnotation(); 8173 const initializer = doOutsideOfContext(NodeFlags.YieldContext | NodeFlags.AwaitContext | NodeFlags.DisallowInContext, parseInitializer); 8174 parseSemicolonAfterPropertyName(name, type, initializer); 8175 const node = factory.createAnnotationPropertyDeclaration( 8176 name, 8177 type, 8178 initializer); 8179 return withJSDoc(finishNode(node, pos), hasJSDoc); 8180 } 8181 8182 function parsePropertyDeclaration( 8183 pos: number, 8184 hasJSDoc: boolean, 8185 decorators: NodeArray<Decorator> | undefined, 8186 modifiers: NodeArray<Modifier> | undefined, 8187 name: PropertyName, 8188 questionToken: QuestionToken | undefined 8189 ): PropertyDeclaration { 8190 const exclamationToken = !questionToken && !scanner.hasPrecedingLineBreak() ? parseOptionalToken(SyntaxKind.ExclamationToken) : undefined; 8191 const type = parseTypeAnnotation(); 8192 const initializer = doOutsideOfContext(NodeFlags.YieldContext | NodeFlags.AwaitContext | NodeFlags.DisallowInContext, parseInitializer); 8193 parseSemicolonAfterPropertyName(name, type, initializer); 8194 const node = factory.createPropertyDeclaration( 8195 combineDecoratorsAndModifiers(decorators, modifiers), 8196 name, 8197 questionToken || exclamationToken, 8198 type, 8199 initializer); 8200 return withJSDoc(finishNode(node, pos), hasJSDoc); 8201 } 8202 8203 function parsePropertyOrMethodDeclaration( 8204 pos: number, 8205 hasJSDoc: boolean, 8206 decorators: NodeArray<Decorator> | undefined, 8207 modifiers: NodeArray<Modifier> | undefined 8208 ): PropertyDeclaration | MethodDeclaration { 8209 const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); 8210 const name = parsePropertyName(); 8211 // Note: this is not legal as per the grammar. But we allow it in the parser and 8212 // report an error in the grammar checker. 8213 const questionToken = parseOptionalToken(SyntaxKind.QuestionToken); 8214 if (asteriskToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) { 8215 return parseMethodDeclaration(pos, hasJSDoc, decorators, modifiers, asteriskToken, name, questionToken, /*exclamationToken*/ undefined, Diagnostics.or_expected); 8216 } 8217 return parsePropertyDeclaration(pos, hasJSDoc, decorators, modifiers, name, questionToken); 8218 } 8219 8220 function parseAccessorDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined, kind: AccessorDeclaration["kind"], flags: SignatureFlags): AccessorDeclaration { 8221 const name = parsePropertyName(); 8222 const typeParameters = parseTypeParameters(); 8223 const parameters = parseParameters(SignatureFlags.None); 8224 const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false); 8225 const body = parseFunctionBlockOrSemicolon(flags); 8226 const node = kind === SyntaxKind.GetAccessor 8227 ? factory.createGetAccessorDeclaration(combineDecoratorsAndModifiers(decorators, modifiers), name, parameters, type, body) 8228 : factory.createSetAccessorDeclaration(combineDecoratorsAndModifiers(decorators, modifiers), name, parameters, body); 8229 // Keep track of `typeParameters` (for both) and `type` (for setters) if they were parsed those indicate grammar errors 8230 (node as Mutable<AccessorDeclaration>).typeParameters = typeParameters; 8231 if (isSetAccessorDeclaration(node)) (node as Mutable<SetAccessorDeclaration>).type = type; 8232 return withJSDoc(finishNode(node, pos), hasJSDoc); 8233 } 8234 8235 function isAnnotationMemberStart(): boolean { 8236 let idToken: SyntaxKind | undefined; 8237 8238 if (token() === SyntaxKind.AtToken) { 8239 return false; 8240 } 8241 8242 if (isModifierKind(token())) { 8243 return false; 8244 } 8245 8246 if (token() === SyntaxKind.AsteriskToken) { 8247 return false; 8248 } 8249 8250 // Try to get the first property-like token following all modifiers. 8251 // This can either be an identifier or the 'get' or 'set' keywords. 8252 if (isLiteralPropertyName()) { 8253 idToken = token(); 8254 nextToken(); 8255 } 8256 8257 // Index signatures and computed properties are prohibited for annotations 8258 if (token() === SyntaxKind.OpenBracketToken) { 8259 return false; 8260 } 8261 8262 // If we were able to get any potential identifier... 8263 if (idToken !== undefined) { 8264 // If we have a non-keyword identifier, or if we have an accessor, then we no need to parse. 8265 if (isKeyword(idToken)) { 8266 return false; 8267 } 8268 8269 // If it *is* a keyword, but not an accessor, check a little farther along 8270 // to see if it should actually be parsed as a class member. 8271 switch (token()) { 8272 case SyntaxKind.ColonToken: // Type Annotation for declaration 8273 case SyntaxKind.EqualsToken: // Initializer for declaration 8274 return true; 8275 default: 8276 // Covers 8277 // - Semicolons (declaration termination) 8278 // - Closing braces (end-of-class, must be declaration) 8279 // - End-of-files (not valid, but permitted so that it gets caught later on) 8280 // - Line-breaks (enabling *automatic semicolon insertion*) 8281 return canParseSemicolon(); 8282 } 8283 } 8284 return false; 8285 } 8286 8287 function isClassMemberStart(): boolean { 8288 let idToken: SyntaxKind | undefined; 8289 8290 if (token() === SyntaxKind.AtToken) { 8291 if (inAllowAnnotationContext() && lookAhead(() => nextToken() === SyntaxKind.InterfaceKeyword)) { 8292 return false; 8293 } 8294 return true; 8295 } 8296 8297 // Eat up all modifiers, but hold on to the last one in case it is actually an identifier. 8298 while (isModifierKind(token())) { 8299 idToken = token(); 8300 // If the idToken is a class modifier (protected, private, public, and static), it is 8301 // certain that we are starting to parse class member. This allows better error recovery 8302 // Example: 8303 // public foo() ... // true 8304 // public @dec blah ... // true; we will then report an error later 8305 // export public ... // true; we will then report an error later 8306 if (isClassMemberModifier(idToken)) { 8307 return true; 8308 } 8309 8310 nextToken(); 8311 } 8312 8313 if (token() === SyntaxKind.AsteriskToken) { 8314 return true; 8315 } 8316 8317 // Try to get the first property-like token following all modifiers. 8318 // This can either be an identifier or the 'get' or 'set' keywords. 8319 if (isLiteralPropertyName()) { 8320 idToken = token(); 8321 nextToken(); 8322 } 8323 8324 // Index signatures and computed properties are class members; we can parse. 8325 if (token() === SyntaxKind.OpenBracketToken) { 8326 return true; 8327 } 8328 8329 // If we were able to get any potential identifier... 8330 if (idToken !== undefined) { 8331 // If we have a non-keyword identifier, or if we have an accessor, then it's safe to parse. 8332 if (!isKeyword(idToken) || idToken === SyntaxKind.SetKeyword || idToken === SyntaxKind.GetKeyword) { 8333 return true; 8334 } 8335 8336 // If it *is* a keyword, but not an accessor, check a little farther along 8337 // to see if it should actually be parsed as a class member. 8338 switch (token()) { 8339 case SyntaxKind.OpenParenToken: // Method declaration 8340 case SyntaxKind.LessThanToken: // Generic Method declaration 8341 case SyntaxKind.ExclamationToken: // Non-null assertion on property name 8342 case SyntaxKind.ColonToken: // Type Annotation for declaration 8343 case SyntaxKind.EqualsToken: // Initializer for declaration 8344 case SyntaxKind.QuestionToken: // Not valid, but permitted so that it gets caught later on. 8345 return true; 8346 default: 8347 // Covers 8348 // - Semicolons (declaration termination) 8349 // - Closing braces (end-of-class, must be declaration) 8350 // - End-of-files (not valid, but permitted so that it gets caught later on) 8351 // - Line-breaks (enabling *automatic semicolon insertion*) 8352 return canParseSemicolon(); 8353 } 8354 } 8355 return false; 8356 } 8357 8358 function parseClassStaticBlockDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: ModifiersArray | undefined): ClassStaticBlockDeclaration { 8359 parseExpectedToken(SyntaxKind.StaticKeyword); 8360 const body = parseClassStaticBlockBody(); 8361 const node = withJSDoc(finishNode(factory.createClassStaticBlockDeclaration(body), pos), hasJSDoc); 8362 (node as Mutable<ClassStaticBlockDeclaration>).illegalDecorators = decorators; 8363 (node as Mutable<ClassStaticBlockDeclaration>).modifiers = modifiers; 8364 return node; 8365 } 8366 8367 function parseClassStaticBlockBody() { 8368 const savedYieldContext = inYieldContext(); 8369 const savedAwaitContext = inAwaitContext(); 8370 8371 setYieldContext(false); 8372 setAwaitContext(true); 8373 8374 const body = parseBlock(/*ignoreMissingOpenBrace*/ false); 8375 8376 setYieldContext(savedYieldContext); 8377 setAwaitContext(savedAwaitContext); 8378 8379 return body; 8380 } 8381 8382 function parseDecoratorExpression() { 8383 if (inAwaitContext() && token() === SyntaxKind.AwaitKeyword) { 8384 // `@await` is is disallowed in an [Await] context, but can cause parsing to go off the rails 8385 // This simply parses the missing identifier and moves on. 8386 const pos = getNodePos(); 8387 const awaitExpression = parseIdentifier(Diagnostics.Expression_expected); 8388 nextToken(); 8389 const memberExpression = parseMemberExpressionRest(pos, awaitExpression, /*allowOptionalChain*/ true); 8390 return parseCallExpressionRest(pos, memberExpression); 8391 } 8392 return parseLeftHandSideExpressionOrHigher(); 8393 } 8394 8395 function tryParseDecorator(): Decorator | undefined { 8396 const pos = getNodePos(); 8397 if (inAllowAnnotationContext() && token() === SyntaxKind.AtToken && lookAhead(() => nextToken() === SyntaxKind.InterfaceKeyword)) { 8398 return undefined; 8399 } 8400 if (!parseOptional(SyntaxKind.AtToken)) { 8401 return undefined; 8402 } 8403 const expression = doInDecoratorContext(parseDecoratorExpression); 8404 return finishNode(factory.createDecorator(expression), pos); 8405 } 8406 8407 function parseDecorators(): NodeArray<Decorator> | undefined { 8408 const pos = getNodePos(); 8409 let list, decorator; 8410 while (decorator = tryParseDecorator()) { 8411 list = append(list, decorator); 8412 } 8413 return list && createNodeArray(list, pos); 8414 } 8415 8416 function tryParseModifier(permitInvalidConstAsModifier?: boolean, stopOnStartOfClassStaticBlock?: boolean, hasSeenStaticModifier?: boolean): Modifier | undefined { 8417 const pos = getNodePos(); 8418 const kind = token(); 8419 8420 if (token() === SyntaxKind.ConstKeyword && permitInvalidConstAsModifier) { 8421 // We need to ensure that any subsequent modifiers appear on the same line 8422 // so that when 'const' is a standalone declaration, we don't issue an error. 8423 if (!tryParse(nextTokenIsOnSameLineAndCanFollowModifier)) { 8424 return undefined; 8425 } 8426 } 8427 else if (stopOnStartOfClassStaticBlock && token() === SyntaxKind.StaticKeyword && lookAhead(nextTokenIsOpenBrace)) { 8428 return undefined; 8429 } 8430 else if (hasSeenStaticModifier && token() === SyntaxKind.StaticKeyword) { 8431 return undefined; 8432 } 8433 else { 8434 if (!parseAnyContextualModifier()) { 8435 return undefined; 8436 } 8437 } 8438 8439 return finishNode(factory.createToken(kind as Modifier["kind"]), pos); 8440 } 8441 8442 function combineDecoratorsAndModifiers(decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): NodeArray<ModifierLike> | undefined { 8443 if (!decorators) return modifiers; 8444 if (!modifiers) return decorators; 8445 const decoratorsAndModifiers = factory.createNodeArray(concatenate<ModifierLike>(decorators, modifiers)); 8446 setTextRangePosEnd(decoratorsAndModifiers, decorators.pos, modifiers.end); 8447 return decoratorsAndModifiers; 8448 } 8449 8450 function hasParamAndNoOnceDecorator(decorators: NodeArray<Decorator> | undefined): boolean { 8451 let hasParamDecorator = false; 8452 let hasOnceDecorator = false; 8453 decorators?.forEach((decorator) => { 8454 if (!ts.isIdentifier(decorator.expression)) { 8455 return; 8456 } 8457 if (decorator.expression.escapedText === 'Param') { 8458 hasParamDecorator = true; 8459 } 8460 else if (decorator.expression.escapedText === 'Once') { 8461 hasOnceDecorator = true; 8462 } 8463 }); 8464 return (hasParamDecorator && !hasOnceDecorator); 8465 } 8466 /* 8467 * There are situations in which a modifier like 'const' will appear unexpectedly, such as on a class member. 8468 * In those situations, if we are entirely sure that 'const' is not valid on its own (such as when ASI takes effect 8469 * and turns it into a standalone declaration), then it is better to parse it and report an error later. 8470 * 8471 * In such situations, 'permitInvalidConstAsModifier' should be set to true. 8472 */ 8473 function parseModifiers( 8474 permitInvalidConstAsModifier?: boolean, 8475 stopOnStartOfClassStaticBlock?: boolean, 8476 shouldAddReadonly?: boolean 8477 ): NodeArray<Modifier> | undefined { 8478 const pos = getNodePos(); 8479 let list, modifier, hasSeenStatic = false; 8480 let hasReadonly = false; 8481 while (modifier = tryParseModifier(permitInvalidConstAsModifier, stopOnStartOfClassStaticBlock, hasSeenStatic)) { 8482 if (modifier.kind === SyntaxKind.StaticKeyword) hasSeenStatic = true; 8483 if (modifier.kind === SyntaxKind.ReadonlyKeyword) { 8484 hasReadonly = true; 8485 } 8486 list = append(list, modifier); 8487 } 8488 if (shouldAddReadonly && !hasReadonly) { 8489 const readonlyModifier = finishVirtualNode(factory.createToken(SyntaxKind.ReadonlyKeyword)); 8490 list = append(list, readonlyModifier); 8491 } 8492 return list && createNodeArray(list, pos); 8493 } 8494 8495 function parseModifiersForArrowFunction(): NodeArray<Modifier> | undefined { 8496 let modifiers: NodeArray<Modifier> | undefined; 8497 if (token() === SyntaxKind.AsyncKeyword) { 8498 const pos = getNodePos(); 8499 nextToken(); 8500 const modifier = finishNode(factory.createToken(SyntaxKind.AsyncKeyword), pos); 8501 modifiers = createNodeArray<Modifier>([modifier], pos); 8502 } 8503 return modifiers; 8504 } 8505 8506 function parseClassElement(): ClassElement { 8507 const pos = getNodePos(); 8508 if (token() === SyntaxKind.SemicolonToken) { 8509 nextToken(); 8510 return finishNode(factory.createSemicolonClassElement(), pos); 8511 } 8512 8513 const hasJSDoc = hasPrecedingJSDocComment(); 8514 const decorators = parseDecorators(); 8515 /* 8516 * shouldAddReadonly adds readonly modifier when the element in struct has the Param decorator 8517 * and doesn't have Once decorator. 8518 */ 8519 const shouldAddReadonly = inStructContext() && hasParamAndNoOnceDecorator(decorators); 8520 const modifiers = parseModifiers(/*permitInvalidConstAsModifier*/ true, /*stopOnStartOfClassStaticBlock*/ true, shouldAddReadonly); 8521 if (token() === SyntaxKind.StaticKeyword && lookAhead(nextTokenIsOpenBrace)) { 8522 return parseClassStaticBlockDeclaration(pos, hasJSDoc, decorators, modifiers); 8523 } 8524 8525 if (parseContextualModifier(SyntaxKind.GetKeyword)) { 8526 return parseAccessorDeclaration(pos, hasJSDoc, decorators, modifiers, SyntaxKind.GetAccessor, SignatureFlags.None); 8527 } 8528 8529 if (parseContextualModifier(SyntaxKind.SetKeyword)) { 8530 return parseAccessorDeclaration(pos, hasJSDoc, decorators, modifiers, SyntaxKind.SetAccessor, SignatureFlags.None); 8531 } 8532 8533 if (token() === SyntaxKind.ConstructorKeyword || token() === SyntaxKind.StringLiteral) { 8534 const constructorDeclaration = tryParseConstructorDeclaration(pos, hasJSDoc, decorators, modifiers); 8535 if (constructorDeclaration) { 8536 return constructorDeclaration; 8537 } 8538 } 8539 8540 if (isIndexSignature()) { 8541 return parseIndexSignatureDeclaration(pos, hasJSDoc, decorators, modifiers); 8542 } 8543 8544 // It is very important that we check this *after* checking indexers because 8545 // the [ token can start an index signature or a computed property name 8546 if (tokenIsIdentifierOrKeyword(token()) || 8547 token() === SyntaxKind.StringLiteral || 8548 token() === SyntaxKind.NumericLiteral || 8549 token() === SyntaxKind.AsteriskToken || 8550 token() === SyntaxKind.OpenBracketToken) { 8551 const isAmbient = some(modifiers, isDeclareModifier); 8552 if (isAmbient) { 8553 for (const m of modifiers!) { 8554 (m as Mutable<Node>).flags |= NodeFlags.Ambient; 8555 } 8556 return doInsideOfContext(NodeFlags.Ambient, () => parsePropertyOrMethodDeclaration(pos, hasJSDoc, decorators, modifiers)); 8557 } 8558 else { 8559 return parsePropertyOrMethodDeclaration(pos, hasJSDoc, decorators, modifiers); 8560 } 8561 } 8562 8563 if (decorators || modifiers) { 8564 // treat this as a property declaration with a missing name. 8565 const name = createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Declaration_expected); 8566 return parsePropertyDeclaration(pos, hasJSDoc, decorators, modifiers, name, /*questionToken*/ undefined); 8567 } 8568 8569 // 'isClassMemberStart' should have hinted not to attempt parsing. 8570 return Debug.fail("Should not have attempted to parse class member declaration."); 8571 } 8572 8573 function parseAnnotationElement(): AnnotationElement { 8574 const pos = getNodePos(); 8575 if (token() === SyntaxKind.SemicolonToken) { 8576 parseErrorAt(pos, pos, Diagnostics.Unexpected_keyword_or_identifier); 8577 } 8578 8579 const hasJSDoc = hasPrecedingJSDocComment(); 8580 if (token() === SyntaxKind.StaticKeyword && lookAhead(nextTokenIsOpenBrace)) { 8581 return createMissingNode<AnnotationElement>(SyntaxKind.AnnotationPropertyDeclaration, /*reportAtCurrentPosition*/ true, 8582 Diagnostics.Unexpected_keyword_or_identifier); 8583 } 8584 8585 if (parseContextualModifier(SyntaxKind.GetKeyword)) { 8586 return createMissingNode<AnnotationElement>(SyntaxKind.AnnotationPropertyDeclaration, /*reportAtCurrentPosition*/ true, 8587 Diagnostics.Unexpected_keyword_or_identifier); 8588 } 8589 8590 if (parseContextualModifier(SyntaxKind.SetKeyword)) { 8591 return createMissingNode<AnnotationElement>(SyntaxKind.AnnotationPropertyDeclaration, /*reportAtCurrentPosition*/ true, 8592 Diagnostics.Unexpected_keyword_or_identifier); 8593 } 8594 8595 if (token() === SyntaxKind.ConstructorKeyword || token() === SyntaxKind.StringLiteral) { 8596 return createMissingNode<AnnotationElement>(SyntaxKind.AnnotationPropertyDeclaration, /*reportAtCurrentPosition*/ true, 8597 Diagnostics.Unexpected_keyword_or_identifier); 8598 } 8599 8600 if (isIndexSignature()) { 8601 return createMissingNode<AnnotationElement>(SyntaxKind.AnnotationPropertyDeclaration, /*reportAtCurrentPosition*/ true, 8602 Diagnostics.Unexpected_keyword_or_identifier); 8603 } 8604 8605 if (tokenIsIdentifierOrKeyword(token())) { 8606 const name = parsePropertyName(); 8607 return parseAnnotationPropertyDeclaration(pos, hasJSDoc, name); 8608 } 8609 8610 // 'isAnnotationMemberStart' should have hinted not to attempt parsing. 8611 return Debug.fail("Should not have attempted to parse annotation member declaration."); 8612 } 8613 8614 function parseClassExpression(): ClassExpression { 8615 return parseClassDeclarationOrExpression(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined, SyntaxKind.ClassExpression) as ClassExpression; 8616 } 8617 8618 function parseClassDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ClassDeclaration { 8619 return parseClassDeclarationOrExpression(pos, hasJSDoc, decorators, modifiers, SyntaxKind.ClassDeclaration) as ClassDeclaration; 8620 } 8621 8622 function parseStructDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): StructDeclaration { 8623 return parseStructDeclarationOrExpression(pos, hasJSDoc, decorators, modifiers); 8624 } 8625 8626 function parseClassDeclarationOrExpression(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined, kind: ClassLikeDeclaration["kind"]): ClassLikeDeclaration { 8627 const savedAwaitContext = inAwaitContext(); 8628 parseExpected(SyntaxKind.ClassKeyword); 8629 8630 // We don't parse the name here in await context, instead we will report a grammar error in the checker. 8631 const name = parseNameOfClassDeclarationOrExpression(); 8632 const typeParameters = parseTypeParameters(); 8633 if (some(modifiers, isExportModifier)) setAwaitContext(/*value*/ true); 8634 const heritageClauses = parseHeritageClauses(); 8635 8636 let members; 8637 if (parseExpected(SyntaxKind.OpenBraceToken)) { 8638 // ClassTail[Yield,Await] : (Modified) See 14.5 8639 // ClassHeritage[?Yield,?Await]opt { ClassBody[?Yield,?Await]opt } 8640 members = parseClassMembers(); 8641 parseExpected(SyntaxKind.CloseBraceToken); 8642 } 8643 else { 8644 members = createMissingList<ClassElement>(); 8645 } 8646 setAwaitContext(savedAwaitContext); 8647 const node = kind === SyntaxKind.ClassDeclaration 8648 ? factory.createClassDeclaration(combineDecoratorsAndModifiers(decorators, modifiers), name, typeParameters, heritageClauses, members) 8649 : factory.createClassExpression(combineDecoratorsAndModifiers(decorators, modifiers), name, typeParameters, heritageClauses, members); 8650 return withJSDoc(finishNode(node, pos), hasJSDoc); 8651 } 8652 8653 function parseStructDeclarationOrExpression(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): StructDeclaration { 8654 const savedAwaitContext = inAwaitContext(); 8655 parseExpected(SyntaxKind.StructKeyword); 8656 setStructContext(true); 8657 // We don't parse the name here in await context, instead we will report a grammar error in the checker. 8658 // struct Identifier logic is same to class Identifier 8659 const name = parseNameOfClassDeclarationOrExpression(); 8660 const typeParameters = parseTypeParameters(); 8661 if (some(modifiers, isExportModifier)) setAwaitContext(/*value*/ true); 8662 let heritageClauses = parseHeritageClauses(); 8663 const customComponent = sourceFileCompilerOptions.ets?.customComponent; 8664 if (!heritageClauses && customComponent) { 8665 heritageClauses = createVirtualHeritageClauses(customComponent); 8666 } 8667 let members; 8668 if (parseExpected(SyntaxKind.OpenBraceToken)) { 8669 // ClassTail[Yield,Await] : (Modified) See 14.5 8670 // ClassHeritage[?Yield,?Await]opt { ClassBody[?Yield,?Await]opt } 8671 members = parseStructMembers(pos); 8672 parseExpected(SyntaxKind.CloseBraceToken); 8673 } 8674 else { 8675 members = createMissingList<ClassElement>(); 8676 } 8677 setAwaitContext(savedAwaitContext); 8678 const node = factory.createStructDeclaration(combineDecoratorsAndModifiers(decorators, modifiers), name, typeParameters, heritageClauses, members); 8679 structStylesComponents.clear(); 8680 setStructContext(false); 8681 return withJSDoc(finishNode(node, pos), hasJSDoc); 8682 } 8683 8684 function createVirtualHeritageClauses(customComponent: string): NodeArray<HeritageClause> { 8685 const curPos = getNodePos(); 8686 const clause = factory.createHeritageClause( 8687 SyntaxKind.ExtendsKeyword, 8688 createNodeArray([finishNode(factory.createExpressionWithTypeArguments( 8689 finishNode(factory.createIdentifier(/*text*/ customComponent), curPos, /*end*/ undefined, /*virtual*/ true), 8690 /*typeArguments*/ undefined 8691 ), curPos)], curPos, /*end*/ undefined, /*hasTrailingComma*/ false) 8692 ); 8693 return createNodeArray([finishNode(clause, curPos, /*end*/ undefined, /*virtual*/ true)], curPos, /*end*/ undefined, /*hasTrailingComma*/ false); 8694 } 8695 8696 function parseNameOfClassDeclarationOrExpression(): Identifier | undefined { 8697 // implements is a future reserved word so 8698 // 'class implements' might mean either 8699 // - class expression with omitted name, 'implements' starts heritage clause 8700 // - class with name 'implements' 8701 // 'isImplementsClause' helps to disambiguate between these two cases 8702 return isBindingIdentifier() && !isImplementsClause() 8703 ? createIdentifier(isBindingIdentifier()) 8704 : undefined; 8705 } 8706 8707 function isImplementsClause() { 8708 return token() === SyntaxKind.ImplementsKeyword && lookAhead(nextTokenIsIdentifierOrKeyword); 8709 } 8710 8711 function parseHeritageClauses(): NodeArray<HeritageClause> | undefined { 8712 // ClassTail[Yield,Await] : (Modified) See 14.5 8713 // ClassHeritage[?Yield,?Await]opt { ClassBody[?Yield,?Await]opt } 8714 8715 if (isHeritageClause()) { 8716 return parseList(ParsingContext.HeritageClauses, parseHeritageClause); 8717 } 8718 8719 return undefined; 8720 } 8721 8722 function parseHeritageClause(): HeritageClause { 8723 const pos = getNodePos(); 8724 const tok = token(); 8725 Debug.assert(tok === SyntaxKind.ExtendsKeyword || tok === SyntaxKind.ImplementsKeyword); // isListElement() should ensure this. 8726 nextToken(); 8727 const types = parseDelimitedList(ParsingContext.HeritageClauseElement, parseExpressionWithTypeArguments); 8728 return finishNode(factory.createHeritageClause(tok, types), pos); 8729 } 8730 8731 function parseExpressionWithTypeArguments(): ExpressionWithTypeArguments { 8732 const pos = getNodePos(); 8733 const expression = parseLeftHandSideExpressionOrHigher(); 8734 if (expression.kind === SyntaxKind.ExpressionWithTypeArguments) { 8735 return expression as ExpressionWithTypeArguments; 8736 } 8737 const typeArguments = tryParseTypeArguments(); 8738 return finishNode(factory.createExpressionWithTypeArguments(expression, typeArguments), pos); 8739 } 8740 8741 function tryParseTypeArguments(): NodeArray<TypeNode> | undefined { 8742 return token() === SyntaxKind.LessThanToken ? 8743 parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken) : undefined; 8744 } 8745 8746 function isHeritageClause(): boolean { 8747 return token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword; 8748 } 8749 8750 function parseClassMembers(): NodeArray<ClassElement> { 8751 return parseList(ParsingContext.ClassMembers, parseClassElement); 8752 } 8753 8754 function parseAnnotationMembers(): NodeArray<AnnotationElement> { 8755 return parseList(ParsingContext.AnnotationMembers, parseAnnotationElement); 8756 } 8757 8758 function parseStructMembers(pos: number): NodeArray<ClassElement> { 8759 const structMembers = parseList(ParsingContext.ClassMembers, parseClassElement); 8760 8761 const virtualStructMembers: ClassElement[] = []; 8762 // create constructor function argument object properties 8763 const virtualParameterProperties: TypeElement[] = []; 8764 structMembers.forEach(member => { 8765 virtualStructMembers.push(member); 8766 if (member.kind === SyntaxKind.PropertyDeclaration) { 8767 const property = <PropertyDeclaration>member; 8768 virtualParameterProperties.push( 8769 finishVirtualNode( 8770 factory.createPropertySignature(getModifiers(property), property.name, factory.createToken(SyntaxKind.QuestionToken), property.type) 8771 ) 8772 ); 8773 } 8774 }); 8775 const parameters: ParameterDeclaration[] = []; 8776 if (virtualParameterProperties.length) { 8777 const type = finishVirtualNode(factory.createTypeLiteralNode(createNodeArray(virtualParameterProperties, 0, 0))); 8778 parameters.push( 8779 finishVirtualNode( 8780 factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, 8781 finishVirtualNode(factory.createIdentifier("value")), factory.createToken(SyntaxKind.QuestionToken), type 8782 ) 8783 ) 8784 ); 8785 } 8786 // Add parameter ##storage?: LocalStorage to struct constructor. 8787 parameters.push( 8788 finishVirtualNode( 8789 factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, 8790 finishVirtualNode(factory.createIdentifier("##storage")), factory.createToken(SyntaxKind.QuestionToken), 8791 finishVirtualNode(factory.createTypeReferenceNode(finishVirtualNode(factory.createIdentifier("LocalStorage")))) 8792 ) 8793 ) 8794 ); 8795 const emptyBody = finishVirtualNode(factory.createBlock(createNodeArray([], 0, 0))); 8796 const virtualConstructor = factory.createConstructorDeclaration(/*modifier*/ undefined, createNodeArray(parameters, 0, 0), emptyBody); 8797 8798 virtualStructMembers.unshift(finishVirtualNode(virtualConstructor, pos, pos)); 8799 8800 return createNodeArray(virtualStructMembers, structMembers.pos); 8801 } 8802 8803 function finishVirtualNode<T extends Node>(node: T, start = 0, end = 0) { 8804 return finishNode(node, start, end, /*virtual*/ true); 8805 } 8806 8807 function parseInterfaceDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): InterfaceDeclaration { 8808 parseExpected(SyntaxKind.InterfaceKeyword); 8809 const name = parseIdentifier(); 8810 const typeParameters = parseTypeParameters(); 8811 const heritageClauses = parseHeritageClauses(); 8812 const members = parseObjectTypeMembers(); 8813 const node = factory.createInterfaceDeclaration(modifiers, name, typeParameters, heritageClauses, members); 8814 (node as Mutable<InterfaceDeclaration>).illegalDecorators = decorators; 8815 return withJSDoc(finishNode(node, pos), hasJSDoc); 8816 } 8817 8818 function parseTypeAliasDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): TypeAliasDeclaration { 8819 parseExpected(SyntaxKind.TypeKeyword); 8820 const name = parseIdentifier(); 8821 const typeParameters = parseTypeParameters(); 8822 parseExpected(SyntaxKind.EqualsToken); 8823 const type = token() === SyntaxKind.IntrinsicKeyword && tryParse(parseKeywordAndNoDot) || parseType(); 8824 parseSemicolon(); 8825 const node = factory.createTypeAliasDeclaration(modifiers, name, typeParameters, type); 8826 (node as Mutable<TypeAliasDeclaration>).illegalDecorators = decorators; 8827 return withJSDoc(finishNode(node, pos), hasJSDoc); 8828 } 8829 8830 // In an ambient declaration, the grammar only allows integer literals as initializers. 8831 // In a non-ambient declaration, the grammar allows uninitialized members only in a 8832 // ConstantEnumMemberSection, which starts at the beginning of an enum declaration 8833 // or any time an integer literal initializer is encountered. 8834 function parseEnumMember(): EnumMember { 8835 const pos = getNodePos(); 8836 const hasJSDoc = hasPrecedingJSDocComment(); 8837 const name = parsePropertyName(); 8838 const initializer = allowInAnd(parseInitializer); 8839 return withJSDoc(finishNode(factory.createEnumMember(name, initializer), pos), hasJSDoc); 8840 } 8841 8842 function parseEnumDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): EnumDeclaration { 8843 parseExpected(SyntaxKind.EnumKeyword); 8844 const name = parseIdentifier(); 8845 let members; 8846 if (parseExpected(SyntaxKind.OpenBraceToken)) { 8847 members = doOutsideOfYieldAndAwaitContext(() => parseDelimitedList(ParsingContext.EnumMembers, parseEnumMember)); 8848 parseExpected(SyntaxKind.CloseBraceToken); 8849 } 8850 else { 8851 members = createMissingList<EnumMember>(); 8852 } 8853 const node = factory.createEnumDeclaration(modifiers, name, members); 8854 (node as Mutable<EnumDeclaration>).illegalDecorators = decorators; 8855 return withJSDoc(finishNode(node, pos), hasJSDoc); 8856 } 8857 8858 function parseModuleBlock(): ModuleBlock { 8859 const pos = getNodePos(); 8860 let statements; 8861 if (parseExpected(SyntaxKind.OpenBraceToken)) { 8862 statements = parseList(ParsingContext.BlockStatements, parseStatement); 8863 parseExpected(SyntaxKind.CloseBraceToken); 8864 } 8865 else { 8866 statements = createMissingList<Statement>(); 8867 } 8868 return finishNode(factory.createModuleBlock(statements), pos); 8869 } 8870 8871 function parseModuleOrNamespaceDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined, flags: NodeFlags): ModuleDeclaration { 8872 // If we are parsing a dotted namespace name, we want to 8873 // propagate the 'Namespace' flag across the names if set. 8874 const namespaceFlag = flags & NodeFlags.Namespace; 8875 const name = parseIdentifier(); 8876 const body = parseOptional(SyntaxKind.DotToken) 8877 ? parseModuleOrNamespaceDeclaration(getNodePos(), /*hasJSDoc*/ false, /*decorators*/ undefined, /*modifiers*/ undefined, NodeFlags.NestedNamespace | namespaceFlag) as NamespaceDeclaration 8878 : parseModuleBlock(); 8879 const node = factory.createModuleDeclaration(modifiers, name, body, flags); 8880 (node as Mutable<ModuleDeclaration>).illegalDecorators = decorators; 8881 return withJSDoc(finishNode(node, pos), hasJSDoc); 8882 } 8883 8884 function parseAmbientExternalModuleDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ModuleDeclaration { 8885 let flags: NodeFlags = 0; 8886 let name; 8887 if (token() === SyntaxKind.GlobalKeyword) { 8888 // parse 'global' as name of global scope augmentation 8889 name = parseIdentifier(); 8890 flags |= NodeFlags.GlobalAugmentation; 8891 } 8892 else { 8893 name = parseLiteralNode() as StringLiteral; 8894 name.text = internIdentifier(name.text); 8895 } 8896 let body: ModuleBlock | undefined; 8897 if (token() === SyntaxKind.OpenBraceToken) { 8898 body = parseModuleBlock(); 8899 } 8900 else { 8901 parseSemicolon(); 8902 } 8903 const node = factory.createModuleDeclaration(modifiers, name, body, flags); 8904 (node as Mutable<ModuleDeclaration>).illegalDecorators = decorators; 8905 return withJSDoc(finishNode(node, pos), hasJSDoc); 8906 } 8907 8908 function parseModuleDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ModuleDeclaration { 8909 let flags: NodeFlags = 0; 8910 if (token() === SyntaxKind.GlobalKeyword) { 8911 // global augmentation 8912 return parseAmbientExternalModuleDeclaration(pos, hasJSDoc, decorators, modifiers); 8913 } 8914 else if (parseOptional(SyntaxKind.NamespaceKeyword)) { 8915 flags |= NodeFlags.Namespace; 8916 } 8917 else { 8918 parseExpected(SyntaxKind.ModuleKeyword); 8919 if (token() === SyntaxKind.StringLiteral) { 8920 return parseAmbientExternalModuleDeclaration(pos, hasJSDoc, decorators, modifiers); 8921 } 8922 } 8923 return parseModuleOrNamespaceDeclaration(pos, hasJSDoc, decorators, modifiers, flags); 8924 } 8925 8926 function isExternalModuleReference() { 8927 return token() === SyntaxKind.RequireKeyword && 8928 lookAhead(nextTokenIsOpenParen); 8929 } 8930 8931 function nextTokenIsOpenParen() { 8932 return nextToken() === SyntaxKind.OpenParenToken; 8933 } 8934 8935 function nextTokenIsOpenBrace() { 8936 return nextToken() === SyntaxKind.OpenBraceToken; 8937 } 8938 8939 function nextTokenIsSlash() { 8940 return nextToken() === SyntaxKind.SlashToken; 8941 } 8942 8943 function parseNamespaceExportDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): NamespaceExportDeclaration { 8944 parseExpected(SyntaxKind.AsKeyword); 8945 parseExpected(SyntaxKind.NamespaceKeyword); 8946 const name = parseIdentifier(); 8947 parseSemicolon(); 8948 const node = factory.createNamespaceExportDeclaration(name); 8949 // NamespaceExportDeclaration nodes cannot have decorators or modifiers, so we attach them here so we can report them in the grammar checker 8950 (node as Mutable<NamespaceExportDeclaration>).illegalDecorators = decorators; 8951 (node as Mutable<NamespaceExportDeclaration>).modifiers = modifiers; 8952 return withJSDoc(finishNode(node, pos), hasJSDoc); 8953 } 8954 8955 function parseImportDeclarationOrImportEqualsDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ImportEqualsDeclaration | ImportDeclaration { 8956 parseExpected(SyntaxKind.ImportKeyword); 8957 8958 const afterImportPos = scanner.getStartPos(); 8959 8960 // We don't parse the identifier here in await context, instead we will report a grammar error in the checker. 8961 let identifier: Identifier | undefined; 8962 if (isIdentifier()) { 8963 identifier = parseIdentifier(); 8964 } 8965 8966 let isTypeOnly = false; 8967 let isLazy = false; 8968 if (token() !== SyntaxKind.FromKeyword && 8969 identifier?.escapedText === "type" && 8970 (isIdentifier() || tokenAfterImportDefinitelyProducesImportDeclaration()) 8971 ) { 8972 isTypeOnly = true; 8973 identifier = isIdentifier() ? parseIdentifier() : undefined; 8974 } 8975 else if (isSetLazy(identifier)) { 8976 isLazy = true; 8977 identifier = isIdentifier() ? parseIdentifier() : undefined; 8978 } 8979 8980 if (identifier && !tokenAfterImportedIdentifierDefinitelyProducesImportDeclaration()) { 8981 return parseImportEqualsDeclaration(pos, hasJSDoc, decorators, modifiers, identifier, isTypeOnly); 8982 } 8983 8984 // ImportDeclaration: 8985 // import ImportClause from ModuleSpecifier; 8986 // import ModuleSpecifier; 8987 let importClause: ImportClause | undefined; 8988 if (identifier || // import id 8989 token() === SyntaxKind.AsteriskToken || // import * 8990 token() === SyntaxKind.OpenBraceToken // import { 8991 ) { 8992 importClause = parseImportClause(identifier, afterImportPos, isTypeOnly); 8993 (importClause as Mutable<ImportClause>).isLazy = isLazy; 8994 parseExpected(SyntaxKind.FromKeyword); 8995 } 8996 const moduleSpecifier = parseModuleSpecifier(); 8997 8998 let assertClause: AssertClause | undefined; 8999 if (token() === SyntaxKind.AssertKeyword && !scanner.hasPrecedingLineBreak()) { 9000 assertClause = parseAssertClause(); 9001 } 9002 9003 parseSemicolon(); 9004 const node = factory.createImportDeclaration(modifiers, importClause, moduleSpecifier, assertClause); 9005 (node as Mutable<ImportDeclaration>).illegalDecorators = decorators; 9006 return withJSDoc(finishNode(node, pos), hasJSDoc); 9007 } 9008 9009 function isSetLazy(identifier: Identifier | undefined): boolean { 9010 // 1. import lazy { export } from "mod"; 9011 // 2. import lazy defaultExport from "mod"; 9012 // 3. import lazy defaultExport, { export, /* ... */ } from "mod"; 9013 return identifier?.escapedText === 'lazy' && 9014 (token() === SyntaxKind.OpenBraceToken || 9015 (isIdentifier() && lookAhead(() => nextToken() === SyntaxKind.FromKeyword)) || 9016 (isIdentifier() && lookAhead(() => nextToken() === SyntaxKind.CommaToken && nextToken() === SyntaxKind.OpenBraceToken))); 9017 } 9018 9019 function parseAssertEntry() { 9020 const pos = getNodePos(); 9021 const name = tokenIsIdentifierOrKeyword(token()) ? parseIdentifierName() : parseLiteralLikeNode(SyntaxKind.StringLiteral) as StringLiteral; 9022 parseExpected(SyntaxKind.ColonToken); 9023 const value = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true); 9024 return finishNode(factory.createAssertEntry(name, value), pos); 9025 } 9026 9027 function parseAssertClause(skipAssertKeyword?: true) { 9028 const pos = getNodePos(); 9029 if (!skipAssertKeyword) { 9030 parseExpected(SyntaxKind.AssertKeyword); 9031 } 9032 const openBracePosition = scanner.getTokenPos(); 9033 if (parseExpected(SyntaxKind.OpenBraceToken)) { 9034 const multiLine = scanner.hasPrecedingLineBreak(); 9035 const elements = parseDelimitedList(ParsingContext.AssertEntries, parseAssertEntry, /*considerSemicolonAsDelimiter*/ true); 9036 if (!parseExpected(SyntaxKind.CloseBraceToken)) { 9037 const lastError = lastOrUndefined(parseDiagnostics); 9038 if (lastError && lastError.code === Diagnostics._0_expected.code) { 9039 addRelatedInfo( 9040 lastError, 9041 createDetachedDiagnostic(fileName, openBracePosition, 1, Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, "{", "}") 9042 ); 9043 } 9044 } 9045 return finishNode(factory.createAssertClause(elements, multiLine), pos); 9046 } 9047 else { 9048 const elements = createNodeArray([], getNodePos(), /*end*/ undefined, /*hasTrailingComma*/ false); 9049 return finishNode(factory.createAssertClause(elements, /*multiLine*/ false), pos); 9050 } 9051 } 9052 9053 function tokenAfterImportDefinitelyProducesImportDeclaration() { 9054 return token() === SyntaxKind.AsteriskToken || token() === SyntaxKind.OpenBraceToken; 9055 } 9056 9057 function tokenAfterImportedIdentifierDefinitelyProducesImportDeclaration() { 9058 // In `import id ___`, the current token decides whether to produce 9059 // an ImportDeclaration or ImportEqualsDeclaration. 9060 return token() === SyntaxKind.CommaToken || token() === SyntaxKind.FromKeyword; 9061 } 9062 9063 function parseImportEqualsDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined, identifier: Identifier, isTypeOnly: boolean): ImportEqualsDeclaration { 9064 parseExpected(SyntaxKind.EqualsToken); 9065 const moduleReference = parseModuleReference(); 9066 parseSemicolon(); 9067 const node = factory.createImportEqualsDeclaration(modifiers, isTypeOnly, identifier, moduleReference); 9068 (node as Mutable<ImportEqualsDeclaration>).illegalDecorators = decorators; 9069 const finished = withJSDoc(finishNode(node, pos), hasJSDoc); 9070 return finished; 9071 } 9072 9073 function parseImportClause(identifier: Identifier | undefined, pos: number, isTypeOnly: boolean) { 9074 // ImportClause: 9075 // ImportedDefaultBinding 9076 // NameSpaceImport 9077 // NamedImports 9078 // ImportedDefaultBinding, NameSpaceImport 9079 // ImportedDefaultBinding, NamedImports 9080 9081 // If there was no default import or if there is comma token after default import 9082 // parse namespace or named imports 9083 let namedBindings: NamespaceImport | NamedImports | undefined; 9084 if (!identifier || 9085 parseOptional(SyntaxKind.CommaToken)) { 9086 namedBindings = token() === SyntaxKind.AsteriskToken ? parseNamespaceImport() : parseNamedImportsOrExports(SyntaxKind.NamedImports); 9087 } 9088 9089 return finishNode(factory.createImportClause(isTypeOnly, identifier, namedBindings), pos); 9090 } 9091 9092 function parseModuleReference() { 9093 return isExternalModuleReference() 9094 ? parseExternalModuleReference() 9095 : parseEntityName(/*allowReservedWords*/ false); 9096 } 9097 9098 function parseExternalModuleReference() { 9099 const pos = getNodePos(); 9100 parseExpected(SyntaxKind.RequireKeyword); 9101 parseExpected(SyntaxKind.OpenParenToken); 9102 const expression = parseModuleSpecifier(); 9103 parseExpected(SyntaxKind.CloseParenToken); 9104 return finishNode(factory.createExternalModuleReference(expression), pos); 9105 } 9106 9107 function parseModuleSpecifier(): Expression { 9108 if (token() === SyntaxKind.StringLiteral) { 9109 const result = parseLiteralNode(); 9110 result.text = internIdentifier(result.text); 9111 return result; 9112 } 9113 else { 9114 // We allow arbitrary expressions here, even though the grammar only allows string 9115 // literals. We check to ensure that it is only a string literal later in the grammar 9116 // check pass. 9117 return parseExpression(); 9118 } 9119 } 9120 9121 function parseNamespaceImport(): NamespaceImport { 9122 // NameSpaceImport: 9123 // * as ImportedBinding 9124 const pos = getNodePos(); 9125 parseExpected(SyntaxKind.AsteriskToken); 9126 parseExpected(SyntaxKind.AsKeyword); 9127 const name = parseIdentifier(); 9128 return finishNode(factory.createNamespaceImport(name), pos); 9129 } 9130 9131 function parseNamedImportsOrExports(kind: SyntaxKind.NamedImports): NamedImports; 9132 function parseNamedImportsOrExports(kind: SyntaxKind.NamedExports): NamedExports; 9133 function parseNamedImportsOrExports(kind: SyntaxKind): NamedImportsOrExports { 9134 const pos = getNodePos(); 9135 9136 // NamedImports: 9137 // { } 9138 // { ImportsList } 9139 // { ImportsList, } 9140 9141 // ImportsList: 9142 // ImportSpecifier 9143 // ImportsList, ImportSpecifier 9144 const node = kind === SyntaxKind.NamedImports 9145 ? factory.createNamedImports(parseBracketedList(ParsingContext.ImportOrExportSpecifiers, parseImportSpecifier, SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken)) 9146 : factory.createNamedExports(parseBracketedList(ParsingContext.ImportOrExportSpecifiers, parseExportSpecifier, SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken)); 9147 return finishNode(node, pos); 9148 } 9149 9150 function parseExportSpecifier() { 9151 const hasJSDoc = hasPrecedingJSDocComment(); 9152 return withJSDoc(parseImportOrExportSpecifier(SyntaxKind.ExportSpecifier) as ExportSpecifier, hasJSDoc); 9153 } 9154 9155 function parseImportSpecifier() { 9156 return parseImportOrExportSpecifier(SyntaxKind.ImportSpecifier) as ImportSpecifier; 9157 } 9158 9159 function parseImportOrExportSpecifier(kind: SyntaxKind): ImportOrExportSpecifier { 9160 const pos = getNodePos(); 9161 // ImportSpecifier: 9162 // BindingIdentifier 9163 // IdentifierName as BindingIdentifier 9164 // ExportSpecifier: 9165 // IdentifierName 9166 // IdentifierName as IdentifierName 9167 let checkIdentifierIsKeyword = isKeyword(token()) && !isIdentifier(); 9168 let checkIdentifierStart = scanner.getTokenPos(); 9169 let checkIdentifierEnd = scanner.getTextPos(); 9170 let isTypeOnly = false; 9171 let propertyName: Identifier | undefined; 9172 let canParseAsKeyword = true; 9173 let name = parseIdentifierName(); 9174 if (name.escapedText === "type") { 9175 // If the first token of an import specifier is 'type', there are a lot of possibilities, 9176 // especially if we see 'as' afterwards: 9177 // 9178 // import { type } from "mod"; - isTypeOnly: false, name: type 9179 // import { type as } from "mod"; - isTypeOnly: true, name: as 9180 // import { type as as } from "mod"; - isTypeOnly: false, name: as, propertyName: type 9181 // import { type as as as } from "mod"; - isTypeOnly: true, name: as, propertyName: as 9182 if (token() === SyntaxKind.AsKeyword) { 9183 // { type as ...? } 9184 const firstAs = parseIdentifierName(); 9185 if (token() === SyntaxKind.AsKeyword) { 9186 // { type as as ...? } 9187 const secondAs = parseIdentifierName(); 9188 if (tokenIsIdentifierOrKeyword(token())) { 9189 // { type as as something } 9190 isTypeOnly = true; 9191 propertyName = firstAs; 9192 name = parseNameWithKeywordCheck(); 9193 canParseAsKeyword = false; 9194 } 9195 else { 9196 // { type as as } 9197 propertyName = name; 9198 name = secondAs; 9199 canParseAsKeyword = false; 9200 } 9201 } 9202 else if (tokenIsIdentifierOrKeyword(token())) { 9203 // { type as something } 9204 propertyName = name; 9205 canParseAsKeyword = false; 9206 name = parseNameWithKeywordCheck(); 9207 } 9208 else { 9209 // { type as } 9210 isTypeOnly = true; 9211 name = firstAs; 9212 } 9213 } 9214 else if (tokenIsIdentifierOrKeyword(token())) { 9215 // { type something ...? } 9216 isTypeOnly = true; 9217 name = parseNameWithKeywordCheck(); 9218 } 9219 } 9220 9221 if (canParseAsKeyword && token() === SyntaxKind.AsKeyword) { 9222 propertyName = name; 9223 parseExpected(SyntaxKind.AsKeyword); 9224 name = parseNameWithKeywordCheck(); 9225 } 9226 if (kind === SyntaxKind.ImportSpecifier && checkIdentifierIsKeyword) { 9227 parseErrorAt(checkIdentifierStart, checkIdentifierEnd, Diagnostics.Identifier_expected); 9228 } 9229 const node = kind === SyntaxKind.ImportSpecifier 9230 ? factory.createImportSpecifier(isTypeOnly, propertyName, name) 9231 : factory.createExportSpecifier(isTypeOnly, propertyName, name); 9232 return finishNode(node, pos); 9233 9234 function parseNameWithKeywordCheck() { 9235 checkIdentifierIsKeyword = isKeyword(token()) && !isIdentifier(); 9236 checkIdentifierStart = scanner.getTokenPos(); 9237 checkIdentifierEnd = scanner.getTextPos(); 9238 return parseIdentifierName(); 9239 } 9240 } 9241 9242 function parseNamespaceExport(pos: number): NamespaceExport { 9243 return finishNode(factory.createNamespaceExport(parseIdentifierName()), pos); 9244 } 9245 9246 function parseExportDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ExportDeclaration { 9247 const savedAwaitContext = inAwaitContext(); 9248 setAwaitContext(/*value*/ true); 9249 let exportClause: NamedExportBindings | undefined; 9250 let moduleSpecifier: Expression | undefined; 9251 let assertClause: AssertClause | undefined; 9252 const isTypeOnly = parseOptional(SyntaxKind.TypeKeyword); 9253 const namespaceExportPos = getNodePos(); 9254 if (parseOptional(SyntaxKind.AsteriskToken)) { 9255 if (parseOptional(SyntaxKind.AsKeyword)) { 9256 exportClause = parseNamespaceExport(namespaceExportPos); 9257 } 9258 parseExpected(SyntaxKind.FromKeyword); 9259 moduleSpecifier = parseModuleSpecifier(); 9260 } 9261 else { 9262 exportClause = parseNamedImportsOrExports(SyntaxKind.NamedExports); 9263 // It is not uncommon to accidentally omit the 'from' keyword. Additionally, in editing scenarios, 9264 // the 'from' keyword can be parsed as a named export when the export clause is unterminated (i.e. `export { from "moduleName";`) 9265 // If we don't have a 'from' keyword, see if we have a string literal such that ASI won't take effect. 9266 if (token() === SyntaxKind.FromKeyword || (token() === SyntaxKind.StringLiteral && !scanner.hasPrecedingLineBreak())) { 9267 parseExpected(SyntaxKind.FromKeyword); 9268 moduleSpecifier = parseModuleSpecifier(); 9269 } 9270 } 9271 if (moduleSpecifier && token() === SyntaxKind.AssertKeyword && !scanner.hasPrecedingLineBreak()) { 9272 assertClause = parseAssertClause(); 9273 } 9274 parseSemicolon(); 9275 setAwaitContext(savedAwaitContext); 9276 const node = factory.createExportDeclaration(modifiers, isTypeOnly, exportClause, moduleSpecifier, assertClause); 9277 (node as Mutable<ExportDeclaration>).illegalDecorators = decorators; 9278 return withJSDoc(finishNode(node, pos), hasJSDoc); 9279 } 9280 9281 function parseExportAssignment(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ExportAssignment { 9282 const savedAwaitContext = inAwaitContext(); 9283 setAwaitContext(/*value*/ true); 9284 let isExportEquals: boolean | undefined; 9285 if (parseOptional(SyntaxKind.EqualsToken)) { 9286 isExportEquals = true; 9287 } 9288 else { 9289 parseExpected(SyntaxKind.DefaultKeyword); 9290 } 9291 const expression = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true); 9292 parseSemicolon(); 9293 setAwaitContext(savedAwaitContext); 9294 const node = factory.createExportAssignment(modifiers, isExportEquals, expression); 9295 (node as Mutable<ExportAssignment>).illegalDecorators = decorators; 9296 return withJSDoc(finishNode(node, pos), hasJSDoc); 9297 } 9298 9299 const enum ParsingContext { 9300 SourceElements, // Elements in source file 9301 BlockStatements, // Statements in block 9302 SwitchClauses, // Clauses in switch statement 9303 SwitchClauseStatements, // Statements in switch clause 9304 TypeMembers, // Members in interface or type literal 9305 ClassMembers, // Members in class declaration 9306 AnnotationMembers, // Members in annotation declaration 9307 EnumMembers, // Members in enum declaration 9308 HeritageClauseElement, // Elements in a heritage clause 9309 VariableDeclarations, // Variable declarations in variable statement 9310 ObjectBindingElements, // Binding elements in object binding list 9311 ArrayBindingElements, // Binding elements in array binding list 9312 ArgumentExpressions, // Expressions in argument list 9313 ObjectLiteralMembers, // Members in object literal 9314 JsxAttributes, // Attributes in jsx element 9315 JsxChildren, // Things between opening and closing JSX tags 9316 ArrayLiteralMembers, // Members in array literal 9317 Parameters, // Parameters in parameter list 9318 JSDocParameters, // JSDoc parameters in parameter list of JSDoc function type 9319 RestProperties, // Property names in a rest type list 9320 TypeParameters, // Type parameters in type parameter list 9321 TypeArguments, // Type arguments in type argument list 9322 TupleElementTypes, // Element types in tuple element type list 9323 HeritageClauses, // Heritage clauses for a class or interface declaration. 9324 ImportOrExportSpecifiers, // Named import clause's import specifier list, 9325 AssertEntries, // Import entries list. 9326 Count // Number of parsing contexts 9327 } 9328 9329 const enum Tristate { 9330 False, 9331 True, 9332 Unknown 9333 } 9334 9335 export namespace JSDocParser { 9336 export function parseJSDocTypeExpressionForTests(content: string, start: number | undefined, length: number | undefined): { jsDocTypeExpression: JSDocTypeExpression, diagnostics: Diagnostic[] } | undefined { 9337 initializeState("file.js", content, ScriptTarget.Latest, /*_syntaxCursor:*/ undefined, ScriptKind.JS); 9338 scanner.setText(content, start, length); 9339 currentToken = scanner.scan(); 9340 const jsDocTypeExpression = parseJSDocTypeExpression(); 9341 9342 const sourceFile = createSourceFile("file.js", ScriptTarget.Latest, ScriptKind.JS, /*isDeclarationFile*/ false, [], factory.createToken(SyntaxKind.EndOfFileToken), NodeFlags.None, noop); 9343 const diagnostics = attachFileToDiagnostics(parseDiagnostics, sourceFile); 9344 if (jsDocDiagnostics) { 9345 sourceFile.jsDocDiagnostics = attachFileToDiagnostics(jsDocDiagnostics, sourceFile); 9346 } 9347 9348 clearState(); 9349 9350 return jsDocTypeExpression ? { jsDocTypeExpression, diagnostics } : undefined; 9351 } 9352 9353 // Parses out a JSDoc type expression. 9354 export function parseJSDocTypeExpression(mayOmitBraces?: boolean): JSDocTypeExpression { 9355 const pos = getNodePos(); 9356 const hasBrace = (mayOmitBraces ? parseOptional : parseExpected)(SyntaxKind.OpenBraceToken); 9357 const type = doInsideOfContext(NodeFlags.JSDoc, parseJSDocType); 9358 if (!mayOmitBraces || hasBrace) { 9359 parseExpectedJSDoc(SyntaxKind.CloseBraceToken); 9360 } 9361 9362 const result = factory.createJSDocTypeExpression(type); 9363 fixupParentReferences(result); 9364 return finishNode(result, pos); 9365 } 9366 9367 export function parseJSDocNameReference(): JSDocNameReference { 9368 const pos = getNodePos(); 9369 const hasBrace = parseOptional(SyntaxKind.OpenBraceToken); 9370 const p2 = getNodePos(); 9371 let entityName: EntityName | JSDocMemberName = parseEntityName(/* allowReservedWords*/ false); 9372 while (token() === SyntaxKind.PrivateIdentifier) { 9373 reScanHashToken(); // rescan #id as # id 9374 nextTokenJSDoc(); // then skip the # 9375 entityName = finishNode(factory.createJSDocMemberName(entityName, parseIdentifier()), p2); 9376 } 9377 if (hasBrace) { 9378 parseExpectedJSDoc(SyntaxKind.CloseBraceToken); 9379 } 9380 9381 const result = factory.createJSDocNameReference(entityName); 9382 fixupParentReferences(result); 9383 return finishNode(result, pos); 9384 } 9385 9386 export function parseIsolatedJSDocComment(content: string, start: number | undefined, length: number | undefined): { jsDoc: JSDoc, diagnostics: Diagnostic[] } | undefined { 9387 initializeState("", content, ScriptTarget.Latest, /*_syntaxCursor:*/ undefined, ScriptKind.JS); 9388 const jsDoc = doInsideOfContext(NodeFlags.JSDoc, () => parseJSDocCommentWorker(start, length)); 9389 9390 const sourceFile = { languageVariant: LanguageVariant.Standard, text: content } as SourceFile; 9391 const diagnostics = attachFileToDiagnostics(parseDiagnostics, sourceFile); 9392 clearState(); 9393 9394 return jsDoc ? { jsDoc, diagnostics } : undefined; 9395 } 9396 9397 export function parseJSDocComment(parent: HasJSDoc, start: number, length: number): JSDoc | undefined { 9398 const saveToken = currentToken; 9399 const saveParseDiagnosticsLength = parseDiagnostics.length; 9400 const saveParseErrorBeforeNextFinishedNode = parseErrorBeforeNextFinishedNode; 9401 9402 const comment = doInsideOfContext(NodeFlags.JSDoc, () => parseJSDocCommentWorker(start, length)); 9403 setParent(comment, parent); 9404 9405 if (contextFlags & NodeFlags.JavaScriptFile) { 9406 if (!jsDocDiagnostics) { 9407 jsDocDiagnostics = []; 9408 } 9409 jsDocDiagnostics.push(...parseDiagnostics); 9410 } 9411 currentToken = saveToken; 9412 parseDiagnostics.length = saveParseDiagnosticsLength; 9413 parseErrorBeforeNextFinishedNode = saveParseErrorBeforeNextFinishedNode; 9414 return comment; 9415 } 9416 9417 const enum JSDocState { 9418 BeginningOfLine, 9419 SawAsterisk, 9420 SavingComments, 9421 SavingBackticks, // NOTE: Only used when parsing tag comments 9422 } 9423 9424 const enum PropertyLikeParse { 9425 Property = 1 << 0, 9426 Parameter = 1 << 1, 9427 CallbackParameter = 1 << 2, 9428 } 9429 9430 function parseJSDocCommentWorker(start = 0, length: number | undefined): JSDoc | undefined { 9431 const content = sourceText; 9432 const end = length === undefined ? content.length : start + length; 9433 length = end - start; 9434 9435 Debug.assert(start >= 0); 9436 Debug.assert(start <= end); 9437 Debug.assert(end <= content.length); 9438 9439 // Check for /** (JSDoc opening part) 9440 if (!isJSDocLikeText(content, start)) { 9441 return undefined; 9442 } 9443 9444 let tags: JSDocTag[]; 9445 let tagsPos: number; 9446 let tagsEnd: number; 9447 let linkEnd: number; 9448 let commentsPos: number | undefined; 9449 let comments: string[] = []; 9450 const parts: JSDocComment[] = []; 9451 9452 // + 3 for leading /**, - 5 in total for /** */ 9453 return scanner.scanRange(start + 3, length - 5, () => { 9454 // Initially we can parse out a tag. We also have seen a starting asterisk. 9455 // This is so that /** * @type */ doesn't parse. 9456 let state = JSDocState.SawAsterisk; 9457 let margin: number | undefined; 9458 // + 4 for leading '/** ' 9459 // + 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 9460 let indent = start - (content.lastIndexOf("\n", start) + 1) + 4; 9461 function pushComment(text: string) { 9462 if (!margin) { 9463 margin = indent; 9464 } 9465 comments.push(text); 9466 indent += text.length; 9467 } 9468 9469 nextTokenJSDoc(); 9470 while (parseOptionalJsdoc(SyntaxKind.WhitespaceTrivia)); 9471 if (parseOptionalJsdoc(SyntaxKind.NewLineTrivia)) { 9472 state = JSDocState.BeginningOfLine; 9473 indent = 0; 9474 } 9475 loop: while (true) { 9476 switch (token()) { 9477 case SyntaxKind.AtToken: 9478 if (state === JSDocState.BeginningOfLine || state === JSDocState.SawAsterisk) { 9479 removeTrailingWhitespace(comments); 9480 if (!commentsPos) commentsPos = getNodePos(); 9481 addTag(parseTag(indent)); 9482 // NOTE: According to usejsdoc.org, a tag goes to end of line, except the last tag. 9483 // Real-world comments may break this rule, so "BeginningOfLine" will not be a real line beginning 9484 // for malformed examples like `/** @param {string} x @returns {number} the length */` 9485 state = JSDocState.BeginningOfLine; 9486 margin = undefined; 9487 } 9488 else { 9489 pushComment(scanner.getTokenText()); 9490 } 9491 break; 9492 case SyntaxKind.NewLineTrivia: 9493 comments.push(scanner.getTokenText()); 9494 state = JSDocState.BeginningOfLine; 9495 indent = 0; 9496 break; 9497 case SyntaxKind.AsteriskToken: 9498 const asterisk = scanner.getTokenText(); 9499 if (state === JSDocState.SawAsterisk || state === JSDocState.SavingComments) { 9500 // If we've already seen an asterisk, then we can no longer parse a tag on this line 9501 state = JSDocState.SavingComments; 9502 pushComment(asterisk); 9503 } 9504 else { 9505 // Ignore the first asterisk on a line 9506 state = JSDocState.SawAsterisk; 9507 indent += asterisk.length; 9508 } 9509 break; 9510 case SyntaxKind.WhitespaceTrivia: 9511 // only collect whitespace if we're already saving comments or have just crossed the comment indent margin 9512 const whitespace = scanner.getTokenText(); 9513 if (state === JSDocState.SavingComments) { 9514 comments.push(whitespace); 9515 } 9516 else if (margin !== undefined && indent + whitespace.length > margin) { 9517 comments.push(whitespace.slice(margin - indent)); 9518 } 9519 indent += whitespace.length; 9520 break; 9521 case SyntaxKind.EndOfFileToken: 9522 break loop; 9523 case SyntaxKind.OpenBraceToken: 9524 state = JSDocState.SavingComments; 9525 const commentEnd = scanner.getStartPos(); 9526 const linkStart = scanner.getTextPos() - 1; 9527 const link = parseJSDocLink(linkStart); 9528 if (link) { 9529 if (!linkEnd) { 9530 removeLeadingNewlines(comments); 9531 } 9532 parts.push(finishNode(factory.createJSDocText(comments.join("")), linkEnd ?? start, commentEnd)); 9533 parts.push(link); 9534 comments = []; 9535 linkEnd = scanner.getTextPos(); 9536 break; 9537 } 9538 // fallthrough if it's not a {@link sequence 9539 default: 9540 // Anything else is doc comment text. We just save it. Because it 9541 // wasn't a tag, we can no longer parse a tag on this line until we hit the next 9542 // line break. 9543 state = JSDocState.SavingComments; 9544 pushComment(scanner.getTokenText()); 9545 break; 9546 } 9547 nextTokenJSDoc(); 9548 } 9549 removeTrailingWhitespace(comments); 9550 if (parts.length && comments.length) { 9551 parts.push(finishNode(factory.createJSDocText(comments.join("")), linkEnd ?? start, commentsPos)); 9552 } 9553 if (parts.length && tags) Debug.assertIsDefined(commentsPos, "having parsed tags implies that the end of the comment span should be set"); 9554 const tagsArray = tags && createNodeArray(tags, tagsPos, tagsEnd); 9555 return finishNode(factory.createJSDocComment(parts.length ? createNodeArray(parts, start, commentsPos) : comments.length ? comments.join("") : undefined, tagsArray), start, end); 9556 }); 9557 9558 function removeLeadingNewlines(comments: string[]) { 9559 while (comments.length && (comments[0] === "\n" || comments[0] === "\r")) { 9560 comments.shift(); 9561 } 9562 } 9563 9564 function removeTrailingWhitespace(comments: string[]) { 9565 while (comments.length && comments[comments.length - 1].trim() === "") { 9566 comments.pop(); 9567 } 9568 } 9569 9570 function isNextNonwhitespaceTokenEndOfFile(): boolean { 9571 // We must use infinite lookahead, as there could be any number of newlines :( 9572 while (true) { 9573 nextTokenJSDoc(); 9574 if (token() === SyntaxKind.EndOfFileToken) { 9575 return true; 9576 } 9577 if (!(token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia)) { 9578 return false; 9579 } 9580 } 9581 } 9582 9583 function skipWhitespace(): void { 9584 if (token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) { 9585 if (lookAhead(isNextNonwhitespaceTokenEndOfFile)) { 9586 return; // Don't skip whitespace prior to EoF (or end of comment) - that shouldn't be included in any node's range 9587 } 9588 } 9589 while (token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) { 9590 nextTokenJSDoc(); 9591 } 9592 } 9593 9594 function skipWhitespaceOrAsterisk(): string { 9595 if (token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) { 9596 if (lookAhead(isNextNonwhitespaceTokenEndOfFile)) { 9597 return ""; // Don't skip whitespace prior to EoF (or end of comment) - that shouldn't be included in any node's range 9598 } 9599 } 9600 9601 let precedingLineBreak = scanner.hasPrecedingLineBreak(); 9602 let seenLineBreak = false; 9603 let indentText = ""; 9604 while ((precedingLineBreak && token() === SyntaxKind.AsteriskToken) || token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) { 9605 indentText += scanner.getTokenText(); 9606 if (token() === SyntaxKind.NewLineTrivia) { 9607 precedingLineBreak = true; 9608 seenLineBreak = true; 9609 indentText = ""; 9610 } 9611 else if (token() === SyntaxKind.AsteriskToken) { 9612 precedingLineBreak = false; 9613 } 9614 nextTokenJSDoc(); 9615 } 9616 return seenLineBreak ? indentText : ""; 9617 } 9618 9619 function parseTag(margin: number) { 9620 Debug.assert(token() === SyntaxKind.AtToken); 9621 const start = scanner.getTokenPos(); 9622 nextTokenJSDoc(); 9623 9624 const tagName = parseJSDocIdentifierName(/*message*/ undefined); 9625 const indentText = skipWhitespaceOrAsterisk(); 9626 9627 let tag: JSDocTag | undefined; 9628 switch (tagName.escapedText) { 9629 case "author": 9630 tag = parseAuthorTag(start, tagName, margin, indentText); 9631 break; 9632 case "implements": 9633 tag = parseImplementsTag(start, tagName, margin, indentText); 9634 break; 9635 case "augments": 9636 case "extends": 9637 tag = parseAugmentsTag(start, tagName, margin, indentText); 9638 break; 9639 case "class": 9640 case "constructor": 9641 tag = parseSimpleTag(start, factory.createJSDocClassTag, tagName, margin, indentText); 9642 break; 9643 case "public": 9644 tag = parseSimpleTag(start, factory.createJSDocPublicTag, tagName, margin, indentText); 9645 break; 9646 case "private": 9647 tag = parseSimpleTag(start, factory.createJSDocPrivateTag, tagName, margin, indentText); 9648 break; 9649 case "protected": 9650 tag = parseSimpleTag(start, factory.createJSDocProtectedTag, tagName, margin, indentText); 9651 break; 9652 case "readonly": 9653 tag = parseSimpleTag(start, factory.createJSDocReadonlyTag, tagName, margin, indentText); 9654 break; 9655 case "override": 9656 tag = parseSimpleTag(start, factory.createJSDocOverrideTag, tagName, margin, indentText); 9657 break; 9658 case "deprecated": 9659 hasDeprecatedTag = true; 9660 tag = parseSimpleTag(start, factory.createJSDocDeprecatedTag, tagName, margin, indentText); 9661 break; 9662 case "this": 9663 tag = parseThisTag(start, tagName, margin, indentText); 9664 break; 9665 case "enum": 9666 tag = parseEnumTag(start, tagName, margin, indentText); 9667 break; 9668 case "arg": 9669 case "argument": 9670 case "param": 9671 return parseParameterOrPropertyTag(start, tagName, PropertyLikeParse.Parameter, margin); 9672 case "return": 9673 case "returns": 9674 tag = parseReturnTag(start, tagName, margin, indentText); 9675 break; 9676 case "template": 9677 tag = parseTemplateTag(start, tagName, margin, indentText); 9678 break; 9679 case "type": 9680 tag = parseTypeTag(start, tagName, margin, indentText); 9681 break; 9682 case "typedef": 9683 tag = parseTypedefTag(start, tagName, margin, indentText); 9684 break; 9685 case "callback": 9686 tag = parseCallbackTag(start, tagName, margin, indentText); 9687 break; 9688 case "see": 9689 tag = parseSeeTag(start, tagName, margin, indentText); 9690 break; 9691 default: 9692 tag = parseUnknownTag(start, tagName, margin, indentText); 9693 break; 9694 } 9695 return tag; 9696 } 9697 9698 function parseTrailingTagComments(pos: number, end: number, margin: number, indentText: string) { 9699 // some tags, like typedef and callback, have already parsed their comments earlier 9700 if (!indentText) { 9701 margin += end - pos; 9702 } 9703 return parseTagComments(margin, indentText.slice(margin)); 9704 } 9705 9706 function parseTagComments(indent: number, initialMargin?: string): string | NodeArray<JSDocComment> | undefined { 9707 const commentsPos = getNodePos(); 9708 let comments: string[] = []; 9709 const parts: JSDocComment[] = []; 9710 let linkEnd; 9711 let state = JSDocState.BeginningOfLine; 9712 let previousWhitespace = true; 9713 let margin: number | undefined; 9714 function pushComment(text: string) { 9715 if (!margin) { 9716 margin = indent; 9717 } 9718 comments.push(text); 9719 indent += text.length; 9720 } 9721 if (initialMargin !== undefined) { 9722 // jump straight to saving comments if there is some initial indentation 9723 if (initialMargin !== "") { 9724 pushComment(initialMargin); 9725 } 9726 state = JSDocState.SawAsterisk; 9727 } 9728 let tok = token() as JSDocSyntaxKind; 9729 loop: while (true) { 9730 switch (tok) { 9731 case SyntaxKind.NewLineTrivia: 9732 state = JSDocState.BeginningOfLine; 9733 // don't use pushComment here because we want to keep the margin unchanged 9734 comments.push(scanner.getTokenText()); 9735 indent = 0; 9736 break; 9737 case SyntaxKind.AtToken: 9738 if (state === JSDocState.SavingBackticks 9739 || state === JSDocState.SavingComments && (!previousWhitespace || lookAhead(isNextJSDocTokenWhitespace))) { 9740 // @ doesn't start a new tag inside ``, and inside a comment, only after whitespace or not before whitespace 9741 comments.push(scanner.getTokenText()); 9742 break; 9743 } 9744 scanner.setTextPos(scanner.getTextPos() - 1); 9745 // falls through 9746 case SyntaxKind.EndOfFileToken: 9747 // Done 9748 break loop; 9749 case SyntaxKind.WhitespaceTrivia: 9750 if (state === JSDocState.SavingComments || state === JSDocState.SavingBackticks) { 9751 pushComment(scanner.getTokenText()); 9752 } 9753 else { 9754 const whitespace = scanner.getTokenText(); 9755 // if the whitespace crosses the margin, take only the whitespace that passes the margin 9756 if (margin !== undefined && indent + whitespace.length > margin) { 9757 comments.push(whitespace.slice(margin - indent)); 9758 } 9759 indent += whitespace.length; 9760 } 9761 break; 9762 case SyntaxKind.OpenBraceToken: 9763 state = JSDocState.SavingComments; 9764 const commentEnd = scanner.getStartPos(); 9765 const linkStart = scanner.getTextPos() - 1; 9766 const link = parseJSDocLink(linkStart); 9767 if (link) { 9768 parts.push(finishNode(factory.createJSDocText(comments.join("")), linkEnd ?? commentsPos, commentEnd)); 9769 parts.push(link); 9770 comments = []; 9771 linkEnd = scanner.getTextPos(); 9772 } 9773 else { 9774 pushComment(scanner.getTokenText()); 9775 } 9776 break; 9777 case SyntaxKind.BacktickToken: 9778 if (state === JSDocState.SavingBackticks) { 9779 state = JSDocState.SavingComments; 9780 } 9781 else { 9782 state = JSDocState.SavingBackticks; 9783 } 9784 pushComment(scanner.getTokenText()); 9785 break; 9786 case SyntaxKind.AsteriskToken: 9787 if (state === JSDocState.BeginningOfLine) { 9788 // leading asterisks start recording on the *next* (non-whitespace) token 9789 state = JSDocState.SawAsterisk; 9790 indent += 1; 9791 break; 9792 } 9793 // record the * as a comment 9794 // falls through 9795 default: 9796 if (state !== JSDocState.SavingBackticks) { 9797 state = JSDocState.SavingComments; // leading identifiers start recording as well 9798 } 9799 pushComment(scanner.getTokenText()); 9800 break; 9801 } 9802 previousWhitespace = token() === SyntaxKind.WhitespaceTrivia; 9803 tok = nextTokenJSDoc(); 9804 } 9805 9806 removeLeadingNewlines(comments); 9807 removeTrailingWhitespace(comments); 9808 if (parts.length) { 9809 if (comments.length) { 9810 parts.push(finishNode(factory.createJSDocText(comments.join("")), linkEnd ?? commentsPos)); 9811 } 9812 return createNodeArray(parts, commentsPos, scanner.getTextPos()); 9813 } 9814 else if (comments.length) { 9815 return comments.join(""); 9816 } 9817 } 9818 9819 function isNextJSDocTokenWhitespace() { 9820 const next = nextTokenJSDoc(); 9821 return next === SyntaxKind.WhitespaceTrivia || next === SyntaxKind.NewLineTrivia; 9822 } 9823 9824 function parseJSDocLink(start: number) { 9825 const linkType = tryParse(parseJSDocLinkPrefix); 9826 if (!linkType) { 9827 return undefined; 9828 } 9829 nextTokenJSDoc(); // start at token after link, then skip any whitespace 9830 skipWhitespace(); 9831 // parseEntityName logs an error for non-identifier, so create a MissingNode ourselves to avoid the error 9832 const p2 = getNodePos(); 9833 let name: EntityName | JSDocMemberName | undefined = tokenIsIdentifierOrKeyword(token()) 9834 ? parseEntityName(/*allowReservedWords*/ true) 9835 : undefined; 9836 if (name) { 9837 while (token() === SyntaxKind.PrivateIdentifier) { 9838 reScanHashToken(); // rescan #id as # id 9839 nextTokenJSDoc(); // then skip the # 9840 name = finishNode(factory.createJSDocMemberName(name, parseIdentifier()), p2); 9841 } 9842 } 9843 const text = []; 9844 while (token() !== SyntaxKind.CloseBraceToken && token() !== SyntaxKind.NewLineTrivia && token() !== SyntaxKind.EndOfFileToken) { 9845 text.push(scanner.getTokenText()); 9846 nextTokenJSDoc(); 9847 } 9848 const create = linkType === "link" ? factory.createJSDocLink 9849 : linkType === "linkcode" ? factory.createJSDocLinkCode 9850 : factory.createJSDocLinkPlain; 9851 return finishNode(create(name, text.join("")), start, scanner.getTextPos()); 9852 } 9853 9854 function parseJSDocLinkPrefix() { 9855 skipWhitespaceOrAsterisk(); 9856 if (token() === SyntaxKind.OpenBraceToken 9857 && nextTokenJSDoc() === SyntaxKind.AtToken 9858 && tokenIsIdentifierOrKeyword(nextTokenJSDoc())) { 9859 const kind = scanner.getTokenValue(); 9860 if (isJSDocLinkTag(kind)) return kind; 9861 } 9862 } 9863 9864 function isJSDocLinkTag(kind: string) { 9865 return kind === "link" || kind === "linkcode" || kind === "linkplain"; 9866 } 9867 9868 function parseUnknownTag(start: number, tagName: Identifier, indent: number, indentText: string) { 9869 return finishNode(factory.createJSDocUnknownTag(tagName, parseTrailingTagComments(start, getNodePos(), indent, indentText)), start); 9870 } 9871 9872 function addTag(tag: JSDocTag | undefined): void { 9873 if (!tag) { 9874 return; 9875 } 9876 if (!tags) { 9877 tags = [tag]; 9878 tagsPos = tag.pos; 9879 } 9880 else { 9881 tags.push(tag); 9882 } 9883 tagsEnd = tag.end; 9884 } 9885 9886 function tryParseTypeExpression(): JSDocTypeExpression | undefined { 9887 skipWhitespaceOrAsterisk(); 9888 return token() === SyntaxKind.OpenBraceToken ? parseJSDocTypeExpression() : undefined; 9889 } 9890 9891 function parseBracketNameInPropertyAndParamTag(): { name: EntityName, isBracketed: boolean } { 9892 // Looking for something like '[foo]', 'foo', '[foo.bar]' or 'foo.bar' 9893 const isBracketed = parseOptionalJsdoc(SyntaxKind.OpenBracketToken); 9894 if (isBracketed) { 9895 skipWhitespace(); 9896 } 9897 // a markdown-quoted name: `arg` is not legal jsdoc, but occurs in the wild 9898 const isBackquoted = parseOptionalJsdoc(SyntaxKind.BacktickToken); 9899 const name = parseJSDocEntityName(); 9900 if (isBackquoted) { 9901 parseExpectedTokenJSDoc(SyntaxKind.BacktickToken); 9902 } 9903 if (isBracketed) { 9904 skipWhitespace(); 9905 // May have an optional default, e.g. '[foo = 42]' 9906 if (parseOptionalToken(SyntaxKind.EqualsToken)) { 9907 parseExpression(); 9908 } 9909 9910 parseExpected(SyntaxKind.CloseBracketToken); 9911 } 9912 9913 return { name, isBracketed }; 9914 } 9915 9916 function isObjectOrObjectArrayTypeReference(node: TypeNode): boolean { 9917 switch (node.kind) { 9918 case SyntaxKind.ObjectKeyword: 9919 return true; 9920 case SyntaxKind.ArrayType: 9921 return isObjectOrObjectArrayTypeReference((node as ArrayTypeNode).elementType); 9922 default: 9923 return isTypeReferenceNode(node) && ts.isIdentifier(node.typeName) && node.typeName.escapedText === "Object" && !node.typeArguments; 9924 } 9925 } 9926 9927 function parseParameterOrPropertyTag(start: number, tagName: Identifier, target: PropertyLikeParse, indent: number): JSDocParameterTag | JSDocPropertyTag { 9928 let typeExpression = tryParseTypeExpression(); 9929 let isNameFirst = !typeExpression; 9930 skipWhitespaceOrAsterisk(); 9931 9932 const { name, isBracketed } = parseBracketNameInPropertyAndParamTag(); 9933 const indentText = skipWhitespaceOrAsterisk(); 9934 9935 if (isNameFirst && !lookAhead(parseJSDocLinkPrefix)) { 9936 typeExpression = tryParseTypeExpression(); 9937 } 9938 9939 const comment = parseTrailingTagComments(start, getNodePos(), indent, indentText); 9940 9941 const nestedTypeLiteral = target !== PropertyLikeParse.CallbackParameter && parseNestedTypeLiteral(typeExpression, name, target, indent); 9942 if (nestedTypeLiteral) { 9943 typeExpression = nestedTypeLiteral; 9944 isNameFirst = true; 9945 } 9946 const result = target === PropertyLikeParse.Property 9947 ? factory.createJSDocPropertyTag(tagName, name, isBracketed, typeExpression, isNameFirst, comment) 9948 : factory.createJSDocParameterTag(tagName, name, isBracketed, typeExpression, isNameFirst, comment); 9949 return finishNode(result, start); 9950 } 9951 9952 function parseNestedTypeLiteral(typeExpression: JSDocTypeExpression | undefined, name: EntityName, target: PropertyLikeParse, indent: number) { 9953 if (typeExpression && isObjectOrObjectArrayTypeReference(typeExpression.type)) { 9954 const pos = getNodePos(); 9955 let child: JSDocPropertyLikeTag | JSDocTypeTag | false; 9956 let children: JSDocPropertyLikeTag[] | undefined; 9957 while (child = tryParse(() => parseChildParameterOrPropertyTag(target, indent, name))) { 9958 if (child.kind === SyntaxKind.JSDocParameterTag || child.kind === SyntaxKind.JSDocPropertyTag) { 9959 children = append(children, child); 9960 } 9961 } 9962 if (children) { 9963 const literal = finishNode(factory.createJSDocTypeLiteral(children, typeExpression.type.kind === SyntaxKind.ArrayType), pos); 9964 return finishNode(factory.createJSDocTypeExpression(literal), pos); 9965 } 9966 } 9967 } 9968 9969 function parseReturnTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocReturnTag { 9970 if (some(tags, isJSDocReturnTag)) { 9971 parseErrorAt(tagName.pos, scanner.getTokenPos(), Diagnostics._0_tag_already_specified, tagName.escapedText); 9972 } 9973 9974 const typeExpression = tryParseTypeExpression(); 9975 return finishNode(factory.createJSDocReturnTag(tagName, typeExpression, parseTrailingTagComments(start, getNodePos(), indent, indentText)), start); 9976 } 9977 9978 function parseTypeTag(start: number, tagName: Identifier, indent?: number, indentText?: string): JSDocTypeTag { 9979 if (some(tags, isJSDocTypeTag)) { 9980 parseErrorAt(tagName.pos, scanner.getTokenPos(), Diagnostics._0_tag_already_specified, tagName.escapedText); 9981 } 9982 9983 const typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true); 9984 const comments = indent !== undefined && indentText !== undefined ? parseTrailingTagComments(start, getNodePos(), indent, indentText) : undefined; 9985 return finishNode(factory.createJSDocTypeTag(tagName, typeExpression, comments), start); 9986 } 9987 9988 function parseSeeTag(start: number, tagName: Identifier, indent?: number, indentText?: string): JSDocSeeTag { 9989 const isMarkdownOrJSDocLink = token() === SyntaxKind.OpenBracketToken 9990 || lookAhead(() => nextTokenJSDoc() === SyntaxKind.AtToken && tokenIsIdentifierOrKeyword(nextTokenJSDoc()) && isJSDocLinkTag(scanner.getTokenValue())); 9991 const nameExpression = isMarkdownOrJSDocLink ? undefined : parseJSDocNameReference(); 9992 const comments = indent !== undefined && indentText !== undefined ? parseTrailingTagComments(start, getNodePos(), indent, indentText) : undefined; 9993 return finishNode(factory.createJSDocSeeTag(tagName, nameExpression, comments), start); 9994 } 9995 9996 function parseAuthorTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocAuthorTag { 9997 const commentStart = getNodePos(); 9998 const textOnly = parseAuthorNameAndEmail(); 9999 let commentEnd = scanner.getStartPos(); 10000 const comments = parseTrailingTagComments(start, commentEnd, indent, indentText); 10001 if (!comments) { 10002 commentEnd = scanner.getStartPos(); 10003 } 10004 const allParts = typeof comments !== "string" 10005 ? createNodeArray(concatenate([finishNode(textOnly, commentStart, commentEnd)], comments) as JSDocComment[], commentStart) // cast away readonly 10006 : textOnly.text + comments; 10007 return finishNode(factory.createJSDocAuthorTag(tagName, allParts), start); 10008 } 10009 10010 function parseAuthorNameAndEmail(): JSDocText { 10011 const comments: string[] = []; 10012 let inEmail = false; 10013 let token = scanner.getToken(); 10014 while (token !== SyntaxKind.EndOfFileToken && token !== SyntaxKind.NewLineTrivia) { 10015 if (token === SyntaxKind.LessThanToken) { 10016 inEmail = true; 10017 } 10018 else if (token === SyntaxKind.AtToken && !inEmail) { 10019 break; 10020 } 10021 else if (token === SyntaxKind.GreaterThanToken && inEmail) { 10022 comments.push(scanner.getTokenText()); 10023 scanner.setTextPos(scanner.getTokenPos() + 1); 10024 break; 10025 } 10026 comments.push(scanner.getTokenText()); 10027 token = nextTokenJSDoc(); 10028 } 10029 10030 return factory.createJSDocText(comments.join("")); 10031 } 10032 10033 function parseImplementsTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocImplementsTag { 10034 const className = parseExpressionWithTypeArgumentsForAugments(); 10035 return finishNode(factory.createJSDocImplementsTag(tagName, className, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start); 10036 } 10037 10038 function parseAugmentsTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocAugmentsTag { 10039 const className = parseExpressionWithTypeArgumentsForAugments(); 10040 return finishNode(factory.createJSDocAugmentsTag(tagName, className, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start); 10041 } 10042 10043 function parseExpressionWithTypeArgumentsForAugments(): ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression } { 10044 const usedBrace = parseOptional(SyntaxKind.OpenBraceToken); 10045 const pos = getNodePos(); 10046 const expression = parsePropertyAccessEntityNameExpression(); 10047 const typeArguments = tryParseTypeArguments(); 10048 const node = factory.createExpressionWithTypeArguments(expression, typeArguments) as ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression }; 10049 const res = finishNode(node, pos); 10050 if (usedBrace) { 10051 parseExpected(SyntaxKind.CloseBraceToken); 10052 } 10053 return res; 10054 } 10055 10056 function parsePropertyAccessEntityNameExpression() { 10057 const pos = getNodePos(); 10058 let node: Identifier | PropertyAccessEntityNameExpression = parseJSDocIdentifierName(); 10059 while (parseOptional(SyntaxKind.DotToken)) { 10060 const name = parseJSDocIdentifierName(); 10061 node = finishNode(factory.createPropertyAccessExpression(node, name), pos) as PropertyAccessEntityNameExpression; 10062 } 10063 return node; 10064 } 10065 10066 function parseSimpleTag(start: number, createTag: (tagName: Identifier | undefined, comment?: string | NodeArray<JSDocComment>) => JSDocTag, tagName: Identifier, margin: number, indentText: string): JSDocTag { 10067 return finishNode(createTag(tagName, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start); 10068 } 10069 10070 function parseThisTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocThisTag { 10071 const typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true); 10072 skipWhitespace(); 10073 return finishNode(factory.createJSDocThisTag(tagName, typeExpression, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start); 10074 } 10075 10076 function parseEnumTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocEnumTag { 10077 const typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true); 10078 skipWhitespace(); 10079 return finishNode(factory.createJSDocEnumTag(tagName, typeExpression, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start); 10080 } 10081 10082 function parseTypedefTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocTypedefTag { 10083 let typeExpression: JSDocTypeExpression | JSDocTypeLiteral | undefined = tryParseTypeExpression(); 10084 skipWhitespaceOrAsterisk(); 10085 10086 const fullName = parseJSDocTypeNameWithNamespace(); 10087 skipWhitespace(); 10088 let comment = parseTagComments(indent); 10089 10090 let end: number | undefined; 10091 if (!typeExpression || isObjectOrObjectArrayTypeReference(typeExpression.type)) { 10092 let child: JSDocTypeTag | JSDocPropertyTag | false; 10093 let childTypeTag: JSDocTypeTag | undefined; 10094 let jsDocPropertyTags: JSDocPropertyTag[] | undefined; 10095 let hasChildren = false; 10096 while (child = tryParse(() => parseChildPropertyTag(indent))) { 10097 hasChildren = true; 10098 if (child.kind === SyntaxKind.JSDocTypeTag) { 10099 if (childTypeTag) { 10100 const lastError = parseErrorAtCurrentToken(Diagnostics.A_JSDoc_typedef_comment_may_not_contain_multiple_type_tags); 10101 if (lastError) { 10102 addRelatedInfo(lastError, createDetachedDiagnostic(fileName, 0, 0, Diagnostics.The_tag_was_first_specified_here)); 10103 } 10104 break; 10105 } 10106 else { 10107 childTypeTag = child; 10108 } 10109 } 10110 else { 10111 jsDocPropertyTags = append(jsDocPropertyTags, child); 10112 } 10113 } 10114 if (hasChildren) { 10115 const isArrayType = typeExpression && typeExpression.type.kind === SyntaxKind.ArrayType; 10116 const jsdocTypeLiteral = factory.createJSDocTypeLiteral(jsDocPropertyTags, isArrayType); 10117 typeExpression = childTypeTag && childTypeTag.typeExpression && !isObjectOrObjectArrayTypeReference(childTypeTag.typeExpression.type) ? 10118 childTypeTag.typeExpression : 10119 finishNode(jsdocTypeLiteral, start); 10120 end = typeExpression.end; 10121 } 10122 } 10123 10124 // Only include the characters between the name end and the next token if a comment was actually parsed out - otherwise it's just whitespace 10125 end = end || comment !== undefined ? 10126 getNodePos() : 10127 (fullName ?? typeExpression ?? tagName).end; 10128 10129 if (!comment) { 10130 comment = parseTrailingTagComments(start, end, indent, indentText); 10131 } 10132 10133 const typedefTag = factory.createJSDocTypedefTag(tagName, typeExpression, fullName, comment); 10134 return finishNode(typedefTag, start, end); 10135 } 10136 10137 function parseJSDocTypeNameWithNamespace(nested?: boolean) { 10138 const pos = scanner.getTokenPos(); 10139 if (!tokenIsIdentifierOrKeyword(token())) { 10140 return undefined; 10141 } 10142 const typeNameOrNamespaceName = parseJSDocIdentifierName(); 10143 if (parseOptional(SyntaxKind.DotToken)) { 10144 const body = parseJSDocTypeNameWithNamespace(/*nested*/ true); 10145 const jsDocNamespaceNode = factory.createModuleDeclaration( 10146 /*modifiers*/ undefined, 10147 typeNameOrNamespaceName, 10148 body, 10149 nested ? NodeFlags.NestedNamespace : undefined 10150 ) as JSDocNamespaceDeclaration; 10151 return finishNode(jsDocNamespaceNode, pos); 10152 } 10153 10154 if (nested) { 10155 typeNameOrNamespaceName.isInJSDocNamespace = true; 10156 } 10157 return typeNameOrNamespaceName; 10158 } 10159 10160 10161 function parseCallbackTagParameters(indent: number) { 10162 const pos = getNodePos(); 10163 let child: JSDocParameterTag | false; 10164 let parameters; 10165 while (child = tryParse(() => parseChildParameterOrPropertyTag(PropertyLikeParse.CallbackParameter, indent) as JSDocParameterTag)) { 10166 parameters = append(parameters, child); 10167 } 10168 return createNodeArray(parameters || [], pos); 10169 } 10170 10171 function parseCallbackTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocCallbackTag { 10172 const fullName = parseJSDocTypeNameWithNamespace(); 10173 skipWhitespace(); 10174 let comment = parseTagComments(indent); 10175 const parameters = parseCallbackTagParameters(indent); 10176 const returnTag = tryParse(() => { 10177 if (parseOptionalJsdoc(SyntaxKind.AtToken)) { 10178 const tag = parseTag(indent); 10179 if (tag && tag.kind === SyntaxKind.JSDocReturnTag) { 10180 return tag as JSDocReturnTag; 10181 } 10182 } 10183 }); 10184 const typeExpression = finishNode(factory.createJSDocSignature(/*typeParameters*/ undefined, parameters, returnTag), start); 10185 if (!comment) { 10186 comment = parseTrailingTagComments(start, getNodePos(), indent, indentText); 10187 } 10188 const end = comment !== undefined ? getNodePos() : typeExpression.end; 10189 return finishNode(factory.createJSDocCallbackTag(tagName, typeExpression, fullName, comment), start, end); 10190 } 10191 10192 function escapedTextsEqual(a: EntityName, b: EntityName): boolean { 10193 while (!ts.isIdentifier(a) || !ts.isIdentifier(b)) { 10194 if (!ts.isIdentifier(a) && !ts.isIdentifier(b) && a.right.escapedText === b.right.escapedText) { 10195 a = a.left; 10196 b = b.left; 10197 } 10198 else { 10199 return false; 10200 } 10201 } 10202 return a.escapedText === b.escapedText; 10203 } 10204 10205 function parseChildPropertyTag(indent: number) { 10206 return parseChildParameterOrPropertyTag(PropertyLikeParse.Property, indent) as JSDocTypeTag | JSDocPropertyTag | false; 10207 } 10208 10209 function parseChildParameterOrPropertyTag(target: PropertyLikeParse, indent: number, name?: EntityName): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false { 10210 let canParseTag = true; 10211 let seenAsterisk = false; 10212 while (true) { 10213 switch (nextTokenJSDoc()) { 10214 case SyntaxKind.AtToken: 10215 if (canParseTag) { 10216 const child = tryParseChildTag(target, indent); 10217 if (child && (child.kind === SyntaxKind.JSDocParameterTag || child.kind === SyntaxKind.JSDocPropertyTag) && 10218 target !== PropertyLikeParse.CallbackParameter && 10219 name && (ts.isIdentifier(child.name) || !escapedTextsEqual(name, child.name.left))) { 10220 return false; 10221 } 10222 return child; 10223 } 10224 seenAsterisk = false; 10225 break; 10226 case SyntaxKind.NewLineTrivia: 10227 canParseTag = true; 10228 seenAsterisk = false; 10229 break; 10230 case SyntaxKind.AsteriskToken: 10231 if (seenAsterisk) { 10232 canParseTag = false; 10233 } 10234 seenAsterisk = true; 10235 break; 10236 case SyntaxKind.Identifier: 10237 canParseTag = false; 10238 break; 10239 case SyntaxKind.EndOfFileToken: 10240 return false; 10241 } 10242 } 10243 } 10244 10245 function tryParseChildTag(target: PropertyLikeParse, indent: number): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false { 10246 Debug.assert(token() === SyntaxKind.AtToken); 10247 const start = scanner.getStartPos(); 10248 nextTokenJSDoc(); 10249 10250 const tagName = parseJSDocIdentifierName(); 10251 skipWhitespace(); 10252 let t: PropertyLikeParse; 10253 switch (tagName.escapedText) { 10254 case "type": 10255 return target === PropertyLikeParse.Property && parseTypeTag(start, tagName); 10256 case "prop": 10257 case "property": 10258 t = PropertyLikeParse.Property; 10259 break; 10260 case "arg": 10261 case "argument": 10262 case "param": 10263 t = PropertyLikeParse.Parameter | PropertyLikeParse.CallbackParameter; 10264 break; 10265 default: 10266 return false; 10267 } 10268 if (!(target & t)) { 10269 return false; 10270 } 10271 return parseParameterOrPropertyTag(start, tagName, target, indent); 10272 } 10273 10274 function parseTemplateTagTypeParameter() { 10275 const typeParameterPos = getNodePos(); 10276 const isBracketed = parseOptionalJsdoc(SyntaxKind.OpenBracketToken); 10277 if (isBracketed) { 10278 skipWhitespace(); 10279 } 10280 const name = parseJSDocIdentifierName(Diagnostics.Unexpected_token_A_type_parameter_name_was_expected_without_curly_braces); 10281 10282 let defaultType: TypeNode | undefined; 10283 if (isBracketed) { 10284 skipWhitespace(); 10285 parseExpected(SyntaxKind.EqualsToken); 10286 defaultType = doInsideOfContext(NodeFlags.JSDoc, parseJSDocType); 10287 parseExpected(SyntaxKind.CloseBracketToken); 10288 } 10289 10290 if (nodeIsMissing(name)) { 10291 return undefined; 10292 } 10293 return finishNode(factory.createTypeParameterDeclaration(/*modifiers*/ undefined, name, /*constraint*/ undefined, defaultType), typeParameterPos); 10294 } 10295 10296 function parseTemplateTagTypeParameters() { 10297 const pos = getNodePos(); 10298 const typeParameters = []; 10299 do { 10300 skipWhitespace(); 10301 const node = parseTemplateTagTypeParameter(); 10302 if (node !== undefined) { 10303 typeParameters.push(node); 10304 } 10305 skipWhitespaceOrAsterisk(); 10306 } while (parseOptionalJsdoc(SyntaxKind.CommaToken)); 10307 return createNodeArray(typeParameters, pos); 10308 } 10309 10310 function parseTemplateTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocTemplateTag { 10311 // The template tag looks like one of the following: 10312 // @template T,U,V 10313 // @template {Constraint} T 10314 // 10315 // According to the [closure docs](https://github.com/google/closure-compiler/wiki/Generic-Types#multiple-bounded-template-types): 10316 // > Multiple bounded generics cannot be declared on the same line. For the sake of clarity, if multiple templates share the same 10317 // > type bound they must be declared on separate lines. 10318 // 10319 // TODO: Determine whether we should enforce this in the checker. 10320 // TODO: Consider moving the `constraint` to the first type parameter as we could then remove `getEffectiveConstraintOfTypeParameter`. 10321 // TODO: Consider only parsing a single type parameter if there is a constraint. 10322 const constraint = token() === SyntaxKind.OpenBraceToken ? parseJSDocTypeExpression() : undefined; 10323 const typeParameters = parseTemplateTagTypeParameters(); 10324 return finishNode(factory.createJSDocTemplateTag(tagName, constraint, typeParameters, parseTrailingTagComments(start, getNodePos(), indent, indentText)), start); 10325 } 10326 10327 function parseOptionalJsdoc(t: JSDocSyntaxKind): boolean { 10328 if (token() === t) { 10329 nextTokenJSDoc(); 10330 return true; 10331 } 10332 return false; 10333 } 10334 10335 function parseJSDocEntityName(): EntityName { 10336 let entity: EntityName = parseJSDocIdentifierName(); 10337 if (parseOptional(SyntaxKind.OpenBracketToken)) { 10338 parseExpected(SyntaxKind.CloseBracketToken); 10339 // Note that y[] is accepted as an entity name, but the postfix brackets are not saved for checking. 10340 // Technically usejsdoc.org requires them for specifying a property of a type equivalent to Array<{ x: ...}> 10341 // but it's not worth it to enforce that restriction. 10342 } 10343 while (parseOptional(SyntaxKind.DotToken)) { 10344 const name = parseJSDocIdentifierName(); 10345 if (parseOptional(SyntaxKind.OpenBracketToken)) { 10346 parseExpected(SyntaxKind.CloseBracketToken); 10347 } 10348 entity = createQualifiedName(entity, name); 10349 } 10350 return entity; 10351 } 10352 10353 function parseJSDocIdentifierName(message?: DiagnosticMessage): Identifier { 10354 if (!tokenIsIdentifierOrKeyword(token())) { 10355 return createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ !message, message || Diagnostics.Identifier_expected); 10356 } 10357 10358 identifierCount++; 10359 const pos = scanner.getTokenPos(); 10360 const end = scanner.getTextPos(); 10361 const originalKeywordKind = token(); 10362 const text = internIdentifier(scanner.getTokenValue()); 10363 const result = finishNode(factory.createIdentifier(text, /*typeArguments*/ undefined, originalKeywordKind), pos, end); 10364 nextTokenJSDoc(); 10365 return result; 10366 } 10367 } 10368 } 10369} 10370 10371namespace IncrementalParser { 10372 export function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks: boolean): SourceFile { 10373 aggressiveChecks = aggressiveChecks || Debug.shouldAssert(AssertionLevel.Aggressive); 10374 10375 checkChangeRange(sourceFile, newText, textChangeRange, aggressiveChecks); 10376 if (textChangeRangeIsUnchanged(textChangeRange)) { 10377 // if the text didn't change, then we can just return our current source file as-is. 10378 return sourceFile; 10379 } 10380 10381 if (sourceFile.statements.length === 0) { 10382 // If we don't have any statements in the current source file, then there's no real 10383 // way to incrementally parse. So just do a full parse instead. 10384 return Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, /*syntaxCursor*/ undefined, /*setParentNodes*/ true, sourceFile.scriptKind, sourceFile.setExternalModuleIndicator); 10385 } 10386 10387 // Make sure we're not trying to incrementally update a source file more than once. Once 10388 // we do an update the original source file is considered unusable from that point onwards. 10389 // 10390 // This is because we do incremental parsing in-place. i.e. we take nodes from the old 10391 // tree and give them new positions and parents. From that point on, trusting the old 10392 // tree at all is not possible as far too much of it may violate invariants. 10393 const incrementalSourceFile = sourceFile as Node as IncrementalNode; 10394 Debug.assert(!incrementalSourceFile.hasBeenIncrementallyParsed); 10395 incrementalSourceFile.hasBeenIncrementallyParsed = true; 10396 Parser.fixupParentReferences(incrementalSourceFile); 10397 const oldText = sourceFile.text; 10398 const syntaxCursor = createSyntaxCursor(sourceFile); 10399 10400 // Make the actual change larger so that we know to reparse anything whose lookahead 10401 // might have intersected the change. 10402 const changeRange = extendToAffectedRange(sourceFile, textChangeRange); 10403 checkChangeRange(sourceFile, newText, changeRange, aggressiveChecks); 10404 10405 // Ensure that extending the affected range only moved the start of the change range 10406 // earlier in the file. 10407 Debug.assert(changeRange.span.start <= textChangeRange.span.start); 10408 Debug.assert(textSpanEnd(changeRange.span) === textSpanEnd(textChangeRange.span)); 10409 Debug.assert(textSpanEnd(textChangeRangeNewSpan(changeRange)) === textSpanEnd(textChangeRangeNewSpan(textChangeRange))); 10410 10411 // The is the amount the nodes after the edit range need to be adjusted. It can be 10412 // positive (if the edit added characters), negative (if the edit deleted characters) 10413 // or zero (if this was a pure overwrite with nothing added/removed). 10414 const delta = textChangeRangeNewSpan(changeRange).length - changeRange.span.length; 10415 10416 // If we added or removed characters during the edit, then we need to go and adjust all 10417 // the nodes after the edit. Those nodes may move forward (if we inserted chars) or they 10418 // may move backward (if we deleted chars). 10419 // 10420 // Doing this helps us out in two ways. First, it means that any nodes/tokens we want 10421 // to reuse are already at the appropriate position in the new text. That way when we 10422 // reuse them, we don't have to figure out if they need to be adjusted. Second, it makes 10423 // it very easy to determine if we can reuse a node. If the node's position is at where 10424 // we are in the text, then we can reuse it. Otherwise we can't. If the node's position 10425 // is ahead of us, then we'll need to rescan tokens. If the node's position is behind 10426 // us, then we'll need to skip it or crumble it as appropriate 10427 // 10428 // We will also adjust the positions of nodes that intersect the change range as well. 10429 // By doing this, we ensure that all the positions in the old tree are consistent, not 10430 // just the positions of nodes entirely before/after the change range. By being 10431 // consistent, we can then easily map from positions to nodes in the old tree easily. 10432 // 10433 // Also, mark any syntax elements that intersect the changed span. We know, up front, 10434 // that we cannot reuse these elements. 10435 updateTokenPositionsAndMarkElements(incrementalSourceFile, 10436 changeRange.span.start, textSpanEnd(changeRange.span), textSpanEnd(textChangeRangeNewSpan(changeRange)), delta, oldText, newText, aggressiveChecks); 10437 10438 // Now that we've set up our internal incremental state just proceed and parse the 10439 // source file in the normal fashion. When possible the parser will retrieve and 10440 // reuse nodes from the old tree. 10441 // 10442 // Note: passing in 'true' for setNodeParents is very important. When incrementally 10443 // parsing, we will be reusing nodes from the old tree, and placing it into new 10444 // parents. If we don't set the parents now, we'll end up with an observably 10445 // inconsistent tree. Setting the parents on the new tree should be very fast. We 10446 // will immediately bail out of walking any subtrees when we can see that their parents 10447 // are already correct. 10448 const result = Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, syntaxCursor, /*setParentNodes*/ true, sourceFile.scriptKind, sourceFile.setExternalModuleIndicator); 10449 result.commentDirectives = getNewCommentDirectives( 10450 sourceFile.commentDirectives, 10451 result.commentDirectives, 10452 changeRange.span.start, 10453 textSpanEnd(changeRange.span), 10454 delta, 10455 oldText, 10456 newText, 10457 aggressiveChecks 10458 ); 10459 result.impliedNodeFormat = sourceFile.impliedNodeFormat; 10460 return result; 10461 } 10462 10463 function getNewCommentDirectives( 10464 oldDirectives: CommentDirective[] | undefined, 10465 newDirectives: CommentDirective[] | undefined, 10466 changeStart: number, 10467 changeRangeOldEnd: number, 10468 delta: number, 10469 oldText: string, 10470 newText: string, 10471 aggressiveChecks: boolean 10472 ): CommentDirective[] | undefined { 10473 if (!oldDirectives) return newDirectives; 10474 let commentDirectives: CommentDirective[] | undefined; 10475 let addedNewlyScannedDirectives = false; 10476 for (const directive of oldDirectives) { 10477 const { range, type } = directive; 10478 // Range before the change 10479 if (range.end < changeStart) { 10480 commentDirectives = append(commentDirectives, directive); 10481 } 10482 else if (range.pos > changeRangeOldEnd) { 10483 addNewlyScannedDirectives(); 10484 // Node is entirely past the change range. We need to move both its pos and 10485 // end, forward or backward appropriately. 10486 const updatedDirective: CommentDirective = { 10487 range: { pos: range.pos + delta, end: range.end + delta }, 10488 type 10489 }; 10490 commentDirectives = append(commentDirectives, updatedDirective); 10491 if (aggressiveChecks) { 10492 Debug.assert(oldText.substring(range.pos, range.end) === newText.substring(updatedDirective.range.pos, updatedDirective.range.end)); 10493 } 10494 } 10495 // Ignore ranges that fall in change range 10496 } 10497 addNewlyScannedDirectives(); 10498 return commentDirectives; 10499 10500 function addNewlyScannedDirectives() { 10501 if (addedNewlyScannedDirectives) return; 10502 addedNewlyScannedDirectives = true; 10503 if (!commentDirectives) { 10504 commentDirectives = newDirectives; 10505 } 10506 else if (newDirectives) { 10507 commentDirectives.push(...newDirectives); 10508 } 10509 } 10510 } 10511 10512 function moveElementEntirelyPastChangeRange(element: IncrementalElement, isArray: boolean, delta: number, oldText: string, newText: string, aggressiveChecks: boolean) { 10513 if (isArray) { 10514 visitArray(element as IncrementalNodeArray); 10515 } 10516 else { 10517 visitNode(element as IncrementalNode); 10518 } 10519 return; 10520 10521 function visitNode(node: IncrementalNode) { 10522 let text = ""; 10523 if (aggressiveChecks && shouldCheckNode(node)) { 10524 text = oldText.substring(node.pos, node.end); 10525 } 10526 10527 // Ditch any existing LS children we may have created. This way we can avoid 10528 // moving them forward. 10529 if (node._children) { 10530 node._children = undefined; 10531 } 10532 10533 setTextRangePosEnd(node, node.pos + delta, node.end + delta); 10534 10535 if (aggressiveChecks && shouldCheckNode(node)) { 10536 Debug.assert(text === newText.substring(node.pos, node.end)); 10537 } 10538 10539 forEachChild(node, visitNode, visitArray); 10540 if (hasJSDocNodes(node)) { 10541 for (const jsDocComment of node.jsDoc!) { 10542 visitNode(jsDocComment as Node as IncrementalNode); 10543 } 10544 } 10545 checkNodePositions(node, aggressiveChecks); 10546 } 10547 10548 function visitArray(array: IncrementalNodeArray) { 10549 array._children = undefined; 10550 setTextRangePosEnd(array, array.pos + delta, array.end + delta); 10551 10552 for (const node of array) { 10553 visitNode(node); 10554 } 10555 } 10556 } 10557 10558 function shouldCheckNode(node: Node) { 10559 switch (node.kind) { 10560 case SyntaxKind.StringLiteral: 10561 case SyntaxKind.NumericLiteral: 10562 case SyntaxKind.Identifier: 10563 return true; 10564 } 10565 10566 return false; 10567 } 10568 10569 function adjustIntersectingElement(element: IncrementalElement, changeStart: number, changeRangeOldEnd: number, changeRangeNewEnd: number, delta: number) { 10570 Debug.assert(element.end >= changeStart, "Adjusting an element that was entirely before the change range"); 10571 Debug.assert(element.pos <= changeRangeOldEnd, "Adjusting an element that was entirely after the change range"); 10572 Debug.assert(element.pos <= element.end); 10573 10574 // We have an element that intersects the change range in some way. It may have its 10575 // start, or its end (or both) in the changed range. We want to adjust any part 10576 // that intersects such that the final tree is in a consistent state. i.e. all 10577 // children have spans within the span of their parent, and all siblings are ordered 10578 // properly. 10579 10580 // We may need to update both the 'pos' and the 'end' of the element. 10581 10582 // If the 'pos' is before the start of the change, then we don't need to touch it. 10583 // If it isn't, then the 'pos' must be inside the change. How we update it will 10584 // depend if delta is positive or negative. If delta is positive then we have 10585 // something like: 10586 // 10587 // -------------------AAA----------------- 10588 // -------------------BBBCCCCCCC----------------- 10589 // 10590 // In this case, we consider any node that started in the change range to still be 10591 // starting at the same position. 10592 // 10593 // however, if the delta is negative, then we instead have something like this: 10594 // 10595 // -------------------XXXYYYYYYY----------------- 10596 // -------------------ZZZ----------------- 10597 // 10598 // In this case, any element that started in the 'X' range will keep its position. 10599 // However any element that started after that will have their pos adjusted to be 10600 // at the end of the new range. i.e. any node that started in the 'Y' range will 10601 // be adjusted to have their start at the end of the 'Z' range. 10602 // 10603 // The element will keep its position if possible. Or Move backward to the new-end 10604 // if it's in the 'Y' range. 10605 const pos = Math.min(element.pos, changeRangeNewEnd); 10606 10607 // If the 'end' is after the change range, then we always adjust it by the delta 10608 // amount. However, if the end is in the change range, then how we adjust it 10609 // will depend on if delta is positive or negative. If delta is positive then we 10610 // have something like: 10611 // 10612 // -------------------AAA----------------- 10613 // -------------------BBBCCCCCCC----------------- 10614 // 10615 // In this case, we consider any node that ended inside the change range to keep its 10616 // end position. 10617 // 10618 // however, if the delta is negative, then we instead have something like this: 10619 // 10620 // -------------------XXXYYYYYYY----------------- 10621 // -------------------ZZZ----------------- 10622 // 10623 // In this case, any element that ended in the 'X' range will keep its position. 10624 // However any element that ended after that will have their pos adjusted to be 10625 // at the end of the new range. i.e. any node that ended in the 'Y' range will 10626 // be adjusted to have their end at the end of the 'Z' range. 10627 const end = element.end >= changeRangeOldEnd ? 10628 // Element ends after the change range. Always adjust the end pos. 10629 element.end + delta : 10630 // Element ends in the change range. The element will keep its position if 10631 // possible. Or Move backward to the new-end if it's in the 'Y' range. 10632 Math.min(element.end, changeRangeNewEnd); 10633 10634 Debug.assert(pos <= end); 10635 if (element.parent) { 10636 Debug.assertGreaterThanOrEqual(pos, element.parent.pos); 10637 Debug.assertLessThanOrEqual(end, element.parent.end); 10638 } 10639 10640 setTextRangePosEnd(element, pos, end); 10641 } 10642 10643 function checkNodePositions(node: Node, aggressiveChecks: boolean) { 10644 if (aggressiveChecks) { 10645 let pos = node.pos; 10646 const visitNode = (child: Node) => { 10647 Debug.assert(child.pos >= pos); 10648 pos = child.end; 10649 }; 10650 if (hasJSDocNodes(node)) { 10651 for (const jsDocComment of node.jsDoc!) { 10652 visitNode(jsDocComment); 10653 } 10654 } 10655 forEachChild(node, visitNode); 10656 Debug.assert(pos <= node.end); 10657 } 10658 } 10659 10660 function updateTokenPositionsAndMarkElements( 10661 sourceFile: IncrementalNode, 10662 changeStart: number, 10663 changeRangeOldEnd: number, 10664 changeRangeNewEnd: number, 10665 delta: number, 10666 oldText: string, 10667 newText: string, 10668 aggressiveChecks: boolean): void { 10669 10670 visitNode(sourceFile); 10671 return; 10672 10673 function visitNode(child: IncrementalNode) { 10674 Debug.assert(child.pos <= child.end); 10675 if (child.pos > changeRangeOldEnd) { 10676 // Node is entirely past the change range. We need to move both its pos and 10677 // end, forward or backward appropriately. 10678 moveElementEntirelyPastChangeRange(child, /*isArray*/ false, delta, oldText, newText, aggressiveChecks); 10679 return; 10680 } 10681 10682 // Check if the element intersects the change range. If it does, then it is not 10683 // reusable. Also, we'll need to recurse to see what constituent portions we may 10684 // be able to use. 10685 const fullEnd = child.end; 10686 if (fullEnd >= changeStart) { 10687 child.intersectsChange = true; 10688 child._children = undefined; 10689 10690 // Adjust the pos or end (or both) of the intersecting element accordingly. 10691 adjustIntersectingElement(child, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta); 10692 forEachChild(child, visitNode, visitArray); 10693 if (hasJSDocNodes(child)) { 10694 for (const jsDocComment of child.jsDoc!) { 10695 visitNode(jsDocComment as Node as IncrementalNode); 10696 } 10697 } 10698 checkNodePositions(child, aggressiveChecks); 10699 return; 10700 } 10701 10702 // Otherwise, the node is entirely before the change range. No need to do anything with it. 10703 Debug.assert(fullEnd < changeStart); 10704 } 10705 10706 function visitArray(array: IncrementalNodeArray) { 10707 Debug.assert(array.pos <= array.end); 10708 if (array.pos > changeRangeOldEnd) { 10709 // Array is entirely after the change range. We need to move it, and move any of 10710 // its children. 10711 moveElementEntirelyPastChangeRange(array, /*isArray*/ true, delta, oldText, newText, aggressiveChecks); 10712 return; 10713 } 10714 10715 // Check if the element intersects the change range. If it does, then it is not 10716 // reusable. Also, we'll need to recurse to see what constituent portions we may 10717 // be able to use. 10718 const fullEnd = array.end; 10719 if (fullEnd >= changeStart) { 10720 array.intersectsChange = true; 10721 array._children = undefined; 10722 10723 // Adjust the pos or end (or both) of the intersecting array accordingly. 10724 adjustIntersectingElement(array, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta); 10725 for (const node of array) { 10726 if (!node.virtual) { 10727 visitNode(node); 10728 } 10729 } 10730 return; 10731 } 10732 10733 // Otherwise, the array is entirely before the change range. No need to do anything with it. 10734 Debug.assert(fullEnd < changeStart); 10735 } 10736 } 10737 10738 function extendToAffectedRange(sourceFile: SourceFile, changeRange: TextChangeRange): TextChangeRange { 10739 // Consider the following code: 10740 // void foo() { /; } 10741 // 10742 // If the text changes with an insertion of / just before the semicolon then we end up with: 10743 // void foo() { //; } 10744 // 10745 // If we were to just use the changeRange a is, then we would not rescan the { token 10746 // (as it does not intersect the actual original change range). Because an edit may 10747 // change the token touching it, we actually need to look back *at least* one token so 10748 // that the prior token sees that change. 10749 const maxLookahead = 1; 10750 10751 let start = changeRange.span.start; 10752 10753 // the first iteration aligns us with the change start. subsequent iteration move us to 10754 // the left by maxLookahead tokens. We only need to do this as long as we're not at the 10755 // start of the tree. 10756 for (let i = 0; start > 0 && i <= maxLookahead; i++) { 10757 const nearestNode = findNearestNodeStartingBeforeOrAtPosition(sourceFile, start); 10758 Debug.assert(nearestNode.pos <= start); 10759 const position = nearestNode.pos; 10760 10761 start = Math.max(0, position - 1); 10762 } 10763 10764 const finalSpan = createTextSpanFromBounds(start, textSpanEnd(changeRange.span)); 10765 const finalLength = changeRange.newLength + (changeRange.span.start - start); 10766 10767 return createTextChangeRange(finalSpan, finalLength); 10768 } 10769 10770 function findNearestNodeStartingBeforeOrAtPosition(sourceFile: SourceFile, position: number): Node { 10771 let bestResult: Node = sourceFile; 10772 let lastNodeEntirelyBeforePosition: Node | undefined; 10773 10774 forEachChild(sourceFile, visit); 10775 10776 if (lastNodeEntirelyBeforePosition) { 10777 const lastChildOfLastEntireNodeBeforePosition = getLastDescendant(lastNodeEntirelyBeforePosition); 10778 if (lastChildOfLastEntireNodeBeforePosition.pos > bestResult.pos) { 10779 bestResult = lastChildOfLastEntireNodeBeforePosition; 10780 } 10781 } 10782 10783 return bestResult; 10784 10785 function getLastDescendant(node: Node): Node { 10786 while (true) { 10787 const lastChild = getLastChild(node); 10788 if (lastChild) { 10789 node = lastChild; 10790 } 10791 else { 10792 return node; 10793 } 10794 } 10795 } 10796 10797 function visit(child: Node) { 10798 if (nodeIsMissing(child)) { 10799 // Missing nodes are effectively invisible to us. We never even consider them 10800 // When trying to find the nearest node before us. 10801 return; 10802 } 10803 10804 // If the child intersects this position, then this node is currently the nearest 10805 // node that starts before the position. 10806 if (child.pos <= position) { 10807 if (child.pos >= bestResult.pos) { 10808 // This node starts before the position, and is closer to the position than 10809 // the previous best node we found. It is now the new best node. 10810 bestResult = child; 10811 } 10812 10813 // Now, the node may overlap the position, or it may end entirely before the 10814 // position. If it overlaps with the position, then either it, or one of its 10815 // children must be the nearest node before the position. So we can just 10816 // recurse into this child to see if we can find something better. 10817 if (position < child.end) { 10818 // The nearest node is either this child, or one of the children inside 10819 // of it. We've already marked this child as the best so far. Recurse 10820 // in case one of the children is better. 10821 forEachChild(child, visit); 10822 10823 // Once we look at the children of this node, then there's no need to 10824 // continue any further. 10825 return true; 10826 } 10827 else { 10828 Debug.assert(child.end <= position); 10829 // The child ends entirely before this position. Say you have the following 10830 // (where $ is the position) 10831 // 10832 // <complex expr 1> ? <complex expr 2> $ : <...> <...> 10833 // 10834 // We would want to find the nearest preceding node in "complex expr 2". 10835 // To support that, we keep track of this node, and once we're done searching 10836 // for a best node, we recurse down this node to see if we can find a good 10837 // result in it. 10838 // 10839 // This approach allows us to quickly skip over nodes that are entirely 10840 // before the position, while still allowing us to find any nodes in the 10841 // last one that might be what we want. 10842 lastNodeEntirelyBeforePosition = child; 10843 } 10844 } 10845 else { 10846 Debug.assert(child.pos > position); 10847 // We're now at a node that is entirely past the position we're searching for. 10848 // This node (and all following nodes) could never contribute to the result, 10849 // so just skip them by returning 'true' here. 10850 return true; 10851 } 10852 } 10853 } 10854 10855 function checkChangeRange(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks: boolean) { 10856 const oldText = sourceFile.text; 10857 if (textChangeRange) { 10858 Debug.assert((oldText.length - textChangeRange.span.length + textChangeRange.newLength) === newText.length); 10859 10860 if (aggressiveChecks || Debug.shouldAssert(AssertionLevel.VeryAggressive)) { 10861 const oldTextPrefix = oldText.substr(0, textChangeRange.span.start); 10862 const newTextPrefix = newText.substr(0, textChangeRange.span.start); 10863 Debug.assert(oldTextPrefix === newTextPrefix); 10864 10865 const oldTextSuffix = oldText.substring(textSpanEnd(textChangeRange.span), oldText.length); 10866 const newTextSuffix = newText.substring(textSpanEnd(textChangeRangeNewSpan(textChangeRange)), newText.length); 10867 Debug.assert(oldTextSuffix === newTextSuffix); 10868 } 10869 } 10870 } 10871 10872 interface IncrementalElement extends ReadonlyTextRange { 10873 readonly parent: Node; 10874 intersectsChange: boolean; 10875 length?: number; 10876 _children: Node[] | undefined; 10877 } 10878 10879 export interface IncrementalNode extends Node, IncrementalElement { 10880 hasBeenIncrementallyParsed: boolean; 10881 } 10882 10883 interface IncrementalNodeArray extends NodeArray<IncrementalNode>, IncrementalElement { 10884 length: number; 10885 } 10886 10887 // Allows finding nodes in the source file at a certain position in an efficient manner. 10888 // The implementation takes advantage of the calling pattern it knows the parser will 10889 // make in order to optimize finding nodes as quickly as possible. 10890 export interface SyntaxCursor { 10891 currentNode(position: number): IncrementalNode; 10892 } 10893 10894 export function createSyntaxCursor(sourceFile: SourceFile): SyntaxCursor { 10895 let currentArray: NodeArray<Node> = sourceFile.statements; 10896 let currentArrayIndex = 0; 10897 10898 Debug.assert(currentArrayIndex < currentArray.length); 10899 let current = currentArray[currentArrayIndex]; 10900 let lastQueriedPosition = InvalidPosition.Value; 10901 10902 return { 10903 currentNode(position: number) { 10904 // Only compute the current node if the position is different than the last time 10905 // we were asked. The parser commonly asks for the node at the same position 10906 // twice. Once to know if can read an appropriate list element at a certain point, 10907 // and then to actually read and consume the node. 10908 if (position !== lastQueriedPosition) { 10909 // Much of the time the parser will need the very next node in the array that 10910 // we just returned a node from.So just simply check for that case and move 10911 // forward in the array instead of searching for the node again. 10912 if (current && current.end === position && currentArrayIndex < (currentArray.length - 1)) { 10913 currentArrayIndex++; 10914 current = currentArray[currentArrayIndex]; 10915 } 10916 10917 // If we don't have a node, or the node we have isn't in the right position, 10918 // then try to find a viable node at the position requested. 10919 if (!current || current.pos !== position) { 10920 findHighestListElementThatStartsAtPosition(position); 10921 } 10922 } 10923 10924 // Cache this query so that we don't do any extra work if the parser calls back 10925 // into us. Note: this is very common as the parser will make pairs of calls like 10926 // 'isListElement -> parseListElement'. If we were unable to find a node when 10927 // called with 'isListElement', we don't want to redo the work when parseListElement 10928 // is called immediately after. 10929 lastQueriedPosition = position; 10930 10931 // Either we don'd have a node, or we have a node at the position being asked for. 10932 Debug.assert(!current || current.pos === position); 10933 return current as IncrementalNode; 10934 } 10935 }; 10936 10937 // Finds the highest element in the tree we can find that starts at the provided position. 10938 // The element must be a direct child of some node list in the tree. This way after we 10939 // return it, we can easily return its next sibling in the list. 10940 function findHighestListElementThatStartsAtPosition(position: number) { 10941 // Clear out any cached state about the last node we found. 10942 currentArray = undefined!; 10943 currentArrayIndex = InvalidPosition.Value; 10944 current = undefined!; 10945 10946 // Recurse into the source file to find the highest node at this position. 10947 forEachChild(sourceFile, visitNode, visitArray); 10948 return; 10949 10950 function visitNode(node: Node) { 10951 if (position >= node.pos && position < node.end) { 10952 // Position was within this node. Keep searching deeper to find the node. 10953 forEachChild(node, visitNode, visitArray); 10954 10955 // don't proceed any further in the search. 10956 return true; 10957 } 10958 10959 // position wasn't in this node, have to keep searching. 10960 return false; 10961 } 10962 10963 function visitArray(array: NodeArray<Node>) { 10964 if (position >= array.pos && position < array.end) { 10965 // position was in this array. Search through this array to see if we find a 10966 // viable element. 10967 for (let i = 0; i < array.length; i++) { 10968 const child = array[i]; 10969 if (child) { 10970 if (child.pos === position) { 10971 // Found the right node. We're done. 10972 currentArray = array; 10973 currentArrayIndex = i; 10974 current = child; 10975 return true; 10976 } 10977 else { 10978 if (child.pos < position && position < child.end) { 10979 // Position in somewhere within this child. Search in it and 10980 // stop searching in this array. 10981 forEachChild(child, visitNode, visitArray); 10982 return true; 10983 } 10984 } 10985 } 10986 } 10987 } 10988 10989 // position wasn't in this array, have to keep searching. 10990 return false; 10991 } 10992 } 10993 } 10994 10995 const enum InvalidPosition { 10996 Value = -1 10997 } 10998} 10999 11000/** @internal */ 11001export function isDeclarationFileName(fileName: string): boolean { 11002 return fileExtensionIsOneOf(fileName, supportedDeclarationExtensions); 11003} 11004 11005/** @internal */ 11006export interface PragmaContext { 11007 languageVersion: ScriptTarget; 11008 pragmas?: PragmaMap; 11009 checkJsDirective?: CheckJsDirective; 11010 referencedFiles: FileReference[]; 11011 typeReferenceDirectives: FileReference[]; 11012 libReferenceDirectives: FileReference[]; 11013 amdDependencies: AmdDependency[]; 11014 hasNoDefaultLib?: boolean; 11015 moduleName?: string; 11016} 11017 11018function parseResolutionMode(mode: string | undefined, pos: number, end: number, reportDiagnostic: PragmaDiagnosticReporter): ModuleKind.ESNext | ModuleKind.CommonJS | undefined { 11019 if (!mode) { 11020 return undefined; 11021 } 11022 if (mode === "import") { 11023 return ModuleKind.ESNext; 11024 } 11025 if (mode === "require") { 11026 return ModuleKind.CommonJS; 11027 } 11028 reportDiagnostic(pos, end - pos, Diagnostics.resolution_mode_should_be_either_require_or_import); 11029 return undefined; 11030} 11031 11032/** @internal */ 11033export function processCommentPragmas(context: PragmaContext, sourceText: string): void { 11034 const pragmas: PragmaPseudoMapEntry[] = []; 11035 11036 for (const range of getLeadingCommentRanges(sourceText, 0) || emptyArray) { 11037 const comment = sourceText.substring(range.pos, range.end); 11038 extractPragmas(pragmas, range, comment); 11039 } 11040 11041 context.pragmas = new Map() as PragmaMap; 11042 for (const pragma of pragmas) { 11043 if (context.pragmas.has(pragma.name)) { 11044 const currentValue = context.pragmas.get(pragma.name); 11045 if (currentValue instanceof Array) { 11046 currentValue.push(pragma.args); 11047 } 11048 else { 11049 context.pragmas.set(pragma.name, [currentValue, pragma.args]); 11050 } 11051 continue; 11052 } 11053 context.pragmas.set(pragma.name, pragma.args); 11054 } 11055} 11056 11057/** @internal */ 11058export type PragmaDiagnosticReporter = (pos: number, length: number, message: DiagnosticMessage) => void; 11059 11060/** @internal */ 11061export function processPragmasIntoFields(context: PragmaContext, reportDiagnostic: PragmaDiagnosticReporter): void { 11062 context.checkJsDirective = undefined; 11063 context.referencedFiles = []; 11064 context.typeReferenceDirectives = []; 11065 context.libReferenceDirectives = []; 11066 context.amdDependencies = []; 11067 context.hasNoDefaultLib = false; 11068 context.pragmas!.forEach((entryOrList, key) => { // TODO: GH#18217 11069 // TODO: The below should be strongly type-guarded and not need casts/explicit annotations, since entryOrList is related to 11070 // key and key is constrained to a union; but it's not (see GH#21483 for at least partial fix) :( 11071 switch (key) { 11072 case "reference": { 11073 const referencedFiles = context.referencedFiles; 11074 const typeReferenceDirectives = context.typeReferenceDirectives; 11075 const libReferenceDirectives = context.libReferenceDirectives; 11076 forEach(toArray(entryOrList) as PragmaPseudoMap["reference"][], arg => { 11077 const { types, lib, path, ["resolution-mode"]: res } = arg.arguments; 11078 if (arg.arguments["no-default-lib"]) { 11079 context.hasNoDefaultLib = true; 11080 } 11081 else if (types) { 11082 const parsed = parseResolutionMode(res, types.pos, types.end, reportDiagnostic); 11083 typeReferenceDirectives.push({ pos: types.pos, end: types.end, fileName: types.value, ...(parsed ? { resolutionMode: parsed } : {}) }); 11084 } 11085 else if (lib) { 11086 libReferenceDirectives.push({ pos: lib.pos, end: lib.end, fileName: lib.value }); 11087 } 11088 else if (path) { 11089 referencedFiles.push({ pos: path.pos, end: path.end, fileName: path.value }); 11090 } 11091 else { 11092 reportDiagnostic(arg.range.pos, arg.range.end - arg.range.pos, Diagnostics.Invalid_reference_directive_syntax); 11093 } 11094 }); 11095 break; 11096 } 11097 case "amd-dependency": { 11098 context.amdDependencies = map( 11099 toArray(entryOrList) as PragmaPseudoMap["amd-dependency"][], 11100 x => ({ name: x.arguments.name, path: x.arguments.path })); 11101 break; 11102 } 11103 case "amd-module": { 11104 if (entryOrList instanceof Array) { 11105 for (const entry of entryOrList) { 11106 if (context.moduleName) { 11107 // TODO: It's probably fine to issue this diagnostic on all instances of the pragma 11108 reportDiagnostic(entry.range.pos, entry.range.end - entry.range.pos, Diagnostics.An_AMD_module_cannot_have_multiple_name_assignments); 11109 } 11110 context.moduleName = (entry as PragmaPseudoMap["amd-module"]).arguments.name; 11111 } 11112 } 11113 else { 11114 context.moduleName = (entryOrList as PragmaPseudoMap["amd-module"]).arguments.name; 11115 } 11116 break; 11117 } 11118 case "ts-nocheck": 11119 case "ts-check": { 11120 // _last_ of either nocheck or check in a file is the "winner" 11121 forEach(toArray(entryOrList), entry => { 11122 if (!context.checkJsDirective || entry.range.pos > context.checkJsDirective.pos) { 11123 context.checkJsDirective = { 11124 enabled: key === "ts-check", 11125 end: entry.range.end, 11126 pos: entry.range.pos 11127 }; 11128 } 11129 }); 11130 break; 11131 } 11132 case "jsx": 11133 case "jsxfrag": 11134 case "jsximportsource": 11135 case "jsxruntime": 11136 return; // Accessed directly 11137 default: Debug.fail("Unhandled pragma kind"); // Can this be made into an assertNever in the future? 11138 } 11139 }); 11140} 11141 11142const namedArgRegExCache = new Map<string, RegExp>(); 11143function getNamedArgRegEx(name: string): RegExp { 11144 if (namedArgRegExCache.has(name)) { 11145 return namedArgRegExCache.get(name)!; 11146 } 11147 const result = new RegExp(`(\\s${name}\\s*=\\s*)(?:(?:'([^']*)')|(?:"([^"]*)"))`, "im"); 11148 namedArgRegExCache.set(name, result); 11149 return result; 11150} 11151 11152const tripleSlashXMLCommentStartRegEx = /^\/\/\/\s*<(\S+)\s.*?\/>/im; 11153const singleLinePragmaRegEx = /^\/\/\/?\s*@(\S+)\s*(.*)\s*$/im; 11154function extractPragmas(pragmas: PragmaPseudoMapEntry[], range: CommentRange, text: string) { 11155 const tripleSlash = range.kind === SyntaxKind.SingleLineCommentTrivia && tripleSlashXMLCommentStartRegEx.exec(text); 11156 if (tripleSlash) { 11157 const name = tripleSlash[1].toLowerCase() as keyof PragmaPseudoMap; // Technically unsafe cast, but we do it so the below check to make it safe typechecks 11158 const pragma = commentPragmas[name] as PragmaDefinition; 11159 if (!pragma || !(pragma.kind! & PragmaKindFlags.TripleSlashXML)) { 11160 return; 11161 } 11162 if (pragma.args) { 11163 const argument: {[index: string]: string | {value: string, pos: number, end: number}} = {}; 11164 for (const arg of pragma.args) { 11165 const matcher = getNamedArgRegEx(arg.name); 11166 const matchResult = matcher.exec(text); 11167 if (!matchResult && !arg.optional) { 11168 return; // Missing required argument, don't parse 11169 } 11170 else if (matchResult) { 11171 const value = matchResult[2] || matchResult[3]; 11172 if (arg.captureSpan) { 11173 const startPos = range.pos + matchResult.index + matchResult[1].length + 1; 11174 argument[arg.name] = { 11175 value, 11176 pos: startPos, 11177 end: startPos + value.length 11178 }; 11179 } 11180 else { 11181 argument[arg.name] = value; 11182 } 11183 } 11184 } 11185 pragmas.push({ name, args: { arguments: argument, range } } as PragmaPseudoMapEntry); 11186 } 11187 else { 11188 pragmas.push({ name, args: { arguments: {}, range } } as PragmaPseudoMapEntry); 11189 } 11190 return; 11191 } 11192 11193 const singleLine = range.kind === SyntaxKind.SingleLineCommentTrivia && singleLinePragmaRegEx.exec(text); 11194 if (singleLine) { 11195 return addPragmaForMatch(pragmas, range, PragmaKindFlags.SingleLine, singleLine); 11196 } 11197 11198 if (range.kind === SyntaxKind.MultiLineCommentTrivia) { 11199 const multiLinePragmaRegEx = /@(\S+)(\s+.*)?$/gim; // Defined inline since it uses the "g" flag, which keeps a persistent index (for iterating) 11200 let multiLineMatch: RegExpExecArray | null; 11201 while (multiLineMatch = multiLinePragmaRegEx.exec(text)) { 11202 addPragmaForMatch(pragmas, range, PragmaKindFlags.MultiLine, multiLineMatch); 11203 } 11204 } 11205} 11206 11207function addPragmaForMatch(pragmas: PragmaPseudoMapEntry[], range: CommentRange, kind: PragmaKindFlags, match: RegExpExecArray) { 11208 if (!match) return; 11209 const name = match[1].toLowerCase() as keyof PragmaPseudoMap; // Technically unsafe cast, but we do it so they below check to make it safe typechecks 11210 const pragma = commentPragmas[name] as PragmaDefinition; 11211 if (!pragma || !(pragma.kind! & kind)) { 11212 return; 11213 } 11214 const args = match[2]; // Split on spaces and match up positionally with definition 11215 const argument = getNamedPragmaArguments(pragma, args); 11216 if (argument === "fail") return; // Missing required argument, fail to parse it 11217 pragmas.push({ name, args: { arguments: argument, range } } as PragmaPseudoMapEntry); 11218 return; 11219} 11220 11221function getNamedPragmaArguments(pragma: PragmaDefinition, text: string | undefined): {[index: string]: string} | "fail" { 11222 if (!text) return {}; 11223 if (!pragma.args) return {}; 11224 const args = trimString(text).split(/\s+/); 11225 const argMap: {[index: string]: string} = {}; 11226 for (let i = 0; i < pragma.args.length; i++) { 11227 const argument = pragma.args[i]; 11228 if (!args[i] && !argument.optional) { 11229 return "fail"; 11230 } 11231 if (argument.captureSpan) { 11232 return Debug.fail("Capture spans not yet implemented for non-xml pragmas"); 11233 } 11234 argMap[argument.name] = args[i]; 11235 } 11236 return argMap; 11237} 11238 11239/** @internal */ 11240export function tagNamesAreEquivalent(lhs: JsxTagNameExpression, rhs: JsxTagNameExpression): boolean { 11241 if (lhs.kind !== rhs.kind) { 11242 return false; 11243 } 11244 11245 if (lhs.kind === SyntaxKind.Identifier) { 11246 return lhs.escapedText === (rhs as Identifier).escapedText; 11247 } 11248 11249 if (lhs.kind === SyntaxKind.ThisKeyword) { 11250 return true; 11251 } 11252 11253 // If we are at this statement then we must have PropertyAccessExpression and because tag name in Jsx element can only 11254 // take forms of JsxTagNameExpression which includes an identifier, "this" expression, or another propertyAccessExpression 11255 // it is safe to case the expression property as such. See parseJsxElementName for how we parse tag name in Jsx element 11256 return (lhs as PropertyAccessExpression).name.escapedText === (rhs as PropertyAccessExpression).name.escapedText && 11257 tagNamesAreEquivalent((lhs as PropertyAccessExpression).expression as JsxTagNameExpression, (rhs as PropertyAccessExpression).expression as JsxTagNameExpression); 11258} 11259