Extract printer from emitter for reusability.

This commit is contained in:
Ron Buckton 2017-01-26 15:46:26 -08:00
parent 64dd8065aa
commit 028e4e2b13
21 changed files with 2939 additions and 2850 deletions

View file

@ -84,6 +84,7 @@ var compilerSources = [
"sourcemap.ts",
"comments.ts",
"declarationEmitter.ts",
"printer.ts",
"emitter.ts",
"program.ts",
"commandLineParser.ts",
@ -121,6 +122,7 @@ var servicesSources = [
"sourcemap.ts",
"comments.ts",
"declarationEmitter.ts",
"printer.ts",
"emitter.ts",
"program.ts",
"commandLineParser.ts",

View file

@ -5,17 +5,13 @@ namespace ts {
export interface CommentWriter {
reset(): void;
setSourceFile(sourceFile: SourceFile): void;
emitNodeWithComments(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void): void;
emitNodeWithComments(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void;
emitBodyWithDetachedComments(node: Node, detachedRange: TextRange, emitCallback: (node: Node) => void): void;
emitTrailingCommentsOfPosition(pos: number): void;
}
export function createCommentWriter(host: EmitHost, writer: EmitTextWriter, sourceMap: SourceMapWriter): CommentWriter {
const compilerOptions = host.getCompilerOptions();
export function createCommentWriter(writer: EmitTextWriter, compilerOptions: CompilerOptions, newLine: string, emitPos: (pos: number) => void): CommentWriter {
const extendedDiagnostics = compilerOptions.extendedDiagnostics;
const newLine = host.getNewLine();
const { emitPos } = sourceMap;
let containerPos = -1;
let containerEnd = -1;
let declarationListContainerEnd = -1;
@ -34,9 +30,9 @@ namespace ts {
emitTrailingCommentsOfPosition,
};
function emitNodeWithComments(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void) {
function emitNodeWithComments(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) {
if (disabled) {
emitCallback(emitContext, node);
emitCallback(hint, node);
return;
}
@ -47,11 +43,11 @@ namespace ts {
// Both pos and end are synthesized, so just emit the node without comments.
if (emitFlags & EmitFlags.NoNestedComments) {
disabled = true;
emitCallback(emitContext, node);
emitCallback(hint, node);
disabled = false;
}
else {
emitCallback(emitContext, node);
emitCallback(hint, node);
}
}
else {
@ -94,11 +90,11 @@ namespace ts {
if (emitFlags & EmitFlags.NoNestedComments) {
disabled = true;
emitCallback(emitContext, node);
emitCallback(hint, node);
disabled = false;
}
else {
emitCallback(emitContext, node);
emitCallback(hint, node);
}
if (extendedDiagnostics) {

View file

@ -35,13 +35,15 @@ namespace ts {
forEachEmittedFile(host, getDeclarationDiagnosticsFromFile, targetSourceFile);
return declarationDiagnostics.getDiagnostics(targetSourceFile ? targetSourceFile.fileName : undefined);
function getDeclarationDiagnosticsFromFile({ declarationFilePath }: EmitFileNames, sources: SourceFile[], isBundledEmit: boolean) {
emitDeclarations(host, resolver, declarationDiagnostics, declarationFilePath, sources, isBundledEmit, /*emitOnlyDtsFiles*/ false);
function getDeclarationDiagnosticsFromFile({ declarationFilePath }: EmitFileNames, sourceFileOrBundle: SourceFile | Bundle) {
emitDeclarations(host, resolver, declarationDiagnostics, declarationFilePath, sourceFileOrBundle, /*emitOnlyDtsFiles*/ false);
}
}
function emitDeclarations(host: EmitHost, resolver: EmitResolver, emitterDiagnostics: DiagnosticCollection, declarationFilePath: string,
sourceFiles: SourceFile[], isBundledEmit: boolean, emitOnlyDtsFiles: boolean): DeclarationEmit {
sourceFileOrBundle: SourceFile | Bundle, emitOnlyDtsFiles: boolean): DeclarationEmit {
const sourceFiles = sourceFileOrBundle.kind === SyntaxKind.Bundle ? sourceFileOrBundle.sourceFiles : [sourceFileOrBundle];
const isBundledEmit = sourceFileOrBundle.kind === SyntaxKind.Bundle;
const newLine = host.getNewLine();
const compilerOptions = host.getCompilerOptions();
@ -1803,8 +1805,9 @@ namespace ts {
}
return addedBundledEmitReference;
function getDeclFileName(emitFileNames: EmitFileNames, _sourceFiles: SourceFile[], isBundledEmit: boolean) {
function getDeclFileName(emitFileNames: EmitFileNames, sourceFileOrBundle: SourceFile | Bundle) {
// Dont add reference path to this file if it is a bundled emit and caller asked not emit bundled file path
const isBundledEmit = sourceFileOrBundle.kind === SyntaxKind.Bundle;
if (isBundledEmit && !addBundledFileReference) {
return;
}
@ -1817,10 +1820,11 @@ namespace ts {
}
/* @internal */
export function writeDeclarationFile(declarationFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean, host: EmitHost, resolver: EmitResolver, emitterDiagnostics: DiagnosticCollection, emitOnlyDtsFiles: boolean) {
const emitDeclarationResult = emitDeclarations(host, resolver, emitterDiagnostics, declarationFilePath, sourceFiles, isBundledEmit, emitOnlyDtsFiles);
export function writeDeclarationFile(declarationFilePath: string, sourceFileOrBundle: SourceFile | Bundle, host: EmitHost, resolver: EmitResolver, emitterDiagnostics: DiagnosticCollection, emitOnlyDtsFiles: boolean) {
const emitDeclarationResult = emitDeclarations(host, resolver, emitterDiagnostics, declarationFilePath, sourceFileOrBundle, emitOnlyDtsFiles);
const emitSkipped = emitDeclarationResult.reportedDeclarationError || host.isEmitBlocked(declarationFilePath) || host.getCompilerOptions().noEmit;
if (!emitSkipped) {
const sourceFiles = sourceFileOrBundle.kind === SyntaxKind.Bundle ? sourceFileOrBundle.sourceFiles : [sourceFileOrBundle];
const declarationOutput = emitDeclarationResult.referencesOutput
+ getDeclarationOutput(emitDeclarationResult.synchronousDeclarationOutput, emitDeclarationResult.moduleElementDeclarationEmitInfo);
writeFile(host, emitterDiagnostics, declarationFilePath, declarationOutput, host.getCompilerOptions().emitBOM, sourceFiles);

File diff suppressed because it is too large Load diff

View file

@ -1530,6 +1530,19 @@ namespace ts {
return node;
}
export function createBundle(sourceFiles: SourceFile[]) {
const node = <Bundle>createNode(SyntaxKind.Bundle);
node.sourceFiles = sourceFiles;
return node;
}
export function updateBundle(node: Bundle, sourceFiles: SourceFile[]) {
if (node.sourceFiles !== sourceFiles) {
return createBundle(sourceFiles);
}
return node;
}
// Compound nodes
export function createComma(left: Expression, right: Expression) {

2659
src/compiler/printer.ts Normal file

File diff suppressed because it is too large Load diff

View file

@ -8,10 +8,9 @@ namespace ts {
*
* @param filePath The path to the generated output file.
* @param sourceMapFilePath The path to the output source map file.
* @param sourceFiles The input source files for the program.
* @param isBundledEmit A value indicating whether the generated output file is a bundle.
* @param sourceFileOrBundle The input source file or bundle for the program.
*/
initialize(filePath: string, sourceMapFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean): void;
initialize(filePath: string, sourceMapFilePath: string, sourceFileOrBundle: SourceFile | Bundle): void;
/**
* Reset the SourceMapWriter to an empty state.
@ -38,11 +37,11 @@ namespace ts {
/**
* Emits a node with possible leading and trailing source maps.
*
* @param emitContext The current emit context
* @param hint The current emit context
* @param node The node to emit.
* @param emitCallback The callback used to emit the node.
*/
emitNodeWithSourceMap(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void): void;
emitNodeWithSourceMap(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void;
/**
* Emits a token of a node node with possible leading and trailing source maps.
@ -115,10 +114,9 @@ namespace ts {
*
* @param filePath The path to the generated output file.
* @param sourceMapFilePath The path to the output source map file.
* @param sourceFiles The input source files for the program.
* @param isBundledEmit A value indicating whether the generated output file is a bundle.
* @param sourceFileOrBundle The input source file or bundle for the program.
*/
function initialize(filePath: string, sourceMapFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean) {
function initialize(filePath: string, sourceMapFilePath: string, sourceFileOrBundle: SourceFile | Bundle) {
if (disabled) {
return;
}
@ -161,11 +159,10 @@ namespace ts {
if (compilerOptions.mapRoot) {
sourceMapDir = normalizeSlashes(compilerOptions.mapRoot);
if (!isBundledEmit) { // emitting single module file
Debug.assert(sourceFiles.length === 1);
if (sourceFileOrBundle.kind === SyntaxKind.SourceFile) { // emitting single module file
// For modules or multiple emit files the mapRoot will have directory structure like the sources
// So if src\a.ts and src\lib\b.ts are compiled together user would be moving the maps into mapRoot\a.js.map and mapRoot\lib\b.js.map
sourceMapDir = getDirectoryPath(getSourceFilePathInNewDir(sourceFiles[0], host, sourceMapDir));
sourceMapDir = getDirectoryPath(getSourceFilePathInNewDir(sourceFileOrBundle, host, sourceMapDir));
}
if (!isRootedDiskPath(sourceMapDir) && !isUrl(sourceMapDir)) {
@ -311,12 +308,13 @@ namespace ts {
/**
* Emits a node with possible leading and trailing source maps.
*
* @param hint A hint as to the intended usage of the node.
* @param node The node to emit.
* @param emitCallback The callback used to emit the node.
*/
function emitNodeWithSourceMap(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void) {
function emitNodeWithSourceMap(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) {
if (disabled) {
return emitCallback(emitContext, node);
return emitCallback(hint, node);
}
if (node) {
@ -332,11 +330,11 @@ namespace ts {
if (emitFlags & EmitFlags.NoNestedSourceMaps) {
disabled = true;
emitCallback(emitContext, node);
emitCallback(hint, node);
disabled = false;
}
else {
emitCallback(emitContext, node);
emitCallback(hint, node);
}
if (node.kind !== SyntaxKind.NotEmittedStatement

View file

@ -105,14 +105,16 @@ namespace ts {
hoistFunctionDeclaration,
requestEmitHelper,
readEmitHelpers,
onSubstituteNode: (_emitContext, node) => node,
onSubstituteNode: (_, node) => node,
enableSubstitution,
isSubstitutionEnabled,
onEmitNode: (node, emitContext, emitCallback) => emitCallback(node, emitContext),
onEmitNode: (hint, node, callback) => callback(hint, node),
enableEmitNotification,
isEmitNotificationEnabled
};
performance.mark("beforeTransform");
// Chain together and initialize each transformer.
const transformation = chain(...transformers)(context);
@ -122,6 +124,9 @@ namespace ts {
// Disable modification of the lexical environment.
lexicalEnvironmentDisabled = true;
performance.mark("afterTransform");
performance.measure("transformTime", "beforeTransform", "afterTransform");
return {
transformed,
emitNodeWithSubstitution,
@ -159,21 +164,16 @@ namespace ts {
/**
* Emits a node with possible substitution.
*
* @param emitContext The current emit context.
* @param hint A hint as to the intended usage of the node.
* @param node The node to emit.
* @param emitCallback The callback used to emit the node or its substitute.
*/
function emitNodeWithSubstitution(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void) {
function emitNodeWithSubstitution(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) {
if (node) {
if (isSubstitutionEnabled(node)) {
const substitute = context.onSubstituteNode(emitContext, node);
if (substitute && substitute !== node) {
emitCallback(emitContext, substitute);
return;
}
node = context.onSubstituteNode(hint, node) || node;
}
emitCallback(emitContext, node);
emitCallback(hint, node);
}
}
@ -196,17 +196,17 @@ namespace ts {
/**
* Emits a node with possible emit notification.
*
* @param emitContext The current emit context.
* @param hint A hint as to the intended usage of the node.
* @param node The node to emit.
* @param emitCallback The callback used to emit the node.
*/
function emitNodeWithNotification(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void) {
function emitNodeWithNotification(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) {
if (node) {
if (isEmitNotificationEnabled(node)) {
context.onEmitNode(emitContext, node, emitCallback);
context.onEmitNode(hint, node, emitCallback);
}
else {
emitCallback(emitContext, node);
emitCallback(hint, node);
}
}
}

View file

@ -3435,9 +3435,11 @@ namespace ts {
/**
* Called by the printer just before a node is printed.
*
* @param hint A hint as to the intended usage of the node.
* @param node The node to be printed.
* @param emitCallback The callback used to emit the node.
*/
function onEmitNode(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void) {
function onEmitNode(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) {
if (enabledSubstitutions & ES2015SubstitutionFlags.CapturedThis && isFunctionLike(node)) {
// If we are tracking a captured `this`, keep track of the enclosing function.
const ancestorFacts = enterSubtree(
@ -3445,11 +3447,11 @@ namespace ts {
getEmitFlags(node) & EmitFlags.CapturesThis
? HierarchyFacts.FunctionIncludes | HierarchyFacts.CapturesThis
: HierarchyFacts.FunctionIncludes);
previousOnEmitNode(emitContext, node, emitCallback);
previousOnEmitNode(hint, node, emitCallback);
exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None);
return;
}
previousOnEmitNode(emitContext, node, emitCallback);
previousOnEmitNode(hint, node, emitCallback);
}
/**
@ -3484,13 +3486,13 @@ namespace ts {
/**
* Hooks node substitutions.
*
* @param emitContext The context for the emitter.
* @param hint The context for the emitter.
* @param node The node to substitute.
*/
function onSubstituteNode(emitContext: EmitContext, node: Node) {
node = previousOnSubstituteNode(emitContext, node);
function onSubstituteNode(hint: EmitHint, node: Node) {
node = previousOnSubstituteNode(hint, node);
if (emitContext === EmitContext.Expression) {
if (hint === EmitHint.Expression) {
return substituteExpression(node);
}

View file

@ -396,33 +396,33 @@ namespace ts {
/**
* Hook for node emit.
*
* @param hint A hint as to the intended usage of the node.
* @param node The node to emit.
* @param emit A callback used to emit the node in the printer.
*/
function onEmitNode(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void): void {
function onEmitNode(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void {
// If we need to support substitutions for `super` in an async method,
// we should track it here.
if (enabledSubstitutions & ES2017SubstitutionFlags.AsyncMethodsWithSuper && isSuperContainer(node)) {
const savedCurrentSuperContainer = currentSuperContainer;
currentSuperContainer = node;
previousOnEmitNode(emitContext, node, emitCallback);
previousOnEmitNode(hint, node, emitCallback);
currentSuperContainer = savedCurrentSuperContainer;
}
else {
previousOnEmitNode(emitContext, node, emitCallback);
previousOnEmitNode(hint, node, emitCallback);
}
}
/**
* Hooks node substitutions.
*
* @param hint A hint as to the intended usage of the node.
* @param node The node to substitute.
* @param isExpression A value indicating whether the node is to be used in an expression
* position.
*/
function onSubstituteNode(emitContext: EmitContext, node: Node) {
node = previousOnSubstituteNode(emitContext, node);
if (emitContext === EmitContext.Expression) {
function onSubstituteNode(hint: EmitHint, node: Node) {
node = previousOnSubstituteNode(hint, node);
if (hint === EmitHint.Expression) {
return substituteExpression(<Expression>node);
}

View file

@ -12,7 +12,7 @@ namespace ts {
const compilerOptions = context.getCompilerOptions();
// enable emit notification only if using --jsx preserve or react-native
let previousOnEmitNode: (emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void) => void;
let previousOnEmitNode: (hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) => void;
let noSubstitution: boolean[];
if (compilerOptions.jsx === JsxEmit.Preserve || compilerOptions.jsx === JsxEmit.ReactNative) {
previousOnEmitNode = context.onEmitNode;
@ -41,9 +41,11 @@ namespace ts {
/**
* Called by the printer just before a node is printed.
*
* @param node The node to be printed.
* @param hint A hint as to the intended usage of the node.
* @param node The node to emit.
* @param emitCallback A callback used to emit the node.
*/
function onEmitNode(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void) {
function onEmitNode(hint: EmitHint, node: Node, emitCallback: (emitContext: EmitHint, node: Node) => void) {
switch (node.kind) {
case SyntaxKind.JsxOpeningElement:
case SyntaxKind.JsxClosingElement:
@ -53,21 +55,21 @@ namespace ts {
break;
}
previousOnEmitNode(emitContext, node, emitCallback);
previousOnEmitNode(hint, node, emitCallback);
}
/**
* Hooks node substitutions.
*
* @param emitContext The context for the emitter.
* @param hint A hint as to the intended usage of the node.
* @param node The node to substitute.
*/
function onSubstituteNode(emitContext: EmitContext, node: Node) {
function onSubstituteNode(hint: EmitHint, node: Node) {
if (node.id && noSubstitution && noSubstitution[node.id]) {
return previousOnSubstituteNode(emitContext, node);
return previousOnSubstituteNode(hint, node);
}
node = previousOnSubstituteNode(emitContext, node);
node = previousOnSubstituteNode(hint, node);
if (isPropertyAccessExpression(node)) {
return substitutePropertyAccessExpression(node);
}

View file

@ -1909,9 +1909,9 @@ namespace ts {
return -1;
}
function onSubstituteNode(emitContext: EmitContext, node: Node): Node {
node = previousOnSubstituteNode(emitContext, node);
if (emitContext === EmitContext.Expression) {
function onSubstituteNode(hint: EmitHint, node: Node): Node {
node = previousOnSubstituteNode(hint, node);
if (hint === EmitHint.Expression) {
return substituteExpression(<Expression>node);
}
return node;

View file

@ -71,18 +71,18 @@ namespace ts {
/**
* Hook for node emit.
*
* @param emitContext A context hint for the emitter.
* @param hint A hint as to the intended usage of the node.
* @param node The node to emit.
* @param emit A callback used to emit the node in the printer.
*/
function onEmitNode(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void): void {
function onEmitNode(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void {
if (isSourceFile(node)) {
currentSourceFile = node;
previousOnEmitNode(emitContext, node, emitCallback);
previousOnEmitNode(hint, node, emitCallback);
currentSourceFile = undefined;
}
else {
previousOnEmitNode(emitContext, node, emitCallback);
previousOnEmitNode(hint, node, emitCallback);
}
}
@ -93,12 +93,12 @@ namespace ts {
/**
* Hooks node substitutions.
*
* @param emitContext A context hint for the emitter.
* @param hint A hint as to the intended usage of the node.
* @param node The node to substitute.
*/
function onSubstituteNode(emitContext: EmitContext, node: Node) {
node = previousOnSubstituteNode(emitContext, node);
if (isIdentifier(node) && emitContext === EmitContext.Expression) {
function onSubstituteNode(hint: EmitHint, node: Node) {
node = previousOnSubstituteNode(hint, node);
if (isIdentifier(node) && hint === EmitHint.Expression) {
return substituteExpressionIdentifier(node);
}
return node;

View file

@ -1207,24 +1207,24 @@ namespace ts {
/**
* Hook for node emit notifications.
*
* @param emitContext A context hint for the emitter.
* @param hint A hint as to the intended usage of the node.
* @param node The node to emit.
* @param emit A callback used to emit the node in the printer.
*/
function onEmitNode(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void): void {
function onEmitNode(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void {
if (node.kind === SyntaxKind.SourceFile) {
currentSourceFile = <SourceFile>node;
currentModuleInfo = moduleInfoMap[getOriginalNodeId(currentSourceFile)];
noSubstitution = [];
previousOnEmitNode(emitContext, node, emitCallback);
previousOnEmitNode(hint, node, emitCallback);
currentSourceFile = undefined;
currentModuleInfo = undefined;
noSubstitution = undefined;
}
else {
previousOnEmitNode(emitContext, node, emitCallback);
previousOnEmitNode(hint, node, emitCallback);
}
}
@ -1235,16 +1235,16 @@ namespace ts {
/**
* Hooks node substitutions.
*
* @param emitContext A context hint for the emitter.
* @param hint A hint as to the intended usage of the node.
* @param node The node to substitute.
*/
function onSubstituteNode(emitContext: EmitContext, node: Node) {
node = previousOnSubstituteNode(emitContext, node);
function onSubstituteNode(hint: EmitHint, node: Node) {
node = previousOnSubstituteNode(hint, node);
if (node.id && noSubstitution[node.id]) {
return node;
}
if (emitContext === EmitContext.Expression) {
if (hint === EmitHint.Expression) {
return substituteExpression(<Expression>node);
}
else if (isShorthandPropertyAssignment(node)) {

View file

@ -1548,11 +1548,11 @@ namespace ts {
/**
* Hook for node emit notifications.
*
* @param emitContext A context hint for the emitter.
* @param hint A hint as to the intended usage of the node.
* @param node The node to emit.
* @param emit A callback used to emit the node in the printer.
* @param emitCallback A callback used to emit the node in the printer.
*/
function onEmitNode(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void): void {
function onEmitNode(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void {
if (node.kind === SyntaxKind.SourceFile) {
const id = getOriginalNodeId(node);
currentSourceFile = <SourceFile>node;
@ -1564,7 +1564,7 @@ namespace ts {
delete noSubstitutionMap[id];
}
previousOnEmitNode(emitContext, node, emitCallback);
previousOnEmitNode(hint, node, emitCallback);
currentSourceFile = undefined;
moduleInfo = undefined;
@ -1572,7 +1572,7 @@ namespace ts {
noSubstitution = undefined;
}
else {
previousOnEmitNode(emitContext, node, emitCallback);
previousOnEmitNode(hint, node, emitCallback);
}
}
@ -1583,16 +1583,16 @@ namespace ts {
/**
* Hooks node substitutions.
*
* @param emitContext A context hint for the emitter.
* @param hint A hint as to the intended usage of the node.
* @param node The node to substitute.
*/
function onSubstituteNode(emitContext: EmitContext, node: Node) {
node = previousOnSubstituteNode(emitContext, node);
function onSubstituteNode(hint: EmitHint, node: Node) {
node = previousOnSubstituteNode(hint, node);
if (isSubstitutionPrevented(node)) {
return node;
}
if (emitContext === EmitContext.Expression) {
if (hint === EmitHint.Expression) {
return substituteExpression(<Expression>node);
}

View file

@ -3154,11 +3154,11 @@ namespace ts {
/**
* Hook for node emit.
*
* @param emitContext A context hint for the emitter.
* @param hint A hint as to the intended usage of the node.
* @param node The node to emit.
* @param emit A callback used to emit the node in the printer.
*/
function onEmitNode(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void): void {
function onEmitNode(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void {
const savedApplicableSubstitutions = applicableSubstitutions;
if (enabledSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports && isTransformedModuleDeclaration(node)) {
@ -3169,7 +3169,7 @@ namespace ts {
applicableSubstitutions |= TypeScriptSubstitutionFlags.NonQualifiedEnumMembers;
}
previousOnEmitNode(emitContext, node, emitCallback);
previousOnEmitNode(hint, node, emitCallback);
applicableSubstitutions = savedApplicableSubstitutions;
}
@ -3177,12 +3177,12 @@ namespace ts {
/**
* Hooks node substitutions.
*
* @param emitContext A context hint for the emitter.
* @param hint A hint as to the intended usage of the node.
* @param node The node to substitute.
*/
function onSubstituteNode(emitContext: EmitContext, node: Node) {
node = previousOnSubstituteNode(emitContext, node);
if (emitContext === EmitContext.Expression) {
function onSubstituteNode(hint: EmitHint, node: Node) {
node = previousOnSubstituteNode(hint, node);
if (hint === EmitHint.Expression) {
return substituteExpression(<Expression>node);
}
else if (isShorthandPropertyAssignment(node)) {

View file

@ -34,6 +34,7 @@
"comments.ts",
"sourcemap.ts",
"declarationEmitter.ts",
"printer.ts",
"emitter.ts",
"program.ts",
"commandLineParser.ts",

View file

@ -348,6 +348,7 @@
EnumMember,
// Top-level nodes
SourceFile,
Bundle,
// JSDoc nodes
JSDocTypeExpression,
@ -557,15 +558,6 @@
export type ModifiersArray = NodeArray<Modifier>;
/*@internal*/
export const enum GeneratedIdentifierKind {
None, // Not automatically generated.
Auto, // Automatically generated identifier.
Loop, // Automatically generated identifier with a preference for '_i'.
Unique, // Unique name based on the 'text' property.
Node, // Unique name based on the node in the 'original' property.
}
export interface Identifier extends PrimaryExpression {
kind: SyntaxKind.Identifier;
text: string; // Text of identifier (with escapes converted to characters)
@ -580,7 +572,14 @@
resolvedSymbol: Symbol;
}
/*@internal*/
export const enum GeneratedIdentifierKind {
None, // Not automatically generated.
Auto, // Automatically generated identifier.
Loop, // Automatically generated identifier with a preference for '_i'.
Unique, // Unique name based on the 'text' property.
Node, // Unique name based on the node in the 'original' property.
}
export interface GeneratedIdentifier extends Identifier {
autoGenerateKind: GeneratedIdentifierKind.Auto
| GeneratedIdentifierKind.Loop
@ -2201,6 +2200,11 @@
/* @internal */ ambientModuleNames: string[];
}
export interface Bundle extends Node {
kind: SyntaxKind.Bundle;
sourceFiles: SourceFile[];
}
export interface ScriptReferenceHost {
getCompilerOptions(): CompilerOptions;
getSourceFile(fileName: string): SourceFile;
@ -3780,8 +3784,7 @@
LastEmitHelper = Generator
}
/* @internal */
export const enum EmitContext {
export const enum EmitHint {
SourceFile, // Emitting a SourceFile
Expression, // Emitting an Expression
IdentifierName, // Emitting an IdentifierName
@ -3856,7 +3859,7 @@
* Hook used by transformers to substitute expressions just before they
* are emitted by the pretty printer.
*/
onSubstituteNode?: (emitContext: EmitContext, node: Node) => Node;
onSubstituteNode?: (hint: EmitHint, node: Node) => Node;
/**
* Enables before/after emit notifications in the pretty printer for the provided
@ -3874,7 +3877,7 @@
* Hook used to allow transformers to capture state before or after
* the printer emits a node.
*/
onEmitNode?: (emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void) => void;
onEmitNode?: (hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) => void;
}
/* @internal */
@ -3887,25 +3890,61 @@
/**
* Emits the substitute for a node, if one is available; otherwise, emits the node.
*
* @param emitContext The current emit context.
* @param hint A hint as to the intended usage of the node.
* @param node The node to substitute.
* @param emitCallback A callback used to emit the node or its substitute.
*/
emitNodeWithSubstitution(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void): void;
emitNodeWithSubstitution(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void;
/**
* Emits a node with possible notification.
*
* @param emitContext The current emit context.
* @param hint A hint as to the intended usage of the node.
* @param node The node to emit.
* @param emitCallback A callback used to emit the node.
*/
emitNodeWithNotification(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void): void;
emitNodeWithNotification(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void;
}
/* @internal */
export type Transformer = (context: TransformationContext) => (node: SourceFile) => SourceFile;
export interface EmitTextWriter {
write(s: string): void;
writeTextOfNode(text: string, node: Node): void;
writeLine(): void;
increaseIndent(): void;
decreaseIndent(): void;
getText(): string;
rawWrite(s: string): void;
writeLiteral(s: string): void;
getTextPos(): number;
getLine(): number;
getColumn(): number;
getIndent(): number;
isAtStartOfLine(): boolean;
reset(): void;
}
export interface Printer {
printNode(hint: EmitHint, node: Node, sourceFile: SourceFile): void;
printFile(sourceFile: SourceFile): void;
printBundle(bundle: Bundle): void;
}
export interface PrinterOptions {
hasGlobalName?: (name: string) => boolean;
onEmitSourceMapOfNode?: (hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) => void;
onEmitSourceMapOfToken?: (node: Node, token: SyntaxKind, pos: number, emitCallback: (token: SyntaxKind, pos: number) => number) => number;
onEmitCommentsOfNode?: (hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) => void;
onEmitDetachedCommentsOfNode?: (node: Node, detachedRange: TextRange, emitCallback: (node: Node) => void) => void;
onEmitTrailingCommentsOfPosition?: (pos: number) => void;
onEmitNode?: (hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) => void;
onEmitHelpers?: (node: Node, writeLines: (text: string) => void) => void;
onSetSourceFile?: (node: SourceFile) => void;
onSubstituteNode?: (hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) => void;
}
export interface TextSpan {
start: number;
length: number;

View file

@ -2088,16 +2088,19 @@ namespace ts {
return undefined;
}
export function getOriginalSourceFiles(sourceFiles: SourceFile[]) {
const originalSourceFiles: SourceFile[] = [];
for (const sourceFile of sourceFiles) {
const originalSourceFile = getParseTreeNode(sourceFile, isSourceFile);
if (originalSourceFile) {
originalSourceFiles.push(originalSourceFile);
}
export function getOriginalSourceFileOrBundle(sourceFileOrBundle: SourceFile | Bundle) {
if (sourceFileOrBundle.kind === SyntaxKind.Bundle) {
return updateBundle(sourceFileOrBundle, sameMap(sourceFileOrBundle.sourceFiles, getOriginalSourceFile));
}
return getOriginalSourceFile(sourceFileOrBundle);
}
return originalSourceFiles;
function getOriginalSourceFile(sourceFile: SourceFile) {
return getParseTreeNode(sourceFile, isSourceFile) || sourceFile;
}
export function getOriginalSourceFiles(sourceFiles: SourceFile[]) {
return sameMap(sourceFiles, getOriginalSourceFile);
}
export function getOriginalNodeId(node: Node) {
@ -2436,23 +2439,6 @@ namespace ts {
s;
}
export interface EmitTextWriter {
write(s: string): void;
writeTextOfNode(text: string, node: Node): void;
writeLine(): void;
increaseIndent(): void;
decreaseIndent(): void;
getText(): string;
rawWrite(s: string): void;
writeLiteral(s: string): void;
getTextPos(): number;
getLine(): number;
getColumn(): number;
getIndent(): number;
isAtStartOfLine(): boolean;
reset(): void;
}
const indentStrings: string[] = ["", " "];
export function getIndentString(level: number) {
if (indentStrings[level] === undefined) {
@ -2635,7 +2621,7 @@ namespace ts {
* Else, calls `getSourceFilesToEmit` with the (optional) target source file to determine the list of source files to emit.
*/
export function forEachEmittedFile(
host: EmitHost, action: (emitFileNames: EmitFileNames, sourceFiles: SourceFile[], isBundledEmit: boolean, emitOnlyDtsFiles: boolean) => void,
host: EmitHost, action: (emitFileNames: EmitFileNames, sourceFileOrBundle: SourceFile | Bundle, emitOnlyDtsFiles: boolean) => void,
sourceFilesOrTargetSourceFile?: SourceFile[] | SourceFile,
emitOnlyDtsFiles?: boolean) {
@ -2646,7 +2632,7 @@ namespace ts {
const jsFilePath = options.outFile || options.out;
const sourceMapFilePath = getSourceMapFilePath(jsFilePath, options);
const declarationFilePath = options.declaration ? removeFileExtension(jsFilePath) + ".d.ts" : undefined;
action({ jsFilePath, sourceMapFilePath, declarationFilePath }, sourceFiles, /*isBundledEmit*/true, emitOnlyDtsFiles);
action({ jsFilePath, sourceMapFilePath, declarationFilePath }, createBundle(sourceFiles), emitOnlyDtsFiles);
}
}
else {
@ -2654,7 +2640,7 @@ namespace ts {
const jsFilePath = getOwnEmitOutputFilePath(sourceFile, host, getOutputExtension(sourceFile, options));
const sourceMapFilePath = getSourceMapFilePath(jsFilePath, options);
const declarationFilePath = !isSourceFileJavaScript(sourceFile) && (emitOnlyDtsFiles || options.declaration) ? getDeclarationEmitOutputFilePath(sourceFile, host) : undefined;
action({ jsFilePath, sourceMapFilePath, declarationFilePath }, [sourceFile], /*isBundledEmit*/false, emitOnlyDtsFiles);
action({ jsFilePath, sourceMapFilePath, declarationFilePath }, sourceFile, emitOnlyDtsFiles);
}
}
}

View file

@ -37,6 +37,7 @@
"../compiler/comments.ts",
"../compiler/sourcemap.ts",
"../compiler/declarationEmitter.ts",
"../compiler/printer.ts",
"../compiler/emitter.ts",
"../compiler/program.ts",
"../compiler/commandLineParser.ts",

View file

@ -34,6 +34,7 @@
"../compiler/comments.ts",
"../compiler/sourcemap.ts",
"../compiler/declarationEmitter.ts",
"../compiler/printer.ts",
"../compiler/emitter.ts",
"../compiler/program.ts",
"../compiler/commandLineParser.ts",