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