Emitter SourceMaps

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:

  1. function emitJavaScript(jsFilePath: string, root?: SourceFile) {
  2. // STUFF ........... removed
  3. let writeComment = writeCommentRange;
  4. /** Write emitted output to disk */
  5. let writeEmittedFiles = writeJavaScriptFile;
  6. /** Emit a node */
  7. let emit = emitNodeWithoutSourceMap;
  8. /** Called just before starting emit of a node */
  9. let emitStart = function (node: Node) { };
  10. /** Called once the emit of the node is done */
  11. let emitEnd = function (node: Node) { };
  12. /** Emit the text for the given token that comes after startPos
  13. * This by default writes the text provided with the given tokenKind
  14. * but if optional emitFn callback is provided the text is emitted using the callback instead of default text
  15. * @param tokenKind the kind of the token to search and emit
  16. * @param startPos the position in the source to start searching for the token
  17. * @param emitFn if given will be invoked to emit the text instead of actual token emit */
  18. let emitToken = emitTokenText;
  19. /** Called to before starting the lexical scopes as in function/class in the emitted code because of node
  20. * @param scopeDeclaration node that starts the lexical scope
  21. * @param scopeName Optional name of this scope instead of deducing one from the declaration node */
  22. let scopeEmitStart = function(scopeDeclaration: Node, scopeName?: string) { };
  23. /** Called after coming out of the scope */
  24. let scopeEmitEnd = function() { };
  25. /** Sourcemap data that will get encoded */
  26. let sourceMapData: SourceMapData;
  27. if (compilerOptions.sourceMap || compilerOptions.inlineSourceMap) {
  28. initializeEmitterWithSourceMaps();
  29. }
  30. if (root) {
  31. // Do not call emit directly. It does not set the currentSourceFile.
  32. emitSourceFile(root);
  33. }
  34. else {
  35. forEach(host.getSourceFiles(), sourceFile => {
  36. if (!isExternalModuleOrDeclarationFile(sourceFile)) {
  37. emitSourceFile(sourceFile);
  38. }
  39. });
  40. }
  41. writeLine();
  42. writeEmittedFiles(writer.getText(), /*writeByteOrderMark*/ compilerOptions.emitBOM);
  43. return;
  44. /// 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:

  1. // end of `initializeEmitterWithSourceMaps`
  2. writeEmittedFiles = writeJavaScriptAndSourceMapFile;
  3. emit = emitNodeWithSourceMap;
  4. emitStart = recordEmitNodeStartSpan;
  5. emitEnd = recordEmitNodeEndSpan;
  6. emitToken = writeTextWithSpanRecord;
  7. scopeEmitStart = recordScopeNameOfNode;
  8. scopeEmitEnd = recordScopeNameEnd;
  9. 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.