1namespace ts { 2 const enum SignatureFlags { 3 None = 0, 4 Yield = 1 << 0, 5 Await = 1 << 1, 6 Type = 1 << 2, 7 IgnoreMissingOpenBrace = 1 << 4, 8 JSDoc = 1 << 5, 9 } 10 11 const enum SpeculationKind { 12 TryParse, 13 Lookahead, 14 Reparse 15 } 16 17 let NodeConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node; 18 let TokenConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node; 19 let IdentifierConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node; 20 let PrivateIdentifierConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node; 21 let SourceFileConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node; 22 23 /** 24 * NOTE: You should not use this, it is only exported to support `createNode` in `~/src/deprecatedCompat/deprecations.ts`. 25 */ 26 /* @internal */ 27 export const parseBaseNodeFactory: BaseNodeFactory = { 28 createBaseSourceFileNode: kind => new (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))(kind, -1, -1), 29 createBaseIdentifierNode: kind => new (IdentifierConstructor || (IdentifierConstructor = objectAllocator.getIdentifierConstructor()))(kind, -1, -1), 30 createBasePrivateIdentifierNode: kind => new (PrivateIdentifierConstructor || (PrivateIdentifierConstructor = objectAllocator.getPrivateIdentifierConstructor()))(kind, -1, -1), 31 createBaseTokenNode: kind => new (TokenConstructor || (TokenConstructor = objectAllocator.getTokenConstructor()))(kind, -1, -1), 32 createBaseNode: kind => new (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor()))(kind, -1, -1), 33 }; 34 35 /* @internal */ 36 export const parseNodeFactory = createNodeFactory(NodeFactoryFlags.NoParenthesizerRules, parseBaseNodeFactory); 37 38 function visitNode<T>(cbNode: (node: Node) => T, node: Node | undefined): T | undefined { 39 return node && cbNode(node); 40 } 41 42 function visitNodes<T>(cbNode: (node: Node) => T, cbNodes: ((node: NodeArray<Node>) => T | undefined) | undefined, nodes: NodeArray<Node> | undefined): T | undefined { 43 if (nodes) { 44 if (cbNodes) { 45 return cbNodes(nodes); 46 } 47 for (const node of nodes) { 48 const result = cbNode(node); 49 if (result) { 50 return result; 51 } 52 } 53 } 54 } 55 56 /*@internal*/ 57 export function isJSDocLikeText(text: string, start: number) { 58 return text.charCodeAt(start + 1) === CharacterCodes.asterisk && 59 text.charCodeAt(start + 2) === CharacterCodes.asterisk && 60 text.charCodeAt(start + 3) !== CharacterCodes.slash; 61 } 62 63 /*@internal*/ 64 export function isFileProbablyExternalModule(sourceFile: SourceFile) { 65 // Try to use the first top-level import/export when available, then 66 // fall back to looking for an 'import.meta' somewhere in the tree if necessary. 67 return forEach(sourceFile.statements, isAnExternalModuleIndicatorNode) || 68 getImportMetaIfNecessary(sourceFile); 69 } 70 71 function isAnExternalModuleIndicatorNode(node: Node) { 72 return canHaveModifiers(node) && hasModifierOfKind(node, SyntaxKind.ExportKeyword) 73 || isImportEqualsDeclaration(node) && isExternalModuleReference(node.moduleReference) 74 || isImportDeclaration(node) 75 || isExportAssignment(node) 76 || isExportDeclaration(node) ? node : undefined; 77 } 78 79 function getImportMetaIfNecessary(sourceFile: SourceFile) { 80 return sourceFile.flags & NodeFlags.PossiblyContainsImportMeta ? 81 walkTreeForImportMeta(sourceFile) : 82 undefined; 83 } 84 85 function walkTreeForImportMeta(node: Node): Node | undefined { 86 return isImportMeta(node) ? node : forEachChild(node, walkTreeForImportMeta); 87 } 88 89 /** Do not use hasModifier inside the parser; it relies on parent pointers. Use this instead. */ 90 function hasModifierOfKind(node: HasModifiers, kind: SyntaxKind) { 91 return some(node.modifiers, m => m.kind === kind); 92 } 93 94 function isImportMeta(node: Node): boolean { 95 return isMetaProperty(node) && node.keywordToken === SyntaxKind.ImportKeyword && node.name.escapedText === "meta"; 96 } 97 98 type ForEachChildFunction<TNode> = <T>(node: TNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined) => T | undefined; 99 type ForEachChildTable = { [TNode in ForEachChildNodes as TNode["kind"]]: ForEachChildFunction<TNode> }; 100 const forEachChildTable: ForEachChildTable = { 101 [SyntaxKind.QualifiedName]: function forEachChildInQualifiedName<T>(node: QualifiedName, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 102 return visitNode(cbNode, node.left) || 103 visitNode(cbNode, node.right); 104 }, 105 [SyntaxKind.TypeParameter]: function forEachChildInTypeParameter<T>(node: TypeParameterDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 106 return visitNodes(cbNode, cbNodes, node.modifiers) || 107 visitNode(cbNode, node.name) || 108 visitNode(cbNode, node.constraint) || 109 visitNode(cbNode, node.default) || 110 visitNode(cbNode, node.expression); 111 }, 112 [SyntaxKind.ShorthandPropertyAssignment]: function forEachChildInShorthandPropertyAssignment<T>(node: ShorthandPropertyAssignment, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 113 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 114 visitNodes(cbNode, cbNodes, node.modifiers) || 115 visitNode(cbNode, node.name) || 116 visitNode(cbNode, node.questionToken) || 117 visitNode(cbNode, node.exclamationToken) || 118 visitNode(cbNode, node.equalsToken) || 119 visitNode(cbNode, node.objectAssignmentInitializer); 120 }, 121 [SyntaxKind.SpreadAssignment]: function forEachChildInSpreadAssignment<T>(node: SpreadAssignment, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 122 return visitNode(cbNode, node.expression); 123 }, 124 [SyntaxKind.Parameter]: function forEachChildInParameter<T>(node: ParameterDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 125 return visitNodes(cbNode, cbNodes, node.modifiers) || 126 visitNode(cbNode, node.dotDotDotToken) || 127 visitNode(cbNode, node.name) || 128 visitNode(cbNode, node.questionToken) || 129 visitNode(cbNode, node.type) || 130 visitNode(cbNode, node.initializer); 131 }, 132 [SyntaxKind.PropertyDeclaration]: function forEachChildInPropertyDeclaration<T>(node: PropertyDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 133 return visitNodes(cbNode, cbNodes, node.modifiers) || 134 visitNode(cbNode, node.name) || 135 visitNode(cbNode, node.questionToken) || 136 visitNode(cbNode, node.exclamationToken) || 137 visitNode(cbNode, node.type) || 138 visitNode(cbNode, node.initializer); 139 }, 140 [SyntaxKind.PropertySignature]: function forEachChildInPropertySignature<T>(node: PropertySignature, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 141 return visitNodes(cbNode, cbNodes, node.modifiers) || 142 visitNode(cbNode, node.name) || 143 visitNode(cbNode, node.questionToken) || 144 visitNode(cbNode, node.type) || 145 visitNode(cbNode, node.initializer); 146 }, 147 [SyntaxKind.PropertyAssignment]: function forEachChildInPropertyAssignment<T>(node: PropertyAssignment, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 148 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 149 visitNodes(cbNode, cbNodes, node.modifiers) || 150 visitNode(cbNode, node.name) || 151 visitNode(cbNode, node.questionToken) || 152 visitNode(cbNode, node.exclamationToken) || 153 visitNode(cbNode, node.initializer); 154 }, 155 [SyntaxKind.VariableDeclaration]: function forEachChildInVariableDeclaration<T>(node: VariableDeclaration, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 156 return visitNode(cbNode, node.name) || 157 visitNode(cbNode, node.exclamationToken) || 158 visitNode(cbNode, node.type) || 159 visitNode(cbNode, node.initializer); 160 }, 161 [SyntaxKind.BindingElement]: function forEachChildInBindingElement<T>(node: BindingElement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 162 return visitNode(cbNode, node.dotDotDotToken) || 163 visitNode(cbNode, node.propertyName) || 164 visitNode(cbNode, node.name) || 165 visitNode(cbNode, node.initializer); 166 }, 167 [SyntaxKind.IndexSignature]: function forEachChildInIndexSignature<T>(node: IndexSignatureDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 168 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 169 visitNodes(cbNode, cbNodes, node.modifiers) || 170 visitNodes(cbNode, cbNodes, node.typeParameters) || 171 visitNodes(cbNode, cbNodes, node.parameters) || 172 visitNode(cbNode, node.type); 173 }, 174 [SyntaxKind.ConstructorType]: function forEachChildInConstructorType<T>(node: ConstructorTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 175 return visitNodes(cbNode, cbNodes, node.modifiers) || 176 visitNodes(cbNode, cbNodes, node.typeParameters) || 177 visitNodes(cbNode, cbNodes, node.parameters) || 178 visitNode(cbNode, node.type); 179 }, 180 [SyntaxKind.FunctionType]: function forEachChildInFunctionType<T>(node: FunctionTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 181 return visitNodes(cbNode, cbNodes, node.modifiers) || 182 visitNodes(cbNode, cbNodes, node.typeParameters) || 183 visitNodes(cbNode, cbNodes, node.parameters) || 184 visitNode(cbNode, node.type); 185 }, 186 [SyntaxKind.CallSignature]: forEachChildInCallOrConstructSignature, 187 [SyntaxKind.ConstructSignature]: forEachChildInCallOrConstructSignature, 188 [SyntaxKind.EtsComponentExpression]: function forEachChildInEtsComponentExpression<T>(node: EtsComponentExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 189 return visitNode(cbNode, node.expression) || 190 visitNodes(cbNode, cbNodes, node.arguments) || 191 visitNode(cbNode, node.body); 192 }, 193 [SyntaxKind.MethodDeclaration]: function forEachChildInMethodDeclaration<T>(node: MethodDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 194 return visitNodes(cbNode, cbNodes, node.modifiers) || 195 visitNode(cbNode, node.asteriskToken) || 196 visitNode(cbNode, node.name) || 197 visitNode(cbNode, node.questionToken) || 198 visitNode(cbNode, node.exclamationToken) || 199 visitNodes(cbNode, cbNodes, node.typeParameters) || 200 visitNodes(cbNode, cbNodes, node.parameters) || 201 visitNode(cbNode, node.type) || 202 visitNode(cbNode, node.body); 203 }, 204 [SyntaxKind.MethodSignature]: function forEachChildInMethodSignature<T>(node: MethodSignature, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 205 return visitNodes(cbNode, cbNodes, node.modifiers) || 206 visitNode(cbNode, node.name) || 207 visitNode(cbNode, node.questionToken) || 208 visitNodes(cbNode, cbNodes, node.typeParameters) || 209 visitNodes(cbNode, cbNodes, node.parameters) || 210 visitNode(cbNode, node.type); 211 }, 212 [SyntaxKind.Constructor]: function forEachChildInConstructor<T>(node: ConstructorDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 213 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 214 visitNodes(cbNode, cbNodes, node.modifiers) || 215 visitNode(cbNode, node.name) || 216 visitNodes(cbNode, cbNodes, node.typeParameters) || 217 visitNodes(cbNode, cbNodes, node.parameters) || 218 visitNode(cbNode, node.type) || 219 visitNode(cbNode, node.body); 220 }, 221 [SyntaxKind.GetAccessor]: function forEachChildInGetAccessor<T>(node: GetAccessorDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 222 return visitNodes(cbNode, cbNodes, node.modifiers) || 223 visitNode(cbNode, node.name) || 224 visitNodes(cbNode, cbNodes, node.typeParameters) || 225 visitNodes(cbNode, cbNodes, node.parameters) || 226 visitNode(cbNode, node.type) || 227 visitNode(cbNode, node.body); 228 }, 229 [SyntaxKind.SetAccessor]: function forEachChildInSetAccessor<T>(node: SetAccessorDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 230 return visitNodes(cbNode, cbNodes, node.modifiers) || 231 visitNode(cbNode, node.name) || 232 visitNodes(cbNode, cbNodes, node.typeParameters) || 233 visitNodes(cbNode, cbNodes, node.parameters) || 234 visitNode(cbNode, node.type) || 235 visitNode(cbNode, node.body); 236 }, 237 [SyntaxKind.FunctionDeclaration]: function forEachChildInFunctionDeclaration<T>(node: FunctionDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 238 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 239 visitNodes(cbNode, cbNodes, node.modifiers) || 240 visitNode(cbNode, node.asteriskToken) || 241 visitNode(cbNode, node.name) || 242 visitNodes(cbNode, cbNodes, node.typeParameters) || 243 visitNodes(cbNode, cbNodes, node.parameters) || 244 visitNode(cbNode, node.type) || 245 visitNode(cbNode, node.body); 246 }, 247 [SyntaxKind.FunctionExpression]: function forEachChildInFunctionExpression<T>(node: FunctionExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 248 return visitNodes(cbNode, cbNodes, node.modifiers) || 249 visitNode(cbNode, node.asteriskToken) || 250 visitNode(cbNode, node.name) || 251 visitNodes(cbNode, cbNodes, node.typeParameters) || 252 visitNodes(cbNode, cbNodes, node.parameters) || 253 visitNode(cbNode, node.type) || 254 visitNode(cbNode, node.body); 255 }, 256 [SyntaxKind.ArrowFunction]: function forEachChildInArrowFunction<T>(node: ArrowFunction, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 257 return visitNodes(cbNode, cbNodes, node.modifiers) || 258 visitNodes(cbNode, cbNodes, node.typeParameters) || 259 visitNodes(cbNode, cbNodes, node.parameters) || 260 visitNode(cbNode, node.type) || 261 visitNode(cbNode, node.equalsGreaterThanToken) || 262 visitNode(cbNode, node.body); 263 }, 264 [SyntaxKind.ClassStaticBlockDeclaration]: function forEachChildInClassStaticBlockDeclaration<T>(node: ClassStaticBlockDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 265 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 266 visitNodes(cbNode, cbNodes, node.modifiers) || 267 visitNode(cbNode, node.body); 268 }, 269 [SyntaxKind.TypeReference]: function forEachChildInTypeReference<T>(node: TypeReferenceNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 270 return visitNode(cbNode, node.typeName) || 271 visitNodes(cbNode, cbNodes, node.typeArguments); 272 }, 273 [SyntaxKind.TypePredicate]: function forEachChildInTypePredicate<T>(node: TypePredicateNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 274 return visitNode(cbNode, node.assertsModifier) || 275 visitNode(cbNode, node.parameterName) || 276 visitNode(cbNode, node.type); 277 }, 278 [SyntaxKind.TypeQuery]: function forEachChildInTypeQuery<T>(node: TypeQueryNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 279 return visitNode(cbNode, node.exprName) || 280 visitNodes(cbNode, cbNodes, node.typeArguments); 281 }, 282 [SyntaxKind.TypeLiteral]: function forEachChildInTypeLiteral<T>(node: TypeLiteralNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 283 return visitNodes(cbNode, cbNodes, node.members); 284 }, 285 [SyntaxKind.ArrayType]: function forEachChildInArrayType<T>(node: ArrayTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 286 return visitNode(cbNode, node.elementType); 287 }, 288 [SyntaxKind.TupleType]: function forEachChildInTupleType<T>(node: TupleTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 289 return visitNodes(cbNode, cbNodes, node.elements); 290 }, 291 [SyntaxKind.UnionType]: forEachChildInUnionOrIntersectionType, 292 [SyntaxKind.IntersectionType]: forEachChildInUnionOrIntersectionType, 293 [SyntaxKind.ConditionalType]: function forEachChildInConditionalType<T>(node: ConditionalTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 294 return visitNode(cbNode, node.checkType) || 295 visitNode(cbNode, node.extendsType) || 296 visitNode(cbNode, node.trueType) || 297 visitNode(cbNode, node.falseType); 298 }, 299 [SyntaxKind.InferType]: function forEachChildInInferType<T>(node: InferTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 300 return visitNode(cbNode, node.typeParameter); 301 }, 302 [SyntaxKind.ImportType]: function forEachChildInImportType<T>(node: ImportTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 303 return visitNode(cbNode, node.argument) || 304 visitNode(cbNode, node.assertions) || 305 visitNode(cbNode, node.qualifier) || 306 visitNodes(cbNode, cbNodes, node.typeArguments); 307 }, 308 [SyntaxKind.ImportTypeAssertionContainer]: function forEachChildInImportTypeAssertionContainer<T>(node: ImportTypeAssertionContainer, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 309 return visitNode(cbNode, node.assertClause); 310 }, 311 [SyntaxKind.ParenthesizedType]: forEachChildInParenthesizedTypeOrTypeOperator, 312 [SyntaxKind.TypeOperator]: forEachChildInParenthesizedTypeOrTypeOperator, 313 [SyntaxKind.IndexedAccessType]: function forEachChildInIndexedAccessType<T>(node: IndexedAccessTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 314 return visitNode(cbNode, node.objectType) || 315 visitNode(cbNode, node.indexType); 316 }, 317 [SyntaxKind.MappedType]: function forEachChildInMappedType<T>(node: MappedTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 318 return visitNode(cbNode, node.readonlyToken) || 319 visitNode(cbNode, node.typeParameter) || 320 visitNode(cbNode, node.nameType) || 321 visitNode(cbNode, node.questionToken) || 322 visitNode(cbNode, node.type) || 323 visitNodes(cbNode, cbNodes, node.members); 324 }, 325 [SyntaxKind.LiteralType]: function forEachChildInLiteralType<T>(node: LiteralTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 326 return visitNode(cbNode, node.literal); 327 }, 328 [SyntaxKind.NamedTupleMember]: function forEachChildInNamedTupleMember<T>(node: NamedTupleMember, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 329 return visitNode(cbNode, node.dotDotDotToken) || 330 visitNode(cbNode, node.name) || 331 visitNode(cbNode, node.questionToken) || 332 visitNode(cbNode, node.type); 333 }, 334 [SyntaxKind.ObjectBindingPattern]: forEachChildInObjectOrArrayBindingPattern, 335 [SyntaxKind.ArrayBindingPattern]: forEachChildInObjectOrArrayBindingPattern, 336 [SyntaxKind.ArrayLiteralExpression]: function forEachChildInArrayLiteralExpression<T>(node: ArrayLiteralExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 337 return visitNodes(cbNode, cbNodes, node.elements); 338 }, 339 [SyntaxKind.ObjectLiteralExpression]: function forEachChildInObjectLiteralExpression<T>(node: ObjectLiteralExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 340 return visitNodes(cbNode, cbNodes, node.properties); 341 }, 342 [SyntaxKind.PropertyAccessExpression]: function forEachChildInPropertyAccessExpression<T>(node: PropertyAccessExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 343 return visitNode(cbNode, node.expression) || 344 visitNode(cbNode, node.questionDotToken) || 345 visitNode(cbNode, node.name); 346 }, 347 [SyntaxKind.ElementAccessExpression]: function forEachChildInElementAccessExpression<T>(node: ElementAccessExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 348 return visitNode(cbNode, node.expression) || 349 visitNode(cbNode, node.questionDotToken) || 350 visitNode(cbNode, node.argumentExpression); 351 }, 352 [SyntaxKind.CallExpression]: forEachChildInCallOrNewExpression, 353 [SyntaxKind.NewExpression]: forEachChildInCallOrNewExpression, 354 [SyntaxKind.TaggedTemplateExpression]: function forEachChildInTaggedTemplateExpression<T>(node: TaggedTemplateExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 355 return visitNode(cbNode, node.tag) || 356 visitNode(cbNode, node.questionDotToken) || 357 visitNodes(cbNode, cbNodes, node.typeArguments) || 358 visitNode(cbNode, node.template); 359 }, 360 [SyntaxKind.TypeAssertionExpression]: function forEachChildInTypeAssertionExpression<T>(node: TypeAssertion, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 361 return visitNode(cbNode, node.type) || 362 visitNode(cbNode, node.expression); 363 }, 364 [SyntaxKind.ParenthesizedExpression]: function forEachChildInParenthesizedExpression<T>(node: ParenthesizedExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 365 return visitNode(cbNode, node.expression); 366 }, 367 [SyntaxKind.DeleteExpression]: function forEachChildInDeleteExpression<T>(node: DeleteExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 368 return visitNode(cbNode, node.expression); 369 }, 370 [SyntaxKind.TypeOfExpression]: function forEachChildInTypeOfExpression<T>(node: TypeOfExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 371 return visitNode(cbNode, node.expression); 372 }, 373 [SyntaxKind.VoidExpression]: function forEachChildInVoidExpression<T>(node: VoidExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 374 return visitNode(cbNode, node.expression); 375 }, 376 [SyntaxKind.PrefixUnaryExpression]: function forEachChildInPrefixUnaryExpression<T>(node: PrefixUnaryExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 377 return visitNode(cbNode, node.operand); 378 }, 379 [SyntaxKind.YieldExpression]: function forEachChildInYieldExpression<T>(node: YieldExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 380 return visitNode(cbNode, node.asteriskToken) || 381 visitNode(cbNode, node.expression); 382 }, 383 [SyntaxKind.AwaitExpression]: function forEachChildInAwaitExpression<T>(node: AwaitExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 384 return visitNode(cbNode, node.expression); 385 }, 386 [SyntaxKind.PostfixUnaryExpression]: function forEachChildInPostfixUnaryExpression<T>(node: PostfixUnaryExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 387 return visitNode(cbNode, node.operand); 388 }, 389 [SyntaxKind.BinaryExpression]: function forEachChildInBinaryExpression<T>(node: BinaryExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 390 return visitNode(cbNode, node.left) || 391 visitNode(cbNode, node.operatorToken) || 392 visitNode(cbNode, node.right); 393 }, 394 [SyntaxKind.AsExpression]: function forEachChildInAsExpression<T>(node: AsExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 395 return visitNode(cbNode, node.expression) || 396 visitNode(cbNode, node.type); 397 }, 398 [SyntaxKind.NonNullExpression]: function forEachChildInNonNullExpression<T>(node: NonNullExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 399 return visitNode(cbNode, node.expression); 400 }, 401 [SyntaxKind.SatisfiesExpression]: function forEachChildInSatisfiesExpression<T>(node: SatisfiesExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 402 return visitNode(cbNode, node.expression) || visitNode(cbNode, node.type); 403 }, 404 [SyntaxKind.MetaProperty]: function forEachChildInMetaProperty<T>(node: MetaProperty, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 405 return visitNode(cbNode, node.name); 406 }, 407 [SyntaxKind.ConditionalExpression]: function forEachChildInConditionalExpression<T>(node: ConditionalExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 408 return visitNode(cbNode, node.condition) || 409 visitNode(cbNode, node.questionToken) || 410 visitNode(cbNode, node.whenTrue) || 411 visitNode(cbNode, node.colonToken) || 412 visitNode(cbNode, node.whenFalse); 413 }, 414 [SyntaxKind.SpreadElement]: function forEachChildInSpreadElement<T>(node: SpreadElement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 415 return visitNode(cbNode, node.expression); 416 }, 417 [SyntaxKind.Block]: forEachChildInBlock, 418 [SyntaxKind.ModuleBlock]: forEachChildInBlock, 419 [SyntaxKind.SourceFile]: function forEachChildInSourceFile<T>(node: SourceFile, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 420 return visitNodes(cbNode, cbNodes, node.statements) || 421 visitNode(cbNode, node.endOfFileToken); 422 }, 423 [SyntaxKind.VariableStatement]: function forEachChildInVariableStatement<T>(node: VariableStatement, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 424 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 425 visitNodes(cbNode, cbNodes, node.modifiers) || 426 visitNode(cbNode, node.declarationList); 427 }, 428 [SyntaxKind.VariableDeclarationList]: function forEachChildInVariableDeclarationList<T>(node: VariableDeclarationList, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 429 return visitNodes(cbNode, cbNodes, node.declarations); 430 }, 431 [SyntaxKind.ExpressionStatement]: function forEachChildInExpressionStatement<T>(node: ExpressionStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 432 return visitNode(cbNode, node.expression); 433 }, 434 [SyntaxKind.IfStatement]: function forEachChildInIfStatement<T>(node: IfStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 435 return visitNode(cbNode, node.expression) || 436 visitNode(cbNode, node.thenStatement) || 437 visitNode(cbNode, node.elseStatement); 438 }, 439 [SyntaxKind.DoStatement]: function forEachChildInDoStatement<T>(node: DoStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 440 return visitNode(cbNode, node.statement) || 441 visitNode(cbNode, node.expression); 442 }, 443 [SyntaxKind.WhileStatement]: function forEachChildInWhileStatement<T>(node: WhileStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 444 return visitNode(cbNode, node.expression) || 445 visitNode(cbNode, node.statement); 446 }, 447 [SyntaxKind.ForStatement]: function forEachChildInForStatement<T>(node: ForStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 448 return visitNode(cbNode, node.initializer) || 449 visitNode(cbNode, node.condition) || 450 visitNode(cbNode, node.incrementor) || 451 visitNode(cbNode, node.statement); 452 }, 453 [SyntaxKind.ForInStatement]: function forEachChildInForInStatement<T>(node: ForInStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 454 return visitNode(cbNode, node.initializer) || 455 visitNode(cbNode, node.expression) || 456 visitNode(cbNode, node.statement); 457 }, 458 [SyntaxKind.ForOfStatement]: function forEachChildInForOfStatement<T>(node: ForOfStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 459 return visitNode(cbNode, node.awaitModifier) || 460 visitNode(cbNode, node.initializer) || 461 visitNode(cbNode, node.expression) || 462 visitNode(cbNode, node.statement); 463 }, 464 [SyntaxKind.ContinueStatement]: forEachChildInContinueOrBreakStatement, 465 [SyntaxKind.BreakStatement]: forEachChildInContinueOrBreakStatement, 466 [SyntaxKind.ReturnStatement]: function forEachChildInReturnStatement<T>(node: ReturnStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 467 return visitNode(cbNode, node.expression); 468 }, 469 [SyntaxKind.WithStatement]: function forEachChildInWithStatement<T>(node: WithStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 470 return visitNode(cbNode, node.expression) || 471 visitNode(cbNode, node.statement); 472 }, 473 [SyntaxKind.SwitchStatement]: function forEachChildInSwitchStatement<T>(node: SwitchStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 474 return visitNode(cbNode, node.expression) || 475 visitNode(cbNode, node.caseBlock); 476 }, 477 [SyntaxKind.CaseBlock]: function forEachChildInCaseBlock<T>(node: CaseBlock, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 478 return visitNodes(cbNode, cbNodes, node.clauses); 479 }, 480 [SyntaxKind.CaseClause]: function forEachChildInCaseClause<T>(node: CaseClause, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 481 return visitNode(cbNode, node.expression) || 482 visitNodes(cbNode, cbNodes, node.statements); 483 }, 484 [SyntaxKind.DefaultClause]: function forEachChildInDefaultClause<T>(node: DefaultClause, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 485 return visitNodes(cbNode, cbNodes, node.statements); 486 }, 487 [SyntaxKind.LabeledStatement]: function forEachChildInLabeledStatement<T>(node: LabeledStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 488 return visitNode(cbNode, node.label) || 489 visitNode(cbNode, node.statement); 490 }, 491 [SyntaxKind.ThrowStatement]: function forEachChildInThrowStatement<T>(node: ThrowStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 492 return visitNode(cbNode, node.expression); 493 }, 494 [SyntaxKind.TryStatement]: function forEachChildInTryStatement<T>(node: TryStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 495 return visitNode(cbNode, node.tryBlock) || 496 visitNode(cbNode, node.catchClause) || 497 visitNode(cbNode, node.finallyBlock); 498 }, 499 [SyntaxKind.CatchClause]: function forEachChildInCatchClause<T>(node: CatchClause, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 500 return visitNode(cbNode, node.variableDeclaration) || 501 visitNode(cbNode, node.block); 502 }, 503 [SyntaxKind.Decorator]: function forEachChildInDecorator<T>(node: Decorator, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 504 return visitNode(cbNode, node.expression); 505 }, 506 [SyntaxKind.ClassDeclaration]: forEachChildInClassDeclarationOrExpression, 507 [SyntaxKind.ClassExpression]: forEachChildInClassDeclarationOrExpression, 508 [SyntaxKind.StructDeclaration]: forEachChildInClassDeclarationOrExpression, 509 [SyntaxKind.InterfaceDeclaration]: function forEachChildInInterfaceDeclaration<T>(node: InterfaceDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 510 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 511 visitNodes(cbNode, cbNodes, node.modifiers) || 512 visitNode(cbNode, node.name) || 513 visitNodes(cbNode, cbNodes, node.typeParameters) || 514 visitNodes(cbNode, cbNodes, node.heritageClauses) || 515 visitNodes(cbNode, cbNodes, node.members); 516 }, 517 [SyntaxKind.TypeAliasDeclaration]: function forEachChildInTypeAliasDeclaration<T>(node: TypeAliasDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 518 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 519 visitNodes(cbNode, cbNodes, node.modifiers) || 520 visitNode(cbNode, node.name) || 521 visitNodes(cbNode, cbNodes, node.typeParameters) || 522 visitNode(cbNode, node.type); 523 }, 524 [SyntaxKind.EnumDeclaration]: function forEachChildInEnumDeclaration<T>(node: EnumDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 525 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 526 visitNodes(cbNode, cbNodes, node.modifiers) || 527 visitNode(cbNode, node.name) || 528 visitNodes(cbNode, cbNodes, node.members); 529 }, 530 [SyntaxKind.EnumMember]: function forEachChildInEnumMember<T>(node: EnumMember, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 531 return visitNode(cbNode, node.name) || 532 visitNode(cbNode, node.initializer); 533 }, 534 [SyntaxKind.ModuleDeclaration]: function forEachChildInModuleDeclaration<T>(node: ModuleDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 535 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 536 visitNodes(cbNode, cbNodes, node.modifiers) || 537 visitNode(cbNode, node.name) || 538 visitNode(cbNode, node.body); 539 }, 540 [SyntaxKind.ImportEqualsDeclaration]: function forEachChildInImportEqualsDeclaration<T>(node: ImportEqualsDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 541 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 542 visitNodes(cbNode, cbNodes, node.modifiers) || 543 visitNode(cbNode, node.name) || 544 visitNode(cbNode, node.moduleReference); 545 }, 546 [SyntaxKind.ImportDeclaration]: function forEachChildInImportDeclaration<T>(node: ImportDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 547 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 548 visitNodes(cbNode, cbNodes, node.modifiers) || 549 visitNode(cbNode, node.importClause) || 550 visitNode(cbNode, node.moduleSpecifier) || 551 visitNode(cbNode, node.assertClause); 552 }, 553 [SyntaxKind.ImportClause]: function forEachChildInImportClause<T>(node: ImportClause, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 554 return visitNode(cbNode, node.name) || 555 visitNode(cbNode, node.namedBindings); 556 }, 557 [SyntaxKind.AssertClause]: function forEachChildInAssertClause<T>(node: AssertClause, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 558 return visitNodes(cbNode, cbNodes, node.elements); 559 }, 560 [SyntaxKind.AssertEntry]: function forEachChildInAssertEntry<T>(node: AssertEntry, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 561 return visitNode(cbNode, node.name) || 562 visitNode(cbNode, node.value); 563 }, 564 [SyntaxKind.NamespaceExportDeclaration]: function forEachChildInNamespaceExportDeclaration<T>(node: NamespaceExportDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 565 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 566 visitNode(cbNode, node.name); 567 }, 568 [SyntaxKind.NamespaceImport]: function forEachChildInNamespaceImport<T>(node: NamespaceImport, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 569 return visitNode(cbNode, node.name); 570 }, 571 [SyntaxKind.NamespaceExport]: function forEachChildInNamespaceExport<T>(node: NamespaceExport, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 572 return visitNode(cbNode, node.name); 573 }, 574 [SyntaxKind.NamedImports]: forEachChildInNamedImportsOrExports, 575 [SyntaxKind.NamedExports]: forEachChildInNamedImportsOrExports, 576 [SyntaxKind.ExportDeclaration]: function forEachChildInExportDeclaration<T>(node: ExportDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 577 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 578 visitNodes(cbNode, cbNodes, node.modifiers) || 579 visitNode(cbNode, node.exportClause) || 580 visitNode(cbNode, node.moduleSpecifier) || 581 visitNode(cbNode, node.assertClause); 582 }, 583 [SyntaxKind.ImportSpecifier]: forEachChildInImportOrExportSpecifier, 584 [SyntaxKind.ExportSpecifier]: forEachChildInImportOrExportSpecifier, 585 [SyntaxKind.ExportAssignment]: function forEachChildInExportAssignment<T>(node: ExportAssignment, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 586 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 587 visitNodes(cbNode, cbNodes, node.modifiers) || 588 visitNode(cbNode, node.expression); 589 }, 590 [SyntaxKind.TemplateExpression]: function forEachChildInTemplateExpression<T>(node: TemplateExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 591 return visitNode(cbNode, node.head) || 592 visitNodes(cbNode, cbNodes, node.templateSpans); 593 }, 594 [SyntaxKind.TemplateSpan]: function forEachChildInTemplateSpan<T>(node: TemplateSpan, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 595 return visitNode(cbNode, node.expression) || 596 visitNode(cbNode, node.literal); 597 }, 598 [SyntaxKind.TemplateLiteralType]: function forEachChildInTemplateLiteralType<T>(node: TemplateLiteralTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 599 return visitNode(cbNode, node.head) || 600 visitNodes(cbNode, cbNodes, node.templateSpans); 601 }, 602 [SyntaxKind.TemplateLiteralTypeSpan]: function forEachChildInTemplateLiteralTypeSpan<T>(node: TemplateLiteralTypeSpan, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 603 return visitNode(cbNode, node.type) || 604 visitNode(cbNode, node.literal); 605 }, 606 [SyntaxKind.ComputedPropertyName]: function forEachChildInComputedPropertyName<T>(node: ComputedPropertyName, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 607 return visitNode(cbNode, node.expression); 608 }, 609 [SyntaxKind.HeritageClause]: function forEachChildInHeritageClause<T>(node: HeritageClause, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 610 return visitNodes(cbNode, cbNodes, node.types); 611 }, 612 [SyntaxKind.ExpressionWithTypeArguments]: function forEachChildInExpressionWithTypeArguments<T>(node: ExpressionWithTypeArguments, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 613 return visitNode(cbNode, node.expression) || 614 visitNodes(cbNode, cbNodes, node.typeArguments); 615 }, 616 [SyntaxKind.ExternalModuleReference]: function forEachChildInExternalModuleReference<T>(node: ExternalModuleReference, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 617 return visitNode(cbNode, node.expression); 618 }, 619 [SyntaxKind.MissingDeclaration]: function forEachChildInMissingDeclaration<T>(node: MissingDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 620 return visitNodes(cbNode, cbNodes, node.illegalDecorators) || 621 visitNodes(cbNode, cbNodes, node.modifiers); 622 }, 623 [SyntaxKind.CommaListExpression]: function forEachChildInCommaListExpression<T>(node: CommaListExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 624 return visitNodes(cbNode, cbNodes, node.elements); 625 }, 626 [SyntaxKind.JsxElement]: function forEachChildInJsxElement<T>(node: JsxElement, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 627 return visitNode(cbNode, node.openingElement) || 628 visitNodes(cbNode, cbNodes, node.children) || 629 visitNode(cbNode, node.closingElement); 630 }, 631 [SyntaxKind.JsxFragment]: function forEachChildInJsxFragment<T>(node: JsxFragment, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 632 return visitNode(cbNode, node.openingFragment) || 633 visitNodes(cbNode, cbNodes, node.children) || 634 visitNode(cbNode, node.closingFragment); 635 }, 636 [SyntaxKind.JsxSelfClosingElement]: forEachChildInJsxOpeningOrSelfClosingElement, 637 [SyntaxKind.JsxOpeningElement]: forEachChildInJsxOpeningOrSelfClosingElement, 638 [SyntaxKind.JsxAttributes]: function forEachChildInJsxAttributes<T>(node: JsxAttributes, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 639 return visitNodes(cbNode, cbNodes, node.properties); 640 }, 641 [SyntaxKind.JsxAttribute]: function forEachChildInJsxAttribute<T>(node: JsxAttribute, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 642 return visitNode(cbNode, node.name) || 643 visitNode(cbNode, node.initializer); 644 }, 645 [SyntaxKind.JsxSpreadAttribute]: function forEachChildInJsxSpreadAttribute<T>(node: JsxSpreadAttribute, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 646 return visitNode(cbNode, node.expression); 647 }, 648 [SyntaxKind.JsxExpression]: function forEachChildInJsxExpression<T>(node: JsxExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 649 return visitNode(cbNode, node.dotDotDotToken) || 650 visitNode(cbNode, node.expression); 651 }, 652 [SyntaxKind.JsxClosingElement]: function forEachChildInJsxClosingElement<T>(node: JsxClosingElement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 653 return visitNode(cbNode, node.tagName); 654 }, 655 [SyntaxKind.OptionalType]: forEachChildInOptionalRestOrJSDocParameterModifier, 656 [SyntaxKind.RestType]: forEachChildInOptionalRestOrJSDocParameterModifier, 657 [SyntaxKind.JSDocTypeExpression]: forEachChildInOptionalRestOrJSDocParameterModifier, 658 [SyntaxKind.JSDocNonNullableType]: forEachChildInOptionalRestOrJSDocParameterModifier, 659 [SyntaxKind.JSDocNullableType]: forEachChildInOptionalRestOrJSDocParameterModifier, 660 [SyntaxKind.JSDocOptionalType]: forEachChildInOptionalRestOrJSDocParameterModifier, 661 [SyntaxKind.JSDocVariadicType]: forEachChildInOptionalRestOrJSDocParameterModifier, 662 [SyntaxKind.JSDocFunctionType]: function forEachChildInJSDocFunctionType<T>(node: JSDocFunctionType, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 663 return visitNodes(cbNode, cbNodes, node.parameters) || 664 visitNode(cbNode, node.type); 665 }, 666 [SyntaxKind.JSDoc]: function forEachChildInJSDoc<T>(node: JSDoc, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 667 return (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)) 668 || visitNodes(cbNode, cbNodes, node.tags); 669 }, 670 [SyntaxKind.JSDocSeeTag]: function forEachChildInJSDocSeeTag<T>(node: JSDocSeeTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 671 return visitNode(cbNode, node.tagName) || 672 visitNode(cbNode, node.name) || 673 (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); 674 }, 675 [SyntaxKind.JSDocNameReference]: function forEachChildInJSDocNameReference<T>(node: JSDocNameReference, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 676 return visitNode(cbNode, node.name); 677 }, 678 [SyntaxKind.JSDocMemberName]: function forEachChildInJSDocMemberName<T>(node: JSDocMemberName, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 679 return visitNode(cbNode, node.left) || 680 visitNode(cbNode, node.right); 681 }, 682 [SyntaxKind.JSDocParameterTag]: forEachChildInJSDocParameterOrPropertyTag, 683 [SyntaxKind.JSDocPropertyTag]: forEachChildInJSDocParameterOrPropertyTag, 684 [SyntaxKind.JSDocAuthorTag]: function forEachChildInJSDocAuthorTag<T>(node: JSDocAuthorTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 685 return visitNode(cbNode, node.tagName) || 686 (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); 687 }, 688 [SyntaxKind.JSDocImplementsTag]: function forEachChildInJSDocImplementsTag<T>(node: JSDocImplementsTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 689 return visitNode(cbNode, node.tagName) || 690 visitNode(cbNode, node.class) || 691 (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); 692 }, 693 [SyntaxKind.JSDocAugmentsTag]: function forEachChildInJSDocAugmentsTag<T>(node: JSDocAugmentsTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 694 return visitNode(cbNode, node.tagName) || 695 visitNode(cbNode, node.class) || 696 (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); 697 }, 698 [SyntaxKind.JSDocTemplateTag]: function forEachChildInJSDocTemplateTag<T>(node: JSDocTemplateTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 699 return visitNode(cbNode, node.tagName) || 700 visitNode(cbNode, node.constraint) || 701 visitNodes(cbNode, cbNodes, node.typeParameters) || 702 (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); 703 }, 704 [SyntaxKind.JSDocTypedefTag]: function forEachChildInJSDocTypedefTag<T>(node: JSDocTypedefTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 705 return visitNode(cbNode, node.tagName) || 706 (node.typeExpression && 707 node.typeExpression.kind === SyntaxKind.JSDocTypeExpression 708 ? visitNode(cbNode, node.typeExpression) || 709 visitNode(cbNode, node.fullName) || 710 (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)) 711 : visitNode(cbNode, node.fullName) || 712 visitNode(cbNode, node.typeExpression) || 713 (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment))); 714 }, 715 [SyntaxKind.JSDocCallbackTag]: function forEachChildInJSDocCallbackTag<T>(node: JSDocCallbackTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 716 return visitNode(cbNode, node.tagName) || 717 visitNode(cbNode, node.fullName) || 718 visitNode(cbNode, node.typeExpression) || 719 (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); 720 }, 721 [SyntaxKind.JSDocReturnTag]: forEachChildInJSDocReturnTag, 722 [SyntaxKind.JSDocTypeTag]: forEachChildInJSDocReturnTag, 723 [SyntaxKind.JSDocThisTag]: forEachChildInJSDocReturnTag, 724 [SyntaxKind.JSDocEnumTag]: forEachChildInJSDocReturnTag, 725 [SyntaxKind.JSDocSignature]: function forEachChildInJSDocSignature<T>(node: JSDocSignature, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 726 return forEach(node.typeParameters, cbNode) || 727 forEach(node.parameters, cbNode) || 728 visitNode(cbNode, node.type); 729 }, 730 [SyntaxKind.JSDocLink]: forEachChildInJSDocLinkCodeOrPlain, 731 [SyntaxKind.JSDocLinkCode]: forEachChildInJSDocLinkCodeOrPlain, 732 [SyntaxKind.JSDocLinkPlain]: forEachChildInJSDocLinkCodeOrPlain, 733 [SyntaxKind.JSDocTypeLiteral]: function forEachChildInJSDocTypeLiteral<T>(node: JSDocTypeLiteral, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 734 return forEach(node.jsDocPropertyTags, cbNode); 735 }, 736 [SyntaxKind.JSDocTag]: forEachChildInJSDocTag, 737 [SyntaxKind.JSDocClassTag]: forEachChildInJSDocTag, 738 [SyntaxKind.JSDocPublicTag]: forEachChildInJSDocTag, 739 [SyntaxKind.JSDocPrivateTag]: forEachChildInJSDocTag, 740 [SyntaxKind.JSDocProtectedTag]: forEachChildInJSDocTag, 741 [SyntaxKind.JSDocReadonlyTag]: forEachChildInJSDocTag, 742 [SyntaxKind.JSDocDeprecatedTag]: forEachChildInJSDocTag, 743 [SyntaxKind.JSDocOverrideTag]: forEachChildInJSDocTag, 744 [SyntaxKind.PartiallyEmittedExpression]: forEachChildInPartiallyEmittedExpression, 745 }; 746 747 // shared 748 749 function forEachChildInCallOrConstructSignature<T>(node: CallSignatureDeclaration | ConstructSignatureDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 750 return visitNodes(cbNode, cbNodes, node.typeParameters) || 751 visitNodes(cbNode, cbNodes, node.parameters) || 752 visitNode(cbNode, node.type); 753 } 754 755 function forEachChildInUnionOrIntersectionType<T>(node: UnionTypeNode | IntersectionTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 756 return visitNodes(cbNode, cbNodes, node.types); 757 } 758 759 function forEachChildInParenthesizedTypeOrTypeOperator<T>(node: ParenthesizedTypeNode | TypeOperatorNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 760 return visitNode(cbNode, node.type); 761 } 762 763 function forEachChildInObjectOrArrayBindingPattern<T>(node: BindingPattern, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 764 return visitNodes(cbNode, cbNodes, node.elements); 765 } 766 767 function forEachChildInCallOrNewExpression<T>(node: CallExpression | NewExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 768 return visitNode(cbNode, node.expression) || 769 // TODO: should we separate these branches out? 770 visitNode(cbNode, (node as CallExpression).questionDotToken) || 771 visitNodes(cbNode, cbNodes, node.typeArguments) || 772 visitNodes(cbNode, cbNodes, node.arguments); 773 } 774 775 function forEachChildInBlock<T>(node: Block | ModuleBlock, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 776 return visitNodes(cbNode, cbNodes, node.statements); 777 } 778 779 function forEachChildInContinueOrBreakStatement<T>(node: ContinueStatement | BreakStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 780 return visitNode(cbNode, node.label); 781 } 782 783 function forEachChildInClassDeclarationOrExpression<T>(node: ClassDeclaration | ClassExpression | StructDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 784 return visitNodes(cbNode, cbNodes, node.modifiers) || 785 visitNode(cbNode, node.name) || 786 visitNodes(cbNode, cbNodes, node.typeParameters) || 787 visitNodes(cbNode, cbNodes, node.heritageClauses) || 788 visitNodes(cbNode, cbNodes, node.members); 789 } 790 791 function forEachChildInNamedImportsOrExports<T>(node: NamedImports | NamedExports, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 792 return visitNodes(cbNode, cbNodes, node.elements); 793 } 794 795 function forEachChildInImportOrExportSpecifier<T>(node: ImportSpecifier | ExportSpecifier, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 796 return visitNode(cbNode, node.propertyName) || 797 visitNode(cbNode, node.name); 798 } 799 800 function forEachChildInJsxOpeningOrSelfClosingElement<T>(node: JsxOpeningLikeElement, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 801 return visitNode(cbNode, node.tagName) || 802 visitNodes(cbNode, cbNodes, node.typeArguments) || 803 visitNode(cbNode, node.attributes); 804 } 805 806 function forEachChildInOptionalRestOrJSDocParameterModifier<T>(node: OptionalTypeNode | RestTypeNode | JSDocTypeExpression | JSDocNullableType | JSDocNonNullableType | JSDocOptionalType | JSDocVariadicType, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 807 return visitNode(cbNode, node.type); 808 } 809 810 function forEachChildInJSDocParameterOrPropertyTag<T>(node: JSDocParameterTag | JSDocPropertyTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 811 return visitNode(cbNode, node.tagName) || 812 (node.isNameFirst 813 ? visitNode(cbNode, node.name) || visitNode(cbNode, node.typeExpression) 814 : visitNode(cbNode, node.typeExpression) || visitNode(cbNode, node.name)) || 815 (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); 816 } 817 818 function forEachChildInJSDocReturnTag<T>(node: JSDocReturnTag | JSDocTypeTag | JSDocThisTag | JSDocEnumTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 819 return visitNode(cbNode, node.tagName) || 820 visitNode(cbNode, node.typeExpression) || 821 (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); 822 } 823 824 function forEachChildInJSDocLinkCodeOrPlain<T>(node: JSDocLink | JSDocLinkCode | JSDocLinkPlain, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 825 return visitNode(cbNode, node.name); 826 } 827 828 function forEachChildInJSDocTag<T>(node: JSDocUnknownTag | JSDocClassTag | JSDocPublicTag | JSDocPrivateTag | JSDocProtectedTag | JSDocReadonlyTag | JSDocDeprecatedTag | JSDocOverrideTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 829 return visitNode(cbNode, node.tagName) 830 || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); 831 } 832 833 function forEachChildInPartiallyEmittedExpression<T>(node: PartiallyEmittedExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 834 return visitNode(cbNode, node.expression); 835 } 836 837 /** 838 * Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes 839 * stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; otherwise, 840 * embedded arrays are flattened and the 'cbNode' callback is invoked for each element. If a callback returns 841 * a truthy value, iteration stops and that value is returned. Otherwise, undefined is returned. 842 * 843 * @param node a given node to visit its children 844 * @param cbNode a callback to be invoked for all child nodes 845 * @param cbNodes a callback to be invoked for embedded array 846 * 847 * @remarks `forEachChild` must visit the children of a node in the order 848 * that they appear in the source code. The language service depends on this property to locate nodes by position. 849 */ 850 export function forEachChild<T>(node: Node, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 851 if (node === undefined || node.kind <= SyntaxKind.LastToken) { 852 return; 853 } 854 const fn = (forEachChildTable as Record<SyntaxKind, ForEachChildFunction<any>>)[node.kind]; 855 return fn === undefined ? undefined : fn(node, cbNode, cbNodes); 856 } 857 858 /** @internal */ 859 /** 860 * Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes 861 * stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; additionally, 862 * unlike `forEachChild`, embedded arrays are flattened and the 'cbNode' callback is invoked for each element. 863 * If a callback returns a truthy value, iteration stops and that value is returned. Otherwise, undefined is returned. 864 * 865 * @param node a given node to visit its children 866 * @param cbNode a callback to be invoked for all child nodes 867 * @param cbNodes a callback to be invoked for embedded array 868 * 869 * @remarks Unlike `forEachChild`, `forEachChildRecursively` handles recursively invoking the traversal on each child node found, 870 * and while doing so, handles traversing the structure without relying on the callstack to encode the tree structure. 871 */ 872 export function forEachChildRecursively<T>(rootNode: Node, cbNode: (node: Node, parent: Node) => T | "skip" | undefined, cbNodes?: (nodes: NodeArray<Node>, parent: Node) => T | "skip" | undefined): T | undefined { 873 const queue: (Node | NodeArray<Node>)[] = gatherPossibleChildren(rootNode); 874 const parents: Node[] = []; // tracks parent references for elements in queue 875 while (parents.length < queue.length) { 876 parents.push(rootNode); 877 } 878 while (queue.length !== 0) { 879 const current = queue.pop()!; 880 const parent = parents.pop()!; 881 if (isArray(current)) { 882 if (cbNodes) { 883 const res = cbNodes(current, parent); 884 if (res) { 885 if (res === "skip") continue; 886 return res; 887 } 888 } 889 for (let i = current.length - 1; i >= 0; --i) { 890 queue.push(current[i]); 891 parents.push(parent); 892 } 893 } 894 else { 895 const res = cbNode(current, parent); 896 if (res) { 897 if (res === "skip") continue; 898 return res; 899 } 900 if (current.kind >= SyntaxKind.FirstNode) { 901 // add children in reverse order to the queue, so popping gives the first child 902 for (const child of gatherPossibleChildren(current)) { 903 queue.push(child); 904 parents.push(current); 905 } 906 } 907 } 908 } 909 } 910 911 function gatherPossibleChildren(node: Node) { 912 const children: (Node | NodeArray<Node>)[] = []; 913 forEachChild(node, addWorkItem, addWorkItem); // By using a stack above and `unshift` here, we emulate a depth-first preorder traversal 914 return children; 915 916 function addWorkItem(n: Node | NodeArray<Node>) { 917 children.unshift(n); 918 } 919 } 920 921 export interface CreateSourceFileOptions { 922 languageVersion: ScriptTarget; 923 /** 924 * Controls the format the file is detected as - this can be derived from only the path 925 * and files on disk, but needs to be done with a module resolution cache in scope to be performant. 926 * This is usually `undefined` for compilations that do not have `moduleResolution` values of `node16` or `nodenext`. 927 */ 928 impliedNodeFormat?: ModuleKind.ESNext | ModuleKind.CommonJS; 929 /** 930 * Controls how module-y-ness is set for the given file. Usually the result of calling 931 * `getSetExternalModuleIndicator` on a valid `CompilerOptions` object. If not present, the default 932 * check specified by `isFileProbablyExternalModule` will be used to set the field. 933 */ 934 setExternalModuleIndicator?: (file: SourceFile) => void; 935 /*@internal*/ packageJsonLocations?: readonly string[]; 936 /*@internal*/ packageJsonScope?: PackageJsonInfo; 937 } 938 939 function setExternalModuleIndicator(sourceFile: SourceFile) { 940 sourceFile.externalModuleIndicator = isFileProbablyExternalModule(sourceFile); 941 } 942 943 let sourceFileCompilerOptions: CompilerOptions; 944 export function createSourceFile(fileName: string, sourceText: string, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, setParentNodes = false, scriptKind?: ScriptKind, options?: CompilerOptions): SourceFile { 945 tracing?.push(tracing.Phase.Parse, "createSourceFile", { path: fileName }, /*separateBeginAndEnd*/ true); 946 performance.mark("beforeParse"); 947 let result: SourceFile; 948 sourceFileCompilerOptions = options ?? defaultInitCompilerOptions; 949 perfLogger.logStartParseSourceFile(fileName); 950 const { 951 languageVersion, 952 setExternalModuleIndicator: overrideSetExternalModuleIndicator, 953 impliedNodeFormat: format 954 } = typeof languageVersionOrOptions === "object" ? languageVersionOrOptions : ({ languageVersion: languageVersionOrOptions } as CreateSourceFileOptions); 955 if (languageVersion === ScriptTarget.JSON) { 956 result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, ScriptKind.JSON, noop); 957 } 958 else { 959 const setIndicator = format === undefined ? overrideSetExternalModuleIndicator : (file: SourceFile) => { 960 file.impliedNodeFormat = format; 961 return (overrideSetExternalModuleIndicator || setExternalModuleIndicator)(file); 962 }; 963 result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, scriptKind, setIndicator); 964 } 965 perfLogger.logStopParseSourceFile(); 966 967 performance.mark("afterParse"); 968 performance.measure("Parse", "beforeParse", "afterParse"); 969 tracing?.pop(); 970 return result; 971 } 972 973 export function parseIsolatedEntityName(text: string, languageVersion: ScriptTarget): EntityName | undefined { 974 return Parser.parseIsolatedEntityName(text, languageVersion); 975 } 976 977 /** 978 * Parse json text into SyntaxTree and return node and parse errors if any 979 * @param fileName 980 * @param sourceText 981 */ 982 export function parseJsonText(fileName: string, sourceText: string): JsonSourceFile { 983 return Parser.parseJsonText(fileName, sourceText); 984 } 985 986 // See also `isExternalOrCommonJsModule` in utilities.ts 987 export function isExternalModule(file: SourceFile): boolean { 988 return file.externalModuleIndicator !== undefined; 989 } 990 991 // Produces a new SourceFile for the 'newText' provided. The 'textChangeRange' parameter 992 // indicates what changed between the 'text' that this SourceFile has and the 'newText'. 993 // The SourceFile will be created with the compiler attempting to reuse as many nodes from 994 // this file as possible. 995 // 996 // Note: this function mutates nodes from this SourceFile. That means any existing nodes 997 // from this SourceFile that are being held onto may change as a result (including 998 // becoming detached from any SourceFile). It is recommended that this SourceFile not 999 // be used once 'update' is called on it. 1000 export function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks = false, option?: CompilerOptions): SourceFile { 1001 sourceFileCompilerOptions = option ?? defaultInitCompilerOptions; 1002 const newSourceFile = IncrementalParser.updateSourceFile(sourceFile, newText, textChangeRange, aggressiveChecks); 1003 // 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. 1004 // We will manually port the flag to the new source file. 1005 (newSourceFile as Mutable<SourceFile>).flags |= (sourceFile.flags & NodeFlags.PermanentlySetIncrementalFlags); 1006 return newSourceFile; 1007 } 1008 1009 /* @internal */ 1010 export function parseIsolatedJSDocComment(content: string, start?: number, length?: number) { 1011 const result = Parser.JSDocParser.parseIsolatedJSDocComment(content, start, length); 1012 if (result && result.jsDoc) { 1013 // because the jsDocComment was parsed out of the source file, it might 1014 // not be covered by the fixupParentReferences. 1015 Parser.fixupParentReferences(result.jsDoc); 1016 } 1017 1018 return result; 1019 } 1020 1021 /* @internal */ 1022 // Exposed only for testing. 1023 export function parseJSDocTypeExpressionForTests(content: string, start?: number, length?: number) { 1024 return Parser.JSDocParser.parseJSDocTypeExpressionForTests(content, start, length); 1025 } 1026 1027 // Implement the parser as a singleton module. We do this for perf reasons because creating 1028 // parser instances can actually be expensive enough to impact us on projects with many source 1029 // files. 1030 namespace Parser { 1031 // Share a single scanner across all calls to parse a source file. This helps speed things 1032 // up by avoiding the cost of creating/compiling scanners over and over again. 1033 const scanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ true); 1034 1035 const disallowInAndDecoratorContext = NodeFlags.DisallowInContext | NodeFlags.DecoratorContext; 1036 1037 // capture constructors in 'initializeState' to avoid null checks 1038 let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; 1039 let TokenConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; 1040 let IdentifierConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; 1041 let PrivateIdentifierConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; 1042 let SourceFileConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; 1043 1044 function countNode(node: Node) { 1045 nodeCount++; 1046 return node; 1047 } 1048 1049 // Rather than using `createBaseNodeFactory` here, we establish a `BaseNodeFactory` that closes over the 1050 // constructors above, which are reset each time `initializeState` is called. 1051 const baseNodeFactory: BaseNodeFactory = { 1052 createBaseSourceFileNode: kind => countNode(new SourceFileConstructor(kind, /*pos*/ 0, /*end*/ 0)), 1053 createBaseIdentifierNode: kind => countNode(new IdentifierConstructor(kind, /*pos*/ 0, /*end*/ 0)), 1054 createBasePrivateIdentifierNode: kind => countNode(new PrivateIdentifierConstructor(kind, /*pos*/ 0, /*end*/ 0)), 1055 createBaseTokenNode: kind => countNode(new TokenConstructor(kind, /*pos*/ 0, /*end*/ 0)), 1056 createBaseNode: kind => countNode(new NodeConstructor(kind, /*pos*/ 0, /*end*/ 0)) 1057 }; 1058 1059 const factory = createNodeFactory(NodeFactoryFlags.NoParenthesizerRules | NodeFactoryFlags.NoNodeConverters | NodeFactoryFlags.NoOriginalNode, baseNodeFactory); 1060 1061 let fileName: string; 1062 let sourceFlags: NodeFlags; 1063 let sourceText: string; 1064 let languageVersion: ScriptTarget; 1065 let scriptKind: ScriptKind; 1066 let languageVariant: LanguageVariant; 1067 let parseDiagnostics: DiagnosticWithDetachedLocation[]; 1068 let jsDocDiagnostics: DiagnosticWithDetachedLocation[]; 1069 let syntaxCursor: IncrementalParser.SyntaxCursor | undefined; 1070 1071 let currentToken: SyntaxKind; 1072 let nodeCount: number; 1073 let identifiers: ESMap<string, string>; 1074 let privateIdentifiers: ESMap<string, string>; 1075 let identifierCount: number; 1076 1077 let parsingContext: ParsingContext; 1078 1079 let notParenthesizedArrow: Set<number> | undefined; 1080 1081 // Flags that dictate what parsing context we're in. For example: 1082 // Whether or not we are in strict parsing mode. All that changes in strict parsing mode is 1083 // that some tokens that would be considered identifiers may be considered keywords. 1084 // 1085 // When adding more parser context flags, consider which is the more common case that the 1086 // flag will be in. This should be the 'false' state for that flag. The reason for this is 1087 // that we don't store data in our nodes unless the value is in the *non-default* state. So, 1088 // for example, more often than code 'allows-in' (or doesn't 'disallow-in'). We opt for 1089 // 'disallow-in' set to 'false'. Otherwise, if we had 'allowsIn' set to 'true', then almost 1090 // all nodes would need extra state on them to store this info. 1091 // 1092 // Note: 'allowIn' and 'allowYield' track 1:1 with the [in] and [yield] concepts in the ES6 1093 // grammar specification. 1094 // 1095 // An important thing about these context concepts. By default they are effectively inherited 1096 // while parsing through every grammar production. i.e. if you don't change them, then when 1097 // you parse a sub-production, it will have the same context values as the parent production. 1098 // This is great most of the time. After all, consider all the 'expression' grammar productions 1099 // and how nearly all of them pass along the 'in' and 'yield' context values: 1100 // 1101 // EqualityExpression[In, Yield] : 1102 // RelationalExpression[?In, ?Yield] 1103 // EqualityExpression[?In, ?Yield] == RelationalExpression[?In, ?Yield] 1104 // EqualityExpression[?In, ?Yield] != RelationalExpression[?In, ?Yield] 1105 // EqualityExpression[?In, ?Yield] === RelationalExpression[?In, ?Yield] 1106 // EqualityExpression[?In, ?Yield] !== RelationalExpression[?In, ?Yield] 1107 // 1108 // Where you have to be careful is then understanding what the points are in the grammar 1109 // where the values are *not* passed along. For example: 1110 // 1111 // SingleNameBinding[Yield,GeneratorParameter] 1112 // [+GeneratorParameter]BindingIdentifier[Yield] Initializer[In]opt 1113 // [~GeneratorParameter]BindingIdentifier[?Yield]Initializer[In, ?Yield]opt 1114 // 1115 // Here this is saying that if the GeneratorParameter context flag is set, that we should 1116 // explicitly set the 'yield' context flag to false before calling into the BindingIdentifier 1117 // and we should explicitly unset the 'yield' context flag before calling into the Initializer. 1118 // production. Conversely, if the GeneratorParameter context flag is not set, then we 1119 // should leave the 'yield' context flag alone. 1120 // 1121 // Getting this all correct is tricky and requires careful reading of the grammar to 1122 // understand when these values should be changed versus when they should be inherited. 1123 // 1124 // Note: it should not be necessary to save/restore these flags during speculative/lookahead 1125 // parsing. These context flags are naturally stored and restored through normal recursive 1126 // descent parsing and unwinding. 1127 let contextFlags: NodeFlags; 1128 1129 let etsFlags: EtsFlags; 1130 1131 // Indicates whether we are currently parsing top-level statements. 1132 let topLevel = true; 1133 1134 // Whether or not we've had a parse error since creating the last AST node. If we have 1135 // encountered an error, it will be stored on the next AST node we create. Parse errors 1136 // can be broken down into three categories: 1137 // 1138 // 1) An error that occurred during scanning. For example, an unterminated literal, or a 1139 // character that was completely not understood. 1140 // 1141 // 2) A token was expected, but was not present. This type of error is commonly produced 1142 // by the 'parseExpected' function. 1143 // 1144 // 3) A token was present that no parsing function was able to consume. This type of error 1145 // only occurs in the 'abortParsingListOrMoveToNextToken' function when the parser 1146 // decides to skip the token. 1147 // 1148 // In all of these cases, we want to mark the next node as having had an error before it. 1149 // With this mark, we can know in incremental settings if this node can be reused, or if 1150 // we have to reparse it. If we don't keep this information around, we may just reuse the 1151 // node. in that event we would then not produce the same errors as we did before, causing 1152 // significant confusion problems. 1153 // 1154 // Note: it is necessary that this value be saved/restored during speculative/lookahead 1155 // parsing. During lookahead parsing, we will often create a node. That node will have 1156 // this value attached, and then this value will be set back to 'false'. If we decide to 1157 // rewind, we must get back to the same value we had prior to the lookahead. 1158 // 1159 // Note: any errors at the end of the file that do not precede a regular node, should get 1160 // attached to the EOF token. 1161 let parseErrorBeforeNextFinishedNode = false; 1162 1163 let extendEtsComponentDeclaration: { name: string, type: string, instance: string } | undefined; 1164 1165 let stylesEtsComponentDeclaration: { name: string, type: string, instance: string } | undefined; 1166 1167 // A map to record file scope '@styles' function name 1168 const fileStylesComponents = new Map<string, SyntaxKind>(); 1169 1170 let currentStructName: string | undefined; 1171 1172 let stateStylesRootNode: string | undefined; 1173 1174 // A map to record struct scope '@styles' method name 1175 const structStylesComponents = new Map<string, { structName: string, kind: SyntaxKind }>(); 1176 1177 export function parseSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, syntaxCursor: IncrementalParser.SyntaxCursor | undefined, setParentNodes = false, scriptKind?: ScriptKind, setExternalModuleIndicatorOverride?: (file: SourceFile) => void): SourceFile { 1178 scriptKind = ensureScriptKind(fileName, scriptKind); 1179 if (scriptKind === ScriptKind.JSON) { 1180 const result = parseJsonText(fileName, sourceText, languageVersion, syntaxCursor, setParentNodes); 1181 convertToObjectWorker(result, result.statements[0]?.expression, result.parseDiagnostics, /*returnValue*/ false, /*knownRootOptions*/ undefined, /*jsonConversionNotifier*/ undefined); 1182 result.referencedFiles = emptyArray; 1183 result.typeReferenceDirectives = emptyArray; 1184 result.libReferenceDirectives = emptyArray; 1185 result.amdDependencies = emptyArray; 1186 result.hasNoDefaultLib = false; 1187 result.pragmas = emptyMap as ReadonlyPragmaMap; 1188 return result; 1189 } 1190 1191 initializeState(fileName, sourceText, languageVersion, syntaxCursor, scriptKind); 1192 1193 const result = parseSourceFileWorker(languageVersion, setParentNodes, scriptKind, setExternalModuleIndicatorOverride || setExternalModuleIndicator); 1194 1195 clearState(); 1196 1197 return result; 1198 } 1199 1200 export function parseIsolatedEntityName(content: string, languageVersion: ScriptTarget): EntityName | undefined { 1201 // Choice of `isDeclarationFile` should be arbitrary 1202 initializeState("", content, languageVersion, /*syntaxCursor*/ undefined, ScriptKind.JS); 1203 // Prime the scanner. 1204 nextToken(); 1205 const entityName = parseEntityName(/*allowReservedWords*/ true); 1206 const isInvalid = token() === SyntaxKind.EndOfFileToken && !parseDiagnostics.length; 1207 clearState(); 1208 return isInvalid ? entityName : undefined; 1209 } 1210 1211 export function parseJsonText(fileName: string, sourceText: string, languageVersion: ScriptTarget = ScriptTarget.ES2015, syntaxCursor?: IncrementalParser.SyntaxCursor, setParentNodes = false): JsonSourceFile { 1212 initializeState(fileName, sourceText, languageVersion, syntaxCursor, ScriptKind.JSON); 1213 sourceFlags = contextFlags; 1214 1215 // Prime the scanner. 1216 nextToken(); 1217 const pos = getNodePos(); 1218 let statements, endOfFileToken; 1219 if (token() === SyntaxKind.EndOfFileToken) { 1220 statements = createNodeArray([], pos, pos); 1221 endOfFileToken = parseTokenNode<EndOfFileToken>(); 1222 } 1223 else { 1224 // Loop and synthesize an ArrayLiteralExpression if there are more than 1225 // one top-level expressions to ensure all input text is consumed. 1226 let expressions: Expression[] | Expression | undefined; 1227 while (token() !== SyntaxKind.EndOfFileToken) { 1228 let expression; 1229 switch (token()) { 1230 case SyntaxKind.OpenBracketToken: 1231 expression = parseArrayLiteralExpression(); 1232 break; 1233 case SyntaxKind.TrueKeyword: 1234 case SyntaxKind.FalseKeyword: 1235 case SyntaxKind.NullKeyword: 1236 expression = parseTokenNode<BooleanLiteral | NullLiteral>(); 1237 break; 1238 case SyntaxKind.MinusToken: 1239 if (lookAhead(() => nextToken() === SyntaxKind.NumericLiteral && nextToken() !== SyntaxKind.ColonToken)) { 1240 expression = parsePrefixUnaryExpression() as JsonMinusNumericLiteral; 1241 } 1242 else { 1243 expression = parseObjectLiteralExpression(); 1244 } 1245 break; 1246 case SyntaxKind.NumericLiteral: 1247 case SyntaxKind.StringLiteral: 1248 if (lookAhead(() => nextToken() !== SyntaxKind.ColonToken)) { 1249 expression = parseLiteralNode() as StringLiteral | NumericLiteral; 1250 break; 1251 } 1252 // falls through 1253 default: 1254 expression = parseObjectLiteralExpression(); 1255 break; 1256 } 1257 1258 // Error recovery: collect multiple top-level expressions 1259 if (expressions && isArray(expressions)) { 1260 expressions.push(expression); 1261 } 1262 else if (expressions) { 1263 expressions = [expressions, expression]; 1264 } 1265 else { 1266 expressions = expression; 1267 if (token() !== SyntaxKind.EndOfFileToken) { 1268 parseErrorAtCurrentToken(Diagnostics.Unexpected_token); 1269 } 1270 } 1271 } 1272 1273 const expression = isArray(expressions) ? finishNode(factory.createArrayLiteralExpression(expressions), pos) : Debug.checkDefined(expressions); 1274 const statement = factory.createExpressionStatement(expression) as JsonObjectExpressionStatement; 1275 finishNode(statement, pos); 1276 statements = createNodeArray([statement], pos); 1277 endOfFileToken = parseExpectedToken(SyntaxKind.EndOfFileToken, Diagnostics.Unexpected_token); 1278 } 1279 1280 // Set source file so that errors will be reported with this file name 1281 const sourceFile = createSourceFile(fileName, ScriptTarget.ES2015, ScriptKind.JSON, /*isDeclaration*/ false, statements, endOfFileToken, sourceFlags, noop); 1282 1283 if (setParentNodes) { 1284 fixupParentReferences(sourceFile); 1285 } 1286 1287 sourceFile.nodeCount = nodeCount; 1288 sourceFile.identifierCount = identifierCount; 1289 sourceFile.identifiers = identifiers; 1290 sourceFile.parseDiagnostics = attachFileToDiagnostics(parseDiagnostics, sourceFile); 1291 if (jsDocDiagnostics) { 1292 sourceFile.jsDocDiagnostics = attachFileToDiagnostics(jsDocDiagnostics, sourceFile); 1293 } 1294 1295 const result = sourceFile as JsonSourceFile; 1296 clearState(); 1297 return result; 1298 } 1299 1300 function initializeState(_fileName: string, _sourceText: string, _languageVersion: ScriptTarget, _syntaxCursor: IncrementalParser.SyntaxCursor | undefined, _scriptKind: ScriptKind) { 1301 NodeConstructor = objectAllocator.getNodeConstructor(); 1302 TokenConstructor = objectAllocator.getTokenConstructor(); 1303 IdentifierConstructor = objectAllocator.getIdentifierConstructor(); 1304 PrivateIdentifierConstructor = objectAllocator.getPrivateIdentifierConstructor(); 1305 SourceFileConstructor = objectAllocator.getSourceFileConstructor(); 1306 1307 fileName = normalizePath(_fileName); 1308 sourceText = _sourceText; 1309 languageVersion = _languageVersion; 1310 syntaxCursor = _syntaxCursor; 1311 scriptKind = _scriptKind; 1312 languageVariant = getLanguageVariant(_scriptKind); 1313 1314 parseDiagnostics = []; 1315 parsingContext = 0; 1316 identifiers = new Map<string, string>(); 1317 privateIdentifiers = new Map<string, string>(); 1318 identifierCount = 0; 1319 nodeCount = 0; 1320 sourceFlags = 0; 1321 topLevel = true; 1322 1323 switch (scriptKind) { 1324 case ScriptKind.JS: 1325 case ScriptKind.JSX: 1326 contextFlags = NodeFlags.JavaScriptFile; 1327 break; 1328 case ScriptKind.JSON: 1329 contextFlags = NodeFlags.JavaScriptFile | NodeFlags.JsonFile; 1330 break; 1331 case ScriptKind.ETS: 1332 contextFlags = NodeFlags.EtsContext; 1333 break; 1334 default: 1335 contextFlags = NodeFlags.None; 1336 break; 1337 } 1338 if (fileName.endsWith(Extension.Ets)) { 1339 contextFlags = NodeFlags.EtsContext; 1340 } 1341 parseErrorBeforeNextFinishedNode = false; 1342 1343 // Initialize and prime the scanner before parsing the source elements. 1344 scanner.setText(sourceText); 1345 scanner.setOnError(scanError); 1346 scanner.setScriptTarget(languageVersion); 1347 scanner.setLanguageVariant(languageVariant); 1348 scanner.setEtsContext(inEtsContext()); 1349 } 1350 1351 function clearState() { 1352 // Clear out the text the scanner is pointing at, so it doesn't keep anything alive unnecessarily. 1353 scanner.clearCommentDirectives(); 1354 scanner.setText(""); 1355 scanner.setOnError(undefined); 1356 scanner.setEtsContext(false); 1357 // Clear any data. We don't want to accidentally hold onto it for too long. 1358 sourceText = undefined!; 1359 languageVersion = undefined!; 1360 syntaxCursor = undefined; 1361 scriptKind = undefined!; 1362 languageVariant = undefined!; 1363 sourceFlags = 0; 1364 parseDiagnostics = undefined!; 1365 jsDocDiagnostics = undefined!; 1366 parsingContext = 0; 1367 identifiers = undefined!; 1368 notParenthesizedArrow = undefined; 1369 topLevel = true; 1370 extendEtsComponentDeclaration = undefined; 1371 stylesEtsComponentDeclaration = undefined; 1372 stateStylesRootNode = undefined; 1373 fileStylesComponents.clear(); 1374 structStylesComponents.clear(); 1375 } 1376 1377 function parseSourceFileWorker(languageVersion: ScriptTarget, setParentNodes: boolean, scriptKind: ScriptKind, setExternalModuleIndicator: (file: SourceFile) => void): SourceFile { 1378 const isDeclarationFile = isDeclarationFileName(fileName); 1379 if (isDeclarationFile) { 1380 contextFlags |= NodeFlags.Ambient; 1381 } 1382 1383 sourceFlags = contextFlags; 1384 1385 // Prime the scanner. 1386 nextToken(); 1387 1388 const statements = parseList(ParsingContext.SourceElements, parseStatement); 1389 Debug.assert(token() === SyntaxKind.EndOfFileToken); 1390 const endOfFileToken = addJSDocComment(parseTokenNode<EndOfFileToken>()); 1391 1392 const sourceFile = createSourceFile(fileName, languageVersion, scriptKind, isDeclarationFile, statements, endOfFileToken, sourceFlags, setExternalModuleIndicator); 1393 1394 // 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 1395 processCommentPragmas(sourceFile as {} as PragmaContext, sourceText); 1396 processPragmasIntoFields(sourceFile as {} as PragmaContext, reportPragmaDiagnostic); 1397 1398 sourceFile.commentDirectives = scanner.getCommentDirectives(); 1399 sourceFile.nodeCount = nodeCount; 1400 sourceFile.identifierCount = identifierCount; 1401 sourceFile.identifiers = identifiers; 1402 sourceFile.parseDiagnostics = attachFileToDiagnostics(parseDiagnostics, sourceFile); 1403 if (jsDocDiagnostics) { 1404 sourceFile.jsDocDiagnostics = attachFileToDiagnostics(jsDocDiagnostics, sourceFile); 1405 } 1406 1407 if (setParentNodes) { 1408 fixupParentReferences(sourceFile); 1409 } 1410 1411 return sourceFile; 1412 1413 function reportPragmaDiagnostic(pos: number, end: number, diagnostic: DiagnosticMessage) { 1414 parseDiagnostics.push(createDetachedDiagnostic(fileName, pos, end, diagnostic)); 1415 } 1416 } 1417 1418 function withJSDoc<T extends HasJSDoc>(node: T, hasJSDoc: boolean): T { 1419 return hasJSDoc ? addJSDocComment(node) : node; 1420 } 1421 1422 let hasDeprecatedTag = false; 1423 function addJSDocComment<T extends HasJSDoc>(node: T): T { 1424 Debug.assert(!node.jsDoc); // Should only be called once per node 1425 const jsDoc = mapDefined(getJSDocCommentRanges(node, sourceText), comment => JSDocParser.parseJSDocComment(node, comment.pos, comment.end - comment.pos)); 1426 if (jsDoc.length) node.jsDoc = jsDoc; 1427 if (hasDeprecatedTag) { 1428 hasDeprecatedTag = false; 1429 (node as Mutable<T>).flags |= NodeFlags.Deprecated; 1430 } 1431 return node; 1432 } 1433 1434 function reparseTopLevelAwait(sourceFile: SourceFile) { 1435 const savedSyntaxCursor = syntaxCursor; 1436 const baseSyntaxCursor = IncrementalParser.createSyntaxCursor(sourceFile); 1437 syntaxCursor = { currentNode }; 1438 1439 const statements: Statement[] = []; 1440 const savedParseDiagnostics = parseDiagnostics; 1441 1442 parseDiagnostics = []; 1443 1444 let pos = 0; 1445 let start = findNextStatementWithAwait(sourceFile.statements, 0); 1446 while (start !== -1) { 1447 // append all statements between pos and start 1448 const prevStatement = sourceFile.statements[pos]; 1449 const nextStatement = sourceFile.statements[start]; 1450 addRange(statements, sourceFile.statements, pos, start); 1451 pos = findNextStatementWithoutAwait(sourceFile.statements, start); 1452 1453 // append all diagnostics associated with the copied range 1454 const diagnosticStart = findIndex(savedParseDiagnostics, diagnostic => diagnostic.start >= prevStatement.pos); 1455 const diagnosticEnd = diagnosticStart >= 0 ? findIndex(savedParseDiagnostics, diagnostic => diagnostic.start >= nextStatement.pos, diagnosticStart) : -1; 1456 if (diagnosticStart >= 0) { 1457 addRange(parseDiagnostics, savedParseDiagnostics, diagnosticStart, diagnosticEnd >= 0 ? diagnosticEnd : undefined); 1458 } 1459 1460 // reparse all statements between start and pos. We skip existing diagnostics for the same range and allow the parser to generate new ones. 1461 speculationHelper(() => { 1462 const savedContextFlags = contextFlags; 1463 contextFlags |= NodeFlags.AwaitContext; 1464 scanner.setTextPos(nextStatement.pos); 1465 nextToken(); 1466 1467 while (token() !== SyntaxKind.EndOfFileToken) { 1468 const startPos = scanner.getStartPos(); 1469 const statement = parseListElement(ParsingContext.SourceElements, parseStatement); 1470 statements.push(statement); 1471 if (startPos === scanner.getStartPos()) { 1472 nextToken(); 1473 } 1474 1475 if (pos >= 0) { 1476 const nonAwaitStatement = sourceFile.statements[pos]; 1477 if (statement.end === nonAwaitStatement.pos) { 1478 // done reparsing this section 1479 break; 1480 } 1481 if (statement.end > nonAwaitStatement.pos) { 1482 // we ate into the next statement, so we must reparse it. 1483 pos = findNextStatementWithoutAwait(sourceFile.statements, pos + 1); 1484 } 1485 } 1486 } 1487 1488 contextFlags = savedContextFlags; 1489 }, SpeculationKind.Reparse); 1490 1491 // find the next statement containing an `await` 1492 start = pos >= 0 ? findNextStatementWithAwait(sourceFile.statements, pos) : -1; 1493 } 1494 1495 // append all statements between pos and the end of the list 1496 if (pos >= 0) { 1497 const prevStatement = sourceFile.statements[pos]; 1498 addRange(statements, sourceFile.statements, pos); 1499 1500 // append all diagnostics associated with the copied range 1501 const diagnosticStart = findIndex(savedParseDiagnostics, diagnostic => diagnostic.start >= prevStatement.pos); 1502 if (diagnosticStart >= 0) { 1503 addRange(parseDiagnostics, savedParseDiagnostics, diagnosticStart); 1504 } 1505 } 1506 1507 syntaxCursor = savedSyntaxCursor; 1508 return factory.updateSourceFile(sourceFile, setTextRange(factory.createNodeArray(statements), sourceFile.statements)); 1509 1510 function containsPossibleTopLevelAwait(node: Node) { 1511 return !(node.flags & NodeFlags.AwaitContext) 1512 && !!(node.transformFlags & TransformFlags.ContainsPossibleTopLevelAwait); 1513 } 1514 1515 function findNextStatementWithAwait(statements: NodeArray<Statement>, start: number) { 1516 for (let i = start; i < statements.length; i++) { 1517 if (containsPossibleTopLevelAwait(statements[i])) { 1518 return i; 1519 } 1520 } 1521 return -1; 1522 } 1523 1524 function findNextStatementWithoutAwait(statements: NodeArray<Statement>, start: number) { 1525 for (let i = start; i < statements.length; i++) { 1526 if (!containsPossibleTopLevelAwait(statements[i])) { 1527 return i; 1528 } 1529 } 1530 return -1; 1531 } 1532 1533 function currentNode(position: number) { 1534 const node = baseSyntaxCursor.currentNode(position); 1535 if (topLevel && node && containsPossibleTopLevelAwait(node)) { 1536 node.intersectsChange = true; 1537 } 1538 return node; 1539 } 1540 1541 } 1542 1543 export function fixupParentReferences(rootNode: Node) { 1544 // normally parent references are set during binding. However, for clients that only need 1545 // a syntax tree, and no semantic features, then the binding process is an unnecessary 1546 // overhead. This functions allows us to set all the parents, without all the expense of 1547 // binding. 1548 setParentRecursive(rootNode, /*incremental*/ true); 1549 } 1550 1551 function createSourceFile( 1552 fileName: string, 1553 languageVersion: ScriptTarget, 1554 scriptKind: ScriptKind, 1555 isDeclarationFile: boolean, 1556 statements: readonly Statement[], 1557 endOfFileToken: EndOfFileToken, 1558 flags: NodeFlags, 1559 setExternalModuleIndicator: (sourceFile: SourceFile) => void): SourceFile { 1560 // code from createNode is inlined here so createNode won't have to deal with special case of creating source files 1561 // this is quite rare comparing to other nodes and createNode should be as fast as possible 1562 let sourceFile = factory.createSourceFile(statements, endOfFileToken, flags); 1563 setTextRangePosWidth(sourceFile, 0, sourceText.length); 1564 setFields(sourceFile); 1565 1566 // If we parsed this as an external module, it may contain top-level await 1567 if (!isDeclarationFile && isExternalModule(sourceFile) && sourceFile.transformFlags & TransformFlags.ContainsPossibleTopLevelAwait) { 1568 sourceFile = reparseTopLevelAwait(sourceFile); 1569 setFields(sourceFile); 1570 } 1571 1572 return sourceFile; 1573 1574 function setFields(sourceFile: SourceFile) { 1575 sourceFile.text = sourceText; 1576 sourceFile.bindDiagnostics = []; 1577 sourceFile.bindSuggestionDiagnostics = undefined; 1578 sourceFile.languageVersion = languageVersion; 1579 sourceFile.fileName = fileName; 1580 sourceFile.languageVariant = getLanguageVariant(scriptKind); 1581 sourceFile.isDeclarationFile = isDeclarationFile; 1582 sourceFile.scriptKind = scriptKind; 1583 1584 setExternalModuleIndicator(sourceFile); 1585 sourceFile.setExternalModuleIndicator = setExternalModuleIndicator; 1586 } 1587 } 1588 1589 function setContextFlag(val: boolean, flag: NodeFlags) { 1590 if (val) { 1591 contextFlags |= flag; 1592 } 1593 else { 1594 contextFlags &= ~flag; 1595 } 1596 } 1597 1598 function setEtsFlag(val: boolean, flag: EtsFlags) { 1599 if (val) { 1600 etsFlags |= flag; 1601 } 1602 else { 1603 etsFlags &= ~flag; 1604 } 1605 } 1606 1607 function setDisallowInContext(val: boolean) { 1608 setContextFlag(val, NodeFlags.DisallowInContext); 1609 } 1610 1611 function setYieldContext(val: boolean) { 1612 setContextFlag(val, NodeFlags.YieldContext); 1613 } 1614 1615 function setDecoratorContext(val: boolean) { 1616 setContextFlag(val, NodeFlags.DecoratorContext); 1617 } 1618 1619 function setAwaitContext(val: boolean) { 1620 setContextFlag(val, NodeFlags.AwaitContext); 1621 } 1622 1623 function setStructContext(val: boolean) { 1624 setEtsFlag(val, EtsFlags.StructContext); 1625 } 1626 1627 function setEtsComponentsContext(val: boolean) { 1628 setEtsFlag(val, EtsFlags.EtsComponentsContext); 1629 } 1630 1631 function setEtsNewExpressionContext(val: boolean) { 1632 setEtsFlag(val, EtsFlags.EtsNewExpressionContext); 1633 } 1634 1635 function setEtsExtendComponentsContext(val: boolean) { 1636 setEtsFlag(val, EtsFlags.EtsExtendComponentsContext); 1637 } 1638 1639 function setEtsStylesComponentsContext(val: boolean) { 1640 setEtsFlag(val, EtsFlags.EtsStylesComponentsContext); 1641 } 1642 1643 function setEtsBuildContext(val: boolean) { 1644 setEtsFlag(val, EtsFlags.EtsBuildContext); 1645 } 1646 1647 function setEtsBuilderContext(val: boolean) { 1648 setEtsFlag(val, EtsFlags.EtsBuilderContext); 1649 } 1650 1651 function setEtsStateStylesContext(val: boolean) { 1652 setEtsFlag(val, EtsFlags.EtsStateStylesContext); 1653 } 1654 1655 function setUICallbackContext(val: boolean) { 1656 setEtsFlag(val, EtsFlags.UICallbackContext); 1657 } 1658 1659 function setSyntaxComponentContext(val: boolean) { 1660 setEtsFlag(val, EtsFlags.SyntaxComponentContext); 1661 } 1662 1663 function doOutsideOfContext<T>(context: NodeFlags, func: () => T): T { 1664 // contextFlagsToClear will contain only the context flags that are 1665 // currently set that we need to temporarily clear 1666 // We don't just blindly reset to the previous flags to ensure 1667 // that we do not mutate cached flags for the incremental 1668 // parser (ThisNodeHasError, ThisNodeOrAnySubNodesHasError, and 1669 // HasAggregatedChildData). 1670 const contextFlagsToClear = context & contextFlags; 1671 if (contextFlagsToClear) { 1672 // clear the requested context flags 1673 setContextFlag(/*val*/ false, contextFlagsToClear); 1674 const result = func(); 1675 // restore the context flags we just cleared 1676 setContextFlag(/*val*/ true, contextFlagsToClear); 1677 return result; 1678 } 1679 1680 // no need to do anything special as we are not in any of the requested contexts 1681 return func(); 1682 } 1683 1684 function doInsideOfContext<T>(context: NodeFlags, func: () => T): T { 1685 // contextFlagsToSet will contain only the context flags that 1686 // are not currently set that we need to temporarily enable. 1687 // We don't just blindly reset to the previous flags to ensure 1688 // that we do not mutate cached flags for the incremental 1689 // parser (ThisNodeHasError, ThisNodeOrAnySubNodesHasError, and 1690 // HasAggregatedChildData). 1691 const contextFlagsToSet = context & ~contextFlags; 1692 if (contextFlagsToSet) { 1693 // set the requested context flags 1694 setContextFlag(/*val*/ true, contextFlagsToSet); 1695 const result = func(); 1696 // reset the context flags we just set 1697 setContextFlag(/*val*/ false, contextFlagsToSet); 1698 return result; 1699 } 1700 1701 // no need to do anything special as we are already in all of the requested contexts 1702 return func(); 1703 } 1704 1705 function allowInAnd<T>(func: () => T): T { 1706 return doOutsideOfContext(NodeFlags.DisallowInContext, func); 1707 } 1708 1709 function disallowInAnd<T>(func: () => T): T { 1710 return doInsideOfContext(NodeFlags.DisallowInContext, func); 1711 } 1712 1713 function allowConditionalTypesAnd<T>(func: () => T): T { 1714 return doOutsideOfContext(NodeFlags.DisallowConditionalTypesContext, func); 1715 } 1716 1717 function disallowConditionalTypesAnd<T>(func: () => T): T { 1718 return doInsideOfContext(NodeFlags.DisallowConditionalTypesContext, func); 1719 } 1720 1721 function doInYieldContext<T>(func: () => T): T { 1722 return doInsideOfContext(NodeFlags.YieldContext, func); 1723 } 1724 1725 function doInDecoratorContext<T>(func: () => T): T { 1726 // setting Ets Extend Components 1727 const extendDecorator = sourceFileCompilerOptions.ets?.extend?.decorator ?? "Extend"; 1728 if (token() === SyntaxKind.Identifier && scanner.getTokenText() === extendDecorator) { 1729 setEtsFlag(true, EtsFlags.EtsExtendComponentsContext); 1730 } 1731 // setting Ets Styles Components 1732 const stylesDecorator = sourceFileCompilerOptions.ets?.styles?.decorator ?? "Styles"; 1733 if (token() === SyntaxKind.Identifier && scanner.getTokenText() === stylesDecorator) { 1734 setEtsFlag(true, EtsFlags.EtsStylesComponentsContext); 1735 } 1736 return doInsideOfContext(NodeFlags.DecoratorContext, func); 1737 } 1738 1739 function doInAwaitContext<T>(func: () => T): T { 1740 return doInsideOfContext(NodeFlags.AwaitContext, func); 1741 } 1742 1743 function doOutsideOfAwaitContext<T>(func: () => T): T { 1744 return doOutsideOfContext(NodeFlags.AwaitContext, func); 1745 } 1746 1747 function doInYieldAndAwaitContext<T>(func: () => T): T { 1748 return doInsideOfContext(NodeFlags.YieldContext | NodeFlags.AwaitContext, func); 1749 } 1750 1751 function doOutsideOfYieldAndAwaitContext<T>(func: () => T): T { 1752 return doOutsideOfContext(NodeFlags.YieldContext | NodeFlags.AwaitContext, func); 1753 } 1754 1755 function inContext(flags: NodeFlags) { 1756 return (contextFlags & flags) !== 0; 1757 } 1758 1759 function inEtsFlagsContext(flags: EtsFlags) { 1760 return (etsFlags & flags) !== 0; 1761 } 1762 1763 function inYieldContext() { 1764 return inContext(NodeFlags.YieldContext); 1765 } 1766 1767 function inDisallowInContext() { 1768 return inContext(NodeFlags.DisallowInContext); 1769 } 1770 1771 function inDisallowConditionalTypesContext() { 1772 return inContext(NodeFlags.DisallowConditionalTypesContext); 1773 } 1774 1775 function inDecoratorContext() { 1776 return inContext(NodeFlags.DecoratorContext); 1777 } 1778 1779 function inAwaitContext() { 1780 return inContext(NodeFlags.AwaitContext); 1781 } 1782 1783 function parseErrorAtCurrentToken(message: DiagnosticMessage, arg0?: any): DiagnosticWithDetachedLocation | undefined { 1784 return parseErrorAt(scanner.getTokenPos(), scanner.getTextPos(), message, arg0); 1785 } 1786 1787 function inEtsContext() { 1788 return inContext(NodeFlags.EtsContext); 1789 } 1790 1791 function inStructContext() { 1792 return inEtsContext() && inEtsFlagsContext(EtsFlags.StructContext); 1793 } 1794 1795 function inEtsComponentsContext() { 1796 return inEtsContext() && inEtsFlagsContext(EtsFlags.EtsComponentsContext); 1797 } 1798 1799 function inEtsNewExpressionContext() { 1800 return inEtsContext() && inEtsFlagsContext(EtsFlags.EtsNewExpressionContext); 1801 } 1802 1803 function inEtsExtendComponentsContext() { 1804 return inEtsContext() && inEtsFlagsContext(EtsFlags.EtsExtendComponentsContext); 1805 } 1806 1807 function inEtsStylesComponentsContext() { 1808 return inEtsContext() && inEtsFlagsContext(EtsFlags.EtsStylesComponentsContext); 1809 } 1810 1811 function inBuildContext() { 1812 return inEtsContext() && inStructContext() && inEtsFlagsContext(EtsFlags.EtsBuildContext); 1813 } 1814 1815 function inBuilderContext() { 1816 return inEtsContext() && inEtsFlagsContext(EtsFlags.EtsBuilderContext); 1817 } 1818 1819 function inEtsStateStylesContext() { 1820 return inEtsContext() && (inBuildContext() || inBuilderContext() || inEtsExtendComponentsContext() || inEtsStylesComponentsContext()) && inEtsFlagsContext(EtsFlags.EtsStateStylesContext); 1821 } 1822 1823 function inUICallbackContext() { 1824 return inEtsContext() && (inBuildContext() || inBuilderContext()) && inEtsFlagsContext(EtsFlags.UICallbackContext); 1825 } 1826 1827 function inSyntaxComponentContext() { 1828 return inEtsContext() && (inBuildContext() || inBuilderContext()) && inEtsFlagsContext(EtsFlags.SyntaxComponentContext); 1829 } 1830 1831 function parseErrorAtPosition(start: number, length: number, message: DiagnosticMessage, arg0?: any): DiagnosticWithDetachedLocation | undefined { 1832 // Don't report another error if it would just be at the same position as the last error. 1833 const lastError = lastOrUndefined(parseDiagnostics); 1834 let result: DiagnosticWithDetachedLocation | undefined; 1835 if (!lastError || start !== lastError.start) { 1836 result = createDetachedDiagnostic(fileName, start, length, message, arg0); 1837 parseDiagnostics.push(result); 1838 } 1839 1840 // Mark that we've encountered an error. We'll set an appropriate bit on the next 1841 // node we finish so that it can't be reused incrementally. 1842 parseErrorBeforeNextFinishedNode = true; 1843 return result; 1844 } 1845 1846 function parseErrorAt(start: number, end: number, message: DiagnosticMessage, arg0?: any): DiagnosticWithDetachedLocation | undefined { 1847 return parseErrorAtPosition(start, end - start, message, arg0); 1848 } 1849 1850 function parseErrorAtRange(range: TextRange, message: DiagnosticMessage, arg0?: any): void { 1851 parseErrorAt(range.pos, range.end, message, arg0); 1852 } 1853 1854 function scanError(message: DiagnosticMessage, length: number): void { 1855 parseErrorAtPosition(scanner.getTextPos(), length, message); 1856 } 1857 1858 function getNodePos(): number { 1859 return scanner.getStartPos(); 1860 } 1861 1862 function hasPrecedingJSDocComment() { 1863 return scanner.hasPrecedingJSDocComment(); 1864 } 1865 1866 // Use this function to access the current token instead of reading the currentToken 1867 // variable. Since function results aren't narrowed in control flow analysis, this ensures 1868 // that the type checker doesn't make wrong assumptions about the type of the current 1869 // token (e.g. a call to nextToken() changes the current token but the checker doesn't 1870 // reason about this side effect). Mainstream VMs inline simple functions like this, so 1871 // there is no performance penalty. 1872 function token(): SyntaxKind { 1873 return currentToken; 1874 } 1875 1876 function nextTokenWithoutCheck() { 1877 return currentToken = scanner.scan(); 1878 } 1879 1880 function nextTokenAnd<T>(func: () => T): T { 1881 nextToken(); 1882 return func(); 1883 } 1884 1885 function nextToken(): SyntaxKind { 1886 // if the keyword had an escape 1887 if (isKeyword(currentToken) && (scanner.hasUnicodeEscape() || scanner.hasExtendedUnicodeEscape())) { 1888 // issue a parse error for the escape 1889 parseErrorAt(scanner.getTokenPos(), scanner.getTextPos(), Diagnostics.Keywords_cannot_contain_escape_characters); 1890 } 1891 return nextTokenWithoutCheck(); 1892 } 1893 1894 function nextTokenJSDoc(): JSDocSyntaxKind { 1895 return currentToken = scanner.scanJsDocToken(); 1896 } 1897 1898 function reScanGreaterToken(): SyntaxKind { 1899 return currentToken = scanner.reScanGreaterToken(); 1900 } 1901 1902 function reScanSlashToken(): SyntaxKind { 1903 return currentToken = scanner.reScanSlashToken(); 1904 } 1905 1906 function reScanTemplateToken(isTaggedTemplate: boolean): SyntaxKind { 1907 return currentToken = scanner.reScanTemplateToken(isTaggedTemplate); 1908 } 1909 1910 function reScanTemplateHeadOrNoSubstitutionTemplate(): SyntaxKind { 1911 return currentToken = scanner.reScanTemplateHeadOrNoSubstitutionTemplate(); 1912 } 1913 1914 function reScanLessThanToken(): SyntaxKind { 1915 return currentToken = scanner.reScanLessThanToken(); 1916 } 1917 1918 function reScanHashToken(): SyntaxKind { 1919 return currentToken = scanner.reScanHashToken(); 1920 } 1921 1922 function scanJsxIdentifier(): SyntaxKind { 1923 return currentToken = scanner.scanJsxIdentifier(); 1924 } 1925 1926 function scanJsxText(): SyntaxKind { 1927 return currentToken = scanner.scanJsxToken(); 1928 } 1929 1930 function scanJsxAttributeValue(): SyntaxKind { 1931 return currentToken = scanner.scanJsxAttributeValue(); 1932 } 1933 1934 function speculationHelper<T>(callback: () => T, speculationKind: SpeculationKind): T { 1935 // Keep track of the state we'll need to rollback to if lookahead fails (or if the 1936 // caller asked us to always reset our state). 1937 const saveToken = currentToken; 1938 const saveParseDiagnosticsLength = parseDiagnostics.length; 1939 const saveParseErrorBeforeNextFinishedNode = parseErrorBeforeNextFinishedNode; 1940 1941 // Note: it is not actually necessary to save/restore the context flags here. That's 1942 // because the saving/restoring of these flags happens naturally through the recursive 1943 // descent nature of our parser. However, we still store this here just so we can 1944 // assert that invariant holds. 1945 const saveContextFlags = contextFlags; 1946 1947 // If we're only looking ahead, then tell the scanner to only lookahead as well. 1948 // Otherwise, if we're actually speculatively parsing, then tell the scanner to do the 1949 // same. 1950 const result = speculationKind !== SpeculationKind.TryParse 1951 ? scanner.lookAhead(callback) 1952 : scanner.tryScan(callback); 1953 1954 Debug.assert(saveContextFlags === contextFlags); 1955 1956 // If our callback returned something 'falsy' or we're just looking ahead, 1957 // then unconditionally restore us to where we were. 1958 if (!result || speculationKind !== SpeculationKind.TryParse) { 1959 currentToken = saveToken; 1960 if (speculationKind !== SpeculationKind.Reparse) { 1961 parseDiagnostics.length = saveParseDiagnosticsLength; 1962 } 1963 parseErrorBeforeNextFinishedNode = saveParseErrorBeforeNextFinishedNode; 1964 } 1965 1966 return result; 1967 } 1968 1969 /** Invokes the provided callback then unconditionally restores the parser to the state it 1970 * was in immediately prior to invoking the callback. The result of invoking the callback 1971 * is returned from this function. 1972 */ 1973 function lookAhead<T>(callback: () => T): T { 1974 return speculationHelper(callback, SpeculationKind.Lookahead); 1975 } 1976 1977 /** Invokes the provided callback. If the callback returns something falsy, then it restores 1978 * the parser to the state it was in immediately prior to invoking the callback. If the 1979 * callback returns something truthy, then the parser state is not rolled back. The result 1980 * of invoking the callback is returned from this function. 1981 */ 1982 function tryParse<T>(callback: () => T): T { 1983 return speculationHelper(callback, SpeculationKind.TryParse); 1984 } 1985 1986 function isBindingIdentifier(): boolean { 1987 if (token() === SyntaxKind.Identifier) { 1988 return true; 1989 } 1990 1991 // `let await`/`let yield` in [Yield] or [Await] are allowed here and disallowed in the binder. 1992 return token() > SyntaxKind.LastReservedWord; 1993 } 1994 1995 // Ignore strict mode flag because we will report an error in type checker instead. 1996 function isIdentifier(): boolean { 1997 if (token() === SyntaxKind.Identifier) { 1998 return true; 1999 } 2000 2001 // If we have a 'yield' keyword, and we're in the [yield] context, then 'yield' is 2002 // considered a keyword and is not an identifier. 2003 if (token() === SyntaxKind.YieldKeyword && inYieldContext()) { 2004 return false; 2005 } 2006 2007 // If we have a 'await' keyword, and we're in the [Await] context, then 'await' is 2008 // considered a keyword and is not an identifier. 2009 if (token() === SyntaxKind.AwaitKeyword && inAwaitContext()) { 2010 return false; 2011 } 2012 2013 return token() > SyntaxKind.LastReservedWord; 2014 } 2015 2016 function parseExpected(kind: SyntaxKind, diagnosticMessage?: DiagnosticMessage, shouldAdvance = true): boolean { 2017 if (token() === kind) { 2018 if (shouldAdvance) { 2019 nextToken(); 2020 } 2021 return true; 2022 } 2023 2024 if (token() !== kind && stateStylesRootNode && inEtsStateStylesContext()) { 2025 return true; 2026 } 2027 2028 // Report specific message if provided with one. Otherwise, report generic fallback message. 2029 if (diagnosticMessage) { 2030 parseErrorAtCurrentToken(diagnosticMessage); 2031 } 2032 else { 2033 parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(kind)); 2034 } 2035 return false; 2036 } 2037 2038 const viableKeywordSuggestions = Object.keys(textToKeywordObj).filter(keyword => keyword.length > 2); 2039 2040 /** 2041 * Provides a better error message than the generic "';' expected" if possible for 2042 * known common variants of a missing semicolon, such as from a mispelled names. 2043 * 2044 * @param node Node preceding the expected semicolon location. 2045 */ 2046 function parseErrorForMissingSemicolonAfter(node: Expression | PropertyName): void { 2047 // Tagged template literals are sometimes used in places where only simple strings are allowed, i.e.: 2048 // module `M1` { 2049 // ^^^^^^^^^^^ This block is parsed as a template literal like module`M1`. 2050 if (isTaggedTemplateExpression(node)) { 2051 parseErrorAt(skipTrivia(sourceText, node.template.pos), node.template.end, Diagnostics.Module_declaration_names_may_only_use_or_quoted_strings); 2052 return; 2053 } 2054 2055 // Otherwise, if this isn't a well-known keyword-like identifier, give the generic fallback message. 2056 const expressionText = ts.isIdentifier(node) ? idText(node) : undefined; 2057 if (!expressionText || !isIdentifierText(expressionText, languageVersion)) { 2058 parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.SemicolonToken)); 2059 return; 2060 } 2061 2062 const pos = skipTrivia(sourceText, node.pos); 2063 2064 // Some known keywords are likely signs of syntax being used improperly. 2065 switch (expressionText) { 2066 case "const": 2067 case "let": 2068 case "var": 2069 parseErrorAt(pos, node.end, Diagnostics.Variable_declaration_not_allowed_at_this_location); 2070 return; 2071 2072 case "declare": 2073 // If a declared node failed to parse, it would have emitted a diagnostic already. 2074 return; 2075 2076 case "interface": 2077 parseErrorForInvalidName(Diagnostics.Interface_name_cannot_be_0, Diagnostics.Interface_must_be_given_a_name, SyntaxKind.OpenBraceToken); 2078 return; 2079 2080 case "is": 2081 parseErrorAt(pos, scanner.getTextPos(), Diagnostics.A_type_predicate_is_only_allowed_in_return_type_position_for_functions_and_methods); 2082 return; 2083 2084 case "module": 2085 case "namespace": 2086 parseErrorForInvalidName(Diagnostics.Namespace_name_cannot_be_0, Diagnostics.Namespace_must_be_given_a_name, SyntaxKind.OpenBraceToken); 2087 return; 2088 2089 case "type": 2090 parseErrorForInvalidName(Diagnostics.Type_alias_name_cannot_be_0, Diagnostics.Type_alias_must_be_given_a_name, SyntaxKind.EqualsToken); 2091 return; 2092 } 2093 2094 // The user alternatively might have misspelled or forgotten to add a space after a common keyword. 2095 const suggestion = getSpellingSuggestion(expressionText, viableKeywordSuggestions, n => n) ?? getSpaceSuggestion(expressionText); 2096 if (suggestion) { 2097 parseErrorAt(pos, node.end, Diagnostics.Unknown_keyword_or_identifier_Did_you_mean_0, suggestion); 2098 return; 2099 } 2100 2101 // Unknown tokens are handled with their own errors in the scanner 2102 if (token() === SyntaxKind.Unknown) { 2103 return; 2104 } 2105 2106 // Otherwise, we know this some kind of unknown word, not just a missing expected semicolon. 2107 parseErrorAt(pos, node.end, Diagnostics.Unexpected_keyword_or_identifier); 2108 } 2109 2110 /** 2111 * Reports a diagnostic error for the current token being an invalid name. 2112 * 2113 * @param blankDiagnostic Diagnostic to report for the case of the name being blank (matched tokenIfBlankName). 2114 * @param nameDiagnostic Diagnostic to report for all other cases. 2115 * @param tokenIfBlankName Current token if the name was invalid for being blank (not provided / skipped). 2116 */ 2117 function parseErrorForInvalidName(nameDiagnostic: DiagnosticMessage, blankDiagnostic: DiagnosticMessage, tokenIfBlankName: SyntaxKind) { 2118 if (token() === tokenIfBlankName) { 2119 parseErrorAtCurrentToken(blankDiagnostic); 2120 } 2121 else { 2122 parseErrorAtCurrentToken(nameDiagnostic, scanner.getTokenValue()); 2123 } 2124 } 2125 2126 function getSpaceSuggestion(expressionText: string) { 2127 for (const keyword of viableKeywordSuggestions) { 2128 if (expressionText.length > keyword.length + 2 && startsWith(expressionText, keyword)) { 2129 return `${keyword} ${expressionText.slice(keyword.length)}`; 2130 } 2131 } 2132 2133 return undefined; 2134 } 2135 2136 function parseSemicolonAfterPropertyName(name: PropertyName, type: TypeNode | undefined, initializer: Expression | undefined) { 2137 if (token() === SyntaxKind.AtToken && !scanner.hasPrecedingLineBreak()) { 2138 parseErrorAtCurrentToken(Diagnostics.Decorators_must_precede_the_name_and_all_keywords_of_property_declarations); 2139 return; 2140 } 2141 2142 if (token() === SyntaxKind.OpenParenToken) { 2143 parseErrorAtCurrentToken(Diagnostics.Cannot_start_a_function_call_in_a_type_annotation); 2144 nextToken(); 2145 return; 2146 } 2147 2148 if (type && !canParseSemicolon()) { 2149 if (initializer) { 2150 parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.SemicolonToken)); 2151 } 2152 else { 2153 parseErrorAtCurrentToken(Diagnostics.Expected_for_property_initializer); 2154 } 2155 return; 2156 } 2157 2158 if (tryParseSemicolon()) { 2159 return; 2160 } 2161 2162 if (initializer) { 2163 parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.SemicolonToken)); 2164 return; 2165 } 2166 2167 parseErrorForMissingSemicolonAfter(name); 2168 } 2169 2170 function parseExpectedJSDoc(kind: JSDocSyntaxKind) { 2171 if (token() === kind) { 2172 nextTokenJSDoc(); 2173 return true; 2174 } 2175 parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(kind)); 2176 return false; 2177 } 2178 2179 function parseExpectedMatchingBrackets(openKind: SyntaxKind, closeKind: SyntaxKind, openParsed: boolean, openPosition: number) { 2180 if (token() === closeKind) { 2181 nextToken(); 2182 return; 2183 } 2184 const lastError = parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(closeKind)); 2185 if (!openParsed) { 2186 return; 2187 } 2188 if (lastError) { 2189 addRelatedInfo( 2190 lastError, 2191 createDetachedDiagnostic(fileName, openPosition, 1, Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, tokenToString(openKind), tokenToString(closeKind)) 2192 ); 2193 } 2194 } 2195 2196 function parseOptional(t: SyntaxKind): boolean { 2197 if (token() === t) { 2198 nextToken(); 2199 return true; 2200 } 2201 return false; 2202 } 2203 2204 function parseOptionalToken<TKind extends SyntaxKind>(t: TKind): Token<TKind>; 2205 function parseOptionalToken(t: SyntaxKind): Node | undefined { 2206 if (token() === t) { 2207 return parseTokenNode(); 2208 } 2209 return undefined; 2210 } 2211 2212 function parseOptionalTokenJSDoc<TKind extends JSDocSyntaxKind>(t: TKind): Token<TKind>; 2213 function parseOptionalTokenJSDoc(t: JSDocSyntaxKind): Node | undefined { 2214 if (token() === t) { 2215 return parseTokenNodeJSDoc(); 2216 } 2217 return undefined; 2218 } 2219 2220 function parseExpectedToken<TKind extends SyntaxKind>(t: TKind, diagnosticMessage?: DiagnosticMessage, arg0?: any): Token<TKind>; 2221 function parseExpectedToken(t: SyntaxKind, diagnosticMessage?: DiagnosticMessage, arg0?: any): Node { 2222 return parseOptionalToken(t) || 2223 createMissingNode(t, /*reportAtCurrentPosition*/ false, diagnosticMessage || Diagnostics._0_expected, arg0 || tokenToString(t)); 2224 } 2225 2226 function parseExpectedTokenJSDoc<TKind extends JSDocSyntaxKind>(t: TKind): Token<TKind>; 2227 function parseExpectedTokenJSDoc(t: JSDocSyntaxKind): Node { 2228 return parseOptionalTokenJSDoc(t) || 2229 createMissingNode(t, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, tokenToString(t)); 2230 } 2231 2232 function parseTokenNode<T extends Node>(): T { 2233 const pos = getNodePos(); 2234 const kind = token(); 2235 nextToken(); 2236 return finishNode(factory.createToken(kind), pos) as T; 2237 } 2238 2239 function parseTokenNodeJSDoc<T extends Node>(): T { 2240 const pos = getNodePos(); 2241 const kind = token(); 2242 nextTokenJSDoc(); 2243 return finishNode(factory.createToken(kind), pos) as T; 2244 } 2245 2246 function canParseSemicolon() { 2247 // If there's a real semicolon, then we can always parse it out. 2248 if (token() === SyntaxKind.SemicolonToken) { 2249 return true; 2250 } 2251 2252 // We can parse out an optional semicolon in ASI cases in the following cases. 2253 return token() === SyntaxKind.CloseBraceToken || token() === SyntaxKind.EndOfFileToken || scanner.hasPrecedingLineBreak(); 2254 } 2255 2256 function tryParseSemicolon() { 2257 if (!canParseSemicolon()) { 2258 return false; 2259 } 2260 2261 if (token() === SyntaxKind.SemicolonToken) { 2262 // consume the semicolon if it was explicitly provided. 2263 nextToken(); 2264 } 2265 2266 return true; 2267 } 2268 2269 function parseSemicolon(): boolean { 2270 return tryParseSemicolon() || parseExpected(SyntaxKind.SemicolonToken); 2271 } 2272 2273 function createNodeArray<T extends Node>(elements: T[], pos: number, end?: number, hasTrailingComma?: boolean): NodeArray<T> { 2274 const array = factory.createNodeArray(elements, hasTrailingComma); 2275 setTextRangePosEnd(array, pos, end ?? scanner.getStartPos()); 2276 return array; 2277 } 2278 2279 function finishNode<T extends Node>(node: T, pos: number, end?: number, virtual?: boolean): T { 2280 setTextRangePosEnd(node, pos, end ?? scanner.getStartPos()); 2281 if (contextFlags) { 2282 (node as Mutable<T>).flags |= contextFlags; 2283 } 2284 2285 // Keep track on the node if we encountered an error while parsing it. If we did, then 2286 // we cannot reuse the node incrementally. Once we've marked this node, clear out the 2287 // flag so that we don't mark any subsequent nodes. 2288 if (parseErrorBeforeNextFinishedNode) { 2289 parseErrorBeforeNextFinishedNode = false; 2290 (node as Mutable<T>).flags |= NodeFlags.ThisNodeHasError; 2291 } 2292 2293 if (virtual) { 2294 node.virtual = true; 2295 } 2296 2297 return node; 2298 } 2299 2300 function createMissingNode<T extends Node>(kind: T["kind"], reportAtCurrentPosition: false, diagnosticMessage?: DiagnosticMessage, arg0?: any): T; 2301 function createMissingNode<T extends Node>(kind: T["kind"], reportAtCurrentPosition: boolean, diagnosticMessage: DiagnosticMessage, arg0?: any): T; 2302 function createMissingNode<T extends Node>(kind: T["kind"], reportAtCurrentPosition: boolean, diagnosticMessage: DiagnosticMessage, arg0?: any): T { 2303 if (reportAtCurrentPosition) { 2304 parseErrorAtPosition(scanner.getStartPos(), 0, diagnosticMessage, arg0); 2305 } 2306 else if (diagnosticMessage) { 2307 parseErrorAtCurrentToken(diagnosticMessage, arg0); 2308 } 2309 2310 const pos = getNodePos(); 2311 const result = 2312 kind === SyntaxKind.Identifier ? factory.createIdentifier("", /*typeArguments*/ undefined, /*originalKeywordKind*/ undefined) : 2313 isTemplateLiteralKind(kind) ? factory.createTemplateLiteralLikeNode(kind, "", "", /*templateFlags*/ undefined) : 2314 kind === SyntaxKind.NumericLiteral ? factory.createNumericLiteral("", /*numericLiteralFlags*/ undefined) : 2315 kind === SyntaxKind.StringLiteral ? factory.createStringLiteral("", /*isSingleQuote*/ undefined) : 2316 kind === SyntaxKind.MissingDeclaration ? factory.createMissingDeclaration() : 2317 factory.createToken(kind); 2318 return finishNode(result, pos) as T; 2319 } 2320 2321 function internIdentifier(text: string): string { 2322 let identifier = identifiers.get(text); 2323 if (identifier === undefined) { 2324 identifiers.set(text, identifier = text); 2325 } 2326 return identifier; 2327 } 2328 2329 // An identifier that starts with two underscores has an extra underscore character prepended to it to avoid issues 2330 // with magic property names like '__proto__'. The 'identifiers' object is used to share a single string instance for 2331 // each identifier in order to reduce memory consumption. 2332 function createIdentifier(isIdentifier: boolean, diagnosticMessage?: DiagnosticMessage, privateIdentifierDiagnosticMessage?: DiagnosticMessage): Identifier { 2333 if (isIdentifier) { 2334 identifierCount++; 2335 const pos = getNodePos(); 2336 // Store original token kind if it is not just an Identifier so we can report appropriate error later in type checker 2337 const originalKeywordKind = token(); 2338 const text = internIdentifier(scanner.getTokenValue()); 2339 const hasExtendedUnicodeEscape = scanner.hasExtendedUnicodeEscape(); 2340 nextTokenWithoutCheck(); 2341 return finishNode(factory.createIdentifier(text, /*typeArguments*/ undefined, originalKeywordKind, hasExtendedUnicodeEscape), pos); 2342 } 2343 2344 if (token() === SyntaxKind.PrivateIdentifier) { 2345 parseErrorAtCurrentToken(privateIdentifierDiagnosticMessage || Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies); 2346 return createIdentifier(/*isIdentifier*/ true); 2347 } 2348 2349 if (token() === SyntaxKind.Unknown && scanner.tryScan(() => scanner.reScanInvalidIdentifier() === SyntaxKind.Identifier)) { 2350 // Scanner has already recorded an 'Invalid character' error, so no need to add another from the parser. 2351 return createIdentifier(/*isIdentifier*/ true); 2352 } 2353 2354 if (stateStylesRootNode && inEtsStateStylesContext() && token() === SyntaxKind.DotToken) { 2355 identifierCount++; 2356 const pos = getNodePos(); 2357 return finishVirtualNode( 2358 factory.createIdentifier(`${stateStylesRootNode}Instance`, /*typeArguments*/ undefined, SyntaxKind.Identifier), 2359 pos, 2360 pos 2361 ); 2362 } 2363 2364 identifierCount++; 2365 // Only for end of file because the error gets reported incorrectly on embedded script tags. 2366 const reportAtCurrentPosition = token() === SyntaxKind.EndOfFileToken; 2367 2368 const isReservedWord = scanner.isReservedWord(); 2369 const msgArg = scanner.getTokenText(); 2370 2371 const defaultMessage = isReservedWord ? 2372 Diagnostics.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here : 2373 Diagnostics.Identifier_expected; 2374 2375 return createMissingNode<Identifier>(SyntaxKind.Identifier, reportAtCurrentPosition, diagnosticMessage || defaultMessage, msgArg); 2376 } 2377 2378 function parseBindingIdentifier(privateIdentifierDiagnosticMessage?: DiagnosticMessage) { 2379 return createIdentifier(isBindingIdentifier(), /*diagnosticMessage*/ undefined, privateIdentifierDiagnosticMessage); 2380 } 2381 2382 function parseIdentifier(diagnosticMessage?: DiagnosticMessage, privateIdentifierDiagnosticMessage?: DiagnosticMessage): Identifier { 2383 return createIdentifier(isIdentifier(), diagnosticMessage, privateIdentifierDiagnosticMessage); 2384 } 2385 2386 function parseEtsIdentifier(pos: number): Identifier { 2387 identifierCount++; 2388 const text = internIdentifier(stylesEtsComponentDeclaration!.type); 2389 return finishVirtualNode(factory.createIdentifier(text), pos, pos); 2390 } 2391 2392 function parseIdentifierName(diagnosticMessage?: DiagnosticMessage): Identifier { 2393 return createIdentifier(tokenIsIdentifierOrKeyword(token()), diagnosticMessage); 2394 } 2395 2396 function isLiteralPropertyName(): boolean { 2397 return tokenIsIdentifierOrKeyword(token()) || 2398 token() === SyntaxKind.StringLiteral || 2399 token() === SyntaxKind.NumericLiteral; 2400 } 2401 2402 function isAssertionKey(): boolean { 2403 return tokenIsIdentifierOrKeyword(token()) || 2404 token() === SyntaxKind.StringLiteral; 2405 } 2406 2407 function parsePropertyNameWorker(allowComputedPropertyNames: boolean): PropertyName { 2408 if (token() === SyntaxKind.StringLiteral || token() === SyntaxKind.NumericLiteral) { 2409 const node = parseLiteralNode() as StringLiteral | NumericLiteral; 2410 node.text = internIdentifier(node.text); 2411 return node; 2412 } 2413 if (allowComputedPropertyNames && token() === SyntaxKind.OpenBracketToken) { 2414 return parseComputedPropertyName(); 2415 } 2416 if (token() === SyntaxKind.PrivateIdentifier) { 2417 return parsePrivateIdentifier(); 2418 } 2419 return parseIdentifierName(); 2420 } 2421 2422 function parsePropertyName(): PropertyName { 2423 return parsePropertyNameWorker(/*allowComputedPropertyNames*/ true); 2424 } 2425 2426 function parseComputedPropertyName(): ComputedPropertyName { 2427 // PropertyName [Yield]: 2428 // LiteralPropertyName 2429 // ComputedPropertyName[?Yield] 2430 const pos = getNodePos(); 2431 parseExpected(SyntaxKind.OpenBracketToken); 2432 // We parse any expression (including a comma expression). But the grammar 2433 // says that only an assignment expression is allowed, so the grammar checker 2434 // will error if it sees a comma expression. 2435 const expression = allowInAnd(parseExpression); 2436 parseExpected(SyntaxKind.CloseBracketToken); 2437 return finishNode(factory.createComputedPropertyName(expression), pos); 2438 } 2439 2440 function internPrivateIdentifier(text: string): string { 2441 let privateIdentifier = privateIdentifiers.get(text); 2442 if (privateIdentifier === undefined) { 2443 privateIdentifiers.set(text, privateIdentifier = text); 2444 } 2445 return privateIdentifier; 2446 } 2447 2448 function parsePrivateIdentifier(): PrivateIdentifier { 2449 const pos = getNodePos(); 2450 const node = factory.createPrivateIdentifier(internPrivateIdentifier(scanner.getTokenValue())); 2451 nextToken(); 2452 return finishNode(node, pos); 2453 } 2454 2455 function parseContextualModifier(t: SyntaxKind): boolean { 2456 return token() === t && tryParse(nextTokenCanFollowModifier); 2457 } 2458 2459 function nextTokenIsOnSameLineAndCanFollowModifier() { 2460 nextToken(); 2461 if (scanner.hasPrecedingLineBreak()) { 2462 return false; 2463 } 2464 return canFollowModifier(); 2465 } 2466 2467 function nextTokenCanFollowModifier() { 2468 switch (token()) { 2469 case SyntaxKind.ConstKeyword: 2470 // 'const' is only a modifier if followed by 'enum'. 2471 return nextToken() === SyntaxKind.EnumKeyword; 2472 case SyntaxKind.ExportKeyword: 2473 nextToken(); 2474 if (token() === SyntaxKind.DefaultKeyword) { 2475 return lookAhead(nextTokenCanFollowDefaultKeyword); 2476 } 2477 if (token() === SyntaxKind.TypeKeyword) { 2478 return lookAhead(nextTokenCanFollowExportModifier); 2479 } 2480 return canFollowExportModifier(); 2481 case SyntaxKind.DefaultKeyword: 2482 return nextTokenCanFollowDefaultKeyword(); 2483 case SyntaxKind.AccessorKeyword: 2484 case SyntaxKind.StaticKeyword: 2485 case SyntaxKind.GetKeyword: 2486 case SyntaxKind.SetKeyword: 2487 nextToken(); 2488 return canFollowModifier(); 2489 default: 2490 return nextTokenIsOnSameLineAndCanFollowModifier(); 2491 } 2492 } 2493 2494 function canFollowExportModifier(): boolean { 2495 return token() !== SyntaxKind.AsteriskToken 2496 && token() !== SyntaxKind.AsKeyword 2497 && token() !== SyntaxKind.OpenBraceToken 2498 && canFollowModifier(); 2499 } 2500 2501 function nextTokenCanFollowExportModifier(): boolean { 2502 nextToken(); 2503 return canFollowExportModifier(); 2504 } 2505 2506 function parseAnyContextualModifier(): boolean { 2507 return isModifierKind(token()) && tryParse(nextTokenCanFollowModifier); 2508 } 2509 2510 function canFollowModifier(): boolean { 2511 return token() === SyntaxKind.OpenBracketToken 2512 || token() === SyntaxKind.OpenBraceToken 2513 || token() === SyntaxKind.AsteriskToken 2514 || token() === SyntaxKind.DotDotDotToken 2515 || isLiteralPropertyName(); 2516 } 2517 2518 function nextTokenCanFollowDefaultKeyword(): boolean { 2519 nextToken(); 2520 return token() === SyntaxKind.ClassKeyword || (inEtsContext() && token() === SyntaxKind.StructKeyword) || 2521 token() === SyntaxKind.FunctionKeyword || token() === SyntaxKind.InterfaceKeyword || 2522 (token() === SyntaxKind.AbstractKeyword && lookAhead(nextTokenIsClassKeywordOnSameLine)) || 2523 (token() === SyntaxKind.AsyncKeyword && lookAhead(nextTokenIsFunctionKeywordOnSameLine)); 2524 } 2525 2526 // True if positioned at the start of a list element 2527 function isListElement(parsingContext: ParsingContext, inErrorRecovery: boolean): boolean { 2528 const node = currentNode(parsingContext); 2529 if (node) { 2530 return true; 2531 } 2532 2533 switch (parsingContext) { 2534 case ParsingContext.SourceElements: 2535 case ParsingContext.BlockStatements: 2536 case ParsingContext.SwitchClauseStatements: 2537 // If we're in error recovery, then we don't want to treat ';' as an empty statement. 2538 // The problem is that ';' can show up in far too many contexts, and if we see one 2539 // and assume it's a statement, then we may bail out inappropriately from whatever 2540 // we're parsing. For example, if we have a semicolon in the middle of a class, then 2541 // we really don't want to assume the class is over and we're on a statement in the 2542 // outer module. We just want to consume and move on. 2543 return !(token() === SyntaxKind.SemicolonToken && inErrorRecovery) && isStartOfStatement(); 2544 case ParsingContext.SwitchClauses: 2545 return token() === SyntaxKind.CaseKeyword || token() === SyntaxKind.DefaultKeyword; 2546 case ParsingContext.TypeMembers: 2547 return lookAhead(isTypeMemberStart); 2548 case ParsingContext.ClassMembers: 2549 // We allow semicolons as class elements (as specified by ES6) as long as we're 2550 // not in error recovery. If we're in error recovery, we don't want an errant 2551 // semicolon to be treated as a class member (since they're almost always used 2552 // for statements. 2553 return lookAhead(isClassMemberStart) || (token() === SyntaxKind.SemicolonToken && !inErrorRecovery); 2554 case ParsingContext.EnumMembers: 2555 // Include open bracket computed properties. This technically also lets in indexers, 2556 // which would be a candidate for improved error reporting. 2557 return token() === SyntaxKind.OpenBracketToken || isLiteralPropertyName(); 2558 case ParsingContext.ObjectLiteralMembers: 2559 switch (token()) { 2560 case SyntaxKind.OpenBracketToken: 2561 case SyntaxKind.AsteriskToken: 2562 case SyntaxKind.DotDotDotToken: 2563 case SyntaxKind.DotToken: // Not an object literal member, but don't want to close the object (see `tests/cases/fourslash/completionsDotInObjectLiteral.ts`) 2564 return true; 2565 default: 2566 return isLiteralPropertyName(); 2567 } 2568 case ParsingContext.RestProperties: 2569 return isLiteralPropertyName(); 2570 case ParsingContext.ObjectBindingElements: 2571 return token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.DotDotDotToken || isLiteralPropertyName(); 2572 case ParsingContext.AssertEntries: 2573 return isAssertionKey(); 2574 case ParsingContext.HeritageClauseElement: 2575 // If we see `{ ... }` then only consume it as an expression if it is followed by `,` or `{` 2576 // That way we won't consume the body of a class in its heritage clause. 2577 if (token() === SyntaxKind.OpenBraceToken) { 2578 return lookAhead(isValidHeritageClauseObjectLiteral); 2579 } 2580 2581 if (!inErrorRecovery) { 2582 return isStartOfLeftHandSideExpression() && !isHeritageClauseExtendsOrImplementsKeyword(); 2583 } 2584 else { 2585 // If we're in error recovery we tighten up what we're willing to match. 2586 // That way we don't treat something like "this" as a valid heritage clause 2587 // element during recovery. 2588 return isIdentifier() && !isHeritageClauseExtendsOrImplementsKeyword(); 2589 } 2590 case ParsingContext.VariableDeclarations: 2591 return isBindingIdentifierOrPrivateIdentifierOrPattern(); 2592 case ParsingContext.ArrayBindingElements: 2593 return token() === SyntaxKind.CommaToken || token() === SyntaxKind.DotDotDotToken || isBindingIdentifierOrPrivateIdentifierOrPattern(); 2594 case ParsingContext.TypeParameters: 2595 return token() === SyntaxKind.InKeyword || isIdentifier(); 2596 case ParsingContext.ArrayLiteralMembers: 2597 switch (token()) { 2598 case SyntaxKind.CommaToken: 2599 case SyntaxKind.DotToken: // Not an array literal member, but don't want to close the array (see `tests/cases/fourslash/completionsDotInArrayLiteralInObjectLiteral.ts`) 2600 return true; 2601 } 2602 // falls through 2603 case ParsingContext.ArgumentExpressions: 2604 return token() === SyntaxKind.DotDotDotToken || isStartOfExpression(); 2605 case ParsingContext.Parameters: 2606 return isStartOfParameter(/*isJSDocParameter*/ false); 2607 case ParsingContext.JSDocParameters: 2608 return isStartOfParameter(/*isJSDocParameter*/ true); 2609 case ParsingContext.TypeArguments: 2610 case ParsingContext.TupleElementTypes: 2611 return token() === SyntaxKind.CommaToken || isStartOfType(); 2612 case ParsingContext.HeritageClauses: 2613 return isHeritageClause(); 2614 case ParsingContext.ImportOrExportSpecifiers: 2615 return tokenIsIdentifierOrKeyword(token()); 2616 case ParsingContext.JsxAttributes: 2617 return tokenIsIdentifierOrKeyword(token()) || token() === SyntaxKind.OpenBraceToken; 2618 case ParsingContext.JsxChildren: 2619 return true; 2620 } 2621 2622 return Debug.fail("Non-exhaustive case in 'isListElement'."); 2623 } 2624 2625 function isValidHeritageClauseObjectLiteral() { 2626 Debug.assert(token() === SyntaxKind.OpenBraceToken); 2627 if (nextToken() === SyntaxKind.CloseBraceToken) { 2628 // if we see "extends {}" then only treat the {} as what we're extending (and not 2629 // the class body) if we have: 2630 // 2631 // extends {} { 2632 // extends {}, 2633 // extends {} extends 2634 // extends {} implements 2635 2636 const next = nextToken(); 2637 return next === SyntaxKind.CommaToken || next === SyntaxKind.OpenBraceToken || next === SyntaxKind.ExtendsKeyword || next === SyntaxKind.ImplementsKeyword; 2638 } 2639 2640 return true; 2641 } 2642 2643 function nextTokenIsIdentifier() { 2644 nextToken(); 2645 return isIdentifier(); 2646 } 2647 2648 function nextTokenIsIdentifierOrKeyword() { 2649 nextToken(); 2650 return tokenIsIdentifierOrKeyword(token()); 2651 } 2652 2653 function nextTokenIsIdentifierOrKeywordOrGreaterThan() { 2654 nextToken(); 2655 return tokenIsIdentifierOrKeywordOrGreaterThan(token()); 2656 } 2657 2658 function isHeritageClauseExtendsOrImplementsKeyword(): boolean { 2659 if (token() === SyntaxKind.ImplementsKeyword || 2660 token() === SyntaxKind.ExtendsKeyword) { 2661 2662 return lookAhead(nextTokenIsStartOfExpression); 2663 } 2664 2665 return false; 2666 } 2667 2668 function nextTokenIsStartOfExpression() { 2669 nextToken(); 2670 return isStartOfExpression(); 2671 } 2672 2673 function nextTokenIsStartOfType() { 2674 nextToken(); 2675 return isStartOfType(); 2676 } 2677 2678 // True if positioned at a list terminator 2679 function isListTerminator(kind: ParsingContext): boolean { 2680 if (token() === SyntaxKind.EndOfFileToken) { 2681 // Being at the end of the file ends all lists. 2682 return true; 2683 } 2684 2685 switch (kind) { 2686 case ParsingContext.BlockStatements: 2687 case ParsingContext.SwitchClauses: 2688 case ParsingContext.TypeMembers: 2689 case ParsingContext.ClassMembers: 2690 case ParsingContext.EnumMembers: 2691 case ParsingContext.ObjectLiteralMembers: 2692 case ParsingContext.ObjectBindingElements: 2693 case ParsingContext.ImportOrExportSpecifiers: 2694 case ParsingContext.AssertEntries: 2695 return token() === SyntaxKind.CloseBraceToken; 2696 case ParsingContext.SwitchClauseStatements: 2697 return token() === SyntaxKind.CloseBraceToken || token() === SyntaxKind.CaseKeyword || token() === SyntaxKind.DefaultKeyword; 2698 case ParsingContext.HeritageClauseElement: 2699 return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword; 2700 case ParsingContext.VariableDeclarations: 2701 return isVariableDeclaratorListTerminator(); 2702 case ParsingContext.TypeParameters: 2703 // Tokens other than '>' are here for better error recovery 2704 return token() === SyntaxKind.GreaterThanToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword; 2705 case ParsingContext.ArgumentExpressions: 2706 // Tokens other than ')' are here for better error recovery 2707 return token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.SemicolonToken; 2708 case ParsingContext.ArrayLiteralMembers: 2709 case ParsingContext.TupleElementTypes: 2710 case ParsingContext.ArrayBindingElements: 2711 return token() === SyntaxKind.CloseBracketToken; 2712 case ParsingContext.JSDocParameters: 2713 case ParsingContext.Parameters: 2714 case ParsingContext.RestProperties: 2715 // Tokens other than ')' and ']' (the latter for index signatures) are here for better error recovery 2716 return token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.CloseBracketToken /*|| token === SyntaxKind.OpenBraceToken*/; 2717 case ParsingContext.TypeArguments: 2718 // All other tokens should cause the type-argument to terminate except comma token 2719 return token() !== SyntaxKind.CommaToken; 2720 case ParsingContext.HeritageClauses: 2721 return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.CloseBraceToken; 2722 case ParsingContext.JsxAttributes: 2723 return token() === SyntaxKind.GreaterThanToken || token() === SyntaxKind.SlashToken; 2724 case ParsingContext.JsxChildren: 2725 return token() === SyntaxKind.LessThanToken && lookAhead(nextTokenIsSlash); 2726 default: 2727 return false; 2728 } 2729 } 2730 2731 function isVariableDeclaratorListTerminator(): boolean { 2732 // If we can consume a semicolon (either explicitly, or with ASI), then consider us done 2733 // with parsing the list of variable declarators. 2734 if (canParseSemicolon()) { 2735 return true; 2736 } 2737 2738 // in the case where we're parsing the variable declarator of a 'for-in' statement, we 2739 // are done if we see an 'in' keyword in front of us. Same with for-of 2740 if (isInOrOfKeyword(token())) { 2741 return true; 2742 } 2743 2744 // ERROR RECOVERY TWEAK: 2745 // For better error recovery, if we see an '=>' then we just stop immediately. We've got an 2746 // arrow function here and it's going to be very unlikely that we'll resynchronize and get 2747 // another variable declaration. 2748 if (token() === SyntaxKind.EqualsGreaterThanToken) { 2749 return true; 2750 } 2751 2752 // Keep trying to parse out variable declarators. 2753 return false; 2754 } 2755 2756 // True if positioned at element or terminator of the current list or any enclosing list 2757 function isInSomeParsingContext(): boolean { 2758 for (let kind = 0; kind < ParsingContext.Count; kind++) { 2759 if (parsingContext & (1 << kind)) { 2760 if (isListElement(kind, /*inErrorRecovery*/ true) || isListTerminator(kind)) { 2761 return true; 2762 } 2763 } 2764 } 2765 2766 return false; 2767 } 2768 2769 // Parses a list of elements 2770 function parseList<T extends Node>(kind: ParsingContext, parseElement: () => T): NodeArray<T> { 2771 const saveParsingContext = parsingContext; 2772 parsingContext |= 1 << kind; 2773 const list = []; 2774 const listPos = getNodePos(); 2775 2776 while (!isListTerminator(kind)) { 2777 if (isListElement(kind, /*inErrorRecovery*/ false)) { 2778 list.push(parseListElement(kind, parseElement)); 2779 2780 continue; 2781 } 2782 2783 if (abortParsingListOrMoveToNextToken(kind)) { 2784 break; 2785 } 2786 } 2787 2788 parsingContext = saveParsingContext; 2789 return createNodeArray(list, listPos); 2790 } 2791 2792 function parseListElement<T extends Node | undefined>(parsingContext: ParsingContext, parseElement: () => T): T { 2793 const node = currentNode(parsingContext); 2794 if (node) { 2795 return consumeNode(node) as T; 2796 } 2797 2798 return parseElement(); 2799 } 2800 2801 function currentNode(parsingContext: ParsingContext, pos?: number): Node | undefined { 2802 // If we don't have a cursor or the parsing context isn't reusable, there's nothing to reuse. 2803 // 2804 // If there is an outstanding parse error that we've encountered, but not attached to 2805 // some node, then we cannot get a node from the old source tree. This is because we 2806 // want to mark the next node we encounter as being unusable. 2807 // 2808 // Note: This may be too conservative. Perhaps we could reuse the node and set the bit 2809 // on it (or its leftmost child) as having the error. For now though, being conservative 2810 // is nice and likely won't ever affect perf. 2811 if (!syntaxCursor || !isReusableParsingContext(parsingContext) || parseErrorBeforeNextFinishedNode) { 2812 return undefined; 2813 } 2814 2815 const node = syntaxCursor.currentNode(pos ?? scanner.getStartPos()); 2816 2817 // Can't reuse a missing node. 2818 // Can't reuse a node that intersected the change range. 2819 // Can't reuse a node that contains a parse error. This is necessary so that we 2820 // produce the same set of errors again. 2821 if (nodeIsMissing(node) || node.intersectsChange || containsParseError(node)) { 2822 return undefined; 2823 } 2824 2825 // We can only reuse a node if it was parsed under the same strict mode that we're 2826 // currently in. i.e. if we originally parsed a node in non-strict mode, but then 2827 // the user added 'using strict' at the top of the file, then we can't use that node 2828 // again as the presence of strict mode may cause us to parse the tokens in the file 2829 // differently. 2830 // 2831 // Note: we *can* reuse tokens when the strict mode changes. That's because tokens 2832 // are unaffected by strict mode. It's just the parser will decide what to do with it 2833 // differently depending on what mode it is in. 2834 // 2835 // This also applies to all our other context flags as well. 2836 const nodeContextFlags = node.flags & NodeFlags.ContextFlags; 2837 if (nodeContextFlags !== contextFlags) { 2838 return undefined; 2839 } 2840 2841 // Ok, we have a node that looks like it could be reused. Now verify that it is valid 2842 // in the current list parsing context that we're currently at. 2843 if (!canReuseNode(node, parsingContext)) { 2844 return undefined; 2845 } 2846 2847 if ((node as JSDocContainer).jsDocCache) { 2848 // jsDocCache may include tags from parent nodes, which might have been modified. 2849 (node as JSDocContainer).jsDocCache = undefined; 2850 } 2851 2852 return node; 2853 } 2854 2855 function consumeNode(node: Node) { 2856 // Move the scanner so it is after the node we just consumed. 2857 scanner.setTextPos(node.end); 2858 nextToken(); 2859 return node; 2860 } 2861 2862 function isReusableParsingContext(parsingContext: ParsingContext): boolean { 2863 switch (parsingContext) { 2864 case ParsingContext.ClassMembers: 2865 case ParsingContext.SwitchClauses: 2866 case ParsingContext.SourceElements: 2867 case ParsingContext.BlockStatements: 2868 case ParsingContext.SwitchClauseStatements: 2869 case ParsingContext.EnumMembers: 2870 case ParsingContext.TypeMembers: 2871 case ParsingContext.VariableDeclarations: 2872 case ParsingContext.JSDocParameters: 2873 case ParsingContext.Parameters: 2874 return true; 2875 } 2876 return false; 2877 } 2878 2879 function canReuseNode(node: Node, parsingContext: ParsingContext): boolean { 2880 switch (parsingContext) { 2881 case ParsingContext.ClassMembers: 2882 return isReusableClassMember(node); 2883 2884 case ParsingContext.SwitchClauses: 2885 return isReusableSwitchClause(node); 2886 2887 case ParsingContext.SourceElements: 2888 case ParsingContext.BlockStatements: 2889 case ParsingContext.SwitchClauseStatements: 2890 return isReusableStatement(node); 2891 2892 case ParsingContext.EnumMembers: 2893 return isReusableEnumMember(node); 2894 2895 case ParsingContext.TypeMembers: 2896 return isReusableTypeMember(node); 2897 2898 case ParsingContext.VariableDeclarations: 2899 return isReusableVariableDeclaration(node); 2900 2901 case ParsingContext.JSDocParameters: 2902 case ParsingContext.Parameters: 2903 return isReusableParameter(node); 2904 2905 // Any other lists we do not care about reusing nodes in. But feel free to add if 2906 // you can do so safely. Danger areas involve nodes that may involve speculative 2907 // parsing. If speculative parsing is involved with the node, then the range the 2908 // parser reached while looking ahead might be in the edited range (see the example 2909 // in canReuseVariableDeclaratorNode for a good case of this). 2910 2911 // case ParsingContext.HeritageClauses: 2912 // This would probably be safe to reuse. There is no speculative parsing with 2913 // heritage clauses. 2914 2915 // case ParsingContext.TypeParameters: 2916 // This would probably be safe to reuse. There is no speculative parsing with 2917 // type parameters. Note that that's because type *parameters* only occur in 2918 // unambiguous *type* contexts. While type *arguments* occur in very ambiguous 2919 // *expression* contexts. 2920 2921 // case ParsingContext.TupleElementTypes: 2922 // This would probably be safe to reuse. There is no speculative parsing with 2923 // tuple types. 2924 2925 // Technically, type argument list types are probably safe to reuse. While 2926 // speculative parsing is involved with them (since type argument lists are only 2927 // produced from speculative parsing a < as a type argument list), we only have 2928 // the types because speculative parsing succeeded. Thus, the lookahead never 2929 // went past the end of the list and rewound. 2930 // case ParsingContext.TypeArguments: 2931 2932 // Note: these are almost certainly not safe to ever reuse. Expressions commonly 2933 // need a large amount of lookahead, and we should not reuse them as they may 2934 // have actually intersected the edit. 2935 // case ParsingContext.ArgumentExpressions: 2936 2937 // This is not safe to reuse for the same reason as the 'AssignmentExpression' 2938 // cases. i.e. a property assignment may end with an expression, and thus might 2939 // have lookahead far beyond it's old node. 2940 // case ParsingContext.ObjectLiteralMembers: 2941 2942 // This is probably not safe to reuse. There can be speculative parsing with 2943 // type names in a heritage clause. There can be generic names in the type 2944 // name list, and there can be left hand side expressions (which can have type 2945 // arguments.) 2946 // case ParsingContext.HeritageClauseElement: 2947 2948 // Perhaps safe to reuse, but it's unlikely we'd see more than a dozen attributes 2949 // on any given element. Same for children. 2950 // case ParsingContext.JsxAttributes: 2951 // case ParsingContext.JsxChildren: 2952 2953 } 2954 2955 return false; 2956 } 2957 2958 function isReusableClassMember(node: Node) { 2959 if (node) { 2960 switch (node.kind) { 2961 case SyntaxKind.Constructor: 2962 case SyntaxKind.IndexSignature: 2963 case SyntaxKind.GetAccessor: 2964 case SyntaxKind.SetAccessor: 2965 case SyntaxKind.SemicolonClassElement: 2966 return true; 2967 case SyntaxKind.PropertyDeclaration: 2968 return !inStructContext(); 2969 case SyntaxKind.MethodDeclaration: 2970 // Method declarations are not necessarily reusable. An object-literal 2971 // may have a method calls "constructor(...)" and we must reparse that 2972 // into an actual .ConstructorDeclaration. 2973 const methodDeclaration = node as MethodDeclaration; 2974 const nameIsConstructor = methodDeclaration.name.kind === SyntaxKind.Identifier && 2975 methodDeclaration.name.originalKeywordKind === SyntaxKind.ConstructorKeyword; 2976 2977 return !nameIsConstructor; 2978 } 2979 } 2980 2981 return false; 2982 } 2983 2984 function isReusableSwitchClause(node: Node) { 2985 if (node) { 2986 switch (node.kind) { 2987 case SyntaxKind.CaseClause: 2988 case SyntaxKind.DefaultClause: 2989 return true; 2990 } 2991 } 2992 2993 return false; 2994 } 2995 2996 function isReusableStatement(node: Node) { 2997 if (node) { 2998 switch (node.kind) { 2999 case SyntaxKind.FunctionDeclaration: 3000 case SyntaxKind.VariableStatement: 3001 case SyntaxKind.Block: 3002 case SyntaxKind.IfStatement: 3003 case SyntaxKind.ExpressionStatement: 3004 case SyntaxKind.ThrowStatement: 3005 case SyntaxKind.ReturnStatement: 3006 case SyntaxKind.SwitchStatement: 3007 case SyntaxKind.BreakStatement: 3008 case SyntaxKind.ContinueStatement: 3009 case SyntaxKind.ForInStatement: 3010 case SyntaxKind.ForOfStatement: 3011 case SyntaxKind.ForStatement: 3012 case SyntaxKind.WhileStatement: 3013 case SyntaxKind.WithStatement: 3014 case SyntaxKind.EmptyStatement: 3015 case SyntaxKind.TryStatement: 3016 case SyntaxKind.LabeledStatement: 3017 case SyntaxKind.DoStatement: 3018 case SyntaxKind.DebuggerStatement: 3019 case SyntaxKind.ImportDeclaration: 3020 case SyntaxKind.ImportEqualsDeclaration: 3021 case SyntaxKind.ExportDeclaration: 3022 case SyntaxKind.ExportAssignment: 3023 case SyntaxKind.ModuleDeclaration: 3024 case SyntaxKind.ClassDeclaration: 3025 case SyntaxKind.StructDeclaration: 3026 case SyntaxKind.InterfaceDeclaration: 3027 case SyntaxKind.EnumDeclaration: 3028 case SyntaxKind.TypeAliasDeclaration: 3029 return true; 3030 } 3031 } 3032 3033 return false; 3034 } 3035 3036 function isReusableEnumMember(node: Node) { 3037 return node.kind === SyntaxKind.EnumMember; 3038 } 3039 3040 function isReusableTypeMember(node: Node) { 3041 if (node) { 3042 switch (node.kind) { 3043 case SyntaxKind.ConstructSignature: 3044 case SyntaxKind.MethodSignature: 3045 case SyntaxKind.IndexSignature: 3046 case SyntaxKind.PropertySignature: 3047 case SyntaxKind.CallSignature: 3048 return true; 3049 } 3050 } 3051 3052 return false; 3053 } 3054 3055 function isReusableVariableDeclaration(node: Node) { 3056 if (node.kind !== SyntaxKind.VariableDeclaration) { 3057 return false; 3058 } 3059 3060 // Very subtle incremental parsing bug. Consider the following code: 3061 // 3062 // let v = new List < A, B 3063 // 3064 // This is actually legal code. It's a list of variable declarators "v = new List<A" 3065 // on one side and "B" on the other. If you then change that to: 3066 // 3067 // let v = new List < A, B >() 3068 // 3069 // then we have a problem. "v = new List<A" doesn't intersect the change range, so we 3070 // start reparsing at "B" and we completely fail to handle this properly. 3071 // 3072 // In order to prevent this, we do not allow a variable declarator to be reused if it 3073 // has an initializer. 3074 const variableDeclarator = node as VariableDeclaration; 3075 return variableDeclarator.initializer === undefined; 3076 } 3077 3078 function isReusableParameter(node: Node) { 3079 if (node.kind !== SyntaxKind.Parameter) { 3080 return false; 3081 } 3082 3083 // See the comment in isReusableVariableDeclaration for why we do this. 3084 const parameter = node as ParameterDeclaration; 3085 return parameter.initializer === undefined; 3086 } 3087 3088 // Returns true if we should abort parsing. 3089 function abortParsingListOrMoveToNextToken(kind: ParsingContext) { 3090 parsingContextErrors(kind); 3091 if (isInSomeParsingContext()) { 3092 return true; 3093 } 3094 3095 nextToken(); 3096 return false; 3097 } 3098 3099 function parsingContextErrors(context: ParsingContext) { 3100 switch (context) { 3101 case ParsingContext.SourceElements: 3102 return token() === SyntaxKind.DefaultKeyword 3103 ? parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.ExportKeyword)) 3104 : parseErrorAtCurrentToken(Diagnostics.Declaration_or_statement_expected); 3105 case ParsingContext.BlockStatements: return parseErrorAtCurrentToken(Diagnostics.Declaration_or_statement_expected); 3106 case ParsingContext.SwitchClauses: return parseErrorAtCurrentToken(Diagnostics.case_or_default_expected); 3107 case ParsingContext.SwitchClauseStatements: return parseErrorAtCurrentToken(Diagnostics.Statement_expected); 3108 case ParsingContext.RestProperties: // fallthrough 3109 case ParsingContext.TypeMembers: return parseErrorAtCurrentToken(Diagnostics.Property_or_signature_expected); 3110 case ParsingContext.ClassMembers: return parseErrorAtCurrentToken(Diagnostics.Unexpected_token_A_constructor_method_accessor_or_property_was_expected); 3111 case ParsingContext.EnumMembers: return parseErrorAtCurrentToken(Diagnostics.Enum_member_expected); 3112 case ParsingContext.HeritageClauseElement: return parseErrorAtCurrentToken(Diagnostics.Expression_expected); 3113 case ParsingContext.VariableDeclarations: 3114 return isKeyword(token()) 3115 ? parseErrorAtCurrentToken(Diagnostics._0_is_not_allowed_as_a_variable_declaration_name, tokenToString(token())) 3116 : parseErrorAtCurrentToken(Diagnostics.Variable_declaration_expected); 3117 case ParsingContext.ObjectBindingElements: return parseErrorAtCurrentToken(Diagnostics.Property_destructuring_pattern_expected); 3118 case ParsingContext.ArrayBindingElements: return parseErrorAtCurrentToken(Diagnostics.Array_element_destructuring_pattern_expected); 3119 case ParsingContext.ArgumentExpressions: return parseErrorAtCurrentToken(Diagnostics.Argument_expression_expected); 3120 case ParsingContext.ObjectLiteralMembers: return parseErrorAtCurrentToken(Diagnostics.Property_assignment_expected); 3121 case ParsingContext.ArrayLiteralMembers: return parseErrorAtCurrentToken(Diagnostics.Expression_or_comma_expected); 3122 case ParsingContext.JSDocParameters: return parseErrorAtCurrentToken(Diagnostics.Parameter_declaration_expected); 3123 case ParsingContext.Parameters: 3124 return isKeyword(token()) 3125 ? parseErrorAtCurrentToken(Diagnostics._0_is_not_allowed_as_a_parameter_name, tokenToString(token())) 3126 : parseErrorAtCurrentToken(Diagnostics.Parameter_declaration_expected); 3127 case ParsingContext.TypeParameters: return parseErrorAtCurrentToken(Diagnostics.Type_parameter_declaration_expected); 3128 case ParsingContext.TypeArguments: return parseErrorAtCurrentToken(Diagnostics.Type_argument_expected); 3129 case ParsingContext.TupleElementTypes: return parseErrorAtCurrentToken(Diagnostics.Type_expected); 3130 case ParsingContext.HeritageClauses: return parseErrorAtCurrentToken(Diagnostics.Unexpected_token_expected); 3131 case ParsingContext.ImportOrExportSpecifiers: return parseErrorAtCurrentToken(Diagnostics.Identifier_expected); 3132 case ParsingContext.JsxAttributes: return parseErrorAtCurrentToken(Diagnostics.Identifier_expected); 3133 case ParsingContext.JsxChildren: return parseErrorAtCurrentToken(Diagnostics.Identifier_expected); 3134 case ParsingContext.AssertEntries: return parseErrorAtCurrentToken(Diagnostics.Identifier_or_string_literal_expected); // AssertionKey. 3135 case ParsingContext.Count: return Debug.fail("ParsingContext.Count used as a context"); // Not a real context, only a marker. 3136 default: Debug.assertNever(context); 3137 } 3138 } 3139 3140 // Parses a comma-delimited list of elements 3141 function parseDelimitedList<T extends Node>(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimiter?: boolean): NodeArray<T>; 3142 function parseDelimitedList<T extends Node | undefined>(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimiter?: boolean): NodeArray<NonNullable<T>> | undefined; 3143 function parseDelimitedList<T extends Node | undefined>(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimiter?: boolean): NodeArray<NonNullable<T>> | undefined { 3144 const saveParsingContext = parsingContext; 3145 parsingContext |= 1 << kind; 3146 const list: NonNullable<T>[] = []; 3147 const listPos = getNodePos(); 3148 3149 let commaStart = -1; // Meaning the previous token was not a comma 3150 while (true) { 3151 if (isListElement(kind, /*inErrorRecovery*/ false)) { 3152 const startPos = scanner.getStartPos(); 3153 const result = parseListElement(kind, parseElement); 3154 if (!result) { 3155 parsingContext = saveParsingContext; 3156 return undefined; 3157 } 3158 list.push(result); 3159 commaStart = scanner.getTokenPos(); 3160 3161 if (parseOptional(SyntaxKind.CommaToken)) { 3162 // No need to check for a zero length node since we know we parsed a comma 3163 continue; 3164 } 3165 3166 commaStart = -1; // Back to the state where the last token was not a comma 3167 if (isListTerminator(kind)) { 3168 break; 3169 } 3170 3171 // We didn't get a comma, and the list wasn't terminated, explicitly parse 3172 // out a comma so we give a good error message. 3173 parseExpected(SyntaxKind.CommaToken, getExpectedCommaDiagnostic(kind)); 3174 3175 // If the token was a semicolon, and the caller allows that, then skip it and 3176 // continue. This ensures we get back on track and don't result in tons of 3177 // parse errors. For example, this can happen when people do things like use 3178 // a semicolon to delimit object literal members. Note: we'll have already 3179 // reported an error when we called parseExpected above. 3180 if (considerSemicolonAsDelimiter && token() === SyntaxKind.SemicolonToken && !scanner.hasPrecedingLineBreak()) { 3181 nextToken(); 3182 } 3183 if (startPos === scanner.getStartPos()) { 3184 // What we're parsing isn't actually remotely recognizable as a element and we've consumed no tokens whatsoever 3185 // Consume a token to advance the parser in some way and avoid an infinite loop 3186 // This can happen when we're speculatively parsing parenthesized expressions which we think may be arrow functions, 3187 // or when a modifier keyword which is disallowed as a parameter name (ie, `static` in strict mode) is supplied 3188 nextToken(); 3189 } 3190 continue; 3191 } 3192 3193 if (isListTerminator(kind)) { 3194 break; 3195 } 3196 3197 if (abortParsingListOrMoveToNextToken(kind)) { 3198 break; 3199 } 3200 } 3201 3202 parsingContext = saveParsingContext; 3203 // Recording the trailing comma is deliberately done after the previous 3204 // loop, and not just if we see a list terminator. This is because the list 3205 // may have ended incorrectly, but it is still important to know if there 3206 // was a trailing comma. 3207 // Check if the last token was a comma. 3208 // Always preserve a trailing comma by marking it on the NodeArray 3209 return createNodeArray(list, listPos, /*end*/ undefined, commaStart >= 0); 3210 } 3211 3212 function getExpectedCommaDiagnostic(kind: ParsingContext) { 3213 return kind === ParsingContext.EnumMembers ? Diagnostics.An_enum_member_name_must_be_followed_by_a_or : undefined; 3214 } 3215 3216 interface MissingList<T extends Node> extends NodeArray<T> { 3217 isMissingList: true; 3218 } 3219 3220 function createMissingList<T extends Node>(): MissingList<T> { 3221 const list = createNodeArray<T>([], getNodePos()) as MissingList<T>; 3222 list.isMissingList = true; 3223 return list; 3224 } 3225 3226 function isMissingList(arr: NodeArray<Node>): boolean { 3227 return !!(arr as MissingList<Node>).isMissingList; 3228 } 3229 3230 function parseBracketedList<T extends Node>(kind: ParsingContext, parseElement: () => T, open: SyntaxKind, close: SyntaxKind): NodeArray<T> { 3231 if (parseExpected(open)) { 3232 const result = parseDelimitedList(kind, parseElement); 3233 parseExpected(close); 3234 return result; 3235 } 3236 3237 return createMissingList<T>(); 3238 } 3239 3240 function parseEntityName(allowReservedWords: boolean, diagnosticMessage?: DiagnosticMessage): EntityName { 3241 const pos = getNodePos(); 3242 let entity: EntityName = allowReservedWords ? parseIdentifierName(diagnosticMessage) : parseIdentifier(diagnosticMessage); 3243 let dotPos = getNodePos(); 3244 while (parseOptional(SyntaxKind.DotToken)) { 3245 if (token() === SyntaxKind.LessThanToken) { 3246 // the entity is part of a JSDoc-style generic, so record the trailing dot for later error reporting 3247 entity.jsdocDotPos = dotPos; 3248 break; 3249 } 3250 dotPos = getNodePos(); 3251 entity = finishNode( 3252 factory.createQualifiedName( 3253 entity, 3254 parseRightSideOfDot(allowReservedWords, /* allowPrivateIdentifiers */ false) as Identifier 3255 ), 3256 pos 3257 ); 3258 } 3259 return entity; 3260 } 3261 3262 function createQualifiedName(entity: EntityName, name: Identifier): QualifiedName { 3263 return finishNode(factory.createQualifiedName(entity, name), entity.pos); 3264 } 3265 3266 function parseRightSideOfDot(allowIdentifierNames: boolean, allowPrivateIdentifiers: boolean): Identifier | PrivateIdentifier { 3267 // Technically a keyword is valid here as all identifiers and keywords are identifier names. 3268 // However, often we'll encounter this in error situations when the identifier or keyword 3269 // is actually starting another valid construct. 3270 // 3271 // So, we check for the following specific case: 3272 // 3273 // name. 3274 // identifierOrKeyword identifierNameOrKeyword 3275 // 3276 // Note: the newlines are important here. For example, if that above code 3277 // were rewritten into: 3278 // 3279 // name.identifierOrKeyword 3280 // identifierNameOrKeyword 3281 // 3282 // Then we would consider it valid. That's because ASI would take effect and 3283 // the code would be implicitly: "name.identifierOrKeyword; identifierNameOrKeyword". 3284 // In the first case though, ASI will not take effect because there is not a 3285 // line terminator after the identifier or keyword. 3286 if (scanner.hasPrecedingLineBreak() && tokenIsIdentifierOrKeyword(token())) { 3287 const matchesPattern = lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine); 3288 3289 if (matchesPattern) { 3290 // Report that we need an identifier. However, report it right after the dot, 3291 // and not on the next token. This is because the next token might actually 3292 // be an identifier and the error would be quite confusing. 3293 return createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Identifier_expected); 3294 } 3295 } 3296 3297 if (token() === SyntaxKind.PrivateIdentifier) { 3298 const node = parsePrivateIdentifier(); 3299 return allowPrivateIdentifiers ? node : createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Identifier_expected); 3300 } 3301 3302 return allowIdentifierNames ? parseIdentifierName() : parseIdentifier(); 3303 } 3304 3305 function parseTemplateSpans(isTaggedTemplate: boolean) { 3306 const pos = getNodePos(); 3307 const list = []; 3308 let node: TemplateSpan; 3309 do { 3310 node = parseTemplateSpan(isTaggedTemplate); 3311 list.push(node); 3312 } 3313 while (node.literal.kind === SyntaxKind.TemplateMiddle); 3314 return createNodeArray(list, pos); 3315 } 3316 3317 function parseTemplateExpression(isTaggedTemplate: boolean): TemplateExpression { 3318 const pos = getNodePos(); 3319 return finishNode( 3320 factory.createTemplateExpression( 3321 parseTemplateHead(isTaggedTemplate), 3322 parseTemplateSpans(isTaggedTemplate) 3323 ), 3324 pos 3325 ); 3326 } 3327 3328 function parseTemplateType(): TemplateLiteralTypeNode { 3329 const pos = getNodePos(); 3330 return finishNode( 3331 factory.createTemplateLiteralType( 3332 parseTemplateHead(/*isTaggedTemplate*/ false), 3333 parseTemplateTypeSpans() 3334 ), 3335 pos 3336 ); 3337 } 3338 3339 function parseTemplateTypeSpans() { 3340 const pos = getNodePos(); 3341 const list = []; 3342 let node: TemplateLiteralTypeSpan; 3343 do { 3344 node = parseTemplateTypeSpan(); 3345 list.push(node); 3346 } 3347 while (node.literal.kind === SyntaxKind.TemplateMiddle); 3348 return createNodeArray(list, pos); 3349 } 3350 3351 function parseTemplateTypeSpan(): TemplateLiteralTypeSpan { 3352 const pos = getNodePos(); 3353 return finishNode( 3354 factory.createTemplateLiteralTypeSpan( 3355 parseType(), 3356 parseLiteralOfTemplateSpan(/*isTaggedTemplate*/ false) 3357 ), 3358 pos 3359 ); 3360 } 3361 3362 function parseLiteralOfTemplateSpan(isTaggedTemplate: boolean) { 3363 if (token() === SyntaxKind.CloseBraceToken) { 3364 reScanTemplateToken(isTaggedTemplate); 3365 return parseTemplateMiddleOrTemplateTail(); 3366 } 3367 else { 3368 // TODO(rbuckton): Do we need to call `parseExpectedToken` or can we just call `createMissingNode` directly? 3369 return parseExpectedToken(SyntaxKind.TemplateTail, Diagnostics._0_expected, tokenToString(SyntaxKind.CloseBraceToken)) as TemplateTail; 3370 } 3371 } 3372 3373 function parseTemplateSpan(isTaggedTemplate: boolean): TemplateSpan { 3374 const pos = getNodePos(); 3375 return finishNode( 3376 factory.createTemplateSpan( 3377 allowInAnd(parseExpression), 3378 parseLiteralOfTemplateSpan(isTaggedTemplate) 3379 ), 3380 pos 3381 ); 3382 } 3383 3384 function parseLiteralNode(): LiteralExpression { 3385 return parseLiteralLikeNode(token()) as LiteralExpression; 3386 } 3387 3388 function parseTemplateHead(isTaggedTemplate: boolean): TemplateHead { 3389 if (isTaggedTemplate) { 3390 reScanTemplateHeadOrNoSubstitutionTemplate(); 3391 } 3392 const fragment = parseLiteralLikeNode(token()); 3393 Debug.assert(fragment.kind === SyntaxKind.TemplateHead, "Template head has wrong token kind"); 3394 return fragment as TemplateHead; 3395 } 3396 3397 function parseTemplateMiddleOrTemplateTail(): TemplateMiddle | TemplateTail { 3398 const fragment = parseLiteralLikeNode(token()); 3399 Debug.assert(fragment.kind === SyntaxKind.TemplateMiddle || fragment.kind === SyntaxKind.TemplateTail, "Template fragment has wrong token kind"); 3400 return fragment as TemplateMiddle | TemplateTail; 3401 } 3402 3403 function getTemplateLiteralRawText(kind: TemplateLiteralToken["kind"]) { 3404 const isLast = kind === SyntaxKind.NoSubstitutionTemplateLiteral || kind === SyntaxKind.TemplateTail; 3405 const tokenText = scanner.getTokenText(); 3406 return tokenText.substring(1, tokenText.length - (scanner.isUnterminated() ? 0 : isLast ? 1 : 2)); 3407 } 3408 3409 function parseLiteralLikeNode(kind: SyntaxKind): LiteralLikeNode { 3410 const pos = getNodePos(); 3411 const node = 3412 isTemplateLiteralKind(kind) ? factory.createTemplateLiteralLikeNode(kind, scanner.getTokenValue(), getTemplateLiteralRawText(kind), scanner.getTokenFlags() & TokenFlags.TemplateLiteralLikeFlags) : 3413 // Octal literals are not allowed in strict mode or ES5 3414 // Note that theoretically the following condition would hold true literals like 009, 3415 // which is not octal. But because of how the scanner separates the tokens, we would 3416 // never get a token like this. Instead, we would get 00 and 9 as two separate tokens. 3417 // We also do not need to check for negatives because any prefix operator would be part of a 3418 // parent unary expression. 3419 kind === SyntaxKind.NumericLiteral ? factory.createNumericLiteral(scanner.getTokenValue(), scanner.getNumericLiteralFlags()) : 3420 kind === SyntaxKind.StringLiteral ? factory.createStringLiteral(scanner.getTokenValue(), /*isSingleQuote*/ undefined, scanner.hasExtendedUnicodeEscape()) : 3421 isLiteralKind(kind) ? factory.createLiteralLikeNode(kind, scanner.getTokenValue()) : 3422 Debug.fail(); 3423 3424 if (scanner.hasExtendedUnicodeEscape()) { 3425 node.hasExtendedUnicodeEscape = true; 3426 } 3427 3428 if (scanner.isUnterminated()) { 3429 node.isUnterminated = true; 3430 } 3431 3432 nextToken(); 3433 return finishNode(node, pos); 3434 } 3435 3436 // TYPES 3437 3438 function parseEntityNameOfTypeReference() { 3439 return parseEntityName(/*allowReservedWords*/ true, Diagnostics.Type_expected); 3440 } 3441 3442 function parseTypeArgumentsOfTypeReference() { 3443 if (!scanner.hasPrecedingLineBreak() && reScanLessThanToken() === SyntaxKind.LessThanToken) { 3444 return parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken); 3445 } 3446 } 3447 3448 function parseTypeReference(): TypeReferenceNode { 3449 const pos = getNodePos(); 3450 return finishNode( 3451 factory.createTypeReferenceNode( 3452 parseEntityNameOfTypeReference(), 3453 parseTypeArgumentsOfTypeReference() 3454 ), 3455 pos 3456 ); 3457 } 3458 3459 // If true, we should abort parsing an error function. 3460 function typeHasArrowFunctionBlockingParseError(node: TypeNode): boolean { 3461 switch (node.kind) { 3462 case SyntaxKind.TypeReference: 3463 return nodeIsMissing((node as TypeReferenceNode).typeName); 3464 case SyntaxKind.FunctionType: 3465 case SyntaxKind.ConstructorType: { 3466 const { parameters, type } = node as FunctionOrConstructorTypeNode; 3467 return isMissingList(parameters) || typeHasArrowFunctionBlockingParseError(type); 3468 } 3469 case SyntaxKind.ParenthesizedType: 3470 return typeHasArrowFunctionBlockingParseError((node as ParenthesizedTypeNode).type); 3471 default: 3472 return false; 3473 } 3474 } 3475 3476 function parseThisTypePredicate(lhs: ThisTypeNode): TypePredicateNode { 3477 nextToken(); 3478 return finishNode(factory.createTypePredicateNode(/*assertsModifier*/ undefined, lhs, parseType()), lhs.pos); 3479 } 3480 3481 function parseThisTypeNode(): ThisTypeNode { 3482 const pos = getNodePos(); 3483 nextToken(); 3484 return finishNode(factory.createThisTypeNode(), pos); 3485 } 3486 3487 function parseJSDocAllType(): JSDocAllType | JSDocOptionalType { 3488 const pos = getNodePos(); 3489 nextToken(); 3490 return finishNode(factory.createJSDocAllType(), pos); 3491 } 3492 3493 function parseJSDocNonNullableType(): TypeNode { 3494 const pos = getNodePos(); 3495 nextToken(); 3496 return finishNode(factory.createJSDocNonNullableType(parseNonArrayType(), /*postfix*/ false), pos); 3497 } 3498 3499 function parseJSDocUnknownOrNullableType(): JSDocUnknownType | JSDocNullableType { 3500 const pos = getNodePos(); 3501 // skip the ? 3502 nextToken(); 3503 3504 // Need to lookahead to decide if this is a nullable or unknown type. 3505 3506 // Here are cases where we'll pick the unknown type: 3507 // 3508 // Foo(?, 3509 // { a: ? } 3510 // Foo(?) 3511 // Foo<?> 3512 // Foo(?= 3513 // (?| 3514 if (token() === SyntaxKind.CommaToken || 3515 token() === SyntaxKind.CloseBraceToken || 3516 token() === SyntaxKind.CloseParenToken || 3517 token() === SyntaxKind.GreaterThanToken || 3518 token() === SyntaxKind.EqualsToken || 3519 token() === SyntaxKind.BarToken) { 3520 return finishNode(factory.createJSDocUnknownType(), pos); 3521 } 3522 else { 3523 return finishNode(factory.createJSDocNullableType(parseType(), /*postfix*/ false), pos); 3524 } 3525 } 3526 3527 function parseJSDocFunctionType(): JSDocFunctionType | TypeReferenceNode { 3528 const pos = getNodePos(); 3529 const hasJSDoc = hasPrecedingJSDocComment(); 3530 if (lookAhead(nextTokenIsOpenParen)) { 3531 nextToken(); 3532 const parameters = parseParameters(SignatureFlags.Type | SignatureFlags.JSDoc); 3533 const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false); 3534 return withJSDoc(finishNode(factory.createJSDocFunctionType(parameters, type), pos), hasJSDoc); 3535 } 3536 return finishNode(factory.createTypeReferenceNode(parseIdentifierName(), /*typeArguments*/ undefined), pos); 3537 } 3538 3539 function parseJSDocParameter(): ParameterDeclaration { 3540 const pos = getNodePos(); 3541 let name: Identifier | undefined; 3542 if (token() === SyntaxKind.ThisKeyword || token() === SyntaxKind.NewKeyword) { 3543 name = parseIdentifierName(); 3544 parseExpected(SyntaxKind.ColonToken); 3545 } 3546 return finishNode( 3547 factory.createParameterDeclaration( 3548 /*modifiers*/ undefined, 3549 /*dotDotDotToken*/ undefined, 3550 // TODO(rbuckton): JSDoc parameters don't have names (except `this`/`new`), should we manufacture an empty identifier? 3551 name!, 3552 /*questionToken*/ undefined, 3553 parseJSDocType(), 3554 /*initializer*/ undefined 3555 ), 3556 pos 3557 ); 3558 } 3559 3560 function parseJSDocType(): TypeNode { 3561 scanner.setInJSDocType(true); 3562 const pos = getNodePos(); 3563 if (parseOptional(SyntaxKind.ModuleKeyword)) { 3564 // TODO(rbuckton): We never set the type for a JSDocNamepathType. What should we put here? 3565 const moduleTag = factory.createJSDocNamepathType(/*type*/ undefined!); 3566 terminate: while (true) { 3567 switch (token()) { 3568 case SyntaxKind.CloseBraceToken: 3569 case SyntaxKind.EndOfFileToken: 3570 case SyntaxKind.CommaToken: 3571 case SyntaxKind.WhitespaceTrivia: 3572 break terminate; 3573 default: 3574 nextTokenJSDoc(); 3575 } 3576 } 3577 3578 scanner.setInJSDocType(false); 3579 return finishNode(moduleTag, pos); 3580 } 3581 3582 const hasDotDotDot = parseOptional(SyntaxKind.DotDotDotToken); 3583 let type = parseTypeOrTypePredicate(); 3584 scanner.setInJSDocType(false); 3585 if (hasDotDotDot) { 3586 type = finishNode(factory.createJSDocVariadicType(type), pos); 3587 } 3588 if (token() === SyntaxKind.EqualsToken) { 3589 nextToken(); 3590 return finishNode(factory.createJSDocOptionalType(type), pos); 3591 } 3592 return type; 3593 } 3594 3595 function parseTypeQuery(): TypeQueryNode { 3596 const pos = getNodePos(); 3597 parseExpected(SyntaxKind.TypeOfKeyword); 3598 const entityName = parseEntityName(/*allowReservedWords*/ true); 3599 // Make sure we perform ASI to prevent parsing the next line's type arguments as part of an instantiation expression. 3600 const typeArguments = !scanner.hasPrecedingLineBreak() ? tryParseTypeArguments() : undefined; 3601 return finishNode(factory.createTypeQueryNode(entityName, typeArguments), pos); 3602 } 3603 3604 function parseTypeParameter(position?: number): TypeParameterDeclaration { 3605 const pos = getNodePos(); 3606 const modifiers = parseModifiers(); 3607 const name = position !== undefined ? parseEtsIdentifier(position) : parseIdentifier(); 3608 let constraint: TypeNode | undefined; 3609 let expression: Expression | undefined; 3610 if (parseOptional(SyntaxKind.ExtendsKeyword)) { 3611 // It's not uncommon for people to write improper constraints to a generic. If the 3612 // user writes a constraint that is an expression and not an actual type, then parse 3613 // it out as an expression (so we can recover well), but report that a type is needed 3614 // instead. 3615 if (isStartOfType() || !isStartOfExpression()) { 3616 constraint = parseType(); 3617 } 3618 else { 3619 // It was not a type, and it looked like an expression. Parse out an expression 3620 // here so we recover well. Note: it is important that we call parseUnaryExpression 3621 // and not parseExpression here. If the user has: 3622 // 3623 // <T extends ""> 3624 // 3625 // We do *not* want to consume the `>` as we're consuming the expression for "". 3626 expression = parseUnaryExpressionOrHigher(); 3627 } 3628 } 3629 3630 const defaultType = parseOptional(SyntaxKind.EqualsToken) ? parseType() : undefined; 3631 const node = factory.createTypeParameterDeclaration(modifiers, name, constraint, defaultType); 3632 node.expression = expression; 3633 return position !== undefined ? finishVirtualNode(node, position, position) : finishNode(node, pos); 3634 } 3635 3636 function parseTypeParameters(): NodeArray<TypeParameterDeclaration> | undefined { 3637 if (token() === SyntaxKind.LessThanToken) { 3638 return parseBracketedList(ParsingContext.TypeParameters, parseTypeParameter, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken); 3639 } 3640 } 3641 3642 function parseEtsTypeParameters(pos: number): NodeArray<TypeParameterDeclaration> | undefined { 3643 return createNodeArray([parseTypeParameter(pos)], getNodePos()); 3644 } 3645 3646 function parseEtsTypeArguments(pos: number, name: string): NodeArray<TypeNode> | undefined { 3647 if ((contextFlags & NodeFlags.JavaScriptFile) !== 0) { 3648 // TypeArguments must not be parsed in JavaScript files to avoid ambiguity with binary operators. 3649 return undefined; 3650 } 3651 3652 return createNodeArray([parseEtsType(pos, name)], getNodePos()); 3653 } 3654 3655 function isStartOfParameter(isJSDocParameter: boolean): boolean { 3656 return token() === SyntaxKind.DotDotDotToken || 3657 isBindingIdentifierOrPrivateIdentifierOrPattern() || 3658 isModifierKind(token()) || 3659 token() === SyntaxKind.AtToken || 3660 isStartOfType(/*inStartOfParameter*/ !isJSDocParameter); 3661 } 3662 3663 function parseNameOfParameter(modifiers: NodeArray<ModifierLike> | undefined) { 3664 // FormalParameter [Yield,Await]: 3665 // BindingElement[?Yield,?Await] 3666 const name = parseIdentifierOrPattern(Diagnostics.Private_identifiers_cannot_be_used_as_parameters); 3667 if (getFullWidth(name) === 0 && !some(modifiers) && isModifierKind(token())) { 3668 // in cases like 3669 // 'use strict' 3670 // function foo(static) 3671 // isParameter('static') === true, because of isModifier('static') 3672 // however 'static' is not a legal identifier in a strict mode. 3673 // so result of this function will be ParameterDeclaration (flags = 0, name = missing, type = undefined, initializer = undefined) 3674 // and current token will not change => parsing of the enclosing parameter list will last till the end of time (or OOM) 3675 // to avoid this we'll advance cursor to the next token. 3676 nextToken(); 3677 } 3678 return name; 3679 } 3680 3681 function isParameterNameStart() { 3682 // Be permissive about await and yield by calling isBindingIdentifier instead of isIdentifier; disallowing 3683 // them during a speculative parse leads to many more follow-on errors than allowing the function to parse then later 3684 // complaining about the use of the keywords. 3685 return isBindingIdentifier() || token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.OpenBraceToken; 3686 } 3687 3688 function parseParameter(inOuterAwaitContext: boolean): ParameterDeclaration { 3689 return parseParameterWorker(inOuterAwaitContext); 3690 } 3691 3692 function parseParameterForSpeculation(inOuterAwaitContext: boolean): ParameterDeclaration | undefined { 3693 return parseParameterWorker(inOuterAwaitContext, /*allowAmbiguity*/ false); 3694 } 3695 3696 function parseParameterWorker(inOuterAwaitContext: boolean): ParameterDeclaration; 3697 function parseParameterWorker(inOuterAwaitContext: boolean, allowAmbiguity: false): ParameterDeclaration | undefined; 3698 function parseParameterWorker(inOuterAwaitContext: boolean, allowAmbiguity = true): ParameterDeclaration | undefined { 3699 const pos = getNodePos(); 3700 const hasJSDoc = hasPrecedingJSDocComment(); 3701 3702 // FormalParameter [Yield,Await]: 3703 // BindingElement[?Yield,?Await] 3704 3705 // Decorators are parsed in the outer [Await] context, the rest of the parameter is parsed in the function's [Await] context. 3706 const decorators = inOuterAwaitContext ? doInAwaitContext(parseDecorators) : doOutsideOfAwaitContext(parseDecorators); 3707 3708 if (token() === SyntaxKind.ThisKeyword) { 3709 const node = factory.createParameterDeclaration( 3710 decorators, 3711 /*dotDotDotToken*/ undefined, 3712 createIdentifier(/*isIdentifier*/ true), 3713 /*questionToken*/ undefined, 3714 parseTypeAnnotation(), 3715 /*initializer*/ undefined 3716 ); 3717 3718 if (decorators) { 3719 parseErrorAtRange(decorators[0], Diagnostics.Decorators_may_not_be_applied_to_this_parameters); 3720 } 3721 3722 return withJSDoc(finishNode(node, pos), hasJSDoc); 3723 } 3724 3725 const savedTopLevel = topLevel; 3726 topLevel = false; 3727 3728 const modifiers = combineDecoratorsAndModifiers(decorators, parseModifiers()); 3729 const dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); 3730 3731 if (!allowAmbiguity && !isParameterNameStart()) { 3732 return undefined; 3733 } 3734 3735 const node = withJSDoc( 3736 finishNode( 3737 factory.createParameterDeclaration( 3738 modifiers, 3739 dotDotDotToken, 3740 parseNameOfParameter(modifiers), 3741 parseOptionalToken(SyntaxKind.QuestionToken), 3742 parseTypeAnnotation(), 3743 parseInitializer() 3744 ), 3745 pos 3746 ), 3747 hasJSDoc 3748 ); 3749 topLevel = savedTopLevel; 3750 return node; 3751 } 3752 3753 function parseReturnType(returnToken: SyntaxKind.EqualsGreaterThanToken, isType: boolean): TypeNode; 3754 function parseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean): TypeNode | undefined; 3755 function parseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean) { 3756 if (shouldParseReturnType(returnToken, isType)) { 3757 return allowConditionalTypesAnd(parseTypeOrTypePredicate); 3758 } 3759 } 3760 3761 function shouldParseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean): boolean { 3762 if (returnToken === SyntaxKind.EqualsGreaterThanToken) { 3763 parseExpected(returnToken); 3764 return true; 3765 } 3766 else if (parseOptional(SyntaxKind.ColonToken)) { 3767 return true; 3768 } 3769 else if (isType && token() === SyntaxKind.EqualsGreaterThanToken) { 3770 // This is easy to get backward, especially in type contexts, so parse the type anyway 3771 parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.ColonToken)); 3772 nextToken(); 3773 return true; 3774 } 3775 return false; 3776 } 3777 3778 function parseParametersWorker(flags: SignatureFlags, allowAmbiguity: true): NodeArray<ParameterDeclaration>; 3779 function parseParametersWorker(flags: SignatureFlags, allowAmbiguity: false): NodeArray<ParameterDeclaration> | undefined; 3780 function parseParametersWorker(flags: SignatureFlags, allowAmbiguity: boolean): NodeArray<ParameterDeclaration> | undefined { 3781 // FormalParameters [Yield,Await]: (modified) 3782 // [empty] 3783 // FormalParameterList[?Yield,Await] 3784 // 3785 // FormalParameter[Yield,Await]: (modified) 3786 // BindingElement[?Yield,Await] 3787 // 3788 // BindingElement [Yield,Await]: (modified) 3789 // SingleNameBinding[?Yield,?Await] 3790 // BindingPattern[?Yield,?Await]Initializer [In, ?Yield,?Await] opt 3791 // 3792 // SingleNameBinding [Yield,Await]: 3793 // BindingIdentifier[?Yield,?Await]Initializer [In, ?Yield,?Await] opt 3794 const savedYieldContext = inYieldContext(); 3795 const savedAwaitContext = inAwaitContext(); 3796 3797 setYieldContext(!!(flags & SignatureFlags.Yield)); 3798 setAwaitContext(!!(flags & SignatureFlags.Await)); 3799 3800 const parameters = flags & SignatureFlags.JSDoc ? 3801 parseDelimitedList(ParsingContext.JSDocParameters, parseJSDocParameter) : 3802 parseDelimitedList(ParsingContext.Parameters, () => allowAmbiguity ? parseParameter(savedAwaitContext) : parseParameterForSpeculation(savedAwaitContext)); 3803 3804 setYieldContext(savedYieldContext); 3805 setAwaitContext(savedAwaitContext); 3806 3807 return parameters; 3808 } 3809 3810 function parseParameters(flags: SignatureFlags): NodeArray<ParameterDeclaration> { 3811 // FormalParameters [Yield,Await]: (modified) 3812 // [empty] 3813 // FormalParameterList[?Yield,Await] 3814 // 3815 // FormalParameter[Yield,Await]: (modified) 3816 // BindingElement[?Yield,Await] 3817 // 3818 // BindingElement [Yield,Await]: (modified) 3819 // SingleNameBinding[?Yield,?Await] 3820 // BindingPattern[?Yield,?Await]Initializer [In, ?Yield,?Await] opt 3821 // 3822 // SingleNameBinding [Yield,Await]: 3823 // BindingIdentifier[?Yield,?Await]Initializer [In, ?Yield,?Await] opt 3824 if (!parseExpected(SyntaxKind.OpenParenToken)) { 3825 return createMissingList<ParameterDeclaration>(); 3826 } 3827 3828 const parameters = parseParametersWorker(flags, /*allowAmbiguity*/ true); 3829 parseExpected(SyntaxKind.CloseParenToken); 3830 return parameters; 3831 } 3832 3833 function parseTypeMemberSemicolon() { 3834 // We allow type members to be separated by commas or (possibly ASI) semicolons. 3835 // First check if it was a comma. If so, we're done with the member. 3836 if (parseOptional(SyntaxKind.CommaToken)) { 3837 return; 3838 } 3839 3840 // Didn't have a comma. We must have a (possible ASI) semicolon. 3841 parseSemicolon(); 3842 } 3843 3844 function parseSignatureMember(kind: SyntaxKind.CallSignature | SyntaxKind.ConstructSignature): CallSignatureDeclaration | ConstructSignatureDeclaration { 3845 const pos = getNodePos(); 3846 const hasJSDoc = hasPrecedingJSDocComment(); 3847 if (kind === SyntaxKind.ConstructSignature) { 3848 parseExpected(SyntaxKind.NewKeyword); 3849 } 3850 3851 const typeParameters = parseTypeParameters(); 3852 const parameters = parseParameters(SignatureFlags.Type); 3853 const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ true); 3854 parseTypeMemberSemicolon(); 3855 const node = kind === SyntaxKind.CallSignature 3856 ? factory.createCallSignature(typeParameters, parameters, type) 3857 : factory.createConstructSignature(typeParameters, parameters, type); 3858 return withJSDoc(finishNode(node, pos), hasJSDoc); 3859 } 3860 3861 function isIndexSignature(): boolean { 3862 return token() === SyntaxKind.OpenBracketToken && lookAhead(isUnambiguouslyIndexSignature); 3863 } 3864 3865 function isUnambiguouslyIndexSignature() { 3866 // The only allowed sequence is: 3867 // 3868 // [id: 3869 // 3870 // However, for error recovery, we also check the following cases: 3871 // 3872 // [... 3873 // [id, 3874 // [id?, 3875 // [id?: 3876 // [id?] 3877 // [public id 3878 // [private id 3879 // [protected id 3880 // [] 3881 // 3882 nextToken(); 3883 if (token() === SyntaxKind.DotDotDotToken || token() === SyntaxKind.CloseBracketToken) { 3884 return true; 3885 } 3886 3887 if (isModifierKind(token())) { 3888 nextToken(); 3889 if (isIdentifier()) { 3890 return true; 3891 } 3892 } 3893 else if (!isIdentifier()) { 3894 return false; 3895 } 3896 else { 3897 // Skip the identifier 3898 nextToken(); 3899 } 3900 3901 // A colon signifies a well formed indexer 3902 // A comma should be a badly formed indexer because comma expressions are not allowed 3903 // in computed properties. 3904 if (token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken) { 3905 return true; 3906 } 3907 3908 // Question mark could be an indexer with an optional property, 3909 // or it could be a conditional expression in a computed property. 3910 if (token() !== SyntaxKind.QuestionToken) { 3911 return false; 3912 } 3913 3914 // If any of the following tokens are after the question mark, it cannot 3915 // be a conditional expression, so treat it as an indexer. 3916 nextToken(); 3917 return token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken || token() === SyntaxKind.CloseBracketToken; 3918 } 3919 3920 function parseIndexSignatureDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): IndexSignatureDeclaration { 3921 const parameters = parseBracketedList<ParameterDeclaration>(ParsingContext.Parameters, () => parseParameter(/*inOuterAwaitContext*/ false), SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken); 3922 const type = parseTypeAnnotation(); 3923 parseTypeMemberSemicolon(); 3924 const node = factory.createIndexSignature(modifiers, parameters, type); 3925 (node as Mutable<IndexSignatureDeclaration>).illegalDecorators = decorators; 3926 return withJSDoc(finishNode(node, pos), hasJSDoc); 3927 } 3928 3929 function parsePropertyOrMethodSignature(pos: number, hasJSDoc: boolean, modifiers: NodeArray<Modifier> | undefined): PropertySignature | MethodSignature { 3930 const name = parsePropertyName(); 3931 const questionToken = parseOptionalToken(SyntaxKind.QuestionToken); 3932 let node: PropertySignature | MethodSignature; 3933 if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) { 3934 // Method signatures don't exist in expression contexts. So they have neither 3935 // [Yield] nor [Await] 3936 const typeParameters = parseTypeParameters(); 3937 const parameters = parseParameters(SignatureFlags.Type); 3938 const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ true); 3939 node = factory.createMethodSignature(modifiers, name, questionToken, typeParameters, parameters, type); 3940 } 3941 else { 3942 const type = parseTypeAnnotation(); 3943 node = factory.createPropertySignature(modifiers, name, questionToken, type); 3944 // Although type literal properties cannot not have initializers, we attempt 3945 // to parse an initializer so we can report in the checker that an interface 3946 // property or type literal property cannot have an initializer. 3947 if (token() === SyntaxKind.EqualsToken) (node as Mutable<PropertySignature>).initializer = parseInitializer(); 3948 } 3949 parseTypeMemberSemicolon(); 3950 return withJSDoc(finishNode(node, pos), hasJSDoc); 3951 } 3952 3953 function isTypeMemberStart(): boolean { 3954 // Return true if we have the start of a signature member 3955 if (token() === SyntaxKind.OpenParenToken || 3956 token() === SyntaxKind.LessThanToken || 3957 token() === SyntaxKind.GetKeyword || 3958 token() === SyntaxKind.SetKeyword) { 3959 return true; 3960 } 3961 let idToken = false; 3962 // Eat up all modifiers, but hold on to the last one in case it is actually an identifier 3963 while (isModifierKind(token())) { 3964 idToken = true; 3965 nextToken(); 3966 } 3967 // Index signatures and computed property names are type members 3968 if (token() === SyntaxKind.OpenBracketToken) { 3969 return true; 3970 } 3971 // Try to get the first property-like token following all modifiers 3972 if (isLiteralPropertyName()) { 3973 idToken = true; 3974 nextToken(); 3975 } 3976 // If we were able to get any potential identifier, check that it is 3977 // the start of a member declaration 3978 if (idToken) { 3979 return token() === SyntaxKind.OpenParenToken || 3980 token() === SyntaxKind.LessThanToken || 3981 token() === SyntaxKind.QuestionToken || 3982 token() === SyntaxKind.ColonToken || 3983 token() === SyntaxKind.CommaToken || 3984 canParseSemicolon(); 3985 } 3986 return false; 3987 } 3988 3989 function parseTypeMember(): TypeElement { 3990 if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) { 3991 return parseSignatureMember(SyntaxKind.CallSignature); 3992 } 3993 if (token() === SyntaxKind.NewKeyword && lookAhead(nextTokenIsOpenParenOrLessThan)) { 3994 return parseSignatureMember(SyntaxKind.ConstructSignature); 3995 } 3996 const pos = getNodePos(); 3997 const hasJSDoc = hasPrecedingJSDocComment(); 3998 const modifiers = parseModifiers(); 3999 if (parseContextualModifier(SyntaxKind.GetKeyword)) { 4000 return parseAccessorDeclaration(pos, hasJSDoc, /*decorators*/ undefined, modifiers, SyntaxKind.GetAccessor, SignatureFlags.Type); 4001 } 4002 4003 if (parseContextualModifier(SyntaxKind.SetKeyword)) { 4004 return parseAccessorDeclaration(pos, hasJSDoc, /*decorators*/ undefined, modifiers, SyntaxKind.SetAccessor, SignatureFlags.Type); 4005 } 4006 4007 if (isIndexSignature()) { 4008 return parseIndexSignatureDeclaration(pos, hasJSDoc, /*decorators*/ undefined, modifiers); 4009 } 4010 return parsePropertyOrMethodSignature(pos, hasJSDoc, modifiers); 4011 } 4012 4013 function nextTokenIsOpenParenOrLessThan() { 4014 nextToken(); 4015 return token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken; 4016 } 4017 4018 function nextTokenIsDot() { 4019 return nextToken() === SyntaxKind.DotToken; 4020 } 4021 4022 function nextTokenIsOpenParenOrLessThanOrDot() { 4023 switch (nextToken()) { 4024 case SyntaxKind.OpenParenToken: 4025 case SyntaxKind.LessThanToken: 4026 case SyntaxKind.DotToken: 4027 return true; 4028 } 4029 return false; 4030 } 4031 4032 function parseTypeLiteral(): TypeLiteralNode { 4033 const pos = getNodePos(); 4034 return finishNode(factory.createTypeLiteralNode(parseObjectTypeMembers()), pos); 4035 } 4036 4037 function parseObjectTypeMembers(): NodeArray<TypeElement> { 4038 let members: NodeArray<TypeElement>; 4039 if (parseExpected(SyntaxKind.OpenBraceToken)) { 4040 members = parseList(ParsingContext.TypeMembers, parseTypeMember); 4041 parseExpected(SyntaxKind.CloseBraceToken); 4042 } 4043 else { 4044 members = createMissingList<TypeElement>(); 4045 } 4046 4047 return members; 4048 } 4049 4050 function isStartOfMappedType() { 4051 nextToken(); 4052 if (token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) { 4053 return nextToken() === SyntaxKind.ReadonlyKeyword; 4054 } 4055 if (token() === SyntaxKind.ReadonlyKeyword) { 4056 nextToken(); 4057 } 4058 return token() === SyntaxKind.OpenBracketToken && nextTokenIsIdentifier() && nextToken() === SyntaxKind.InKeyword; 4059 } 4060 4061 function parseMappedTypeParameter() { 4062 const pos = getNodePos(); 4063 const name = parseIdentifierName(); 4064 parseExpected(SyntaxKind.InKeyword); 4065 const type = parseType(); 4066 return finishNode(factory.createTypeParameterDeclaration(/*modifiers*/ undefined, name, type, /*defaultType*/ undefined), pos); 4067 } 4068 4069 function parseMappedType() { 4070 const pos = getNodePos(); 4071 parseExpected(SyntaxKind.OpenBraceToken); 4072 let readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined; 4073 if (token() === SyntaxKind.ReadonlyKeyword || token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) { 4074 readonlyToken = parseTokenNode<ReadonlyKeyword | PlusToken | MinusToken>(); 4075 if (readonlyToken.kind !== SyntaxKind.ReadonlyKeyword) { 4076 parseExpected(SyntaxKind.ReadonlyKeyword); 4077 } 4078 } 4079 parseExpected(SyntaxKind.OpenBracketToken); 4080 const typeParameter = parseMappedTypeParameter(); 4081 const nameType = parseOptional(SyntaxKind.AsKeyword) ? parseType() : undefined; 4082 parseExpected(SyntaxKind.CloseBracketToken); 4083 let questionToken: QuestionToken | PlusToken | MinusToken | undefined; 4084 if (token() === SyntaxKind.QuestionToken || token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) { 4085 questionToken = parseTokenNode<QuestionToken | PlusToken | MinusToken>(); 4086 if (questionToken.kind !== SyntaxKind.QuestionToken) { 4087 parseExpected(SyntaxKind.QuestionToken); 4088 } 4089 } 4090 const type = parseTypeAnnotation(); 4091 parseSemicolon(); 4092 const members = parseList(ParsingContext.TypeMembers, parseTypeMember); 4093 parseExpected(SyntaxKind.CloseBraceToken); 4094 return finishNode(factory.createMappedTypeNode(readonlyToken, typeParameter, nameType, questionToken, type, members), pos); 4095 } 4096 4097 function parseTupleElementType() { 4098 const pos = getNodePos(); 4099 if (parseOptional(SyntaxKind.DotDotDotToken)) { 4100 return finishNode(factory.createRestTypeNode(parseType()), pos); 4101 } 4102 const type = parseType(); 4103 if (isJSDocNullableType(type) && type.pos === type.type.pos) { 4104 const node = factory.createOptionalTypeNode(type.type); 4105 setTextRange(node, type); 4106 (node as Mutable<Node>).flags = type.flags; 4107 return node; 4108 } 4109 return type; 4110 } 4111 4112 function isNextTokenColonOrQuestionColon() { 4113 return nextToken() === SyntaxKind.ColonToken || (token() === SyntaxKind.QuestionToken && nextToken() === SyntaxKind.ColonToken); 4114 } 4115 4116 function isTupleElementName() { 4117 if (token() === SyntaxKind.DotDotDotToken) { 4118 return tokenIsIdentifierOrKeyword(nextToken()) && isNextTokenColonOrQuestionColon(); 4119 } 4120 return tokenIsIdentifierOrKeyword(token()) && isNextTokenColonOrQuestionColon(); 4121 } 4122 4123 function parseTupleElementNameOrTupleElementType() { 4124 if (lookAhead(isTupleElementName)) { 4125 const pos = getNodePos(); 4126 const hasJSDoc = hasPrecedingJSDocComment(); 4127 const dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); 4128 const name = parseIdentifierName(); 4129 const questionToken = parseOptionalToken(SyntaxKind.QuestionToken); 4130 parseExpected(SyntaxKind.ColonToken); 4131 const type = parseTupleElementType(); 4132 const node = factory.createNamedTupleMember(dotDotDotToken, name, questionToken, type); 4133 return withJSDoc(finishNode(node, pos), hasJSDoc); 4134 } 4135 return parseTupleElementType(); 4136 } 4137 4138 function parseTupleType(): TupleTypeNode { 4139 const pos = getNodePos(); 4140 return finishNode( 4141 factory.createTupleTypeNode( 4142 parseBracketedList(ParsingContext.TupleElementTypes, parseTupleElementNameOrTupleElementType, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken) 4143 ), 4144 pos 4145 ); 4146 } 4147 4148 function parseParenthesizedType(): TypeNode { 4149 const pos = getNodePos(); 4150 parseExpected(SyntaxKind.OpenParenToken); 4151 const type = parseType(); 4152 parseExpected(SyntaxKind.CloseParenToken); 4153 return finishNode(factory.createParenthesizedType(type), pos); 4154 } 4155 4156 function parseModifiersForConstructorType(): NodeArray<Modifier> | undefined { 4157 let modifiers: NodeArray<Modifier> | undefined; 4158 if (token() === SyntaxKind.AbstractKeyword) { 4159 const pos = getNodePos(); 4160 nextToken(); 4161 const modifier = finishNode(factory.createToken(SyntaxKind.AbstractKeyword), pos); 4162 modifiers = createNodeArray<Modifier>([modifier], pos); 4163 } 4164 return modifiers; 4165 } 4166 4167 function parseFunctionOrConstructorType(): TypeNode { 4168 const pos = getNodePos(); 4169 const hasJSDoc = hasPrecedingJSDocComment(); 4170 const modifiers = parseModifiersForConstructorType(); 4171 const isConstructorType = parseOptional(SyntaxKind.NewKeyword); 4172 const typeParameters = parseTypeParameters(); 4173 const parameters = parseParameters(SignatureFlags.Type); 4174 const type = parseReturnType(SyntaxKind.EqualsGreaterThanToken, /*isType*/ false); 4175 const node = isConstructorType 4176 ? factory.createConstructorTypeNode(modifiers, typeParameters, parameters, type) 4177 : factory.createFunctionTypeNode(typeParameters, parameters, type); 4178 if (!isConstructorType) (node as Mutable<FunctionTypeNode>).modifiers = modifiers; 4179 return withJSDoc(finishNode(node, pos), hasJSDoc); 4180 } 4181 4182 function parseKeywordAndNoDot(): TypeNode | undefined { 4183 const node = parseTokenNode<TypeNode>(); 4184 return token() === SyntaxKind.DotToken ? undefined : node; 4185 } 4186 4187 function parseLiteralTypeNode(negative?: boolean): LiteralTypeNode { 4188 const pos = getNodePos(); 4189 if (negative) { 4190 nextToken(); 4191 } 4192 let expression: BooleanLiteral | NullLiteral | LiteralExpression | PrefixUnaryExpression = 4193 token() === SyntaxKind.TrueKeyword || token() === SyntaxKind.FalseKeyword || token() === SyntaxKind.NullKeyword ? 4194 parseTokenNode<BooleanLiteral | NullLiteral>() : 4195 parseLiteralLikeNode(token()) as LiteralExpression; 4196 if (negative) { 4197 expression = finishNode(factory.createPrefixUnaryExpression(SyntaxKind.MinusToken, expression), pos); 4198 } 4199 return finishNode(factory.createLiteralTypeNode(expression), pos); 4200 } 4201 4202 function isStartOfTypeOfImportType() { 4203 nextToken(); 4204 return token() === SyntaxKind.ImportKeyword; 4205 } 4206 4207 function parseImportTypeAssertions(): ImportTypeAssertionContainer { 4208 const pos = getNodePos(); 4209 const openBracePosition = scanner.getTokenPos(); 4210 parseExpected(SyntaxKind.OpenBraceToken); 4211 const multiLine = scanner.hasPrecedingLineBreak(); 4212 parseExpected(SyntaxKind.AssertKeyword); 4213 parseExpected(SyntaxKind.ColonToken); 4214 const clause = parseAssertClause(/*skipAssertKeyword*/ true); 4215 if (!parseExpected(SyntaxKind.CloseBraceToken)) { 4216 const lastError = lastOrUndefined(parseDiagnostics); 4217 if (lastError && lastError.code === Diagnostics._0_expected.code) { 4218 addRelatedInfo( 4219 lastError, 4220 createDetachedDiagnostic(fileName, openBracePosition, 1, Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, "{", "}") 4221 ); 4222 } 4223 } 4224 return finishNode(factory.createImportTypeAssertionContainer(clause, multiLine), pos); 4225 } 4226 4227 function parseImportType(): ImportTypeNode { 4228 sourceFlags |= NodeFlags.PossiblyContainsDynamicImport; 4229 const pos = getNodePos(); 4230 const isTypeOf = parseOptional(SyntaxKind.TypeOfKeyword); 4231 parseExpected(SyntaxKind.ImportKeyword); 4232 parseExpected(SyntaxKind.OpenParenToken); 4233 const type = parseType(); 4234 let assertions: ImportTypeAssertionContainer | undefined; 4235 if (parseOptional(SyntaxKind.CommaToken)) { 4236 assertions = parseImportTypeAssertions(); 4237 } 4238 parseExpected(SyntaxKind.CloseParenToken); 4239 const qualifier = parseOptional(SyntaxKind.DotToken) ? parseEntityNameOfTypeReference() : undefined; 4240 const typeArguments = parseTypeArgumentsOfTypeReference(); 4241 return finishNode(factory.createImportTypeNode(type, assertions, qualifier, typeArguments, isTypeOf), pos); 4242 } 4243 4244 function nextTokenIsNumericOrBigIntLiteral() { 4245 nextToken(); 4246 return token() === SyntaxKind.NumericLiteral || token() === SyntaxKind.BigIntLiteral; 4247 } 4248 4249 function parseNonArrayType(): TypeNode { 4250 switch (token()) { 4251 case SyntaxKind.AnyKeyword: 4252 case SyntaxKind.UnknownKeyword: 4253 case SyntaxKind.StringKeyword: 4254 case SyntaxKind.NumberKeyword: 4255 case SyntaxKind.BigIntKeyword: 4256 case SyntaxKind.SymbolKeyword: 4257 case SyntaxKind.BooleanKeyword: 4258 case SyntaxKind.UndefinedKeyword: 4259 case SyntaxKind.NeverKeyword: 4260 case SyntaxKind.ObjectKeyword: 4261 // If these are followed by a dot, then parse these out as a dotted type reference instead. 4262 return tryParse(parseKeywordAndNoDot) || parseTypeReference(); 4263 case SyntaxKind.AsteriskEqualsToken: 4264 // If there is '*=', treat it as * followed by postfix = 4265 scanner.reScanAsteriskEqualsToken(); 4266 // falls through 4267 case SyntaxKind.AsteriskToken: 4268 return parseJSDocAllType(); 4269 case SyntaxKind.QuestionQuestionToken: 4270 // If there is '??', treat it as prefix-'?' in JSDoc type. 4271 scanner.reScanQuestionToken(); 4272 // falls through 4273 case SyntaxKind.QuestionToken: 4274 return parseJSDocUnknownOrNullableType(); 4275 case SyntaxKind.FunctionKeyword: 4276 return parseJSDocFunctionType(); 4277 case SyntaxKind.ExclamationToken: 4278 return parseJSDocNonNullableType(); 4279 case SyntaxKind.NoSubstitutionTemplateLiteral: 4280 case SyntaxKind.StringLiteral: 4281 case SyntaxKind.NumericLiteral: 4282 case SyntaxKind.BigIntLiteral: 4283 case SyntaxKind.TrueKeyword: 4284 case SyntaxKind.FalseKeyword: 4285 case SyntaxKind.NullKeyword: 4286 return parseLiteralTypeNode(); 4287 case SyntaxKind.MinusToken: 4288 return lookAhead(nextTokenIsNumericOrBigIntLiteral) ? parseLiteralTypeNode(/*negative*/ true) : parseTypeReference(); 4289 case SyntaxKind.VoidKeyword: 4290 return parseTokenNode<TypeNode>(); 4291 case SyntaxKind.ThisKeyword: { 4292 const thisKeyword = parseThisTypeNode(); 4293 if (token() === SyntaxKind.IsKeyword && !scanner.hasPrecedingLineBreak()) { 4294 return parseThisTypePredicate(thisKeyword); 4295 } 4296 else { 4297 return thisKeyword; 4298 } 4299 } 4300 case SyntaxKind.TypeOfKeyword: 4301 return lookAhead(isStartOfTypeOfImportType) ? parseImportType() : parseTypeQuery(); 4302 case SyntaxKind.OpenBraceToken: 4303 return lookAhead(isStartOfMappedType) ? parseMappedType() : parseTypeLiteral(); 4304 case SyntaxKind.OpenBracketToken: 4305 return parseTupleType(); 4306 case SyntaxKind.OpenParenToken: 4307 return parseParenthesizedType(); 4308 case SyntaxKind.ImportKeyword: 4309 return parseImportType(); 4310 case SyntaxKind.AssertsKeyword: 4311 return lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine) ? parseAssertsTypePredicate() : parseTypeReference(); 4312 case SyntaxKind.TemplateHead: 4313 return parseTemplateType(); 4314 default: 4315 return parseTypeReference(); 4316 } 4317 } 4318 4319 function isStartOfType(inStartOfParameter?: boolean): boolean { 4320 switch (token()) { 4321 case SyntaxKind.AnyKeyword: 4322 case SyntaxKind.UnknownKeyword: 4323 case SyntaxKind.StringKeyword: 4324 case SyntaxKind.NumberKeyword: 4325 case SyntaxKind.BigIntKeyword: 4326 case SyntaxKind.BooleanKeyword: 4327 case SyntaxKind.ReadonlyKeyword: 4328 case SyntaxKind.SymbolKeyword: 4329 case SyntaxKind.UniqueKeyword: 4330 case SyntaxKind.VoidKeyword: 4331 case SyntaxKind.UndefinedKeyword: 4332 case SyntaxKind.NullKeyword: 4333 case SyntaxKind.ThisKeyword: 4334 case SyntaxKind.TypeOfKeyword: 4335 case SyntaxKind.NeverKeyword: 4336 case SyntaxKind.OpenBraceToken: 4337 case SyntaxKind.OpenBracketToken: 4338 case SyntaxKind.LessThanToken: 4339 case SyntaxKind.BarToken: 4340 case SyntaxKind.AmpersandToken: 4341 case SyntaxKind.NewKeyword: 4342 case SyntaxKind.StringLiteral: 4343 case SyntaxKind.NumericLiteral: 4344 case SyntaxKind.BigIntLiteral: 4345 case SyntaxKind.TrueKeyword: 4346 case SyntaxKind.FalseKeyword: 4347 case SyntaxKind.ObjectKeyword: 4348 case SyntaxKind.AsteriskToken: 4349 case SyntaxKind.QuestionToken: 4350 case SyntaxKind.ExclamationToken: 4351 case SyntaxKind.DotDotDotToken: 4352 case SyntaxKind.InferKeyword: 4353 case SyntaxKind.ImportKeyword: 4354 case SyntaxKind.AssertsKeyword: 4355 case SyntaxKind.NoSubstitutionTemplateLiteral: 4356 case SyntaxKind.TemplateHead: 4357 return true; 4358 case SyntaxKind.FunctionKeyword: 4359 return !inStartOfParameter; 4360 case SyntaxKind.MinusToken: 4361 return !inStartOfParameter && lookAhead(nextTokenIsNumericOrBigIntLiteral); 4362 case SyntaxKind.OpenParenToken: 4363 // Only consider '(' the start of a type if followed by ')', '...', an identifier, a modifier, 4364 // or something that starts a type. We don't want to consider things like '(1)' a type. 4365 return !inStartOfParameter && lookAhead(isStartOfParenthesizedOrFunctionType); 4366 default: 4367 return isIdentifier(); 4368 } 4369 } 4370 4371 function isStartOfParenthesizedOrFunctionType() { 4372 nextToken(); 4373 return token() === SyntaxKind.CloseParenToken || isStartOfParameter(/*isJSDocParameter*/ false) || isStartOfType(); 4374 } 4375 4376 function parsePostfixTypeOrHigher(): TypeNode { 4377 const pos = getNodePos(); 4378 let type = parseNonArrayType(); 4379 while (!scanner.hasPrecedingLineBreak()) { 4380 switch (token()) { 4381 case SyntaxKind.ExclamationToken: 4382 nextToken(); 4383 type = finishNode(factory.createJSDocNonNullableType(type, /*postfix*/ true), pos); 4384 break; 4385 case SyntaxKind.QuestionToken: 4386 // If next token is start of a type we have a conditional type 4387 if (lookAhead(nextTokenIsStartOfType)) { 4388 return type; 4389 } 4390 nextToken(); 4391 type = finishNode(factory.createJSDocNullableType(type, /*postfix*/ true), pos); 4392 break; 4393 case SyntaxKind.OpenBracketToken: 4394 parseExpected(SyntaxKind.OpenBracketToken); 4395 if (isStartOfType()) { 4396 const indexType = parseType(); 4397 parseExpected(SyntaxKind.CloseBracketToken); 4398 type = finishNode(factory.createIndexedAccessTypeNode(type, indexType), pos); 4399 } 4400 else { 4401 parseExpected(SyntaxKind.CloseBracketToken); 4402 type = finishNode(factory.createArrayTypeNode(type), pos); 4403 } 4404 break; 4405 default: 4406 return type; 4407 } 4408 } 4409 return type; 4410 } 4411 4412 function parseTypeOperator(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword) { 4413 const pos = getNodePos(); 4414 parseExpected(operator); 4415 return finishNode(factory.createTypeOperatorNode(operator, parseTypeOperatorOrHigher()), pos); 4416 } 4417 4418 function tryParseConstraintOfInferType() { 4419 if (parseOptional(SyntaxKind.ExtendsKeyword)) { 4420 const constraint = disallowConditionalTypesAnd(parseType); 4421 if (inDisallowConditionalTypesContext() || token() !== SyntaxKind.QuestionToken) { 4422 return constraint; 4423 } 4424 } 4425 } 4426 4427 function parseTypeParameterOfInferType(): TypeParameterDeclaration { 4428 const pos = getNodePos(); 4429 const name = parseIdentifier(); 4430 const constraint = tryParse(tryParseConstraintOfInferType); 4431 const node = factory.createTypeParameterDeclaration(/*modifiers*/ undefined, name, constraint); 4432 return finishNode(node, pos); 4433 } 4434 4435 function parseInferType(): InferTypeNode { 4436 const pos = getNodePos(); 4437 parseExpected(SyntaxKind.InferKeyword); 4438 return finishNode(factory.createInferTypeNode(parseTypeParameterOfInferType()), pos); 4439 } 4440 4441 function parseTypeOperatorOrHigher(): TypeNode { 4442 const operator = token(); 4443 switch (operator) { 4444 case SyntaxKind.KeyOfKeyword: 4445 case SyntaxKind.UniqueKeyword: 4446 case SyntaxKind.ReadonlyKeyword: 4447 return parseTypeOperator(operator); 4448 case SyntaxKind.InferKeyword: 4449 return parseInferType(); 4450 } 4451 return allowConditionalTypesAnd(parsePostfixTypeOrHigher); 4452 } 4453 4454 function parseFunctionOrConstructorTypeToError( 4455 isInUnionType: boolean 4456 ): TypeNode | undefined { 4457 // the function type and constructor type shorthand notation 4458 // are not allowed directly in unions and intersections, but we'll 4459 // try to parse them gracefully and issue a helpful message. 4460 if (isStartOfFunctionTypeOrConstructorType()) { 4461 const type = parseFunctionOrConstructorType(); 4462 let diagnostic: DiagnosticMessage; 4463 if (isFunctionTypeNode(type)) { 4464 diagnostic = isInUnionType 4465 ? Diagnostics.Function_type_notation_must_be_parenthesized_when_used_in_a_union_type 4466 : Diagnostics.Function_type_notation_must_be_parenthesized_when_used_in_an_intersection_type; 4467 } 4468 else { 4469 diagnostic = isInUnionType 4470 ? Diagnostics.Constructor_type_notation_must_be_parenthesized_when_used_in_a_union_type 4471 : Diagnostics.Constructor_type_notation_must_be_parenthesized_when_used_in_an_intersection_type; 4472 4473 } 4474 parseErrorAtRange(type, diagnostic); 4475 return type; 4476 } 4477 return undefined; 4478 } 4479 4480 function parseUnionOrIntersectionType( 4481 operator: SyntaxKind.BarToken | SyntaxKind.AmpersandToken, 4482 parseConstituentType: () => TypeNode, 4483 createTypeNode: (types: NodeArray<TypeNode>) => UnionOrIntersectionTypeNode 4484 ): TypeNode { 4485 const pos = getNodePos(); 4486 const isUnionType = operator === SyntaxKind.BarToken; 4487 const hasLeadingOperator = parseOptional(operator); 4488 let type = hasLeadingOperator && parseFunctionOrConstructorTypeToError(isUnionType) 4489 || parseConstituentType(); 4490 if (token() === operator || hasLeadingOperator) { 4491 const types = [type]; 4492 while (parseOptional(operator)) { 4493 types.push(parseFunctionOrConstructorTypeToError(isUnionType) || parseConstituentType()); 4494 } 4495 type = finishNode(createTypeNode(createNodeArray(types, pos)), pos); 4496 } 4497 return type; 4498 } 4499 4500 function parseIntersectionTypeOrHigher(): TypeNode { 4501 return parseUnionOrIntersectionType(SyntaxKind.AmpersandToken, parseTypeOperatorOrHigher, factory.createIntersectionTypeNode); 4502 } 4503 4504 function parseUnionTypeOrHigher(): TypeNode { 4505 return parseUnionOrIntersectionType(SyntaxKind.BarToken, parseIntersectionTypeOrHigher, factory.createUnionTypeNode); 4506 } 4507 4508 function nextTokenIsNewKeyword(): boolean { 4509 nextToken(); 4510 return token() === SyntaxKind.NewKeyword; 4511 } 4512 4513 function isStartOfFunctionTypeOrConstructorType(): boolean { 4514 if (token() === SyntaxKind.LessThanToken) { 4515 return true; 4516 } 4517 if (token() === SyntaxKind.OpenParenToken && lookAhead(isUnambiguouslyStartOfFunctionType)) { 4518 return true; 4519 } 4520 return token() === SyntaxKind.NewKeyword || 4521 token() === SyntaxKind.AbstractKeyword && lookAhead(nextTokenIsNewKeyword); 4522 } 4523 4524 function skipParameterStart(): boolean { 4525 if (isModifierKind(token())) { 4526 // Skip modifiers 4527 parseModifiers(); 4528 } 4529 if (isIdentifier() || token() === SyntaxKind.ThisKeyword) { 4530 nextToken(); 4531 return true; 4532 } 4533 if (token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.OpenBraceToken) { 4534 // Return true if we can parse an array or object binding pattern with no errors 4535 const previousErrorCount = parseDiagnostics.length; 4536 parseIdentifierOrPattern(); 4537 return previousErrorCount === parseDiagnostics.length; 4538 } 4539 return false; 4540 } 4541 4542 function isUnambiguouslyStartOfFunctionType() { 4543 nextToken(); 4544 if (token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.DotDotDotToken) { 4545 // ( ) 4546 // ( ... 4547 return true; 4548 } 4549 if (skipParameterStart()) { 4550 // We successfully skipped modifiers (if any) and an identifier or binding pattern, 4551 // now see if we have something that indicates a parameter declaration 4552 if (token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken || 4553 token() === SyntaxKind.QuestionToken || token() === SyntaxKind.EqualsToken) { 4554 // ( xxx : 4555 // ( xxx , 4556 // ( xxx ? 4557 // ( xxx = 4558 return true; 4559 } 4560 if (token() === SyntaxKind.CloseParenToken) { 4561 nextToken(); 4562 if (token() === SyntaxKind.EqualsGreaterThanToken) { 4563 // ( xxx ) => 4564 return true; 4565 } 4566 } 4567 } 4568 return false; 4569 } 4570 4571 function parseTypeOrTypePredicate(): TypeNode { 4572 const pos = getNodePos(); 4573 const typePredicateVariable = isIdentifier() && tryParse(parseTypePredicatePrefix); 4574 const type = parseType(); 4575 if (typePredicateVariable) { 4576 return finishNode(factory.createTypePredicateNode(/*assertsModifier*/ undefined, typePredicateVariable, type), pos); 4577 } 4578 else { 4579 return type; 4580 } 4581 } 4582 4583 function parseTypePredicatePrefix() { 4584 const id = parseIdentifier(); 4585 if (token() === SyntaxKind.IsKeyword && !scanner.hasPrecedingLineBreak()) { 4586 nextToken(); 4587 return id; 4588 } 4589 } 4590 4591 function parseAssertsTypePredicate(): TypeNode { 4592 const pos = getNodePos(); 4593 const assertsModifier = parseExpectedToken(SyntaxKind.AssertsKeyword); 4594 const parameterName = token() === SyntaxKind.ThisKeyword ? parseThisTypeNode() : parseIdentifier(); 4595 const type = parseOptional(SyntaxKind.IsKeyword) ? parseType() : undefined; 4596 return finishNode(factory.createTypePredicateNode(assertsModifier, parameterName, type), pos); 4597 } 4598 4599 function parseType(): TypeNode { 4600 if (contextFlags & NodeFlags.TypeExcludesFlags) { 4601 return doOutsideOfContext(NodeFlags.TypeExcludesFlags, parseType); 4602 } 4603 4604 if (isStartOfFunctionTypeOrConstructorType()) { 4605 return parseFunctionOrConstructorType(); 4606 } 4607 const pos = getNodePos(); 4608 const type = parseUnionTypeOrHigher(); 4609 if (!inDisallowConditionalTypesContext() && !scanner.hasPrecedingLineBreak() && parseOptional(SyntaxKind.ExtendsKeyword)) { 4610 // The type following 'extends' is not permitted to be another conditional type 4611 const extendsType = disallowConditionalTypesAnd(parseType); 4612 parseExpected(SyntaxKind.QuestionToken); 4613 const trueType = allowConditionalTypesAnd(parseType); 4614 parseExpected(SyntaxKind.ColonToken); 4615 const falseType = allowConditionalTypesAnd(parseType); 4616 return finishNode(factory.createConditionalTypeNode(type, extendsType, trueType, falseType), pos); 4617 } 4618 return type; 4619 } 4620 4621 function parseEtsType(pos: number, name: string): TypeNode { 4622 const contextFlagsToClear = NodeFlags.TypeExcludesFlags & contextFlags; 4623 if (contextFlagsToClear) { 4624 // clear the requested context flags 4625 setContextFlag(/*val*/ false, contextFlagsToClear); 4626 const result = parseEtsTypeReferenceWorker(pos, name); 4627 // restore the context flags we just cleared 4628 setContextFlag(/*val*/ true, contextFlagsToClear); 4629 return result; 4630 } 4631 4632 return parseEtsTypeReferenceWorker(pos, name); 4633 } 4634 4635 function parseEtsTypeReferenceWorker(pos: number, name: string): TypeNode { 4636 return finishVirtualNode( 4637 factory.createTypeReferenceNode( 4638 finishVirtualNode(factory.createIdentifier(name), pos, pos) 4639 ), 4640 pos, pos 4641 ); 4642 } 4643 4644 function parseTypeAnnotation(): TypeNode | undefined { 4645 return parseOptional(SyntaxKind.ColonToken) ? parseType() : undefined; 4646 } 4647 4648 // EXPRESSIONS 4649 function isStartOfLeftHandSideExpression(): boolean { 4650 switch (token()) { 4651 case SyntaxKind.ThisKeyword: 4652 case SyntaxKind.SuperKeyword: 4653 case SyntaxKind.NullKeyword: 4654 case SyntaxKind.TrueKeyword: 4655 case SyntaxKind.FalseKeyword: 4656 case SyntaxKind.NumericLiteral: 4657 case SyntaxKind.BigIntLiteral: 4658 case SyntaxKind.StringLiteral: 4659 case SyntaxKind.NoSubstitutionTemplateLiteral: 4660 case SyntaxKind.TemplateHead: 4661 case SyntaxKind.OpenParenToken: 4662 case SyntaxKind.OpenBracketToken: 4663 case SyntaxKind.OpenBraceToken: 4664 case SyntaxKind.FunctionKeyword: 4665 case SyntaxKind.ClassKeyword: 4666 case SyntaxKind.NewKeyword: 4667 case SyntaxKind.SlashToken: 4668 case SyntaxKind.SlashEqualsToken: 4669 case SyntaxKind.Identifier: 4670 return true; 4671 case SyntaxKind.StructKeyword: 4672 return inEtsContext(); 4673 case SyntaxKind.ImportKeyword: 4674 return lookAhead(nextTokenIsOpenParenOrLessThanOrDot); 4675 default: 4676 return isIdentifier(); 4677 } 4678 } 4679 4680 function isStartOfExpression(): boolean { 4681 if (isStartOfLeftHandSideExpression()) { 4682 return true; 4683 } 4684 4685 switch (token()) { 4686 case SyntaxKind.PlusToken: 4687 case SyntaxKind.MinusToken: 4688 case SyntaxKind.TildeToken: 4689 case SyntaxKind.ExclamationToken: 4690 case SyntaxKind.DeleteKeyword: 4691 case SyntaxKind.TypeOfKeyword: 4692 case SyntaxKind.VoidKeyword: 4693 case SyntaxKind.PlusPlusToken: 4694 case SyntaxKind.MinusMinusToken: 4695 case SyntaxKind.LessThanToken: 4696 case SyntaxKind.AwaitKeyword: 4697 case SyntaxKind.YieldKeyword: 4698 case SyntaxKind.PrivateIdentifier: 4699 // Yield/await always starts an expression. Either it is an identifier (in which case 4700 // it is definitely an expression). Or it's a keyword (either because we're in 4701 // a generator or async function, or in strict mode (or both)) and it started a yield or await expression. 4702 return true; 4703 case SyntaxKind.DotToken: 4704 return isValidExtendOrStylesContext(); 4705 default: 4706 // Error tolerance. If we see the start of some binary operator, we consider 4707 // that the start of an expression. That way we'll parse out a missing identifier, 4708 // give a good message about an identifier being missing, and then consume the 4709 // rest of the binary expression. 4710 if (isBinaryOperator()) { 4711 return true; 4712 } 4713 4714 return isIdentifier(); 4715 } 4716 } 4717 4718 function isValidExtendOrStylesContext(): boolean { 4719 return (inEtsExtendComponentsContext() && !!extendEtsComponentDeclaration) || 4720 (inEtsStylesComponentsContext() && !!stylesEtsComponentDeclaration); 4721 } 4722 4723 function isStartOfExpressionStatement(): boolean { 4724 // As per the grammar, none of '{' or 'function' or 'class' can start an expression statement. 4725 return token() !== SyntaxKind.OpenBraceToken && 4726 token() !== SyntaxKind.FunctionKeyword && 4727 token() !== SyntaxKind.ClassKeyword && 4728 (!inEtsContext() || token() !== SyntaxKind.StructKeyword) && 4729 token() !== SyntaxKind.AtToken && 4730 isStartOfExpression(); 4731 } 4732 4733 function parseExpression(): Expression { 4734 // Expression[in]: 4735 // AssignmentExpression[in] 4736 // Expression[in] , AssignmentExpression[in] 4737 4738 // clear the decorator context when parsing Expression, as it should be unambiguous when parsing a decorator 4739 const saveDecoratorContext = inDecoratorContext(); 4740 if (saveDecoratorContext) { 4741 setDecoratorContext(/*val*/ false); 4742 } 4743 4744 const pos = getNodePos(); 4745 let expr = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true); 4746 let operatorToken: BinaryOperatorToken; 4747 while ((operatorToken = parseOptionalToken(SyntaxKind.CommaToken))) { 4748 expr = makeBinaryExpression(expr, operatorToken, parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true), pos); 4749 } 4750 4751 if (saveDecoratorContext) { 4752 setDecoratorContext(/*val*/ true); 4753 } 4754 return expr; 4755 } 4756 4757 function parseInitializer(): Expression | undefined { 4758 return parseOptional(SyntaxKind.EqualsToken) ? parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true) : undefined; 4759 } 4760 4761 function parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction: boolean): Expression { 4762 // AssignmentExpression[in,yield]: 4763 // 1) ConditionalExpression[?in,?yield] 4764 // 2) LeftHandSideExpression = AssignmentExpression[?in,?yield] 4765 // 3) LeftHandSideExpression AssignmentOperator AssignmentExpression[?in,?yield] 4766 // 4) ArrowFunctionExpression[?in,?yield] 4767 // 5) AsyncArrowFunctionExpression[in,yield,await] 4768 // 6) [+Yield] YieldExpression[?In] 4769 // 4770 // Note: for ease of implementation we treat productions '2' and '3' as the same thing. 4771 // (i.e. they're both BinaryExpressions with an assignment operator in it). 4772 4773 // First, do the simple check if we have a YieldExpression (production '6'). 4774 if (isYieldExpression()) { 4775 return parseYieldExpression(); 4776 } 4777 4778 // Then, check if we have an arrow function (production '4' and '5') that starts with a parenthesized 4779 // parameter list or is an async arrow function. 4780 // AsyncArrowFunctionExpression: 4781 // 1) async[no LineTerminator here]AsyncArrowBindingIdentifier[?Yield][no LineTerminator here]=>AsyncConciseBody[?In] 4782 // 2) CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await][no LineTerminator here]=>AsyncConciseBody[?In] 4783 // Production (1) of AsyncArrowFunctionExpression is parsed in "tryParseAsyncSimpleArrowFunctionExpression". 4784 // And production (2) is parsed in "tryParseParenthesizedArrowFunctionExpression". 4785 // 4786 // If we do successfully parse arrow-function, we must *not* recurse for productions 1, 2 or 3. An ArrowFunction is 4787 // not a LeftHandSideExpression, nor does it start a ConditionalExpression. So we are done 4788 // with AssignmentExpression if we see one. 4789 const arrowExpression = tryParseParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction) || tryParseAsyncSimpleArrowFunctionExpression(allowReturnTypeInArrowFunction); 4790 if (arrowExpression) { 4791 return arrowExpression; 4792 } 4793 4794 // Now try to see if we're in production '1', '2' or '3'. A conditional expression can 4795 // start with a LogicalOrExpression, while the assignment productions can only start with 4796 // LeftHandSideExpressions. 4797 // 4798 // So, first, we try to just parse out a BinaryExpression. If we get something that is a 4799 // LeftHandSide or higher, then we can try to parse out the assignment expression part. 4800 // Otherwise, we try to parse out the conditional expression bit. We want to allow any 4801 // binary expression here, so we pass in the 'lowest' precedence here so that it matches 4802 // and consumes anything. 4803 const pos = getNodePos(); 4804 const expr = parseBinaryExpressionOrHigher(OperatorPrecedence.Lowest); 4805 4806 // To avoid a look-ahead, we did not handle the case of an arrow function with a single un-parenthesized 4807 // parameter ('x => ...') above. We handle it here by checking if the parsed expression was a single 4808 // identifier and the current token is an arrow. 4809 if (expr.kind === SyntaxKind.Identifier && token() === SyntaxKind.EqualsGreaterThanToken) { 4810 return parseSimpleArrowFunctionExpression(pos, expr as Identifier, allowReturnTypeInArrowFunction, /*asyncModifier*/ undefined); 4811 } 4812 4813 // Now see if we might be in cases '2' or '3'. 4814 // If the expression was a LHS expression, and we have an assignment operator, then 4815 // we're in '2' or '3'. Consume the assignment and return. 4816 // 4817 // Note: we call reScanGreaterToken so that we get an appropriately merged token 4818 // for cases like `> > =` becoming `>>=` 4819 if (isLeftHandSideExpression(expr) && isAssignmentOperator(reScanGreaterToken())) { 4820 return makeBinaryExpression(expr, parseTokenNode(), parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction), pos); 4821 } 4822 4823 // It's a CallExpression with open brace followed, therefore, we think it's an EtsComponentExpression 4824 if ((inBuildContext() || inBuilderContext()) && inUICallbackContext() && ts.isCallExpression(expr) && token() === SyntaxKind.OpenBraceToken) { 4825 return makeEtsComponentExpression(expr, pos); 4826 } 4827 4828 // It wasn't an assignment or a lambda. This is a conditional expression: 4829 return parseConditionalExpressionRest(expr, pos, allowReturnTypeInArrowFunction); 4830 } 4831 4832 function makeEtsComponentExpression(expression: Expression, pos: number): EtsComponentExpression { 4833 const name = (<CallExpression>expression).expression; 4834 const body = parseFunctionBlock(SignatureFlags.None); 4835 return finishNode(factory.createEtsComponentExpression(<Identifier>name, (<CallExpression>expression).arguments, body), pos); 4836 } 4837 4838 function isYieldExpression(): boolean { 4839 if (token() === SyntaxKind.YieldKeyword) { 4840 // If we have a 'yield' keyword, and this is a context where yield expressions are 4841 // allowed, then definitely parse out a yield expression. 4842 if (inYieldContext()) { 4843 return true; 4844 } 4845 4846 // We're in a context where 'yield expr' is not allowed. However, if we can 4847 // definitely tell that the user was trying to parse a 'yield expr' and not 4848 // just a normal expr that start with a 'yield' identifier, then parse out 4849 // a 'yield expr'. We can then report an error later that they are only 4850 // allowed in generator expressions. 4851 // 4852 // for example, if we see 'yield(foo)', then we'll have to treat that as an 4853 // invocation expression of something called 'yield'. However, if we have 4854 // 'yield foo' then that is not legal as a normal expression, so we can 4855 // definitely recognize this as a yield expression. 4856 // 4857 // for now we just check if the next token is an identifier. More heuristics 4858 // can be added here later as necessary. We just need to make sure that we 4859 // don't accidentally consume something legal. 4860 return lookAhead(nextTokenIsIdentifierOrKeywordOrLiteralOnSameLine); 4861 } 4862 4863 return false; 4864 } 4865 4866 function nextTokenIsIdentifierOnSameLine() { 4867 nextToken(); 4868 return !scanner.hasPrecedingLineBreak() && isIdentifier(); 4869 } 4870 4871 function parseYieldExpression(): YieldExpression { 4872 const pos = getNodePos(); 4873 4874 // YieldExpression[In] : 4875 // yield 4876 // yield [no LineTerminator here] [Lexical goal InputElementRegExp]AssignmentExpression[?In, Yield] 4877 // yield [no LineTerminator here] * [Lexical goal InputElementRegExp]AssignmentExpression[?In, Yield] 4878 nextToken(); 4879 4880 if (!scanner.hasPrecedingLineBreak() && 4881 (token() === SyntaxKind.AsteriskToken || isStartOfExpression())) { 4882 return finishNode( 4883 factory.createYieldExpression( 4884 parseOptionalToken(SyntaxKind.AsteriskToken), 4885 parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true) 4886 ), 4887 pos 4888 ); 4889 } 4890 else { 4891 // if the next token is not on the same line as yield. or we don't have an '*' or 4892 // the start of an expression, then this is just a simple "yield" expression. 4893 return finishNode(factory.createYieldExpression(/*asteriskToken*/ undefined, /*expression*/ undefined), pos); 4894 } 4895 } 4896 4897 function parseSimpleArrowFunctionExpression(pos: number, identifier: Identifier, allowReturnTypeInArrowFunction: boolean, asyncModifier?: NodeArray<Modifier> | undefined): ArrowFunction { 4898 Debug.assert(token() === SyntaxKind.EqualsGreaterThanToken, "parseSimpleArrowFunctionExpression should only have been called if we had a =>"); 4899 const parameter = factory.createParameterDeclaration( 4900 /*modifiers*/ undefined, 4901 /*dotDotDotToken*/ undefined, 4902 identifier, 4903 /*questionToken*/ undefined, 4904 /*type*/ undefined, 4905 /*initializer*/ undefined 4906 ); 4907 finishNode(parameter, identifier.pos); 4908 4909 const parameters = createNodeArray<ParameterDeclaration>([parameter], parameter.pos, parameter.end); 4910 const equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken); 4911 const body = parseArrowFunctionExpressionBody(/*isAsync*/ !!asyncModifier, allowReturnTypeInArrowFunction); 4912 const node = factory.createArrowFunction(asyncModifier, /*typeParameters*/ undefined, parameters, /*type*/ undefined, equalsGreaterThanToken, body); 4913 return addJSDocComment(finishNode(node, pos)); 4914 } 4915 4916 function tryParseParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction: boolean): Expression | undefined { 4917 const triState = isParenthesizedArrowFunctionExpression(); 4918 if (triState === Tristate.False) { 4919 // It's definitely not a parenthesized arrow function expression. 4920 return undefined; 4921 } 4922 4923 // If we definitely have an arrow function, then we can just parse one, not requiring a 4924 // following => or { token. Otherwise, we *might* have an arrow function. Try to parse 4925 // it out, but don't allow any ambiguity, and return 'undefined' if this could be an 4926 // expression instead. 4927 return triState === Tristate.True ? 4928 parseParenthesizedArrowFunctionExpression(/*allowAmbiguity*/ true, /*allowReturnTypeInArrowFunction*/ true) : 4929 tryParse(() => parsePossibleParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction)); 4930 } 4931 4932 // True -> We definitely expect a parenthesized arrow function here. 4933 // False -> There *cannot* be a parenthesized arrow function here. 4934 // Unknown -> There *might* be a parenthesized arrow function here. 4935 // Speculatively look ahead to be sure, and rollback if not. 4936 function isParenthesizedArrowFunctionExpression(): Tristate { 4937 if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken || token() === SyntaxKind.AsyncKeyword) { 4938 return lookAhead(isParenthesizedArrowFunctionExpressionWorker); 4939 } 4940 4941 if (token() === SyntaxKind.EqualsGreaterThanToken) { 4942 // ERROR RECOVERY TWEAK: 4943 // If we see a standalone => try to parse it as an arrow function expression as that's 4944 // likely what the user intended to write. 4945 return Tristate.True; 4946 } 4947 // Definitely not a parenthesized arrow function. 4948 return Tristate.False; 4949 } 4950 4951 function isParenthesizedArrowFunctionExpressionWorker() { 4952 if (token() === SyntaxKind.AsyncKeyword) { 4953 nextToken(); 4954 if (scanner.hasPrecedingLineBreak()) { 4955 return Tristate.False; 4956 } 4957 if (token() !== SyntaxKind.OpenParenToken && token() !== SyntaxKind.LessThanToken) { 4958 return Tristate.False; 4959 } 4960 } 4961 4962 const first = token(); 4963 const second = nextToken(); 4964 4965 if (first === SyntaxKind.OpenParenToken) { 4966 if (second === SyntaxKind.CloseParenToken) { 4967 // Simple cases: "() =>", "(): ", and "() {". 4968 // This is an arrow function with no parameters. 4969 // The last one is not actually an arrow function, 4970 // but this is probably what the user intended. 4971 const third = nextToken(); 4972 switch (third) { 4973 case SyntaxKind.EqualsGreaterThanToken: 4974 case SyntaxKind.ColonToken: 4975 case SyntaxKind.OpenBraceToken: 4976 return Tristate.True; 4977 default: 4978 return Tristate.False; 4979 } 4980 } 4981 4982 // If encounter "([" or "({", this could be the start of a binding pattern. 4983 // Examples: 4984 // ([ x ]) => { } 4985 // ({ x }) => { } 4986 // ([ x ]) 4987 // ({ x }) 4988 if (second === SyntaxKind.OpenBracketToken || second === SyntaxKind.OpenBraceToken) { 4989 return Tristate.Unknown; 4990 } 4991 4992 // Simple case: "(..." 4993 // This is an arrow function with a rest parameter. 4994 if (second === SyntaxKind.DotDotDotToken) { 4995 return Tristate.True; 4996 } 4997 4998 // Check for "(xxx yyy", where xxx is a modifier and yyy is an identifier. This 4999 // isn't actually allowed, but we want to treat it as a lambda so we can provide 5000 // a good error message. 5001 if (isModifierKind(second) && second !== SyntaxKind.AsyncKeyword && lookAhead(nextTokenIsIdentifier)) { 5002 if (nextToken() === SyntaxKind.AsKeyword) { 5003 // https://github.com/microsoft/TypeScript/issues/44466 5004 return Tristate.False; 5005 } 5006 return Tristate.True; 5007 } 5008 5009 // If we had "(" followed by something that's not an identifier, 5010 // then this definitely doesn't look like a lambda. "this" is not 5011 // valid, but we want to parse it and then give a semantic error. 5012 if (!isIdentifier() && second !== SyntaxKind.ThisKeyword) { 5013 return Tristate.False; 5014 } 5015 5016 switch (nextToken()) { 5017 case SyntaxKind.ColonToken: 5018 // If we have something like "(a:", then we must have a 5019 // type-annotated parameter in an arrow function expression. 5020 return Tristate.True; 5021 case SyntaxKind.QuestionToken: 5022 nextToken(); 5023 // If we have "(a?:" or "(a?," or "(a?=" or "(a?)" then it is definitely a lambda. 5024 if (token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken || token() === SyntaxKind.EqualsToken || token() === SyntaxKind.CloseParenToken) { 5025 return Tristate.True; 5026 } 5027 // Otherwise it is definitely not a lambda. 5028 return Tristate.False; 5029 case SyntaxKind.CommaToken: 5030 case SyntaxKind.EqualsToken: 5031 case SyntaxKind.CloseParenToken: 5032 // If we have "(a," or "(a=" or "(a)" this *could* be an arrow function 5033 return Tristate.Unknown; 5034 } 5035 // It is definitely not an arrow function 5036 return Tristate.False; 5037 } 5038 else { 5039 Debug.assert(first === SyntaxKind.LessThanToken); 5040 5041 // If we have "<" not followed by an identifier, 5042 // then this definitely is not an arrow function. 5043 if (!isIdentifier()) { 5044 return Tristate.False; 5045 } 5046 5047 // JSX overrides 5048 if (languageVariant === LanguageVariant.JSX) { 5049 const isArrowFunctionInJsx = lookAhead(() => { 5050 const third = nextToken(); 5051 if (third === SyntaxKind.ExtendsKeyword) { 5052 const fourth = nextToken(); 5053 switch (fourth) { 5054 case SyntaxKind.EqualsToken: 5055 case SyntaxKind.GreaterThanToken: 5056 return false; 5057 default: 5058 return true; 5059 } 5060 } 5061 else if (third === SyntaxKind.CommaToken || third === SyntaxKind.EqualsToken) { 5062 return true; 5063 } 5064 return false; 5065 }); 5066 5067 if (isArrowFunctionInJsx) { 5068 return Tristate.True; 5069 } 5070 5071 return Tristate.False; 5072 } 5073 5074 // This *could* be a parenthesized arrow function. 5075 return Tristate.Unknown; 5076 } 5077 } 5078 5079 function parsePossibleParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction: boolean): ArrowFunction | undefined { 5080 const tokenPos = scanner.getTokenPos(); 5081 if (notParenthesizedArrow?.has(tokenPos)) { 5082 return undefined; 5083 } 5084 5085 const result = parseParenthesizedArrowFunctionExpression(/*allowAmbiguity*/ false, allowReturnTypeInArrowFunction); 5086 if (!result) { 5087 (notParenthesizedArrow || (notParenthesizedArrow = new Set())).add(tokenPos); 5088 } 5089 5090 return result; 5091 } 5092 5093 function tryParseAsyncSimpleArrowFunctionExpression(allowReturnTypeInArrowFunction: boolean): ArrowFunction | undefined { 5094 // We do a check here so that we won't be doing unnecessarily call to "lookAhead" 5095 if (token() === SyntaxKind.AsyncKeyword) { 5096 if (lookAhead(isUnParenthesizedAsyncArrowFunctionWorker) === Tristate.True) { 5097 const pos = getNodePos(); 5098 const asyncModifier = parseModifiersForArrowFunction(); 5099 const expr = parseBinaryExpressionOrHigher(OperatorPrecedence.Lowest); 5100 return parseSimpleArrowFunctionExpression(pos, expr as Identifier, allowReturnTypeInArrowFunction, asyncModifier); 5101 } 5102 } 5103 return undefined; 5104 } 5105 5106 function isUnParenthesizedAsyncArrowFunctionWorker(): Tristate { 5107 // AsyncArrowFunctionExpression: 5108 // 1) async[no LineTerminator here]AsyncArrowBindingIdentifier[?Yield][no LineTerminator here]=>AsyncConciseBody[?In] 5109 // 2) CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await][no LineTerminator here]=>AsyncConciseBody[?In] 5110 if (token() === SyntaxKind.AsyncKeyword) { 5111 nextToken(); 5112 // If the "async" is followed by "=>" token then it is not a beginning of an async arrow-function 5113 // but instead a simple arrow-function which will be parsed inside "parseAssignmentExpressionOrHigher" 5114 if (scanner.hasPrecedingLineBreak() || token() === SyntaxKind.EqualsGreaterThanToken) { 5115 return Tristate.False; 5116 } 5117 // Check for un-parenthesized AsyncArrowFunction 5118 const expr = parseBinaryExpressionOrHigher(OperatorPrecedence.Lowest); 5119 if (!scanner.hasPrecedingLineBreak() && expr.kind === SyntaxKind.Identifier && token() === SyntaxKind.EqualsGreaterThanToken) { 5120 return Tristate.True; 5121 } 5122 } 5123 5124 return Tristate.False; 5125 } 5126 5127 function parseParenthesizedArrowFunctionExpression(allowAmbiguity: boolean, allowReturnTypeInArrowFunction: boolean): ArrowFunction | undefined { 5128 const pos = getNodePos(); 5129 const hasJSDoc = hasPrecedingJSDocComment(); 5130 const modifiers = parseModifiersForArrowFunction(); 5131 const isAsync = some(modifiers, isAsyncModifier) ? SignatureFlags.Await : SignatureFlags.None; 5132 // Arrow functions are never generators. 5133 // 5134 // If we're speculatively parsing a signature for a parenthesized arrow function, then 5135 // we have to have a complete parameter list. Otherwise we might see something like 5136 // a => (b => c) 5137 // And think that "(b =>" was actually a parenthesized arrow function with a missing 5138 // close paren. 5139 const typeParameters = parseTypeParameters(); 5140 5141 let parameters: NodeArray<ParameterDeclaration>; 5142 if (!parseExpected(SyntaxKind.OpenParenToken)) { 5143 if (!allowAmbiguity) { 5144 return undefined; 5145 } 5146 parameters = createMissingList<ParameterDeclaration>(); 5147 } 5148 else { 5149 if (!allowAmbiguity) { 5150 const maybeParameters = parseParametersWorker(isAsync, allowAmbiguity); 5151 if (!maybeParameters) { 5152 return undefined; 5153 } 5154 parameters = maybeParameters; 5155 } 5156 else { 5157 parameters = parseParametersWorker(isAsync, allowAmbiguity); 5158 } 5159 if (!parseExpected(SyntaxKind.CloseParenToken) && !allowAmbiguity) { 5160 return undefined; 5161 } 5162 } 5163 5164 const hasReturnColon = token() === SyntaxKind.ColonToken; 5165 const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false); 5166 if (type && !allowAmbiguity && typeHasArrowFunctionBlockingParseError(type)) { 5167 return undefined; 5168 } 5169 5170 // Parsing a signature isn't enough. 5171 // Parenthesized arrow signatures often look like other valid expressions. 5172 // For instance: 5173 // - "(x = 10)" is an assignment expression parsed as a signature with a default parameter value. 5174 // - "(x,y)" is a comma expression parsed as a signature with two parameters. 5175 // - "a ? (b): c" will have "(b):" parsed as a signature with a return type annotation. 5176 // - "a ? (b): function() {}" will too, since function() is a valid JSDoc function type. 5177 // - "a ? (b): (function() {})" as well, but inside of a parenthesized type with an arbitrary amount of nesting. 5178 // 5179 // So we need just a bit of lookahead to ensure that it can only be a signature. 5180 5181 let unwrappedType = type; 5182 while (unwrappedType?.kind === SyntaxKind.ParenthesizedType) { 5183 unwrappedType = (unwrappedType as ParenthesizedTypeNode).type; // Skip parens if need be 5184 } 5185 5186 const hasJSDocFunctionType = unwrappedType && isJSDocFunctionType(unwrappedType); 5187 if (!allowAmbiguity && token() !== SyntaxKind.EqualsGreaterThanToken && (hasJSDocFunctionType || token() !== SyntaxKind.OpenBraceToken)) { 5188 // Returning undefined here will cause our caller to rewind to where we started from. 5189 return undefined; 5190 } 5191 5192 // If we have an arrow, then try to parse the body. Even if not, try to parse if we 5193 // have an opening brace, just in case we're in an error state. 5194 const lastToken = token(); 5195 const equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken); 5196 let originUIContextFlag = inUICallbackContext() 5197 setUICallbackContext(inSyntaxComponentContext() ? true : false); 5198 setSyntaxComponentContext(false); 5199 const body = (lastToken === SyntaxKind.EqualsGreaterThanToken || lastToken === SyntaxKind.OpenBraceToken) 5200 ? parseArrowFunctionExpressionBody(some(modifiers, isAsyncModifier), allowReturnTypeInArrowFunction) 5201 : parseIdentifier(); 5202 setUICallbackContext(originUIContextFlag); 5203 // Given: 5204 // x ? y => ({ y }) : z => ({ z }) 5205 // We try to parse the body of the first arrow function by looking at: 5206 // ({ y }) : z => ({ z }) 5207 // This is a valid arrow function with "z" as the return type. 5208 // 5209 // But, if we're in the true side of a conditional expression, this colon 5210 // terminates the expression, so we cannot allow a return type if we aren't 5211 // certain whether or not the preceding text was parsed as a parameter list. 5212 // 5213 // For example, 5214 // a() ? (b: number, c?: string): void => d() : e 5215 // is determined by isParenthesizedArrowFunctionExpression to unambiguously 5216 // be an arrow expression, so we allow a return type. 5217 if (!allowReturnTypeInArrowFunction && hasReturnColon) { 5218 // However, if the arrow function we were able to parse is followed by another colon 5219 // as in: 5220 // a ? (x): string => x : null 5221 // Then allow the arrow function, and treat the second colon as terminating 5222 // the conditional expression. It's okay to do this because this code would 5223 // be a syntax error in JavaScript (as the second colon shouldn't be there). 5224 if (token() !== SyntaxKind.ColonToken) { 5225 return undefined; 5226 } 5227 } 5228 5229 const node = factory.createArrowFunction(modifiers, typeParameters, parameters, type, equalsGreaterThanToken, body); 5230 return withJSDoc(finishNode(node, pos), hasJSDoc); 5231 } 5232 5233 function parseArrowFunctionExpressionBody(isAsync: boolean, allowReturnTypeInArrowFunction: boolean): Block | Expression { 5234 if (token() === SyntaxKind.OpenBraceToken) { 5235 return parseFunctionBlock(isAsync ? SignatureFlags.Await : SignatureFlags.None); 5236 } 5237 5238 if (token() !== SyntaxKind.SemicolonToken && 5239 token() !== SyntaxKind.FunctionKeyword && 5240 token() !== SyntaxKind.ClassKeyword && 5241 (!inEtsContext() || token() !== SyntaxKind.StructKeyword) && 5242 isStartOfStatement() && 5243 !isStartOfExpressionStatement()) { 5244 // Check if we got a plain statement (i.e. no expression-statements, no function/class expressions/declarations) 5245 // 5246 // Here we try to recover from a potential error situation in the case where the 5247 // user meant to supply a block. For example, if the user wrote: 5248 // 5249 // a => 5250 // let v = 0; 5251 // } 5252 // 5253 // they may be missing an open brace. Check to see if that's the case so we can 5254 // try to recover better. If we don't do this, then the next close curly we see may end 5255 // up preemptively closing the containing construct. 5256 // 5257 // Note: even when 'IgnoreMissingOpenBrace' is passed, parseBody will still error. 5258 return parseFunctionBlock(SignatureFlags.IgnoreMissingOpenBrace | (isAsync ? SignatureFlags.Await : SignatureFlags.None)); 5259 } 5260 5261 const savedTopLevel = topLevel; 5262 topLevel = false; 5263 const node = isAsync 5264 ? doInAwaitContext(() => parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction)) 5265 : doOutsideOfAwaitContext(() => parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction)); 5266 topLevel = savedTopLevel; 5267 return node; 5268 } 5269 5270 function parseConditionalExpressionRest(leftOperand: Expression, pos: number, allowReturnTypeInArrowFunction: boolean): Expression { 5271 // Note: we are passed in an expression which was produced from parseBinaryExpressionOrHigher. 5272 const questionToken = parseOptionalToken(SyntaxKind.QuestionToken); 5273 if (!questionToken) { 5274 return leftOperand; 5275 } 5276 5277 // Note: we explicitly 'allowIn' in the whenTrue part of the condition expression, and 5278 // we do not that for the 'whenFalse' part. 5279 let colonToken; 5280 return finishNode( 5281 factory.createConditionalExpression( 5282 leftOperand, 5283 questionToken, 5284 doOutsideOfContext(disallowInAndDecoratorContext, () => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ false)), 5285 colonToken = parseExpectedToken(SyntaxKind.ColonToken), 5286 nodeIsPresent(colonToken) 5287 ? parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction) 5288 : createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, tokenToString(SyntaxKind.ColonToken)) 5289 ), 5290 pos 5291 ); 5292 } 5293 5294 function parseBinaryExpressionOrHigher(precedence: OperatorPrecedence): Expression { 5295 const pos = getNodePos(); 5296 const leftOperand = parseUnaryExpressionOrHigher(); 5297 return parseBinaryExpressionRest(precedence, leftOperand, pos); 5298 } 5299 5300 function isInOrOfKeyword(t: SyntaxKind) { 5301 return t === SyntaxKind.InKeyword || t === SyntaxKind.OfKeyword; 5302 } 5303 5304 function parseBinaryExpressionRest(precedence: OperatorPrecedence, leftOperand: Expression, pos: number): Expression { 5305 while (true) { 5306 // We either have a binary operator here, or we're finished. We call 5307 // reScanGreaterToken so that we merge token sequences like > and = into >= 5308 5309 reScanGreaterToken(); 5310 const newPrecedence = getBinaryOperatorPrecedence(token()); 5311 5312 // Check the precedence to see if we should "take" this operator 5313 // - For left associative operator (all operator but **), consume the operator, 5314 // recursively call the function below, and parse binaryExpression as a rightOperand 5315 // of the caller if the new precedence of the operator is greater then or equal to the current precedence. 5316 // For example: 5317 // a - b - c; 5318 // ^token; leftOperand = b. Return b to the caller as a rightOperand 5319 // a * b - c 5320 // ^token; leftOperand = b. Return b to the caller as a rightOperand 5321 // a - b * c; 5322 // ^token; leftOperand = b. Return b * c to the caller as a rightOperand 5323 // - For right associative operator (**), consume the operator, recursively call the function 5324 // and parse binaryExpression as a rightOperand of the caller if the new precedence of 5325 // the operator is strictly grater than the current precedence 5326 // For example: 5327 // a ** b ** c; 5328 // ^^token; leftOperand = b. Return b ** c to the caller as a rightOperand 5329 // a - b ** c; 5330 // ^^token; leftOperand = b. Return b ** c to the caller as a rightOperand 5331 // a ** b - c 5332 // ^token; leftOperand = b. Return b to the caller as a rightOperand 5333 const consumeCurrentOperator = token() === SyntaxKind.AsteriskAsteriskToken ? 5334 newPrecedence >= precedence : 5335 newPrecedence > precedence; 5336 5337 if (!consumeCurrentOperator) { 5338 break; 5339 } 5340 5341 if (token() === SyntaxKind.InKeyword && inDisallowInContext()) { 5342 break; 5343 } 5344 5345 if (token() === SyntaxKind.AsKeyword || token() === SyntaxKind.SatisfiesKeyword) { 5346 // Make sure we *do* perform ASI for constructs like this: 5347 // var x = foo 5348 // as (Bar) 5349 // This should be parsed as an initialized variable, followed 5350 // by a function call to 'as' with the argument 'Bar' 5351 if (scanner.hasPrecedingLineBreak()) { 5352 break; 5353 } 5354 else { 5355 const keywordKind = token(); 5356 nextToken(); 5357 leftOperand = keywordKind === SyntaxKind.SatisfiesKeyword ? makeSatisfiesExpression(leftOperand, parseType()) : 5358 makeAsExpression(leftOperand, parseType()); 5359 } 5360 } 5361 else { 5362 leftOperand = makeBinaryExpression(leftOperand, parseTokenNode(), parseBinaryExpressionOrHigher(newPrecedence), pos); 5363 } 5364 } 5365 5366 return leftOperand; 5367 } 5368 5369 function isBinaryOperator() { 5370 if (inDisallowInContext() && token() === SyntaxKind.InKeyword) { 5371 return false; 5372 } 5373 5374 return getBinaryOperatorPrecedence(token()) > 0; 5375 } 5376 5377 function makeSatisfiesExpression(left: Expression, right: TypeNode): SatisfiesExpression { 5378 return finishNode(factory.createSatisfiesExpression(left, right), left.pos); 5379 } 5380 5381 function makeBinaryExpression(left: Expression, operatorToken: BinaryOperatorToken, right: Expression, pos: number): BinaryExpression { 5382 return finishNode(factory.createBinaryExpression(left, operatorToken, right), pos); 5383 } 5384 5385 function makeAsExpression(left: Expression, right: TypeNode): AsExpression { 5386 return finishNode(factory.createAsExpression(left, right), left.pos); 5387 } 5388 5389 function parsePrefixUnaryExpression() { 5390 const pos = getNodePos(); 5391 return finishNode(factory.createPrefixUnaryExpression(token() as PrefixUnaryOperator, nextTokenAnd(parseSimpleUnaryExpression)), pos); 5392 } 5393 5394 function parseDeleteExpression() { 5395 const pos = getNodePos(); 5396 return finishNode(factory.createDeleteExpression(nextTokenAnd(parseSimpleUnaryExpression)), pos); 5397 } 5398 5399 function parseTypeOfExpression() { 5400 const pos = getNodePos(); 5401 return finishNode(factory.createTypeOfExpression(nextTokenAnd(parseSimpleUnaryExpression)), pos); 5402 } 5403 5404 function parseVoidExpression() { 5405 const pos = getNodePos(); 5406 return finishNode(factory.createVoidExpression(nextTokenAnd(parseSimpleUnaryExpression)), pos); 5407 } 5408 5409 function isAwaitExpression(): boolean { 5410 if (token() === SyntaxKind.AwaitKeyword) { 5411 if (inAwaitContext()) { 5412 return true; 5413 } 5414 5415 // here we are using similar heuristics as 'isYieldExpression' 5416 return lookAhead(nextTokenIsIdentifierOrKeywordOrLiteralOnSameLine); 5417 } 5418 5419 return false; 5420 } 5421 5422 function parseAwaitExpression() { 5423 const pos = getNodePos(); 5424 return finishNode(factory.createAwaitExpression(nextTokenAnd(parseSimpleUnaryExpression)), pos); 5425 } 5426 5427 /** 5428 * Parse ES7 exponential expression and await expression 5429 * 5430 * ES7 ExponentiationExpression: 5431 * 1) UnaryExpression[?Yield] 5432 * 2) UpdateExpression[?Yield] ** ExponentiationExpression[?Yield] 5433 * 5434 */ 5435 function parseUnaryExpressionOrHigher(): UnaryExpression | BinaryExpression { 5436 /** 5437 * ES7 UpdateExpression: 5438 * 1) LeftHandSideExpression[?Yield] 5439 * 2) LeftHandSideExpression[?Yield][no LineTerminator here]++ 5440 * 3) LeftHandSideExpression[?Yield][no LineTerminator here]-- 5441 * 4) ++UnaryExpression[?Yield] 5442 * 5) --UnaryExpression[?Yield] 5443 */ 5444 if (isUpdateExpression()) { 5445 const pos = getNodePos(); 5446 const updateExpression = parseUpdateExpression(); 5447 return token() === SyntaxKind.AsteriskAsteriskToken ? 5448 parseBinaryExpressionRest(getBinaryOperatorPrecedence(token()), updateExpression, pos) as BinaryExpression : 5449 updateExpression; 5450 } 5451 5452 /** 5453 * ES7 UnaryExpression: 5454 * 1) UpdateExpression[?yield] 5455 * 2) delete UpdateExpression[?yield] 5456 * 3) void UpdateExpression[?yield] 5457 * 4) typeof UpdateExpression[?yield] 5458 * 5) + UpdateExpression[?yield] 5459 * 6) - UpdateExpression[?yield] 5460 * 7) ~ UpdateExpression[?yield] 5461 * 8) ! UpdateExpression[?yield] 5462 */ 5463 const unaryOperator = token(); 5464 const simpleUnaryExpression = parseSimpleUnaryExpression(); 5465 if (token() === SyntaxKind.AsteriskAsteriskToken) { 5466 const pos = skipTrivia(sourceText, simpleUnaryExpression.pos); 5467 const { end } = simpleUnaryExpression; 5468 if (simpleUnaryExpression.kind === SyntaxKind.TypeAssertionExpression) { 5469 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); 5470 } 5471 else { 5472 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)); 5473 } 5474 } 5475 return simpleUnaryExpression; 5476 } 5477 5478 /** 5479 * Parse ES7 simple-unary expression or higher: 5480 * 5481 * ES7 UnaryExpression: 5482 * 1) UpdateExpression[?yield] 5483 * 2) delete UnaryExpression[?yield] 5484 * 3) void UnaryExpression[?yield] 5485 * 4) typeof UnaryExpression[?yield] 5486 * 5) + UnaryExpression[?yield] 5487 * 6) - UnaryExpression[?yield] 5488 * 7) ~ UnaryExpression[?yield] 5489 * 8) ! UnaryExpression[?yield] 5490 * 9) [+Await] await UnaryExpression[?yield] 5491 */ 5492 function parseSimpleUnaryExpression(): UnaryExpression { 5493 switch (token()) { 5494 case SyntaxKind.PlusToken: 5495 case SyntaxKind.MinusToken: 5496 case SyntaxKind.TildeToken: 5497 case SyntaxKind.ExclamationToken: 5498 return parsePrefixUnaryExpression(); 5499 case SyntaxKind.DeleteKeyword: 5500 return parseDeleteExpression(); 5501 case SyntaxKind.TypeOfKeyword: 5502 return parseTypeOfExpression(); 5503 case SyntaxKind.VoidKeyword: 5504 return parseVoidExpression(); 5505 case SyntaxKind.LessThanToken: 5506 // This is modified UnaryExpression grammar in TypeScript 5507 // UnaryExpression (modified): 5508 // < type > UnaryExpression 5509 return parseTypeAssertion(); 5510 case SyntaxKind.AwaitKeyword: 5511 if (isAwaitExpression()) { 5512 return parseAwaitExpression(); 5513 } 5514 // falls through 5515 default: 5516 return parseUpdateExpression(); 5517 } 5518 } 5519 5520 /** 5521 * Check if the current token can possibly be an ES7 increment expression. 5522 * 5523 * ES7 UpdateExpression: 5524 * LeftHandSideExpression[?Yield] 5525 * LeftHandSideExpression[?Yield][no LineTerminator here]++ 5526 * LeftHandSideExpression[?Yield][no LineTerminator here]-- 5527 * ++LeftHandSideExpression[?Yield] 5528 * --LeftHandSideExpression[?Yield] 5529 */ 5530 function isUpdateExpression(): boolean { 5531 // This function is called inside parseUnaryExpression to decide 5532 // whether to call parseSimpleUnaryExpression or call parseUpdateExpression directly 5533 switch (token()) { 5534 case SyntaxKind.PlusToken: 5535 case SyntaxKind.MinusToken: 5536 case SyntaxKind.TildeToken: 5537 case SyntaxKind.ExclamationToken: 5538 case SyntaxKind.DeleteKeyword: 5539 case SyntaxKind.TypeOfKeyword: 5540 case SyntaxKind.VoidKeyword: 5541 case SyntaxKind.AwaitKeyword: 5542 return false; 5543 case SyntaxKind.LessThanToken: 5544 // If we are not in JSX context, we are parsing TypeAssertion which is an UnaryExpression 5545 if (languageVariant !== LanguageVariant.JSX) { 5546 return false; 5547 } 5548 // We are in JSX context and the token is part of JSXElement. 5549 // falls through 5550 default: 5551 return true; 5552 } 5553 } 5554 5555 /** 5556 * Parse ES7 UpdateExpression. UpdateExpression is used instead of ES6's PostFixExpression. 5557 * 5558 * ES7 UpdateExpression[yield]: 5559 * 1) LeftHandSideExpression[?yield] 5560 * 2) LeftHandSideExpression[?yield] [[no LineTerminator here]]++ 5561 * 3) LeftHandSideExpression[?yield] [[no LineTerminator here]]-- 5562 * 4) ++LeftHandSideExpression[?yield] 5563 * 5) --LeftHandSideExpression[?yield] 5564 * In TypeScript (2), (3) are parsed as PostfixUnaryExpression. (4), (5) are parsed as PrefixUnaryExpression 5565 */ 5566 function parseUpdateExpression(): UpdateExpression { 5567 if (token() === SyntaxKind.PlusPlusToken || token() === SyntaxKind.MinusMinusToken) { 5568 const pos = getNodePos(); 5569 return finishNode(factory.createPrefixUnaryExpression(token() as PrefixUnaryOperator, nextTokenAnd(parseLeftHandSideExpressionOrHigher)), pos); 5570 } 5571 else if (languageVariant === LanguageVariant.JSX && token() === SyntaxKind.LessThanToken && lookAhead(nextTokenIsIdentifierOrKeywordOrGreaterThan)) { 5572 // JSXElement is part of primaryExpression 5573 return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true); 5574 } 5575 5576 const expression = parseLeftHandSideExpressionOrHigher(); 5577 5578 Debug.assert(isLeftHandSideExpression(expression)); 5579 if ((token() === SyntaxKind.PlusPlusToken || token() === SyntaxKind.MinusMinusToken) && !scanner.hasPrecedingLineBreak()) { 5580 const operator = token() as PostfixUnaryOperator; 5581 nextToken(); 5582 return finishNode(factory.createPostfixUnaryExpression(expression, operator), expression.pos); 5583 } 5584 5585 return expression; 5586 } 5587 5588 function parseLeftHandSideExpressionOrHigher(): LeftHandSideExpression { 5589 // Original Ecma: 5590 // LeftHandSideExpression: See 11.2 5591 // NewExpression 5592 // CallExpression 5593 // 5594 // Our simplification: 5595 // 5596 // LeftHandSideExpression: See 11.2 5597 // MemberExpression 5598 // CallExpression 5599 // 5600 // See comment in parseMemberExpressionOrHigher on how we replaced NewExpression with 5601 // MemberExpression to make our lives easier. 5602 // 5603 // to best understand the below code, it's important to see how CallExpression expands 5604 // out into its own productions: 5605 // 5606 // CallExpression: 5607 // MemberExpression Arguments 5608 // CallExpression Arguments 5609 // CallExpression[Expression] 5610 // CallExpression.IdentifierName 5611 // import (AssignmentExpression) 5612 // super Arguments 5613 // super.IdentifierName 5614 // 5615 // Because of the recursion in these calls, we need to bottom out first. There are three 5616 // bottom out states we can run into: 1) We see 'super' which must start either of 5617 // the last two CallExpression productions. 2) We see 'import' which must start import call. 5618 // 3)we have a MemberExpression which either completes the LeftHandSideExpression, 5619 // or starts the beginning of the first four CallExpression productions. 5620 const pos = getNodePos(); 5621 let expression: MemberExpression; 5622 if (token() === SyntaxKind.ImportKeyword) { 5623 if (lookAhead(nextTokenIsOpenParenOrLessThan)) { 5624 // We don't want to eagerly consume all import keyword as import call expression so we look ahead to find "(" 5625 // For example: 5626 // var foo3 = require("subfolder 5627 // import * as foo1 from "module-from-node 5628 // We want this import to be a statement rather than import call expression 5629 sourceFlags |= NodeFlags.PossiblyContainsDynamicImport; 5630 expression = parseTokenNode<PrimaryExpression>(); 5631 } 5632 else if (lookAhead(nextTokenIsDot)) { 5633 // This is an 'import.*' metaproperty (i.e. 'import.meta') 5634 nextToken(); // advance past the 'import' 5635 nextToken(); // advance past the dot 5636 expression = finishNode(factory.createMetaProperty(SyntaxKind.ImportKeyword, parseIdentifierName()), pos); 5637 sourceFlags |= NodeFlags.PossiblyContainsImportMeta; 5638 } 5639 else { 5640 expression = parseMemberExpressionOrHigher(); 5641 } 5642 } 5643 else { 5644 expression = token() === SyntaxKind.SuperKeyword ? parseSuperExpression() : parseMemberExpressionOrHigher(); 5645 } 5646 5647 // Now, we *may* be complete. However, we might have consumed the start of a 5648 // CallExpression or OptionalExpression. As such, we need to consume the rest 5649 // of it here to be complete. 5650 return parseCallExpressionRest(pos, expression); 5651 } 5652 5653 function parseMemberExpressionOrHigher(): MemberExpression { 5654 // Note: to make our lives simpler, we decompose the NewExpression productions and 5655 // place ObjectCreationExpression and FunctionExpression into PrimaryExpression. 5656 // like so: 5657 // 5658 // PrimaryExpression : See 11.1 5659 // this 5660 // Identifier 5661 // Literal 5662 // ArrayLiteral 5663 // ObjectLiteral 5664 // (Expression) 5665 // FunctionExpression 5666 // new MemberExpression Arguments? 5667 // 5668 // MemberExpression : See 11.2 5669 // PrimaryExpression 5670 // MemberExpression[Expression] 5671 // MemberExpression.IdentifierName 5672 // 5673 // CallExpression : See 11.2 5674 // MemberExpression 5675 // CallExpression Arguments 5676 // CallExpression[Expression] 5677 // CallExpression.IdentifierName 5678 // 5679 // Technically this is ambiguous. i.e. CallExpression defines: 5680 // 5681 // CallExpression: 5682 // CallExpression Arguments 5683 // 5684 // If you see: "new Foo()" 5685 // 5686 // Then that could be treated as a single ObjectCreationExpression, or it could be 5687 // treated as the invocation of "new Foo". We disambiguate that in code (to match 5688 // the original grammar) by making sure that if we see an ObjectCreationExpression 5689 // we always consume arguments if they are there. So we treat "new Foo()" as an 5690 // object creation only, and not at all as an invocation. Another way to think 5691 // about this is that for every "new" that we see, we will consume an argument list if 5692 // it is there as part of the *associated* object creation node. Any additional 5693 // argument lists we see, will become invocation expressions. 5694 // 5695 // Because there are no other places in the grammar now that refer to FunctionExpression 5696 // or ObjectCreationExpression, it is safe to push down into the PrimaryExpression 5697 // production. 5698 // 5699 // Because CallExpression and MemberExpression are left recursive, we need to bottom out 5700 // of the recursion immediately. So we parse out a primary expression to start with. 5701 const pos = getNodePos(); 5702 let expression; 5703 5704 if (inEtsExtendComponentsContext() && extendEtsComponentDeclaration && token() === SyntaxKind.DotToken) { 5705 expression = finishVirtualNode(factory.createIdentifier(extendEtsComponentDeclaration.instance, /*typeArguments*/ undefined, SyntaxKind.Identifier), pos, pos); 5706 } 5707 else if (inEtsStylesComponentsContext() && stylesEtsComponentDeclaration && token() === SyntaxKind.DotToken) { 5708 expression = finishVirtualNode(factory.createIdentifier(stylesEtsComponentDeclaration.instance, /*typeArguments*/ undefined, SyntaxKind.Identifier), pos, pos); 5709 } 5710 else if (inEtsStateStylesContext() && stateStylesRootNode && token() === SyntaxKind.DotToken) { 5711 expression = finishVirtualNode(factory.createIdentifier(`${stateStylesRootNode}Instance`, /*typeArguments*/ undefined, SyntaxKind.Identifier), pos, pos); 5712 } 5713 else { 5714 expression = parsePrimaryExpression(); 5715 } 5716 return parseMemberExpressionRest(pos, expression, /*allowOptionalChain*/ true); 5717 } 5718 5719 function parseSuperExpression(): MemberExpression { 5720 const pos = getNodePos(); 5721 let expression = parseTokenNode<MemberExpression>(); 5722 if (token() === SyntaxKind.LessThanToken) { 5723 const startPos = getNodePos(); 5724 const typeArguments = tryParse(parseTypeArgumentsInExpression); 5725 if (typeArguments !== undefined) { 5726 parseErrorAt(startPos, getNodePos(), Diagnostics.super_may_not_use_type_arguments); 5727 if (!isTemplateStartOfTaggedTemplate()) { 5728 expression = factory.createExpressionWithTypeArguments(expression, typeArguments); 5729 } 5730 } 5731 } 5732 5733 if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.DotToken || token() === SyntaxKind.OpenBracketToken) { 5734 return expression; 5735 } 5736 5737 // If we have seen "super" it must be followed by '(' or '.'. 5738 // If it wasn't then just try to parse out a '.' and report an error. 5739 parseExpectedToken(SyntaxKind.DotToken, Diagnostics.super_must_be_followed_by_an_argument_list_or_member_access); 5740 // private names will never work with `super` (`super.#foo`), but that's a semantic error, not syntactic 5741 return finishNode(factory.createPropertyAccessExpression(expression, parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ true)), pos); 5742 } 5743 5744 function parseJsxElementOrSelfClosingElementOrFragment(inExpressionContext: boolean, topInvalidNodePosition?: number, openingTag?: JsxOpeningElement | JsxOpeningFragment): JsxElement | JsxSelfClosingElement | JsxFragment { 5745 const pos = getNodePos(); 5746 const opening = parseJsxOpeningOrSelfClosingElementOrOpeningFragment(inExpressionContext); 5747 let result: JsxElement | JsxSelfClosingElement | JsxFragment; 5748 if (opening.kind === SyntaxKind.JsxOpeningElement) { 5749 let children = parseJsxChildren(opening); 5750 let closingElement: JsxClosingElement; 5751 5752 const lastChild: JsxChild | undefined = children[children.length - 1]; 5753 if (lastChild?.kind === SyntaxKind.JsxElement 5754 && !tagNamesAreEquivalent(lastChild.openingElement.tagName, lastChild.closingElement.tagName) 5755 && tagNamesAreEquivalent(opening.tagName, lastChild.closingElement.tagName)) { 5756 // when an unclosed JsxOpeningElement incorrectly parses its parent's JsxClosingElement, 5757 // restructure (<div>(...<span>...</div>)) --> (<div>(...<span>...</>)</div>) 5758 // (no need to error; the parent will error) 5759 const end = lastChild.children.end; 5760 const newLast = finishNode(factory.createJsxElement( 5761 lastChild.openingElement, 5762 lastChild.children, 5763 finishNode(factory.createJsxClosingElement(finishNode(factory.createIdentifier(""), end, end)), end, end)), 5764 lastChild.openingElement.pos, 5765 end); 5766 5767 children = createNodeArray([...children.slice(0, children.length - 1), newLast], children.pos, end); 5768 closingElement = lastChild.closingElement; 5769 } 5770 else { 5771 closingElement = parseJsxClosingElement(opening, inExpressionContext); 5772 if (!tagNamesAreEquivalent(opening.tagName, closingElement.tagName)) { 5773 if (openingTag && isJsxOpeningElement(openingTag) && tagNamesAreEquivalent(closingElement.tagName, openingTag.tagName)) { 5774 // opening incorrectly matched with its parent's closing -- put error on opening 5775 parseErrorAtRange(opening.tagName, Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, getTextOfNodeFromSourceText(sourceText, opening.tagName)); 5776 } 5777 else { 5778 // other opening/closing mismatches -- put error on closing 5779 parseErrorAtRange(closingElement.tagName, Diagnostics.Expected_corresponding_JSX_closing_tag_for_0, getTextOfNodeFromSourceText(sourceText, opening.tagName)); 5780 } 5781 } 5782 } 5783 result = finishNode(factory.createJsxElement(opening, children, closingElement), pos); 5784 } 5785 else if (opening.kind === SyntaxKind.JsxOpeningFragment) { 5786 result = finishNode(factory.createJsxFragment(opening, parseJsxChildren(opening), parseJsxClosingFragment(inExpressionContext)), pos); 5787 } 5788 else { 5789 Debug.assert(opening.kind === SyntaxKind.JsxSelfClosingElement); 5790 // Nothing else to do for self-closing elements 5791 result = opening; 5792 } 5793 5794 // If the user writes the invalid code '<div></div><div></div>' in an expression context (i.e. not wrapped in 5795 // an enclosing tag), we'll naively try to parse ^ this as a 'less than' operator and the remainder of the tag 5796 // as garbage, which will cause the formatter to badly mangle the JSX. Perform a speculative parse of a JSX 5797 // element if we see a < token so that we can wrap it in a synthetic binary expression so the formatter 5798 // does less damage and we can report a better error. 5799 // Since JSX elements are invalid < operands anyway, this lookahead parse will only occur in error scenarios 5800 // of one sort or another. 5801 if (inExpressionContext && token() === SyntaxKind.LessThanToken) { 5802 const topBadPos = typeof topInvalidNodePosition === "undefined" ? result.pos : topInvalidNodePosition; 5803 const invalidElement = tryParse(() => parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true, topBadPos)); 5804 if (invalidElement) { 5805 const operatorToken = createMissingNode(SyntaxKind.CommaToken, /*reportAtCurrentPosition*/ false); 5806 setTextRangePosWidth(operatorToken, invalidElement.pos, 0); 5807 parseErrorAt(skipTrivia(sourceText, topBadPos), invalidElement.end, Diagnostics.JSX_expressions_must_have_one_parent_element); 5808 return finishNode(factory.createBinaryExpression(result, operatorToken as Token<SyntaxKind.CommaToken>, invalidElement), pos) as Node as JsxElement; 5809 } 5810 } 5811 5812 return result; 5813 } 5814 5815 function parseJsxText(): JsxText { 5816 const pos = getNodePos(); 5817 const node = factory.createJsxText(scanner.getTokenValue(), currentToken === SyntaxKind.JsxTextAllWhiteSpaces); 5818 currentToken = scanner.scanJsxToken(); 5819 return finishNode(node, pos); 5820 } 5821 5822 function parseJsxChild(openingTag: JsxOpeningElement | JsxOpeningFragment, token: JsxTokenSyntaxKind): JsxChild | undefined { 5823 switch (token) { 5824 case SyntaxKind.EndOfFileToken: 5825 // If we hit EOF, issue the error at the tag that lacks the closing element 5826 // rather than at the end of the file (which is useless) 5827 if (isJsxOpeningFragment(openingTag)) { 5828 parseErrorAtRange(openingTag, Diagnostics.JSX_fragment_has_no_corresponding_closing_tag); 5829 } 5830 else { 5831 // We want the error span to cover only 'Foo.Bar' in < Foo.Bar > 5832 // or to cover only 'Foo' in < Foo > 5833 const tag = openingTag.tagName; 5834 const start = skipTrivia(sourceText, tag.pos); 5835 parseErrorAt(start, tag.end, Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, getTextOfNodeFromSourceText(sourceText, openingTag.tagName)); 5836 } 5837 return undefined; 5838 case SyntaxKind.LessThanSlashToken: 5839 case SyntaxKind.ConflictMarkerTrivia: 5840 return undefined; 5841 case SyntaxKind.JsxText: 5842 case SyntaxKind.JsxTextAllWhiteSpaces: 5843 return parseJsxText(); 5844 case SyntaxKind.OpenBraceToken: 5845 return parseJsxExpression(/*inExpressionContext*/ false); 5846 case SyntaxKind.LessThanToken: 5847 return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ false, /*topInvalidNodePosition*/ undefined, openingTag); 5848 default: 5849 return Debug.assertNever(token); 5850 } 5851 } 5852 5853 function parseJsxChildren(openingTag: JsxOpeningElement | JsxOpeningFragment): NodeArray<JsxChild> { 5854 const list = []; 5855 const listPos = getNodePos(); 5856 const saveParsingContext = parsingContext; 5857 parsingContext |= 1 << ParsingContext.JsxChildren; 5858 5859 while (true) { 5860 const child = parseJsxChild(openingTag, currentToken = scanner.reScanJsxToken()); 5861 if (!child) break; 5862 list.push(child); 5863 if (isJsxOpeningElement(openingTag) 5864 && child?.kind === SyntaxKind.JsxElement 5865 && !tagNamesAreEquivalent(child.openingElement.tagName, child.closingElement.tagName) 5866 && tagNamesAreEquivalent(openingTag.tagName, child.closingElement.tagName)) { 5867 // stop after parsing a mismatched child like <div>...(<span></div>) in order to reattach the </div> higher 5868 break; 5869 } 5870 } 5871 5872 parsingContext = saveParsingContext; 5873 return createNodeArray(list, listPos); 5874 } 5875 5876 function parseJsxAttributes(): JsxAttributes { 5877 const pos = getNodePos(); 5878 return finishNode(factory.createJsxAttributes(parseList(ParsingContext.JsxAttributes, parseJsxAttribute)), pos); 5879 } 5880 5881 function parseJsxOpeningOrSelfClosingElementOrOpeningFragment(inExpressionContext: boolean): JsxOpeningElement | JsxSelfClosingElement | JsxOpeningFragment { 5882 const pos = getNodePos(); 5883 5884 parseExpected(SyntaxKind.LessThanToken); 5885 5886 if (token() === SyntaxKind.GreaterThanToken) { 5887 // See below for explanation of scanJsxText 5888 scanJsxText(); 5889 return finishNode(factory.createJsxOpeningFragment(), pos); 5890 } 5891 const tagName = parseJsxElementName(); 5892 const typeArguments = (contextFlags & NodeFlags.JavaScriptFile) === 0 ? tryParseTypeArguments() : undefined; 5893 const attributes = parseJsxAttributes(); 5894 5895 let node: JsxOpeningLikeElement; 5896 5897 if (token() === SyntaxKind.GreaterThanToken) { 5898 // Closing tag, so scan the immediately-following text with the JSX scanning instead 5899 // of regular scanning to avoid treating illegal characters (e.g. '#') as immediate 5900 // scanning errors 5901 scanJsxText(); 5902 node = factory.createJsxOpeningElement(tagName, typeArguments, attributes); 5903 } 5904 else { 5905 parseExpected(SyntaxKind.SlashToken); 5906 if (parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*shouldAdvance*/ false)) { 5907 // manually advance the scanner in order to look for jsx text inside jsx 5908 if (inExpressionContext) { 5909 nextToken(); 5910 } 5911 else { 5912 scanJsxText(); 5913 } 5914 } 5915 node = factory.createJsxSelfClosingElement(tagName, typeArguments, attributes); 5916 } 5917 5918 return finishNode(node, pos); 5919 } 5920 5921 function parseJsxElementName(): JsxTagNameExpression { 5922 const pos = getNodePos(); 5923 scanJsxIdentifier(); 5924 // JsxElement can have name in the form of 5925 // propertyAccessExpression 5926 // primaryExpression in the form of an identifier and "this" keyword 5927 // We can't just simply use parseLeftHandSideExpressionOrHigher because then we will start consider class,function etc as a keyword 5928 // We only want to consider "this" as a primaryExpression 5929 let expression: JsxTagNameExpression = token() === SyntaxKind.ThisKeyword ? 5930 parseTokenNode<ThisExpression>() : parseIdentifierName(); 5931 while (parseOptional(SyntaxKind.DotToken)) { 5932 expression = finishNode(factory.createPropertyAccessExpression(expression, parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ false)), pos) as JsxTagNamePropertyAccess; 5933 } 5934 return expression; 5935 } 5936 5937 function parseJsxExpression(inExpressionContext: boolean): JsxExpression | undefined { 5938 const pos = getNodePos(); 5939 if (!parseExpected(SyntaxKind.OpenBraceToken)) { 5940 return undefined; 5941 } 5942 5943 let dotDotDotToken: DotDotDotToken | undefined; 5944 let expression: Expression | undefined; 5945 if (token() !== SyntaxKind.CloseBraceToken) { 5946 dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); 5947 // Only an AssignmentExpression is valid here per the JSX spec, 5948 // but we can unambiguously parse a comma sequence and provide 5949 // a better error message in grammar checking. 5950 expression = parseExpression(); 5951 } 5952 if (inExpressionContext) { 5953 parseExpected(SyntaxKind.CloseBraceToken); 5954 } 5955 else { 5956 if (parseExpected(SyntaxKind.CloseBraceToken, /*message*/ undefined, /*shouldAdvance*/ false)) { 5957 scanJsxText(); 5958 } 5959 } 5960 5961 return finishNode(factory.createJsxExpression(dotDotDotToken, expression), pos); 5962 } 5963 5964 function parseJsxAttribute(): JsxAttribute | JsxSpreadAttribute { 5965 if (token() === SyntaxKind.OpenBraceToken) { 5966 return parseJsxSpreadAttribute(); 5967 } 5968 5969 scanJsxIdentifier(); 5970 const pos = getNodePos(); 5971 return finishNode(factory.createJsxAttribute(parseIdentifierName(), parseJsxAttributeValue()), pos); 5972 } 5973 5974 function parseJsxAttributeValue(): JsxAttributeValue | undefined { 5975 if (token() === SyntaxKind.EqualsToken) { 5976 if (scanJsxAttributeValue() === SyntaxKind.StringLiteral) { 5977 return parseLiteralNode() as StringLiteral; 5978 } 5979 if (token() === SyntaxKind.OpenBraceToken) { 5980 return parseJsxExpression(/*inExpressionContext*/ true); 5981 } 5982 if (token() === SyntaxKind.LessThanToken) { 5983 return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true); 5984 } 5985 parseErrorAtCurrentToken(Diagnostics.or_JSX_element_expected); 5986 } 5987 return undefined; 5988 } 5989 5990 function parseJsxSpreadAttribute(): JsxSpreadAttribute { 5991 const pos = getNodePos(); 5992 parseExpected(SyntaxKind.OpenBraceToken); 5993 parseExpected(SyntaxKind.DotDotDotToken); 5994 const expression = parseExpression(); 5995 parseExpected(SyntaxKind.CloseBraceToken); 5996 return finishNode(factory.createJsxSpreadAttribute(expression), pos); 5997 } 5998 5999 function parseJsxClosingElement(open: JsxOpeningElement, inExpressionContext: boolean): JsxClosingElement { 6000 const pos = getNodePos(); 6001 parseExpected(SyntaxKind.LessThanSlashToken); 6002 const tagName = parseJsxElementName(); 6003 if (parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*shouldAdvance*/ false)) { 6004 // manually advance the scanner in order to look for jsx text inside jsx 6005 if (inExpressionContext || !tagNamesAreEquivalent(open.tagName, tagName)) { 6006 nextToken(); 6007 } 6008 else { 6009 scanJsxText(); 6010 } 6011 } 6012 return finishNode(factory.createJsxClosingElement(tagName), pos); 6013 } 6014 6015 function parseJsxClosingFragment(inExpressionContext: boolean): JsxClosingFragment { 6016 const pos = getNodePos(); 6017 parseExpected(SyntaxKind.LessThanSlashToken); 6018 if (tokenIsIdentifierOrKeyword(token())) { 6019 parseErrorAtRange(parseJsxElementName(), Diagnostics.Expected_corresponding_closing_tag_for_JSX_fragment); 6020 } 6021 if (parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*shouldAdvance*/ false)) { 6022 // manually advance the scanner in order to look for jsx text inside jsx 6023 if (inExpressionContext) { 6024 nextToken(); 6025 } 6026 else { 6027 scanJsxText(); 6028 } 6029 } 6030 return finishNode(factory.createJsxJsxClosingFragment(), pos); 6031 } 6032 6033 function parseTypeAssertion(): TypeAssertion { 6034 const pos = getNodePos(); 6035 parseExpected(SyntaxKind.LessThanToken); 6036 const type = parseType(); 6037 parseExpected(SyntaxKind.GreaterThanToken); 6038 const expression = parseSimpleUnaryExpression(); 6039 return finishNode(factory.createTypeAssertion(type, expression), pos); 6040 } 6041 6042 function nextTokenIsIdentifierOrKeywordOrOpenBracketOrTemplate() { 6043 nextToken(); 6044 return tokenIsIdentifierOrKeyword(token()) 6045 || token() === SyntaxKind.OpenBracketToken 6046 || isTemplateStartOfTaggedTemplate(); 6047 } 6048 6049 function isStartOfOptionalPropertyOrElementAccessChain() { 6050 return token() === SyntaxKind.QuestionDotToken 6051 && lookAhead(nextTokenIsIdentifierOrKeywordOrOpenBracketOrTemplate); 6052 } 6053 6054 function tryReparseOptionalChain(node: Expression) { 6055 if (node.flags & NodeFlags.OptionalChain) { 6056 return true; 6057 } 6058 // check for an optional chain in a non-null expression 6059 if (isNonNullExpression(node)) { 6060 let expr = node.expression; 6061 while (isNonNullExpression(expr) && !(expr.flags & NodeFlags.OptionalChain)) { 6062 expr = expr.expression; 6063 } 6064 if (expr.flags & NodeFlags.OptionalChain) { 6065 // this is part of an optional chain. Walk down from `node` to `expression` and set the flag. 6066 while (isNonNullExpression(node)) { 6067 (node as Mutable<NonNullExpression>).flags |= NodeFlags.OptionalChain; 6068 node = node.expression; 6069 } 6070 return true; 6071 } 6072 } 6073 return false; 6074 } 6075 6076 function parsePropertyAccessExpressionRest(pos: number, expression: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined) { 6077 const name = parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ true); 6078 const isOptionalChain = questionDotToken || tryReparseOptionalChain(expression); 6079 const propertyAccess = isOptionalChain ? 6080 factory.createPropertyAccessChain(expression, questionDotToken, name) : 6081 factory.createPropertyAccessExpression(expression, name); 6082 if (isOptionalChain && isPrivateIdentifier(propertyAccess.name)) { 6083 parseErrorAtRange(propertyAccess.name, Diagnostics.An_optional_chain_cannot_contain_private_identifiers); 6084 } 6085 if (isExpressionWithTypeArguments(expression) && expression.typeArguments) { 6086 const pos = expression.typeArguments.pos - 1; 6087 const end = skipTrivia(sourceText, expression.typeArguments.end) + 1; 6088 parseErrorAt(pos, end, Diagnostics.An_instantiation_expression_cannot_be_followed_by_a_property_access); 6089 } 6090 return finishNode(propertyAccess, pos); 6091 } 6092 6093 function parseElementAccessExpressionRest(pos: number, expression: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined) { 6094 let argumentExpression: Expression; 6095 if (token() === SyntaxKind.CloseBracketToken) { 6096 argumentExpression = createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.An_element_access_expression_should_take_an_argument); 6097 } 6098 else { 6099 const argument = allowInAnd(parseExpression); 6100 if (isStringOrNumericLiteralLike(argument)) { 6101 argument.text = internIdentifier(argument.text); 6102 } 6103 argumentExpression = argument; 6104 } 6105 6106 parseExpected(SyntaxKind.CloseBracketToken); 6107 6108 const indexedAccess = questionDotToken || tryReparseOptionalChain(expression) ? 6109 factory.createElementAccessChain(expression, questionDotToken, argumentExpression) : 6110 factory.createElementAccessExpression(expression, argumentExpression); 6111 return finishNode(indexedAccess, pos); 6112 } 6113 6114 function parseMemberExpressionRest(pos: number, expression: LeftHandSideExpression, allowOptionalChain: boolean): MemberExpression { 6115 while (true) { 6116 let questionDotToken: QuestionDotToken | undefined; 6117 let isPropertyAccess = false; 6118 if (allowOptionalChain && isStartOfOptionalPropertyOrElementAccessChain()) { 6119 questionDotToken = parseExpectedToken(SyntaxKind.QuestionDotToken); 6120 isPropertyAccess = tokenIsIdentifierOrKeyword(token()); 6121 } 6122 else { 6123 isPropertyAccess = parseOptional(SyntaxKind.DotToken); 6124 } 6125 6126 if (isPropertyAccess) { 6127 expression = parsePropertyAccessExpressionRest(pos, expression, questionDotToken); 6128 continue; 6129 } 6130 6131 // when in the [Decorator] context, we do not parse ElementAccess as it could be part of a ComputedPropertyName 6132 if ((questionDotToken || !inDecoratorContext()) && parseOptional(SyntaxKind.OpenBracketToken)) { 6133 expression = parseElementAccessExpressionRest(pos, expression, questionDotToken); 6134 continue; 6135 } 6136 6137 if (isTemplateStartOfTaggedTemplate()) { 6138 // Absorb type arguments into TemplateExpression when preceding expression is ExpressionWithTypeArguments 6139 expression = !questionDotToken && expression.kind === SyntaxKind.ExpressionWithTypeArguments ? 6140 parseTaggedTemplateRest(pos, (expression as ExpressionWithTypeArguments).expression, questionDotToken, (expression as ExpressionWithTypeArguments).typeArguments) : 6141 parseTaggedTemplateRest(pos, expression, questionDotToken, /*typeArguments*/ undefined); 6142 continue; 6143 } 6144 6145 if (!questionDotToken) { 6146 if (token() === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak()) { 6147 nextToken(); 6148 expression = finishNode(factory.createNonNullExpression(expression), pos); 6149 continue; 6150 } 6151 const typeArguments = tryParse(parseTypeArgumentsInExpression); 6152 if (typeArguments) { 6153 expression = finishNode(factory.createExpressionWithTypeArguments(expression, typeArguments), pos); 6154 continue; 6155 } 6156 } 6157 6158 return expression as MemberExpression; 6159 } 6160 } 6161 6162 function isTemplateStartOfTaggedTemplate() { 6163 return token() === SyntaxKind.NoSubstitutionTemplateLiteral || token() === SyntaxKind.TemplateHead; 6164 } 6165 6166 function parseTaggedTemplateRest(pos: number, tag: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined, typeArguments: NodeArray<TypeNode> | undefined) { 6167 const tagExpression = factory.createTaggedTemplateExpression( 6168 tag, 6169 typeArguments, 6170 token() === SyntaxKind.NoSubstitutionTemplateLiteral ? 6171 (reScanTemplateHeadOrNoSubstitutionTemplate(), parseLiteralNode() as NoSubstitutionTemplateLiteral) : 6172 parseTemplateExpression(/*isTaggedTemplate*/ true) 6173 ); 6174 if (questionDotToken || tag.flags & NodeFlags.OptionalChain) { 6175 (tagExpression as Mutable<Node>).flags |= NodeFlags.OptionalChain; 6176 } 6177 tagExpression.questionDotToken = questionDotToken; 6178 return finishNode(tagExpression, pos); 6179 } 6180 6181 function parseCallExpressionRest(pos: number, expression: LeftHandSideExpression): LeftHandSideExpression { 6182 let currentNodeName: string | undefined; 6183 while (true) { 6184 expression = parseMemberExpressionRest(pos, expression, /*allowOptionalChain*/ true); 6185 let typeArguments: NodeArray<TypeNode> | undefined; 6186 const questionDotToken = parseOptionalToken(SyntaxKind.QuestionDotToken); 6187 if (questionDotToken) { 6188 typeArguments = tryParse(parseTypeArgumentsInExpression); 6189 if (isTemplateStartOfTaggedTemplate()) { 6190 expression = parseTaggedTemplateRest(pos, expression, questionDotToken, typeArguments); 6191 continue; 6192 } 6193 } 6194 if (typeArguments || token() === SyntaxKind.OpenParenToken) { 6195 // Absorb type arguments into CallExpression when preceding expression is ExpressionWithTypeArguments 6196 if (!questionDotToken && expression.kind === SyntaxKind.ExpressionWithTypeArguments) { 6197 typeArguments = (expression as ExpressionWithTypeArguments).typeArguments; 6198 expression = (expression as ExpressionWithTypeArguments).expression; 6199 } 6200 6201 if (isValidVirtualTypeArgumentsContext() && isPropertyAccessExpression(expression)) { 6202 const [rootNode, type] = getRootComponent(expression, sourceFileCompilerOptions); 6203 if (rootNode && type) { 6204 let rootNodeName = ''; 6205 if (type === 'otherType') { 6206 rootNodeName = 'Common'; 6207 } else { 6208 rootNodeName = (<Identifier>(rootNode.expression)).escapedText.toString(); 6209 } 6210 currentNodeName = getTextOfPropertyName(expression.name).toString(); 6211 if (currentNodeName === sourceFileCompilerOptions?.ets?.styles?.property) { 6212 setEtsStateStylesContext(true); 6213 stateStylesRootNode = rootNodeName; 6214 } 6215 else { 6216 setEtsStateStylesContext(false); 6217 stateStylesRootNode = undefined; 6218 } 6219 const syntaxComponents = sourceFileCompilerOptions?.ets?.syntaxComponents?.attrUICallback?.filter( 6220 (item: any) => item.name === rootNodeName); 6221 if (type === 'callExpressionComponentType' && syntaxComponents && syntaxComponents.length && 6222 syntaxComponents[0]?.attributes?.includes(currentNodeName)) { 6223 setSyntaxComponentContext(true); 6224 } else if (type === 'etsComponentType') { 6225 typeArguments = parseEtsTypeArguments(pos, `${rootNodeName}Attribute`); 6226 } 6227 } 6228 else if (inEtsStateStylesContext() && stateStylesRootNode) { 6229 typeArguments = parseEtsTypeArguments(pos, `${stateStylesRootNode}Attribute`); 6230 } else if (inEtsStylesComponentsContext() || inEtsExtendComponentsContext()) { 6231 const virtualNode = getVirtualEtsComponent(expression); 6232 if (virtualNode) { 6233 let rootNodeName = (<Identifier>(virtualNode.expression)).escapedText.toString(); 6234 currentNodeName = getTextOfPropertyName(expression.name).toString(); 6235 if (currentNodeName === sourceFileCompilerOptions?.ets?.styles?.property) { 6236 setEtsStateStylesContext(true); 6237 rootNodeName = rootNodeName.replace("Instance", ""); 6238 stateStylesRootNode = rootNodeName; 6239 typeArguments = parseEtsTypeArguments(pos, `${rootNodeName}Attribute`); 6240 } 6241 } 6242 } 6243 } 6244 if (isValidVirtualTypeArgumentsContext() && ts.isIdentifier(expression) && 6245 sourceFileCompilerOptions?.ets?.syntaxComponents?.paramsUICallback?.includes(expression.escapedText.toString())) { 6246 setSyntaxComponentContext(true); 6247 } 6248 const argumentList = parseArgumentList(); 6249 const callExpr = questionDotToken || tryReparseOptionalChain(expression) ? 6250 factory.createCallChain(expression, questionDotToken, typeArguments, argumentList) : 6251 factory.createCallExpression(expression, typeArguments, argumentList); 6252 expression = finishNode(callExpr, pos); 6253 continue; 6254 } 6255 if (questionDotToken) { 6256 // We parsed `?.` but then failed to parse anything, so report a missing identifier here. 6257 const name = createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ false, Diagnostics.Identifier_expected); 6258 expression = finishNode(factory.createPropertyAccessChain(expression, questionDotToken, name), pos); 6259 } 6260 break; 6261 } 6262 if (currentNodeName === sourceFileCompilerOptions?.ets?.styles?.property) { 6263 setEtsStateStylesContext(false); 6264 stateStylesRootNode = undefined; 6265 } 6266 return expression; 6267 } 6268 6269 function isValidVirtualTypeArgumentsContext(): boolean { 6270 return inBuildContext() || inBuilderContext() || inEtsStylesComponentsContext() || inEtsExtendComponentsContext(); 6271 } 6272 6273 function parseArgumentList() { 6274 parseExpected(SyntaxKind.OpenParenToken); 6275 const result = parseDelimitedList(ParsingContext.ArgumentExpressions, parseArgumentExpression); 6276 parseExpected(SyntaxKind.CloseParenToken); 6277 return result; 6278 } 6279 6280 function parseTypeArgumentsInExpression() { 6281 if ((contextFlags & NodeFlags.JavaScriptFile) !== 0) { 6282 // TypeArguments must not be parsed in JavaScript files to avoid ambiguity with binary operators. 6283 return undefined; 6284 } 6285 6286 if (reScanLessThanToken() !== SyntaxKind.LessThanToken) { 6287 return undefined; 6288 } 6289 nextToken(); 6290 6291 const typeArguments = parseDelimitedList(ParsingContext.TypeArguments, parseType); 6292 if (reScanGreaterToken() !== SyntaxKind.GreaterThanToken) { 6293 // If it doesn't have the closing `>` then it's definitely not an type argument list. 6294 return undefined; 6295 } 6296 nextToken(); 6297 6298 // We successfully parsed a type argument list. The next token determines whether we want to 6299 // treat it as such. If the type argument list is followed by `(` or a template literal, as in 6300 // `f<number>(42)`, we favor the type argument interpretation even though JavaScript would view 6301 // it as a relational expression. 6302 return typeArguments && canFollowTypeArgumentsInExpression() ? typeArguments : undefined; 6303 } 6304 6305 function canFollowTypeArgumentsInExpression(): boolean { 6306 switch (token()) { 6307 // These tokens can follow a type argument list in a call expression. 6308 case SyntaxKind.OpenParenToken: // foo<x>( 6309 case SyntaxKind.NoSubstitutionTemplateLiteral: // foo<T> `...` 6310 case SyntaxKind.TemplateHead: // foo<T> `...${100}...` 6311 return true; 6312 // A type argument list followed by `<` never makes sense, and a type argument list followed 6313 // by `>` is ambiguous with a (re-scanned) `>>` operator, so we disqualify both. Also, in 6314 // this context, `+` and `-` are unary operators, not binary operators. 6315 case SyntaxKind.LessThanToken: 6316 case SyntaxKind.GreaterThanToken: 6317 case SyntaxKind.PlusToken: 6318 case SyntaxKind.MinusToken: 6319 return false; 6320 } 6321 // We favor the type argument list interpretation when it is immediately followed by 6322 // a line break, a binary operator, or something that can't start an expression. 6323 return scanner.hasPrecedingLineBreak() || isBinaryOperator() || !isStartOfExpression(); 6324 } 6325 6326 function isCurrentTokenAnEtsComponentExpression(): boolean { 6327 if (!inEtsComponentsContext()) { 6328 return false; 6329 } 6330 const components = sourceFileCompilerOptions.ets?.components ?? []; 6331 return components.includes(scanner.getTokenText()); 6332 } 6333 6334 function parseEtsComponentExpression(): EtsComponentExpression { 6335 const pos = getNodePos(); 6336 const name = parseBindingIdentifier(); 6337 const argumentList = parseArgumentList(); 6338 const body = token() === SyntaxKind.OpenBraceToken ? parseFunctionBlock(SignatureFlags.None) : undefined; 6339 const node = factory.createEtsComponentExpression(name, argumentList, body); 6340 return finishNode(node, pos); 6341 } 6342 6343 function parsePrimaryExpression(): PrimaryExpression { 6344 switch (token()) { 6345 case SyntaxKind.NumericLiteral: 6346 case SyntaxKind.BigIntLiteral: 6347 case SyntaxKind.StringLiteral: 6348 case SyntaxKind.NoSubstitutionTemplateLiteral: 6349 return parseLiteralNode(); 6350 case SyntaxKind.ThisKeyword: 6351 case SyntaxKind.SuperKeyword: 6352 case SyntaxKind.NullKeyword: 6353 case SyntaxKind.TrueKeyword: 6354 case SyntaxKind.FalseKeyword: 6355 return parseTokenNode<PrimaryExpression>(); 6356 case SyntaxKind.OpenParenToken: 6357 return parseParenthesizedExpression(); 6358 case SyntaxKind.OpenBracketToken: 6359 return parseArrayLiteralExpression(); 6360 case SyntaxKind.OpenBraceToken: 6361 return parseObjectLiteralExpression(); 6362 case SyntaxKind.AsyncKeyword: 6363 // Async arrow functions are parsed earlier in parseAssignmentExpressionOrHigher. 6364 // If we encounter `async [no LineTerminator here] function` then this is an async 6365 // function; otherwise, its an identifier. 6366 if (!lookAhead(nextTokenIsFunctionKeywordOnSameLine)) { 6367 break; 6368 } 6369 6370 return parseFunctionExpression(); 6371 case SyntaxKind.ClassKeyword: 6372 return parseClassExpression(); 6373 case SyntaxKind.FunctionKeyword: 6374 return parseFunctionExpression(); 6375 case SyntaxKind.NewKeyword: 6376 return parseNewExpressionOrNewDotTarget(); 6377 case SyntaxKind.SlashToken: 6378 case SyntaxKind.SlashEqualsToken: 6379 if (reScanSlashToken() === SyntaxKind.RegularExpressionLiteral) { 6380 return parseLiteralNode(); 6381 } 6382 break; 6383 case SyntaxKind.TemplateHead: 6384 return parseTemplateExpression(/* isTaggedTemplate */ false); 6385 case SyntaxKind.PrivateIdentifier: 6386 return parsePrivateIdentifier(); 6387 } 6388 6389 if(isCurrentTokenAnEtsComponentExpression() && !inEtsNewExpressionContext()){ 6390 return parseEtsComponentExpression(); 6391 } 6392 6393 return parseIdentifier(Diagnostics.Expression_expected); 6394 } 6395 6396 function parseParenthesizedExpression(): ParenthesizedExpression { 6397 const pos = getNodePos(); 6398 const hasJSDoc = hasPrecedingJSDocComment(); 6399 parseExpected(SyntaxKind.OpenParenToken); 6400 const expression = allowInAnd(parseExpression); 6401 parseExpected(SyntaxKind.CloseParenToken); 6402 return withJSDoc(finishNode(factory.createParenthesizedExpression(expression), pos), hasJSDoc); 6403 } 6404 6405 function parseSpreadElement(): Expression { 6406 const pos = getNodePos(); 6407 parseExpected(SyntaxKind.DotDotDotToken); 6408 const expression = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true); 6409 return finishNode(factory.createSpreadElement(expression), pos); 6410 } 6411 6412 function parseArgumentOrArrayLiteralElement(): Expression { 6413 return token() === SyntaxKind.DotDotDotToken ? parseSpreadElement() : 6414 token() === SyntaxKind.CommaToken ? finishNode(factory.createOmittedExpression(), getNodePos()) : 6415 parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true); 6416 } 6417 6418 function parseArgumentExpression(): Expression { 6419 return doOutsideOfContext(disallowInAndDecoratorContext, parseArgumentOrArrayLiteralElement); 6420 } 6421 6422 function parseArrayLiteralExpression(): ArrayLiteralExpression { 6423 const pos = getNodePos(); 6424 const openBracketPosition = scanner.getTokenPos(); 6425 const openBracketParsed = parseExpected(SyntaxKind.OpenBracketToken); 6426 const multiLine = scanner.hasPrecedingLineBreak(); 6427 const elements = parseDelimitedList(ParsingContext.ArrayLiteralMembers, parseArgumentOrArrayLiteralElement); 6428 parseExpectedMatchingBrackets(SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken, openBracketParsed, openBracketPosition); 6429 return finishNode(factory.createArrayLiteralExpression(elements, multiLine), pos); 6430 } 6431 6432 function parseObjectLiteralElement(): ObjectLiteralElementLike { 6433 const pos = getNodePos(); 6434 const hasJSDoc = hasPrecedingJSDocComment(); 6435 6436 if (parseOptionalToken(SyntaxKind.DotDotDotToken)) { 6437 const expression = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true); 6438 return withJSDoc(finishNode(factory.createSpreadAssignment(expression), pos), hasJSDoc); 6439 } 6440 6441 const decorators = parseDecorators(); 6442 const modifiers = parseModifiers(); 6443 6444 if (parseContextualModifier(SyntaxKind.GetKeyword)) { 6445 return parseAccessorDeclaration(pos, hasJSDoc, decorators, modifiers, SyntaxKind.GetAccessor, SignatureFlags.None); 6446 } 6447 if (parseContextualModifier(SyntaxKind.SetKeyword)) { 6448 return parseAccessorDeclaration(pos, hasJSDoc, decorators, modifiers, SyntaxKind.SetAccessor, SignatureFlags.None); 6449 } 6450 6451 const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); 6452 const tokenIsIdentifier = isIdentifier(); 6453 const name = parsePropertyName(); 6454 6455 // Disallowing of optional property assignments and definite assignment assertion happens in the grammar checker. 6456 const questionToken = parseOptionalToken(SyntaxKind.QuestionToken); 6457 const exclamationToken = parseOptionalToken(SyntaxKind.ExclamationToken); 6458 6459 if (asteriskToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) { 6460 return parseMethodDeclaration(pos, hasJSDoc, decorators, modifiers, asteriskToken, name, questionToken, exclamationToken); 6461 } 6462 6463 // check if it is short-hand property assignment or normal property assignment 6464 // NOTE: if token is EqualsToken it is interpreted as CoverInitializedName production 6465 // CoverInitializedName[Yield] : 6466 // IdentifierReference[?Yield] Initializer[In, ?Yield] 6467 // this is necessary because ObjectLiteral productions are also used to cover grammar for ObjectAssignmentPattern 6468 let node: Mutable<ShorthandPropertyAssignment | PropertyAssignment>; 6469 const isShorthandPropertyAssignment = tokenIsIdentifier && (token() !== SyntaxKind.ColonToken); 6470 if (isShorthandPropertyAssignment) { 6471 const equalsToken = parseOptionalToken(SyntaxKind.EqualsToken); 6472 const objectAssignmentInitializer = equalsToken ? allowInAnd(() => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true)) : undefined; 6473 node = factory.createShorthandPropertyAssignment(name as Identifier, objectAssignmentInitializer); 6474 // Save equals token for error reporting. 6475 // TODO(rbuckton): Consider manufacturing this when we need to report an error as it is otherwise not useful. 6476 node.equalsToken = equalsToken; 6477 } 6478 else { 6479 parseExpected(SyntaxKind.ColonToken); 6480 const initializer = allowInAnd(() => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true)); 6481 node = factory.createPropertyAssignment(name, initializer); 6482 } 6483 // Decorators, Modifiers, questionToken, and exclamationToken are not supported by property assignments and are reported in the grammar checker 6484 node.illegalDecorators = decorators; 6485 node.modifiers = modifiers; 6486 node.questionToken = questionToken; 6487 node.exclamationToken = exclamationToken; 6488 return withJSDoc(finishNode(node, pos), hasJSDoc); 6489 } 6490 6491 function parseObjectLiteralExpression(): ObjectLiteralExpression { 6492 const pos = getNodePos(); 6493 const openBracePosition = scanner.getTokenPos(); 6494 const openBraceParsed = parseExpected(SyntaxKind.OpenBraceToken); 6495 const multiLine = scanner.hasPrecedingLineBreak(); 6496 const properties = parseDelimitedList(ParsingContext.ObjectLiteralMembers, parseObjectLiteralElement, /*considerSemicolonAsDelimiter*/ true); 6497 parseExpectedMatchingBrackets(SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, openBraceParsed, openBracePosition); 6498 return finishNode(factory.createObjectLiteralExpression(properties, multiLine), pos); 6499 } 6500 6501 function parseFunctionExpression(): FunctionExpression { 6502 // GeneratorExpression: 6503 // function* BindingIdentifier [Yield][opt](FormalParameters[Yield]){ GeneratorBody } 6504 // 6505 // FunctionExpression: 6506 // function BindingIdentifier[opt](FormalParameters){ FunctionBody } 6507 const savedDecoratorContext = inDecoratorContext(); 6508 setDecoratorContext(/*val*/ false); 6509 6510 const pos = getNodePos(); 6511 const hasJSDoc = hasPrecedingJSDocComment(); 6512 const modifiers = parseModifiers(); 6513 parseExpected(SyntaxKind.FunctionKeyword); 6514 const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); 6515 const isGenerator = asteriskToken ? SignatureFlags.Yield : SignatureFlags.None; 6516 const isAsync = some(modifiers, isAsyncModifier) ? SignatureFlags.Await : SignatureFlags.None; 6517 const name = isGenerator && isAsync ? doInYieldAndAwaitContext(parseOptionalBindingIdentifier) : 6518 isGenerator ? doInYieldContext(parseOptionalBindingIdentifier) : 6519 isAsync ? doInAwaitContext(parseOptionalBindingIdentifier) : 6520 parseOptionalBindingIdentifier(); 6521 6522 const typeParameters = parseTypeParameters(); 6523 const parameters = parseParameters(isGenerator | isAsync); 6524 const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false); 6525 const body = parseFunctionBlock(isGenerator | isAsync); 6526 6527 setDecoratorContext(savedDecoratorContext); 6528 6529 const node = factory.createFunctionExpression(modifiers, asteriskToken, name, typeParameters, parameters, type, body); 6530 return withJSDoc(finishNode(node, pos), hasJSDoc); 6531 } 6532 6533 function parseOptionalBindingIdentifier(): Identifier | undefined { 6534 return isBindingIdentifier() ? parseBindingIdentifier() : undefined; 6535 } 6536 6537 function parseNewExpressionOrNewDotTarget(): NewExpression | MetaProperty { 6538 setEtsNewExpressionContext(inEtsComponentsContext()); 6539 const pos = getNodePos(); 6540 parseExpected(SyntaxKind.NewKeyword); 6541 if (parseOptional(SyntaxKind.DotToken)) { 6542 const name = parseIdentifierName(); 6543 return finishNode(factory.createMetaProperty(SyntaxKind.NewKeyword, name), pos); 6544 } 6545 const expressionPos = getNodePos(); 6546 let expression: LeftHandSideExpression = parseMemberExpressionRest(expressionPos, parsePrimaryExpression(), /*allowOptionalChain*/ false); 6547 let typeArguments: NodeArray<TypeNode> | undefined; 6548 // Absorb type arguments into NewExpression when preceding expression is ExpressionWithTypeArguments 6549 if (expression.kind === SyntaxKind.ExpressionWithTypeArguments) { 6550 typeArguments = (expression as ExpressionWithTypeArguments).typeArguments; 6551 expression = (expression as ExpressionWithTypeArguments).expression; 6552 } 6553 if (token() === SyntaxKind.QuestionDotToken) { 6554 parseErrorAtCurrentToken(Diagnostics.Invalid_optional_chain_from_new_expression_Did_you_mean_to_call_0, getTextOfNodeFromSourceText(sourceText, expression)); 6555 } 6556 const argumentList = token() === SyntaxKind.OpenParenToken ? parseArgumentList() : undefined; 6557 setEtsNewExpressionContext(false); 6558 return finishNode(factory.createNewExpression(expression, typeArguments, argumentList), pos); 6559 } 6560 6561 // STATEMENTS 6562 function parseBlock(ignoreMissingOpenBrace: boolean, diagnosticMessage?: DiagnosticMessage): Block { 6563 const pos = getNodePos(); 6564 const hasJSDoc = hasPrecedingJSDocComment(); 6565 const openBracePosition = scanner.getTokenPos(); 6566 const openBraceParsed = parseExpected(SyntaxKind.OpenBraceToken, diagnosticMessage); 6567 if (openBraceParsed || ignoreMissingOpenBrace) { 6568 const multiLine = scanner.hasPrecedingLineBreak(); 6569 const statements = parseList(ParsingContext.BlockStatements, parseStatement); 6570 parseExpectedMatchingBrackets(SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, openBraceParsed, openBracePosition); 6571 const result = withJSDoc(finishNode(factory.createBlock(statements, multiLine), pos), hasJSDoc); 6572 if (token() === SyntaxKind.EqualsToken) { 6573 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); 6574 nextToken(); 6575 } 6576 6577 return result; 6578 } 6579 else { 6580 const statements = createMissingList<Statement>(); 6581 return withJSDoc(finishNode(factory.createBlock(statements, /*multiLine*/ undefined), pos), hasJSDoc); 6582 } 6583 } 6584 6585 function parseFunctionBlock(flags: SignatureFlags, diagnosticMessage?: DiagnosticMessage): Block { 6586 const savedYieldContext = inYieldContext(); 6587 setYieldContext(!!(flags & SignatureFlags.Yield)); 6588 6589 const savedAwaitContext = inAwaitContext(); 6590 setAwaitContext(!!(flags & SignatureFlags.Await)); 6591 6592 const savedTopLevel = topLevel; 6593 topLevel = false; 6594 6595 // We may be in a [Decorator] context when parsing a function expression or 6596 // arrow function. The body of the function is not in [Decorator] context. 6597 const saveDecoratorContext = inDecoratorContext(); 6598 if (saveDecoratorContext) { 6599 setDecoratorContext(/*val*/ false); 6600 } 6601 6602 const block = parseBlock(!!(flags & SignatureFlags.IgnoreMissingOpenBrace), diagnosticMessage); 6603 6604 if (saveDecoratorContext) { 6605 setDecoratorContext(/*val*/ true); 6606 } 6607 6608 topLevel = savedTopLevel; 6609 setYieldContext(savedYieldContext); 6610 setAwaitContext(savedAwaitContext); 6611 6612 return block; 6613 } 6614 6615 function parseEmptyStatement(): Statement { 6616 const pos = getNodePos(); 6617 const hasJSDoc = hasPrecedingJSDocComment(); 6618 parseExpected(SyntaxKind.SemicolonToken); 6619 return withJSDoc(finishNode(factory.createEmptyStatement(), pos), hasJSDoc); 6620 } 6621 6622 function parseIfStatement(): IfStatement { 6623 const pos = getNodePos(); 6624 const hasJSDoc = hasPrecedingJSDocComment(); 6625 parseExpected(SyntaxKind.IfKeyword); 6626 const openParenPosition = scanner.getTokenPos(); 6627 const openParenParsed = parseExpected(SyntaxKind.OpenParenToken); 6628 const expression = allowInAnd(parseExpression); 6629 parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition); 6630 const thenStatement = parseStatement(); 6631 const elseStatement = parseOptional(SyntaxKind.ElseKeyword) ? parseStatement() : undefined; 6632 return withJSDoc(finishNode(factory.createIfStatement(expression, thenStatement, elseStatement), pos), hasJSDoc); 6633 } 6634 6635 function parseDoStatement(): DoStatement { 6636 const pos = getNodePos(); 6637 const hasJSDoc = hasPrecedingJSDocComment(); 6638 parseExpected(SyntaxKind.DoKeyword); 6639 const statement = parseStatement(); 6640 parseExpected(SyntaxKind.WhileKeyword); 6641 const openParenPosition = scanner.getTokenPos(); 6642 const openParenParsed = parseExpected(SyntaxKind.OpenParenToken); 6643 const expression = allowInAnd(parseExpression); 6644 parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition); 6645 6646 // From: https://mail.mozilla.org/pipermail/es-discuss/2011-August/016188.html 6647 // 157 min --- All allen at wirfs-brock.com CONF --- "do{;}while(false)false" prohibited in 6648 // spec but allowed in consensus reality. Approved -- this is the de-facto standard whereby 6649 // do;while(0)x will have a semicolon inserted before x. 6650 parseOptional(SyntaxKind.SemicolonToken); 6651 return withJSDoc(finishNode(factory.createDoStatement(statement, expression), pos), hasJSDoc); 6652 } 6653 6654 function parseWhileStatement(): WhileStatement { 6655 const pos = getNodePos(); 6656 const hasJSDoc = hasPrecedingJSDocComment(); 6657 parseExpected(SyntaxKind.WhileKeyword); 6658 const openParenPosition = scanner.getTokenPos(); 6659 const openParenParsed = parseExpected(SyntaxKind.OpenParenToken); 6660 const expression = allowInAnd(parseExpression); 6661 parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition); 6662 const statement = parseStatement(); 6663 return withJSDoc(finishNode(factory.createWhileStatement(expression, statement), pos), hasJSDoc); 6664 } 6665 6666 function parseForOrForInOrForOfStatement(): Statement { 6667 const pos = getNodePos(); 6668 const hasJSDoc = hasPrecedingJSDocComment(); 6669 parseExpected(SyntaxKind.ForKeyword); 6670 const awaitToken = parseOptionalToken(SyntaxKind.AwaitKeyword); 6671 parseExpected(SyntaxKind.OpenParenToken); 6672 6673 let initializer!: VariableDeclarationList | Expression; 6674 if (token() !== SyntaxKind.SemicolonToken) { 6675 if (token() === SyntaxKind.VarKeyword || token() === SyntaxKind.LetKeyword || token() === SyntaxKind.ConstKeyword) { 6676 initializer = parseVariableDeclarationList(/*inForStatementInitializer*/ true); 6677 } 6678 else { 6679 initializer = disallowInAnd(parseExpression); 6680 } 6681 } 6682 6683 let node: IterationStatement; 6684 if (awaitToken ? parseExpected(SyntaxKind.OfKeyword) : parseOptional(SyntaxKind.OfKeyword)) { 6685 const expression = allowInAnd(() => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true)); 6686 parseExpected(SyntaxKind.CloseParenToken); 6687 node = factory.createForOfStatement(awaitToken, initializer, expression, parseStatement()); 6688 } 6689 else if (parseOptional(SyntaxKind.InKeyword)) { 6690 const expression = allowInAnd(parseExpression); 6691 parseExpected(SyntaxKind.CloseParenToken); 6692 node = factory.createForInStatement(initializer, expression, parseStatement()); 6693 } 6694 else { 6695 parseExpected(SyntaxKind.SemicolonToken); 6696 const condition = token() !== SyntaxKind.SemicolonToken && token() !== SyntaxKind.CloseParenToken 6697 ? allowInAnd(parseExpression) 6698 : undefined; 6699 parseExpected(SyntaxKind.SemicolonToken); 6700 const incrementor = token() !== SyntaxKind.CloseParenToken 6701 ? allowInAnd(parseExpression) 6702 : undefined; 6703 parseExpected(SyntaxKind.CloseParenToken); 6704 node = factory.createForStatement(initializer, condition, incrementor, parseStatement()); 6705 } 6706 6707 return withJSDoc(finishNode(node, pos) as ForStatement | ForInOrOfStatement, hasJSDoc); 6708 } 6709 6710 function parseBreakOrContinueStatement(kind: SyntaxKind): BreakOrContinueStatement { 6711 const pos = getNodePos(); 6712 const hasJSDoc = hasPrecedingJSDocComment(); 6713 6714 parseExpected(kind === SyntaxKind.BreakStatement ? SyntaxKind.BreakKeyword : SyntaxKind.ContinueKeyword); 6715 const label = canParseSemicolon() ? undefined : parseIdentifier(); 6716 6717 parseSemicolon(); 6718 const node = kind === SyntaxKind.BreakStatement 6719 ? factory.createBreakStatement(label) 6720 : factory.createContinueStatement(label); 6721 return withJSDoc(finishNode(node, pos), hasJSDoc); 6722 } 6723 6724 function parseReturnStatement(): ReturnStatement { 6725 const pos = getNodePos(); 6726 const hasJSDoc = hasPrecedingJSDocComment(); 6727 parseExpected(SyntaxKind.ReturnKeyword); 6728 const expression = canParseSemicolon() ? undefined : allowInAnd(parseExpression); 6729 parseSemicolon(); 6730 return withJSDoc(finishNode(factory.createReturnStatement(expression), pos), hasJSDoc); 6731 } 6732 6733 function parseWithStatement(): WithStatement { 6734 const pos = getNodePos(); 6735 const hasJSDoc = hasPrecedingJSDocComment(); 6736 parseExpected(SyntaxKind.WithKeyword); 6737 const openParenPosition = scanner.getTokenPos(); 6738 const openParenParsed = parseExpected(SyntaxKind.OpenParenToken); 6739 const expression = allowInAnd(parseExpression); 6740 parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition); 6741 const statement = doInsideOfContext(NodeFlags.InWithStatement, parseStatement); 6742 return withJSDoc(finishNode(factory.createWithStatement(expression, statement), pos), hasJSDoc); 6743 } 6744 6745 function parseCaseClause(): CaseClause { 6746 const pos = getNodePos(); 6747 const hasJSDoc = hasPrecedingJSDocComment(); 6748 parseExpected(SyntaxKind.CaseKeyword); 6749 const expression = allowInAnd(parseExpression); 6750 parseExpected(SyntaxKind.ColonToken); 6751 const statements = parseList(ParsingContext.SwitchClauseStatements, parseStatement); 6752 return withJSDoc(finishNode(factory.createCaseClause(expression, statements), pos), hasJSDoc); 6753 } 6754 6755 function parseDefaultClause(): DefaultClause { 6756 const pos = getNodePos(); 6757 parseExpected(SyntaxKind.DefaultKeyword); 6758 parseExpected(SyntaxKind.ColonToken); 6759 const statements = parseList(ParsingContext.SwitchClauseStatements, parseStatement); 6760 return finishNode(factory.createDefaultClause(statements), pos); 6761 } 6762 6763 function parseCaseOrDefaultClause(): CaseOrDefaultClause { 6764 return token() === SyntaxKind.CaseKeyword ? parseCaseClause() : parseDefaultClause(); 6765 } 6766 6767 function parseCaseBlock(): CaseBlock { 6768 const pos = getNodePos(); 6769 parseExpected(SyntaxKind.OpenBraceToken); 6770 const clauses = parseList(ParsingContext.SwitchClauses, parseCaseOrDefaultClause); 6771 parseExpected(SyntaxKind.CloseBraceToken); 6772 return finishNode(factory.createCaseBlock(clauses), pos); 6773 } 6774 6775 function parseSwitchStatement(): SwitchStatement { 6776 const pos = getNodePos(); 6777 const hasJSDoc = hasPrecedingJSDocComment(); 6778 parseExpected(SyntaxKind.SwitchKeyword); 6779 parseExpected(SyntaxKind.OpenParenToken); 6780 const expression = allowInAnd(parseExpression); 6781 parseExpected(SyntaxKind.CloseParenToken); 6782 const caseBlock = parseCaseBlock(); 6783 return withJSDoc(finishNode(factory.createSwitchStatement(expression, caseBlock), pos), hasJSDoc); 6784 } 6785 6786 function parseThrowStatement(): ThrowStatement { 6787 // ThrowStatement[Yield] : 6788 // throw [no LineTerminator here]Expression[In, ?Yield]; 6789 6790 const pos = getNodePos(); 6791 const hasJSDoc = hasPrecedingJSDocComment(); 6792 parseExpected(SyntaxKind.ThrowKeyword); 6793 6794 // Because of automatic semicolon insertion, we need to report error if this 6795 // throw could be terminated with a semicolon. Note: we can't call 'parseExpression' 6796 // directly as that might consume an expression on the following line. 6797 // Instead, we create a "missing" identifier, but don't report an error. The actual error 6798 // will be reported in the grammar walker. 6799 let expression = scanner.hasPrecedingLineBreak() ? undefined : allowInAnd(parseExpression); 6800 if (expression === undefined) { 6801 identifierCount++; 6802 expression = finishNode(factory.createIdentifier(""), getNodePos()); 6803 } 6804 if (!tryParseSemicolon()) { 6805 parseErrorForMissingSemicolonAfter(expression); 6806 } 6807 return withJSDoc(finishNode(factory.createThrowStatement(expression), pos), hasJSDoc); 6808 } 6809 6810 // TODO: Review for error recovery 6811 function parseTryStatement(): TryStatement { 6812 const pos = getNodePos(); 6813 const hasJSDoc = hasPrecedingJSDocComment(); 6814 6815 parseExpected(SyntaxKind.TryKeyword); 6816 const tryBlock = parseBlock(/*ignoreMissingOpenBrace*/ false); 6817 const catchClause = token() === SyntaxKind.CatchKeyword ? parseCatchClause() : undefined; 6818 6819 // If we don't have a catch clause, then we must have a finally clause. Try to parse 6820 // one out no matter what. 6821 let finallyBlock: Block | undefined; 6822 if (!catchClause || token() === SyntaxKind.FinallyKeyword) { 6823 parseExpected(SyntaxKind.FinallyKeyword, Diagnostics.catch_or_finally_expected); 6824 finallyBlock = parseBlock(/*ignoreMissingOpenBrace*/ false); 6825 } 6826 6827 return withJSDoc(finishNode(factory.createTryStatement(tryBlock, catchClause, finallyBlock), pos), hasJSDoc); 6828 } 6829 6830 function parseCatchClause(): CatchClause { 6831 const pos = getNodePos(); 6832 parseExpected(SyntaxKind.CatchKeyword); 6833 6834 let variableDeclaration; 6835 if (parseOptional(SyntaxKind.OpenParenToken)) { 6836 variableDeclaration = parseVariableDeclaration(); 6837 parseExpected(SyntaxKind.CloseParenToken); 6838 } 6839 else { 6840 // Keep shape of node to avoid degrading performance. 6841 variableDeclaration = undefined; 6842 } 6843 6844 const block = parseBlock(/*ignoreMissingOpenBrace*/ false); 6845 return finishNode(factory.createCatchClause(variableDeclaration, block), pos); 6846 } 6847 6848 function parseDebuggerStatement(): Statement { 6849 const pos = getNodePos(); 6850 const hasJSDoc = hasPrecedingJSDocComment(); 6851 parseExpected(SyntaxKind.DebuggerKeyword); 6852 parseSemicolon(); 6853 return withJSDoc(finishNode(factory.createDebuggerStatement(), pos), hasJSDoc); 6854 } 6855 6856 function parseExpressionOrLabeledStatement(): ExpressionStatement | LabeledStatement { 6857 // Avoiding having to do the lookahead for a labeled statement by just trying to parse 6858 // out an expression, seeing if it is identifier and then seeing if it is followed by 6859 // a colon. 6860 const pos = getNodePos(); 6861 let hasJSDoc = hasPrecedingJSDocComment(); 6862 let node: ExpressionStatement | LabeledStatement; 6863 const hasParen = token() === SyntaxKind.OpenParenToken; 6864 const expression = allowInAnd(parseExpression); 6865 if (ts.isIdentifier(expression) && parseOptional(SyntaxKind.ColonToken)) { 6866 node = factory.createLabeledStatement(expression, parseStatement()); 6867 } 6868 else { 6869 if (!tryParseSemicolon()) { 6870 parseErrorForMissingSemicolonAfter(expression); 6871 } 6872 node = factory.createExpressionStatement(expression); 6873 if (hasParen) { 6874 // do not parse the same jsdoc twice 6875 hasJSDoc = false; 6876 } 6877 } 6878 return withJSDoc(finishNode(node, pos), hasJSDoc); 6879 } 6880 6881 function nextTokenIsIdentifierOrKeywordOnSameLine() { 6882 nextToken(); 6883 return tokenIsIdentifierOrKeyword(token()) && !scanner.hasPrecedingLineBreak(); 6884 } 6885 6886 function nextTokenIsClassKeywordOnSameLine() { 6887 nextToken(); 6888 return token() === SyntaxKind.ClassKeyword && !scanner.hasPrecedingLineBreak(); 6889 } 6890 6891 function nextTokenIsFunctionKeywordOnSameLine() { 6892 nextToken(); 6893 return token() === SyntaxKind.FunctionKeyword && !scanner.hasPrecedingLineBreak(); 6894 } 6895 6896 function nextTokenIsIdentifierOrKeywordOrLiteralOnSameLine() { 6897 nextToken(); 6898 return (tokenIsIdentifierOrKeyword(token()) || token() === SyntaxKind.NumericLiteral || token() === SyntaxKind.BigIntLiteral || token() === SyntaxKind.StringLiteral) && !scanner.hasPrecedingLineBreak(); 6899 } 6900 6901 function isDeclaration(): boolean { 6902 while (true) { 6903 switch (token()) { 6904 case SyntaxKind.VarKeyword: 6905 case SyntaxKind.LetKeyword: 6906 case SyntaxKind.ConstKeyword: 6907 case SyntaxKind.FunctionKeyword: 6908 case SyntaxKind.ClassKeyword: 6909 case SyntaxKind.EnumKeyword: 6910 return true; 6911 case SyntaxKind.StructKeyword: 6912 return inEtsContext(); 6913 6914 6915 // 'declare', 'module', 'namespace', 'interface'* and 'type' are all legal JavaScript identifiers; 6916 // however, an identifier cannot be followed by another identifier on the same line. This is what we 6917 // count on to parse out the respective declarations. For instance, we exploit this to say that 6918 // 6919 // namespace n 6920 // 6921 // can be none other than the beginning of a namespace declaration, but need to respect that JavaScript sees 6922 // 6923 // namespace 6924 // n 6925 // 6926 // as the identifier 'namespace' on one line followed by the identifier 'n' on another. 6927 // We need to look one token ahead to see if it permissible to try parsing a declaration. 6928 // 6929 // *Note*: 'interface' is actually a strict mode reserved word. So while 6930 // 6931 // "use strict" 6932 // interface 6933 // I {} 6934 // 6935 // could be legal, it would add complexity for very little gain. 6936 case SyntaxKind.InterfaceKeyword: 6937 case SyntaxKind.TypeKeyword: 6938 return nextTokenIsIdentifierOnSameLine(); 6939 case SyntaxKind.ModuleKeyword: 6940 case SyntaxKind.NamespaceKeyword: 6941 return nextTokenIsIdentifierOrStringLiteralOnSameLine(); 6942 case SyntaxKind.AbstractKeyword: 6943 case SyntaxKind.AccessorKeyword: 6944 case SyntaxKind.AsyncKeyword: 6945 case SyntaxKind.DeclareKeyword: 6946 case SyntaxKind.PrivateKeyword: 6947 case SyntaxKind.ProtectedKeyword: 6948 case SyntaxKind.PublicKeyword: 6949 case SyntaxKind.ReadonlyKeyword: 6950 nextToken(); 6951 // ASI takes effect for this modifier. 6952 if (scanner.hasPrecedingLineBreak()) { 6953 return false; 6954 } 6955 continue; 6956 6957 case SyntaxKind.GlobalKeyword: 6958 nextToken(); 6959 return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.Identifier || token() === SyntaxKind.ExportKeyword; 6960 6961 case SyntaxKind.ImportKeyword: 6962 nextToken(); 6963 return token() === SyntaxKind.StringLiteral || token() === SyntaxKind.AsteriskToken || 6964 token() === SyntaxKind.OpenBraceToken || tokenIsIdentifierOrKeyword(token()); 6965 case SyntaxKind.ExportKeyword: 6966 let currentToken = nextToken(); 6967 if (currentToken === SyntaxKind.TypeKeyword) { 6968 currentToken = lookAhead(nextToken); 6969 } 6970 if (currentToken === SyntaxKind.EqualsToken || currentToken === SyntaxKind.AsteriskToken || 6971 currentToken === SyntaxKind.OpenBraceToken || currentToken === SyntaxKind.DefaultKeyword || 6972 currentToken === SyntaxKind.AsKeyword) { 6973 return true; 6974 } 6975 continue; 6976 6977 case SyntaxKind.StaticKeyword: 6978 nextToken(); 6979 continue; 6980 default: 6981 return false; 6982 } 6983 } 6984 } 6985 6986 function isStartOfDeclaration(): boolean { 6987 return lookAhead(isDeclaration); 6988 } 6989 6990 function isStartOfStatement(): boolean { 6991 switch (token()) { 6992 case SyntaxKind.AtToken: 6993 case SyntaxKind.SemicolonToken: 6994 case SyntaxKind.OpenBraceToken: 6995 case SyntaxKind.VarKeyword: 6996 case SyntaxKind.LetKeyword: 6997 case SyntaxKind.FunctionKeyword: 6998 case SyntaxKind.ClassKeyword: 6999 case SyntaxKind.EnumKeyword: 7000 case SyntaxKind.IfKeyword: 7001 case SyntaxKind.DoKeyword: 7002 case SyntaxKind.WhileKeyword: 7003 case SyntaxKind.ForKeyword: 7004 case SyntaxKind.ContinueKeyword: 7005 case SyntaxKind.BreakKeyword: 7006 case SyntaxKind.ReturnKeyword: 7007 case SyntaxKind.WithKeyword: 7008 case SyntaxKind.SwitchKeyword: 7009 case SyntaxKind.ThrowKeyword: 7010 case SyntaxKind.TryKeyword: 7011 case SyntaxKind.DebuggerKeyword: 7012 // 'catch' and 'finally' do not actually indicate that the code is part of a statement, 7013 // however, we say they are here so that we may gracefully parse them and error later. 7014 // falls through 7015 case SyntaxKind.CatchKeyword: 7016 case SyntaxKind.FinallyKeyword: 7017 return true; 7018 case SyntaxKind.StructKeyword: 7019 return inEtsContext(); 7020 7021 case SyntaxKind.ImportKeyword: 7022 return isStartOfDeclaration() || lookAhead(nextTokenIsOpenParenOrLessThanOrDot); 7023 7024 case SyntaxKind.ConstKeyword: 7025 case SyntaxKind.ExportKeyword: 7026 return isStartOfDeclaration(); 7027 7028 case SyntaxKind.AsyncKeyword: 7029 case SyntaxKind.DeclareKeyword: 7030 case SyntaxKind.InterfaceKeyword: 7031 case SyntaxKind.ModuleKeyword: 7032 case SyntaxKind.NamespaceKeyword: 7033 case SyntaxKind.TypeKeyword: 7034 case SyntaxKind.GlobalKeyword: 7035 // When these don't start a declaration, they're an identifier in an expression statement 7036 return true; 7037 7038 case SyntaxKind.AccessorKeyword: 7039 case SyntaxKind.PublicKeyword: 7040 case SyntaxKind.PrivateKeyword: 7041 case SyntaxKind.ProtectedKeyword: 7042 case SyntaxKind.StaticKeyword: 7043 case SyntaxKind.ReadonlyKeyword: 7044 // When these don't start a declaration, they may be the start of a class member if an identifier 7045 // immediately follows. Otherwise they're an identifier in an expression statement. 7046 return isStartOfDeclaration() || !lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine); 7047 7048 default: 7049 return isStartOfExpression(); 7050 } 7051 } 7052 7053 function nextTokenIsBindingIdentifierOrStartOfDestructuring() { 7054 nextToken(); 7055 return isBindingIdentifier() || token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.OpenBracketToken; 7056 } 7057 7058 function isLetDeclaration() { 7059 // In ES6 'let' always starts a lexical declaration if followed by an identifier or { 7060 // or [. 7061 return lookAhead(nextTokenIsBindingIdentifierOrStartOfDestructuring); 7062 } 7063 7064 function parseStatement(): Statement { 7065 switch (token()) { 7066 case SyntaxKind.SemicolonToken: 7067 return parseEmptyStatement(); 7068 case SyntaxKind.OpenBraceToken: 7069 return parseBlock(/*ignoreMissingOpenBrace*/ false); 7070 case SyntaxKind.VarKeyword: 7071 return parseVariableStatement(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined); 7072 case SyntaxKind.LetKeyword: 7073 if (isLetDeclaration()) { 7074 return parseVariableStatement(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined); 7075 } 7076 break; 7077 case SyntaxKind.FunctionKeyword: 7078 return parseFunctionDeclaration(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined); 7079 case SyntaxKind.StructKeyword: 7080 if (inEtsContext()) { 7081 return parseStructDeclaration(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined); 7082 } 7083 break; 7084 case SyntaxKind.ClassKeyword: 7085 return parseClassDeclaration(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined); 7086 case SyntaxKind.IfKeyword: 7087 return parseIfStatement(); 7088 case SyntaxKind.DoKeyword: 7089 return parseDoStatement(); 7090 case SyntaxKind.WhileKeyword: 7091 return parseWhileStatement(); 7092 case SyntaxKind.ForKeyword: 7093 return parseForOrForInOrForOfStatement(); 7094 case SyntaxKind.ContinueKeyword: 7095 return parseBreakOrContinueStatement(SyntaxKind.ContinueStatement); 7096 case SyntaxKind.BreakKeyword: 7097 return parseBreakOrContinueStatement(SyntaxKind.BreakStatement); 7098 case SyntaxKind.ReturnKeyword: 7099 return parseReturnStatement(); 7100 case SyntaxKind.WithKeyword: 7101 return parseWithStatement(); 7102 case SyntaxKind.SwitchKeyword: 7103 return parseSwitchStatement(); 7104 case SyntaxKind.ThrowKeyword: 7105 return parseThrowStatement(); 7106 case SyntaxKind.TryKeyword: 7107 // Include 'catch' and 'finally' for error recovery. 7108 // falls through 7109 case SyntaxKind.CatchKeyword: 7110 case SyntaxKind.FinallyKeyword: 7111 return parseTryStatement(); 7112 case SyntaxKind.DebuggerKeyword: 7113 return parseDebuggerStatement(); 7114 case SyntaxKind.AtToken: 7115 return parseDeclaration(); 7116 case SyntaxKind.AsyncKeyword: 7117 case SyntaxKind.InterfaceKeyword: 7118 case SyntaxKind.TypeKeyword: 7119 case SyntaxKind.ModuleKeyword: 7120 case SyntaxKind.NamespaceKeyword: 7121 case SyntaxKind.DeclareKeyword: 7122 case SyntaxKind.ConstKeyword: 7123 case SyntaxKind.EnumKeyword: 7124 case SyntaxKind.ExportKeyword: 7125 case SyntaxKind.ImportKeyword: 7126 case SyntaxKind.PrivateKeyword: 7127 case SyntaxKind.ProtectedKeyword: 7128 case SyntaxKind.PublicKeyword: 7129 case SyntaxKind.AbstractKeyword: 7130 case SyntaxKind.AccessorKeyword: 7131 case SyntaxKind.StaticKeyword: 7132 case SyntaxKind.ReadonlyKeyword: 7133 case SyntaxKind.GlobalKeyword: 7134 if (isStartOfDeclaration()) { 7135 return parseDeclaration(); 7136 } 7137 break; 7138 } 7139 return parseExpressionOrLabeledStatement(); 7140 } 7141 7142 function isDeclareModifier(modifier: Modifier) { 7143 return modifier.kind === SyntaxKind.DeclareKeyword; 7144 } 7145 7146 function parseDeclaration(): Statement { 7147 // `parseListElement` attempted to get the reused node at this position, 7148 // but the ambient context flag was not yet set, so the node appeared 7149 // not reusable in that context. 7150 const pos = getNodePos(); 7151 const hasJSDoc = hasPrecedingJSDocComment(); 7152 const decorators = parseDecorators(); 7153 7154 if (token() === SyntaxKind.FunctionKeyword || token() === SyntaxKind.ExportKeyword) { 7155 if (hasEtsExtendDecoratorNames(decorators, sourceFileCompilerOptions)) { 7156 const extendEtsComponentDecoratorNames = getEtsExtendDecoratorsComponentNames(decorators, sourceFileCompilerOptions); 7157 if (extendEtsComponentDecoratorNames.length > 0) { 7158 sourceFileCompilerOptions.ets?.extend.components.forEach(({ name, type, instance }) => { 7159 if (name === last(extendEtsComponentDecoratorNames)) { 7160 extendEtsComponentDeclaration = { name, type, instance }; 7161 } 7162 }); 7163 } 7164 setEtsExtendComponentsContext(!!extendEtsComponentDeclaration); 7165 } 7166 else if (hasEtsStylesDecoratorNames(decorators, sourceFileCompilerOptions)) { 7167 const stylesEtsComponentDecoratorNames = getEtsStylesDecoratorComponentNames(decorators, sourceFileCompilerOptions); 7168 if (stylesEtsComponentDecoratorNames.length > 0) { 7169 stylesEtsComponentDeclaration = sourceFileCompilerOptions.ets?.styles.component; 7170 } 7171 setEtsStylesComponentsContext(!!stylesEtsComponentDeclaration); 7172 } 7173 else { 7174 setEtsComponentsContext(isTokenInsideBuilder(decorators, sourceFileCompilerOptions)); 7175 } 7176 } 7177 7178 const modifiers = parseModifiers(); 7179 const isAmbient = some(modifiers, isDeclareModifier); 7180 if (isAmbient) { 7181 const node = tryReuseAmbientDeclaration(pos); 7182 if (node) { 7183 return node; 7184 } 7185 7186 for (const m of modifiers!) { 7187 (m as Mutable<Node>).flags |= NodeFlags.Ambient; 7188 } 7189 return doInsideOfContext(NodeFlags.Ambient, () => parseDeclarationWorker(pos, hasJSDoc, decorators, modifiers)); 7190 } 7191 else { 7192 return parseDeclarationWorker(pos, hasJSDoc, decorators, modifiers); 7193 } 7194 } 7195 7196 function tryReuseAmbientDeclaration(pos: number): Statement | undefined { 7197 return doInsideOfContext(NodeFlags.Ambient, () => { 7198 const node = currentNode(parsingContext, pos); 7199 if (node) { 7200 return consumeNode(node) as Statement; 7201 } 7202 }); 7203 } 7204 7205 function parseDeclarationWorker(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): Statement { 7206 switch (token()) { 7207 case SyntaxKind.VarKeyword: 7208 case SyntaxKind.LetKeyword: 7209 case SyntaxKind.ConstKeyword: 7210 return parseVariableStatement(pos, hasJSDoc, decorators, modifiers); 7211 case SyntaxKind.FunctionKeyword: 7212 return parseFunctionDeclaration(pos, hasJSDoc, decorators, modifiers); 7213 case SyntaxKind.ClassKeyword: 7214 return parseClassDeclaration(pos, hasJSDoc, decorators, modifiers); 7215 case SyntaxKind.StructKeyword: 7216 if (inEtsContext()) { 7217 return parseStructDeclaration(pos, hasJSDoc, decorators, modifiers); 7218 } 7219 return parseDeclarationDefault(pos,decorators, modifiers); 7220 case SyntaxKind.InterfaceKeyword: 7221 return parseInterfaceDeclaration(pos, hasJSDoc, decorators, modifiers); 7222 case SyntaxKind.TypeKeyword: 7223 return parseTypeAliasDeclaration(pos, hasJSDoc, decorators, modifiers); 7224 case SyntaxKind.EnumKeyword: 7225 return parseEnumDeclaration(pos, hasJSDoc, decorators, modifiers); 7226 case SyntaxKind.GlobalKeyword: 7227 case SyntaxKind.ModuleKeyword: 7228 case SyntaxKind.NamespaceKeyword: 7229 return parseModuleDeclaration(pos, hasJSDoc, decorators, modifiers); 7230 case SyntaxKind.ImportKeyword: 7231 return parseImportDeclarationOrImportEqualsDeclaration(pos, hasJSDoc, decorators, modifiers); 7232 case SyntaxKind.ExportKeyword: 7233 nextToken(); 7234 switch (token()) { 7235 case SyntaxKind.DefaultKeyword: 7236 case SyntaxKind.EqualsToken: 7237 return parseExportAssignment(pos, hasJSDoc, decorators, modifiers); 7238 case SyntaxKind.AsKeyword: 7239 return parseNamespaceExportDeclaration(pos, hasJSDoc, decorators, modifiers); 7240 default: 7241 return parseExportDeclaration(pos, hasJSDoc, decorators, modifiers); 7242 } 7243 default: 7244 return parseDeclarationDefault(pos,decorators, modifiers); 7245 } 7246 } 7247 7248 function parseDeclarationDefault(pos: number,decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): Statement { 7249 if (decorators || modifiers) { 7250 // We reached this point because we encountered decorators and/or modifiers and assumed a declaration 7251 // would follow. For recovery and error reporting purposes, return an incomplete declaration. 7252 const missing = createMissingNode<MissingDeclaration>(SyntaxKind.MissingDeclaration, /*reportAtCurrentPosition*/ true, Diagnostics.Declaration_expected); 7253 setTextRangePos(missing, pos); 7254 missing.illegalDecorators = decorators; 7255 missing.modifiers = modifiers; 7256 return missing; 7257 } 7258 return undefined!; // TODO: GH#18217 7259 } 7260 7261 function nextTokenIsIdentifierOrStringLiteralOnSameLine() { 7262 nextToken(); 7263 return !scanner.hasPrecedingLineBreak() && (isIdentifier() || token() === SyntaxKind.StringLiteral); 7264 } 7265 7266 function parseFunctionBlockOrSemicolon(flags: SignatureFlags, diagnosticMessage?: DiagnosticMessage): Block | undefined { 7267 if (token() !== SyntaxKind.OpenBraceToken) { 7268 if (flags & SignatureFlags.Type) { 7269 parseTypeMemberSemicolon(); 7270 return; 7271 } 7272 if (canParseSemicolon()) { 7273 parseSemicolon(); 7274 return; 7275 } 7276 } 7277 return parseFunctionBlock(flags, diagnosticMessage); 7278 } 7279 7280 // DECLARATIONS 7281 7282 function parseArrayBindingElement(): ArrayBindingElement { 7283 const pos = getNodePos(); 7284 if (token() === SyntaxKind.CommaToken) { 7285 return finishNode(factory.createOmittedExpression(), pos); 7286 } 7287 const dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); 7288 const name = parseIdentifierOrPattern(); 7289 const initializer = parseInitializer(); 7290 return finishNode(factory.createBindingElement(dotDotDotToken, /*propertyName*/ undefined, name, initializer), pos); 7291 } 7292 7293 function parseObjectBindingElement(): BindingElement { 7294 const pos = getNodePos(); 7295 const dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); 7296 const tokenIsIdentifier = isBindingIdentifier(); 7297 let propertyName: PropertyName | undefined = parsePropertyName(); 7298 let name: BindingName; 7299 if (tokenIsIdentifier && token() !== SyntaxKind.ColonToken) { 7300 name = propertyName as Identifier; 7301 propertyName = undefined; 7302 } 7303 else { 7304 parseExpected(SyntaxKind.ColonToken); 7305 name = parseIdentifierOrPattern(); 7306 } 7307 const initializer = parseInitializer(); 7308 return finishNode(factory.createBindingElement(dotDotDotToken, propertyName, name, initializer), pos); 7309 } 7310 7311 function parseObjectBindingPattern(): ObjectBindingPattern { 7312 const pos = getNodePos(); 7313 parseExpected(SyntaxKind.OpenBraceToken); 7314 const elements = parseDelimitedList(ParsingContext.ObjectBindingElements, parseObjectBindingElement); 7315 parseExpected(SyntaxKind.CloseBraceToken); 7316 return finishNode(factory.createObjectBindingPattern(elements), pos); 7317 } 7318 7319 function parseArrayBindingPattern(): ArrayBindingPattern { 7320 const pos = getNodePos(); 7321 parseExpected(SyntaxKind.OpenBracketToken); 7322 const elements = parseDelimitedList(ParsingContext.ArrayBindingElements, parseArrayBindingElement); 7323 parseExpected(SyntaxKind.CloseBracketToken); 7324 return finishNode(factory.createArrayBindingPattern(elements), pos); 7325 } 7326 7327 function isBindingIdentifierOrPrivateIdentifierOrPattern() { 7328 return token() === SyntaxKind.OpenBraceToken 7329 || token() === SyntaxKind.OpenBracketToken 7330 || token() === SyntaxKind.PrivateIdentifier 7331 || isBindingIdentifier(); 7332 } 7333 7334 function parseIdentifierOrPattern(privateIdentifierDiagnosticMessage?: DiagnosticMessage): Identifier | BindingPattern { 7335 if (token() === SyntaxKind.OpenBracketToken) { 7336 return parseArrayBindingPattern(); 7337 } 7338 if (token() === SyntaxKind.OpenBraceToken) { 7339 return parseObjectBindingPattern(); 7340 } 7341 return parseBindingIdentifier(privateIdentifierDiagnosticMessage); 7342 } 7343 7344 function parseVariableDeclarationAllowExclamation() { 7345 return parseVariableDeclaration(/*allowExclamation*/ true); 7346 } 7347 7348 function parseVariableDeclaration(allowExclamation?: boolean): VariableDeclaration { 7349 const pos = getNodePos(); 7350 const hasJSDoc = hasPrecedingJSDocComment(); 7351 const name = parseIdentifierOrPattern(Diagnostics.Private_identifiers_are_not_allowed_in_variable_declarations); 7352 let exclamationToken: ExclamationToken | undefined; 7353 if (allowExclamation && name.kind === SyntaxKind.Identifier && 7354 token() === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak()) { 7355 exclamationToken = parseTokenNode<Token<SyntaxKind.ExclamationToken>>(); 7356 } 7357 const type = parseTypeAnnotation(); 7358 const initializer = isInOrOfKeyword(token()) ? undefined : parseInitializer(); 7359 const node = factory.createVariableDeclaration(name, exclamationToken, type, initializer); 7360 return withJSDoc(finishNode(node, pos), hasJSDoc); 7361 } 7362 7363 function parseVariableDeclarationList(inForStatementInitializer: boolean): VariableDeclarationList { 7364 const pos = getNodePos(); 7365 7366 let flags: NodeFlags = 0; 7367 switch (token()) { 7368 case SyntaxKind.VarKeyword: 7369 break; 7370 case SyntaxKind.LetKeyword: 7371 flags |= NodeFlags.Let; 7372 break; 7373 case SyntaxKind.ConstKeyword: 7374 flags |= NodeFlags.Const; 7375 break; 7376 default: 7377 Debug.fail(); 7378 } 7379 7380 nextToken(); 7381 7382 // The user may have written the following: 7383 // 7384 // for (let of X) { } 7385 // 7386 // In this case, we want to parse an empty declaration list, and then parse 'of' 7387 // as a keyword. The reason this is not automatic is that 'of' is a valid identifier. 7388 // So we need to look ahead to determine if 'of' should be treated as a keyword in 7389 // this context. 7390 // The checker will then give an error that there is an empty declaration list. 7391 let declarations: readonly VariableDeclaration[]; 7392 if (token() === SyntaxKind.OfKeyword && lookAhead(canFollowContextualOfKeyword)) { 7393 declarations = createMissingList<VariableDeclaration>(); 7394 } 7395 else { 7396 const savedDisallowIn = inDisallowInContext(); 7397 setDisallowInContext(inForStatementInitializer); 7398 7399 declarations = parseDelimitedList(ParsingContext.VariableDeclarations, 7400 inForStatementInitializer ? parseVariableDeclaration : parseVariableDeclarationAllowExclamation); 7401 7402 setDisallowInContext(savedDisallowIn); 7403 } 7404 7405 return finishNode(factory.createVariableDeclarationList(declarations, flags), pos); 7406 } 7407 7408 function canFollowContextualOfKeyword(): boolean { 7409 return nextTokenIsIdentifier() && nextToken() === SyntaxKind.CloseParenToken; 7410 } 7411 7412 function parseVariableStatement(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): VariableStatement { 7413 const declarationList = parseVariableDeclarationList(/*inForStatementInitializer*/ false); 7414 parseSemicolon(); 7415 const node = factory.createVariableStatement(modifiers, declarationList); 7416 // Decorators are not allowed on a variable statement, so we keep track of them to report them in the grammar checker. 7417 node.illegalDecorators = decorators; 7418 return withJSDoc(finishNode(node, pos), hasJSDoc); 7419 } 7420 7421 function parseFunctionDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): FunctionDeclaration { 7422 const savedAwaitContext = inAwaitContext(); 7423 7424 const modifierFlags = modifiersToFlags(modifiers); 7425 parseExpected(SyntaxKind.FunctionKeyword); 7426 const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); 7427 // We don't parse the name here in await context, instead we will report a grammar error in the checker. 7428 const name = modifierFlags & ModifierFlags.Default ? parseOptionalBindingIdentifier() : parseBindingIdentifier(); 7429 if(name && hasEtsStylesDecoratorNames(decorators, sourceFileCompilerOptions)) { 7430 fileStylesComponents.set(name.escapedText.toString(), SyntaxKind.FunctionDeclaration); 7431 } 7432 const originalUICallbackContext = inUICallbackContext(); 7433 setEtsBuilderContext(hasEtsBuilderDecoratorNames(decorators, sourceFileCompilerOptions)); 7434 setUICallbackContext(inBuilderContext()); 7435 const isGenerator = asteriskToken ? SignatureFlags.Yield : SignatureFlags.None; 7436 const isAsync = modifierFlags & ModifierFlags.Async ? SignatureFlags.Await : SignatureFlags.None; 7437 const typeParameters = inEtsStylesComponentsContext() && stylesEtsComponentDeclaration ? parseEtsTypeParameters(scanner.getStartPos()) : parseTypeParameters(); 7438 if (modifierFlags & ModifierFlags.Export) setAwaitContext(/*value*/ true); 7439 const parameters = parseParameters(isGenerator | isAsync); 7440 const typeStartPos = scanner.getStartPos(); 7441 const type = getFunctionDeclarationReturnType(); 7442 const body = parseFunctionBlockOrSemicolon(isGenerator | isAsync, Diagnostics.or_expected); 7443 setEtsBuilderContext(false); 7444 setUICallbackContext(originalUICallbackContext); 7445 setEtsExtendComponentsContext(false); 7446 extendEtsComponentDeclaration = undefined; 7447 setEtsStylesComponentsContext(false); 7448 stylesEtsComponentDeclaration = undefined; 7449 setEtsComponentsContext(inBuildContext()); 7450 setAwaitContext(savedAwaitContext); 7451 const node = factory.createFunctionDeclaration(modifiers, asteriskToken, name, typeParameters, parameters, type, body); 7452 (node as Mutable<FunctionDeclaration>).illegalDecorators = decorators; 7453 return withJSDoc(finishNode(node, pos), hasJSDoc); 7454 7455 function getFunctionDeclarationReturnType(): TypeNode | undefined { 7456 let returnType = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false); 7457 // If function decorated by Extend and type is not defined, then will use Ets Extend Components Type 7458 if (!returnType && extendEtsComponentDeclaration && inEtsExtendComponentsContext()) { 7459 returnType = finishVirtualNode(factory.createTypeReferenceNode( 7460 finishVirtualNode(factory.createIdentifier(extendEtsComponentDeclaration.type), typeStartPos, typeStartPos)), 7461 typeStartPos, typeStartPos); 7462 } 7463 // If function decorated by Styles and type is not defined, then will use Ets Styles Components Type 7464 if (!returnType && stylesEtsComponentDeclaration && inEtsStylesComponentsContext()) { 7465 returnType = finishVirtualNode(factory.createTypeReferenceNode( 7466 finishVirtualNode(factory.createIdentifier(stylesEtsComponentDeclaration.type), typeStartPos, typeStartPos)), 7467 typeStartPos, typeStartPos); 7468 } 7469 return returnType; 7470 } 7471 } 7472 7473 function parseConstructorName() { 7474 if (token() === SyntaxKind.ConstructorKeyword) { 7475 return parseExpected(SyntaxKind.ConstructorKeyword); 7476 } 7477 if (token() === SyntaxKind.StringLiteral && lookAhead(nextToken) === SyntaxKind.OpenParenToken) { 7478 return tryParse(() => { 7479 const literalNode = parseLiteralNode(); 7480 return literalNode.text === "constructor" ? literalNode : undefined; 7481 }); 7482 } 7483 } 7484 7485 function tryParseConstructorDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ConstructorDeclaration | undefined { 7486 return tryParse(() => { 7487 if (parseConstructorName()) { 7488 const typeParameters = parseTypeParameters(); 7489 const parameters = parseParameters(SignatureFlags.None); 7490 const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false); 7491 const body = parseFunctionBlockOrSemicolon(SignatureFlags.None, Diagnostics.or_expected); 7492 const node = factory.createConstructorDeclaration(modifiers, parameters, body); 7493 7494 // Attach invalid nodes if they exist so that we can report them in the grammar checker. 7495 (node as Mutable<ConstructorDeclaration>).illegalDecorators = decorators; 7496 (node as Mutable<ConstructorDeclaration>).typeParameters = typeParameters; 7497 (node as Mutable<ConstructorDeclaration>).type = type; 7498 return withJSDoc(finishNode(node, pos), hasJSDoc); 7499 } 7500 }); 7501 } 7502 7503 7504 function isTokenInsideStructBuild(methodName: PropertyName): boolean { 7505 const renderMethod = sourceFileCompilerOptions.ets?.render?.method?.find(render => render === "build") ?? "build"; 7506 7507 if (methodName.kind === SyntaxKind.Identifier && methodName.escapedText === renderMethod) { 7508 return true; 7509 } 7510 return false; 7511 } 7512 7513 function isTokenInsideStructBuilder(decorators: NodeArray<Decorator> | undefined): boolean { 7514 return isTokenInsideBuilder(decorators, sourceFileCompilerOptions); 7515 } 7516 7517 function isTokenInsideStructPageTransition(methodName: PropertyName): boolean { 7518 const renderMethod = sourceFileCompilerOptions.ets?.render?.method?.find(render => render === "pageTransition") ?? "pageTransition"; 7519 7520 if (methodName.kind === SyntaxKind.Identifier && methodName.escapedText === renderMethod) { 7521 return true; 7522 } 7523 return false; 7524 } 7525 7526 function parseMethodDeclaration( 7527 pos: number, 7528 hasJSDoc: boolean, 7529 decorators: NodeArray<Decorator> | undefined, 7530 modifiers: NodeArray<Modifier> | undefined, 7531 asteriskToken: AsteriskToken | undefined, 7532 name: PropertyName, 7533 questionToken: QuestionToken | undefined, 7534 exclamationToken: ExclamationToken | undefined, 7535 diagnosticMessage?: DiagnosticMessage 7536 ): MethodDeclaration { 7537 const methodName = getPropertyNameForPropertyNameNode(name)?.toString(); 7538 const orignalEtsBuildContext = inBuildContext(); 7539 const orignalEtsBuilderContext = inBuilderContext(); 7540 const orignalUICallbackContext = inUICallbackContext(); 7541 setEtsBuildContext(methodName === sourceFileCompilerOptions?.ets?.render?.method?.find(render => render === "build")); 7542 setEtsBuilderContext(hasEtsBuilderDecoratorNames(decorators, sourceFileCompilerOptions)); 7543 setUICallbackContext(inBuildContext() || inBuilderContext()); 7544 if (inStructContext() && hasEtsStylesDecoratorNames(decorators, sourceFileCompilerOptions)) { 7545 if (methodName && currentStructName) { 7546 structStylesComponents.set(methodName, { structName: currentStructName, kind: SyntaxKind.MethodDeclaration }); 7547 } 7548 const stylesEtsComponentDecoratorNames = getEtsStylesDecoratorComponentNames(decorators, sourceFileCompilerOptions); 7549 if (stylesEtsComponentDecoratorNames.length > 0) { 7550 stylesEtsComponentDeclaration = sourceFileCompilerOptions.ets?.styles.component; 7551 } 7552 setEtsStylesComponentsContext(!!stylesEtsComponentDeclaration); 7553 } 7554 const orignalEtsComponentsContext: boolean = inEtsComponentsContext(); 7555 setEtsComponentsContext(inStructContext() && (isTokenInsideStructBuild(name) || isTokenInsideStructBuilder(decorators) || 7556 isTokenInsideStructPageTransition(name))); 7557 const isGenerator = asteriskToken ? SignatureFlags.Yield : SignatureFlags.None; 7558 const isAsync = some(modifiers, isAsyncModifier) ? SignatureFlags.Await : SignatureFlags.None; 7559 const typeParameters = inEtsStylesComponentsContext() && stylesEtsComponentDeclaration ? parseEtsTypeParameters(pos) : parseTypeParameters(); 7560 const parameters = parseParameters(isGenerator | isAsync); 7561 const typeStartPos = scanner.getStartPos(); 7562 const type = getMethodDeclarationReturnType(); 7563 const body = parseFunctionBlockOrSemicolon(isGenerator | isAsync, diagnosticMessage); 7564 const node = factory.createMethodDeclaration( 7565 combineDecoratorsAndModifiers(decorators, modifiers), 7566 asteriskToken, 7567 name, 7568 questionToken, 7569 typeParameters, 7570 parameters, 7571 type, 7572 body 7573 ); 7574 7575 // An exclamation token on a method is invalid syntax and will be handled by the grammar checker 7576 (node as Mutable<MethodDeclaration>).exclamationToken = exclamationToken; 7577 setEtsBuildContext(orignalEtsBuildContext); 7578 setEtsBuilderContext(orignalEtsBuilderContext); 7579 setUICallbackContext(orignalUICallbackContext); 7580 setEtsStylesComponentsContext(false); 7581 stylesEtsComponentDeclaration = undefined; 7582 setEtsComponentsContext(orignalEtsComponentsContext); 7583 return withJSDoc(finishNode(node, pos), hasJSDoc); 7584 7585 function getMethodDeclarationReturnType(): TypeNode | undefined { 7586 let returnType = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false); 7587 // If function decorated by Styles and type is not defined, then will use Ets Styles Components Type 7588 if (!returnType && stylesEtsComponentDeclaration && inEtsStylesComponentsContext()) { 7589 returnType = finishVirtualNode(factory.createTypeReferenceNode( 7590 finishVirtualNode(factory.createIdentifier(stylesEtsComponentDeclaration.type), typeStartPos, typeStartPos)), 7591 typeStartPos, typeStartPos); 7592 } 7593 return returnType; 7594 } 7595 } 7596 7597 function parsePropertyDeclaration( 7598 pos: number, 7599 hasJSDoc: boolean, 7600 decorators: NodeArray<Decorator> | undefined, 7601 modifiers: NodeArray<Modifier> | undefined, 7602 name: PropertyName, 7603 questionToken: QuestionToken | undefined 7604 ): PropertyDeclaration { 7605 const exclamationToken = !questionToken && !scanner.hasPrecedingLineBreak() ? parseOptionalToken(SyntaxKind.ExclamationToken) : undefined; 7606 const type = parseTypeAnnotation(); 7607 const initializer = doOutsideOfContext(NodeFlags.YieldContext | NodeFlags.AwaitContext | NodeFlags.DisallowInContext, parseInitializer); 7608 parseSemicolonAfterPropertyName(name, type, initializer); 7609 const node = factory.createPropertyDeclaration( 7610 combineDecoratorsAndModifiers(decorators, modifiers), 7611 name, 7612 questionToken || exclamationToken, 7613 type, 7614 initializer); 7615 return withJSDoc(finishNode(node, pos), hasJSDoc); 7616 } 7617 7618 function parsePropertyOrMethodDeclaration( 7619 pos: number, 7620 hasJSDoc: boolean, 7621 decorators: NodeArray<Decorator> | undefined, 7622 modifiers: NodeArray<Modifier> | undefined 7623 ): PropertyDeclaration | MethodDeclaration { 7624 const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); 7625 const name = parsePropertyName(); 7626 // Note: this is not legal as per the grammar. But we allow it in the parser and 7627 // report an error in the grammar checker. 7628 const questionToken = parseOptionalToken(SyntaxKind.QuestionToken); 7629 if (asteriskToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) { 7630 return parseMethodDeclaration(pos, hasJSDoc, decorators, modifiers, asteriskToken, name, questionToken, /*exclamationToken*/ undefined, Diagnostics.or_expected); 7631 } 7632 return parsePropertyDeclaration(pos, hasJSDoc, decorators, modifiers, name, questionToken); 7633 } 7634 7635 function parseAccessorDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined, kind: AccessorDeclaration["kind"], flags: SignatureFlags): AccessorDeclaration { 7636 const name = parsePropertyName(); 7637 const typeParameters = parseTypeParameters(); 7638 const parameters = parseParameters(SignatureFlags.None); 7639 const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false); 7640 const body = parseFunctionBlockOrSemicolon(flags); 7641 const node = kind === SyntaxKind.GetAccessor 7642 ? factory.createGetAccessorDeclaration(combineDecoratorsAndModifiers(decorators, modifiers), name, parameters, type, body) 7643 : factory.createSetAccessorDeclaration(combineDecoratorsAndModifiers(decorators, modifiers), name, parameters, body); 7644 // Keep track of `typeParameters` (for both) and `type` (for setters) if they were parsed those indicate grammar errors 7645 (node as Mutable<AccessorDeclaration>).typeParameters = typeParameters; 7646 if (isSetAccessorDeclaration(node)) (node as Mutable<SetAccessorDeclaration>).type = type; 7647 return withJSDoc(finishNode(node, pos), hasJSDoc); 7648 } 7649 7650 function isClassMemberStart(): boolean { 7651 let idToken: SyntaxKind | undefined; 7652 7653 if (token() === SyntaxKind.AtToken) { 7654 return true; 7655 } 7656 7657 // Eat up all modifiers, but hold on to the last one in case it is actually an identifier. 7658 while (isModifierKind(token())) { 7659 idToken = token(); 7660 // If the idToken is a class modifier (protected, private, public, and static), it is 7661 // certain that we are starting to parse class member. This allows better error recovery 7662 // Example: 7663 // public foo() ... // true 7664 // public @dec blah ... // true; we will then report an error later 7665 // export public ... // true; we will then report an error later 7666 if (isClassMemberModifier(idToken)) { 7667 return true; 7668 } 7669 7670 nextToken(); 7671 } 7672 7673 if (token() === SyntaxKind.AsteriskToken) { 7674 return true; 7675 } 7676 7677 // Try to get the first property-like token following all modifiers. 7678 // This can either be an identifier or the 'get' or 'set' keywords. 7679 if (isLiteralPropertyName()) { 7680 idToken = token(); 7681 nextToken(); 7682 } 7683 7684 // Index signatures and computed properties are class members; we can parse. 7685 if (token() === SyntaxKind.OpenBracketToken) { 7686 return true; 7687 } 7688 7689 // If we were able to get any potential identifier... 7690 if (idToken !== undefined) { 7691 // If we have a non-keyword identifier, or if we have an accessor, then it's safe to parse. 7692 if (!isKeyword(idToken) || idToken === SyntaxKind.SetKeyword || idToken === SyntaxKind.GetKeyword) { 7693 return true; 7694 } 7695 7696 // If it *is* a keyword, but not an accessor, check a little farther along 7697 // to see if it should actually be parsed as a class member. 7698 switch (token()) { 7699 case SyntaxKind.OpenParenToken: // Method declaration 7700 case SyntaxKind.LessThanToken: // Generic Method declaration 7701 case SyntaxKind.ExclamationToken: // Non-null assertion on property name 7702 case SyntaxKind.ColonToken: // Type Annotation for declaration 7703 case SyntaxKind.EqualsToken: // Initializer for declaration 7704 case SyntaxKind.QuestionToken: // Not valid, but permitted so that it gets caught later on. 7705 return true; 7706 default: 7707 // Covers 7708 // - Semicolons (declaration termination) 7709 // - Closing braces (end-of-class, must be declaration) 7710 // - End-of-files (not valid, but permitted so that it gets caught later on) 7711 // - Line-breaks (enabling *automatic semicolon insertion*) 7712 return canParseSemicolon(); 7713 } 7714 } 7715 7716 return false; 7717 } 7718 7719 function parseClassStaticBlockDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: ModifiersArray | undefined): ClassStaticBlockDeclaration { 7720 parseExpectedToken(SyntaxKind.StaticKeyword); 7721 const body = parseClassStaticBlockBody(); 7722 const node = withJSDoc(finishNode(factory.createClassStaticBlockDeclaration(body), pos), hasJSDoc); 7723 (node as Mutable<ClassStaticBlockDeclaration>).illegalDecorators = decorators; 7724 (node as Mutable<ClassStaticBlockDeclaration>).modifiers = modifiers; 7725 return node; 7726 } 7727 7728 function parseClassStaticBlockBody() { 7729 const savedYieldContext = inYieldContext(); 7730 const savedAwaitContext = inAwaitContext(); 7731 7732 setYieldContext(false); 7733 setAwaitContext(true); 7734 7735 const body = parseBlock(/*ignoreMissingOpenBrace*/ false); 7736 7737 setYieldContext(savedYieldContext); 7738 setAwaitContext(savedAwaitContext); 7739 7740 return body; 7741 } 7742 7743 function parseDecoratorExpression() { 7744 if (inAwaitContext() && token() === SyntaxKind.AwaitKeyword) { 7745 // `@await` is is disallowed in an [Await] context, but can cause parsing to go off the rails 7746 // This simply parses the missing identifier and moves on. 7747 const pos = getNodePos(); 7748 const awaitExpression = parseIdentifier(Diagnostics.Expression_expected); 7749 nextToken(); 7750 const memberExpression = parseMemberExpressionRest(pos, awaitExpression, /*allowOptionalChain*/ true); 7751 return parseCallExpressionRest(pos, memberExpression); 7752 } 7753 return parseLeftHandSideExpressionOrHigher(); 7754 } 7755 7756 function tryParseDecorator(): Decorator | undefined { 7757 const pos = getNodePos(); 7758 if (!parseOptional(SyntaxKind.AtToken)) { 7759 return undefined; 7760 } 7761 const expression = doInDecoratorContext(parseDecoratorExpression); 7762 return finishNode(factory.createDecorator(expression), pos); 7763 } 7764 7765 function parseDecorators(): NodeArray<Decorator> | undefined { 7766 const pos = getNodePos(); 7767 let list, decorator; 7768 while (decorator = tryParseDecorator()) { 7769 list = append(list, decorator); 7770 } 7771 return list && createNodeArray(list, pos); 7772 } 7773 7774 function tryParseModifier(permitInvalidConstAsModifier?: boolean, stopOnStartOfClassStaticBlock?: boolean, hasSeenStaticModifier?: boolean): Modifier | undefined { 7775 const pos = getNodePos(); 7776 const kind = token(); 7777 7778 if (token() === SyntaxKind.ConstKeyword && permitInvalidConstAsModifier) { 7779 // We need to ensure that any subsequent modifiers appear on the same line 7780 // so that when 'const' is a standalone declaration, we don't issue an error. 7781 if (!tryParse(nextTokenIsOnSameLineAndCanFollowModifier)) { 7782 return undefined; 7783 } 7784 } 7785 else if (stopOnStartOfClassStaticBlock && token() === SyntaxKind.StaticKeyword && lookAhead(nextTokenIsOpenBrace)) { 7786 return undefined; 7787 } 7788 else if (hasSeenStaticModifier && token() === SyntaxKind.StaticKeyword) { 7789 return undefined; 7790 } 7791 else { 7792 if (!parseAnyContextualModifier()) { 7793 return undefined; 7794 } 7795 } 7796 7797 return finishNode(factory.createToken(kind as Modifier["kind"]), pos); 7798 } 7799 7800 function combineDecoratorsAndModifiers(decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): NodeArray<ModifierLike> | undefined { 7801 if (!decorators) return modifiers; 7802 if (!modifiers) return decorators; 7803 const decoratorsAndModifiers = factory.createNodeArray(concatenate<ModifierLike>(decorators, modifiers)); 7804 setTextRangePosEnd(decoratorsAndModifiers, decorators.pos, modifiers.end); 7805 return decoratorsAndModifiers; 7806 } 7807 7808 function hasParamAndNoOnceDecorator(decorators: NodeArray<Decorator> | undefined): boolean { 7809 let hasParamDecorator = false; 7810 let hasOnceDecorator = false; 7811 decorators?.forEach((decorator) => { 7812 if (!ts.isIdentifier(decorator.expression)) { 7813 return; 7814 } 7815 if (decorator.expression.escapedText === 'Param') { 7816 hasParamDecorator = true; 7817 } 7818 else if (decorator.expression.escapedText === 'Once') { 7819 hasOnceDecorator = true; 7820 } 7821 }); 7822 return (hasParamDecorator && !hasOnceDecorator); 7823 } 7824 /* 7825 * There are situations in which a modifier like 'const' will appear unexpectedly, such as on a class member. 7826 * In those situations, if we are entirely sure that 'const' is not valid on its own (such as when ASI takes effect 7827 * and turns it into a standalone declaration), then it is better to parse it and report an error later. 7828 * 7829 * In such situations, 'permitInvalidConstAsModifier' should be set to true. 7830 */ 7831 function parseModifiers( 7832 permitInvalidConstAsModifier?: boolean, 7833 stopOnStartOfClassStaticBlock?: boolean, 7834 shouldAddReadonly?: boolean 7835 ): NodeArray<Modifier> | undefined { 7836 const pos = getNodePos(); 7837 let list, modifier, hasSeenStatic = false; 7838 let hasReadonly = false; 7839 while (modifier = tryParseModifier(permitInvalidConstAsModifier, stopOnStartOfClassStaticBlock, hasSeenStatic)) { 7840 if (modifier.kind === SyntaxKind.StaticKeyword) hasSeenStatic = true; 7841 if (modifier.kind === SyntaxKind.ReadonlyKeyword) { 7842 hasReadonly = true; 7843 } 7844 list = append(list, modifier); 7845 } 7846 if (shouldAddReadonly && !hasReadonly) { 7847 const readonlyModifier = finishVirtualNode(factory.createToken(SyntaxKind.ReadonlyKeyword)); 7848 list = append(list, readonlyModifier); 7849 } 7850 return list && createNodeArray(list, pos); 7851 } 7852 7853 function parseModifiersForArrowFunction(): NodeArray<Modifier> | undefined { 7854 let modifiers: NodeArray<Modifier> | undefined; 7855 if (token() === SyntaxKind.AsyncKeyword) { 7856 const pos = getNodePos(); 7857 nextToken(); 7858 const modifier = finishNode(factory.createToken(SyntaxKind.AsyncKeyword), pos); 7859 modifiers = createNodeArray<Modifier>([modifier], pos); 7860 } 7861 return modifiers; 7862 } 7863 7864 function parseClassElement(): ClassElement { 7865 const pos = getNodePos(); 7866 if (token() === SyntaxKind.SemicolonToken) { 7867 nextToken(); 7868 return finishNode(factory.createSemicolonClassElement(), pos); 7869 } 7870 7871 const hasJSDoc = hasPrecedingJSDocComment(); 7872 const decorators = parseDecorators(); 7873 /* 7874 * shouldAddReadonly adds readonly modifier when the element in struct has the Param decorator 7875 * and doesn't have Once decorator. 7876 */ 7877 const shouldAddReadonly = inStructContext() && hasParamAndNoOnceDecorator(decorators); 7878 const modifiers = parseModifiers(/*permitInvalidConstAsModifier*/ true, /*stopOnStartOfClassStaticBlock*/ true, shouldAddReadonly); 7879 if (token() === SyntaxKind.StaticKeyword && lookAhead(nextTokenIsOpenBrace)) { 7880 return parseClassStaticBlockDeclaration(pos, hasJSDoc, decorators, modifiers); 7881 } 7882 7883 if (parseContextualModifier(SyntaxKind.GetKeyword)) { 7884 return parseAccessorDeclaration(pos, hasJSDoc, decorators, modifiers, SyntaxKind.GetAccessor, SignatureFlags.None); 7885 } 7886 7887 if (parseContextualModifier(SyntaxKind.SetKeyword)) { 7888 return parseAccessorDeclaration(pos, hasJSDoc, decorators, modifiers, SyntaxKind.SetAccessor, SignatureFlags.None); 7889 } 7890 7891 if (token() === SyntaxKind.ConstructorKeyword || token() === SyntaxKind.StringLiteral) { 7892 const constructorDeclaration = tryParseConstructorDeclaration(pos, hasJSDoc, decorators, modifiers); 7893 if (constructorDeclaration) { 7894 return constructorDeclaration; 7895 } 7896 } 7897 7898 if (isIndexSignature()) { 7899 return parseIndexSignatureDeclaration(pos, hasJSDoc, decorators, modifiers); 7900 } 7901 7902 // It is very important that we check this *after* checking indexers because 7903 // the [ token can start an index signature or a computed property name 7904 if (tokenIsIdentifierOrKeyword(token()) || 7905 token() === SyntaxKind.StringLiteral || 7906 token() === SyntaxKind.NumericLiteral || 7907 token() === SyntaxKind.AsteriskToken || 7908 token() === SyntaxKind.OpenBracketToken) { 7909 const isAmbient = some(modifiers, isDeclareModifier); 7910 if (isAmbient) { 7911 for (const m of modifiers!) { 7912 (m as Mutable<Node>).flags |= NodeFlags.Ambient; 7913 } 7914 return doInsideOfContext(NodeFlags.Ambient, () => parsePropertyOrMethodDeclaration(pos, hasJSDoc, decorators, modifiers)); 7915 } 7916 else { 7917 return parsePropertyOrMethodDeclaration(pos, hasJSDoc, decorators, modifiers); 7918 } 7919 } 7920 7921 if (decorators || modifiers) { 7922 // treat this as a property declaration with a missing name. 7923 const name = createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Declaration_expected); 7924 return parsePropertyDeclaration(pos, hasJSDoc, decorators, modifiers, name, /*questionToken*/ undefined); 7925 } 7926 7927 // 'isClassMemberStart' should have hinted not to attempt parsing. 7928 return Debug.fail("Should not have attempted to parse class member declaration."); 7929 } 7930 7931 function parseClassExpression(): ClassExpression { 7932 return parseClassDeclarationOrExpression(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined, SyntaxKind.ClassExpression) as ClassExpression; 7933 } 7934 7935 function parseClassDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ClassDeclaration { 7936 return parseClassDeclarationOrExpression(pos, hasJSDoc, decorators, modifiers, SyntaxKind.ClassDeclaration) as ClassDeclaration; 7937 } 7938 7939 function parseStructDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): StructDeclaration { 7940 return parseStructDeclarationOrExpression(pos, hasJSDoc, decorators, modifiers); 7941 } 7942 7943 function parseClassDeclarationOrExpression(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined, kind: ClassLikeDeclaration["kind"]): ClassLikeDeclaration { 7944 const savedAwaitContext = inAwaitContext(); 7945 parseExpected(SyntaxKind.ClassKeyword); 7946 7947 // We don't parse the name here in await context, instead we will report a grammar error in the checker. 7948 const name = parseNameOfClassDeclarationOrExpression(); 7949 const typeParameters = parseTypeParameters(); 7950 if (some(modifiers, isExportModifier)) setAwaitContext(/*value*/ true); 7951 const heritageClauses = parseHeritageClauses(); 7952 7953 let members; 7954 if (parseExpected(SyntaxKind.OpenBraceToken)) { 7955 // ClassTail[Yield,Await] : (Modified) See 14.5 7956 // ClassHeritage[?Yield,?Await]opt { ClassBody[?Yield,?Await]opt } 7957 members = parseClassMembers(); 7958 parseExpected(SyntaxKind.CloseBraceToken); 7959 } 7960 else { 7961 members = createMissingList<ClassElement>(); 7962 } 7963 setAwaitContext(savedAwaitContext); 7964 const node = kind === SyntaxKind.ClassDeclaration 7965 ? factory.createClassDeclaration(combineDecoratorsAndModifiers(decorators, modifiers), name, typeParameters, heritageClauses, members) 7966 : factory.createClassExpression(combineDecoratorsAndModifiers(decorators, modifiers), name, typeParameters, heritageClauses, members); 7967 return withJSDoc(finishNode(node, pos), hasJSDoc); 7968 } 7969 7970 function parseStructDeclarationOrExpression(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): StructDeclaration { 7971 const savedAwaitContext = inAwaitContext(); 7972 parseExpected(SyntaxKind.StructKeyword); 7973 setStructContext(true); 7974 // We don't parse the name here in await context, instead we will report a grammar error in the checker. 7975 // struct Identifier logic is same to class Identifier 7976 const name = parseNameOfClassDeclarationOrExpression(); 7977 const typeParameters = parseTypeParameters(); 7978 if (some(modifiers, isExportModifier)) setAwaitContext(/*value*/ true); 7979 let heritageClauses = parseHeritageClauses(); 7980 const customComponent = sourceFileCompilerOptions.ets?.customComponent; 7981 if (!heritageClauses && customComponent) { 7982 heritageClauses = createVirtualHeritageClauses(customComponent); 7983 } 7984 let members; 7985 if (parseExpected(SyntaxKind.OpenBraceToken)) { 7986 // ClassTail[Yield,Await] : (Modified) See 14.5 7987 // ClassHeritage[?Yield,?Await]opt { ClassBody[?Yield,?Await]opt } 7988 members = parseStructMembers(pos); 7989 parseExpected(SyntaxKind.CloseBraceToken); 7990 } 7991 else { 7992 members = createMissingList<ClassElement>(); 7993 } 7994 setAwaitContext(savedAwaitContext); 7995 const node = factory.createStructDeclaration(combineDecoratorsAndModifiers(decorators, modifiers), name, typeParameters, heritageClauses, members); 7996 structStylesComponents.clear(); 7997 setStructContext(false); 7998 return withJSDoc(finishNode(node, pos), hasJSDoc); 7999 } 8000 8001 function createVirtualHeritageClauses(customComponent: string): NodeArray<HeritageClause> { 8002 const curPos = getNodePos(); 8003 const clause = factory.createHeritageClause( 8004 SyntaxKind.ExtendsKeyword, 8005 createNodeArray([finishNode(factory.createExpressionWithTypeArguments( 8006 finishNode(factory.createIdentifier(/*text*/ customComponent), curPos, /*end*/ undefined, /*virtual*/ true), 8007 /*typeArguments*/ undefined 8008 ), curPos)], curPos, /*end*/ undefined, /*hasTrailingComma*/ false) 8009 ); 8010 return createNodeArray([finishNode(clause, curPos, /*end*/ undefined, /*virtual*/ true)], curPos, /*end*/ undefined, /*hasTrailingComma*/ false); 8011 } 8012 8013 function parseNameOfClassDeclarationOrExpression(): Identifier | undefined { 8014 // implements is a future reserved word so 8015 // 'class implements' might mean either 8016 // - class expression with omitted name, 'implements' starts heritage clause 8017 // - class with name 'implements' 8018 // 'isImplementsClause' helps to disambiguate between these two cases 8019 return isBindingIdentifier() && !isImplementsClause() 8020 ? createIdentifier(isBindingIdentifier()) 8021 : undefined; 8022 } 8023 8024 function isImplementsClause() { 8025 return token() === SyntaxKind.ImplementsKeyword && lookAhead(nextTokenIsIdentifierOrKeyword); 8026 } 8027 8028 function parseHeritageClauses(): NodeArray<HeritageClause> | undefined { 8029 // ClassTail[Yield,Await] : (Modified) See 14.5 8030 // ClassHeritage[?Yield,?Await]opt { ClassBody[?Yield,?Await]opt } 8031 8032 if (isHeritageClause()) { 8033 return parseList(ParsingContext.HeritageClauses, parseHeritageClause); 8034 } 8035 8036 return undefined; 8037 } 8038 8039 function parseHeritageClause(): HeritageClause { 8040 const pos = getNodePos(); 8041 const tok = token(); 8042 Debug.assert(tok === SyntaxKind.ExtendsKeyword || tok === SyntaxKind.ImplementsKeyword); // isListElement() should ensure this. 8043 nextToken(); 8044 const types = parseDelimitedList(ParsingContext.HeritageClauseElement, parseExpressionWithTypeArguments); 8045 return finishNode(factory.createHeritageClause(tok, types), pos); 8046 } 8047 8048 function parseExpressionWithTypeArguments(): ExpressionWithTypeArguments { 8049 const pos = getNodePos(); 8050 const expression = parseLeftHandSideExpressionOrHigher(); 8051 if (expression.kind === SyntaxKind.ExpressionWithTypeArguments) { 8052 return expression as ExpressionWithTypeArguments; 8053 } 8054 const typeArguments = tryParseTypeArguments(); 8055 return finishNode(factory.createExpressionWithTypeArguments(expression, typeArguments), pos); 8056 } 8057 8058 function tryParseTypeArguments(): NodeArray<TypeNode> | undefined { 8059 return token() === SyntaxKind.LessThanToken ? 8060 parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken) : undefined; 8061 } 8062 8063 function isHeritageClause(): boolean { 8064 return token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword; 8065 } 8066 8067 function parseClassMembers(): NodeArray<ClassElement> { 8068 return parseList(ParsingContext.ClassMembers, parseClassElement); 8069 } 8070 8071 function parseStructMembers(pos: number): NodeArray<ClassElement> { 8072 const structMembers = parseList(ParsingContext.ClassMembers, parseClassElement); 8073 8074 const virtualStructMembers: ClassElement[] = []; 8075 // create constructor function argument object properties 8076 const virtualParameterProperties: TypeElement[] = []; 8077 structMembers.forEach(member => { 8078 virtualStructMembers.push(member); 8079 if (member.kind === SyntaxKind.PropertyDeclaration) { 8080 const property = <PropertyDeclaration>member; 8081 virtualParameterProperties.push( 8082 finishVirtualNode( 8083 factory.createPropertySignature(getModifiers(property), property.name, factory.createToken(SyntaxKind.QuestionToken), property.type) 8084 ) 8085 ); 8086 } 8087 }); 8088 const parameters: ParameterDeclaration[] = []; 8089 if (virtualParameterProperties.length) { 8090 const type = finishVirtualNode(factory.createTypeLiteralNode(createNodeArray(virtualParameterProperties, 0, 0))); 8091 parameters.push( 8092 finishVirtualNode( 8093 factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, 8094 finishVirtualNode(factory.createIdentifier("value")), factory.createToken(SyntaxKind.QuestionToken), type 8095 ) 8096 ) 8097 ); 8098 } 8099 // Add parameter ##storage?: LocalStorage to struct constructor. 8100 parameters.push( 8101 finishVirtualNode( 8102 factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, 8103 finishVirtualNode(factory.createIdentifier("##storage")), factory.createToken(SyntaxKind.QuestionToken), 8104 finishVirtualNode(factory.createTypeReferenceNode(finishVirtualNode(factory.createIdentifier("LocalStorage")))) 8105 ) 8106 ) 8107 ); 8108 const emptyBody = finishVirtualNode(factory.createBlock(createNodeArray([], 0, 0))); 8109 const virtualConstructor = factory.createConstructorDeclaration(/*modifier*/ undefined, createNodeArray(parameters, 0, 0), emptyBody); 8110 8111 virtualStructMembers.unshift(finishVirtualNode(virtualConstructor, pos, pos)); 8112 8113 return createNodeArray(virtualStructMembers, structMembers.pos); 8114 } 8115 8116 function finishVirtualNode<T extends Node>(node: T, start = 0, end = 0) { 8117 return finishNode(node, start, end, /*virtual*/ true); 8118 } 8119 8120 function parseInterfaceDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): InterfaceDeclaration { 8121 parseExpected(SyntaxKind.InterfaceKeyword); 8122 const name = parseIdentifier(); 8123 const typeParameters = parseTypeParameters(); 8124 const heritageClauses = parseHeritageClauses(); 8125 const members = parseObjectTypeMembers(); 8126 const node = factory.createInterfaceDeclaration(modifiers, name, typeParameters, heritageClauses, members); 8127 (node as Mutable<InterfaceDeclaration>).illegalDecorators = decorators; 8128 return withJSDoc(finishNode(node, pos), hasJSDoc); 8129 } 8130 8131 function parseTypeAliasDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): TypeAliasDeclaration { 8132 parseExpected(SyntaxKind.TypeKeyword); 8133 const name = parseIdentifier(); 8134 const typeParameters = parseTypeParameters(); 8135 parseExpected(SyntaxKind.EqualsToken); 8136 const type = token() === SyntaxKind.IntrinsicKeyword && tryParse(parseKeywordAndNoDot) || parseType(); 8137 parseSemicolon(); 8138 const node = factory.createTypeAliasDeclaration(modifiers, name, typeParameters, type); 8139 (node as Mutable<TypeAliasDeclaration>).illegalDecorators = decorators; 8140 return withJSDoc(finishNode(node, pos), hasJSDoc); 8141 } 8142 8143 // In an ambient declaration, the grammar only allows integer literals as initializers. 8144 // In a non-ambient declaration, the grammar allows uninitialized members only in a 8145 // ConstantEnumMemberSection, which starts at the beginning of an enum declaration 8146 // or any time an integer literal initializer is encountered. 8147 function parseEnumMember(): EnumMember { 8148 const pos = getNodePos(); 8149 const hasJSDoc = hasPrecedingJSDocComment(); 8150 const name = parsePropertyName(); 8151 const initializer = allowInAnd(parseInitializer); 8152 return withJSDoc(finishNode(factory.createEnumMember(name, initializer), pos), hasJSDoc); 8153 } 8154 8155 function parseEnumDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): EnumDeclaration { 8156 parseExpected(SyntaxKind.EnumKeyword); 8157 const name = parseIdentifier(); 8158 let members; 8159 if (parseExpected(SyntaxKind.OpenBraceToken)) { 8160 members = doOutsideOfYieldAndAwaitContext(() => parseDelimitedList(ParsingContext.EnumMembers, parseEnumMember)); 8161 parseExpected(SyntaxKind.CloseBraceToken); 8162 } 8163 else { 8164 members = createMissingList<EnumMember>(); 8165 } 8166 const node = factory.createEnumDeclaration(modifiers, name, members); 8167 (node as Mutable<EnumDeclaration>).illegalDecorators = decorators; 8168 return withJSDoc(finishNode(node, pos), hasJSDoc); 8169 } 8170 8171 function parseModuleBlock(): ModuleBlock { 8172 const pos = getNodePos(); 8173 let statements; 8174 if (parseExpected(SyntaxKind.OpenBraceToken)) { 8175 statements = parseList(ParsingContext.BlockStatements, parseStatement); 8176 parseExpected(SyntaxKind.CloseBraceToken); 8177 } 8178 else { 8179 statements = createMissingList<Statement>(); 8180 } 8181 return finishNode(factory.createModuleBlock(statements), pos); 8182 } 8183 8184 function parseModuleOrNamespaceDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined, flags: NodeFlags): ModuleDeclaration { 8185 // If we are parsing a dotted namespace name, we want to 8186 // propagate the 'Namespace' flag across the names if set. 8187 const namespaceFlag = flags & NodeFlags.Namespace; 8188 const name = parseIdentifier(); 8189 const body = parseOptional(SyntaxKind.DotToken) 8190 ? parseModuleOrNamespaceDeclaration(getNodePos(), /*hasJSDoc*/ false, /*decorators*/ undefined, /*modifiers*/ undefined, NodeFlags.NestedNamespace | namespaceFlag) as NamespaceDeclaration 8191 : parseModuleBlock(); 8192 const node = factory.createModuleDeclaration(modifiers, name, body, flags); 8193 (node as Mutable<ModuleDeclaration>).illegalDecorators = decorators; 8194 return withJSDoc(finishNode(node, pos), hasJSDoc); 8195 } 8196 8197 function parseAmbientExternalModuleDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ModuleDeclaration { 8198 let flags: NodeFlags = 0; 8199 let name; 8200 if (token() === SyntaxKind.GlobalKeyword) { 8201 // parse 'global' as name of global scope augmentation 8202 name = parseIdentifier(); 8203 flags |= NodeFlags.GlobalAugmentation; 8204 } 8205 else { 8206 name = parseLiteralNode() as StringLiteral; 8207 name.text = internIdentifier(name.text); 8208 } 8209 let body: ModuleBlock | undefined; 8210 if (token() === SyntaxKind.OpenBraceToken) { 8211 body = parseModuleBlock(); 8212 } 8213 else { 8214 parseSemicolon(); 8215 } 8216 const node = factory.createModuleDeclaration(modifiers, name, body, flags); 8217 (node as Mutable<ModuleDeclaration>).illegalDecorators = decorators; 8218 return withJSDoc(finishNode(node, pos), hasJSDoc); 8219 } 8220 8221 function parseModuleDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ModuleDeclaration { 8222 let flags: NodeFlags = 0; 8223 if (token() === SyntaxKind.GlobalKeyword) { 8224 // global augmentation 8225 return parseAmbientExternalModuleDeclaration(pos, hasJSDoc, decorators, modifiers); 8226 } 8227 else if (parseOptional(SyntaxKind.NamespaceKeyword)) { 8228 flags |= NodeFlags.Namespace; 8229 } 8230 else { 8231 parseExpected(SyntaxKind.ModuleKeyword); 8232 if (token() === SyntaxKind.StringLiteral) { 8233 return parseAmbientExternalModuleDeclaration(pos, hasJSDoc, decorators, modifiers); 8234 } 8235 } 8236 return parseModuleOrNamespaceDeclaration(pos, hasJSDoc, decorators, modifiers, flags); 8237 } 8238 8239 function isExternalModuleReference() { 8240 return token() === SyntaxKind.RequireKeyword && 8241 lookAhead(nextTokenIsOpenParen); 8242 } 8243 8244 function nextTokenIsOpenParen() { 8245 return nextToken() === SyntaxKind.OpenParenToken; 8246 } 8247 8248 function nextTokenIsOpenBrace() { 8249 return nextToken() === SyntaxKind.OpenBraceToken; 8250 } 8251 8252 function nextTokenIsSlash() { 8253 return nextToken() === SyntaxKind.SlashToken; 8254 } 8255 8256 function parseNamespaceExportDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): NamespaceExportDeclaration { 8257 parseExpected(SyntaxKind.AsKeyword); 8258 parseExpected(SyntaxKind.NamespaceKeyword); 8259 const name = parseIdentifier(); 8260 parseSemicolon(); 8261 const node = factory.createNamespaceExportDeclaration(name); 8262 // NamespaceExportDeclaration nodes cannot have decorators or modifiers, so we attach them here so we can report them in the grammar checker 8263 (node as Mutable<NamespaceExportDeclaration>).illegalDecorators = decorators; 8264 (node as Mutable<NamespaceExportDeclaration>).modifiers = modifiers; 8265 return withJSDoc(finishNode(node, pos), hasJSDoc); 8266 } 8267 8268 function parseImportDeclarationOrImportEqualsDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ImportEqualsDeclaration | ImportDeclaration { 8269 parseExpected(SyntaxKind.ImportKeyword); 8270 8271 const afterImportPos = scanner.getStartPos(); 8272 8273 // We don't parse the identifier here in await context, instead we will report a grammar error in the checker. 8274 let identifier: Identifier | undefined; 8275 if (isIdentifier()) { 8276 identifier = parseIdentifier(); 8277 } 8278 8279 let isTypeOnly = false; 8280 let isLazy = false; 8281 if (token() !== SyntaxKind.FromKeyword && 8282 identifier?.escapedText === "type" && 8283 (isIdentifier() || tokenAfterImportDefinitelyProducesImportDeclaration()) 8284 ) { 8285 isTypeOnly = true; 8286 identifier = isIdentifier() ? parseIdentifier() : undefined; 8287 } 8288 else if (identifier?.escapedText === 'lazy' && token() === SyntaxKind.OpenBraceToken) { 8289 isLazy = true; 8290 identifier = undefined; 8291 } 8292 8293 if (identifier && !tokenAfterImportedIdentifierDefinitelyProducesImportDeclaration()) { 8294 return parseImportEqualsDeclaration(pos, hasJSDoc, decorators, modifiers, identifier, isTypeOnly); 8295 } 8296 8297 // ImportDeclaration: 8298 // import ImportClause from ModuleSpecifier ; 8299 // import ModuleSpecifier; 8300 let importClause: ImportClause | undefined; 8301 if (identifier || // import id 8302 token() === SyntaxKind.AsteriskToken || // import * 8303 token() === SyntaxKind.OpenBraceToken // import { 8304 ) { 8305 importClause = parseImportClause(identifier, afterImportPos, isTypeOnly); 8306 (importClause as Mutable<ImportClause>).isLazy = isLazy; 8307 parseExpected(SyntaxKind.FromKeyword); 8308 } 8309 const moduleSpecifier = parseModuleSpecifier(); 8310 8311 let assertClause: AssertClause | undefined; 8312 if (token() === SyntaxKind.AssertKeyword && !scanner.hasPrecedingLineBreak()) { 8313 assertClause = parseAssertClause(); 8314 } 8315 8316 parseSemicolon(); 8317 const node = factory.createImportDeclaration(modifiers, importClause, moduleSpecifier, assertClause); 8318 (node as Mutable<ImportDeclaration>).illegalDecorators = decorators; 8319 return withJSDoc(finishNode(node, pos), hasJSDoc); 8320 } 8321 8322 function parseAssertEntry() { 8323 const pos = getNodePos(); 8324 const name = tokenIsIdentifierOrKeyword(token()) ? parseIdentifierName() : parseLiteralLikeNode(SyntaxKind.StringLiteral) as StringLiteral; 8325 parseExpected(SyntaxKind.ColonToken); 8326 const value = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true); 8327 return finishNode(factory.createAssertEntry(name, value), pos); 8328 } 8329 8330 function parseAssertClause(skipAssertKeyword?: true) { 8331 const pos = getNodePos(); 8332 if (!skipAssertKeyword) { 8333 parseExpected(SyntaxKind.AssertKeyword); 8334 } 8335 const openBracePosition = scanner.getTokenPos(); 8336 if (parseExpected(SyntaxKind.OpenBraceToken)) { 8337 const multiLine = scanner.hasPrecedingLineBreak(); 8338 const elements = parseDelimitedList(ParsingContext.AssertEntries, parseAssertEntry, /*considerSemicolonAsDelimiter*/ true); 8339 if (!parseExpected(SyntaxKind.CloseBraceToken)) { 8340 const lastError = lastOrUndefined(parseDiagnostics); 8341 if (lastError && lastError.code === Diagnostics._0_expected.code) { 8342 addRelatedInfo( 8343 lastError, 8344 createDetachedDiagnostic(fileName, openBracePosition, 1, Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, "{", "}") 8345 ); 8346 } 8347 } 8348 return finishNode(factory.createAssertClause(elements, multiLine), pos); 8349 } 8350 else { 8351 const elements = createNodeArray([], getNodePos(), /*end*/ undefined, /*hasTrailingComma*/ false); 8352 return finishNode(factory.createAssertClause(elements, /*multiLine*/ false), pos); 8353 } 8354 } 8355 8356 function tokenAfterImportDefinitelyProducesImportDeclaration() { 8357 return token() === SyntaxKind.AsteriskToken || token() === SyntaxKind.OpenBraceToken; 8358 } 8359 8360 function tokenAfterImportedIdentifierDefinitelyProducesImportDeclaration() { 8361 // In `import id ___`, the current token decides whether to produce 8362 // an ImportDeclaration or ImportEqualsDeclaration. 8363 return token() === SyntaxKind.CommaToken || token() === SyntaxKind.FromKeyword; 8364 } 8365 8366 function parseImportEqualsDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined, identifier: Identifier, isTypeOnly: boolean): ImportEqualsDeclaration { 8367 parseExpected(SyntaxKind.EqualsToken); 8368 const moduleReference = parseModuleReference(); 8369 parseSemicolon(); 8370 const node = factory.createImportEqualsDeclaration(modifiers, isTypeOnly, identifier, moduleReference); 8371 (node as Mutable<ImportEqualsDeclaration>).illegalDecorators = decorators; 8372 const finished = withJSDoc(finishNode(node, pos), hasJSDoc); 8373 return finished; 8374 } 8375 8376 function parseImportClause(identifier: Identifier | undefined, pos: number, isTypeOnly: boolean) { 8377 // ImportClause: 8378 // ImportedDefaultBinding 8379 // NameSpaceImport 8380 // NamedImports 8381 // ImportedDefaultBinding, NameSpaceImport 8382 // ImportedDefaultBinding, NamedImports 8383 8384 // If there was no default import or if there is comma token after default import 8385 // parse namespace or named imports 8386 let namedBindings: NamespaceImport | NamedImports | undefined; 8387 if (!identifier || 8388 parseOptional(SyntaxKind.CommaToken)) { 8389 namedBindings = token() === SyntaxKind.AsteriskToken ? parseNamespaceImport() : parseNamedImportsOrExports(SyntaxKind.NamedImports); 8390 } 8391 8392 return finishNode(factory.createImportClause(isTypeOnly, identifier, namedBindings), pos); 8393 } 8394 8395 function parseModuleReference() { 8396 return isExternalModuleReference() 8397 ? parseExternalModuleReference() 8398 : parseEntityName(/*allowReservedWords*/ false); 8399 } 8400 8401 function parseExternalModuleReference() { 8402 const pos = getNodePos(); 8403 parseExpected(SyntaxKind.RequireKeyword); 8404 parseExpected(SyntaxKind.OpenParenToken); 8405 const expression = parseModuleSpecifier(); 8406 parseExpected(SyntaxKind.CloseParenToken); 8407 return finishNode(factory.createExternalModuleReference(expression), pos); 8408 } 8409 8410 function parseModuleSpecifier(): Expression { 8411 if (token() === SyntaxKind.StringLiteral) { 8412 const result = parseLiteralNode(); 8413 result.text = internIdentifier(result.text); 8414 return result; 8415 } 8416 else { 8417 // We allow arbitrary expressions here, even though the grammar only allows string 8418 // literals. We check to ensure that it is only a string literal later in the grammar 8419 // check pass. 8420 return parseExpression(); 8421 } 8422 } 8423 8424 function parseNamespaceImport(): NamespaceImport { 8425 // NameSpaceImport: 8426 // * as ImportedBinding 8427 const pos = getNodePos(); 8428 parseExpected(SyntaxKind.AsteriskToken); 8429 parseExpected(SyntaxKind.AsKeyword); 8430 const name = parseIdentifier(); 8431 return finishNode(factory.createNamespaceImport(name), pos); 8432 } 8433 8434 function parseNamedImportsOrExports(kind: SyntaxKind.NamedImports): NamedImports; 8435 function parseNamedImportsOrExports(kind: SyntaxKind.NamedExports): NamedExports; 8436 function parseNamedImportsOrExports(kind: SyntaxKind): NamedImportsOrExports { 8437 const pos = getNodePos(); 8438 8439 // NamedImports: 8440 // { } 8441 // { ImportsList } 8442 // { ImportsList, } 8443 8444 // ImportsList: 8445 // ImportSpecifier 8446 // ImportsList, ImportSpecifier 8447 const node = kind === SyntaxKind.NamedImports 8448 ? factory.createNamedImports(parseBracketedList(ParsingContext.ImportOrExportSpecifiers, parseImportSpecifier, SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken)) 8449 : factory.createNamedExports(parseBracketedList(ParsingContext.ImportOrExportSpecifiers, parseExportSpecifier, SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken)); 8450 return finishNode(node, pos); 8451 } 8452 8453 function parseExportSpecifier() { 8454 const hasJSDoc = hasPrecedingJSDocComment(); 8455 return withJSDoc(parseImportOrExportSpecifier(SyntaxKind.ExportSpecifier) as ExportSpecifier, hasJSDoc); 8456 } 8457 8458 function parseImportSpecifier() { 8459 return parseImportOrExportSpecifier(SyntaxKind.ImportSpecifier) as ImportSpecifier; 8460 } 8461 8462 function parseImportOrExportSpecifier(kind: SyntaxKind): ImportOrExportSpecifier { 8463 const pos = getNodePos(); 8464 // ImportSpecifier: 8465 // BindingIdentifier 8466 // IdentifierName as BindingIdentifier 8467 // ExportSpecifier: 8468 // IdentifierName 8469 // IdentifierName as IdentifierName 8470 let checkIdentifierIsKeyword = isKeyword(token()) && !isIdentifier(); 8471 let checkIdentifierStart = scanner.getTokenPos(); 8472 let checkIdentifierEnd = scanner.getTextPos(); 8473 let isTypeOnly = false; 8474 let propertyName: Identifier | undefined; 8475 let canParseAsKeyword = true; 8476 let name = parseIdentifierName(); 8477 if (name.escapedText === "type") { 8478 // If the first token of an import specifier is 'type', there are a lot of possibilities, 8479 // especially if we see 'as' afterwards: 8480 // 8481 // import { type } from "mod"; - isTypeOnly: false, name: type 8482 // import { type as } from "mod"; - isTypeOnly: true, name: as 8483 // import { type as as } from "mod"; - isTypeOnly: false, name: as, propertyName: type 8484 // import { type as as as } from "mod"; - isTypeOnly: true, name: as, propertyName: as 8485 if (token() === SyntaxKind.AsKeyword) { 8486 // { type as ...? } 8487 const firstAs = parseIdentifierName(); 8488 if (token() === SyntaxKind.AsKeyword) { 8489 // { type as as ...? } 8490 const secondAs = parseIdentifierName(); 8491 if (tokenIsIdentifierOrKeyword(token())) { 8492 // { type as as something } 8493 isTypeOnly = true; 8494 propertyName = firstAs; 8495 name = parseNameWithKeywordCheck(); 8496 canParseAsKeyword = false; 8497 } 8498 else { 8499 // { type as as } 8500 propertyName = name; 8501 name = secondAs; 8502 canParseAsKeyword = false; 8503 } 8504 } 8505 else if (tokenIsIdentifierOrKeyword(token())) { 8506 // { type as something } 8507 propertyName = name; 8508 canParseAsKeyword = false; 8509 name = parseNameWithKeywordCheck(); 8510 } 8511 else { 8512 // { type as } 8513 isTypeOnly = true; 8514 name = firstAs; 8515 } 8516 } 8517 else if (tokenIsIdentifierOrKeyword(token())) { 8518 // { type something ...? } 8519 isTypeOnly = true; 8520 name = parseNameWithKeywordCheck(); 8521 } 8522 } 8523 8524 if (canParseAsKeyword && token() === SyntaxKind.AsKeyword) { 8525 propertyName = name; 8526 parseExpected(SyntaxKind.AsKeyword); 8527 name = parseNameWithKeywordCheck(); 8528 } 8529 if (kind === SyntaxKind.ImportSpecifier && checkIdentifierIsKeyword) { 8530 parseErrorAt(checkIdentifierStart, checkIdentifierEnd, Diagnostics.Identifier_expected); 8531 } 8532 const node = kind === SyntaxKind.ImportSpecifier 8533 ? factory.createImportSpecifier(isTypeOnly, propertyName, name) 8534 : factory.createExportSpecifier(isTypeOnly, propertyName, name); 8535 return finishNode(node, pos); 8536 8537 function parseNameWithKeywordCheck() { 8538 checkIdentifierIsKeyword = isKeyword(token()) && !isIdentifier(); 8539 checkIdentifierStart = scanner.getTokenPos(); 8540 checkIdentifierEnd = scanner.getTextPos(); 8541 return parseIdentifierName(); 8542 } 8543 } 8544 8545 function parseNamespaceExport(pos: number): NamespaceExport { 8546 return finishNode(factory.createNamespaceExport(parseIdentifierName()), pos); 8547 } 8548 8549 function parseExportDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ExportDeclaration { 8550 const savedAwaitContext = inAwaitContext(); 8551 setAwaitContext(/*value*/ true); 8552 let exportClause: NamedExportBindings | undefined; 8553 let moduleSpecifier: Expression | undefined; 8554 let assertClause: AssertClause | undefined; 8555 const isTypeOnly = parseOptional(SyntaxKind.TypeKeyword); 8556 const namespaceExportPos = getNodePos(); 8557 if (parseOptional(SyntaxKind.AsteriskToken)) { 8558 if (parseOptional(SyntaxKind.AsKeyword)) { 8559 exportClause = parseNamespaceExport(namespaceExportPos); 8560 } 8561 parseExpected(SyntaxKind.FromKeyword); 8562 moduleSpecifier = parseModuleSpecifier(); 8563 } 8564 else { 8565 exportClause = parseNamedImportsOrExports(SyntaxKind.NamedExports); 8566 // It is not uncommon to accidentally omit the 'from' keyword. Additionally, in editing scenarios, 8567 // the 'from' keyword can be parsed as a named export when the export clause is unterminated (i.e. `export { from "moduleName";`) 8568 // If we don't have a 'from' keyword, see if we have a string literal such that ASI won't take effect. 8569 if (token() === SyntaxKind.FromKeyword || (token() === SyntaxKind.StringLiteral && !scanner.hasPrecedingLineBreak())) { 8570 parseExpected(SyntaxKind.FromKeyword); 8571 moduleSpecifier = parseModuleSpecifier(); 8572 } 8573 } 8574 if (moduleSpecifier && token() === SyntaxKind.AssertKeyword && !scanner.hasPrecedingLineBreak()) { 8575 assertClause = parseAssertClause(); 8576 } 8577 parseSemicolon(); 8578 setAwaitContext(savedAwaitContext); 8579 const node = factory.createExportDeclaration(modifiers, isTypeOnly, exportClause, moduleSpecifier, assertClause); 8580 (node as Mutable<ExportDeclaration>).illegalDecorators = decorators; 8581 return withJSDoc(finishNode(node, pos), hasJSDoc); 8582 } 8583 8584 function parseExportAssignment(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ExportAssignment { 8585 const savedAwaitContext = inAwaitContext(); 8586 setAwaitContext(/*value*/ true); 8587 let isExportEquals: boolean | undefined; 8588 if (parseOptional(SyntaxKind.EqualsToken)) { 8589 isExportEquals = true; 8590 } 8591 else { 8592 parseExpected(SyntaxKind.DefaultKeyword); 8593 } 8594 const expression = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true); 8595 parseSemicolon(); 8596 setAwaitContext(savedAwaitContext); 8597 const node = factory.createExportAssignment(modifiers, isExportEquals, expression); 8598 (node as Mutable<ExportAssignment>).illegalDecorators = decorators; 8599 return withJSDoc(finishNode(node, pos), hasJSDoc); 8600 } 8601 8602 const enum ParsingContext { 8603 SourceElements, // Elements in source file 8604 BlockStatements, // Statements in block 8605 SwitchClauses, // Clauses in switch statement 8606 SwitchClauseStatements, // Statements in switch clause 8607 TypeMembers, // Members in interface or type literal 8608 ClassMembers, // Members in class declaration 8609 EnumMembers, // Members in enum declaration 8610 HeritageClauseElement, // Elements in a heritage clause 8611 VariableDeclarations, // Variable declarations in variable statement 8612 ObjectBindingElements, // Binding elements in object binding list 8613 ArrayBindingElements, // Binding elements in array binding list 8614 ArgumentExpressions, // Expressions in argument list 8615 ObjectLiteralMembers, // Members in object literal 8616 JsxAttributes, // Attributes in jsx element 8617 JsxChildren, // Things between opening and closing JSX tags 8618 ArrayLiteralMembers, // Members in array literal 8619 Parameters, // Parameters in parameter list 8620 JSDocParameters, // JSDoc parameters in parameter list of JSDoc function type 8621 RestProperties, // Property names in a rest type list 8622 TypeParameters, // Type parameters in type parameter list 8623 TypeArguments, // Type arguments in type argument list 8624 TupleElementTypes, // Element types in tuple element type list 8625 HeritageClauses, // Heritage clauses for a class or interface declaration. 8626 ImportOrExportSpecifiers, // Named import clause's import specifier list, 8627 AssertEntries, // Import entries list. 8628 Count // Number of parsing contexts 8629 } 8630 8631 const enum Tristate { 8632 False, 8633 True, 8634 Unknown 8635 } 8636 8637 export namespace JSDocParser { 8638 export function parseJSDocTypeExpressionForTests(content: string, start: number | undefined, length: number | undefined): { jsDocTypeExpression: JSDocTypeExpression, diagnostics: Diagnostic[] } | undefined { 8639 initializeState("file.js", content, ScriptTarget.Latest, /*_syntaxCursor:*/ undefined, ScriptKind.JS); 8640 scanner.setText(content, start, length); 8641 currentToken = scanner.scan(); 8642 const jsDocTypeExpression = parseJSDocTypeExpression(); 8643 8644 const sourceFile = createSourceFile("file.js", ScriptTarget.Latest, ScriptKind.JS, /*isDeclarationFile*/ false, [], factory.createToken(SyntaxKind.EndOfFileToken), NodeFlags.None, noop); 8645 const diagnostics = attachFileToDiagnostics(parseDiagnostics, sourceFile); 8646 if (jsDocDiagnostics) { 8647 sourceFile.jsDocDiagnostics = attachFileToDiagnostics(jsDocDiagnostics, sourceFile); 8648 } 8649 8650 clearState(); 8651 8652 return jsDocTypeExpression ? { jsDocTypeExpression, diagnostics } : undefined; 8653 } 8654 8655 // Parses out a JSDoc type expression. 8656 export function parseJSDocTypeExpression(mayOmitBraces?: boolean): JSDocTypeExpression { 8657 const pos = getNodePos(); 8658 const hasBrace = (mayOmitBraces ? parseOptional : parseExpected)(SyntaxKind.OpenBraceToken); 8659 const type = doInsideOfContext(NodeFlags.JSDoc, parseJSDocType); 8660 if (!mayOmitBraces || hasBrace) { 8661 parseExpectedJSDoc(SyntaxKind.CloseBraceToken); 8662 } 8663 8664 const result = factory.createJSDocTypeExpression(type); 8665 fixupParentReferences(result); 8666 return finishNode(result, pos); 8667 } 8668 8669 export function parseJSDocNameReference(): JSDocNameReference { 8670 const pos = getNodePos(); 8671 const hasBrace = parseOptional(SyntaxKind.OpenBraceToken); 8672 const p2 = getNodePos(); 8673 let entityName: EntityName | JSDocMemberName = parseEntityName(/* allowReservedWords*/ false); 8674 while (token() === SyntaxKind.PrivateIdentifier) { 8675 reScanHashToken(); // rescan #id as # id 8676 nextTokenJSDoc(); // then skip the # 8677 entityName = finishNode(factory.createJSDocMemberName(entityName, parseIdentifier()), p2); 8678 } 8679 if (hasBrace) { 8680 parseExpectedJSDoc(SyntaxKind.CloseBraceToken); 8681 } 8682 8683 const result = factory.createJSDocNameReference(entityName); 8684 fixupParentReferences(result); 8685 return finishNode(result, pos); 8686 } 8687 8688 export function parseIsolatedJSDocComment(content: string, start: number | undefined, length: number | undefined): { jsDoc: JSDoc, diagnostics: Diagnostic[] } | undefined { 8689 initializeState("", content, ScriptTarget.Latest, /*_syntaxCursor:*/ undefined, ScriptKind.JS); 8690 const jsDoc = doInsideOfContext(NodeFlags.JSDoc, () => parseJSDocCommentWorker(start, length)); 8691 8692 const sourceFile = { languageVariant: LanguageVariant.Standard, text: content } as SourceFile; 8693 const diagnostics = attachFileToDiagnostics(parseDiagnostics, sourceFile); 8694 clearState(); 8695 8696 return jsDoc ? { jsDoc, diagnostics } : undefined; 8697 } 8698 8699 export function parseJSDocComment(parent: HasJSDoc, start: number, length: number): JSDoc | undefined { 8700 const saveToken = currentToken; 8701 const saveParseDiagnosticsLength = parseDiagnostics.length; 8702 const saveParseErrorBeforeNextFinishedNode = parseErrorBeforeNextFinishedNode; 8703 8704 const comment = doInsideOfContext(NodeFlags.JSDoc, () => parseJSDocCommentWorker(start, length)); 8705 setParent(comment, parent); 8706 8707 if (contextFlags & NodeFlags.JavaScriptFile) { 8708 if (!jsDocDiagnostics) { 8709 jsDocDiagnostics = []; 8710 } 8711 jsDocDiagnostics.push(...parseDiagnostics); 8712 } 8713 currentToken = saveToken; 8714 parseDiagnostics.length = saveParseDiagnosticsLength; 8715 parseErrorBeforeNextFinishedNode = saveParseErrorBeforeNextFinishedNode; 8716 return comment; 8717 } 8718 8719 const enum JSDocState { 8720 BeginningOfLine, 8721 SawAsterisk, 8722 SavingComments, 8723 SavingBackticks, // NOTE: Only used when parsing tag comments 8724 } 8725 8726 const enum PropertyLikeParse { 8727 Property = 1 << 0, 8728 Parameter = 1 << 1, 8729 CallbackParameter = 1 << 2, 8730 } 8731 8732 function parseJSDocCommentWorker(start = 0, length: number | undefined): JSDoc | undefined { 8733 const content = sourceText; 8734 const end = length === undefined ? content.length : start + length; 8735 length = end - start; 8736 8737 Debug.assert(start >= 0); 8738 Debug.assert(start <= end); 8739 Debug.assert(end <= content.length); 8740 8741 // Check for /** (JSDoc opening part) 8742 if (!isJSDocLikeText(content, start)) { 8743 return undefined; 8744 } 8745 8746 let tags: JSDocTag[]; 8747 let tagsPos: number; 8748 let tagsEnd: number; 8749 let linkEnd: number; 8750 let commentsPos: number | undefined; 8751 let comments: string[] = []; 8752 const parts: JSDocComment[] = []; 8753 8754 // + 3 for leading /**, - 5 in total for /** */ 8755 return scanner.scanRange(start + 3, length - 5, () => { 8756 // Initially we can parse out a tag. We also have seen a starting asterisk. 8757 // This is so that /** * @type */ doesn't parse. 8758 let state = JSDocState.SawAsterisk; 8759 let margin: number | undefined; 8760 // + 4 for leading '/** ' 8761 // + 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 8762 let indent = start - (content.lastIndexOf("\n", start) + 1) + 4; 8763 function pushComment(text: string) { 8764 if (!margin) { 8765 margin = indent; 8766 } 8767 comments.push(text); 8768 indent += text.length; 8769 } 8770 8771 nextTokenJSDoc(); 8772 while (parseOptionalJsdoc(SyntaxKind.WhitespaceTrivia)); 8773 if (parseOptionalJsdoc(SyntaxKind.NewLineTrivia)) { 8774 state = JSDocState.BeginningOfLine; 8775 indent = 0; 8776 } 8777 loop: while (true) { 8778 switch (token()) { 8779 case SyntaxKind.AtToken: 8780 if (state === JSDocState.BeginningOfLine || state === JSDocState.SawAsterisk) { 8781 removeTrailingWhitespace(comments); 8782 if (!commentsPos) commentsPos = getNodePos(); 8783 addTag(parseTag(indent)); 8784 // NOTE: According to usejsdoc.org, a tag goes to end of line, except the last tag. 8785 // Real-world comments may break this rule, so "BeginningOfLine" will not be a real line beginning 8786 // for malformed examples like `/** @param {string} x @returns {number} the length */` 8787 state = JSDocState.BeginningOfLine; 8788 margin = undefined; 8789 } 8790 else { 8791 pushComment(scanner.getTokenText()); 8792 } 8793 break; 8794 case SyntaxKind.NewLineTrivia: 8795 comments.push(scanner.getTokenText()); 8796 state = JSDocState.BeginningOfLine; 8797 indent = 0; 8798 break; 8799 case SyntaxKind.AsteriskToken: 8800 const asterisk = scanner.getTokenText(); 8801 if (state === JSDocState.SawAsterisk || state === JSDocState.SavingComments) { 8802 // If we've already seen an asterisk, then we can no longer parse a tag on this line 8803 state = JSDocState.SavingComments; 8804 pushComment(asterisk); 8805 } 8806 else { 8807 // Ignore the first asterisk on a line 8808 state = JSDocState.SawAsterisk; 8809 indent += asterisk.length; 8810 } 8811 break; 8812 case SyntaxKind.WhitespaceTrivia: 8813 // only collect whitespace if we're already saving comments or have just crossed the comment indent margin 8814 const whitespace = scanner.getTokenText(); 8815 if (state === JSDocState.SavingComments) { 8816 comments.push(whitespace); 8817 } 8818 else if (margin !== undefined && indent + whitespace.length > margin) { 8819 comments.push(whitespace.slice(margin - indent)); 8820 } 8821 indent += whitespace.length; 8822 break; 8823 case SyntaxKind.EndOfFileToken: 8824 break loop; 8825 case SyntaxKind.OpenBraceToken: 8826 state = JSDocState.SavingComments; 8827 const commentEnd = scanner.getStartPos(); 8828 const linkStart = scanner.getTextPos() - 1; 8829 const link = parseJSDocLink(linkStart); 8830 if (link) { 8831 if (!linkEnd) { 8832 removeLeadingNewlines(comments); 8833 } 8834 parts.push(finishNode(factory.createJSDocText(comments.join("")), linkEnd ?? start, commentEnd)); 8835 parts.push(link); 8836 comments = []; 8837 linkEnd = scanner.getTextPos(); 8838 break; 8839 } 8840 // fallthrough if it's not a {@link sequence 8841 default: 8842 // Anything else is doc comment text. We just save it. Because it 8843 // wasn't a tag, we can no longer parse a tag on this line until we hit the next 8844 // line break. 8845 state = JSDocState.SavingComments; 8846 pushComment(scanner.getTokenText()); 8847 break; 8848 } 8849 nextTokenJSDoc(); 8850 } 8851 removeTrailingWhitespace(comments); 8852 if (parts.length && comments.length) { 8853 parts.push(finishNode(factory.createJSDocText(comments.join("")), linkEnd ?? start, commentsPos)); 8854 } 8855 if (parts.length && tags) Debug.assertIsDefined(commentsPos, "having parsed tags implies that the end of the comment span should be set"); 8856 const tagsArray = tags && createNodeArray(tags, tagsPos, tagsEnd); 8857 return finishNode(factory.createJSDocComment(parts.length ? createNodeArray(parts, start, commentsPos) : comments.length ? comments.join("") : undefined, tagsArray), start, end); 8858 }); 8859 8860 function removeLeadingNewlines(comments: string[]) { 8861 while (comments.length && (comments[0] === "\n" || comments[0] === "\r")) { 8862 comments.shift(); 8863 } 8864 } 8865 8866 function removeTrailingWhitespace(comments: string[]) { 8867 while (comments.length && comments[comments.length - 1].trim() === "") { 8868 comments.pop(); 8869 } 8870 } 8871 8872 function isNextNonwhitespaceTokenEndOfFile(): boolean { 8873 // We must use infinite lookahead, as there could be any number of newlines :( 8874 while (true) { 8875 nextTokenJSDoc(); 8876 if (token() === SyntaxKind.EndOfFileToken) { 8877 return true; 8878 } 8879 if (!(token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia)) { 8880 return false; 8881 } 8882 } 8883 } 8884 8885 function skipWhitespace(): void { 8886 if (token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) { 8887 if (lookAhead(isNextNonwhitespaceTokenEndOfFile)) { 8888 return; // Don't skip whitespace prior to EoF (or end of comment) - that shouldn't be included in any node's range 8889 } 8890 } 8891 while (token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) { 8892 nextTokenJSDoc(); 8893 } 8894 } 8895 8896 function skipWhitespaceOrAsterisk(): string { 8897 if (token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) { 8898 if (lookAhead(isNextNonwhitespaceTokenEndOfFile)) { 8899 return ""; // Don't skip whitespace prior to EoF (or end of comment) - that shouldn't be included in any node's range 8900 } 8901 } 8902 8903 let precedingLineBreak = scanner.hasPrecedingLineBreak(); 8904 let seenLineBreak = false; 8905 let indentText = ""; 8906 while ((precedingLineBreak && token() === SyntaxKind.AsteriskToken) || token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) { 8907 indentText += scanner.getTokenText(); 8908 if (token() === SyntaxKind.NewLineTrivia) { 8909 precedingLineBreak = true; 8910 seenLineBreak = true; 8911 indentText = ""; 8912 } 8913 else if (token() === SyntaxKind.AsteriskToken) { 8914 precedingLineBreak = false; 8915 } 8916 nextTokenJSDoc(); 8917 } 8918 return seenLineBreak ? indentText : ""; 8919 } 8920 8921 function parseTag(margin: number) { 8922 Debug.assert(token() === SyntaxKind.AtToken); 8923 const start = scanner.getTokenPos(); 8924 nextTokenJSDoc(); 8925 8926 const tagName = parseJSDocIdentifierName(/*message*/ undefined); 8927 const indentText = skipWhitespaceOrAsterisk(); 8928 8929 let tag: JSDocTag | undefined; 8930 switch (tagName.escapedText) { 8931 case "author": 8932 tag = parseAuthorTag(start, tagName, margin, indentText); 8933 break; 8934 case "implements": 8935 tag = parseImplementsTag(start, tagName, margin, indentText); 8936 break; 8937 case "augments": 8938 case "extends": 8939 tag = parseAugmentsTag(start, tagName, margin, indentText); 8940 break; 8941 case "class": 8942 case "constructor": 8943 tag = parseSimpleTag(start, factory.createJSDocClassTag, tagName, margin, indentText); 8944 break; 8945 case "public": 8946 tag = parseSimpleTag(start, factory.createJSDocPublicTag, tagName, margin, indentText); 8947 break; 8948 case "private": 8949 tag = parseSimpleTag(start, factory.createJSDocPrivateTag, tagName, margin, indentText); 8950 break; 8951 case "protected": 8952 tag = parseSimpleTag(start, factory.createJSDocProtectedTag, tagName, margin, indentText); 8953 break; 8954 case "readonly": 8955 tag = parseSimpleTag(start, factory.createJSDocReadonlyTag, tagName, margin, indentText); 8956 break; 8957 case "override": 8958 tag = parseSimpleTag(start, factory.createJSDocOverrideTag, tagName, margin, indentText); 8959 break; 8960 case "deprecated": 8961 hasDeprecatedTag = true; 8962 tag = parseSimpleTag(start, factory.createJSDocDeprecatedTag, tagName, margin, indentText); 8963 break; 8964 case "this": 8965 tag = parseThisTag(start, tagName, margin, indentText); 8966 break; 8967 case "enum": 8968 tag = parseEnumTag(start, tagName, margin, indentText); 8969 break; 8970 case "arg": 8971 case "argument": 8972 case "param": 8973 return parseParameterOrPropertyTag(start, tagName, PropertyLikeParse.Parameter, margin); 8974 case "return": 8975 case "returns": 8976 tag = parseReturnTag(start, tagName, margin, indentText); 8977 break; 8978 case "template": 8979 tag = parseTemplateTag(start, tagName, margin, indentText); 8980 break; 8981 case "type": 8982 tag = parseTypeTag(start, tagName, margin, indentText); 8983 break; 8984 case "typedef": 8985 tag = parseTypedefTag(start, tagName, margin, indentText); 8986 break; 8987 case "callback": 8988 tag = parseCallbackTag(start, tagName, margin, indentText); 8989 break; 8990 case "see": 8991 tag = parseSeeTag(start, tagName, margin, indentText); 8992 break; 8993 default: 8994 tag = parseUnknownTag(start, tagName, margin, indentText); 8995 break; 8996 } 8997 return tag; 8998 } 8999 9000 function parseTrailingTagComments(pos: number, end: number, margin: number, indentText: string) { 9001 // some tags, like typedef and callback, have already parsed their comments earlier 9002 if (!indentText) { 9003 margin += end - pos; 9004 } 9005 return parseTagComments(margin, indentText.slice(margin)); 9006 } 9007 9008 function parseTagComments(indent: number, initialMargin?: string): string | NodeArray<JSDocComment> | undefined { 9009 const commentsPos = getNodePos(); 9010 let comments: string[] = []; 9011 const parts: JSDocComment[] = []; 9012 let linkEnd; 9013 let state = JSDocState.BeginningOfLine; 9014 let previousWhitespace = true; 9015 let margin: number | undefined; 9016 function pushComment(text: string) { 9017 if (!margin) { 9018 margin = indent; 9019 } 9020 comments.push(text); 9021 indent += text.length; 9022 } 9023 if (initialMargin !== undefined) { 9024 // jump straight to saving comments if there is some initial indentation 9025 if (initialMargin !== "") { 9026 pushComment(initialMargin); 9027 } 9028 state = JSDocState.SawAsterisk; 9029 } 9030 let tok = token() as JSDocSyntaxKind; 9031 loop: while (true) { 9032 switch (tok) { 9033 case SyntaxKind.NewLineTrivia: 9034 state = JSDocState.BeginningOfLine; 9035 // don't use pushComment here because we want to keep the margin unchanged 9036 comments.push(scanner.getTokenText()); 9037 indent = 0; 9038 break; 9039 case SyntaxKind.AtToken: 9040 if (state === JSDocState.SavingBackticks 9041 || state === JSDocState.SavingComments && (!previousWhitespace || lookAhead(isNextJSDocTokenWhitespace))) { 9042 // @ doesn't start a new tag inside ``, and inside a comment, only after whitespace or not before whitespace 9043 comments.push(scanner.getTokenText()); 9044 break; 9045 } 9046 scanner.setTextPos(scanner.getTextPos() - 1); 9047 // falls through 9048 case SyntaxKind.EndOfFileToken: 9049 // Done 9050 break loop; 9051 case SyntaxKind.WhitespaceTrivia: 9052 if (state === JSDocState.SavingComments || state === JSDocState.SavingBackticks) { 9053 pushComment(scanner.getTokenText()); 9054 } 9055 else { 9056 const whitespace = scanner.getTokenText(); 9057 // if the whitespace crosses the margin, take only the whitespace that passes the margin 9058 if (margin !== undefined && indent + whitespace.length > margin) { 9059 comments.push(whitespace.slice(margin - indent)); 9060 } 9061 indent += whitespace.length; 9062 } 9063 break; 9064 case SyntaxKind.OpenBraceToken: 9065 state = JSDocState.SavingComments; 9066 const commentEnd = scanner.getStartPos(); 9067 const linkStart = scanner.getTextPos() - 1; 9068 const link = parseJSDocLink(linkStart); 9069 if (link) { 9070 parts.push(finishNode(factory.createJSDocText(comments.join("")), linkEnd ?? commentsPos, commentEnd)); 9071 parts.push(link); 9072 comments = []; 9073 linkEnd = scanner.getTextPos(); 9074 } 9075 else { 9076 pushComment(scanner.getTokenText()); 9077 } 9078 break; 9079 case SyntaxKind.BacktickToken: 9080 if (state === JSDocState.SavingBackticks) { 9081 state = JSDocState.SavingComments; 9082 } 9083 else { 9084 state = JSDocState.SavingBackticks; 9085 } 9086 pushComment(scanner.getTokenText()); 9087 break; 9088 case SyntaxKind.AsteriskToken: 9089 if (state === JSDocState.BeginningOfLine) { 9090 // leading asterisks start recording on the *next* (non-whitespace) token 9091 state = JSDocState.SawAsterisk; 9092 indent += 1; 9093 break; 9094 } 9095 // record the * as a comment 9096 // falls through 9097 default: 9098 if (state !== JSDocState.SavingBackticks) { 9099 state = JSDocState.SavingComments; // leading identifiers start recording as well 9100 } 9101 pushComment(scanner.getTokenText()); 9102 break; 9103 } 9104 previousWhitespace = token() === SyntaxKind.WhitespaceTrivia; 9105 tok = nextTokenJSDoc(); 9106 } 9107 9108 removeLeadingNewlines(comments); 9109 removeTrailingWhitespace(comments); 9110 if (parts.length) { 9111 if (comments.length) { 9112 parts.push(finishNode(factory.createJSDocText(comments.join("")), linkEnd ?? commentsPos)); 9113 } 9114 return createNodeArray(parts, commentsPos, scanner.getTextPos()); 9115 } 9116 else if (comments.length) { 9117 return comments.join(""); 9118 } 9119 } 9120 9121 function isNextJSDocTokenWhitespace() { 9122 const next = nextTokenJSDoc(); 9123 return next === SyntaxKind.WhitespaceTrivia || next === SyntaxKind.NewLineTrivia; 9124 } 9125 9126 function parseJSDocLink(start: number) { 9127 const linkType = tryParse(parseJSDocLinkPrefix); 9128 if (!linkType) { 9129 return undefined; 9130 } 9131 nextTokenJSDoc(); // start at token after link, then skip any whitespace 9132 skipWhitespace(); 9133 // parseEntityName logs an error for non-identifier, so create a MissingNode ourselves to avoid the error 9134 const p2 = getNodePos(); 9135 let name: EntityName | JSDocMemberName | undefined = tokenIsIdentifierOrKeyword(token()) 9136 ? parseEntityName(/*allowReservedWords*/ true) 9137 : undefined; 9138 if (name) { 9139 while (token() === SyntaxKind.PrivateIdentifier) { 9140 reScanHashToken(); // rescan #id as # id 9141 nextTokenJSDoc(); // then skip the # 9142 name = finishNode(factory.createJSDocMemberName(name, parseIdentifier()), p2); 9143 } 9144 } 9145 const text = []; 9146 while (token() !== SyntaxKind.CloseBraceToken && token() !== SyntaxKind.NewLineTrivia && token() !== SyntaxKind.EndOfFileToken) { 9147 text.push(scanner.getTokenText()); 9148 nextTokenJSDoc(); 9149 } 9150 const create = linkType === "link" ? factory.createJSDocLink 9151 : linkType === "linkcode" ? factory.createJSDocLinkCode 9152 : factory.createJSDocLinkPlain; 9153 return finishNode(create(name, text.join("")), start, scanner.getTextPos()); 9154 } 9155 9156 function parseJSDocLinkPrefix() { 9157 skipWhitespaceOrAsterisk(); 9158 if (token() === SyntaxKind.OpenBraceToken 9159 && nextTokenJSDoc() === SyntaxKind.AtToken 9160 && tokenIsIdentifierOrKeyword(nextTokenJSDoc())) { 9161 const kind = scanner.getTokenValue(); 9162 if (isJSDocLinkTag(kind)) return kind; 9163 } 9164 } 9165 9166 function isJSDocLinkTag(kind: string) { 9167 return kind === "link" || kind === "linkcode" || kind === "linkplain"; 9168 } 9169 9170 function parseUnknownTag(start: number, tagName: Identifier, indent: number, indentText: string) { 9171 return finishNode(factory.createJSDocUnknownTag(tagName, parseTrailingTagComments(start, getNodePos(), indent, indentText)), start); 9172 } 9173 9174 function addTag(tag: JSDocTag | undefined): void { 9175 if (!tag) { 9176 return; 9177 } 9178 if (!tags) { 9179 tags = [tag]; 9180 tagsPos = tag.pos; 9181 } 9182 else { 9183 tags.push(tag); 9184 } 9185 tagsEnd = tag.end; 9186 } 9187 9188 function tryParseTypeExpression(): JSDocTypeExpression | undefined { 9189 skipWhitespaceOrAsterisk(); 9190 return token() === SyntaxKind.OpenBraceToken ? parseJSDocTypeExpression() : undefined; 9191 } 9192 9193 function parseBracketNameInPropertyAndParamTag(): { name: EntityName, isBracketed: boolean } { 9194 // Looking for something like '[foo]', 'foo', '[foo.bar]' or 'foo.bar' 9195 const isBracketed = parseOptionalJsdoc(SyntaxKind.OpenBracketToken); 9196 if (isBracketed) { 9197 skipWhitespace(); 9198 } 9199 // a markdown-quoted name: `arg` is not legal jsdoc, but occurs in the wild 9200 const isBackquoted = parseOptionalJsdoc(SyntaxKind.BacktickToken); 9201 const name = parseJSDocEntityName(); 9202 if (isBackquoted) { 9203 parseExpectedTokenJSDoc(SyntaxKind.BacktickToken); 9204 } 9205 if (isBracketed) { 9206 skipWhitespace(); 9207 // May have an optional default, e.g. '[foo = 42]' 9208 if (parseOptionalToken(SyntaxKind.EqualsToken)) { 9209 parseExpression(); 9210 } 9211 9212 parseExpected(SyntaxKind.CloseBracketToken); 9213 } 9214 9215 return { name, isBracketed }; 9216 } 9217 9218 function isObjectOrObjectArrayTypeReference(node: TypeNode): boolean { 9219 switch (node.kind) { 9220 case SyntaxKind.ObjectKeyword: 9221 return true; 9222 case SyntaxKind.ArrayType: 9223 return isObjectOrObjectArrayTypeReference((node as ArrayTypeNode).elementType); 9224 default: 9225 return isTypeReferenceNode(node) && ts.isIdentifier(node.typeName) && node.typeName.escapedText === "Object" && !node.typeArguments; 9226 } 9227 } 9228 9229 function parseParameterOrPropertyTag(start: number, tagName: Identifier, target: PropertyLikeParse, indent: number): JSDocParameterTag | JSDocPropertyTag { 9230 let typeExpression = tryParseTypeExpression(); 9231 let isNameFirst = !typeExpression; 9232 skipWhitespaceOrAsterisk(); 9233 9234 const { name, isBracketed } = parseBracketNameInPropertyAndParamTag(); 9235 const indentText = skipWhitespaceOrAsterisk(); 9236 9237 if (isNameFirst && !lookAhead(parseJSDocLinkPrefix)) { 9238 typeExpression = tryParseTypeExpression(); 9239 } 9240 9241 const comment = parseTrailingTagComments(start, getNodePos(), indent, indentText); 9242 9243 const nestedTypeLiteral = target !== PropertyLikeParse.CallbackParameter && parseNestedTypeLiteral(typeExpression, name, target, indent); 9244 if (nestedTypeLiteral) { 9245 typeExpression = nestedTypeLiteral; 9246 isNameFirst = true; 9247 } 9248 const result = target === PropertyLikeParse.Property 9249 ? factory.createJSDocPropertyTag(tagName, name, isBracketed, typeExpression, isNameFirst, comment) 9250 : factory.createJSDocParameterTag(tagName, name, isBracketed, typeExpression, isNameFirst, comment); 9251 return finishNode(result, start); 9252 } 9253 9254 function parseNestedTypeLiteral(typeExpression: JSDocTypeExpression | undefined, name: EntityName, target: PropertyLikeParse, indent: number) { 9255 if (typeExpression && isObjectOrObjectArrayTypeReference(typeExpression.type)) { 9256 const pos = getNodePos(); 9257 let child: JSDocPropertyLikeTag | JSDocTypeTag | false; 9258 let children: JSDocPropertyLikeTag[] | undefined; 9259 while (child = tryParse(() => parseChildParameterOrPropertyTag(target, indent, name))) { 9260 if (child.kind === SyntaxKind.JSDocParameterTag || child.kind === SyntaxKind.JSDocPropertyTag) { 9261 children = append(children, child); 9262 } 9263 } 9264 if (children) { 9265 const literal = finishNode(factory.createJSDocTypeLiteral(children, typeExpression.type.kind === SyntaxKind.ArrayType), pos); 9266 return finishNode(factory.createJSDocTypeExpression(literal), pos); 9267 } 9268 } 9269 } 9270 9271 function parseReturnTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocReturnTag { 9272 if (some(tags, isJSDocReturnTag)) { 9273 parseErrorAt(tagName.pos, scanner.getTokenPos(), Diagnostics._0_tag_already_specified, tagName.escapedText); 9274 } 9275 9276 const typeExpression = tryParseTypeExpression(); 9277 return finishNode(factory.createJSDocReturnTag(tagName, typeExpression, parseTrailingTagComments(start, getNodePos(), indent, indentText)), start); 9278 } 9279 9280 function parseTypeTag(start: number, tagName: Identifier, indent?: number, indentText?: string): JSDocTypeTag { 9281 if (some(tags, isJSDocTypeTag)) { 9282 parseErrorAt(tagName.pos, scanner.getTokenPos(), Diagnostics._0_tag_already_specified, tagName.escapedText); 9283 } 9284 9285 const typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true); 9286 const comments = indent !== undefined && indentText !== undefined ? parseTrailingTagComments(start, getNodePos(), indent, indentText) : undefined; 9287 return finishNode(factory.createJSDocTypeTag(tagName, typeExpression, comments), start); 9288 } 9289 9290 function parseSeeTag(start: number, tagName: Identifier, indent?: number, indentText?: string): JSDocSeeTag { 9291 const isMarkdownOrJSDocLink = token() === SyntaxKind.OpenBracketToken 9292 || lookAhead(() => nextTokenJSDoc() === SyntaxKind.AtToken && tokenIsIdentifierOrKeyword(nextTokenJSDoc()) && isJSDocLinkTag(scanner.getTokenValue())); 9293 const nameExpression = isMarkdownOrJSDocLink ? undefined : parseJSDocNameReference(); 9294 const comments = indent !== undefined && indentText !== undefined ? parseTrailingTagComments(start, getNodePos(), indent, indentText) : undefined; 9295 return finishNode(factory.createJSDocSeeTag(tagName, nameExpression, comments), start); 9296 } 9297 9298 function parseAuthorTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocAuthorTag { 9299 const commentStart = getNodePos(); 9300 const textOnly = parseAuthorNameAndEmail(); 9301 let commentEnd = scanner.getStartPos(); 9302 const comments = parseTrailingTagComments(start, commentEnd, indent, indentText); 9303 if (!comments) { 9304 commentEnd = scanner.getStartPos(); 9305 } 9306 const allParts = typeof comments !== "string" 9307 ? createNodeArray(concatenate([finishNode(textOnly, commentStart, commentEnd)], comments) as JSDocComment[], commentStart) // cast away readonly 9308 : textOnly.text + comments; 9309 return finishNode(factory.createJSDocAuthorTag(tagName, allParts), start); 9310 } 9311 9312 function parseAuthorNameAndEmail(): JSDocText { 9313 const comments: string[] = []; 9314 let inEmail = false; 9315 let token = scanner.getToken(); 9316 while (token !== SyntaxKind.EndOfFileToken && token !== SyntaxKind.NewLineTrivia) { 9317 if (token === SyntaxKind.LessThanToken) { 9318 inEmail = true; 9319 } 9320 else if (token === SyntaxKind.AtToken && !inEmail) { 9321 break; 9322 } 9323 else if (token === SyntaxKind.GreaterThanToken && inEmail) { 9324 comments.push(scanner.getTokenText()); 9325 scanner.setTextPos(scanner.getTokenPos() + 1); 9326 break; 9327 } 9328 comments.push(scanner.getTokenText()); 9329 token = nextTokenJSDoc(); 9330 } 9331 9332 return factory.createJSDocText(comments.join("")); 9333 } 9334 9335 function parseImplementsTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocImplementsTag { 9336 const className = parseExpressionWithTypeArgumentsForAugments(); 9337 return finishNode(factory.createJSDocImplementsTag(tagName, className, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start); 9338 } 9339 9340 function parseAugmentsTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocAugmentsTag { 9341 const className = parseExpressionWithTypeArgumentsForAugments(); 9342 return finishNode(factory.createJSDocAugmentsTag(tagName, className, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start); 9343 } 9344 9345 function parseExpressionWithTypeArgumentsForAugments(): ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression } { 9346 const usedBrace = parseOptional(SyntaxKind.OpenBraceToken); 9347 const pos = getNodePos(); 9348 const expression = parsePropertyAccessEntityNameExpression(); 9349 const typeArguments = tryParseTypeArguments(); 9350 const node = factory.createExpressionWithTypeArguments(expression, typeArguments) as ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression }; 9351 const res = finishNode(node, pos); 9352 if (usedBrace) { 9353 parseExpected(SyntaxKind.CloseBraceToken); 9354 } 9355 return res; 9356 } 9357 9358 function parsePropertyAccessEntityNameExpression() { 9359 const pos = getNodePos(); 9360 let node: Identifier | PropertyAccessEntityNameExpression = parseJSDocIdentifierName(); 9361 while (parseOptional(SyntaxKind.DotToken)) { 9362 const name = parseJSDocIdentifierName(); 9363 node = finishNode(factory.createPropertyAccessExpression(node, name), pos) as PropertyAccessEntityNameExpression; 9364 } 9365 return node; 9366 } 9367 9368 function parseSimpleTag(start: number, createTag: (tagName: Identifier | undefined, comment?: string | NodeArray<JSDocComment>) => JSDocTag, tagName: Identifier, margin: number, indentText: string): JSDocTag { 9369 return finishNode(createTag(tagName, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start); 9370 } 9371 9372 function parseThisTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocThisTag { 9373 const typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true); 9374 skipWhitespace(); 9375 return finishNode(factory.createJSDocThisTag(tagName, typeExpression, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start); 9376 } 9377 9378 function parseEnumTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocEnumTag { 9379 const typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true); 9380 skipWhitespace(); 9381 return finishNode(factory.createJSDocEnumTag(tagName, typeExpression, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start); 9382 } 9383 9384 function parseTypedefTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocTypedefTag { 9385 let typeExpression: JSDocTypeExpression | JSDocTypeLiteral | undefined = tryParseTypeExpression(); 9386 skipWhitespaceOrAsterisk(); 9387 9388 const fullName = parseJSDocTypeNameWithNamespace(); 9389 skipWhitespace(); 9390 let comment = parseTagComments(indent); 9391 9392 let end: number | undefined; 9393 if (!typeExpression || isObjectOrObjectArrayTypeReference(typeExpression.type)) { 9394 let child: JSDocTypeTag | JSDocPropertyTag | false; 9395 let childTypeTag: JSDocTypeTag | undefined; 9396 let jsDocPropertyTags: JSDocPropertyTag[] | undefined; 9397 let hasChildren = false; 9398 while (child = tryParse(() => parseChildPropertyTag(indent))) { 9399 hasChildren = true; 9400 if (child.kind === SyntaxKind.JSDocTypeTag) { 9401 if (childTypeTag) { 9402 const lastError = parseErrorAtCurrentToken(Diagnostics.A_JSDoc_typedef_comment_may_not_contain_multiple_type_tags); 9403 if (lastError) { 9404 addRelatedInfo(lastError, createDetachedDiagnostic(fileName, 0, 0, Diagnostics.The_tag_was_first_specified_here)); 9405 } 9406 break; 9407 } 9408 else { 9409 childTypeTag = child; 9410 } 9411 } 9412 else { 9413 jsDocPropertyTags = append(jsDocPropertyTags, child); 9414 } 9415 } 9416 if (hasChildren) { 9417 const isArrayType = typeExpression && typeExpression.type.kind === SyntaxKind.ArrayType; 9418 const jsdocTypeLiteral = factory.createJSDocTypeLiteral(jsDocPropertyTags, isArrayType); 9419 typeExpression = childTypeTag && childTypeTag.typeExpression && !isObjectOrObjectArrayTypeReference(childTypeTag.typeExpression.type) ? 9420 childTypeTag.typeExpression : 9421 finishNode(jsdocTypeLiteral, start); 9422 end = typeExpression.end; 9423 } 9424 } 9425 9426 // Only include the characters between the name end and the next token if a comment was actually parsed out - otherwise it's just whitespace 9427 end = end || comment !== undefined ? 9428 getNodePos() : 9429 (fullName ?? typeExpression ?? tagName).end; 9430 9431 if (!comment) { 9432 comment = parseTrailingTagComments(start, end, indent, indentText); 9433 } 9434 9435 const typedefTag = factory.createJSDocTypedefTag(tagName, typeExpression, fullName, comment); 9436 return finishNode(typedefTag, start, end); 9437 } 9438 9439 function parseJSDocTypeNameWithNamespace(nested?: boolean) { 9440 const pos = scanner.getTokenPos(); 9441 if (!tokenIsIdentifierOrKeyword(token())) { 9442 return undefined; 9443 } 9444 const typeNameOrNamespaceName = parseJSDocIdentifierName(); 9445 if (parseOptional(SyntaxKind.DotToken)) { 9446 const body = parseJSDocTypeNameWithNamespace(/*nested*/ true); 9447 const jsDocNamespaceNode = factory.createModuleDeclaration( 9448 /*modifiers*/ undefined, 9449 typeNameOrNamespaceName, 9450 body, 9451 nested ? NodeFlags.NestedNamespace : undefined 9452 ) as JSDocNamespaceDeclaration; 9453 return finishNode(jsDocNamespaceNode, pos); 9454 } 9455 9456 if (nested) { 9457 typeNameOrNamespaceName.isInJSDocNamespace = true; 9458 } 9459 return typeNameOrNamespaceName; 9460 } 9461 9462 9463 function parseCallbackTagParameters(indent: number) { 9464 const pos = getNodePos(); 9465 let child: JSDocParameterTag | false; 9466 let parameters; 9467 while (child = tryParse(() => parseChildParameterOrPropertyTag(PropertyLikeParse.CallbackParameter, indent) as JSDocParameterTag)) { 9468 parameters = append(parameters, child); 9469 } 9470 return createNodeArray(parameters || [], pos); 9471 } 9472 9473 function parseCallbackTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocCallbackTag { 9474 const fullName = parseJSDocTypeNameWithNamespace(); 9475 skipWhitespace(); 9476 let comment = parseTagComments(indent); 9477 const parameters = parseCallbackTagParameters(indent); 9478 const returnTag = tryParse(() => { 9479 if (parseOptionalJsdoc(SyntaxKind.AtToken)) { 9480 const tag = parseTag(indent); 9481 if (tag && tag.kind === SyntaxKind.JSDocReturnTag) { 9482 return tag as JSDocReturnTag; 9483 } 9484 } 9485 }); 9486 const typeExpression = finishNode(factory.createJSDocSignature(/*typeParameters*/ undefined, parameters, returnTag), start); 9487 if (!comment) { 9488 comment = parseTrailingTagComments(start, getNodePos(), indent, indentText); 9489 } 9490 const end = comment !== undefined ? getNodePos() : typeExpression.end; 9491 return finishNode(factory.createJSDocCallbackTag(tagName, typeExpression, fullName, comment), start, end); 9492 } 9493 9494 function escapedTextsEqual(a: EntityName, b: EntityName): boolean { 9495 while (!ts.isIdentifier(a) || !ts.isIdentifier(b)) { 9496 if (!ts.isIdentifier(a) && !ts.isIdentifier(b) && a.right.escapedText === b.right.escapedText) { 9497 a = a.left; 9498 b = b.left; 9499 } 9500 else { 9501 return false; 9502 } 9503 } 9504 return a.escapedText === b.escapedText; 9505 } 9506 9507 function parseChildPropertyTag(indent: number) { 9508 return parseChildParameterOrPropertyTag(PropertyLikeParse.Property, indent) as JSDocTypeTag | JSDocPropertyTag | false; 9509 } 9510 9511 function parseChildParameterOrPropertyTag(target: PropertyLikeParse, indent: number, name?: EntityName): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false { 9512 let canParseTag = true; 9513 let seenAsterisk = false; 9514 while (true) { 9515 switch (nextTokenJSDoc()) { 9516 case SyntaxKind.AtToken: 9517 if (canParseTag) { 9518 const child = tryParseChildTag(target, indent); 9519 if (child && (child.kind === SyntaxKind.JSDocParameterTag || child.kind === SyntaxKind.JSDocPropertyTag) && 9520 target !== PropertyLikeParse.CallbackParameter && 9521 name && (ts.isIdentifier(child.name) || !escapedTextsEqual(name, child.name.left))) { 9522 return false; 9523 } 9524 return child; 9525 } 9526 seenAsterisk = false; 9527 break; 9528 case SyntaxKind.NewLineTrivia: 9529 canParseTag = true; 9530 seenAsterisk = false; 9531 break; 9532 case SyntaxKind.AsteriskToken: 9533 if (seenAsterisk) { 9534 canParseTag = false; 9535 } 9536 seenAsterisk = true; 9537 break; 9538 case SyntaxKind.Identifier: 9539 canParseTag = false; 9540 break; 9541 case SyntaxKind.EndOfFileToken: 9542 return false; 9543 } 9544 } 9545 } 9546 9547 function tryParseChildTag(target: PropertyLikeParse, indent: number): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false { 9548 Debug.assert(token() === SyntaxKind.AtToken); 9549 const start = scanner.getStartPos(); 9550 nextTokenJSDoc(); 9551 9552 const tagName = parseJSDocIdentifierName(); 9553 skipWhitespace(); 9554 let t: PropertyLikeParse; 9555 switch (tagName.escapedText) { 9556 case "type": 9557 return target === PropertyLikeParse.Property && parseTypeTag(start, tagName); 9558 case "prop": 9559 case "property": 9560 t = PropertyLikeParse.Property; 9561 break; 9562 case "arg": 9563 case "argument": 9564 case "param": 9565 t = PropertyLikeParse.Parameter | PropertyLikeParse.CallbackParameter; 9566 break; 9567 default: 9568 return false; 9569 } 9570 if (!(target & t)) { 9571 return false; 9572 } 9573 return parseParameterOrPropertyTag(start, tagName, target, indent); 9574 } 9575 9576 function parseTemplateTagTypeParameter() { 9577 const typeParameterPos = getNodePos(); 9578 const isBracketed = parseOptionalJsdoc(SyntaxKind.OpenBracketToken); 9579 if (isBracketed) { 9580 skipWhitespace(); 9581 } 9582 const name = parseJSDocIdentifierName(Diagnostics.Unexpected_token_A_type_parameter_name_was_expected_without_curly_braces); 9583 9584 let defaultType: TypeNode | undefined; 9585 if (isBracketed) { 9586 skipWhitespace(); 9587 parseExpected(SyntaxKind.EqualsToken); 9588 defaultType = doInsideOfContext(NodeFlags.JSDoc, parseJSDocType); 9589 parseExpected(SyntaxKind.CloseBracketToken); 9590 } 9591 9592 if (nodeIsMissing(name)) { 9593 return undefined; 9594 } 9595 return finishNode(factory.createTypeParameterDeclaration(/*modifiers*/ undefined, name, /*constraint*/ undefined, defaultType), typeParameterPos); 9596 } 9597 9598 function parseTemplateTagTypeParameters() { 9599 const pos = getNodePos(); 9600 const typeParameters = []; 9601 do { 9602 skipWhitespace(); 9603 const node = parseTemplateTagTypeParameter(); 9604 if (node !== undefined) { 9605 typeParameters.push(node); 9606 } 9607 skipWhitespaceOrAsterisk(); 9608 } while (parseOptionalJsdoc(SyntaxKind.CommaToken)); 9609 return createNodeArray(typeParameters, pos); 9610 } 9611 9612 function parseTemplateTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocTemplateTag { 9613 // The template tag looks like one of the following: 9614 // @template T,U,V 9615 // @template {Constraint} T 9616 // 9617 // According to the [closure docs](https://github.com/google/closure-compiler/wiki/Generic-Types#multiple-bounded-template-types): 9618 // > Multiple bounded generics cannot be declared on the same line. For the sake of clarity, if multiple templates share the same 9619 // > type bound they must be declared on separate lines. 9620 // 9621 // TODO: Determine whether we should enforce this in the checker. 9622 // TODO: Consider moving the `constraint` to the first type parameter as we could then remove `getEffectiveConstraintOfTypeParameter`. 9623 // TODO: Consider only parsing a single type parameter if there is a constraint. 9624 const constraint = token() === SyntaxKind.OpenBraceToken ? parseJSDocTypeExpression() : undefined; 9625 const typeParameters = parseTemplateTagTypeParameters(); 9626 return finishNode(factory.createJSDocTemplateTag(tagName, constraint, typeParameters, parseTrailingTagComments(start, getNodePos(), indent, indentText)), start); 9627 } 9628 9629 function parseOptionalJsdoc(t: JSDocSyntaxKind): boolean { 9630 if (token() === t) { 9631 nextTokenJSDoc(); 9632 return true; 9633 } 9634 return false; 9635 } 9636 9637 function parseJSDocEntityName(): EntityName { 9638 let entity: EntityName = parseJSDocIdentifierName(); 9639 if (parseOptional(SyntaxKind.OpenBracketToken)) { 9640 parseExpected(SyntaxKind.CloseBracketToken); 9641 // Note that y[] is accepted as an entity name, but the postfix brackets are not saved for checking. 9642 // Technically usejsdoc.org requires them for specifying a property of a type equivalent to Array<{ x: ...}> 9643 // but it's not worth it to enforce that restriction. 9644 } 9645 while (parseOptional(SyntaxKind.DotToken)) { 9646 const name = parseJSDocIdentifierName(); 9647 if (parseOptional(SyntaxKind.OpenBracketToken)) { 9648 parseExpected(SyntaxKind.CloseBracketToken); 9649 } 9650 entity = createQualifiedName(entity, name); 9651 } 9652 return entity; 9653 } 9654 9655 function parseJSDocIdentifierName(message?: DiagnosticMessage): Identifier { 9656 if (!tokenIsIdentifierOrKeyword(token())) { 9657 return createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ !message, message || Diagnostics.Identifier_expected); 9658 } 9659 9660 identifierCount++; 9661 const pos = scanner.getTokenPos(); 9662 const end = scanner.getTextPos(); 9663 const originalKeywordKind = token(); 9664 const text = internIdentifier(scanner.getTokenValue()); 9665 const result = finishNode(factory.createIdentifier(text, /*typeArguments*/ undefined, originalKeywordKind), pos, end); 9666 nextTokenJSDoc(); 9667 return result; 9668 } 9669 } 9670 } 9671 } 9672 9673 namespace IncrementalParser { 9674 export function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks: boolean): SourceFile { 9675 aggressiveChecks = aggressiveChecks || Debug.shouldAssert(AssertionLevel.Aggressive); 9676 9677 checkChangeRange(sourceFile, newText, textChangeRange, aggressiveChecks); 9678 if (textChangeRangeIsUnchanged(textChangeRange)) { 9679 // if the text didn't change, then we can just return our current source file as-is. 9680 return sourceFile; 9681 } 9682 9683 if (sourceFile.statements.length === 0) { 9684 // If we don't have any statements in the current source file, then there's no real 9685 // way to incrementally parse. So just do a full parse instead. 9686 return Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, /*syntaxCursor*/ undefined, /*setParentNodes*/ true, sourceFile.scriptKind, sourceFile.setExternalModuleIndicator); 9687 } 9688 9689 // Make sure we're not trying to incrementally update a source file more than once. Once 9690 // we do an update the original source file is considered unusable from that point onwards. 9691 // 9692 // This is because we do incremental parsing in-place. i.e. we take nodes from the old 9693 // tree and give them new positions and parents. From that point on, trusting the old 9694 // tree at all is not possible as far too much of it may violate invariants. 9695 const incrementalSourceFile = sourceFile as Node as IncrementalNode; 9696 Debug.assert(!incrementalSourceFile.hasBeenIncrementallyParsed); 9697 incrementalSourceFile.hasBeenIncrementallyParsed = true; 9698 Parser.fixupParentReferences(incrementalSourceFile); 9699 const oldText = sourceFile.text; 9700 const syntaxCursor = createSyntaxCursor(sourceFile); 9701 9702 // Make the actual change larger so that we know to reparse anything whose lookahead 9703 // might have intersected the change. 9704 const changeRange = extendToAffectedRange(sourceFile, textChangeRange); 9705 checkChangeRange(sourceFile, newText, changeRange, aggressiveChecks); 9706 9707 // Ensure that extending the affected range only moved the start of the change range 9708 // earlier in the file. 9709 Debug.assert(changeRange.span.start <= textChangeRange.span.start); 9710 Debug.assert(textSpanEnd(changeRange.span) === textSpanEnd(textChangeRange.span)); 9711 Debug.assert(textSpanEnd(textChangeRangeNewSpan(changeRange)) === textSpanEnd(textChangeRangeNewSpan(textChangeRange))); 9712 9713 // The is the amount the nodes after the edit range need to be adjusted. It can be 9714 // positive (if the edit added characters), negative (if the edit deleted characters) 9715 // or zero (if this was a pure overwrite with nothing added/removed). 9716 const delta = textChangeRangeNewSpan(changeRange).length - changeRange.span.length; 9717 9718 // If we added or removed characters during the edit, then we need to go and adjust all 9719 // the nodes after the edit. Those nodes may move forward (if we inserted chars) or they 9720 // may move backward (if we deleted chars). 9721 // 9722 // Doing this helps us out in two ways. First, it means that any nodes/tokens we want 9723 // to reuse are already at the appropriate position in the new text. That way when we 9724 // reuse them, we don't have to figure out if they need to be adjusted. Second, it makes 9725 // it very easy to determine if we can reuse a node. If the node's position is at where 9726 // we are in the text, then we can reuse it. Otherwise we can't. If the node's position 9727 // is ahead of us, then we'll need to rescan tokens. If the node's position is behind 9728 // us, then we'll need to skip it or crumble it as appropriate 9729 // 9730 // We will also adjust the positions of nodes that intersect the change range as well. 9731 // By doing this, we ensure that all the positions in the old tree are consistent, not 9732 // just the positions of nodes entirely before/after the change range. By being 9733 // consistent, we can then easily map from positions to nodes in the old tree easily. 9734 // 9735 // Also, mark any syntax elements that intersect the changed span. We know, up front, 9736 // that we cannot reuse these elements. 9737 updateTokenPositionsAndMarkElements(incrementalSourceFile, 9738 changeRange.span.start, textSpanEnd(changeRange.span), textSpanEnd(textChangeRangeNewSpan(changeRange)), delta, oldText, newText, aggressiveChecks); 9739 9740 // Now that we've set up our internal incremental state just proceed and parse the 9741 // source file in the normal fashion. When possible the parser will retrieve and 9742 // reuse nodes from the old tree. 9743 // 9744 // Note: passing in 'true' for setNodeParents is very important. When incrementally 9745 // parsing, we will be reusing nodes from the old tree, and placing it into new 9746 // parents. If we don't set the parents now, we'll end up with an observably 9747 // inconsistent tree. Setting the parents on the new tree should be very fast. We 9748 // will immediately bail out of walking any subtrees when we can see that their parents 9749 // are already correct. 9750 const result = Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, syntaxCursor, /*setParentNodes*/ true, sourceFile.scriptKind, sourceFile.setExternalModuleIndicator); 9751 result.commentDirectives = getNewCommentDirectives( 9752 sourceFile.commentDirectives, 9753 result.commentDirectives, 9754 changeRange.span.start, 9755 textSpanEnd(changeRange.span), 9756 delta, 9757 oldText, 9758 newText, 9759 aggressiveChecks 9760 ); 9761 result.impliedNodeFormat = sourceFile.impliedNodeFormat; 9762 return result; 9763 } 9764 9765 function getNewCommentDirectives( 9766 oldDirectives: CommentDirective[] | undefined, 9767 newDirectives: CommentDirective[] | undefined, 9768 changeStart: number, 9769 changeRangeOldEnd: number, 9770 delta: number, 9771 oldText: string, 9772 newText: string, 9773 aggressiveChecks: boolean 9774 ): CommentDirective[] | undefined { 9775 if (!oldDirectives) return newDirectives; 9776 let commentDirectives: CommentDirective[] | undefined; 9777 let addedNewlyScannedDirectives = false; 9778 for (const directive of oldDirectives) { 9779 const { range, type } = directive; 9780 // Range before the change 9781 if (range.end < changeStart) { 9782 commentDirectives = append(commentDirectives, directive); 9783 } 9784 else if (range.pos > changeRangeOldEnd) { 9785 addNewlyScannedDirectives(); 9786 // Node is entirely past the change range. We need to move both its pos and 9787 // end, forward or backward appropriately. 9788 const updatedDirective: CommentDirective = { 9789 range: { pos: range.pos + delta, end: range.end + delta }, 9790 type 9791 }; 9792 commentDirectives = append(commentDirectives, updatedDirective); 9793 if (aggressiveChecks) { 9794 Debug.assert(oldText.substring(range.pos, range.end) === newText.substring(updatedDirective.range.pos, updatedDirective.range.end)); 9795 } 9796 } 9797 // Ignore ranges that fall in change range 9798 } 9799 addNewlyScannedDirectives(); 9800 return commentDirectives; 9801 9802 function addNewlyScannedDirectives() { 9803 if (addedNewlyScannedDirectives) return; 9804 addedNewlyScannedDirectives = true; 9805 if (!commentDirectives) { 9806 commentDirectives = newDirectives; 9807 } 9808 else if (newDirectives) { 9809 commentDirectives.push(...newDirectives); 9810 } 9811 } 9812 } 9813 9814 function moveElementEntirelyPastChangeRange(element: IncrementalElement, isArray: boolean, delta: number, oldText: string, newText: string, aggressiveChecks: boolean) { 9815 if (isArray) { 9816 visitArray(element as IncrementalNodeArray); 9817 } 9818 else { 9819 visitNode(element as IncrementalNode); 9820 } 9821 return; 9822 9823 function visitNode(node: IncrementalNode) { 9824 let text = ""; 9825 if (aggressiveChecks && shouldCheckNode(node)) { 9826 text = oldText.substring(node.pos, node.end); 9827 } 9828 9829 // Ditch any existing LS children we may have created. This way we can avoid 9830 // moving them forward. 9831 if (node._children) { 9832 node._children = undefined; 9833 } 9834 9835 setTextRangePosEnd(node, node.pos + delta, node.end + delta); 9836 9837 if (aggressiveChecks && shouldCheckNode(node)) { 9838 Debug.assert(text === newText.substring(node.pos, node.end)); 9839 } 9840 9841 forEachChild(node, visitNode, visitArray); 9842 if (hasJSDocNodes(node)) { 9843 for (const jsDocComment of node.jsDoc!) { 9844 visitNode(jsDocComment as Node as IncrementalNode); 9845 } 9846 } 9847 checkNodePositions(node, aggressiveChecks); 9848 } 9849 9850 function visitArray(array: IncrementalNodeArray) { 9851 array._children = undefined; 9852 setTextRangePosEnd(array, array.pos + delta, array.end + delta); 9853 9854 for (const node of array) { 9855 visitNode(node); 9856 } 9857 } 9858 } 9859 9860 function shouldCheckNode(node: Node) { 9861 switch (node.kind) { 9862 case SyntaxKind.StringLiteral: 9863 case SyntaxKind.NumericLiteral: 9864 case SyntaxKind.Identifier: 9865 return true; 9866 } 9867 9868 return false; 9869 } 9870 9871 function adjustIntersectingElement(element: IncrementalElement, changeStart: number, changeRangeOldEnd: number, changeRangeNewEnd: number, delta: number) { 9872 Debug.assert(element.end >= changeStart, "Adjusting an element that was entirely before the change range"); 9873 Debug.assert(element.pos <= changeRangeOldEnd, "Adjusting an element that was entirely after the change range"); 9874 Debug.assert(element.pos <= element.end); 9875 9876 // We have an element that intersects the change range in some way. It may have its 9877 // start, or its end (or both) in the changed range. We want to adjust any part 9878 // that intersects such that the final tree is in a consistent state. i.e. all 9879 // children have spans within the span of their parent, and all siblings are ordered 9880 // properly. 9881 9882 // We may need to update both the 'pos' and the 'end' of the element. 9883 9884 // If the 'pos' is before the start of the change, then we don't need to touch it. 9885 // If it isn't, then the 'pos' must be inside the change. How we update it will 9886 // depend if delta is positive or negative. If delta is positive then we have 9887 // something like: 9888 // 9889 // -------------------AAA----------------- 9890 // -------------------BBBCCCCCCC----------------- 9891 // 9892 // In this case, we consider any node that started in the change range to still be 9893 // starting at the same position. 9894 // 9895 // however, if the delta is negative, then we instead have something like this: 9896 // 9897 // -------------------XXXYYYYYYY----------------- 9898 // -------------------ZZZ----------------- 9899 // 9900 // In this case, any element that started in the 'X' range will keep its position. 9901 // However any element that started after that will have their pos adjusted to be 9902 // at the end of the new range. i.e. any node that started in the 'Y' range will 9903 // be adjusted to have their start at the end of the 'Z' range. 9904 // 9905 // The element will keep its position if possible. Or Move backward to the new-end 9906 // if it's in the 'Y' range. 9907 const pos = Math.min(element.pos, changeRangeNewEnd); 9908 9909 // If the 'end' is after the change range, then we always adjust it by the delta 9910 // amount. However, if the end is in the change range, then how we adjust it 9911 // will depend on if delta is positive or negative. If delta is positive then we 9912 // have something like: 9913 // 9914 // -------------------AAA----------------- 9915 // -------------------BBBCCCCCCC----------------- 9916 // 9917 // In this case, we consider any node that ended inside the change range to keep its 9918 // end position. 9919 // 9920 // however, if the delta is negative, then we instead have something like this: 9921 // 9922 // -------------------XXXYYYYYYY----------------- 9923 // -------------------ZZZ----------------- 9924 // 9925 // In this case, any element that ended in the 'X' range will keep its position. 9926 // However any element that ended after that will have their pos adjusted to be 9927 // at the end of the new range. i.e. any node that ended in the 'Y' range will 9928 // be adjusted to have their end at the end of the 'Z' range. 9929 const end = element.end >= changeRangeOldEnd ? 9930 // Element ends after the change range. Always adjust the end pos. 9931 element.end + delta : 9932 // Element ends in the change range. The element will keep its position if 9933 // possible. Or Move backward to the new-end if it's in the 'Y' range. 9934 Math.min(element.end, changeRangeNewEnd); 9935 9936 Debug.assert(pos <= end); 9937 if (element.parent) { 9938 Debug.assertGreaterThanOrEqual(pos, element.parent.pos); 9939 Debug.assertLessThanOrEqual(end, element.parent.end); 9940 } 9941 9942 setTextRangePosEnd(element, pos, end); 9943 } 9944 9945 function checkNodePositions(node: Node, aggressiveChecks: boolean) { 9946 if (aggressiveChecks) { 9947 let pos = node.pos; 9948 const visitNode = (child: Node) => { 9949 Debug.assert(child.pos >= pos); 9950 pos = child.end; 9951 }; 9952 if (hasJSDocNodes(node)) { 9953 for (const jsDocComment of node.jsDoc!) { 9954 visitNode(jsDocComment); 9955 } 9956 } 9957 forEachChild(node, visitNode); 9958 Debug.assert(pos <= node.end); 9959 } 9960 } 9961 9962 function updateTokenPositionsAndMarkElements( 9963 sourceFile: IncrementalNode, 9964 changeStart: number, 9965 changeRangeOldEnd: number, 9966 changeRangeNewEnd: number, 9967 delta: number, 9968 oldText: string, 9969 newText: string, 9970 aggressiveChecks: boolean): void { 9971 9972 visitNode(sourceFile); 9973 return; 9974 9975 function visitNode(child: IncrementalNode) { 9976 Debug.assert(child.pos <= child.end); 9977 if (child.pos > changeRangeOldEnd) { 9978 // Node is entirely past the change range. We need to move both its pos and 9979 // end, forward or backward appropriately. 9980 moveElementEntirelyPastChangeRange(child, /*isArray*/ false, delta, oldText, newText, aggressiveChecks); 9981 return; 9982 } 9983 9984 // Check if the element intersects the change range. If it does, then it is not 9985 // reusable. Also, we'll need to recurse to see what constituent portions we may 9986 // be able to use. 9987 const fullEnd = child.end; 9988 if (fullEnd >= changeStart) { 9989 child.intersectsChange = true; 9990 child._children = undefined; 9991 9992 // Adjust the pos or end (or both) of the intersecting element accordingly. 9993 adjustIntersectingElement(child, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta); 9994 forEachChild(child, visitNode, visitArray); 9995 if (hasJSDocNodes(child)) { 9996 for (const jsDocComment of child.jsDoc!) { 9997 visitNode(jsDocComment as Node as IncrementalNode); 9998 } 9999 } 10000 checkNodePositions(child, aggressiveChecks); 10001 return; 10002 } 10003 10004 // Otherwise, the node is entirely before the change range. No need to do anything with it. 10005 Debug.assert(fullEnd < changeStart); 10006 } 10007 10008 function visitArray(array: IncrementalNodeArray) { 10009 Debug.assert(array.pos <= array.end); 10010 if (array.pos > changeRangeOldEnd) { 10011 // Array is entirely after the change range. We need to move it, and move any of 10012 // its children. 10013 moveElementEntirelyPastChangeRange(array, /*isArray*/ true, delta, oldText, newText, aggressiveChecks); 10014 return; 10015 } 10016 10017 // Check if the element intersects the change range. If it does, then it is not 10018 // reusable. Also, we'll need to recurse to see what constituent portions we may 10019 // be able to use. 10020 const fullEnd = array.end; 10021 if (fullEnd >= changeStart) { 10022 array.intersectsChange = true; 10023 array._children = undefined; 10024 10025 // Adjust the pos or end (or both) of the intersecting array accordingly. 10026 adjustIntersectingElement(array, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta); 10027 for (const node of array) { 10028 if (!node.virtual) { 10029 visitNode(node); 10030 } 10031 } 10032 return; 10033 } 10034 10035 // Otherwise, the array is entirely before the change range. No need to do anything with it. 10036 Debug.assert(fullEnd < changeStart); 10037 } 10038 } 10039 10040 function extendToAffectedRange(sourceFile: SourceFile, changeRange: TextChangeRange): TextChangeRange { 10041 // Consider the following code: 10042 // void foo() { /; } 10043 // 10044 // If the text changes with an insertion of / just before the semicolon then we end up with: 10045 // void foo() { //; } 10046 // 10047 // If we were to just use the changeRange a is, then we would not rescan the { token 10048 // (as it does not intersect the actual original change range). Because an edit may 10049 // change the token touching it, we actually need to look back *at least* one token so 10050 // that the prior token sees that change. 10051 const maxLookahead = 1; 10052 10053 let start = changeRange.span.start; 10054 10055 // the first iteration aligns us with the change start. subsequent iteration move us to 10056 // the left by maxLookahead tokens. We only need to do this as long as we're not at the 10057 // start of the tree. 10058 for (let i = 0; start > 0 && i <= maxLookahead; i++) { 10059 const nearestNode = findNearestNodeStartingBeforeOrAtPosition(sourceFile, start); 10060 Debug.assert(nearestNode.pos <= start); 10061 const position = nearestNode.pos; 10062 10063 start = Math.max(0, position - 1); 10064 } 10065 10066 const finalSpan = createTextSpanFromBounds(start, textSpanEnd(changeRange.span)); 10067 const finalLength = changeRange.newLength + (changeRange.span.start - start); 10068 10069 return createTextChangeRange(finalSpan, finalLength); 10070 } 10071 10072 function findNearestNodeStartingBeforeOrAtPosition(sourceFile: SourceFile, position: number): Node { 10073 let bestResult: Node = sourceFile; 10074 let lastNodeEntirelyBeforePosition: Node | undefined; 10075 10076 forEachChild(sourceFile, visit); 10077 10078 if (lastNodeEntirelyBeforePosition) { 10079 const lastChildOfLastEntireNodeBeforePosition = getLastDescendant(lastNodeEntirelyBeforePosition); 10080 if (lastChildOfLastEntireNodeBeforePosition.pos > bestResult.pos) { 10081 bestResult = lastChildOfLastEntireNodeBeforePosition; 10082 } 10083 } 10084 10085 return bestResult; 10086 10087 function getLastDescendant(node: Node): Node { 10088 while (true) { 10089 const lastChild = getLastChild(node); 10090 if (lastChild) { 10091 node = lastChild; 10092 } 10093 else { 10094 return node; 10095 } 10096 } 10097 } 10098 10099 function visit(child: Node) { 10100 if (nodeIsMissing(child)) { 10101 // Missing nodes are effectively invisible to us. We never even consider them 10102 // When trying to find the nearest node before us. 10103 return; 10104 } 10105 10106 // If the child intersects this position, then this node is currently the nearest 10107 // node that starts before the position. 10108 if (child.pos <= position) { 10109 if (child.pos >= bestResult.pos) { 10110 // This node starts before the position, and is closer to the position than 10111 // the previous best node we found. It is now the new best node. 10112 bestResult = child; 10113 } 10114 10115 // Now, the node may overlap the position, or it may end entirely before the 10116 // position. If it overlaps with the position, then either it, or one of its 10117 // children must be the nearest node before the position. So we can just 10118 // recurse into this child to see if we can find something better. 10119 if (position < child.end) { 10120 // The nearest node is either this child, or one of the children inside 10121 // of it. We've already marked this child as the best so far. Recurse 10122 // in case one of the children is better. 10123 forEachChild(child, visit); 10124 10125 // Once we look at the children of this node, then there's no need to 10126 // continue any further. 10127 return true; 10128 } 10129 else { 10130 Debug.assert(child.end <= position); 10131 // The child ends entirely before this position. Say you have the following 10132 // (where $ is the position) 10133 // 10134 // <complex expr 1> ? <complex expr 2> $ : <...> <...> 10135 // 10136 // We would want to find the nearest preceding node in "complex expr 2". 10137 // To support that, we keep track of this node, and once we're done searching 10138 // for a best node, we recurse down this node to see if we can find a good 10139 // result in it. 10140 // 10141 // This approach allows us to quickly skip over nodes that are entirely 10142 // before the position, while still allowing us to find any nodes in the 10143 // last one that might be what we want. 10144 lastNodeEntirelyBeforePosition = child; 10145 } 10146 } 10147 else { 10148 Debug.assert(child.pos > position); 10149 // We're now at a node that is entirely past the position we're searching for. 10150 // This node (and all following nodes) could never contribute to the result, 10151 // so just skip them by returning 'true' here. 10152 return true; 10153 } 10154 } 10155 } 10156 10157 function checkChangeRange(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks: boolean) { 10158 const oldText = sourceFile.text; 10159 if (textChangeRange) { 10160 Debug.assert((oldText.length - textChangeRange.span.length + textChangeRange.newLength) === newText.length); 10161 10162 if (aggressiveChecks || Debug.shouldAssert(AssertionLevel.VeryAggressive)) { 10163 const oldTextPrefix = oldText.substr(0, textChangeRange.span.start); 10164 const newTextPrefix = newText.substr(0, textChangeRange.span.start); 10165 Debug.assert(oldTextPrefix === newTextPrefix); 10166 10167 const oldTextSuffix = oldText.substring(textSpanEnd(textChangeRange.span), oldText.length); 10168 const newTextSuffix = newText.substring(textSpanEnd(textChangeRangeNewSpan(textChangeRange)), newText.length); 10169 Debug.assert(oldTextSuffix === newTextSuffix); 10170 } 10171 } 10172 } 10173 10174 interface IncrementalElement extends ReadonlyTextRange { 10175 readonly parent: Node; 10176 intersectsChange: boolean; 10177 length?: number; 10178 _children: Node[] | undefined; 10179 } 10180 10181 export interface IncrementalNode extends Node, IncrementalElement { 10182 hasBeenIncrementallyParsed: boolean; 10183 } 10184 10185 interface IncrementalNodeArray extends NodeArray<IncrementalNode>, IncrementalElement { 10186 length: number; 10187 } 10188 10189 // Allows finding nodes in the source file at a certain position in an efficient manner. 10190 // The implementation takes advantage of the calling pattern it knows the parser will 10191 // make in order to optimize finding nodes as quickly as possible. 10192 export interface SyntaxCursor { 10193 currentNode(position: number): IncrementalNode; 10194 } 10195 10196 export function createSyntaxCursor(sourceFile: SourceFile): SyntaxCursor { 10197 let currentArray: NodeArray<Node> = sourceFile.statements; 10198 let currentArrayIndex = 0; 10199 10200 Debug.assert(currentArrayIndex < currentArray.length); 10201 let current = currentArray[currentArrayIndex]; 10202 let lastQueriedPosition = InvalidPosition.Value; 10203 10204 return { 10205 currentNode(position: number) { 10206 // Only compute the current node if the position is different than the last time 10207 // we were asked. The parser commonly asks for the node at the same position 10208 // twice. Once to know if can read an appropriate list element at a certain point, 10209 // and then to actually read and consume the node. 10210 if (position !== lastQueriedPosition) { 10211 // Much of the time the parser will need the very next node in the array that 10212 // we just returned a node from.So just simply check for that case and move 10213 // forward in the array instead of searching for the node again. 10214 if (current && current.end === position && currentArrayIndex < (currentArray.length - 1)) { 10215 currentArrayIndex++; 10216 current = currentArray[currentArrayIndex]; 10217 } 10218 10219 // If we don't have a node, or the node we have isn't in the right position, 10220 // then try to find a viable node at the position requested. 10221 if (!current || current.pos !== position) { 10222 findHighestListElementThatStartsAtPosition(position); 10223 } 10224 } 10225 10226 // Cache this query so that we don't do any extra work if the parser calls back 10227 // into us. Note: this is very common as the parser will make pairs of calls like 10228 // 'isListElement -> parseListElement'. If we were unable to find a node when 10229 // called with 'isListElement', we don't want to redo the work when parseListElement 10230 // is called immediately after. 10231 lastQueriedPosition = position; 10232 10233 // Either we don'd have a node, or we have a node at the position being asked for. 10234 Debug.assert(!current || current.pos === position); 10235 return current as IncrementalNode; 10236 } 10237 }; 10238 10239 // Finds the highest element in the tree we can find that starts at the provided position. 10240 // The element must be a direct child of some node list in the tree. This way after we 10241 // return it, we can easily return its next sibling in the list. 10242 function findHighestListElementThatStartsAtPosition(position: number) { 10243 // Clear out any cached state about the last node we found. 10244 currentArray = undefined!; 10245 currentArrayIndex = InvalidPosition.Value; 10246 current = undefined!; 10247 10248 // Recurse into the source file to find the highest node at this position. 10249 forEachChild(sourceFile, visitNode, visitArray); 10250 return; 10251 10252 function visitNode(node: Node) { 10253 if (position >= node.pos && position < node.end) { 10254 // Position was within this node. Keep searching deeper to find the node. 10255 forEachChild(node, visitNode, visitArray); 10256 10257 // don't proceed any further in the search. 10258 return true; 10259 } 10260 10261 // position wasn't in this node, have to keep searching. 10262 return false; 10263 } 10264 10265 function visitArray(array: NodeArray<Node>) { 10266 if (position >= array.pos && position < array.end) { 10267 // position was in this array. Search through this array to see if we find a 10268 // viable element. 10269 for (let i = 0; i < array.length; i++) { 10270 const child = array[i]; 10271 if (child) { 10272 if (child.pos === position) { 10273 // Found the right node. We're done. 10274 currentArray = array; 10275 currentArrayIndex = i; 10276 current = child; 10277 return true; 10278 } 10279 else { 10280 if (child.pos < position && position < child.end) { 10281 // Position in somewhere within this child. Search in it and 10282 // stop searching in this array. 10283 forEachChild(child, visitNode, visitArray); 10284 return true; 10285 } 10286 } 10287 } 10288 } 10289 } 10290 10291 // position wasn't in this array, have to keep searching. 10292 return false; 10293 } 10294 } 10295 } 10296 10297 const enum InvalidPosition { 10298 Value = -1 10299 } 10300 } 10301 10302 /** @internal */ 10303 export function isDeclarationFileName(fileName: string): boolean { 10304 return fileExtensionIsOneOf(fileName, supportedDeclarationExtensions); 10305 } 10306 10307 /*@internal*/ 10308 export interface PragmaContext { 10309 languageVersion: ScriptTarget; 10310 pragmas?: PragmaMap; 10311 checkJsDirective?: CheckJsDirective; 10312 referencedFiles: FileReference[]; 10313 typeReferenceDirectives: FileReference[]; 10314 libReferenceDirectives: FileReference[]; 10315 amdDependencies: AmdDependency[]; 10316 hasNoDefaultLib?: boolean; 10317 moduleName?: string; 10318 } 10319 10320 function parseResolutionMode(mode: string | undefined, pos: number, end: number, reportDiagnostic: PragmaDiagnosticReporter): ModuleKind.ESNext | ModuleKind.CommonJS | undefined { 10321 if (!mode) { 10322 return undefined; 10323 } 10324 if (mode === "import") { 10325 return ModuleKind.ESNext; 10326 } 10327 if (mode === "require") { 10328 return ModuleKind.CommonJS; 10329 } 10330 reportDiagnostic(pos, end - pos, Diagnostics.resolution_mode_should_be_either_require_or_import); 10331 return undefined; 10332 } 10333 10334 /*@internal*/ 10335 export function processCommentPragmas(context: PragmaContext, sourceText: string): void { 10336 const pragmas: PragmaPseudoMapEntry[] = []; 10337 10338 for (const range of getLeadingCommentRanges(sourceText, 0) || emptyArray) { 10339 const comment = sourceText.substring(range.pos, range.end); 10340 extractPragmas(pragmas, range, comment); 10341 } 10342 10343 context.pragmas = new Map() as PragmaMap; 10344 for (const pragma of pragmas) { 10345 if (context.pragmas.has(pragma.name)) { 10346 const currentValue = context.pragmas.get(pragma.name); 10347 if (currentValue instanceof Array) { 10348 currentValue.push(pragma.args); 10349 } 10350 else { 10351 context.pragmas.set(pragma.name, [currentValue, pragma.args]); 10352 } 10353 continue; 10354 } 10355 context.pragmas.set(pragma.name, pragma.args); 10356 } 10357 } 10358 10359 /*@internal*/ 10360 type PragmaDiagnosticReporter = (pos: number, length: number, message: DiagnosticMessage) => void; 10361 10362 /*@internal*/ 10363 export function processPragmasIntoFields(context: PragmaContext, reportDiagnostic: PragmaDiagnosticReporter): void { 10364 context.checkJsDirective = undefined; 10365 context.referencedFiles = []; 10366 context.typeReferenceDirectives = []; 10367 context.libReferenceDirectives = []; 10368 context.amdDependencies = []; 10369 context.hasNoDefaultLib = false; 10370 context.pragmas!.forEach((entryOrList, key) => { // TODO: GH#18217 10371 // TODO: The below should be strongly type-guarded and not need casts/explicit annotations, since entryOrList is related to 10372 // key and key is constrained to a union; but it's not (see GH#21483 for at least partial fix) :( 10373 switch (key) { 10374 case "reference": { 10375 const referencedFiles = context.referencedFiles; 10376 const typeReferenceDirectives = context.typeReferenceDirectives; 10377 const libReferenceDirectives = context.libReferenceDirectives; 10378 forEach(toArray(entryOrList) as PragmaPseudoMap["reference"][], arg => { 10379 const { types, lib, path, ["resolution-mode"]: res } = arg.arguments; 10380 if (arg.arguments["no-default-lib"]) { 10381 context.hasNoDefaultLib = true; 10382 } 10383 else if (types) { 10384 const parsed = parseResolutionMode(res, types.pos, types.end, reportDiagnostic); 10385 typeReferenceDirectives.push({ pos: types.pos, end: types.end, fileName: types.value, ...(parsed ? { resolutionMode: parsed } : {}) }); 10386 } 10387 else if (lib) { 10388 libReferenceDirectives.push({ pos: lib.pos, end: lib.end, fileName: lib.value }); 10389 } 10390 else if (path) { 10391 referencedFiles.push({ pos: path.pos, end: path.end, fileName: path.value }); 10392 } 10393 else { 10394 reportDiagnostic(arg.range.pos, arg.range.end - arg.range.pos, Diagnostics.Invalid_reference_directive_syntax); 10395 } 10396 }); 10397 break; 10398 } 10399 case "amd-dependency": { 10400 context.amdDependencies = map( 10401 toArray(entryOrList) as PragmaPseudoMap["amd-dependency"][], 10402 x => ({ name: x.arguments.name, path: x.arguments.path })); 10403 break; 10404 } 10405 case "amd-module": { 10406 if (entryOrList instanceof Array) { 10407 for (const entry of entryOrList) { 10408 if (context.moduleName) { 10409 // TODO: It's probably fine to issue this diagnostic on all instances of the pragma 10410 reportDiagnostic(entry.range.pos, entry.range.end - entry.range.pos, Diagnostics.An_AMD_module_cannot_have_multiple_name_assignments); 10411 } 10412 context.moduleName = (entry as PragmaPseudoMap["amd-module"]).arguments.name; 10413 } 10414 } 10415 else { 10416 context.moduleName = (entryOrList as PragmaPseudoMap["amd-module"]).arguments.name; 10417 } 10418 break; 10419 } 10420 case "ts-nocheck": 10421 case "ts-check": { 10422 // _last_ of either nocheck or check in a file is the "winner" 10423 forEach(toArray(entryOrList), entry => { 10424 if (!context.checkJsDirective || entry.range.pos > context.checkJsDirective.pos) { 10425 context.checkJsDirective = { 10426 enabled: key === "ts-check", 10427 end: entry.range.end, 10428 pos: entry.range.pos 10429 }; 10430 } 10431 }); 10432 break; 10433 } 10434 case "jsx": 10435 case "jsxfrag": 10436 case "jsximportsource": 10437 case "jsxruntime": 10438 return; // Accessed directly 10439 default: Debug.fail("Unhandled pragma kind"); // Can this be made into an assertNever in the future? 10440 } 10441 }); 10442 } 10443 10444 const namedArgRegExCache = new Map<string, RegExp>(); 10445 function getNamedArgRegEx(name: string): RegExp { 10446 if (namedArgRegExCache.has(name)) { 10447 return namedArgRegExCache.get(name)!; 10448 } 10449 const result = new RegExp(`(\\s${name}\\s*=\\s*)(?:(?:'([^']*)')|(?:"([^"]*)"))`, "im"); 10450 namedArgRegExCache.set(name, result); 10451 return result; 10452 } 10453 10454 const tripleSlashXMLCommentStartRegEx = /^\/\/\/\s*<(\S+)\s.*?\/>/im; 10455 const singleLinePragmaRegEx = /^\/\/\/?\s*@(\S+)\s*(.*)\s*$/im; 10456 function extractPragmas(pragmas: PragmaPseudoMapEntry[], range: CommentRange, text: string) { 10457 const tripleSlash = range.kind === SyntaxKind.SingleLineCommentTrivia && tripleSlashXMLCommentStartRegEx.exec(text); 10458 if (tripleSlash) { 10459 const name = tripleSlash[1].toLowerCase() as keyof PragmaPseudoMap; // Technically unsafe cast, but we do it so the below check to make it safe typechecks 10460 const pragma = commentPragmas[name] as PragmaDefinition; 10461 if (!pragma || !(pragma.kind! & PragmaKindFlags.TripleSlashXML)) { 10462 return; 10463 } 10464 if (pragma.args) { 10465 const argument: {[index: string]: string | {value: string, pos: number, end: number}} = {}; 10466 for (const arg of pragma.args) { 10467 const matcher = getNamedArgRegEx(arg.name); 10468 const matchResult = matcher.exec(text); 10469 if (!matchResult && !arg.optional) { 10470 return; // Missing required argument, don't parse 10471 } 10472 else if (matchResult) { 10473 const value = matchResult[2] || matchResult[3]; 10474 if (arg.captureSpan) { 10475 const startPos = range.pos + matchResult.index + matchResult[1].length + 1; 10476 argument[arg.name] = { 10477 value, 10478 pos: startPos, 10479 end: startPos + value.length 10480 }; 10481 } 10482 else { 10483 argument[arg.name] = value; 10484 } 10485 } 10486 } 10487 pragmas.push({ name, args: { arguments: argument, range } } as PragmaPseudoMapEntry); 10488 } 10489 else { 10490 pragmas.push({ name, args: { arguments: {}, range } } as PragmaPseudoMapEntry); 10491 } 10492 return; 10493 } 10494 10495 const singleLine = range.kind === SyntaxKind.SingleLineCommentTrivia && singleLinePragmaRegEx.exec(text); 10496 if (singleLine) { 10497 return addPragmaForMatch(pragmas, range, PragmaKindFlags.SingleLine, singleLine); 10498 } 10499 10500 if (range.kind === SyntaxKind.MultiLineCommentTrivia) { 10501 const multiLinePragmaRegEx = /@(\S+)(\s+.*)?$/gim; // Defined inline since it uses the "g" flag, which keeps a persistent index (for iterating) 10502 let multiLineMatch: RegExpExecArray | null; 10503 while (multiLineMatch = multiLinePragmaRegEx.exec(text)) { 10504 addPragmaForMatch(pragmas, range, PragmaKindFlags.MultiLine, multiLineMatch); 10505 } 10506 } 10507 } 10508 10509 function addPragmaForMatch(pragmas: PragmaPseudoMapEntry[], range: CommentRange, kind: PragmaKindFlags, match: RegExpExecArray) { 10510 if (!match) return; 10511 const name = match[1].toLowerCase() as keyof PragmaPseudoMap; // Technically unsafe cast, but we do it so they below check to make it safe typechecks 10512 const pragma = commentPragmas[name] as PragmaDefinition; 10513 if (!pragma || !(pragma.kind! & kind)) { 10514 return; 10515 } 10516 const args = match[2]; // Split on spaces and match up positionally with definition 10517 const argument = getNamedPragmaArguments(pragma, args); 10518 if (argument === "fail") return; // Missing required argument, fail to parse it 10519 pragmas.push({ name, args: { arguments: argument, range } } as PragmaPseudoMapEntry); 10520 return; 10521 } 10522 10523 function getNamedPragmaArguments(pragma: PragmaDefinition, text: string | undefined): {[index: string]: string} | "fail" { 10524 if (!text) return {}; 10525 if (!pragma.args) return {}; 10526 const args = trimString(text).split(/\s+/); 10527 const argMap: {[index: string]: string} = {}; 10528 for (let i = 0; i < pragma.args.length; i++) { 10529 const argument = pragma.args[i]; 10530 if (!args[i] && !argument.optional) { 10531 return "fail"; 10532 } 10533 if (argument.captureSpan) { 10534 return Debug.fail("Capture spans not yet implemented for non-xml pragmas"); 10535 } 10536 argMap[argument.name] = args[i]; 10537 } 10538 return argMap; 10539 } 10540 10541 /** @internal */ 10542 export function tagNamesAreEquivalent(lhs: JsxTagNameExpression, rhs: JsxTagNameExpression): boolean { 10543 if (lhs.kind !== rhs.kind) { 10544 return false; 10545 } 10546 10547 if (lhs.kind === SyntaxKind.Identifier) { 10548 return lhs.escapedText === (rhs as Identifier).escapedText; 10549 } 10550 10551 if (lhs.kind === SyntaxKind.ThisKeyword) { 10552 return true; 10553 } 10554 10555 // If we are at this statement then we must have PropertyAccessExpression and because tag name in Jsx element can only 10556 // take forms of JsxTagNameExpression which includes an identifier, "this" expression, or another propertyAccessExpression 10557 // it is safe to case the expression property as such. See parseJsxElementName for how we parse tag name in Jsx element 10558 return (lhs as PropertyAccessExpression).name.escapedText === (rhs as PropertyAccessExpression).name.escapedText && 10559 tagNamesAreEquivalent((lhs as PropertyAccessExpression).expression as JsxTagNameExpression, (rhs as PropertyAccessExpression).expression as JsxTagNameExpression); 10560 } 10561} 10562