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