Emitter Functions
emitFiles
emitFilesemitter.tsで定義されています。下記が関数シグネチャです:
// targetSourceFile is when users only want one file in entire project to be emitted. This is used in compileOnSave feature
export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile?: SourceFile): EmitResult {EmitHostはCompilerHostを簡略化した(狭めたような)バージョンです(実行時においては、実際には多くのユースケースでCompilerHostとなります)。
emitFilesからの最も興味深いコールスタックは次のとおりです:
emitFiles ->
emitFile(jsFilePath, targetSourceFile) ->
emitJavaScript(jsFilePath, targetSourceFile);emitJavaScript
emitJavaScriptこの関数には多くの良いコメントがありますので、以下に示します:
function emitJavaScript(jsFilePath: string, root?: SourceFile) {
let writer = createTextWriter(newLine);
let write = writer.write;
let writeTextOfNode = writer.writeTextOfNode;
let writeLine = writer.writeLine;
let increaseIndent = writer.increaseIndent;
let decreaseIndent = writer.decreaseIndent;
let currentSourceFile: SourceFile;
// name of an exporter function if file is a System external module
// System.register([...], function (<exporter>) {...})
// exporting in System modules looks like:
// export var x; ... x = 1
// =>
// var x;... exporter("x", x = 1)
let exportFunctionForFile: string;
let generatedNameSet: Map<string> = {};
let nodeToGeneratedName: string[] = [];
let computedPropertyNamesToGeneratedNames: string[];
let extendsEmitted = false;
let decorateEmitted = false;
let paramEmitted = false;
let awaiterEmitted = false;
let tempFlags = 0;
let tempVariables: Identifier[];
let tempParameters: Identifier[];
let externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[];
let exportSpecifiers: Map<ExportSpecifier[]>;
let exportEquals: ExportAssignment;
let hasExportStars: boolean;
/** Write emitted output to disk */
let writeEmittedFiles = writeJavaScriptFile;
let detachedCommentsInfo: { nodePos: number; detachedCommentEndPos: number }[];
let writeComment = writeCommentRange;
/** 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
}基本的にそれはたくさんのローカルのものを準備します(これらの関数はemitter.tsの大部分を形成します)。そして次にemitを起動するローカル関数emitSourceFileに渡します。emitSourceFile関数は単にcurrentSourceFileを設定し、順番にemit関数に渡します。
emit関数は_comment_ emit + 実際のJavaScript emitを処理します。実際のJavaScript emitは、emitJavaScriptWorker関数の仕事です。
emitJavaScriptWorker
emitJavaScriptWorker関数の全体:
再帰は、単に必要に応じてこれらの関数から他のemitFoo関数を呼び出すことによって行われます。emitFunctionDeclarationの抜粋です:
最終更新
役に立ちましたか?