1/*@internal*/ 2namespace ts { 3 export function transformNodeModule(context: TransformationContext) { 4 const previousOnSubstituteNode = context.onSubstituteNode; 5 const previousOnEmitNode = context.onEmitNode; 6 7 const esmTransform = transformECMAScriptModule(context); 8 9 const esmOnSubstituteNode = context.onSubstituteNode; 10 const esmOnEmitNode = context.onEmitNode; 11 12 context.onSubstituteNode = previousOnSubstituteNode; 13 context.onEmitNode = previousOnEmitNode; 14 15 const cjsTransform = transformModule(context); 16 17 const cjsOnSubstituteNode = context.onSubstituteNode; 18 const cjsOnEmitNode = context.onEmitNode; 19 20 context.onSubstituteNode = onSubstituteNode; 21 context.onEmitNode = onEmitNode; 22 context.enableSubstitution(SyntaxKind.SourceFile); 23 context.enableEmitNotification(SyntaxKind.SourceFile); 24 25 let currentSourceFile: SourceFile | undefined; 26 return transformSourceFileOrBundle; 27 28 function onSubstituteNode(hint: EmitHint, node: Node) { 29 if (isSourceFile(node)) { 30 currentSourceFile = node; 31 // Neither component transform wants substitution notifications for `SourceFile`s, and, in fact, relies on 32 // the source file emit notification to setup scope variables for substitutions (so we _cannot_ call their substitute 33 // functions on source files safely, as that context only gets setup in a later pipeline phase!) 34 return previousOnSubstituteNode(hint, node); 35 } 36 else { 37 if (!currentSourceFile) { 38 return previousOnSubstituteNode(hint, node); 39 } 40 if (currentSourceFile.impliedNodeFormat === ModuleKind.ESNext) { 41 return esmOnSubstituteNode(hint, node); 42 } 43 return cjsOnSubstituteNode(hint, node); 44 } 45 } 46 47 function onEmitNode(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void { 48 if (isSourceFile(node)) { 49 currentSourceFile = node; 50 } 51 if (!currentSourceFile) { 52 return previousOnEmitNode(hint, node, emitCallback); 53 } 54 if (currentSourceFile.impliedNodeFormat === ModuleKind.ESNext) { 55 return esmOnEmitNode(hint, node, emitCallback); 56 } 57 return cjsOnEmitNode(hint, node, emitCallback); 58 } 59 60 function getModuleTransformForFile(file: SourceFile): (typeof esmTransform) { 61 return file.impliedNodeFormat === ModuleKind.ESNext ? esmTransform : cjsTransform; 62 } 63 64 function transformSourceFile(node: SourceFile) { 65 if (node.isDeclarationFile) { 66 return node; 67 } 68 69 currentSourceFile = node; 70 const result = getModuleTransformForFile(node)(node); 71 currentSourceFile = undefined; 72 Debug.assert(isSourceFile(result)); 73 return result; 74 } 75 76 function transformSourceFileOrBundle(node: SourceFile | Bundle) { 77 return node.kind === SyntaxKind.SourceFile ? transformSourceFile(node) : transformBundle(node); 78 } 79 80 function transformBundle(node: Bundle) { 81 return context.factory.createBundle(map(node.sourceFiles, transformSourceFile), node.prepends); 82 } 83 } 84} 85