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