1namespace ts { 2 export function isExternalModuleNameRelative(moduleName: string): boolean { 3 // TypeScript 1.0 spec (April 2014): 11.2.1 4 // An external module name is "relative" if the first term is "." or "..". 5 // Update: We also consider a path like `C:\foo.ts` "relative" because we do not search for it in `node_modules`, `oh_modules` or treat it as an ambient module. 6 return pathIsRelative(moduleName) || isRootedDiskPath(moduleName); 7 } 8 9 export function sortAndDeduplicateDiagnostics<T extends Diagnostic>(diagnostics: readonly T[]): SortedReadonlyArray<T> { 10 return sortAndDeduplicate<T>(diagnostics, compareDiagnostics); 11 } 12 13 export function getDefaultLibFileName(options: CompilerOptions): string { 14 switch (getEmitScriptTarget(options)) { 15 case ScriptTarget.ESNext: 16 return "lib.esnext.full.d.ts"; 17 case ScriptTarget.ES2022: 18 return "lib.es2022.full.d.ts"; 19 case ScriptTarget.ES2021: 20 return "lib.es2021.full.d.ts"; 21 case ScriptTarget.ES2020: 22 return "lib.es2020.full.d.ts"; 23 case ScriptTarget.ES2019: 24 return "lib.es2019.full.d.ts"; 25 case ScriptTarget.ES2018: 26 return "lib.es2018.full.d.ts"; 27 case ScriptTarget.ES2017: 28 return "lib.es2017.full.d.ts"; 29 case ScriptTarget.ES2016: 30 return "lib.es2016.full.d.ts"; 31 case ScriptTarget.ES2015: 32 return "lib.es6.d.ts"; // We don't use lib.es2015.full.d.ts due to breaking change. 33 default: 34 return "lib.d.ts"; 35 } 36 } 37 38 export function textSpanEnd(span: TextSpan) { 39 return span.start + span.length; 40 } 41 42 export function textSpanIsEmpty(span: TextSpan) { 43 return span.length === 0; 44 } 45 46 export function textSpanContainsPosition(span: TextSpan, position: number) { 47 return position >= span.start && position < textSpanEnd(span); 48 } 49 50 /* @internal */ 51 export function textRangeContainsPositionInclusive(span: TextRange, position: number): boolean { 52 return position >= span.pos && position <= span.end; 53 } 54 55 // Returns true if 'span' contains 'other'. 56 export function textSpanContainsTextSpan(span: TextSpan, other: TextSpan) { 57 return other.start >= span.start && textSpanEnd(other) <= textSpanEnd(span); 58 } 59 60 export function textSpanOverlapsWith(span: TextSpan, other: TextSpan) { 61 return textSpanOverlap(span, other) !== undefined; 62 } 63 64 export function textSpanOverlap(span1: TextSpan, span2: TextSpan): TextSpan | undefined { 65 const overlap = textSpanIntersection(span1, span2); 66 return overlap && overlap.length === 0 ? undefined : overlap; 67 } 68 69 export function textSpanIntersectsWithTextSpan(span: TextSpan, other: TextSpan) { 70 return decodedTextSpanIntersectsWith(span.start, span.length, other.start, other.length); 71 } 72 73 export function textSpanIntersectsWith(span: TextSpan, start: number, length: number) { 74 return decodedTextSpanIntersectsWith(span.start, span.length, start, length); 75 } 76 77 export function decodedTextSpanIntersectsWith(start1: number, length1: number, start2: number, length2: number) { 78 const end1 = start1 + length1; 79 const end2 = start2 + length2; 80 return start2 <= end1 && end2 >= start1; 81 } 82 83 export function textSpanIntersectsWithPosition(span: TextSpan, position: number) { 84 return position <= textSpanEnd(span) && position >= span.start; 85 } 86 87 export function textSpanIntersection(span1: TextSpan, span2: TextSpan): TextSpan | undefined { 88 const start = Math.max(span1.start, span2.start); 89 const end = Math.min(textSpanEnd(span1), textSpanEnd(span2)); 90 return start <= end ? createTextSpanFromBounds(start, end) : undefined; 91 } 92 93 export function createTextSpan(start: number, length: number): TextSpan { 94 if (start < 0) { 95 throw new Error("start < 0"); 96 } 97 if (length < 0) { 98 throw new Error("length < 0"); 99 } 100 101 return { start, length }; 102 } 103 104 export function createTextSpanFromBounds(start: number, end: number) { 105 return createTextSpan(start, end - start); 106 } 107 108 export function textChangeRangeNewSpan(range: TextChangeRange) { 109 return createTextSpan(range.span.start, range.newLength); 110 } 111 112 export function textChangeRangeIsUnchanged(range: TextChangeRange) { 113 return textSpanIsEmpty(range.span) && range.newLength === 0; 114 } 115 116 export function createTextChangeRange(span: TextSpan, newLength: number): TextChangeRange { 117 if (newLength < 0) { 118 throw new Error("newLength < 0"); 119 } 120 121 return { span, newLength }; 122 } 123 124 export let unchangedTextChangeRange = createTextChangeRange(createTextSpan(0, 0), 0); // eslint-disable-line prefer-const 125 126 /** 127 * Called to merge all the changes that occurred across several versions of a script snapshot 128 * into a single change. i.e. if a user keeps making successive edits to a script we will 129 * have a text change from V1 to V2, V2 to V3, ..., Vn. 130 * 131 * This function will then merge those changes into a single change range valid between V1 and 132 * Vn. 133 */ 134 export function collapseTextChangeRangesAcrossMultipleVersions(changes: readonly TextChangeRange[]): TextChangeRange { 135 if (changes.length === 0) { 136 return unchangedTextChangeRange; 137 } 138 139 if (changes.length === 1) { 140 return changes[0]; 141 } 142 143 // We change from talking about { { oldStart, oldLength }, newLength } to { oldStart, oldEnd, newEnd } 144 // as it makes things much easier to reason about. 145 const change0 = changes[0]; 146 147 let oldStartN = change0.span.start; 148 let oldEndN = textSpanEnd(change0.span); 149 let newEndN = oldStartN + change0.newLength; 150 151 for (let i = 1; i < changes.length; i++) { 152 const nextChange = changes[i]; 153 154 // Consider the following case: 155 // i.e. two edits. The first represents the text change range { { 10, 50 }, 30 }. i.e. The span starting 156 // at 10, with length 50 is reduced to length 30. The second represents the text change range { { 30, 30 }, 40 }. 157 // i.e. the span starting at 30 with length 30 is increased to length 40. 158 // 159 // 0 10 20 30 40 50 60 70 80 90 100 160 // ------------------------------------------------------------------------------------------------------- 161 // | / 162 // | /---- 163 // T1 | /---- 164 // | /---- 165 // | /---- 166 // ------------------------------------------------------------------------------------------------------- 167 // | \ 168 // | \ 169 // T2 | \ 170 // | \ 171 // | \ 172 // ------------------------------------------------------------------------------------------------------- 173 // 174 // Merging these turns out to not be too difficult. First, determining the new start of the change is trivial 175 // it's just the min of the old and new starts. i.e.: 176 // 177 // 0 10 20 30 40 50 60 70 80 90 100 178 // ------------------------------------------------------------*------------------------------------------ 179 // | / 180 // | /---- 181 // T1 | /---- 182 // | /---- 183 // | /---- 184 // ----------------------------------------$-------------------$------------------------------------------ 185 // . | \ 186 // . | \ 187 // T2 . | \ 188 // . | \ 189 // . | \ 190 // ----------------------------------------------------------------------*-------------------------------- 191 // 192 // (Note the dots represent the newly inferred start. 193 // Determining the new and old end is also pretty simple. Basically it boils down to paying attention to the 194 // absolute positions at the asterisks, and the relative change between the dollar signs. Basically, we see 195 // which if the two $'s precedes the other, and we move that one forward until they line up. in this case that 196 // means: 197 // 198 // 0 10 20 30 40 50 60 70 80 90 100 199 // --------------------------------------------------------------------------------*---------------------- 200 // | / 201 // | /---- 202 // T1 | /---- 203 // | /---- 204 // | /---- 205 // ------------------------------------------------------------$------------------------------------------ 206 // . | \ 207 // . | \ 208 // T2 . | \ 209 // . | \ 210 // . | \ 211 // ----------------------------------------------------------------------*-------------------------------- 212 // 213 // In other words (in this case), we're recognizing that the second edit happened after where the first edit 214 // ended with a delta of 20 characters (60 - 40). Thus, if we go back in time to where the first edit started 215 // that's the same as if we started at char 80 instead of 60. 216 // 217 // As it so happens, the same logic applies if the second edit precedes the first edit. In that case rather 218 // than pushing the first edit forward to match the second, we'll push the second edit forward to match the 219 // first. 220 // 221 // In this case that means we have { oldStart: 10, oldEnd: 80, newEnd: 70 } or, in TextChangeRange 222 // semantics: { { start: 10, length: 70 }, newLength: 60 } 223 // 224 // The math then works out as follows. 225 // If we have { oldStart1, oldEnd1, newEnd1 } and { oldStart2, oldEnd2, newEnd2 } then we can compute the 226 // final result like so: 227 // 228 // { 229 // oldStart3: Min(oldStart1, oldStart2), 230 // oldEnd3: Max(oldEnd1, oldEnd1 + (oldEnd2 - newEnd1)), 231 // newEnd3: Max(newEnd2, newEnd2 + (newEnd1 - oldEnd2)) 232 // } 233 234 const oldStart1 = oldStartN; 235 const oldEnd1 = oldEndN; 236 const newEnd1 = newEndN; 237 238 const oldStart2 = nextChange.span.start; 239 const oldEnd2 = textSpanEnd(nextChange.span); 240 const newEnd2 = oldStart2 + nextChange.newLength; 241 242 oldStartN = Math.min(oldStart1, oldStart2); 243 oldEndN = Math.max(oldEnd1, oldEnd1 + (oldEnd2 - newEnd1)); 244 newEndN = Math.max(newEnd2, newEnd2 + (newEnd1 - oldEnd2)); 245 } 246 247 return createTextChangeRange(createTextSpanFromBounds(oldStartN, oldEndN), /*newLength*/ newEndN - oldStartN); 248 } 249 250 export function getTypeParameterOwner(d: Declaration): Declaration | undefined { 251 if (d && d.kind === SyntaxKind.TypeParameter) { 252 for (let current: Node = d; current; current = current.parent) { 253 if (isFunctionLike(current) || isClassLike(current) || current.kind === SyntaxKind.InterfaceDeclaration) { 254 return current as Declaration; 255 } 256 } 257 } 258 } 259 260 export type ParameterPropertyDeclaration = ParameterDeclaration & { parent: ConstructorDeclaration, name: Identifier }; 261 export function isParameterPropertyDeclaration(node: Node, parent: Node): node is ParameterPropertyDeclaration { 262 return hasSyntacticModifier(node, ModifierFlags.ParameterPropertyModifier) && parent.kind === SyntaxKind.Constructor; 263 } 264 265 export function isEmptyBindingPattern(node: BindingName): node is BindingPattern { 266 if (isBindingPattern(node)) { 267 return every(node.elements, isEmptyBindingElement); 268 } 269 return false; 270 } 271 272 export function isEmptyBindingElement(node: BindingElement): boolean { 273 if (isOmittedExpression(node)) { 274 return true; 275 } 276 return isEmptyBindingPattern(node.name); 277 } 278 279 export function walkUpBindingElementsAndPatterns(binding: BindingElement): VariableDeclaration | ParameterDeclaration { 280 let node = binding.parent; 281 while (isBindingElement(node.parent)) { 282 node = node.parent.parent; 283 } 284 return node.parent; 285 } 286 287 function getCombinedFlags(node: Node, getFlags: (n: Node) => number): number { 288 if (isBindingElement(node)) { 289 node = walkUpBindingElementsAndPatterns(node); 290 } 291 let flags = getFlags(node); 292 if (node.kind === SyntaxKind.VariableDeclaration) { 293 node = node.parent; 294 } 295 if (node && node.kind === SyntaxKind.VariableDeclarationList) { 296 flags |= getFlags(node); 297 node = node.parent; 298 } 299 if (node && node.kind === SyntaxKind.VariableStatement) { 300 flags |= getFlags(node); 301 } 302 return flags; 303 } 304 305 export function getCombinedModifierFlags(node: Declaration): ModifierFlags { 306 return getCombinedFlags(node, getEffectiveModifierFlags); 307 } 308 309 /* @internal */ 310 export function getCombinedNodeFlagsAlwaysIncludeJSDoc(node: Declaration): ModifierFlags { 311 return getCombinedFlags(node, getEffectiveModifierFlagsAlwaysIncludeJSDoc); 312 } 313 314 // Returns the node flags for this node and all relevant parent nodes. This is done so that 315 // nodes like variable declarations and binding elements can returned a view of their flags 316 // that includes the modifiers from their container. i.e. flags like export/declare aren't 317 // stored on the variable declaration directly, but on the containing variable statement 318 // (if it has one). Similarly, flags for let/const are stored on the variable declaration 319 // list. By calling this function, all those flags are combined so that the client can treat 320 // the node as if it actually had those flags. 321 export function getCombinedNodeFlags(node: Node): NodeFlags { 322 return getCombinedFlags(node, n => n.flags); 323 } 324 325 /* @internal */ 326 export const supportedLocaleDirectories = ["cs", "de", "es", "fr", "it", "ja", "ko", "pl", "pt-br", "ru", "tr", "zh-cn", "zh-tw"]; 327 328 /** 329 * Checks to see if the locale is in the appropriate format, 330 * and if it is, attempts to set the appropriate language. 331 */ 332 export function validateLocaleAndSetLanguage( 333 locale: string, 334 sys: { getExecutingFilePath(): string, resolvePath(path: string): string, fileExists(fileName: string): boolean, readFile(fileName: string): string | undefined }, 335 errors?: Push<Diagnostic>) { 336 const lowerCaseLocale = locale.toLowerCase(); 337 const matchResult = /^([a-z]+)([_\-]([a-z]+))?$/.exec(lowerCaseLocale); 338 339 if (!matchResult) { 340 if (errors) { 341 errors.push(createCompilerDiagnostic(Diagnostics.Locale_must_be_of_the_form_language_or_language_territory_For_example_0_or_1, "en", "ja-jp")); 342 } 343 return; 344 } 345 346 const language = matchResult[1]; 347 const territory = matchResult[3]; 348 349 // First try the entire locale, then fall back to just language if that's all we have. 350 // Either ways do not fail, and fallback to the English diagnostic strings. 351 if (contains(supportedLocaleDirectories, lowerCaseLocale) && !trySetLanguageAndTerritory(language, territory, errors)) { 352 trySetLanguageAndTerritory(language, /*territory*/ undefined, errors); 353 } 354 355 // Set the UI locale for string collation 356 setUILocale(locale); 357 358 function trySetLanguageAndTerritory(language: string, territory: string | undefined, errors?: Push<Diagnostic>): boolean { 359 const compilerFilePath = normalizePath(sys.getExecutingFilePath()); 360 const containingDirectoryPath = getDirectoryPath(compilerFilePath); 361 362 let filePath = combinePaths(containingDirectoryPath, language); 363 364 if (territory) { 365 filePath = filePath + "-" + territory; 366 } 367 368 filePath = sys.resolvePath(combinePaths(filePath, "diagnosticMessages.generated.json")); 369 370 if (!sys.fileExists(filePath)) { 371 return false; 372 } 373 374 // TODO: Add codePage support for readFile? 375 let fileContents: string | undefined = ""; 376 try { 377 fileContents = sys.readFile(filePath); 378 } 379 catch (e) { 380 if (errors) { 381 errors.push(createCompilerDiagnostic(Diagnostics.Unable_to_open_file_0, filePath)); 382 } 383 return false; 384 } 385 try { 386 // this is a global mutation (or live binding update)! 387 setLocalizedDiagnosticMessages(JSON.parse(fileContents!)); 388 } 389 catch { 390 if (errors) { 391 errors.push(createCompilerDiagnostic(Diagnostics.Corrupted_locale_file_0, filePath)); 392 } 393 return false; 394 } 395 396 return true; 397 } 398 } 399 400 export function getOriginalNode(node: Node): Node; 401 export function getOriginalNode<T extends Node>(node: Node, nodeTest: (node: Node) => node is T): T; 402 export function getOriginalNode(node: Node | undefined): Node | undefined; 403 export function getOriginalNode<T extends Node>(node: Node | undefined, nodeTest: (node: Node | undefined) => node is T): T | undefined; 404 export function getOriginalNode(node: Node | undefined, nodeTest?: (node: Node | undefined) => boolean): Node | undefined { 405 if (node) { 406 while (node.original !== undefined) { 407 node = node.original; 408 } 409 } 410 411 return !nodeTest || nodeTest(node) ? node : undefined; 412 } 413 414 /** 415 * Iterates through the parent chain of a node and performs the callback on each parent until the callback 416 * returns a truthy value, then returns that value. 417 * If no such value is found, it applies the callback until the parent pointer is undefined or the callback returns "quit" 418 * At that point findAncestor returns undefined. 419 */ 420 export function findAncestor<T extends Node>(node: Node | undefined, callback: (element: Node) => element is T): T | undefined; 421 export function findAncestor(node: Node | undefined, callback: (element: Node) => boolean | "quit"): Node | undefined; 422 export function findAncestor(node: Node, callback: (element: Node) => boolean | "quit"): Node | undefined { 423 while (node) { 424 const result = callback(node); 425 if (result === "quit") { 426 return undefined; 427 } 428 else if (result) { 429 return node; 430 } 431 node = node.parent; 432 } 433 return undefined; 434 } 435 436 /** 437 * Gets a value indicating whether a node originated in the parse tree. 438 * 439 * @param node The node to test. 440 */ 441 export function isParseTreeNode(node: Node): boolean { 442 return (node.flags & NodeFlags.Synthesized) === 0; 443 } 444 445 /** 446 * Gets the original parse tree node for a node. 447 * 448 * @param node The original node. 449 * @returns The original parse tree node if found; otherwise, undefined. 450 */ 451 export function getParseTreeNode(node: Node | undefined): Node | undefined; 452 453 /** 454 * Gets the original parse tree node for a node. 455 * 456 * @param node The original node. 457 * @param nodeTest A callback used to ensure the correct type of parse tree node is returned. 458 * @returns The original parse tree node if found; otherwise, undefined. 459 */ 460 export function getParseTreeNode<T extends Node>(node: T | undefined, nodeTest?: (node: Node) => node is T): T | undefined; 461 export function getParseTreeNode(node: Node | undefined, nodeTest?: (node: Node) => boolean): Node | undefined { 462 if (node === undefined || isParseTreeNode(node)) { 463 return node; 464 } 465 466 node = node.original; 467 while (node) { 468 if (isParseTreeNode(node)) { 469 return !nodeTest || nodeTest(node) ? node : undefined; 470 } 471 node = node.original; 472 } 473 } 474 475 /** Add an extra underscore to identifiers that start with two underscores to avoid issues with magic names like '__proto__' */ 476 export function escapeLeadingUnderscores(identifier: string): __String { 477 return (identifier.length >= 2 && identifier.charCodeAt(0) === CharacterCodes._ && identifier.charCodeAt(1) === CharacterCodes._ ? "_" + identifier : identifier) as __String; 478 } 479 480 /** 481 * Remove extra underscore from escaped identifier text content. 482 * 483 * @param identifier The escaped identifier text. 484 * @returns The unescaped identifier text. 485 */ 486 export function unescapeLeadingUnderscores(identifier: __String): string { 487 const id = identifier as string; 488 return id.length >= 3 && id.charCodeAt(0) === CharacterCodes._ && id.charCodeAt(1) === CharacterCodes._ && id.charCodeAt(2) === CharacterCodes._ ? id.substr(1) : id; 489 } 490 491 export function idText(identifierOrPrivateName: Identifier | PrivateIdentifier): string { 492 return unescapeLeadingUnderscores(identifierOrPrivateName.escapedText); 493 } 494 export function symbolName(symbol: Symbol): string { 495 if (symbol.valueDeclaration && isPrivateIdentifierClassElementDeclaration(symbol.valueDeclaration)) { 496 return idText(symbol.valueDeclaration.name); 497 } 498 return unescapeLeadingUnderscores(symbol.escapedName); 499 } 500 501 /** 502 * A JSDocTypedef tag has an _optional_ name field - if a name is not directly present, we should 503 * attempt to draw the name from the node the declaration is on (as that declaration is what its' symbol 504 * will be merged with) 505 */ 506 function nameForNamelessJSDocTypedef(declaration: JSDocTypedefTag | JSDocEnumTag): Identifier | PrivateIdentifier | undefined { 507 const hostNode = declaration.parent.parent; 508 if (!hostNode) { 509 return undefined; 510 } 511 // Covers classes, functions - any named declaration host node 512 if (isDeclaration(hostNode)) { 513 return getDeclarationIdentifier(hostNode); 514 } 515 // Covers remaining cases (returning undefined if none match). 516 switch (hostNode.kind) { 517 case SyntaxKind.VariableStatement: 518 if (hostNode.declarationList && hostNode.declarationList.declarations[0]) { 519 return getDeclarationIdentifier(hostNode.declarationList.declarations[0]); 520 } 521 break; 522 case SyntaxKind.ExpressionStatement: 523 let expr = hostNode.expression; 524 if (expr.kind === SyntaxKind.BinaryExpression && (expr as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken) { 525 expr = (expr as BinaryExpression).left; 526 } 527 switch (expr.kind) { 528 case SyntaxKind.PropertyAccessExpression: 529 return (expr as PropertyAccessExpression).name; 530 case SyntaxKind.ElementAccessExpression: 531 const arg = (expr as ElementAccessExpression).argumentExpression; 532 if (isIdentifier(arg)) { 533 return arg; 534 } 535 } 536 break; 537 case SyntaxKind.ParenthesizedExpression: { 538 return getDeclarationIdentifier(hostNode.expression); 539 } 540 case SyntaxKind.LabeledStatement: { 541 if (isDeclaration(hostNode.statement) || isExpression(hostNode.statement)) { 542 return getDeclarationIdentifier(hostNode.statement); 543 } 544 break; 545 } 546 } 547 } 548 549 function getDeclarationIdentifier(node: Declaration | Expression): Identifier | undefined { 550 const name = getNameOfDeclaration(node); 551 return name && isIdentifier(name) ? name : undefined; 552 } 553 554 /** @internal */ 555 export function nodeHasName(statement: Node, name: Identifier) { 556 if (isNamedDeclaration(statement) && isIdentifier(statement.name) && idText(statement.name as Identifier) === idText(name)) { 557 return true; 558 } 559 if (isVariableStatement(statement) && some(statement.declarationList.declarations, d => nodeHasName(d, name))) { 560 return true; 561 } 562 return false; 563 } 564 565 export function getNameOfJSDocTypedef(declaration: JSDocTypedefTag): Identifier | PrivateIdentifier | undefined { 566 return declaration.name || nameForNamelessJSDocTypedef(declaration); 567 } 568 569 /** @internal */ 570 export function isNamedDeclaration(node: Node): node is NamedDeclaration & { name: DeclarationName } { 571 return !!(node as NamedDeclaration).name; // A 'name' property should always be a DeclarationName. 572 } 573 574 /** @internal */ 575 export function getNonAssignedNameOfDeclaration(declaration: Declaration | Expression): DeclarationName | undefined { 576 switch (declaration.kind) { 577 case SyntaxKind.Identifier: 578 return declaration as Identifier; 579 case SyntaxKind.JSDocPropertyTag: 580 case SyntaxKind.JSDocParameterTag: { 581 const { name } = declaration as JSDocPropertyLikeTag; 582 if (name.kind === SyntaxKind.QualifiedName) { 583 return name.right; 584 } 585 break; 586 } 587 case SyntaxKind.CallExpression: 588 case SyntaxKind.BinaryExpression: { 589 const expr = declaration as BinaryExpression | CallExpression; 590 switch (getAssignmentDeclarationKind(expr)) { 591 case AssignmentDeclarationKind.ExportsProperty: 592 case AssignmentDeclarationKind.ThisProperty: 593 case AssignmentDeclarationKind.Property: 594 case AssignmentDeclarationKind.PrototypeProperty: 595 return getElementOrPropertyAccessArgumentExpressionOrName((expr as BinaryExpression).left as AccessExpression); 596 case AssignmentDeclarationKind.ObjectDefinePropertyValue: 597 case AssignmentDeclarationKind.ObjectDefinePropertyExports: 598 case AssignmentDeclarationKind.ObjectDefinePrototypeProperty: 599 return (expr as BindableObjectDefinePropertyCall).arguments[1]; 600 default: 601 return undefined; 602 } 603 } 604 case SyntaxKind.JSDocTypedefTag: 605 return getNameOfJSDocTypedef(declaration as JSDocTypedefTag); 606 case SyntaxKind.JSDocEnumTag: 607 return nameForNamelessJSDocTypedef(declaration as JSDocEnumTag); 608 case SyntaxKind.ExportAssignment: { 609 const { expression } = declaration as ExportAssignment; 610 return isIdentifier(expression) ? expression : undefined; 611 } 612 case SyntaxKind.ElementAccessExpression: 613 const expr = declaration as ElementAccessExpression; 614 if (isBindableStaticElementAccessExpression(expr)) { 615 return expr.argumentExpression; 616 } 617 } 618 return (declaration as NamedDeclaration).name; 619 } 620 621 export function getNameOfDeclaration(declaration: Declaration | Expression | undefined): DeclarationName | undefined { 622 if (declaration === undefined) return undefined; 623 return getNonAssignedNameOfDeclaration(declaration) || 624 (isFunctionExpression(declaration) || isArrowFunction(declaration) || isClassExpression(declaration) ? getAssignedName(declaration) : undefined); 625 } 626 627 /*@internal*/ 628 export function getAssignedName(node: Node): DeclarationName | undefined { 629 if (!node.parent) { 630 return undefined; 631 } 632 else if (isPropertyAssignment(node.parent) || isBindingElement(node.parent)) { 633 return node.parent.name; 634 } 635 else if (isBinaryExpression(node.parent) && node === node.parent.right) { 636 if (isIdentifier(node.parent.left)) { 637 return node.parent.left; 638 } 639 else if (isAccessExpression(node.parent.left)) { 640 return getElementOrPropertyAccessArgumentExpressionOrName(node.parent.left); 641 } 642 } 643 else if (isVariableDeclaration(node.parent) && isIdentifier(node.parent.name)) { 644 return node.parent.name; 645 } 646 } 647 648 export function getDecorators(node: HasDecorators): readonly Decorator[] | undefined { 649 if (hasDecorators(node)) { 650 return filter(node.modifiers, isDecorator); 651 } 652 } 653 654 export function getModifiers(node: HasModifiers): readonly Modifier[] | undefined { 655 if (hasSyntacticModifier(node, ModifierFlags.Modifier)) { 656 return filter(node.modifiers, isModifier); 657 } 658 } 659 660 export function getAllDecorators(node: Node | undefined): readonly Decorator[] { 661 const allDecorators: Decorator[] = []; 662 if (!node) { 663 return allDecorators; 664 } 665 const decorators = getDecorators(node as HasDecorators); 666 if (decorators) { 667 allDecorators.push(...decorators); 668 } 669 const illegalDecorators = getIllegalDecorators(node as HasIllegalDecorators); 670 if (illegalDecorators) { 671 allDecorators.push(...illegalDecorators); 672 } 673 return allDecorators; 674 } 675 676 export function getIllegalDecorators(node: HasIllegalDecorators): readonly Decorator[] | undefined { 677 if (hasIllegalDecorators(node)) { 678 return node.illegalDecorators; 679 } 680 } 681 682 function getJSDocParameterTagsWorker(param: ParameterDeclaration, noCache?: boolean): readonly JSDocParameterTag[] { 683 if (param.name) { 684 if (isIdentifier(param.name)) { 685 const name = param.name.escapedText; 686 return getJSDocTagsWorker(param.parent, noCache).filter((tag): tag is JSDocParameterTag => isJSDocParameterTag(tag) && isIdentifier(tag.name) && tag.name.escapedText === name); 687 } 688 else { 689 const i = param.parent.parameters.indexOf(param); 690 Debug.assert(i > -1, "Parameters should always be in their parents' parameter list"); 691 const paramTags = getJSDocTagsWorker(param.parent, noCache).filter(isJSDocParameterTag); 692 if (i < paramTags.length) { 693 return [paramTags[i]]; 694 } 695 } 696 } 697 // return empty array for: out-of-order binding patterns and JSDoc function syntax, which has un-named parameters 698 return emptyArray; 699 } 700 701 /** 702 * Gets the JSDoc parameter tags for the node if present. 703 * 704 * @remarks Returns any JSDoc param tag whose name matches the provided 705 * parameter, whether a param tag on a containing function 706 * expression, or a param tag on a variable declaration whose 707 * initializer is the containing function. The tags closest to the 708 * node are returned first, so in the previous example, the param 709 * tag on the containing function expression would be first. 710 * 711 * For binding patterns, parameter tags are matched by position. 712 */ 713 export function getJSDocParameterTags(param: ParameterDeclaration): readonly JSDocParameterTag[] { 714 return getJSDocParameterTagsWorker(param, /*noCache*/ false); 715 } 716 717 /* @internal */ 718 export function getJSDocParameterTagsNoCache(param: ParameterDeclaration): readonly JSDocParameterTag[] { 719 return getJSDocParameterTagsWorker(param, /*noCache*/ true); 720 } 721 722 function getJSDocTypeParameterTagsWorker(param: TypeParameterDeclaration, noCache?: boolean): readonly JSDocTemplateTag[] { 723 const name = param.name.escapedText; 724 return getJSDocTagsWorker(param.parent, noCache).filter((tag): tag is JSDocTemplateTag => 725 isJSDocTemplateTag(tag) && tag.typeParameters.some(tp => tp.name.escapedText === name)); 726 } 727 728 /** 729 * Gets the JSDoc type parameter tags for the node if present. 730 * 731 * @remarks Returns any JSDoc template tag whose names match the provided 732 * parameter, whether a template tag on a containing function 733 * expression, or a template tag on a variable declaration whose 734 * initializer is the containing function. The tags closest to the 735 * node are returned first, so in the previous example, the template 736 * tag on the containing function expression would be first. 737 */ 738 export function getJSDocTypeParameterTags(param: TypeParameterDeclaration): readonly JSDocTemplateTag[] { 739 return getJSDocTypeParameterTagsWorker(param, /*noCache*/ false); 740 } 741 742 /* @internal */ 743 export function getJSDocTypeParameterTagsNoCache(param: TypeParameterDeclaration): readonly JSDocTemplateTag[] { 744 return getJSDocTypeParameterTagsWorker(param, /*noCache*/ true); 745 } 746 747 /** 748 * Return true if the node has JSDoc parameter tags. 749 * 750 * @remarks Includes parameter tags that are not directly on the node, 751 * for example on a variable declaration whose initializer is a function expression. 752 */ 753 export function hasJSDocParameterTags(node: FunctionLikeDeclaration | SignatureDeclaration): boolean { 754 return !!getFirstJSDocTag(node, isJSDocParameterTag); 755 } 756 757 /** Gets the JSDoc augments tag for the node if present */ 758 export function getJSDocAugmentsTag(node: Node): JSDocAugmentsTag | undefined { 759 return getFirstJSDocTag(node, isJSDocAugmentsTag); 760 } 761 762 /** Gets the JSDoc implements tags for the node if present */ 763 export function getJSDocImplementsTags(node: Node): readonly JSDocImplementsTag[] { 764 return getAllJSDocTags(node, isJSDocImplementsTag); 765 } 766 767 /** Gets the JSDoc class tag for the node if present */ 768 export function getJSDocClassTag(node: Node): JSDocClassTag | undefined { 769 return getFirstJSDocTag(node, isJSDocClassTag); 770 } 771 772 /** Gets the JSDoc public tag for the node if present */ 773 export function getJSDocPublicTag(node: Node): JSDocPublicTag | undefined { 774 return getFirstJSDocTag(node, isJSDocPublicTag); 775 } 776 777 /*@internal*/ 778 export function getJSDocPublicTagNoCache(node: Node): JSDocPublicTag | undefined { 779 return getFirstJSDocTag(node, isJSDocPublicTag, /*noCache*/ true); 780 } 781 782 /** Gets the JSDoc private tag for the node if present */ 783 export function getJSDocPrivateTag(node: Node): JSDocPrivateTag | undefined { 784 return getFirstJSDocTag(node, isJSDocPrivateTag); 785 } 786 787 /*@internal*/ 788 export function getJSDocPrivateTagNoCache(node: Node): JSDocPrivateTag | undefined { 789 return getFirstJSDocTag(node, isJSDocPrivateTag, /*noCache*/ true); 790 } 791 792 /** Gets the JSDoc protected tag for the node if present */ 793 export function getJSDocProtectedTag(node: Node): JSDocProtectedTag | undefined { 794 return getFirstJSDocTag(node, isJSDocProtectedTag); 795 } 796 797 /*@internal*/ 798 export function getJSDocProtectedTagNoCache(node: Node): JSDocProtectedTag | undefined { 799 return getFirstJSDocTag(node, isJSDocProtectedTag, /*noCache*/ true); 800 } 801 802 /** Gets the JSDoc protected tag for the node if present */ 803 export function getJSDocReadonlyTag(node: Node): JSDocReadonlyTag | undefined { 804 return getFirstJSDocTag(node, isJSDocReadonlyTag); 805 } 806 807 /*@internal*/ 808 export function getJSDocReadonlyTagNoCache(node: Node): JSDocReadonlyTag | undefined { 809 return getFirstJSDocTag(node, isJSDocReadonlyTag, /*noCache*/ true); 810 } 811 812 export function getJSDocOverrideTagNoCache(node: Node): JSDocOverrideTag | undefined { 813 return getFirstJSDocTag(node, isJSDocOverrideTag, /*noCache*/ true); 814 } 815 816 /** Gets the JSDoc deprecated tag for the node if present */ 817 export function getJSDocDeprecatedTag(node: Node): JSDocDeprecatedTag | undefined { 818 return getFirstJSDocTag(node, isJSDocDeprecatedTag); 819 } 820 821 /*@internal */ 822 export function getJSDocDeprecatedTagNoCache(node: Node): JSDocDeprecatedTag | undefined { 823 return getFirstJSDocTag(node, isJSDocDeprecatedTag, /*noCache*/ true); 824 } 825 826 /** Gets the JSDoc enum tag for the node if present */ 827 export function getJSDocEnumTag(node: Node): JSDocEnumTag | undefined { 828 return getFirstJSDocTag(node, isJSDocEnumTag); 829 } 830 831 /** Gets the JSDoc this tag for the node if present */ 832 export function getJSDocThisTag(node: Node): JSDocThisTag | undefined { 833 return getFirstJSDocTag(node, isJSDocThisTag); 834 } 835 836 /** Gets the JSDoc return tag for the node if present */ 837 export function getJSDocReturnTag(node: Node): JSDocReturnTag | undefined { 838 return getFirstJSDocTag(node, isJSDocReturnTag); 839 } 840 841 /** Gets the JSDoc template tag for the node if present */ 842 export function getJSDocTemplateTag(node: Node): JSDocTemplateTag | undefined { 843 return getFirstJSDocTag(node, isJSDocTemplateTag); 844 } 845 846 /** Gets the JSDoc type tag for the node if present and valid */ 847 export function getJSDocTypeTag(node: Node): JSDocTypeTag | undefined { 848 // We should have already issued an error if there were multiple type jsdocs, so just use the first one. 849 const tag = getFirstJSDocTag(node, isJSDocTypeTag); 850 if (tag && tag.typeExpression && tag.typeExpression.type) { 851 return tag; 852 } 853 return undefined; 854 } 855 856 /** 857 * Gets the type node for the node if provided via JSDoc. 858 * 859 * @remarks The search includes any JSDoc param tag that relates 860 * to the provided parameter, for example a type tag on the 861 * parameter itself, or a param tag on a containing function 862 * expression, or a param tag on a variable declaration whose 863 * initializer is the containing function. The tags closest to the 864 * node are examined first, so in the previous example, the type 865 * tag directly on the node would be returned. 866 */ 867 export function getJSDocType(node: Node): TypeNode | undefined { 868 let tag: JSDocTypeTag | JSDocParameterTag | undefined = getFirstJSDocTag(node, isJSDocTypeTag); 869 if (!tag && isParameter(node)) { 870 tag = find(getJSDocParameterTags(node), tag => !!tag.typeExpression); 871 } 872 873 return tag && tag.typeExpression && tag.typeExpression.type; 874 } 875 876 /** 877 * Gets the return type node for the node if provided via JSDoc return tag or type tag. 878 * 879 * @remarks `getJSDocReturnTag` just gets the whole JSDoc tag. This function 880 * gets the type from inside the braces, after the fat arrow, etc. 881 */ 882 export function getJSDocReturnType(node: Node): TypeNode | undefined { 883 const returnTag = getJSDocReturnTag(node); 884 if (returnTag && returnTag.typeExpression) { 885 return returnTag.typeExpression.type; 886 } 887 const typeTag = getJSDocTypeTag(node); 888 if (typeTag && typeTag.typeExpression) { 889 const type = typeTag.typeExpression.type; 890 if (isTypeLiteralNode(type)) { 891 const sig = find(type.members, isCallSignatureDeclaration); 892 return sig && sig.type; 893 } 894 if (isFunctionTypeNode(type) || isJSDocFunctionType(type)) { 895 return type.type; 896 } 897 } 898 } 899 900 function getJSDocTagsWorker(node: Node, noCache?: boolean): readonly JSDocTag[] { 901 let tags = (node as JSDocContainer).jsDocCache; 902 // If cache is 'null', that means we did the work of searching for JSDoc tags and came up with nothing. 903 if (tags === undefined || noCache) { 904 const comments = getJSDocCommentsAndTags(node, noCache); 905 Debug.assert(comments.length < 2 || comments[0] !== comments[1]); 906 tags = flatMap(comments, j => isJSDoc(j) ? j.tags : j); 907 if (!noCache) { 908 (node as JSDocContainer).jsDocCache = tags; 909 } 910 } 911 return tags; 912 } 913 914 /** Get all JSDoc tags related to a node, including those on parent nodes. */ 915 export function getJSDocTags(node: Node): readonly JSDocTag[] { 916 return getJSDocTagsWorker(node, /*noCache*/ false); 917 } 918 919 /* @internal */ 920 export function getJSDocTagsNoCache(node: Node): readonly JSDocTag[] { 921 return getJSDocTagsWorker(node, /*noCache*/ true); 922 } 923 924 /** Get the first JSDoc tag of a specified kind, or undefined if not present. */ 925 function getFirstJSDocTag<T extends JSDocTag>(node: Node, predicate: (tag: JSDocTag) => tag is T, noCache?: boolean): T | undefined { 926 return find(getJSDocTagsWorker(node, noCache), predicate); 927 } 928 929 /** Gets all JSDoc tags that match a specified predicate */ 930 export function getAllJSDocTags<T extends JSDocTag>(node: Node, predicate: (tag: JSDocTag) => tag is T): readonly T[] { 931 return getJSDocTags(node).filter(predicate); 932 } 933 934 /** Gets all JSDoc tags of a specified kind */ 935 export function getAllJSDocTagsOfKind(node: Node, kind: SyntaxKind): readonly JSDocTag[] { 936 return getJSDocTags(node).filter(doc => doc.kind === kind); 937 } 938 939 /** Gets the text of a jsdoc comment, flattening links to their text. */ 940 export function getTextOfJSDocComment(comment?: string | NodeArray<JSDocComment>) { 941 return typeof comment === "string" ? comment 942 : comment?.map(c => c.kind === SyntaxKind.JSDocText ? c.text : formatJSDocLink(c)).join(""); 943 } 944 945 function formatJSDocLink(link: JSDocLink | JSDocLinkCode | JSDocLinkPlain) { 946 const kind = link.kind === SyntaxKind.JSDocLink ? "link" 947 : link.kind === SyntaxKind.JSDocLinkCode ? "linkcode" 948 : "linkplain"; 949 const name = link.name ? entityNameToString(link.name) : ""; 950 const space = link.name && link.text.startsWith("://") ? "" : " "; 951 return `{@${kind} ${name}${space}${link.text}}`; 952 } 953 954 /** 955 * Gets the effective type parameters. If the node was parsed in a 956 * JavaScript file, gets the type parameters from the `@template` tag from JSDoc. 957 * 958 * This does *not* return type parameters from a jsdoc reference to a generic type, eg 959 * 960 * type Id = <T>(x: T) => T 961 * /** @type {Id} / 962 * function id(x) { return x } 963 */ 964 export function getEffectiveTypeParameterDeclarations(node: DeclarationWithTypeParameters): readonly TypeParameterDeclaration[] { 965 if (isJSDocSignature(node)) { 966 return emptyArray; 967 } 968 if (isJSDocTypeAlias(node)) { 969 Debug.assert(node.parent.kind === SyntaxKind.JSDoc); 970 return flatMap(node.parent.tags, tag => isJSDocTemplateTag(tag) ? tag.typeParameters : undefined); 971 } 972 if (node.typeParameters) { 973 return node.typeParameters; 974 } 975 if (canHaveIllegalTypeParameters(node) && node.typeParameters) { 976 return node.typeParameters; 977 } 978 if (isInJSFile(node)) { 979 const decls = getJSDocTypeParameterDeclarations(node); 980 if (decls.length) { 981 return decls; 982 } 983 const typeTag = getJSDocType(node); 984 if (typeTag && isFunctionTypeNode(typeTag) && typeTag.typeParameters) { 985 return typeTag.typeParameters; 986 } 987 } 988 return emptyArray; 989 } 990 991 export function getEffectiveConstraintOfTypeParameter(node: TypeParameterDeclaration): TypeNode | undefined { 992 return node.constraint ? node.constraint : 993 isJSDocTemplateTag(node.parent) && node === node.parent.typeParameters[0] ? node.parent.constraint : 994 undefined; 995 } 996 997 // #region 998 999 export function isMemberName(node: Node): node is MemberName { 1000 return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.PrivateIdentifier; 1001 } 1002 1003 /* @internal */ 1004 export function isGetOrSetAccessorDeclaration(node: Node): node is AccessorDeclaration { 1005 return node.kind === SyntaxKind.SetAccessor || node.kind === SyntaxKind.GetAccessor; 1006 } 1007 1008 export function isPropertyAccessChain(node: Node): node is PropertyAccessChain { 1009 return isPropertyAccessExpression(node) && !!(node.flags & NodeFlags.OptionalChain); 1010 } 1011 1012 export function isElementAccessChain(node: Node): node is ElementAccessChain { 1013 return isElementAccessExpression(node) && !!(node.flags & NodeFlags.OptionalChain); 1014 } 1015 1016 export function isCallChain(node: Node): node is CallChain { 1017 return isCallExpression(node) && !!(node.flags & NodeFlags.OptionalChain); 1018 } 1019 1020 export function isOptionalChain(node: Node): node is PropertyAccessChain | ElementAccessChain | CallChain | NonNullChain { 1021 const kind = node.kind; 1022 return !!(node.flags & NodeFlags.OptionalChain) && 1023 (kind === SyntaxKind.PropertyAccessExpression 1024 || kind === SyntaxKind.ElementAccessExpression 1025 || kind === SyntaxKind.CallExpression 1026 || kind === SyntaxKind.NonNullExpression); 1027 } 1028 1029 /* @internal */ 1030 export function isOptionalChainRoot(node: Node): node is OptionalChainRoot { 1031 return isOptionalChain(node) && !isNonNullExpression(node) && !!node.questionDotToken; 1032 } 1033 1034 /** 1035 * Determines whether a node is the expression preceding an optional chain (i.e. `a` in `a?.b`). 1036 */ 1037 /* @internal */ 1038 export function isExpressionOfOptionalChainRoot(node: Node): node is Expression & { parent: OptionalChainRoot } { 1039 return isOptionalChainRoot(node.parent) && node.parent.expression === node; 1040 } 1041 1042 /** 1043 * Determines whether a node is the outermost `OptionalChain` in an ECMAScript `OptionalExpression`: 1044 * 1045 * 1. For `a?.b.c`, the outermost chain is `a?.b.c` (`c` is the end of the chain starting at `a?.`) 1046 * 2. For `a?.b!`, the outermost chain is `a?.b` (`b` is the end of the chain starting at `a?.`) 1047 * 3. For `(a?.b.c).d`, the outermost chain is `a?.b.c` (`c` is the end of the chain starting at `a?.` since parens end the chain) 1048 * 4. For `a?.b.c?.d`, both `a?.b.c` and `a?.b.c?.d` are outermost (`c` is the end of the chain starting at `a?.`, and `d` is 1049 * the end of the chain starting at `c?.`) 1050 * 5. For `a?.(b?.c).d`, both `b?.c` and `a?.(b?.c)d` are outermost (`c` is the end of the chain starting at `b`, and `d` is 1051 * the end of the chain starting at `a?.`) 1052 */ 1053 /* @internal */ 1054 export function isOutermostOptionalChain(node: OptionalChain) { 1055 return !isOptionalChain(node.parent) // cases 1, 2, and 3 1056 || isOptionalChainRoot(node.parent) // case 4 1057 || node !== node.parent.expression; // case 5 1058 } 1059 1060 export function isNullishCoalesce(node: Node) { 1061 return node.kind === SyntaxKind.BinaryExpression && (node as BinaryExpression).operatorToken.kind === SyntaxKind.QuestionQuestionToken; 1062 } 1063 1064 export function isConstTypeReference(node: Node) { 1065 return isTypeReferenceNode(node) && isIdentifier(node.typeName) && 1066 node.typeName.escapedText === "const" && !node.typeArguments; 1067 } 1068 1069 export function skipPartiallyEmittedExpressions(node: Expression): Expression; 1070 export function skipPartiallyEmittedExpressions(node: Node): Node; 1071 export function skipPartiallyEmittedExpressions(node: Node) { 1072 return skipOuterExpressions(node, OuterExpressionKinds.PartiallyEmittedExpressions); 1073 } 1074 1075 export function isNonNullChain(node: Node): node is NonNullChain { 1076 return isNonNullExpression(node) && !!(node.flags & NodeFlags.OptionalChain); 1077 } 1078 1079 export function isBreakOrContinueStatement(node: Node): node is BreakOrContinueStatement { 1080 return node.kind === SyntaxKind.BreakStatement || node.kind === SyntaxKind.ContinueStatement; 1081 } 1082 1083 export function isNamedExportBindings(node: Node): node is NamedExportBindings { 1084 return node.kind === SyntaxKind.NamespaceExport || node.kind === SyntaxKind.NamedExports; 1085 } 1086 1087 export function isUnparsedTextLike(node: Node): node is UnparsedTextLike { 1088 switch (node.kind) { 1089 case SyntaxKind.UnparsedText: 1090 case SyntaxKind.UnparsedInternalText: 1091 return true; 1092 default: 1093 return false; 1094 } 1095 } 1096 1097 export function isUnparsedNode(node: Node): node is UnparsedNode { 1098 return isUnparsedTextLike(node) || 1099 node.kind === SyntaxKind.UnparsedPrologue || 1100 node.kind === SyntaxKind.UnparsedSyntheticReference; 1101 } 1102 1103 export function isJSDocPropertyLikeTag(node: Node): node is JSDocPropertyLikeTag { 1104 return node.kind === SyntaxKind.JSDocPropertyTag || node.kind === SyntaxKind.JSDocParameterTag; 1105 } 1106 1107 // #endregion 1108 1109 // #region 1110 // Node tests 1111 // 1112 // All node tests in the following list should *not* reference parent pointers so that 1113 // they may be used with transformations. 1114 /* @internal */ 1115 export function isNode(node: Node) { 1116 return isNodeKind(node.kind); 1117 } 1118 1119 /* @internal */ 1120 export function isNodeKind(kind: SyntaxKind) { 1121 return kind >= SyntaxKind.FirstNode; 1122 } 1123 1124 /** 1125 * True if kind is of some token syntax kind. 1126 * For example, this is true for an IfKeyword but not for an IfStatement. 1127 * Literals are considered tokens, except TemplateLiteral, but does include TemplateHead/Middle/Tail. 1128 */ 1129 export function isTokenKind(kind: SyntaxKind): boolean { 1130 return kind >= SyntaxKind.FirstToken && kind <= SyntaxKind.LastToken; 1131 } 1132 1133 /** 1134 * True if node is of some token syntax kind. 1135 * For example, this is true for an IfKeyword but not for an IfStatement. 1136 * Literals are considered tokens, except TemplateLiteral, but does include TemplateHead/Middle/Tail. 1137 */ 1138 export function isToken(n: Node): boolean { 1139 return isTokenKind(n.kind); 1140 } 1141 1142 // Node Arrays 1143 1144 /* @internal */ 1145 export function isNodeArray<T extends Node>(array: readonly T[]): array is NodeArray<T> { 1146 return hasProperty(array, "pos") && hasProperty(array, "end"); 1147 } 1148 1149 // Literals 1150 1151 /* @internal */ 1152 export function isLiteralKind(kind: SyntaxKind): kind is LiteralToken["kind"] { 1153 return SyntaxKind.FirstLiteralToken <= kind && kind <= SyntaxKind.LastLiteralToken; 1154 } 1155 1156 export function isLiteralExpression(node: Node): node is LiteralExpression { 1157 return isLiteralKind(node.kind); 1158 } 1159 1160 /** @internal */ 1161 export function isLiteralExpressionOfObject(node: Node) { 1162 switch (node.kind) { 1163 case SyntaxKind.ObjectLiteralExpression: 1164 case SyntaxKind.ArrayLiteralExpression: 1165 case SyntaxKind.RegularExpressionLiteral: 1166 case SyntaxKind.FunctionExpression: 1167 case SyntaxKind.ClassExpression: 1168 return true; 1169 } 1170 return false; 1171 } 1172 1173 // Pseudo-literals 1174 1175 /* @internal */ 1176 export function isTemplateLiteralKind(kind: SyntaxKind): kind is TemplateLiteralToken["kind"] { 1177 return SyntaxKind.FirstTemplateToken <= kind && kind <= SyntaxKind.LastTemplateToken; 1178 } 1179 1180 export function isTemplateLiteralToken(node: Node): node is TemplateLiteralToken { 1181 return isTemplateLiteralKind(node.kind); 1182 } 1183 1184 export function isTemplateMiddleOrTemplateTail(node: Node): node is TemplateMiddle | TemplateTail { 1185 const kind = node.kind; 1186 return kind === SyntaxKind.TemplateMiddle 1187 || kind === SyntaxKind.TemplateTail; 1188 } 1189 1190 export function isImportOrExportSpecifier(node: Node): node is ImportSpecifier | ExportSpecifier { 1191 return isImportSpecifier(node) || isExportSpecifier(node); 1192 } 1193 1194 export function isTypeOnlyImportOrExportDeclaration(node: Node): node is TypeOnlyAliasDeclaration { 1195 switch (node.kind) { 1196 case SyntaxKind.ImportSpecifier: 1197 case SyntaxKind.ExportSpecifier: 1198 return (node as ImportOrExportSpecifier).isTypeOnly || (node as ImportOrExportSpecifier).parent.parent.isTypeOnly; 1199 case SyntaxKind.NamespaceImport: 1200 return (node as NamespaceImport).parent.isTypeOnly; 1201 case SyntaxKind.ImportClause: 1202 case SyntaxKind.ImportEqualsDeclaration: 1203 return (node as ImportClause | ImportEqualsDeclaration).isTypeOnly; 1204 default: 1205 return false; 1206 } 1207 } 1208 1209 export function isAssertionKey(node: Node): node is AssertionKey { 1210 return isStringLiteral(node) || isIdentifier(node); 1211 } 1212 1213 export function isStringTextContainingNode(node: Node): node is StringLiteral | TemplateLiteralToken { 1214 return node.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(node.kind); 1215 } 1216 1217 // Identifiers 1218 1219 /* @internal */ 1220 export function isGeneratedIdentifier(node: Node): node is GeneratedIdentifier { 1221 return isIdentifier(node) && (node.autoGenerateFlags! & GeneratedIdentifierFlags.KindMask) > GeneratedIdentifierFlags.None; 1222 } 1223 1224 /* @internal */ 1225 export function isGeneratedPrivateIdentifier(node: Node): node is GeneratedPrivateIdentifier { 1226 return isPrivateIdentifier(node) && (node.autoGenerateFlags! & GeneratedIdentifierFlags.KindMask) > GeneratedIdentifierFlags.None; 1227 } 1228 1229 // Private Identifiers 1230 /*@internal*/ 1231 export function isPrivateIdentifierClassElementDeclaration(node: Node): node is PrivateClassElementDeclaration { 1232 return (isPropertyDeclaration(node) || isMethodOrAccessor(node)) && isPrivateIdentifier(node.name); 1233 } 1234 1235 /*@internal*/ 1236 export function isPrivateIdentifierPropertyAccessExpression(node: Node): node is PrivateIdentifierPropertyAccessExpression { 1237 return isPropertyAccessExpression(node) && isPrivateIdentifier(node.name); 1238 } 1239 1240 // Keywords 1241 1242 /* @internal */ 1243 export function isModifierKind(token: SyntaxKind): token is Modifier["kind"] { 1244 switch (token) { 1245 case SyntaxKind.AbstractKeyword: 1246 case SyntaxKind.AccessorKeyword: 1247 case SyntaxKind.AsyncKeyword: 1248 case SyntaxKind.ConstKeyword: 1249 case SyntaxKind.DeclareKeyword: 1250 case SyntaxKind.DefaultKeyword: 1251 case SyntaxKind.ExportKeyword: 1252 case SyntaxKind.InKeyword: 1253 case SyntaxKind.PublicKeyword: 1254 case SyntaxKind.PrivateKeyword: 1255 case SyntaxKind.ProtectedKeyword: 1256 case SyntaxKind.ReadonlyKeyword: 1257 case SyntaxKind.StaticKeyword: 1258 case SyntaxKind.OutKeyword: 1259 case SyntaxKind.OverrideKeyword: 1260 return true; 1261 } 1262 return false; 1263 } 1264 1265 /* @internal */ 1266 export function isParameterPropertyModifier(kind: SyntaxKind): boolean { 1267 return !!(modifierToFlag(kind) & ModifierFlags.ParameterPropertyModifier); 1268 } 1269 1270 /* @internal */ 1271 export function isClassMemberModifier(idToken: SyntaxKind): boolean { 1272 return isParameterPropertyModifier(idToken) || 1273 idToken === SyntaxKind.StaticKeyword || 1274 idToken === SyntaxKind.OverrideKeyword || 1275 idToken === SyntaxKind.AccessorKeyword; 1276 } 1277 1278 export function isModifier(node: Node): node is Modifier { 1279 return isModifierKind(node.kind); 1280 } 1281 1282 export function isEntityName(node: Node): node is EntityName { 1283 const kind = node.kind; 1284 return kind === SyntaxKind.QualifiedName 1285 || kind === SyntaxKind.Identifier; 1286 } 1287 1288 export function isPropertyName(node: Node): node is PropertyName { 1289 const kind = node.kind; 1290 return kind === SyntaxKind.Identifier 1291 || kind === SyntaxKind.PrivateIdentifier 1292 || kind === SyntaxKind.StringLiteral 1293 || kind === SyntaxKind.NumericLiteral 1294 || kind === SyntaxKind.ComputedPropertyName; 1295 } 1296 1297 export function isBindingName(node: Node): node is BindingName { 1298 const kind = node.kind; 1299 return kind === SyntaxKind.Identifier 1300 || kind === SyntaxKind.ObjectBindingPattern 1301 || kind === SyntaxKind.ArrayBindingPattern; 1302 } 1303 1304 // Functions 1305 1306 export function isFunctionLike(node: Node | undefined): node is SignatureDeclaration { 1307 return !!node && isFunctionLikeKind(node.kind); 1308 } 1309 1310 /* @internal */ 1311 export function isFunctionLikeOrClassStaticBlockDeclaration(node: Node | undefined): node is SignatureDeclaration | ClassStaticBlockDeclaration { 1312 return !!node && (isFunctionLikeKind(node.kind) || isClassStaticBlockDeclaration(node)); 1313 } 1314 1315 /* @internal */ 1316 export function isFunctionLikeDeclaration(node: Node): node is FunctionLikeDeclaration { 1317 return node && isFunctionLikeDeclarationKind(node.kind); 1318 } 1319 1320 /* @internal */ 1321 export function isBooleanLiteral(node: Node): node is BooleanLiteral { 1322 return node.kind === SyntaxKind.TrueKeyword || node.kind === SyntaxKind.FalseKeyword; 1323 } 1324 1325 function isFunctionLikeDeclarationKind(kind: SyntaxKind): boolean { 1326 switch (kind) { 1327 case SyntaxKind.FunctionDeclaration: 1328 case SyntaxKind.MethodDeclaration: 1329 case SyntaxKind.Constructor: 1330 case SyntaxKind.GetAccessor: 1331 case SyntaxKind.SetAccessor: 1332 case SyntaxKind.FunctionExpression: 1333 case SyntaxKind.ArrowFunction: 1334 return true; 1335 default: 1336 return false; 1337 } 1338 } 1339 1340 /* @internal */ 1341 export function isFunctionLikeKind(kind: SyntaxKind): boolean { 1342 switch (kind) { 1343 case SyntaxKind.MethodSignature: 1344 case SyntaxKind.CallSignature: 1345 case SyntaxKind.JSDocSignature: 1346 case SyntaxKind.ConstructSignature: 1347 case SyntaxKind.IndexSignature: 1348 case SyntaxKind.FunctionType: 1349 case SyntaxKind.JSDocFunctionType: 1350 case SyntaxKind.ConstructorType: 1351 return true; 1352 default: 1353 return isFunctionLikeDeclarationKind(kind); 1354 } 1355 } 1356 1357 /* @internal */ 1358 export function isFunctionOrModuleBlock(node: Node): boolean { 1359 return isSourceFile(node) || isModuleBlock(node) || isBlock(node) && isFunctionLike(node.parent); 1360 } 1361 1362 // Classes 1363 export function isClassElement(node: Node): node is ClassElement { 1364 const kind = node.kind; 1365 return kind === SyntaxKind.Constructor 1366 || kind === SyntaxKind.PropertyDeclaration 1367 || kind === SyntaxKind.MethodDeclaration 1368 || kind === SyntaxKind.GetAccessor 1369 || kind === SyntaxKind.SetAccessor 1370 || kind === SyntaxKind.IndexSignature 1371 || kind === SyntaxKind.ClassStaticBlockDeclaration 1372 || kind === SyntaxKind.SemicolonClassElement; 1373 } 1374 1375 export function isClassLike(node: Node): node is ClassLikeDeclaration { 1376 return node && (node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.ClassExpression || node.kind === SyntaxKind.StructDeclaration); 1377 } 1378 1379 export function isStruct(node: Node): node is StructDeclaration { 1380 return node && node.kind === SyntaxKind.StructDeclaration; 1381 } 1382 1383 export function isAccessor(node: Node): node is AccessorDeclaration { 1384 return node && (node.kind === SyntaxKind.GetAccessor || node.kind === SyntaxKind.SetAccessor); 1385 } 1386 1387 export function isAutoAccessorPropertyDeclaration(node: Node): node is AutoAccessorPropertyDeclaration { 1388 return isPropertyDeclaration(node) && hasAccessorModifier(node); 1389 } 1390 1391 /* @internal */ 1392 export function isMethodOrAccessor(node: Node): node is MethodDeclaration | AccessorDeclaration { 1393 switch (node.kind) { 1394 case SyntaxKind.MethodDeclaration: 1395 case SyntaxKind.GetAccessor: 1396 case SyntaxKind.SetAccessor: 1397 return true; 1398 default: 1399 return false; 1400 } 1401 } 1402 1403 /* @internal */ 1404 export function isNamedClassElement(node: Node): node is MethodDeclaration | AccessorDeclaration | PropertyDeclaration { 1405 switch (node.kind) { 1406 case SyntaxKind.MethodDeclaration: 1407 case SyntaxKind.GetAccessor: 1408 case SyntaxKind.SetAccessor: 1409 case SyntaxKind.PropertyDeclaration: 1410 return true; 1411 default: 1412 return false; 1413 } 1414 } 1415 1416 // Type members 1417 1418 export function isModifierLike(node: Node): node is ModifierLike { 1419 return isModifier(node) || isDecorator(node); 1420 } 1421 1422 export function isTypeElement(node: Node): node is TypeElement { 1423 const kind = node.kind; 1424 return kind === SyntaxKind.ConstructSignature 1425 || kind === SyntaxKind.CallSignature 1426 || kind === SyntaxKind.PropertySignature 1427 || kind === SyntaxKind.MethodSignature 1428 || kind === SyntaxKind.IndexSignature 1429 || kind === SyntaxKind.GetAccessor 1430 || kind === SyntaxKind.SetAccessor; 1431 } 1432 1433 export function isClassOrTypeElement(node: Node): node is ClassElement | TypeElement { 1434 return isTypeElement(node) || isClassElement(node); 1435 } 1436 1437 export function isObjectLiteralElementLike(node: Node): node is ObjectLiteralElementLike { 1438 const kind = node.kind; 1439 return kind === SyntaxKind.PropertyAssignment 1440 || kind === SyntaxKind.ShorthandPropertyAssignment 1441 || kind === SyntaxKind.SpreadAssignment 1442 || kind === SyntaxKind.MethodDeclaration 1443 || kind === SyntaxKind.GetAccessor 1444 || kind === SyntaxKind.SetAccessor; 1445 } 1446 1447 // Type 1448 1449 /** 1450 * Node test that determines whether a node is a valid type node. 1451 * This differs from the `isPartOfTypeNode` function which determines whether a node is *part* 1452 * of a TypeNode. 1453 */ 1454 export function isTypeNode(node: Node): node is TypeNode { 1455 return isTypeNodeKind(node.kind); 1456 } 1457 1458 export function isFunctionOrConstructorTypeNode(node: Node): node is FunctionTypeNode | ConstructorTypeNode { 1459 switch (node.kind) { 1460 case SyntaxKind.FunctionType: 1461 case SyntaxKind.ConstructorType: 1462 return true; 1463 } 1464 1465 return false; 1466 } 1467 1468 // Binding patterns 1469 1470 /* @internal */ 1471 export function isBindingPattern(node: Node | undefined): node is BindingPattern { 1472 if (node) { 1473 const kind = node.kind; 1474 return kind === SyntaxKind.ArrayBindingPattern 1475 || kind === SyntaxKind.ObjectBindingPattern; 1476 } 1477 1478 return false; 1479 } 1480 1481 /* @internal */ 1482 export function isAssignmentPattern(node: Node): node is AssignmentPattern { 1483 const kind = node.kind; 1484 return kind === SyntaxKind.ArrayLiteralExpression 1485 || kind === SyntaxKind.ObjectLiteralExpression; 1486 } 1487 1488 1489 /* @internal */ 1490 export function isArrayBindingElement(node: Node): node is ArrayBindingElement { 1491 const kind = node.kind; 1492 return kind === SyntaxKind.BindingElement 1493 || kind === SyntaxKind.OmittedExpression; 1494 } 1495 1496 1497 /** 1498 * Determines whether the BindingOrAssignmentElement is a BindingElement-like declaration 1499 */ 1500 /* @internal */ 1501 export function isDeclarationBindingElement(bindingElement: BindingOrAssignmentElement): bindingElement is VariableDeclaration | ParameterDeclaration | BindingElement { 1502 switch (bindingElement.kind) { 1503 case SyntaxKind.VariableDeclaration: 1504 case SyntaxKind.Parameter: 1505 case SyntaxKind.BindingElement: 1506 return true; 1507 } 1508 1509 return false; 1510 } 1511 1512 /** 1513 * Determines whether a node is a BindingOrAssignmentPattern 1514 */ 1515 /* @internal */ 1516 export function isBindingOrAssignmentPattern(node: BindingOrAssignmentElementTarget): node is BindingOrAssignmentPattern { 1517 return isObjectBindingOrAssignmentPattern(node) 1518 || isArrayBindingOrAssignmentPattern(node); 1519 } 1520 1521 /** 1522 * Determines whether a node is an ObjectBindingOrAssignmentPattern 1523 */ 1524 /* @internal */ 1525 export function isObjectBindingOrAssignmentPattern(node: BindingOrAssignmentElementTarget): node is ObjectBindingOrAssignmentPattern { 1526 switch (node.kind) { 1527 case SyntaxKind.ObjectBindingPattern: 1528 case SyntaxKind.ObjectLiteralExpression: 1529 return true; 1530 } 1531 1532 return false; 1533 } 1534 1535 /* @internal */ 1536 export function isObjectBindingOrAssignmentElement(node: Node): node is ObjectBindingOrAssignmentElement { 1537 switch (node.kind) { 1538 case SyntaxKind.BindingElement: 1539 case SyntaxKind.PropertyAssignment: // AssignmentProperty 1540 case SyntaxKind.ShorthandPropertyAssignment: // AssignmentProperty 1541 case SyntaxKind.SpreadAssignment: // AssignmentRestProperty 1542 return true; 1543 } 1544 return false; 1545 } 1546 1547 /** 1548 * Determines whether a node is an ArrayBindingOrAssignmentPattern 1549 */ 1550 /* @internal */ 1551 export function isArrayBindingOrAssignmentPattern(node: BindingOrAssignmentElementTarget): node is ArrayBindingOrAssignmentPattern { 1552 switch (node.kind) { 1553 case SyntaxKind.ArrayBindingPattern: 1554 case SyntaxKind.ArrayLiteralExpression: 1555 return true; 1556 } 1557 1558 return false; 1559 } 1560 1561 /* @internal */ 1562 export function isPropertyAccessOrQualifiedNameOrImportTypeNode(node: Node): node is PropertyAccessExpression | QualifiedName | ImportTypeNode { 1563 const kind = node.kind; 1564 return kind === SyntaxKind.PropertyAccessExpression 1565 || kind === SyntaxKind.QualifiedName 1566 || kind === SyntaxKind.ImportType; 1567 } 1568 1569 // Expression 1570 1571 export function isPropertyAccessOrQualifiedName(node: Node): node is PropertyAccessExpression | QualifiedName { 1572 const kind = node.kind; 1573 return kind === SyntaxKind.PropertyAccessExpression 1574 || kind === SyntaxKind.QualifiedName; 1575 } 1576 1577 export function isCallLikeExpression(node: Node): node is CallLikeExpression { 1578 switch (node.kind) { 1579 case SyntaxKind.JsxOpeningElement: 1580 case SyntaxKind.JsxSelfClosingElement: 1581 case SyntaxKind.CallExpression: 1582 case SyntaxKind.NewExpression: 1583 case SyntaxKind.TaggedTemplateExpression: 1584 case SyntaxKind.Decorator: 1585 case SyntaxKind.EtsComponentExpression: 1586 return true; 1587 default: 1588 return false; 1589 } 1590 } 1591 1592 export function isCallOrNewExpression(node: Node): node is CallExpression | NewExpression { 1593 return node.kind === SyntaxKind.CallExpression || node.kind === SyntaxKind.NewExpression; 1594 } 1595 1596 export function isTemplateLiteral(node: Node): node is TemplateLiteral { 1597 const kind = node.kind; 1598 return kind === SyntaxKind.TemplateExpression 1599 || kind === SyntaxKind.NoSubstitutionTemplateLiteral; 1600 } 1601 1602 /* @internal */ 1603 export function isLeftHandSideExpression(node: Node): node is LeftHandSideExpression { 1604 return isLeftHandSideExpressionKind(skipPartiallyEmittedExpressions(node).kind); 1605 } 1606 1607 function isLeftHandSideExpressionKind(kind: SyntaxKind): boolean { 1608 switch (kind) { 1609 case SyntaxKind.PropertyAccessExpression: 1610 case SyntaxKind.ElementAccessExpression: 1611 case SyntaxKind.NewExpression: 1612 case SyntaxKind.CallExpression: 1613 case SyntaxKind.JsxElement: 1614 case SyntaxKind.JsxSelfClosingElement: 1615 case SyntaxKind.JsxFragment: 1616 case SyntaxKind.TaggedTemplateExpression: 1617 case SyntaxKind.ArrayLiteralExpression: 1618 case SyntaxKind.ParenthesizedExpression: 1619 case SyntaxKind.ObjectLiteralExpression: 1620 case SyntaxKind.ClassExpression: 1621 case SyntaxKind.FunctionExpression: 1622 case SyntaxKind.EtsComponentExpression: 1623 case SyntaxKind.Identifier: 1624 case SyntaxKind.PrivateIdentifier: // technically this is only an Expression if it's in a `#field in expr` BinaryExpression 1625 case SyntaxKind.RegularExpressionLiteral: 1626 case SyntaxKind.NumericLiteral: 1627 case SyntaxKind.BigIntLiteral: 1628 case SyntaxKind.StringLiteral: 1629 case SyntaxKind.NoSubstitutionTemplateLiteral: 1630 case SyntaxKind.TemplateExpression: 1631 case SyntaxKind.FalseKeyword: 1632 case SyntaxKind.NullKeyword: 1633 case SyntaxKind.ThisKeyword: 1634 case SyntaxKind.TrueKeyword: 1635 case SyntaxKind.SuperKeyword: 1636 case SyntaxKind.NonNullExpression: 1637 case SyntaxKind.ExpressionWithTypeArguments: 1638 case SyntaxKind.MetaProperty: 1639 case SyntaxKind.ImportKeyword: // technically this is only an Expression if it's in a CallExpression 1640 return true; 1641 default: 1642 return false; 1643 } 1644 } 1645 1646 /* @internal */ 1647 export function isUnaryExpression(node: Node): node is UnaryExpression { 1648 return isUnaryExpressionKind(skipPartiallyEmittedExpressions(node).kind); 1649 } 1650 1651 function isUnaryExpressionKind(kind: SyntaxKind): boolean { 1652 switch (kind) { 1653 case SyntaxKind.PrefixUnaryExpression: 1654 case SyntaxKind.PostfixUnaryExpression: 1655 case SyntaxKind.DeleteExpression: 1656 case SyntaxKind.TypeOfExpression: 1657 case SyntaxKind.VoidExpression: 1658 case SyntaxKind.AwaitExpression: 1659 case SyntaxKind.TypeAssertionExpression: 1660 return true; 1661 default: 1662 return isLeftHandSideExpressionKind(kind); 1663 } 1664 } 1665 1666 /* @internal */ 1667 export function isUnaryExpressionWithWrite(expr: Node): expr is PrefixUnaryExpression | PostfixUnaryExpression { 1668 switch (expr.kind) { 1669 case SyntaxKind.PostfixUnaryExpression: 1670 return true; 1671 case SyntaxKind.PrefixUnaryExpression: 1672 return (expr as PrefixUnaryExpression).operator === SyntaxKind.PlusPlusToken || 1673 (expr as PrefixUnaryExpression).operator === SyntaxKind.MinusMinusToken; 1674 default: 1675 return false; 1676 } 1677 } 1678 1679 /* @internal */ 1680 /** 1681 * Determines whether a node is an expression based only on its kind. 1682 * Use `isExpressionNode` if not in transforms. 1683 */ 1684 export function isExpression(node: Node): node is Expression { 1685 return isExpressionKind(skipPartiallyEmittedExpressions(node).kind); 1686 } 1687 1688 function isExpressionKind(kind: SyntaxKind): boolean { 1689 switch (kind) { 1690 case SyntaxKind.ConditionalExpression: 1691 case SyntaxKind.YieldExpression: 1692 case SyntaxKind.ArrowFunction: 1693 case SyntaxKind.BinaryExpression: 1694 case SyntaxKind.SpreadElement: 1695 case SyntaxKind.AsExpression: 1696 case SyntaxKind.OmittedExpression: 1697 case SyntaxKind.CommaListExpression: 1698 case SyntaxKind.PartiallyEmittedExpression: 1699 case SyntaxKind.SatisfiesExpression: 1700 return true; 1701 default: 1702 return isUnaryExpressionKind(kind); 1703 } 1704 } 1705 1706 export function isAssertionExpression(node: Node): node is AssertionExpression { 1707 const kind = node.kind; 1708 return kind === SyntaxKind.TypeAssertionExpression 1709 || kind === SyntaxKind.AsExpression; 1710 } 1711 1712 /* @internal */ 1713 export function isNotEmittedOrPartiallyEmittedNode(node: Node): node is NotEmittedStatement | PartiallyEmittedExpression { 1714 return isNotEmittedStatement(node) 1715 || isPartiallyEmittedExpression(node); 1716 } 1717 1718 // Statement 1719 1720 export function isIterationStatement(node: Node, lookInLabeledStatements: false): node is IterationStatement; 1721 export function isIterationStatement(node: Node, lookInLabeledStatements: boolean): node is IterationStatement | LabeledStatement; 1722 export function isIterationStatement(node: Node, lookInLabeledStatements: boolean): node is IterationStatement { 1723 switch (node.kind) { 1724 case SyntaxKind.ForStatement: 1725 case SyntaxKind.ForInStatement: 1726 case SyntaxKind.ForOfStatement: 1727 case SyntaxKind.DoStatement: 1728 case SyntaxKind.WhileStatement: 1729 return true; 1730 case SyntaxKind.LabeledStatement: 1731 return lookInLabeledStatements && isIterationStatement((node as LabeledStatement).statement, lookInLabeledStatements); 1732 } 1733 1734 return false; 1735 } 1736 1737 /* @internal */ 1738 export function isScopeMarker(node: Node) { 1739 return isExportAssignment(node) || isExportDeclaration(node); 1740 } 1741 1742 /* @internal */ 1743 export function hasScopeMarker(statements: readonly Statement[]) { 1744 return some(statements, isScopeMarker); 1745 } 1746 1747 /* @internal */ 1748 export function needsScopeMarker(result: Statement) { 1749 return !isAnyImportOrReExport(result) && !isExportAssignment(result) && !hasSyntacticModifier(result, ModifierFlags.Export) && !isAmbientModule(result); 1750 } 1751 1752 /* @internal */ 1753 export function isExternalModuleIndicator(result: Statement) { 1754 // Exported top-level member indicates moduleness 1755 return isAnyImportOrReExport(result) || isExportAssignment(result) || hasSyntacticModifier(result, ModifierFlags.Export); 1756 } 1757 1758 /* @internal */ 1759 export function isForInOrOfStatement(node: Node): node is ForInOrOfStatement { 1760 return node.kind === SyntaxKind.ForInStatement || node.kind === SyntaxKind.ForOfStatement; 1761 } 1762 1763 // Element 1764 1765 /* @internal */ 1766 export function isConciseBody(node: Node): node is ConciseBody { 1767 return isBlock(node) 1768 || isExpression(node); 1769 } 1770 1771 /* @internal */ 1772 export function isFunctionBody(node: Node): node is FunctionBody { 1773 return isBlock(node); 1774 } 1775 1776 /* @internal */ 1777 export function isForInitializer(node: Node): node is ForInitializer { 1778 return isVariableDeclarationList(node) 1779 || isExpression(node); 1780 } 1781 1782 /* @internal */ 1783 export function isModuleBody(node: Node): node is ModuleBody { 1784 const kind = node.kind; 1785 return kind === SyntaxKind.ModuleBlock 1786 || kind === SyntaxKind.ModuleDeclaration 1787 || kind === SyntaxKind.Identifier; 1788 } 1789 1790 /* @internal */ 1791 export function isNamespaceBody(node: Node): node is NamespaceBody { 1792 const kind = node.kind; 1793 return kind === SyntaxKind.ModuleBlock 1794 || kind === SyntaxKind.ModuleDeclaration; 1795 } 1796 1797 /* @internal */ 1798 export function isJSDocNamespaceBody(node: Node): node is JSDocNamespaceBody { 1799 const kind = node.kind; 1800 return kind === SyntaxKind.Identifier 1801 || kind === SyntaxKind.ModuleDeclaration; 1802 } 1803 1804 /* @internal */ 1805 export function isNamedImportBindings(node: Node): node is NamedImportBindings { 1806 const kind = node.kind; 1807 return kind === SyntaxKind.NamedImports 1808 || kind === SyntaxKind.NamespaceImport; 1809 } 1810 1811 /* @internal */ 1812 export function isModuleOrEnumDeclaration(node: Node): node is ModuleDeclaration | EnumDeclaration { 1813 return node.kind === SyntaxKind.ModuleDeclaration || node.kind === SyntaxKind.EnumDeclaration; 1814 } 1815 1816 function isDeclarationKind(kind: SyntaxKind) { 1817 return kind === SyntaxKind.ArrowFunction 1818 || kind === SyntaxKind.BindingElement 1819 || kind === SyntaxKind.ClassDeclaration 1820 || kind === SyntaxKind.ClassExpression 1821 || kind === SyntaxKind.ClassStaticBlockDeclaration 1822 || kind === SyntaxKind.StructDeclaration 1823 || kind === SyntaxKind.Constructor 1824 || kind === SyntaxKind.EnumDeclaration 1825 || kind === SyntaxKind.EnumMember 1826 || kind === SyntaxKind.ExportSpecifier 1827 || kind === SyntaxKind.FunctionDeclaration 1828 || kind === SyntaxKind.FunctionExpression 1829 || kind === SyntaxKind.GetAccessor 1830 || kind === SyntaxKind.ImportClause 1831 || kind === SyntaxKind.ImportEqualsDeclaration 1832 || kind === SyntaxKind.ImportSpecifier 1833 || kind === SyntaxKind.InterfaceDeclaration 1834 || kind === SyntaxKind.JsxAttribute 1835 || kind === SyntaxKind.MethodDeclaration 1836 || kind === SyntaxKind.MethodSignature 1837 || kind === SyntaxKind.ModuleDeclaration 1838 || kind === SyntaxKind.NamespaceExportDeclaration 1839 || kind === SyntaxKind.NamespaceImport 1840 || kind === SyntaxKind.NamespaceExport 1841 || kind === SyntaxKind.Parameter 1842 || kind === SyntaxKind.PropertyAssignment 1843 || kind === SyntaxKind.PropertyDeclaration 1844 || kind === SyntaxKind.PropertySignature 1845 || kind === SyntaxKind.SetAccessor 1846 || kind === SyntaxKind.ShorthandPropertyAssignment 1847 || kind === SyntaxKind.TypeAliasDeclaration 1848 || kind === SyntaxKind.TypeParameter 1849 || kind === SyntaxKind.VariableDeclaration 1850 || kind === SyntaxKind.JSDocTypedefTag 1851 || kind === SyntaxKind.JSDocCallbackTag 1852 || kind === SyntaxKind.JSDocPropertyTag; 1853 } 1854 1855 function isDeclarationStatementKind(kind: SyntaxKind) { 1856 return kind === SyntaxKind.FunctionDeclaration 1857 || kind === SyntaxKind.MissingDeclaration 1858 || kind === SyntaxKind.ClassDeclaration 1859 || kind === SyntaxKind.StructDeclaration 1860 || kind === SyntaxKind.InterfaceDeclaration 1861 || kind === SyntaxKind.TypeAliasDeclaration 1862 || kind === SyntaxKind.EnumDeclaration 1863 || kind === SyntaxKind.ModuleDeclaration 1864 || kind === SyntaxKind.ImportDeclaration 1865 || kind === SyntaxKind.ImportEqualsDeclaration 1866 || kind === SyntaxKind.ExportDeclaration 1867 || kind === SyntaxKind.ExportAssignment 1868 || kind === SyntaxKind.NamespaceExportDeclaration; 1869 } 1870 1871 function isStatementKindButNotDeclarationKind(kind: SyntaxKind) { 1872 return kind === SyntaxKind.BreakStatement 1873 || kind === SyntaxKind.ContinueStatement 1874 || kind === SyntaxKind.DebuggerStatement 1875 || kind === SyntaxKind.DoStatement 1876 || kind === SyntaxKind.ExpressionStatement 1877 || kind === SyntaxKind.EmptyStatement 1878 || kind === SyntaxKind.ForInStatement 1879 || kind === SyntaxKind.ForOfStatement 1880 || kind === SyntaxKind.ForStatement 1881 || kind === SyntaxKind.IfStatement 1882 || kind === SyntaxKind.LabeledStatement 1883 || kind === SyntaxKind.ReturnStatement 1884 || kind === SyntaxKind.SwitchStatement 1885 || kind === SyntaxKind.ThrowStatement 1886 || kind === SyntaxKind.TryStatement 1887 || kind === SyntaxKind.VariableStatement 1888 || kind === SyntaxKind.WhileStatement 1889 || kind === SyntaxKind.WithStatement 1890 || kind === SyntaxKind.NotEmittedStatement 1891 || kind === SyntaxKind.EndOfDeclarationMarker 1892 || kind === SyntaxKind.MergeDeclarationMarker; 1893 } 1894 1895 /* @internal */ 1896 export function isDeclaration(node: Node): node is NamedDeclaration { 1897 if (node.kind === SyntaxKind.TypeParameter) { 1898 return (node.parent && node.parent.kind !== SyntaxKind.JSDocTemplateTag) || isInJSFile(node); 1899 } 1900 1901 return isDeclarationKind(node.kind); 1902 } 1903 1904 /* @internal */ 1905 export function isDeclarationStatement(node: Node): node is DeclarationStatement { 1906 return isDeclarationStatementKind(node.kind); 1907 } 1908 1909 /** 1910 * Determines whether the node is a statement that is not also a declaration 1911 */ 1912 /* @internal */ 1913 export function isStatementButNotDeclaration(node: Node): node is Statement { 1914 return isStatementKindButNotDeclarationKind(node.kind); 1915 } 1916 1917 /* @internal */ 1918 export function isStatement(node: Node): node is Statement { 1919 const kind = node.kind; 1920 return isStatementKindButNotDeclarationKind(kind) 1921 || isDeclarationStatementKind(kind) 1922 || isBlockStatement(node); 1923 } 1924 1925 function isBlockStatement(node: Node): node is Block { 1926 if (node.kind !== SyntaxKind.Block) return false; 1927 if (node.parent !== undefined) { 1928 if (node.parent.kind === SyntaxKind.TryStatement || node.parent.kind === SyntaxKind.CatchClause) { 1929 return false; 1930 } 1931 } 1932 return !isFunctionBlock(node); 1933 } 1934 1935 /** 1936 * NOTE: This is similar to `isStatement` but does not access parent pointers. 1937 */ 1938 /* @internal */ 1939 export function isStatementOrBlock(node: Node): node is Statement | Block { 1940 const kind = node.kind; 1941 return isStatementKindButNotDeclarationKind(kind) 1942 || isDeclarationStatementKind(kind) 1943 || kind === SyntaxKind.Block; 1944 } 1945 1946 // Module references 1947 1948 /* @internal */ 1949 export function isModuleReference(node: Node): node is ModuleReference { 1950 const kind = node.kind; 1951 return kind === SyntaxKind.ExternalModuleReference 1952 || kind === SyntaxKind.QualifiedName 1953 || kind === SyntaxKind.Identifier; 1954 } 1955 1956 // JSX 1957 1958 /* @internal */ 1959 export function isJsxTagNameExpression(node: Node): node is JsxTagNameExpression { 1960 const kind = node.kind; 1961 return kind === SyntaxKind.ThisKeyword 1962 || kind === SyntaxKind.Identifier 1963 || kind === SyntaxKind.PropertyAccessExpression; 1964 } 1965 1966 /* @internal */ 1967 export function isJsxChild(node: Node): node is JsxChild { 1968 const kind = node.kind; 1969 return kind === SyntaxKind.JsxElement 1970 || kind === SyntaxKind.JsxExpression 1971 || kind === SyntaxKind.JsxSelfClosingElement 1972 || kind === SyntaxKind.JsxText 1973 || kind === SyntaxKind.JsxFragment; 1974 } 1975 1976 /* @internal */ 1977 export function isJsxAttributeLike(node: Node): node is JsxAttributeLike { 1978 const kind = node.kind; 1979 return kind === SyntaxKind.JsxAttribute 1980 || kind === SyntaxKind.JsxSpreadAttribute; 1981 } 1982 1983 /* @internal */ 1984 export function isStringLiteralOrJsxExpression(node: Node): node is StringLiteral | JsxExpression { 1985 const kind = node.kind; 1986 return kind === SyntaxKind.StringLiteral 1987 || kind === SyntaxKind.JsxExpression; 1988 } 1989 1990 export function isJsxOpeningLikeElement(node: Node): node is JsxOpeningLikeElement { 1991 const kind = node.kind; 1992 return kind === SyntaxKind.JsxOpeningElement 1993 || kind === SyntaxKind.JsxSelfClosingElement; 1994 } 1995 1996 // Clauses 1997 1998 export function isCaseOrDefaultClause(node: Node): node is CaseOrDefaultClause { 1999 const kind = node.kind; 2000 return kind === SyntaxKind.CaseClause 2001 || kind === SyntaxKind.DefaultClause; 2002 } 2003 2004 // JSDoc 2005 2006 /** True if node is of some JSDoc syntax kind. */ 2007 /* @internal */ 2008 export function isJSDocNode(node: Node): boolean { 2009 return node.kind >= SyntaxKind.FirstJSDocNode && node.kind <= SyntaxKind.LastJSDocNode; 2010 } 2011 2012 /** True if node is of a kind that may contain comment text. */ 2013 export function isJSDocCommentContainingNode(node: Node): boolean { 2014 return node.kind === SyntaxKind.JSDoc 2015 || node.kind === SyntaxKind.JSDocNamepathType 2016 || node.kind === SyntaxKind.JSDocText 2017 || isJSDocLinkLike(node) 2018 || isJSDocTag(node) 2019 || isJSDocTypeLiteral(node) 2020 || isJSDocSignature(node); 2021 } 2022 2023 // TODO: determine what this does before making it public. 2024 /* @internal */ 2025 export function isJSDocTag(node: Node): node is JSDocTag { 2026 return node.kind >= SyntaxKind.FirstJSDocTagNode && node.kind <= SyntaxKind.LastJSDocTagNode; 2027 } 2028 2029 export function isSetAccessor(node: Node): node is SetAccessorDeclaration { 2030 return node.kind === SyntaxKind.SetAccessor; 2031 } 2032 2033 export function isGetAccessor(node: Node): node is GetAccessorDeclaration { 2034 return node.kind === SyntaxKind.GetAccessor; 2035 } 2036 2037 /** True if has jsdoc nodes attached to it. */ 2038 /* @internal */ 2039 // TODO: GH#19856 Would like to return `node is Node & { jsDoc: JSDoc[] }` but it causes long compile times 2040 export function hasJSDocNodes(node: Node): node is HasJSDoc { 2041 const { jsDoc } = node as JSDocContainer; 2042 return !!jsDoc && jsDoc.length > 0; 2043 } 2044 2045 /** True if has type node attached to it. */ 2046 /* @internal */ 2047 export function hasType(node: Node): node is HasType { 2048 return !!(node as HasType).type; 2049 } 2050 2051 /** True if has initializer node attached to it. */ 2052 /* @internal */ 2053 export function hasInitializer(node: Node): node is HasInitializer { 2054 return !!(node as HasInitializer).initializer; 2055 } 2056 2057 /** True if has initializer node attached to it. */ 2058 export function hasOnlyExpressionInitializer(node: Node): node is HasExpressionInitializer { 2059 switch (node.kind) { 2060 case SyntaxKind.VariableDeclaration: 2061 case SyntaxKind.Parameter: 2062 case SyntaxKind.BindingElement: 2063 case SyntaxKind.PropertyDeclaration: 2064 case SyntaxKind.PropertyAssignment: 2065 case SyntaxKind.EnumMember: 2066 return true; 2067 default: 2068 return false; 2069 } 2070 } 2071 2072 export function isObjectLiteralElement(node: Node): node is ObjectLiteralElement { 2073 return node.kind === SyntaxKind.JsxAttribute || node.kind === SyntaxKind.JsxSpreadAttribute || isObjectLiteralElementLike(node); 2074 } 2075 2076 /* @internal */ 2077 export function isTypeReferenceType(node: Node): node is TypeReferenceType { 2078 return node.kind === SyntaxKind.TypeReference || node.kind === SyntaxKind.ExpressionWithTypeArguments; 2079 } 2080 2081 const MAX_SMI_X86 = 0x3fff_ffff; 2082 /* @internal */ 2083 export function guessIndentation(lines: string[]) { 2084 let indentation = MAX_SMI_X86; 2085 for (const line of lines) { 2086 if (!line.length) { 2087 continue; 2088 } 2089 let i = 0; 2090 for (; i < line.length && i < indentation; i++) { 2091 if (!isWhiteSpaceLike(line.charCodeAt(i))) { 2092 break; 2093 } 2094 } 2095 if (i < indentation) { 2096 indentation = i; 2097 } 2098 if (indentation === 0) { 2099 return 0; 2100 } 2101 } 2102 return indentation === MAX_SMI_X86 ? undefined : indentation; 2103 } 2104 2105 export function isStringLiteralLike(node: Node): node is StringLiteralLike { 2106 return node.kind === SyntaxKind.StringLiteral || node.kind === SyntaxKind.NoSubstitutionTemplateLiteral; 2107 } 2108 2109 export function isJSDocLinkLike(node: Node): node is JSDocLink | JSDocLinkCode | JSDocLinkPlain { 2110 return node.kind === SyntaxKind.JSDocLink || node.kind === SyntaxKind.JSDocLinkCode || node.kind === SyntaxKind.JSDocLinkPlain; 2111 } 2112 2113 export function hasRestParameter(s: SignatureDeclaration | JSDocSignature): boolean { 2114 const last = lastOrUndefined<ParameterDeclaration | JSDocParameterTag>(s.parameters); 2115 return !!last && isRestParameter(last); 2116 } 2117 2118 export function isRestParameter(node: ParameterDeclaration | JSDocParameterTag): boolean { 2119 const type = isJSDocParameterTag(node) ? (node.typeExpression && node.typeExpression.type) : node.type; 2120 return (node as ParameterDeclaration).dotDotDotToken !== undefined || !!type && type.kind === SyntaxKind.JSDocVariadicType; 2121 } 2122 2123 // #endregion 2124} 2125