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