We said that the bulk of the emitter.ts
is the local function emitJavaScript
(we showed the initialization routine of this function before). It basically sets up a bunch of locals and hits off to emitSourceFile
. The following is a revisiting of the function, this time focusing on SourceMap
stuff:
function emitJavaScript(jsFilePath: string, root?: SourceFile) {
// STUFF ........... removed
let writeComment = writeCommentRange;
/** Write emitted output to disk */
let writeEmittedFiles = writeJavaScriptFile;
/** Emit a node */
let emit = emitNodeWithoutSourceMap;
/** Called just before starting emit of a node */
let emitStart = function (node: Node) { };
/** Called once the emit of the node is done */
let emitEnd = function (node: Node) { };
/** Emit the text for the given token that comes after startPos
* This by default writes the text provided with the given tokenKind
* but if optional emitFn callback is provided the text is emitted using the callback instead of default text
* @param tokenKind the kind of the token to search and emit
* @param startPos the position in the source to start searching for the token
* @param emitFn if given will be invoked to emit the text instead of actual token emit */
let emitToken = emitTokenText;
/** Called to before starting the lexical scopes as in function/class in the emitted code because of node
* @param scopeDeclaration node that starts the lexical scope
* @param scopeName Optional name of this scope instead of deducing one from the declaration node */
let scopeEmitStart = function(scopeDeclaration: Node, scopeName?: string) { };
/** Called after coming out of the scope */
let scopeEmitEnd = function() { };
/** Sourcemap data that will get encoded */
let sourceMapData: SourceMapData;
if (compilerOptions.sourceMap || compilerOptions.inlineSourceMap) {
initializeEmitterWithSourceMaps();
}
if (root) {
// Do not call emit directly. It does not set the currentSourceFile.
emitSourceFile(root);
}
else {
forEach(host.getSourceFiles(), sourceFile => {
if (!isExternalModuleOrDeclarationFile(sourceFile)) {
emitSourceFile(sourceFile);
}
});
}
writeLine();
writeEmittedFiles(writer.getText(), /*writeByteOrderMark*/ compilerOptions.emitBOM);
return;
/// BUNCH OF LOCAL FUNCTIONS
The important function call here : initializeEmitterWithSourceMaps
which is a function local to emitJavaScript
that overrides some locals that were already defined here. At the bottom of initializeEmitterWithSourceMaps
you will notice the overriding:
// end of `initializeEmitterWithSourceMaps`
writeEmittedFiles = writeJavaScriptAndSourceMapFile;
emit = emitNodeWithSourceMap;
emitStart = recordEmitNodeStartSpan;
emitEnd = recordEmitNodeEndSpan;
emitToken = writeTextWithSpanRecord;
scopeEmitStart = recordScopeNameOfNode;
scopeEmitEnd = recordScopeNameEnd;
writeComment = writeCommentRangeWithMap;
This means that the bulk of emitter code can not care about SourceMap
and just use these local functions the same way with or without SourceMaps.