1/* @internal */ 2namespace ts { 3 function getModuleTransformer(moduleKind: ModuleKind): TransformerFactory<SourceFile | Bundle> { 4 switch (moduleKind) { 5 case ModuleKind.ESNext: 6 case ModuleKind.ES2022: 7 case ModuleKind.ES2020: 8 case ModuleKind.ES2015: 9 return transformECMAScriptModule; 10 case ModuleKind.System: 11 return transformSystemModule; 12 case ModuleKind.Node16: 13 case ModuleKind.NodeNext: 14 return transformNodeModule; 15 default: 16 return transformModule; 17 } 18 } 19 20 const enum TransformationState { 21 Uninitialized, 22 Initialized, 23 Completed, 24 Disposed 25 } 26 27 const enum SyntaxKindFeatureFlags { 28 Substitution = 1 << 0, 29 EmitNotifications = 1 << 1, 30 } 31 32 export const noTransformers: EmitTransformers = { scriptTransformers: emptyArray, declarationTransformers: emptyArray }; 33 34 export function getTransformers(compilerOptions: CompilerOptions, customTransformers?: CustomTransformers, emitOnlyDtsFiles?: boolean): EmitTransformers { 35 return { 36 scriptTransformers: getScriptTransformers(compilerOptions, customTransformers, emitOnlyDtsFiles), 37 declarationTransformers: getDeclarationTransformers(customTransformers), 38 }; 39 } 40 41 function getScriptTransformers(compilerOptions: CompilerOptions, customTransformers?: CustomTransformers, emitOnlyDtsFiles?: boolean) { 42 if (emitOnlyDtsFiles) return emptyArray; 43 44 const languageVersion = getEmitScriptTarget(compilerOptions); 45 const moduleKind = getEmitModuleKind(compilerOptions); 46 const transformers: TransformerFactory<SourceFile | Bundle>[] = []; 47 48 addRange(transformers, customTransformers && map(customTransformers.before, wrapScriptTransformerFactory)); 49 50 transformers.push(transformTypeScript); 51 transformers.push(transformLegacyDecorators); 52 transformers.push(transformClassFields); 53 54 if (getJSXTransformEnabled(compilerOptions)) { 55 transformers.push(transformJsx); 56 } 57 58 if (languageVersion < ScriptTarget.ESNext) { 59 transformers.push(transformESNext); 60 } 61 62 if (languageVersion < ScriptTarget.ES2021) { 63 transformers.push(transformES2021); 64 } 65 66 if (languageVersion < ScriptTarget.ES2020) { 67 transformers.push(transformES2020); 68 } 69 70 if (languageVersion < ScriptTarget.ES2019) { 71 transformers.push(transformES2019); 72 } 73 74 if (languageVersion < ScriptTarget.ES2018) { 75 transformers.push(transformES2018); 76 } 77 78 if (languageVersion < ScriptTarget.ES2017) { 79 transformers.push(transformES2017); 80 } 81 82 if (languageVersion < ScriptTarget.ES2016) { 83 transformers.push(transformES2016); 84 } 85 86 if (languageVersion < ScriptTarget.ES2015) { 87 transformers.push(transformES2015); 88 transformers.push(transformGenerators); 89 } 90 91 transformers.push(getModuleTransformer(moduleKind)); 92 93 // The ES5 transformer is last so that it can substitute expressions like `exports.default` 94 // for ES3. 95 if (languageVersion < ScriptTarget.ES5) { 96 transformers.push(transformES5); 97 } 98 99 addRange(transformers, customTransformers && map(customTransformers.after, wrapScriptTransformerFactory)); 100 return transformers; 101 } 102 103 function getDeclarationTransformers(customTransformers?: CustomTransformers) { 104 const transformers: TransformerFactory<SourceFile | Bundle>[] = []; 105 transformers.push(transformDeclarations); 106 addRange(transformers, customTransformers && map(customTransformers.afterDeclarations, wrapDeclarationTransformerFactory)); 107 return transformers; 108 } 109 110 /** 111 * Wrap a custom script or declaration transformer object in a `Transformer` callback with fallback support for transforming bundles. 112 */ 113 function wrapCustomTransformer(transformer: CustomTransformer): Transformer<Bundle | SourceFile> { 114 return node => isBundle(node) ? transformer.transformBundle(node) : transformer.transformSourceFile(node); 115 } 116 117 /** 118 * Wrap a transformer factory that may return a custom script or declaration transformer object. 119 */ 120 function wrapCustomTransformerFactory<T extends SourceFile | Bundle>(transformer: TransformerFactory<T> | CustomTransformerFactory, handleDefault: (context: TransformationContext, tx: Transformer<T>) => Transformer<Bundle | SourceFile>): TransformerFactory<Bundle | SourceFile> { 121 return context => { 122 const customTransformer = transformer(context); 123 return typeof customTransformer === "function" 124 ? handleDefault(context, customTransformer) 125 : wrapCustomTransformer(customTransformer); 126 }; 127 } 128 129 function wrapScriptTransformerFactory(transformer: TransformerFactory<SourceFile> | CustomTransformerFactory): TransformerFactory<Bundle | SourceFile> { 130 return wrapCustomTransformerFactory(transformer, chainBundle); 131 } 132 133 function wrapDeclarationTransformerFactory(transformer: TransformerFactory<Bundle | SourceFile> | CustomTransformerFactory): TransformerFactory<Bundle | SourceFile> { 134 return wrapCustomTransformerFactory(transformer, (_, node) => node); 135 } 136 137 export function noEmitSubstitution(_hint: EmitHint, node: Node) { 138 return node; 139 } 140 141 export function noEmitNotification(hint: EmitHint, node: Node, callback: (hint: EmitHint, node: Node) => void) { 142 callback(hint, node); 143 } 144 145 /** 146 * Transforms an array of SourceFiles by passing them through each transformer. 147 * 148 * @param resolver The emit resolver provided by the checker. 149 * @param host The emit host object used to interact with the file system. 150 * @param options Compiler options to surface in the `TransformationContext`. 151 * @param nodes An array of nodes to transform. 152 * @param transforms An array of `TransformerFactory` callbacks. 153 * @param allowDtsFiles A value indicating whether to allow the transformation of .d.ts files. 154 */ 155 export function transformNodes<T extends Node>(resolver: EmitResolver | undefined, host: EmitHost | undefined, factory: NodeFactory, options: CompilerOptions, nodes: readonly T[], transformers: readonly TransformerFactory<T>[], allowDtsFiles: boolean): TransformationResult<T> { 156 const enabledSyntaxKindFeatures = new Array<SyntaxKindFeatureFlags>(SyntaxKind.Count); 157 let lexicalEnvironmentVariableDeclarations: VariableDeclaration[]; 158 let lexicalEnvironmentFunctionDeclarations: FunctionDeclaration[]; 159 let lexicalEnvironmentStatements: Statement[]; 160 let lexicalEnvironmentFlags = LexicalEnvironmentFlags.None; 161 let lexicalEnvironmentVariableDeclarationsStack: VariableDeclaration[][] = []; 162 let lexicalEnvironmentFunctionDeclarationsStack: FunctionDeclaration[][] = []; 163 let lexicalEnvironmentStatementsStack: Statement[][] = []; 164 let lexicalEnvironmentFlagsStack: LexicalEnvironmentFlags[] = []; 165 let lexicalEnvironmentStackOffset = 0; 166 let lexicalEnvironmentSuspended = false; 167 let blockScopedVariableDeclarationsStack: Identifier[][] = []; 168 let blockScopeStackOffset = 0; 169 let blockScopedVariableDeclarations: Identifier[]; 170 let emitHelpers: EmitHelper[] | undefined; 171 let onSubstituteNode: TransformationContext["onSubstituteNode"] = noEmitSubstitution; 172 let onEmitNode: TransformationContext["onEmitNode"] = noEmitNotification; 173 let state = TransformationState.Uninitialized; 174 const diagnostics: DiagnosticWithLocation[] = []; 175 176 // The transformation context is provided to each transformer as part of transformer 177 // initialization. 178 const context: TransformationContext = { 179 factory, 180 getCompilerOptions: () => options, 181 getEmitResolver: () => resolver!, // TODO: GH#18217 182 getEmitHost: () => host!, // TODO: GH#18217 183 getEmitHelperFactory: memoize(() => createEmitHelperFactory(context)), 184 startLexicalEnvironment, 185 suspendLexicalEnvironment, 186 resumeLexicalEnvironment, 187 endLexicalEnvironment, 188 setLexicalEnvironmentFlags, 189 getLexicalEnvironmentFlags, 190 hoistVariableDeclaration, 191 hoistFunctionDeclaration, 192 addInitializationStatement, 193 startBlockScope, 194 endBlockScope, 195 addBlockScopedVariable, 196 requestEmitHelper, 197 readEmitHelpers, 198 enableSubstitution, 199 enableEmitNotification, 200 isSubstitutionEnabled, 201 isEmitNotificationEnabled, 202 isLexicalEnvironmentSuspended, 203 get onSubstituteNode() { return onSubstituteNode; }, 204 set onSubstituteNode(value) { 205 Debug.assert(state < TransformationState.Initialized, "Cannot modify transformation hooks after initialization has completed."); 206 Debug.assert(value !== undefined, "Value must not be 'undefined'"); 207 onSubstituteNode = value; 208 }, 209 get onEmitNode() { return onEmitNode; }, 210 set onEmitNode(value) { 211 Debug.assert(state < TransformationState.Initialized, "Cannot modify transformation hooks after initialization has completed."); 212 Debug.assert(value !== undefined, "Value must not be 'undefined'"); 213 onEmitNode = value; 214 }, 215 addDiagnostic(diag) { 216 diagnostics.push(diag); 217 } 218 }; 219 220 // Ensure the parse tree is clean before applying transformations 221 for (const node of nodes) { 222 disposeEmitNodes(getSourceFileOfNode(getParseTreeNode(node))); 223 } 224 225 const recordInfo = MemoryDotting.recordStage(MemoryDotting.TRANSFORM); 226 performance.mark("beforeTransform"); 227 228 // Chain together and initialize each transformer. 229 const transformersWithContext = transformers.map(t => t(context)); 230 const transformation = (node: T): T => { 231 for (const transform of transformersWithContext) { 232 node = transform(node); 233 } 234 return node; 235 }; 236 237 // prevent modification of transformation hooks. 238 state = TransformationState.Initialized; 239 240 // Transform each node. 241 const transformed: T[] = []; 242 for (const node of nodes) { 243 tracing?.push(tracing.Phase.Emit, "transformNodes", node.kind === SyntaxKind.SourceFile ? { path: (node as any as SourceFile).path } : { kind: node.kind, pos: node.pos, end: node.end }); 244 transformed.push((allowDtsFiles ? transformation : transformRoot)(node)); 245 tracing?.pop(); 246 } 247 248 // prevent modification of the lexical environment. 249 state = TransformationState.Completed; 250 251 performance.mark("afterTransform"); 252 MemoryDotting.stopRecordStage(recordInfo); 253 performance.measure("transformTime", "beforeTransform", "afterTransform"); 254 255 return { 256 transformed, 257 substituteNode, 258 emitNodeWithNotification, 259 isEmitNotificationEnabled, 260 dispose, 261 diagnostics 262 }; 263 264 function transformRoot(node: T) { 265 return node && (!isSourceFile(node) || !node.isDeclarationFile) ? transformation(node) : node; 266 } 267 268 /** 269 * Enables expression substitutions in the pretty printer for the provided SyntaxKind. 270 */ 271 function enableSubstitution(kind: SyntaxKind) { 272 Debug.assert(state < TransformationState.Completed, "Cannot modify the transformation context after transformation has completed."); 273 enabledSyntaxKindFeatures[kind] |= SyntaxKindFeatureFlags.Substitution; 274 } 275 276 /** 277 * Determines whether expression substitutions are enabled for the provided node. 278 */ 279 function isSubstitutionEnabled(node: Node) { 280 return (enabledSyntaxKindFeatures[node.kind] & SyntaxKindFeatureFlags.Substitution) !== 0 281 && (getEmitFlags(node) & EmitFlags.NoSubstitution) === 0; 282 } 283 284 /** 285 * Emits a node with possible substitution. 286 * 287 * @param hint A hint as to the intended usage of the node. 288 * @param node The node to emit. 289 * @param emitCallback The callback used to emit the node or its substitute. 290 */ 291 function substituteNode(hint: EmitHint, node: Node) { 292 Debug.assert(state < TransformationState.Disposed, "Cannot substitute a node after the result is disposed."); 293 return node && isSubstitutionEnabled(node) && onSubstituteNode(hint, node) || node; 294 } 295 296 /** 297 * Enables before/after emit notifications in the pretty printer for the provided SyntaxKind. 298 */ 299 function enableEmitNotification(kind: SyntaxKind) { 300 Debug.assert(state < TransformationState.Completed, "Cannot modify the transformation context after transformation has completed."); 301 enabledSyntaxKindFeatures[kind] |= SyntaxKindFeatureFlags.EmitNotifications; 302 } 303 304 /** 305 * Determines whether before/after emit notifications should be raised in the pretty 306 * printer when it emits a node. 307 */ 308 function isEmitNotificationEnabled(node: Node) { 309 return (enabledSyntaxKindFeatures[node.kind] & SyntaxKindFeatureFlags.EmitNotifications) !== 0 310 || (getEmitFlags(node) & EmitFlags.AdviseOnEmitNode) !== 0; 311 } 312 313 /** 314 * Emits a node with possible emit notification. 315 * 316 * @param hint A hint as to the intended usage of the node. 317 * @param node The node to emit. 318 * @param emitCallback The callback used to emit the node. 319 */ 320 function emitNodeWithNotification(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) { 321 Debug.assert(state < TransformationState.Disposed, "Cannot invoke TransformationResult callbacks after the result is disposed."); 322 if (node) { 323 // TODO: Remove check and unconditionally use onEmitNode when API is breakingly changed 324 // (see https://github.com/microsoft/TypeScript/pull/36248/files/5062623f39120171b98870c71344b3242eb03d23#r369766739) 325 if (isEmitNotificationEnabled(node)) { 326 onEmitNode(hint, node, emitCallback); 327 } 328 else { 329 emitCallback(hint, node); 330 } 331 } 332 } 333 334 /** 335 * Records a hoisted variable declaration for the provided name within a lexical environment. 336 */ 337 function hoistVariableDeclaration(name: Identifier): void { 338 Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization."); 339 Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed."); 340 const decl = setEmitFlags(factory.createVariableDeclaration(name), EmitFlags.NoNestedSourceMaps); 341 if (!lexicalEnvironmentVariableDeclarations) { 342 lexicalEnvironmentVariableDeclarations = [decl]; 343 } 344 else { 345 lexicalEnvironmentVariableDeclarations.push(decl); 346 } 347 if (lexicalEnvironmentFlags & LexicalEnvironmentFlags.InParameters) { 348 lexicalEnvironmentFlags |= LexicalEnvironmentFlags.VariablesHoistedInParameters; 349 } 350 } 351 352 /** 353 * Records a hoisted function declaration within a lexical environment. 354 */ 355 function hoistFunctionDeclaration(func: FunctionDeclaration): void { 356 Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization."); 357 Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed."); 358 setEmitFlags(func, EmitFlags.CustomPrologue); 359 if (!lexicalEnvironmentFunctionDeclarations) { 360 lexicalEnvironmentFunctionDeclarations = [func]; 361 } 362 else { 363 lexicalEnvironmentFunctionDeclarations.push(func); 364 } 365 } 366 367 /** 368 * Adds an initialization statement to the top of the lexical environment. 369 */ 370 function addInitializationStatement(node: Statement): void { 371 Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization."); 372 Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed."); 373 setEmitFlags(node, EmitFlags.CustomPrologue); 374 if (!lexicalEnvironmentStatements) { 375 lexicalEnvironmentStatements = [node]; 376 } 377 else { 378 lexicalEnvironmentStatements.push(node); 379 } 380 } 381 382 /** 383 * Starts a new lexical environment. Any existing hoisted variable or function declarations 384 * are pushed onto a stack, and the related storage variables are reset. 385 */ 386 function startLexicalEnvironment(): void { 387 Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization."); 388 Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed."); 389 Debug.assert(!lexicalEnvironmentSuspended, "Lexical environment is suspended."); 390 391 // Save the current lexical environment. Rather than resizing the array we adjust the 392 // stack size variable. This allows us to reuse existing array slots we've 393 // already allocated between transformations to avoid allocation and GC overhead during 394 // transformation. 395 lexicalEnvironmentVariableDeclarationsStack[lexicalEnvironmentStackOffset] = lexicalEnvironmentVariableDeclarations; 396 lexicalEnvironmentFunctionDeclarationsStack[lexicalEnvironmentStackOffset] = lexicalEnvironmentFunctionDeclarations; 397 lexicalEnvironmentStatementsStack[lexicalEnvironmentStackOffset] = lexicalEnvironmentStatements; 398 lexicalEnvironmentFlagsStack[lexicalEnvironmentStackOffset] = lexicalEnvironmentFlags; 399 lexicalEnvironmentStackOffset++; 400 lexicalEnvironmentVariableDeclarations = undefined!; 401 lexicalEnvironmentFunctionDeclarations = undefined!; 402 lexicalEnvironmentStatements = undefined!; 403 lexicalEnvironmentFlags = LexicalEnvironmentFlags.None; 404 } 405 406 /** Suspends the current lexical environment, usually after visiting a parameter list. */ 407 function suspendLexicalEnvironment(): void { 408 Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization."); 409 Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed."); 410 Debug.assert(!lexicalEnvironmentSuspended, "Lexical environment is already suspended."); 411 lexicalEnvironmentSuspended = true; 412 } 413 414 /** Resumes a suspended lexical environment, usually before visiting a function body. */ 415 function resumeLexicalEnvironment(): void { 416 Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization."); 417 Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed."); 418 Debug.assert(lexicalEnvironmentSuspended, "Lexical environment is not suspended."); 419 lexicalEnvironmentSuspended = false; 420 } 421 422 /** 423 * Ends a lexical environment. The previous set of hoisted declarations are restored and 424 * any hoisted declarations added in this environment are returned. 425 */ 426 function endLexicalEnvironment(): Statement[] | undefined { 427 Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization."); 428 Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed."); 429 Debug.assert(!lexicalEnvironmentSuspended, "Lexical environment is suspended."); 430 431 let statements: Statement[] | undefined; 432 if (lexicalEnvironmentVariableDeclarations || 433 lexicalEnvironmentFunctionDeclarations || 434 lexicalEnvironmentStatements) { 435 if (lexicalEnvironmentFunctionDeclarations) { 436 statements = [...lexicalEnvironmentFunctionDeclarations]; 437 } 438 439 if (lexicalEnvironmentVariableDeclarations) { 440 const statement = factory.createVariableStatement( 441 /*modifiers*/ undefined, 442 factory.createVariableDeclarationList(lexicalEnvironmentVariableDeclarations) 443 ); 444 445 setEmitFlags(statement, EmitFlags.CustomPrologue); 446 447 if (!statements) { 448 statements = [statement]; 449 } 450 else { 451 statements.push(statement); 452 } 453 } 454 455 if (lexicalEnvironmentStatements) { 456 if (!statements) { 457 statements = [...lexicalEnvironmentStatements]; 458 } 459 else { 460 statements = [...statements, ...lexicalEnvironmentStatements]; 461 } 462 } 463 } 464 465 // Restore the previous lexical environment. 466 lexicalEnvironmentStackOffset--; 467 lexicalEnvironmentVariableDeclarations = lexicalEnvironmentVariableDeclarationsStack[lexicalEnvironmentStackOffset]; 468 lexicalEnvironmentFunctionDeclarations = lexicalEnvironmentFunctionDeclarationsStack[lexicalEnvironmentStackOffset]; 469 lexicalEnvironmentStatements = lexicalEnvironmentStatementsStack[lexicalEnvironmentStackOffset]; 470 lexicalEnvironmentFlags = lexicalEnvironmentFlagsStack[lexicalEnvironmentStackOffset]; 471 if (lexicalEnvironmentStackOffset === 0) { 472 lexicalEnvironmentVariableDeclarationsStack = []; 473 lexicalEnvironmentFunctionDeclarationsStack = []; 474 lexicalEnvironmentStatementsStack = []; 475 lexicalEnvironmentFlagsStack = []; 476 } 477 return statements; 478 } 479 480 function setLexicalEnvironmentFlags(flags: LexicalEnvironmentFlags, value: boolean): void { 481 lexicalEnvironmentFlags = value ? 482 lexicalEnvironmentFlags | flags : 483 lexicalEnvironmentFlags & ~flags; 484 } 485 486 function getLexicalEnvironmentFlags(): LexicalEnvironmentFlags { 487 return lexicalEnvironmentFlags; 488 } 489 490 /** 491 * Starts a block scope. Any existing block hoisted variables are pushed onto the stack and the related storage variables are reset. 492 */ 493 function startBlockScope() { 494 Debug.assert(state > TransformationState.Uninitialized, "Cannot start a block scope during initialization."); 495 Debug.assert(state < TransformationState.Completed, "Cannot start a block scope after transformation has completed."); 496 blockScopedVariableDeclarationsStack[blockScopeStackOffset] = blockScopedVariableDeclarations; 497 blockScopeStackOffset++; 498 blockScopedVariableDeclarations = undefined!; 499 } 500 501 /** 502 * Ends a block scope. The previous set of block hoisted variables are restored. Any hoisted declarations are returned. 503 */ 504 function endBlockScope() { 505 Debug.assert(state > TransformationState.Uninitialized, "Cannot end a block scope during initialization."); 506 Debug.assert(state < TransformationState.Completed, "Cannot end a block scope after transformation has completed."); 507 const statements: Statement[] | undefined = some(blockScopedVariableDeclarations) ? 508 [ 509 factory.createVariableStatement( 510 /*modifiers*/ undefined, 511 factory.createVariableDeclarationList( 512 blockScopedVariableDeclarations.map(identifier => factory.createVariableDeclaration(identifier)), 513 NodeFlags.Let 514 ) 515 ) 516 ] : undefined; 517 blockScopeStackOffset--; 518 blockScopedVariableDeclarations = blockScopedVariableDeclarationsStack[blockScopeStackOffset]; 519 if (blockScopeStackOffset === 0) { 520 blockScopedVariableDeclarationsStack = []; 521 } 522 return statements; 523 } 524 525 function addBlockScopedVariable(name: Identifier): void { 526 Debug.assert(blockScopeStackOffset > 0, "Cannot add a block scoped variable outside of an iteration body."); 527 (blockScopedVariableDeclarations || (blockScopedVariableDeclarations = [])).push(name); 528 } 529 530 function requestEmitHelper(helper: EmitHelper): void { 531 Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the transformation context during initialization."); 532 Debug.assert(state < TransformationState.Completed, "Cannot modify the transformation context after transformation has completed."); 533 Debug.assert(!helper.scoped, "Cannot request a scoped emit helper."); 534 if (helper.dependencies) { 535 for (const h of helper.dependencies) { 536 requestEmitHelper(h); 537 } 538 } 539 emitHelpers = append(emitHelpers, helper); 540 } 541 542 function readEmitHelpers(): EmitHelper[] | undefined { 543 Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the transformation context during initialization."); 544 Debug.assert(state < TransformationState.Completed, "Cannot modify the transformation context after transformation has completed."); 545 const helpers = emitHelpers; 546 emitHelpers = undefined; 547 return helpers; 548 } 549 550 function dispose() { 551 if (state < TransformationState.Disposed) { 552 // Clean up emit nodes on parse tree 553 for (const node of nodes) { 554 disposeEmitNodes(getSourceFileOfNode(getParseTreeNode(node))); 555 } 556 557 // Release references to external entries for GC purposes. 558 lexicalEnvironmentVariableDeclarations = undefined!; 559 lexicalEnvironmentVariableDeclarationsStack = undefined!; 560 lexicalEnvironmentFunctionDeclarations = undefined!; 561 lexicalEnvironmentFunctionDeclarationsStack = undefined!; 562 onSubstituteNode = undefined!; 563 onEmitNode = undefined!; 564 emitHelpers = undefined; 565 566 // Prevent further use of the transformation result. 567 state = TransformationState.Disposed; 568 } 569 } 570 571 /** Determines whether the lexical environment is suspended */ 572 function isLexicalEnvironmentSuspended(): boolean { 573 return lexicalEnvironmentSuspended; 574 } 575 } 576 577 export const nullTransformationContext: TransformationContext = { 578 factory: factory, // eslint-disable-line object-shorthand 579 getCompilerOptions: () => ({}), 580 getEmitResolver: notImplemented, 581 getEmitHost: notImplemented, 582 getEmitHelperFactory: notImplemented, 583 startLexicalEnvironment: noop, 584 resumeLexicalEnvironment: noop, 585 suspendLexicalEnvironment: noop, 586 endLexicalEnvironment: returnUndefined, 587 setLexicalEnvironmentFlags: noop, 588 getLexicalEnvironmentFlags: () => 0, 589 hoistVariableDeclaration: noop, 590 hoistFunctionDeclaration: noop, 591 addInitializationStatement: noop, 592 startBlockScope: noop, 593 endBlockScope: returnUndefined, 594 addBlockScopedVariable: noop, 595 requestEmitHelper: noop, 596 readEmitHelpers: notImplemented, 597 enableSubstitution: noop, 598 enableEmitNotification: noop, 599 isSubstitutionEnabled: notImplemented, 600 isEmitNotificationEnabled: notImplemented, 601 onSubstituteNode: noEmitSubstitution, 602 onEmitNode: noEmitNotification, 603 addDiagnostic: noop, 604 }; 605} 606