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 export function isAnnotationElement(node: Node): node is AnnotationElement { 1363 const kind = node.kind; 1364 return kind === SyntaxKind.AnnotationPropertyDeclaration; 1365 } 1366 1367 // Classes 1368 export function isClassElement(node: Node): node is ClassElement { 1369 const kind = node.kind; 1370 return kind === SyntaxKind.Constructor 1371 || kind === SyntaxKind.PropertyDeclaration 1372 || kind === SyntaxKind.MethodDeclaration 1373 || kind === SyntaxKind.GetAccessor 1374 || kind === SyntaxKind.SetAccessor 1375 || kind === SyntaxKind.IndexSignature 1376 || kind === SyntaxKind.ClassStaticBlockDeclaration 1377 || kind === SyntaxKind.SemicolonClassElement; 1378 } 1379 1380 export function isClassLike(node: Node): node is ClassLikeDeclaration { 1381 return node && (node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.ClassExpression || node.kind === SyntaxKind.StructDeclaration); 1382 } 1383 1384 export function isStruct(node: Node): node is StructDeclaration { 1385 return node && node.kind === SyntaxKind.StructDeclaration; 1386 } 1387 1388 export function isAccessor(node: Node): node is AccessorDeclaration { 1389 return node && (node.kind === SyntaxKind.GetAccessor || node.kind === SyntaxKind.SetAccessor); 1390 } 1391 1392 export function isAutoAccessorPropertyDeclaration(node: Node): node is AutoAccessorPropertyDeclaration { 1393 return isPropertyDeclaration(node) && hasAccessorModifier(node); 1394 } 1395 1396 /* @internal */ 1397 export function isMethodOrAccessor(node: Node): node is MethodDeclaration | AccessorDeclaration { 1398 switch (node.kind) { 1399 case SyntaxKind.MethodDeclaration: 1400 case SyntaxKind.GetAccessor: 1401 case SyntaxKind.SetAccessor: 1402 return true; 1403 default: 1404 return false; 1405 } 1406 } 1407 1408 /* @internal */ 1409 export function isNamedClassElement(node: Node): node is MethodDeclaration | AccessorDeclaration | PropertyDeclaration { 1410 switch (node.kind) { 1411 case SyntaxKind.MethodDeclaration: 1412 case SyntaxKind.GetAccessor: 1413 case SyntaxKind.SetAccessor: 1414 case SyntaxKind.PropertyDeclaration: 1415 return true; 1416 default: 1417 return false; 1418 } 1419 } 1420 1421 // Type members 1422 1423 export function isModifierLike(node: Node): node is ModifierLike { 1424 return isModifier(node) || isDecorator(node); 1425 } 1426 1427 export function isTypeElement(node: Node): node is TypeElement { 1428 const kind = node.kind; 1429 return kind === SyntaxKind.ConstructSignature 1430 || kind === SyntaxKind.CallSignature 1431 || kind === SyntaxKind.PropertySignature 1432 || kind === SyntaxKind.MethodSignature 1433 || kind === SyntaxKind.IndexSignature 1434 || kind === SyntaxKind.GetAccessor 1435 || kind === SyntaxKind.SetAccessor; 1436 } 1437 1438 export function isClassOrTypeElement(node: Node): node is ClassElement | TypeElement { 1439 return isTypeElement(node) || isClassElement(node); 1440 } 1441 1442 export function isObjectLiteralElementLike(node: Node): node is ObjectLiteralElementLike { 1443 const kind = node.kind; 1444 return kind === SyntaxKind.PropertyAssignment 1445 || kind === SyntaxKind.ShorthandPropertyAssignment 1446 || kind === SyntaxKind.SpreadAssignment 1447 || kind === SyntaxKind.MethodDeclaration 1448 || kind === SyntaxKind.GetAccessor 1449 || kind === SyntaxKind.SetAccessor; 1450 } 1451 1452 // Type 1453 1454 /** 1455 * Node test that determines whether a node is a valid type node. 1456 * This differs from the `isPartOfTypeNode` function which determines whether a node is *part* 1457 * of a TypeNode. 1458 */ 1459 export function isTypeNode(node: Node): node is TypeNode { 1460 return isTypeNodeKind(node.kind); 1461 } 1462 1463 export function isFunctionOrConstructorTypeNode(node: Node): node is FunctionTypeNode | ConstructorTypeNode { 1464 switch (node.kind) { 1465 case SyntaxKind.FunctionType: 1466 case SyntaxKind.ConstructorType: 1467 return true; 1468 } 1469 1470 return false; 1471 } 1472 1473 // Binding patterns 1474 1475 /* @internal */ 1476 export function isBindingPattern(node: Node | undefined): node is BindingPattern { 1477 if (node) { 1478 const kind = node.kind; 1479 return kind === SyntaxKind.ArrayBindingPattern 1480 || kind === SyntaxKind.ObjectBindingPattern; 1481 } 1482 1483 return false; 1484 } 1485 1486 /* @internal */ 1487 export function isAssignmentPattern(node: Node): node is AssignmentPattern { 1488 const kind = node.kind; 1489 return kind === SyntaxKind.ArrayLiteralExpression 1490 || kind === SyntaxKind.ObjectLiteralExpression; 1491 } 1492 1493 1494 /* @internal */ 1495 export function isArrayBindingElement(node: Node): node is ArrayBindingElement { 1496 const kind = node.kind; 1497 return kind === SyntaxKind.BindingElement 1498 || kind === SyntaxKind.OmittedExpression; 1499 } 1500 1501 1502 /** 1503 * Determines whether the BindingOrAssignmentElement is a BindingElement-like declaration 1504 */ 1505 /* @internal */ 1506 export function isDeclarationBindingElement(bindingElement: BindingOrAssignmentElement): bindingElement is VariableDeclaration | ParameterDeclaration | BindingElement { 1507 switch (bindingElement.kind) { 1508 case SyntaxKind.VariableDeclaration: 1509 case SyntaxKind.Parameter: 1510 case SyntaxKind.BindingElement: 1511 return true; 1512 } 1513 1514 return false; 1515 } 1516 1517 /** 1518 * Determines whether a node is a BindingOrAssignmentPattern 1519 */ 1520 /* @internal */ 1521 export function isBindingOrAssignmentPattern(node: BindingOrAssignmentElementTarget): node is BindingOrAssignmentPattern { 1522 return isObjectBindingOrAssignmentPattern(node) 1523 || isArrayBindingOrAssignmentPattern(node); 1524 } 1525 1526 /** 1527 * Determines whether a node is an ObjectBindingOrAssignmentPattern 1528 */ 1529 /* @internal */ 1530 export function isObjectBindingOrAssignmentPattern(node: BindingOrAssignmentElementTarget): node is ObjectBindingOrAssignmentPattern { 1531 switch (node.kind) { 1532 case SyntaxKind.ObjectBindingPattern: 1533 case SyntaxKind.ObjectLiteralExpression: 1534 return true; 1535 } 1536 1537 return false; 1538 } 1539 1540 /* @internal */ 1541 export function isObjectBindingOrAssignmentElement(node: Node): node is ObjectBindingOrAssignmentElement { 1542 switch (node.kind) { 1543 case SyntaxKind.BindingElement: 1544 case SyntaxKind.PropertyAssignment: // AssignmentProperty 1545 case SyntaxKind.ShorthandPropertyAssignment: // AssignmentProperty 1546 case SyntaxKind.SpreadAssignment: // AssignmentRestProperty 1547 return true; 1548 } 1549 return false; 1550 } 1551 1552 /** 1553 * Determines whether a node is an ArrayBindingOrAssignmentPattern 1554 */ 1555 /* @internal */ 1556 export function isArrayBindingOrAssignmentPattern(node: BindingOrAssignmentElementTarget): node is ArrayBindingOrAssignmentPattern { 1557 switch (node.kind) { 1558 case SyntaxKind.ArrayBindingPattern: 1559 case SyntaxKind.ArrayLiteralExpression: 1560 return true; 1561 } 1562 1563 return false; 1564 } 1565 1566 /* @internal */ 1567 export function isPropertyAccessOrQualifiedNameOrImportTypeNode(node: Node): node is PropertyAccessExpression | QualifiedName | ImportTypeNode { 1568 const kind = node.kind; 1569 return kind === SyntaxKind.PropertyAccessExpression 1570 || kind === SyntaxKind.QualifiedName 1571 || kind === SyntaxKind.ImportType; 1572 } 1573 1574 // Expression 1575 1576 export function isPropertyAccessOrQualifiedName(node: Node): node is PropertyAccessExpression | QualifiedName { 1577 const kind = node.kind; 1578 return kind === SyntaxKind.PropertyAccessExpression 1579 || kind === SyntaxKind.QualifiedName; 1580 } 1581 1582 export function isCallLikeExpression(node: Node): node is CallLikeExpression { 1583 switch (node.kind) { 1584 case SyntaxKind.JsxOpeningElement: 1585 case SyntaxKind.JsxSelfClosingElement: 1586 case SyntaxKind.CallExpression: 1587 case SyntaxKind.NewExpression: 1588 case SyntaxKind.TaggedTemplateExpression: 1589 case SyntaxKind.Decorator: 1590 case SyntaxKind.EtsComponentExpression: 1591 return true; 1592 default: 1593 return false; 1594 } 1595 } 1596 1597 export function isCallOrNewExpression(node: Node): node is CallExpression | NewExpression { 1598 return node.kind === SyntaxKind.CallExpression || node.kind === SyntaxKind.NewExpression; 1599 } 1600 1601 export function isTemplateLiteral(node: Node): node is TemplateLiteral { 1602 const kind = node.kind; 1603 return kind === SyntaxKind.TemplateExpression 1604 || kind === SyntaxKind.NoSubstitutionTemplateLiteral; 1605 } 1606 1607 /* @internal */ 1608 export function isLeftHandSideExpression(node: Node): node is LeftHandSideExpression { 1609 return isLeftHandSideExpressionKind(skipPartiallyEmittedExpressions(node).kind); 1610 } 1611 1612 function isLeftHandSideExpressionKind(kind: SyntaxKind): boolean { 1613 switch (kind) { 1614 case SyntaxKind.PropertyAccessExpression: 1615 case SyntaxKind.ElementAccessExpression: 1616 case SyntaxKind.NewExpression: 1617 case SyntaxKind.CallExpression: 1618 case SyntaxKind.JsxElement: 1619 case SyntaxKind.JsxSelfClosingElement: 1620 case SyntaxKind.JsxFragment: 1621 case SyntaxKind.TaggedTemplateExpression: 1622 case SyntaxKind.ArrayLiteralExpression: 1623 case SyntaxKind.ParenthesizedExpression: 1624 case SyntaxKind.ObjectLiteralExpression: 1625 case SyntaxKind.ClassExpression: 1626 case SyntaxKind.FunctionExpression: 1627 case SyntaxKind.EtsComponentExpression: 1628 case SyntaxKind.Identifier: 1629 case SyntaxKind.PrivateIdentifier: // technically this is only an Expression if it's in a `#field in expr` BinaryExpression 1630 case SyntaxKind.RegularExpressionLiteral: 1631 case SyntaxKind.NumericLiteral: 1632 case SyntaxKind.BigIntLiteral: 1633 case SyntaxKind.StringLiteral: 1634 case SyntaxKind.NoSubstitutionTemplateLiteral: 1635 case SyntaxKind.TemplateExpression: 1636 case SyntaxKind.FalseKeyword: 1637 case SyntaxKind.NullKeyword: 1638 case SyntaxKind.ThisKeyword: 1639 case SyntaxKind.TrueKeyword: 1640 case SyntaxKind.SuperKeyword: 1641 case SyntaxKind.NonNullExpression: 1642 case SyntaxKind.ExpressionWithTypeArguments: 1643 case SyntaxKind.MetaProperty: 1644 case SyntaxKind.ImportKeyword: // technically this is only an Expression if it's in a CallExpression 1645 return true; 1646 default: 1647 return false; 1648 } 1649 } 1650 1651 /* @internal */ 1652 export function isUnaryExpression(node: Node): node is UnaryExpression { 1653 return isUnaryExpressionKind(skipPartiallyEmittedExpressions(node).kind); 1654 } 1655 1656 function isUnaryExpressionKind(kind: SyntaxKind): boolean { 1657 switch (kind) { 1658 case SyntaxKind.PrefixUnaryExpression: 1659 case SyntaxKind.PostfixUnaryExpression: 1660 case SyntaxKind.DeleteExpression: 1661 case SyntaxKind.TypeOfExpression: 1662 case SyntaxKind.VoidExpression: 1663 case SyntaxKind.AwaitExpression: 1664 case SyntaxKind.TypeAssertionExpression: 1665 return true; 1666 default: 1667 return isLeftHandSideExpressionKind(kind); 1668 } 1669 } 1670 1671 /* @internal */ 1672 export function isUnaryExpressionWithWrite(expr: Node): expr is PrefixUnaryExpression | PostfixUnaryExpression { 1673 switch (expr.kind) { 1674 case SyntaxKind.PostfixUnaryExpression: 1675 return true; 1676 case SyntaxKind.PrefixUnaryExpression: 1677 return (expr as PrefixUnaryExpression).operator === SyntaxKind.PlusPlusToken || 1678 (expr as PrefixUnaryExpression).operator === SyntaxKind.MinusMinusToken; 1679 default: 1680 return false; 1681 } 1682 } 1683 1684 /* @internal */ 1685 /** 1686 * Determines whether a node is an expression based only on its kind. 1687 * Use `isExpressionNode` if not in transforms. 1688 */ 1689 export function isExpression(node: Node): node is Expression { 1690 return isExpressionKind(skipPartiallyEmittedExpressions(node).kind); 1691 } 1692 1693 function isExpressionKind(kind: SyntaxKind): boolean { 1694 switch (kind) { 1695 case SyntaxKind.ConditionalExpression: 1696 case SyntaxKind.YieldExpression: 1697 case SyntaxKind.ArrowFunction: 1698 case SyntaxKind.BinaryExpression: 1699 case SyntaxKind.SpreadElement: 1700 case SyntaxKind.AsExpression: 1701 case SyntaxKind.OmittedExpression: 1702 case SyntaxKind.CommaListExpression: 1703 case SyntaxKind.PartiallyEmittedExpression: 1704 case SyntaxKind.SatisfiesExpression: 1705 return true; 1706 default: 1707 return isUnaryExpressionKind(kind); 1708 } 1709 } 1710 1711 export function isAssertionExpression(node: Node): node is AssertionExpression { 1712 const kind = node.kind; 1713 return kind === SyntaxKind.TypeAssertionExpression 1714 || kind === SyntaxKind.AsExpression; 1715 } 1716 1717 /* @internal */ 1718 export function isNotEmittedOrPartiallyEmittedNode(node: Node): node is NotEmittedStatement | PartiallyEmittedExpression { 1719 return isNotEmittedStatement(node) 1720 || isPartiallyEmittedExpression(node); 1721 } 1722 1723 // Statement 1724 1725 export function isIterationStatement(node: Node, lookInLabeledStatements: false): node is IterationStatement; 1726 export function isIterationStatement(node: Node, lookInLabeledStatements: boolean): node is IterationStatement | LabeledStatement; 1727 export function isIterationStatement(node: Node, lookInLabeledStatements: boolean): node is IterationStatement { 1728 switch (node.kind) { 1729 case SyntaxKind.ForStatement: 1730 case SyntaxKind.ForInStatement: 1731 case SyntaxKind.ForOfStatement: 1732 case SyntaxKind.DoStatement: 1733 case SyntaxKind.WhileStatement: 1734 return true; 1735 case SyntaxKind.LabeledStatement: 1736 return lookInLabeledStatements && isIterationStatement((node as LabeledStatement).statement, lookInLabeledStatements); 1737 } 1738 1739 return false; 1740 } 1741 1742 /* @internal */ 1743 export function isScopeMarker(node: Node) { 1744 return isExportAssignment(node) || isExportDeclaration(node); 1745 } 1746 1747 /* @internal */ 1748 export function hasScopeMarker(statements: readonly Statement[]) { 1749 return some(statements, isScopeMarker); 1750 } 1751 1752 /* @internal */ 1753 export function needsScopeMarker(result: Statement) { 1754 return !isAnyImportOrReExport(result) && !isExportAssignment(result) && !hasSyntacticModifier(result, ModifierFlags.Export) && !isAmbientModule(result); 1755 } 1756 1757 /* @internal */ 1758 export function isExternalModuleIndicator(result: Statement) { 1759 // Exported top-level member indicates moduleness 1760 return isAnyImportOrReExport(result) || isExportAssignment(result) || hasSyntacticModifier(result, ModifierFlags.Export); 1761 } 1762 1763 /** 1764 * Semantics of annotations is not defined for JS. The presence of AnnotationDeclaration 1765 * in SourceFile shouldn't effect on resulting JS code. 1766 * But AnnotationDeclaration reuse a general mechanics for declaration importing and exporting. 1767 * It may lead to generation of boilerplate code in process of transformation into JS. 1768 * For example, 1769 * // A.ts 1770 * export @inteface Anno {} 1771 * 1772 * // A.js 1773 * exports.__esModule = true; // <-- side effect 1774 * 1775 * Following function returns true if SourceFile contains only AnnotationDeclaration 1776 * as importing or exporting entity. 1777 */ 1778 /* @internal */ 1779 export function isOnlyAnnotationsAreExportedOrImported(s: SourceFile, resolver: EmitResolver) { 1780 // Ingnore any files except ets 1781 if (!isInEtsFile(s)) { 1782 return false; 1783 } 1784 // SourceFile exports or imports contains only annotation declarations 1785 const exports = mapDefined(s.statements, (s: Statement) => { 1786 const os = getOriginalNode(s) as Statement; 1787 return isExternalModuleIndicator(os) ? os : undefined; 1788 }); 1789 const imports = s.imports; 1790 if (exports.length === 0 && imports.length === 0) { 1791 return false; 1792 } 1793 return every(exports, e => { 1794 if (isAnnotationDeclaration(e)) { 1795 return true; 1796 } 1797 else if (isExportDeclaration(e) && e.exportClause && isNamedExports(e.exportClause)) { 1798 return e.exportClause.elements.length > 0 && every(e.exportClause.elements, e => resolver.isReferredToAnnotation(e) === true); 1799 } 1800 else if (isExportAssignment(e) && resolver.isReferredToAnnotation(e) === true) { 1801 return true; 1802 } 1803 else if (isImportDeclaration(e) && e.importClause && e.importClause.namedBindings && isNamedImports(e.importClause.namedBindings)) { 1804 return e.importClause.namedBindings.elements.length > 0 && every(e.importClause.namedBindings.elements, e => resolver.isReferredToAnnotation(e) === true); 1805 } 1806 return false; 1807 }) && every(imports, i => { 1808 if (isImportDeclaration(i.parent) && i.parent.importClause && i.parent.importClause.namedBindings && isNamedImports(i.parent.importClause.namedBindings)) { 1809 return i.parent.importClause.namedBindings.elements.length > 0 && every(i.parent.importClause.namedBindings.elements, e => resolver.isReferredToAnnotation(e) === true); 1810 } 1811 else if (isExportDeclaration(i.parent) && i.parent.exportClause && isNamedExports(i.parent.exportClause)) { 1812 return i.parent.exportClause.elements.length > 0 && every(i.parent.exportClause.elements, e => resolver.isReferredToAnnotation(e) === true); 1813 } 1814 return false; 1815 }); 1816 } 1817 1818 1819 /* @internal */ 1820 export function isForInOrOfStatement(node: Node): node is ForInOrOfStatement { 1821 return node.kind === SyntaxKind.ForInStatement || node.kind === SyntaxKind.ForOfStatement; 1822 } 1823 1824 // Element 1825 1826 /* @internal */ 1827 export function isConciseBody(node: Node): node is ConciseBody { 1828 return isBlock(node) 1829 || isExpression(node); 1830 } 1831 1832 /* @internal */ 1833 export function isFunctionBody(node: Node): node is FunctionBody { 1834 return isBlock(node); 1835 } 1836 1837 /* @internal */ 1838 export function isForInitializer(node: Node): node is ForInitializer { 1839 return isVariableDeclarationList(node) 1840 || isExpression(node); 1841 } 1842 1843 /* @internal */ 1844 export function isModuleBody(node: Node): node is ModuleBody { 1845 const kind = node.kind; 1846 return kind === SyntaxKind.ModuleBlock 1847 || kind === SyntaxKind.ModuleDeclaration 1848 || kind === SyntaxKind.Identifier; 1849 } 1850 1851 /* @internal */ 1852 export function isNamespaceBody(node: Node): node is NamespaceBody { 1853 const kind = node.kind; 1854 return kind === SyntaxKind.ModuleBlock 1855 || kind === SyntaxKind.ModuleDeclaration; 1856 } 1857 1858 /* @internal */ 1859 export function isJSDocNamespaceBody(node: Node): node is JSDocNamespaceBody { 1860 const kind = node.kind; 1861 return kind === SyntaxKind.Identifier 1862 || kind === SyntaxKind.ModuleDeclaration; 1863 } 1864 1865 /* @internal */ 1866 export function isNamedImportBindings(node: Node): node is NamedImportBindings { 1867 const kind = node.kind; 1868 return kind === SyntaxKind.NamedImports 1869 || kind === SyntaxKind.NamespaceImport; 1870 } 1871 1872 /* @internal */ 1873 export function isModuleOrEnumDeclaration(node: Node): node is ModuleDeclaration | EnumDeclaration { 1874 return node.kind === SyntaxKind.ModuleDeclaration || node.kind === SyntaxKind.EnumDeclaration; 1875 } 1876 1877 function isDeclarationKind(kind: SyntaxKind) { 1878 return kind === SyntaxKind.ArrowFunction 1879 || kind === SyntaxKind.BindingElement 1880 || kind === SyntaxKind.ClassDeclaration 1881 || kind === SyntaxKind.ClassExpression 1882 || kind === SyntaxKind.ClassStaticBlockDeclaration 1883 || kind === SyntaxKind.StructDeclaration 1884 || kind === SyntaxKind.AnnotationDeclaration 1885 || kind === SyntaxKind.Constructor 1886 || kind === SyntaxKind.EnumDeclaration 1887 || kind === SyntaxKind.EnumMember 1888 || kind === SyntaxKind.ExportSpecifier 1889 || kind === SyntaxKind.FunctionDeclaration 1890 || kind === SyntaxKind.FunctionExpression 1891 || kind === SyntaxKind.GetAccessor 1892 || kind === SyntaxKind.ImportClause 1893 || kind === SyntaxKind.ImportEqualsDeclaration 1894 || kind === SyntaxKind.ImportSpecifier 1895 || kind === SyntaxKind.InterfaceDeclaration 1896 || kind === SyntaxKind.JsxAttribute 1897 || kind === SyntaxKind.MethodDeclaration 1898 || kind === SyntaxKind.MethodSignature 1899 || kind === SyntaxKind.ModuleDeclaration 1900 || kind === SyntaxKind.NamespaceExportDeclaration 1901 || kind === SyntaxKind.NamespaceImport 1902 || kind === SyntaxKind.NamespaceExport 1903 || kind === SyntaxKind.Parameter 1904 || kind === SyntaxKind.PropertyAssignment 1905 || kind === SyntaxKind.PropertyDeclaration 1906 || kind === SyntaxKind.AnnotationPropertyDeclaration 1907 || kind === SyntaxKind.PropertySignature 1908 || kind === SyntaxKind.SetAccessor 1909 || kind === SyntaxKind.ShorthandPropertyAssignment 1910 || kind === SyntaxKind.TypeAliasDeclaration 1911 || kind === SyntaxKind.TypeParameter 1912 || kind === SyntaxKind.VariableDeclaration 1913 || kind === SyntaxKind.JSDocTypedefTag 1914 || kind === SyntaxKind.JSDocCallbackTag 1915 || kind === SyntaxKind.JSDocPropertyTag; 1916 } 1917 1918 function isDeclarationStatementKind(kind: SyntaxKind) { 1919 return kind === SyntaxKind.FunctionDeclaration 1920 || kind === SyntaxKind.MissingDeclaration 1921 || kind === SyntaxKind.ClassDeclaration 1922 || kind === SyntaxKind.StructDeclaration 1923 || kind === SyntaxKind.AnnotationDeclaration 1924 || kind === SyntaxKind.InterfaceDeclaration 1925 || kind === SyntaxKind.TypeAliasDeclaration 1926 || kind === SyntaxKind.EnumDeclaration 1927 || kind === SyntaxKind.ModuleDeclaration 1928 || kind === SyntaxKind.ImportDeclaration 1929 || kind === SyntaxKind.ImportEqualsDeclaration 1930 || kind === SyntaxKind.ExportDeclaration 1931 || kind === SyntaxKind.ExportAssignment 1932 || kind === SyntaxKind.NamespaceExportDeclaration; 1933 } 1934 1935 function isStatementKindButNotDeclarationKind(kind: SyntaxKind) { 1936 return kind === SyntaxKind.BreakStatement 1937 || kind === SyntaxKind.ContinueStatement 1938 || kind === SyntaxKind.DebuggerStatement 1939 || kind === SyntaxKind.DoStatement 1940 || kind === SyntaxKind.ExpressionStatement 1941 || kind === SyntaxKind.EmptyStatement 1942 || kind === SyntaxKind.ForInStatement 1943 || kind === SyntaxKind.ForOfStatement 1944 || kind === SyntaxKind.ForStatement 1945 || kind === SyntaxKind.IfStatement 1946 || kind === SyntaxKind.LabeledStatement 1947 || kind === SyntaxKind.ReturnStatement 1948 || kind === SyntaxKind.SwitchStatement 1949 || kind === SyntaxKind.ThrowStatement 1950 || kind === SyntaxKind.TryStatement 1951 || kind === SyntaxKind.VariableStatement 1952 || kind === SyntaxKind.WhileStatement 1953 || kind === SyntaxKind.WithStatement 1954 || kind === SyntaxKind.NotEmittedStatement 1955 || kind === SyntaxKind.EndOfDeclarationMarker 1956 || kind === SyntaxKind.MergeDeclarationMarker; 1957 } 1958 1959 /* @internal */ 1960 export function isDeclaration(node: Node): node is NamedDeclaration { 1961 if (node.kind === SyntaxKind.TypeParameter) { 1962 return (node.parent && node.parent.kind !== SyntaxKind.JSDocTemplateTag) || isInJSFile(node); 1963 } 1964 1965 return isDeclarationKind(node.kind); 1966 } 1967 1968 /* @internal */ 1969 export function isDeclarationStatement(node: Node): node is DeclarationStatement { 1970 return isDeclarationStatementKind(node.kind); 1971 } 1972 1973 /** 1974 * Determines whether the node is a statement that is not also a declaration 1975 */ 1976 /* @internal */ 1977 export function isStatementButNotDeclaration(node: Node): node is Statement { 1978 return isStatementKindButNotDeclarationKind(node.kind); 1979 } 1980 1981 /* @internal */ 1982 export function isStatement(node: Node): node is Statement { 1983 const kind = node.kind; 1984 return isStatementKindButNotDeclarationKind(kind) 1985 || isDeclarationStatementKind(kind) 1986 || isBlockStatement(node); 1987 } 1988 1989 function isBlockStatement(node: Node): node is Block { 1990 if (node.kind !== SyntaxKind.Block) return false; 1991 if (node.parent !== undefined) { 1992 if (node.parent.kind === SyntaxKind.TryStatement || node.parent.kind === SyntaxKind.CatchClause) { 1993 return false; 1994 } 1995 } 1996 return !isFunctionBlock(node); 1997 } 1998 1999 /** 2000 * NOTE: This is similar to `isStatement` but does not access parent pointers. 2001 */ 2002 /* @internal */ 2003 export function isStatementOrBlock(node: Node): node is Statement | Block { 2004 const kind = node.kind; 2005 return isStatementKindButNotDeclarationKind(kind) 2006 || isDeclarationStatementKind(kind) 2007 || kind === SyntaxKind.Block; 2008 } 2009 2010 // Module references 2011 2012 /* @internal */ 2013 export function isModuleReference(node: Node): node is ModuleReference { 2014 const kind = node.kind; 2015 return kind === SyntaxKind.ExternalModuleReference 2016 || kind === SyntaxKind.QualifiedName 2017 || kind === SyntaxKind.Identifier; 2018 } 2019 2020 // JSX 2021 2022 /* @internal */ 2023 export function isJsxTagNameExpression(node: Node): node is JsxTagNameExpression { 2024 const kind = node.kind; 2025 return kind === SyntaxKind.ThisKeyword 2026 || kind === SyntaxKind.Identifier 2027 || kind === SyntaxKind.PropertyAccessExpression; 2028 } 2029 2030 /* @internal */ 2031 export function isJsxChild(node: Node): node is JsxChild { 2032 const kind = node.kind; 2033 return kind === SyntaxKind.JsxElement 2034 || kind === SyntaxKind.JsxExpression 2035 || kind === SyntaxKind.JsxSelfClosingElement 2036 || kind === SyntaxKind.JsxText 2037 || kind === SyntaxKind.JsxFragment; 2038 } 2039 2040 /* @internal */ 2041 export function isJsxAttributeLike(node: Node): node is JsxAttributeLike { 2042 const kind = node.kind; 2043 return kind === SyntaxKind.JsxAttribute 2044 || kind === SyntaxKind.JsxSpreadAttribute; 2045 } 2046 2047 /* @internal */ 2048 export function isStringLiteralOrJsxExpression(node: Node): node is StringLiteral | JsxExpression { 2049 const kind = node.kind; 2050 return kind === SyntaxKind.StringLiteral 2051 || kind === SyntaxKind.JsxExpression; 2052 } 2053 2054 export function isJsxOpeningLikeElement(node: Node): node is JsxOpeningLikeElement { 2055 const kind = node.kind; 2056 return kind === SyntaxKind.JsxOpeningElement 2057 || kind === SyntaxKind.JsxSelfClosingElement; 2058 } 2059 2060 // Clauses 2061 2062 export function isCaseOrDefaultClause(node: Node): node is CaseOrDefaultClause { 2063 const kind = node.kind; 2064 return kind === SyntaxKind.CaseClause 2065 || kind === SyntaxKind.DefaultClause; 2066 } 2067 2068 // JSDoc 2069 2070 /** True if node is of some JSDoc syntax kind. */ 2071 /* @internal */ 2072 export function isJSDocNode(node: Node): boolean { 2073 return node.kind >= SyntaxKind.FirstJSDocNode && node.kind <= SyntaxKind.LastJSDocNode; 2074 } 2075 2076 /** True if node is of a kind that may contain comment text. */ 2077 export function isJSDocCommentContainingNode(node: Node): boolean { 2078 return node.kind === SyntaxKind.JSDoc 2079 || node.kind === SyntaxKind.JSDocNamepathType 2080 || node.kind === SyntaxKind.JSDocText 2081 || isJSDocLinkLike(node) 2082 || isJSDocTag(node) 2083 || isJSDocTypeLiteral(node) 2084 || isJSDocSignature(node); 2085 } 2086 2087 // TODO: determine what this does before making it public. 2088 /* @internal */ 2089 export function isJSDocTag(node: Node): node is JSDocTag { 2090 return node.kind >= SyntaxKind.FirstJSDocTagNode && node.kind <= SyntaxKind.LastJSDocTagNode; 2091 } 2092 2093 export function isSetAccessor(node: Node): node is SetAccessorDeclaration { 2094 return node.kind === SyntaxKind.SetAccessor; 2095 } 2096 2097 export function isGetAccessor(node: Node): node is GetAccessorDeclaration { 2098 return node.kind === SyntaxKind.GetAccessor; 2099 } 2100 2101 /** True if has jsdoc nodes attached to it. */ 2102 /* @internal */ 2103 // TODO: GH#19856 Would like to return `node is Node & { jsDoc: JSDoc[] }` but it causes long compile times 2104 export function hasJSDocNodes(node: Node): node is HasJSDoc { 2105 const { jsDoc } = node as JSDocContainer; 2106 return !!jsDoc && jsDoc.length > 0; 2107 } 2108 2109 /** True if has type node attached to it. */ 2110 /* @internal */ 2111 export function hasType(node: Node): node is HasType { 2112 return !!(node as HasType).type; 2113 } 2114 2115 /** True if has initializer node attached to it. */ 2116 /* @internal */ 2117 export function hasInitializer(node: Node): node is HasInitializer { 2118 return !!(node as HasInitializer).initializer; 2119 } 2120 2121 /** True if has initializer node attached to it. */ 2122 export function hasOnlyExpressionInitializer(node: Node): node is HasExpressionInitializer { 2123 switch (node.kind) { 2124 case SyntaxKind.VariableDeclaration: 2125 case SyntaxKind.Parameter: 2126 case SyntaxKind.BindingElement: 2127 case SyntaxKind.PropertyDeclaration: 2128 case SyntaxKind.AnnotationPropertyDeclaration: 2129 case SyntaxKind.PropertyAssignment: 2130 case SyntaxKind.EnumMember: 2131 return true; 2132 default: 2133 return false; 2134 } 2135 } 2136 2137 export function isObjectLiteralElement(node: Node): node is ObjectLiteralElement { 2138 return node.kind === SyntaxKind.JsxAttribute || node.kind === SyntaxKind.JsxSpreadAttribute || isObjectLiteralElementLike(node); 2139 } 2140 2141 /* @internal */ 2142 export function isTypeReferenceType(node: Node): node is TypeReferenceType { 2143 return node.kind === SyntaxKind.TypeReference || node.kind === SyntaxKind.ExpressionWithTypeArguments; 2144 } 2145 2146 const MAX_SMI_X86 = 0x3fff_ffff; 2147 /* @internal */ 2148 export function guessIndentation(lines: string[]) { 2149 let indentation = MAX_SMI_X86; 2150 for (const line of lines) { 2151 if (!line.length) { 2152 continue; 2153 } 2154 let i = 0; 2155 for (; i < line.length && i < indentation; i++) { 2156 if (!isWhiteSpaceLike(line.charCodeAt(i))) { 2157 break; 2158 } 2159 } 2160 if (i < indentation) { 2161 indentation = i; 2162 } 2163 if (indentation === 0) { 2164 return 0; 2165 } 2166 } 2167 return indentation === MAX_SMI_X86 ? undefined : indentation; 2168 } 2169 2170 export function isStringLiteralLike(node: Node): node is StringLiteralLike { 2171 return node.kind === SyntaxKind.StringLiteral || node.kind === SyntaxKind.NoSubstitutionTemplateLiteral; 2172 } 2173 2174 export function isJSDocLinkLike(node: Node): node is JSDocLink | JSDocLinkCode | JSDocLinkPlain { 2175 return node.kind === SyntaxKind.JSDocLink || node.kind === SyntaxKind.JSDocLinkCode || node.kind === SyntaxKind.JSDocLinkPlain; 2176 } 2177 2178 export function hasRestParameter(s: SignatureDeclaration | JSDocSignature): boolean { 2179 const last = lastOrUndefined<ParameterDeclaration | JSDocParameterTag>(s.parameters); 2180 return !!last && isRestParameter(last); 2181 } 2182 2183 export function isRestParameter(node: ParameterDeclaration | JSDocParameterTag): boolean { 2184 const type = isJSDocParameterTag(node) ? (node.typeExpression && node.typeExpression.type) : node.type; 2185 return (node as ParameterDeclaration).dotDotDotToken !== undefined || !!type && type.kind === SyntaxKind.JSDocVariadicType; 2186 } 2187 2188 // #endregion 2189} 2190