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 performance.mark("beforeTransform"); 226 227 // Chain together and initialize each transformer. 228 const transformersWithContext = transformers.map(t => t(context)); 229 const transformation = (node: T): T => { 230 for (const transform of transformersWithContext) { 231 node = transform(node); 232 } 233 return node; 234 }; 235 236 // prevent modification of transformation hooks. 237 state = TransformationState.Initialized; 238 239 // Transform each node. 240 const transformed: T[] = []; 241 for (const node of nodes) { 242 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 }); 243 transformed.push((allowDtsFiles ? transformation : transformRoot)(node)); 244 tracing?.pop(); 245 } 246 247 // prevent modification of the lexical environment. 248 state = TransformationState.Completed; 249 250 performance.mark("afterTransform"); 251 performance.measure("transformTime", "beforeTransform", "afterTransform"); 252 253 return { 254 transformed, 255 substituteNode, 256 emitNodeWithNotification, 257 isEmitNotificationEnabled, 258 dispose, 259 diagnostics 260 }; 261 262 function transformRoot(node: T) { 263 return node && (!isSourceFile(node) || !node.isDeclarationFile) ? transformation(node) : node; 264 } 265 266 /** 267 * Enables expression substitutions in the pretty printer for the provided SyntaxKind. 268 */ 269 function enableSubstitution(kind: SyntaxKind) { 270 Debug.assert(state < TransformationState.Completed, "Cannot modify the transformation context after transformation has completed."); 271 enabledSyntaxKindFeatures[kind] |= SyntaxKindFeatureFlags.Substitution; 272 } 273 274 /** 275 * Determines whether expression substitutions are enabled for the provided node. 276 */ 277 function isSubstitutionEnabled(node: Node) { 278 return (enabledSyntaxKindFeatures[node.kind] & SyntaxKindFeatureFlags.Substitution) !== 0 279 && (getEmitFlags(node) & EmitFlags.NoSubstitution) === 0; 280 } 281 282 /** 283 * Emits a node with possible substitution. 284 * 285 * @param hint A hint as to the intended usage of the node. 286 * @param node The node to emit. 287 * @param emitCallback The callback used to emit the node or its substitute. 288 */ 289 function substituteNode(hint: EmitHint, node: Node) { 290 Debug.assert(state < TransformationState.Disposed, "Cannot substitute a node after the result is disposed."); 291 return node && isSubstitutionEnabled(node) && onSubstituteNode(hint, node) || node; 292 } 293 294 /** 295 * Enables before/after emit notifications in the pretty printer for the provided SyntaxKind. 296 */ 297 function enableEmitNotification(kind: SyntaxKind) { 298 Debug.assert(state < TransformationState.Completed, "Cannot modify the transformation context after transformation has completed."); 299 enabledSyntaxKindFeatures[kind] |= SyntaxKindFeatureFlags.EmitNotifications; 300 } 301 302 /** 303 * Determines whether before/after emit notifications should be raised in the pretty 304 * printer when it emits a node. 305 */ 306 function isEmitNotificationEnabled(node: Node) { 307 return (enabledSyntaxKindFeatures[node.kind] & SyntaxKindFeatureFlags.EmitNotifications) !== 0 308 || (getEmitFlags(node) & EmitFlags.AdviseOnEmitNode) !== 0; 309 } 310 311 /** 312 * Emits a node with possible emit notification. 313 * 314 * @param hint A hint as to the intended usage of the node. 315 * @param node The node to emit. 316 * @param emitCallback The callback used to emit the node. 317 */ 318 function emitNodeWithNotification(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) { 319 Debug.assert(state < TransformationState.Disposed, "Cannot invoke TransformationResult callbacks after the result is disposed."); 320 if (node) { 321 // TODO: Remove check and unconditionally use onEmitNode when API is breakingly changed 322 // (see https://github.com/microsoft/TypeScript/pull/36248/files/5062623f39120171b98870c71344b3242eb03d23#r369766739) 323 if (isEmitNotificationEnabled(node)) { 324 onEmitNode(hint, node, emitCallback); 325 } 326 else { 327 emitCallback(hint, node); 328 } 329 } 330 } 331 332 /** 333 * Records a hoisted variable declaration for the provided name within a lexical environment. 334 */ 335 function hoistVariableDeclaration(name: Identifier): void { 336 Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization."); 337 Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed."); 338 const decl = setEmitFlags(factory.createVariableDeclaration(name), EmitFlags.NoNestedSourceMaps); 339 if (!lexicalEnvironmentVariableDeclarations) { 340 lexicalEnvironmentVariableDeclarations = [decl]; 341 } 342 else { 343 lexicalEnvironmentVariableDeclarations.push(decl); 344 } 345 if (lexicalEnvironmentFlags & LexicalEnvironmentFlags.InParameters) { 346 lexicalEnvironmentFlags |= LexicalEnvironmentFlags.VariablesHoistedInParameters; 347 } 348 } 349 350 /** 351 * Records a hoisted function declaration within a lexical environment. 352 */ 353 function hoistFunctionDeclaration(func: FunctionDeclaration): void { 354 Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization."); 355 Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed."); 356 setEmitFlags(func, EmitFlags.CustomPrologue); 357 if (!lexicalEnvironmentFunctionDeclarations) { 358 lexicalEnvironmentFunctionDeclarations = [func]; 359 } 360 else { 361 lexicalEnvironmentFunctionDeclarations.push(func); 362 } 363 } 364 365 /** 366 * Adds an initialization statement to the top of the lexical environment. 367 */ 368 function addInitializationStatement(node: Statement): void { 369 Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization."); 370 Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed."); 371 setEmitFlags(node, EmitFlags.CustomPrologue); 372 if (!lexicalEnvironmentStatements) { 373 lexicalEnvironmentStatements = [node]; 374 } 375 else { 376 lexicalEnvironmentStatements.push(node); 377 } 378 } 379 380 /** 381 * Starts a new lexical environment. Any existing hoisted variable or function declarations 382 * are pushed onto a stack, and the related storage variables are reset. 383 */ 384 function startLexicalEnvironment(): void { 385 Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization."); 386 Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed."); 387 Debug.assert(!lexicalEnvironmentSuspended, "Lexical environment is suspended."); 388 389 // Save the current lexical environment. Rather than resizing the array we adjust the 390 // stack size variable. This allows us to reuse existing array slots we've 391 // already allocated between transformations to avoid allocation and GC overhead during 392 // transformation. 393 lexicalEnvironmentVariableDeclarationsStack[lexicalEnvironmentStackOffset] = lexicalEnvironmentVariableDeclarations; 394 lexicalEnvironmentFunctionDeclarationsStack[lexicalEnvironmentStackOffset] = lexicalEnvironmentFunctionDeclarations; 395 lexicalEnvironmentStatementsStack[lexicalEnvironmentStackOffset] = lexicalEnvironmentStatements; 396 lexicalEnvironmentFlagsStack[lexicalEnvironmentStackOffset] = lexicalEnvironmentFlags; 397 lexicalEnvironmentStackOffset++; 398 lexicalEnvironmentVariableDeclarations = undefined!; 399 lexicalEnvironmentFunctionDeclarations = undefined!; 400 lexicalEnvironmentStatements = undefined!; 401 lexicalEnvironmentFlags = LexicalEnvironmentFlags.None; 402 } 403 404 /** Suspends the current lexical environment, usually after visiting a parameter list. */ 405 function suspendLexicalEnvironment(): void { 406 Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization."); 407 Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed."); 408 Debug.assert(!lexicalEnvironmentSuspended, "Lexical environment is already suspended."); 409 lexicalEnvironmentSuspended = true; 410 } 411 412 /** Resumes a suspended lexical environment, usually before visiting a function body. */ 413 function resumeLexicalEnvironment(): void { 414 Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization."); 415 Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed."); 416 Debug.assert(lexicalEnvironmentSuspended, "Lexical environment is not suspended."); 417 lexicalEnvironmentSuspended = false; 418 } 419 420 /** 421 * Ends a lexical environment. The previous set of hoisted declarations are restored and 422 * any hoisted declarations added in this environment are returned. 423 */ 424 function endLexicalEnvironment(): Statement[] | undefined { 425 Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization."); 426 Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed."); 427 Debug.assert(!lexicalEnvironmentSuspended, "Lexical environment is suspended."); 428 429 let statements: Statement[] | undefined; 430 if (lexicalEnvironmentVariableDeclarations || 431 lexicalEnvironmentFunctionDeclarations || 432 lexicalEnvironmentStatements) { 433 if (lexicalEnvironmentFunctionDeclarations) { 434 statements = [...lexicalEnvironmentFunctionDeclarations]; 435 } 436 437 if (lexicalEnvironmentVariableDeclarations) { 438 const statement = factory.createVariableStatement( 439 /*modifiers*/ undefined, 440 factory.createVariableDeclarationList(lexicalEnvironmentVariableDeclarations) 441 ); 442 443 setEmitFlags(statement, EmitFlags.CustomPrologue); 444 445 if (!statements) { 446 statements = [statement]; 447 } 448 else { 449 statements.push(statement); 450 } 451 } 452 453 if (lexicalEnvironmentStatements) { 454 if (!statements) { 455 statements = [...lexicalEnvironmentStatements]; 456 } 457 else { 458 statements = [...statements, ...lexicalEnvironmentStatements]; 459 } 460 } 461 } 462 463 // Restore the previous lexical environment. 464 lexicalEnvironmentStackOffset--; 465 lexicalEnvironmentVariableDeclarations = lexicalEnvironmentVariableDeclarationsStack[lexicalEnvironmentStackOffset]; 466 lexicalEnvironmentFunctionDeclarations = lexicalEnvironmentFunctionDeclarationsStack[lexicalEnvironmentStackOffset]; 467 lexicalEnvironmentStatements = lexicalEnvironmentStatementsStack[lexicalEnvironmentStackOffset]; 468 lexicalEnvironmentFlags = lexicalEnvironmentFlagsStack[lexicalEnvironmentStackOffset]; 469 if (lexicalEnvironmentStackOffset === 0) { 470 lexicalEnvironmentVariableDeclarationsStack = []; 471 lexicalEnvironmentFunctionDeclarationsStack = []; 472 lexicalEnvironmentStatementsStack = []; 473 lexicalEnvironmentFlagsStack = []; 474 } 475 return statements; 476 } 477 478 function setLexicalEnvironmentFlags(flags: LexicalEnvironmentFlags, value: boolean): void { 479 lexicalEnvironmentFlags = value ? 480 lexicalEnvironmentFlags | flags : 481 lexicalEnvironmentFlags & ~flags; 482 } 483 484 function getLexicalEnvironmentFlags(): LexicalEnvironmentFlags { 485 return lexicalEnvironmentFlags; 486 } 487 488 /** 489 * Starts a block scope. Any existing block hoisted variables are pushed onto the stack and the related storage variables are reset. 490 */ 491 function startBlockScope() { 492 Debug.assert(state > TransformationState.Uninitialized, "Cannot start a block scope during initialization."); 493 Debug.assert(state < TransformationState.Completed, "Cannot start a block scope after transformation has completed."); 494 blockScopedVariableDeclarationsStack[blockScopeStackOffset] = blockScopedVariableDeclarations; 495 blockScopeStackOffset++; 496 blockScopedVariableDeclarations = undefined!; 497 } 498 499 /** 500 * Ends a block scope. The previous set of block hoisted variables are restored. Any hoisted declarations are returned. 501 */ 502 function endBlockScope() { 503 Debug.assert(state > TransformationState.Uninitialized, "Cannot end a block scope during initialization."); 504 Debug.assert(state < TransformationState.Completed, "Cannot end a block scope after transformation has completed."); 505 const statements: Statement[] | undefined = some(blockScopedVariableDeclarations) ? 506 [ 507 factory.createVariableStatement( 508 /*modifiers*/ undefined, 509 factory.createVariableDeclarationList( 510 blockScopedVariableDeclarations.map(identifier => factory.createVariableDeclaration(identifier)), 511 NodeFlags.Let 512 ) 513 ) 514 ] : undefined; 515 blockScopeStackOffset--; 516 blockScopedVariableDeclarations = blockScopedVariableDeclarationsStack[blockScopeStackOffset]; 517 if (blockScopeStackOffset === 0) { 518 blockScopedVariableDeclarationsStack = []; 519 } 520 return statements; 521 } 522 523 function addBlockScopedVariable(name: Identifier): void { 524 Debug.assert(blockScopeStackOffset > 0, "Cannot add a block scoped variable outside of an iteration body."); 525 (blockScopedVariableDeclarations || (blockScopedVariableDeclarations = [])).push(name); 526 } 527 528 function requestEmitHelper(helper: EmitHelper): void { 529 Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the transformation context during initialization."); 530 Debug.assert(state < TransformationState.Completed, "Cannot modify the transformation context after transformation has completed."); 531 Debug.assert(!helper.scoped, "Cannot request a scoped emit helper."); 532 if (helper.dependencies) { 533 for (const h of helper.dependencies) { 534 requestEmitHelper(h); 535 } 536 } 537 emitHelpers = append(emitHelpers, helper); 538 } 539 540 function readEmitHelpers(): EmitHelper[] | undefined { 541 Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the transformation context during initialization."); 542 Debug.assert(state < TransformationState.Completed, "Cannot modify the transformation context after transformation has completed."); 543 const helpers = emitHelpers; 544 emitHelpers = undefined; 545 return helpers; 546 } 547 548 function dispose() { 549 if (state < TransformationState.Disposed) { 550 // Clean up emit nodes on parse tree 551 for (const node of nodes) { 552 disposeEmitNodes(getSourceFileOfNode(getParseTreeNode(node))); 553 } 554 555 // Release references to external entries for GC purposes. 556 lexicalEnvironmentVariableDeclarations = undefined!; 557 lexicalEnvironmentVariableDeclarationsStack = undefined!; 558 lexicalEnvironmentFunctionDeclarations = undefined!; 559 lexicalEnvironmentFunctionDeclarationsStack = undefined!; 560 onSubstituteNode = undefined!; 561 onEmitNode = undefined!; 562 emitHelpers = undefined; 563 564 // Prevent further use of the transformation result. 565 state = TransformationState.Disposed; 566 } 567 } 568 569 /** Determines whether the lexical environment is suspended */ 570 function isLexicalEnvironmentSuspended(): boolean { 571 return lexicalEnvironmentSuspended; 572 } 573 } 574 575 export const nullTransformationContext: TransformationContext = { 576 factory: factory, // eslint-disable-line object-shorthand 577 getCompilerOptions: () => ({}), 578 getEmitResolver: notImplemented, 579 getEmitHost: notImplemented, 580 getEmitHelperFactory: notImplemented, 581 startLexicalEnvironment: noop, 582 resumeLexicalEnvironment: noop, 583 suspendLexicalEnvironment: noop, 584 endLexicalEnvironment: returnUndefined, 585 setLexicalEnvironmentFlags: noop, 586 getLexicalEnvironmentFlags: () => 0, 587 hoistVariableDeclaration: noop, 588 hoistFunctionDeclaration: noop, 589 addInitializationStatement: noop, 590 startBlockScope: noop, 591 endBlockScope: returnUndefined, 592 addBlockScopedVariable: noop, 593 requestEmitHelper: noop, 594 readEmitHelpers: notImplemented, 595 enableSubstitution: noop, 596 enableEmitNotification: noop, 597 isSubstitutionEnabled: notImplemented, 598 isEmitNotificationEnabled: notImplemented, 599 onSubstituteNode: noEmitSubstitution, 600 onEmitNode: noEmitNotification, 601 addDiagnostic: noop, 602 }; 603} 604