1/* @internal */ 2namespace ts { 3 export enum LogLevel { 4 Off, 5 Error, 6 Warning, 7 Info, 8 Verbose 9 } 10 11 export interface LoggingHost { 12 log(level: LogLevel, s: string): void; 13 } 14 15 export interface DeprecationOptions { 16 message?: string; 17 error?: boolean; 18 since?: Version | string; 19 warnAfter?: Version | string; 20 errorAfter?: Version | string; 21 typeScriptVersion?: Version | string; 22 } 23 24 export namespace Debug { 25 let typeScriptVersion: Version | undefined; 26 27 /* eslint-disable prefer-const */ 28 let currentAssertionLevel = AssertionLevel.None; 29 export let currentLogLevel = LogLevel.Warning; 30 export let isDebugging = false; 31 export let loggingHost: LoggingHost | undefined; 32 /* eslint-enable prefer-const */ 33 34 type AssertionKeys = MatchingKeys<typeof Debug, AnyFunction>; 35 export function getTypeScriptVersion() { 36 return typeScriptVersion ?? (typeScriptVersion = new Version(version)); 37 } 38 39 export function shouldLog(level: LogLevel): boolean { 40 return currentLogLevel <= level; 41 } 42 43 function logMessage(level: LogLevel, s: string): void { 44 if (loggingHost && shouldLog(level)) { 45 loggingHost.log(level, s); 46 } 47 } 48 49 export function log(s: string): void { 50 logMessage(LogLevel.Info, s); 51 } 52 53 export namespace log { 54 export function error(s: string): void { 55 logMessage(LogLevel.Error, s); 56 } 57 58 export function warn(s: string): void { 59 logMessage(LogLevel.Warning, s); 60 } 61 62 export function log(s: string): void { 63 logMessage(LogLevel.Info, s); 64 } 65 66 export function trace(s: string): void { 67 logMessage(LogLevel.Verbose, s); 68 } 69 } 70 71 const assertionCache: Partial<Record<AssertionKeys, { level: AssertionLevel, assertion: AnyFunction }>> = {}; 72 73 export function getAssertionLevel() { 74 return currentAssertionLevel; 75 } 76 77 export function setAssertionLevel(level: AssertionLevel) { 78 const prevAssertionLevel = currentAssertionLevel; 79 currentAssertionLevel = level; 80 81 if (level > prevAssertionLevel) { 82 // restore assertion functions for the current assertion level (see `shouldAssertFunction`). 83 for (const key of getOwnKeys(assertionCache) as AssertionKeys[]) { 84 const cachedFunc = assertionCache[key]; 85 if (cachedFunc !== undefined && Debug[key] !== cachedFunc.assertion && level >= cachedFunc.level) { 86 (Debug as any)[key] = cachedFunc; 87 assertionCache[key] = undefined; 88 } 89 } 90 } 91 } 92 93 export function shouldAssert(level: AssertionLevel): boolean { 94 return currentAssertionLevel >= level; 95 } 96 97 /** 98 * Tests whether an assertion function should be executed. If it shouldn't, it is cached and replaced with `ts.noop`. 99 * Replaced assertion functions are restored when `Debug.setAssertionLevel` is set to a high enough level. 100 * @param level The minimum assertion level required. 101 * @param name The name of the current assertion function. 102 */ 103 function shouldAssertFunction<K extends AssertionKeys>(level: AssertionLevel, name: K): boolean { 104 if (!shouldAssert(level)) { 105 assertionCache[name] = { level, assertion: Debug[name] }; 106 (Debug as any)[name] = noop; 107 return false; 108 } 109 return true; 110 } 111 112 export function fail(message?: string, stackCrawlMark?: AnyFunction): never { 113 debugger; 114 const e = new Error(message ? `Debug Failure. ${message}` : "Debug Failure."); 115 if ((<any>Error).captureStackTrace) { 116 (<any>Error).captureStackTrace(e, stackCrawlMark || fail); 117 } 118 throw e; 119 } 120 121 export function failBadSyntaxKind(node: Node, message?: string, stackCrawlMark?: AnyFunction): never { 122 return fail( 123 `${message || "Unexpected node."}\r\nNode ${formatSyntaxKind(node.kind)} was unexpected.`, 124 stackCrawlMark || failBadSyntaxKind); 125 } 126 127 export function assert(expression: unknown, message?: string, verboseDebugInfo?: string | (() => string), stackCrawlMark?: AnyFunction): asserts expression { 128 if (!expression) { 129 message = message ? `False expression: ${message}` : "False expression."; 130 if (verboseDebugInfo) { 131 message += "\r\nVerbose Debug Information: " + (typeof verboseDebugInfo === "string" ? verboseDebugInfo : verboseDebugInfo()); 132 } 133 fail(message, stackCrawlMark || assert); 134 } 135 } 136 137 export function assertEqual<T>(a: T, b: T, msg?: string, msg2?: string, stackCrawlMark?: AnyFunction): void { 138 if (a !== b) { 139 const message = msg ? msg2 ? `${msg} ${msg2}` : msg : ""; 140 fail(`Expected ${a} === ${b}. ${message}`, stackCrawlMark || assertEqual); 141 } 142 } 143 144 export function assertLessThan(a: number, b: number, msg?: string, stackCrawlMark?: AnyFunction): void { 145 if (a >= b) { 146 fail(`Expected ${a} < ${b}. ${msg || ""}`, stackCrawlMark || assertLessThan); 147 } 148 } 149 150 export function assertLessThanOrEqual(a: number, b: number, stackCrawlMark?: AnyFunction): void { 151 if (a > b) { 152 fail(`Expected ${a} <= ${b}`, stackCrawlMark || assertLessThanOrEqual); 153 } 154 } 155 156 export function assertGreaterThanOrEqual(a: number, b: number, stackCrawlMark?: AnyFunction): void { 157 if (a < b) { 158 fail(`Expected ${a} >= ${b}`, stackCrawlMark || assertGreaterThanOrEqual); 159 } 160 } 161 162 export function assertIsDefined<T>(value: T, message?: string, stackCrawlMark?: AnyFunction): asserts value is NonNullable<T> { 163 // eslint-disable-next-line no-null/no-null 164 if (value === undefined || value === null) { 165 fail(message, stackCrawlMark || assertIsDefined); 166 } 167 } 168 169 export function checkDefined<T>(value: T | null | undefined, message?: string, stackCrawlMark?: AnyFunction): T { 170 assertIsDefined(value, message, stackCrawlMark || checkDefined); 171 return value; 172 } 173 174 /** 175 * @deprecated Use `checkDefined` to check whether a value is defined inline. Use `assertIsDefined` to check whether 176 * a value is defined at the statement level. 177 */ 178 export const assertDefined = checkDefined; 179 180 export function assertEachIsDefined<T extends Node>(value: NodeArray<T>, message?: string, stackCrawlMark?: AnyFunction): asserts value is NodeArray<T>; 181 export function assertEachIsDefined<T>(value: readonly T[], message?: string, stackCrawlMark?: AnyFunction): asserts value is readonly NonNullable<T>[]; 182 export function assertEachIsDefined<T>(value: readonly T[], message?: string, stackCrawlMark?: AnyFunction) { 183 for (const v of value) { 184 assertIsDefined(v, message, stackCrawlMark || assertEachIsDefined); 185 } 186 } 187 188 export function checkEachDefined<T, A extends readonly T[]>(value: A, message?: string, stackCrawlMark?: AnyFunction): A { 189 assertEachIsDefined(value, message, stackCrawlMark || checkEachDefined); 190 return value; 191 } 192 193 /** 194 * @deprecated Use `checkEachDefined` to check whether the elements of an array are defined inline. Use `assertEachIsDefined` to check whether 195 * the elements of an array are defined at the statement level. 196 */ 197 export const assertEachDefined = checkEachDefined; 198 199 export function assertNever(member: never, message = "Illegal value:", stackCrawlMark?: AnyFunction): never { 200 const detail = typeof member === "object" && hasProperty(member, "kind") && hasProperty(member, "pos") && formatSyntaxKind ? "SyntaxKind: " + formatSyntaxKind((member as Node).kind) : JSON.stringify(member); 201 return fail(`${message} ${detail}`, stackCrawlMark || assertNever); 202 } 203 204 export function assertEachNode<T extends Node, U extends T>(nodes: NodeArray<T>, test: (node: T) => node is U, message?: string, stackCrawlMark?: AnyFunction): asserts nodes is NodeArray<U>; 205 export function assertEachNode<T extends Node, U extends T>(nodes: readonly T[], test: (node: T) => node is U, message?: string, stackCrawlMark?: AnyFunction): asserts nodes is readonly U[]; 206 export function assertEachNode(nodes: readonly Node[], test: (node: Node) => boolean, message?: string, stackCrawlMark?: AnyFunction): void; 207 export function assertEachNode(nodes: readonly Node[], test: (node: Node) => boolean, message?: string, stackCrawlMark?: AnyFunction) { 208 if (shouldAssertFunction(AssertionLevel.Normal, "assertEachNode")) { 209 assert( 210 test === undefined || every(nodes, test), 211 message || "Unexpected node.", 212 () => `Node array did not pass test '${getFunctionName(test)}'.`, 213 stackCrawlMark || assertEachNode); 214 } 215 } 216 217 export function assertNode<T extends Node, U extends T>(node: T | undefined, test: (node: T) => node is U, message?: string, stackCrawlMark?: AnyFunction): asserts node is U; 218 export function assertNode(node: Node | undefined, test: ((node: Node) => boolean) | undefined, message?: string, stackCrawlMark?: AnyFunction): void; 219 export function assertNode(node: Node | undefined, test: ((node: Node) => boolean) | undefined, message?: string, stackCrawlMark?: AnyFunction) { 220 if (shouldAssertFunction(AssertionLevel.Normal, "assertNode")) { 221 assert( 222 node !== undefined && (test === undefined || test(node)), 223 message || "Unexpected node.", 224 () => `Node ${formatSyntaxKind(node!.kind)} did not pass test '${getFunctionName(test!)}'.`, 225 stackCrawlMark || assertNode); 226 } 227 } 228 229 export function assertNotNode<T extends Node, U extends T>(node: T | undefined, test: (node: Node) => node is U, message?: string, stackCrawlMark?: AnyFunction): asserts node is Exclude<T, U>; 230 export function assertNotNode(node: Node | undefined, test: ((node: Node) => boolean) | undefined, message?: string, stackCrawlMark?: AnyFunction): void; 231 export function assertNotNode(node: Node | undefined, test: ((node: Node) => boolean) | undefined, message?: string, stackCrawlMark?: AnyFunction) { 232 if (shouldAssertFunction(AssertionLevel.Normal, "assertNotNode")) { 233 assert( 234 node === undefined || test === undefined || !test(node), 235 message || "Unexpected node.", 236 () => `Node ${formatSyntaxKind(node!.kind)} should not have passed test '${getFunctionName(test!)}'.`, 237 stackCrawlMark || assertNotNode); 238 } 239 } 240 241 export function assertOptionalNode<T extends Node, U extends T>(node: T, test: (node: T) => node is U, message?: string, stackCrawlMark?: AnyFunction): asserts node is U; 242 export function assertOptionalNode<T extends Node, U extends T>(node: T | undefined, test: (node: T) => node is U, message?: string, stackCrawlMark?: AnyFunction): asserts node is U | undefined; 243 export function assertOptionalNode(node: Node | undefined, test: ((node: Node) => boolean) | undefined, message?: string, stackCrawlMark?: AnyFunction): void; 244 export function assertOptionalNode(node: Node | undefined, test: ((node: Node) => boolean) | undefined, message?: string, stackCrawlMark?: AnyFunction) { 245 if (shouldAssertFunction(AssertionLevel.Normal, "assertOptionalNode")) { 246 assert( 247 test === undefined || node === undefined || test(node), 248 message || "Unexpected node.", 249 () => `Node ${formatSyntaxKind(node!.kind)} did not pass test '${getFunctionName(test!)}'.`, 250 stackCrawlMark || assertOptionalNode); 251 } 252 } 253 254 export function assertOptionalToken<T extends Node, K extends SyntaxKind>(node: T, kind: K, message?: string, stackCrawlMark?: AnyFunction): asserts node is Extract<T, { readonly kind: K }>; 255 export function assertOptionalToken<T extends Node, K extends SyntaxKind>(node: T | undefined, kind: K, message?: string, stackCrawlMark?: AnyFunction): asserts node is Extract<T, { readonly kind: K }> | undefined; 256 export function assertOptionalToken(node: Node | undefined, kind: SyntaxKind | undefined, message?: string, stackCrawlMark?: AnyFunction): void; 257 export function assertOptionalToken(node: Node | undefined, kind: SyntaxKind | undefined, message?: string, stackCrawlMark?: AnyFunction) { 258 if (shouldAssertFunction(AssertionLevel.Normal, "assertOptionalToken")) { 259 assert( 260 kind === undefined || node === undefined || node.kind === kind, 261 message || "Unexpected node.", 262 () => `Node ${formatSyntaxKind(node!.kind)} was not a '${formatSyntaxKind(kind)}' token.`, 263 stackCrawlMark || assertOptionalToken); 264 } 265 } 266 267 export function assertMissingNode(node: Node | undefined, message?: string, stackCrawlMark?: AnyFunction): asserts node is undefined; 268 export function assertMissingNode(node: Node | undefined, message?: string, stackCrawlMark?: AnyFunction) { 269 if (shouldAssertFunction(AssertionLevel.Normal, "assertMissingNode")) { 270 assert( 271 node === undefined, 272 message || "Unexpected node.", 273 () => `Node ${formatSyntaxKind(node!.kind)} was unexpected'.`, 274 stackCrawlMark || assertMissingNode); 275 } 276 } 277 278 export function getFunctionName(func: AnyFunction) { 279 if (typeof func !== "function") { 280 return ""; 281 } 282 else if (func.hasOwnProperty("name")) { 283 return (<any>func).name; 284 } 285 else { 286 const text = Function.prototype.toString.call(func); 287 const match = /^function\s+([\w\$]+)\s*\(/.exec(text); 288 return match ? match[1] : ""; 289 } 290 } 291 292 export function formatSymbol(symbol: Symbol): string { 293 return `{ name: ${unescapeLeadingUnderscores(symbol.escapedName)}; flags: ${formatSymbolFlags(symbol.flags)}; declarations: ${map(symbol.declarations, node => formatSyntaxKind(node.kind))} }`; 294 } 295 296 /** 297 * Formats an enum value as a string for debugging and debug assertions. 298 */ 299 export function formatEnum(value = 0, enumObject: any, isFlags?: boolean) { 300 const members = getEnumMembers(enumObject); 301 if (value === 0) { 302 return members.length > 0 && members[0][0] === 0 ? members[0][1] : "0"; 303 } 304 if (isFlags) { 305 let result = ""; 306 let remainingFlags = value; 307 for (const [enumValue, enumName] of members) { 308 if (enumValue > value) { 309 break; 310 } 311 if (enumValue !== 0 && enumValue & value) { 312 result = `${result}${result ? "|" : ""}${enumName}`; 313 remainingFlags &= ~enumValue; 314 } 315 } 316 if (remainingFlags === 0) { 317 return result; 318 } 319 } 320 else { 321 for (const [enumValue, enumName] of members) { 322 if (enumValue === value) { 323 return enumName; 324 } 325 } 326 } 327 return value.toString(); 328 } 329 330 function getEnumMembers(enumObject: any) { 331 const result: [number, string][] = []; 332 for (const name in enumObject) { 333 const value = enumObject[name]; 334 if (typeof value === "number") { 335 result.push([value, name]); 336 } 337 } 338 339 return stableSort<[number, string]>(result, (x, y) => compareValues(x[0], y[0])); 340 } 341 342 export function formatSyntaxKind(kind: SyntaxKind | undefined): string { 343 return formatEnum(kind, (<any>ts).SyntaxKind, /*isFlags*/ false); 344 } 345 346 export function formatNodeFlags(flags: NodeFlags | undefined): string { 347 return formatEnum(flags, (<any>ts).NodeFlags, /*isFlags*/ true); 348 } 349 350 export function formatModifierFlags(flags: ModifierFlags | undefined): string { 351 return formatEnum(flags, (<any>ts).ModifierFlags, /*isFlags*/ true); 352 } 353 354 export function formatTransformFlags(flags: TransformFlags | undefined): string { 355 return formatEnum(flags, (<any>ts).TransformFlags, /*isFlags*/ true); 356 } 357 358 export function formatEmitFlags(flags: EmitFlags | undefined): string { 359 return formatEnum(flags, (<any>ts).EmitFlags, /*isFlags*/ true); 360 } 361 362 export function formatSymbolFlags(flags: SymbolFlags | undefined): string { 363 return formatEnum(flags, (<any>ts).SymbolFlags, /*isFlags*/ true); 364 } 365 366 export function formatTypeFlags(flags: TypeFlags | undefined): string { 367 return formatEnum(flags, (<any>ts).TypeFlags, /*isFlags*/ true); 368 } 369 370 export function formatSignatureFlags(flags: SignatureFlags | undefined): string { 371 return formatEnum(flags, (<any>ts).SignatureFlags, /*isFlags*/ true); 372 } 373 374 export function formatObjectFlags(flags: ObjectFlags | undefined): string { 375 return formatEnum(flags, (<any>ts).ObjectFlags, /*isFlags*/ true); 376 } 377 378 export function formatFlowFlags(flags: FlowFlags | undefined): string { 379 return formatEnum(flags, (<any>ts).FlowFlags, /*isFlags*/ true); 380 } 381 382 let isDebugInfoEnabled = false; 383 384 interface ExtendedDebugModule { 385 init(_ts: typeof ts): void; 386 formatControlFlowGraph(flowNode: FlowNode): string; 387 } 388 389 let extendedDebugModule: ExtendedDebugModule | undefined; 390 391 function extendedDebug() { 392 enableDebugInfo(); 393 if (!extendedDebugModule) { 394 throw new Error("Debugging helpers could not be loaded."); 395 } 396 return extendedDebugModule; 397 } 398 399 export function printControlFlowGraph(flowNode: FlowNode) { 400 return console.log(formatControlFlowGraph(flowNode)); 401 } 402 403 export function formatControlFlowGraph(flowNode: FlowNode) { 404 return extendedDebug().formatControlFlowGraph(flowNode); 405 } 406 407 let flowNodeProto: FlowNodeBase | undefined; 408 409 function attachFlowNodeDebugInfoWorker(flowNode: FlowNodeBase) { 410 if (!("__debugFlowFlags" in flowNode)) { // eslint-disable-line no-in-operator 411 Object.defineProperties(flowNode, { 412 // for use with vscode-js-debug's new customDescriptionGenerator in launch.json 413 __tsDebuggerDisplay: { 414 value(this: FlowNodeBase) { 415 const flowHeader = 416 this.flags & FlowFlags.Start ? "FlowStart" : 417 this.flags & FlowFlags.BranchLabel ? "FlowBranchLabel" : 418 this.flags & FlowFlags.LoopLabel ? "FlowLoopLabel" : 419 this.flags & FlowFlags.Assignment ? "FlowAssignment" : 420 this.flags & FlowFlags.TrueCondition ? "FlowTrueCondition" : 421 this.flags & FlowFlags.FalseCondition ? "FlowFalseCondition" : 422 this.flags & FlowFlags.SwitchClause ? "FlowSwitchClause" : 423 this.flags & FlowFlags.ArrayMutation ? "FlowArrayMutation" : 424 this.flags & FlowFlags.Call ? "FlowCall" : 425 this.flags & FlowFlags.ReduceLabel ? "FlowReduceLabel" : 426 this.flags & FlowFlags.Unreachable ? "FlowUnreachable" : 427 "UnknownFlow"; 428 const remainingFlags = this.flags & ~(FlowFlags.Referenced - 1); 429 return `${flowHeader}${remainingFlags ? ` (${formatFlowFlags(remainingFlags)})`: ""}`; 430 } 431 }, 432 __debugFlowFlags: { get(this: FlowNodeBase) { return formatEnum(this.flags, (ts as any).FlowFlags, /*isFlags*/ true); } }, 433 __debugToString: { value(this: FlowNodeBase) { return formatControlFlowGraph(this); } } 434 }); 435 } 436 } 437 438 export function attachFlowNodeDebugInfo(flowNode: FlowNodeBase) { 439 if (isDebugInfoEnabled) { 440 if (typeof Object.setPrototypeOf === "function") { 441 // if we're in es2015, attach the method to a shared prototype for `FlowNode` 442 // so the method doesn't show up in the watch window. 443 if (!flowNodeProto) { 444 flowNodeProto = Object.create(Object.prototype) as FlowNodeBase; 445 attachFlowNodeDebugInfoWorker(flowNodeProto); 446 } 447 Object.setPrototypeOf(flowNode, flowNodeProto); 448 } 449 else { 450 // not running in an es2015 environment, attach the method directly. 451 attachFlowNodeDebugInfoWorker(flowNode); 452 } 453 } 454 } 455 456 let nodeArrayProto: NodeArray<Node> | undefined; 457 458 function attachNodeArrayDebugInfoWorker(array: NodeArray<Node>) { 459 if (!("__tsDebuggerDisplay" in array)) { // eslint-disable-line no-in-operator 460 Object.defineProperties(array, { 461 __tsDebuggerDisplay: { 462 value(this: NodeArray<Node>, defaultValue: string) { 463 // An `Array` with extra properties is rendered as `[A, B, prop1: 1, prop2: 2]`. Most of 464 // these aren't immediately useful so we trim off the `prop1: ..., prop2: ...` part from the 465 // formatted string. 466 defaultValue = String(defaultValue).replace(/(?:,[\s\w\d_]+:[^,]+)+\]$/, "]"); 467 return `NodeArray ${defaultValue}`; 468 } 469 } 470 }); 471 } 472 } 473 474 export function attachNodeArrayDebugInfo(array: NodeArray<Node>) { 475 if (isDebugInfoEnabled) { 476 if (typeof Object.setPrototypeOf === "function") { 477 // if we're in es2015, attach the method to a shared prototype for `NodeArray` 478 // so the method doesn't show up in the watch window. 479 if (!nodeArrayProto) { 480 nodeArrayProto = Object.create(Array.prototype) as NodeArray<Node>; 481 attachNodeArrayDebugInfoWorker(nodeArrayProto); 482 } 483 Object.setPrototypeOf(array, nodeArrayProto); 484 } 485 else { 486 // not running in an es2015 environment, attach the method directly. 487 attachNodeArrayDebugInfoWorker(array); 488 } 489 } 490 } 491 492 /** 493 * Injects debug information into frequently used types. 494 */ 495 export function enableDebugInfo() { 496 if (isDebugInfoEnabled) return; 497 498 // avoid recomputing 499 let weakTypeTextMap: WeakMap<Type, string> | undefined; 500 let weakNodeTextMap: WeakMap<Node, string> | undefined; 501 502 function getWeakTypeTextMap() { 503 if (weakTypeTextMap === undefined) { 504 if (typeof WeakMap === "function") weakTypeTextMap = new WeakMap(); 505 } 506 return weakTypeTextMap; 507 } 508 509 function getWeakNodeTextMap() { 510 if (weakNodeTextMap === undefined) { 511 if (typeof WeakMap === "function") weakNodeTextMap = new WeakMap(); 512 } 513 return weakNodeTextMap; 514 } 515 516 517 // Add additional properties in debug mode to assist with debugging. 518 Object.defineProperties(objectAllocator.getSymbolConstructor().prototype, { 519 // for use with vscode-js-debug's new customDescriptionGenerator in launch.json 520 __tsDebuggerDisplay: { 521 value(this: Symbol) { 522 const symbolHeader = 523 this.flags & SymbolFlags.Transient ? "TransientSymbol" : 524 "Symbol"; 525 const remainingSymbolFlags = this.flags & ~SymbolFlags.Transient; 526 return `${symbolHeader} '${symbolName(this)}'${remainingSymbolFlags ? ` (${formatSymbolFlags(remainingSymbolFlags)})` : ""}`; 527 } 528 }, 529 __debugFlags: { get(this: Symbol) { return formatSymbolFlags(this.flags); } } 530 }); 531 532 Object.defineProperties(objectAllocator.getTypeConstructor().prototype, { 533 // for use with vscode-js-debug's new customDescriptionGenerator in launch.json 534 __tsDebuggerDisplay: { 535 value(this: Type) { 536 const typeHeader = 537 this.flags & TypeFlags.Nullable ? "NullableType" : 538 this.flags & TypeFlags.StringOrNumberLiteral ? `LiteralType ${JSON.stringify((this as LiteralType).value)}` : 539 this.flags & TypeFlags.BigIntLiteral ? `LiteralType ${(this as BigIntLiteralType).value.negative ? "-" : ""}${(this as BigIntLiteralType).value.base10Value}n` : 540 this.flags & TypeFlags.UniqueESSymbol ? "UniqueESSymbolType" : 541 this.flags & TypeFlags.Enum ? "EnumType" : 542 this.flags & TypeFlags.Intrinsic ? `IntrinsicType ${(this as IntrinsicType).intrinsicName}` : 543 this.flags & TypeFlags.Union ? "UnionType" : 544 this.flags & TypeFlags.Intersection ? "IntersectionType" : 545 this.flags & TypeFlags.Index ? "IndexType" : 546 this.flags & TypeFlags.IndexedAccess ? "IndexedAccessType" : 547 this.flags & TypeFlags.Conditional ? "ConditionalType" : 548 this.flags & TypeFlags.Substitution ? "SubstitutionType" : 549 this.flags & TypeFlags.TypeParameter ? "TypeParameter" : 550 this.flags & TypeFlags.Object ? 551 (this as ObjectType).objectFlags & ObjectFlags.ClassOrInterface ? "InterfaceType" : 552 (this as ObjectType).objectFlags & ObjectFlags.Reference ? "TypeReference" : 553 (this as ObjectType).objectFlags & ObjectFlags.Tuple ? "TupleType" : 554 (this as ObjectType).objectFlags & ObjectFlags.Anonymous ? "AnonymousType" : 555 (this as ObjectType).objectFlags & ObjectFlags.Mapped ? "MappedType" : 556 (this as ObjectType).objectFlags & ObjectFlags.ReverseMapped ? "ReverseMappedType" : 557 (this as ObjectType).objectFlags & ObjectFlags.EvolvingArray ? "EvolvingArrayType" : 558 "ObjectType" : 559 "Type"; 560 const remainingObjectFlags = this.flags & TypeFlags.Object ? (this as ObjectType).objectFlags & ~ObjectFlags.ObjectTypeKindMask : 0; 561 return `${typeHeader}${this.symbol ? ` '${symbolName(this.symbol)}'` : ""}${remainingObjectFlags ? ` (${formatObjectFlags(remainingObjectFlags)})` : ""}`; 562 } 563 }, 564 __debugFlags: { get(this: Type) { return formatTypeFlags(this.flags); } }, 565 __debugObjectFlags: { get(this: Type) { return this.flags & TypeFlags.Object ? formatObjectFlags((<ObjectType>this).objectFlags) : ""; } }, 566 __debugTypeToString: { 567 value(this: Type) { 568 // avoid recomputing 569 const map = getWeakTypeTextMap(); 570 let text = map?.get(this); 571 if (text === undefined) { 572 text = this.checker.typeToString(this); 573 map?.set(this, text); 574 } 575 return text; 576 } 577 }, 578 }); 579 580 Object.defineProperties(objectAllocator.getSignatureConstructor().prototype, { 581 __debugFlags: { get(this: Signature) { return formatSignatureFlags(this.flags); } }, 582 __debugSignatureToString: { value(this: Signature) { return this.checker?.signatureToString(this); } } 583 }); 584 585 const nodeConstructors = [ 586 objectAllocator.getNodeConstructor(), 587 objectAllocator.getIdentifierConstructor(), 588 objectAllocator.getTokenConstructor(), 589 objectAllocator.getSourceFileConstructor() 590 ]; 591 592 for (const ctor of nodeConstructors) { 593 if (!ctor.prototype.hasOwnProperty("__debugKind")) { 594 Object.defineProperties(ctor.prototype, { 595 // for use with vscode-js-debug's new customDescriptionGenerator in launch.json 596 __tsDebuggerDisplay: { 597 value(this: Node) { 598 const nodeHeader = 599 isGeneratedIdentifier(this) ? "GeneratedIdentifier" : 600 isIdentifier(this) ? `Identifier '${idText(this)}'` : 601 isPrivateIdentifier(this) ? `PrivateIdentifier '${idText(this)}'` : 602 isStringLiteral(this) ? `StringLiteral ${JSON.stringify(this.text.length < 10 ? this.text : this.text.slice(10) + "...")}` : 603 isNumericLiteral(this) ? `NumericLiteral ${this.text}` : 604 isBigIntLiteral(this) ? `BigIntLiteral ${this.text}n` : 605 isTypeParameterDeclaration(this) ? "TypeParameterDeclaration" : 606 isParameter(this) ? "ParameterDeclaration" : 607 isConstructorDeclaration(this) ? "ConstructorDeclaration" : 608 isGetAccessorDeclaration(this) ? "GetAccessorDeclaration" : 609 isSetAccessorDeclaration(this) ? "SetAccessorDeclaration" : 610 isCallSignatureDeclaration(this) ? "CallSignatureDeclaration" : 611 isConstructSignatureDeclaration(this) ? "ConstructSignatureDeclaration" : 612 isIndexSignatureDeclaration(this) ? "IndexSignatureDeclaration" : 613 isTypePredicateNode(this) ? "TypePredicateNode" : 614 isTypeReferenceNode(this) ? "TypeReferenceNode" : 615 isFunctionTypeNode(this) ? "FunctionTypeNode" : 616 isConstructorTypeNode(this) ? "ConstructorTypeNode" : 617 isTypeQueryNode(this) ? "TypeQueryNode" : 618 isTypeLiteralNode(this) ? "TypeLiteralNode" : 619 isArrayTypeNode(this) ? "ArrayTypeNode" : 620 isTupleTypeNode(this) ? "TupleTypeNode" : 621 isOptionalTypeNode(this) ? "OptionalTypeNode" : 622 isRestTypeNode(this) ? "RestTypeNode" : 623 isUnionTypeNode(this) ? "UnionTypeNode" : 624 isIntersectionTypeNode(this) ? "IntersectionTypeNode" : 625 isConditionalTypeNode(this) ? "ConditionalTypeNode" : 626 isInferTypeNode(this) ? "InferTypeNode" : 627 isParenthesizedTypeNode(this) ? "ParenthesizedTypeNode" : 628 isThisTypeNode(this) ? "ThisTypeNode" : 629 isTypeOperatorNode(this) ? "TypeOperatorNode" : 630 isIndexedAccessTypeNode(this) ? "IndexedAccessTypeNode" : 631 isMappedTypeNode(this) ? "MappedTypeNode" : 632 isLiteralTypeNode(this) ? "LiteralTypeNode" : 633 isNamedTupleMember(this) ? "NamedTupleMember" : 634 isImportTypeNode(this) ? "ImportTypeNode" : 635 formatSyntaxKind(this.kind); 636 return `${nodeHeader}${this.flags ? ` (${formatNodeFlags(this.flags)})` : ""}`; 637 } 638 }, 639 __debugKind: { get(this: Node) { return formatSyntaxKind(this.kind); } }, 640 __debugNodeFlags: { get(this: Node) { return formatNodeFlags(this.flags); } }, 641 __debugModifierFlags: { get(this: Node) { return formatModifierFlags(getEffectiveModifierFlagsNoCache(this)); } }, 642 __debugTransformFlags: { get(this: Node) { return formatTransformFlags(this.transformFlags); } }, 643 __debugIsParseTreeNode: { get(this: Node) { return isParseTreeNode(this); } }, 644 __debugEmitFlags: { get(this: Node) { return formatEmitFlags(getEmitFlags(this)); } }, 645 __debugGetText: { 646 value(this: Node, includeTrivia?: boolean) { 647 if (nodeIsSynthesized(this)) return ""; 648 // avoid recomputing 649 const map = getWeakNodeTextMap(); 650 let text = map?.get(this); 651 if (text === undefined) { 652 const parseNode = getParseTreeNode(this); 653 const sourceFile = parseNode && getSourceFileOfNode(parseNode); 654 text = sourceFile ? getSourceTextOfNodeFromSourceFile(sourceFile, parseNode!, includeTrivia) : ""; 655 map?.set(this, text); 656 } 657 return text; 658 } 659 } 660 }); 661 } 662 } 663 664 // attempt to load extended debugging information 665 try { 666 if (sys && sys.require) { 667 const basePath = getDirectoryPath(resolvePath(sys.getExecutingFilePath())); 668 const result = sys.require(basePath, "./compiler-debug") as RequireResult<ExtendedDebugModule>; 669 if (!result.error) { 670 result.module.init(ts); 671 extendedDebugModule = result.module; 672 } 673 } 674 } 675 catch { 676 // do nothing 677 } 678 679 isDebugInfoEnabled = true; 680 } 681 682 function formatDeprecationMessage(name: string, error: boolean | undefined, errorAfter: Version | undefined, since: Version | undefined, message: string | undefined) { 683 let deprecationMessage = error ? "DeprecationError: " : "DeprecationWarning: "; 684 deprecationMessage += `'${name}' `; 685 deprecationMessage += since ? `has been deprecated since v${since}` : "is deprecated"; 686 deprecationMessage += error ? " and can no longer be used." : errorAfter ? ` and will no longer be usable after v${errorAfter}.` : "."; 687 deprecationMessage += message ? ` ${formatStringFromArgs(message, [name], 0)}` : ""; 688 return deprecationMessage; 689 } 690 691 function createErrorDeprecation(name: string, errorAfter: Version | undefined, since: Version | undefined, message: string | undefined) { 692 const deprecationMessage = formatDeprecationMessage(name, /*error*/ true, errorAfter, since, message); 693 return () => { 694 throw new TypeError(deprecationMessage); 695 }; 696 } 697 698 function createWarningDeprecation(name: string, errorAfter: Version | undefined, since: Version | undefined, message: string | undefined) { 699 let hasWrittenDeprecation = false; 700 return () => { 701 if (!hasWrittenDeprecation) { 702 log.warn(formatDeprecationMessage(name, /*error*/ false, errorAfter, since, message)); 703 hasWrittenDeprecation = true; 704 } 705 }; 706 } 707 708 function createDeprecation(name: string, options: DeprecationOptions & { error: true }): () => never; 709 function createDeprecation(name: string, options?: DeprecationOptions): () => void; 710 function createDeprecation(name: string, options: DeprecationOptions = {}) { 711 const version = typeof options.typeScriptVersion === "string" ? new Version(options.typeScriptVersion) : options.typeScriptVersion ?? getTypeScriptVersion(); 712 const errorAfter = typeof options.errorAfter === "string" ? new Version(options.errorAfter) : options.errorAfter; 713 const warnAfter = typeof options.warnAfter === "string" ? new Version(options.warnAfter) : options.warnAfter; 714 const since = typeof options.since === "string" ? new Version(options.since) : options.since ?? warnAfter; 715 const error = options.error || errorAfter && version.compareTo(errorAfter) <= 0; 716 const warn = !warnAfter || version.compareTo(warnAfter) >= 0; 717 return error ? createErrorDeprecation(name, errorAfter, since, options.message) : 718 warn ? createWarningDeprecation(name, errorAfter, since, options.message) : 719 noop; 720 } 721 722 function wrapFunction<F extends (...args: any[]) => any>(deprecation: () => void, func: F): F { 723 return function (this: unknown) { 724 deprecation(); 725 return func.apply(this, arguments); 726 } as F; 727 } 728 729 export function deprecate<F extends (...args: any[]) => any>(func: F, options?: DeprecationOptions): F { 730 const deprecation = createDeprecation(getFunctionName(func), options); 731 return wrapFunction(deprecation, func); 732 } 733 } 734} 735