Pulls transformation out of printFile to reduce number of closures. Also some additional cleanup.

This commit is contained in:
Ron Buckton
2016-05-31 13:31:38 -07:00
parent 736f09d7b0
commit b59e1dafc8
9 changed files with 2783 additions and 2638 deletions
+10 -10
View File
@@ -17136,7 +17136,7 @@ namespace ts {
function isArgumentsLocalBinding(node: Identifier): boolean {
if (!isGeneratedIdentifier(node)) {
node = getSourceTreeNodeOfType(node, isIdentifier);
node = getParseTreeNode(node, isIdentifier);
if (node) {
return getReferencedValueSymbol(node) === argumentsSymbol;
}
@@ -17182,7 +17182,7 @@ namespace ts {
// When resolved as an expression identifier, if the given node references an exported entity, return the declaration
// node of the exported entity's container. Otherwise, return undefined.
function getReferencedExportContainer(node: Identifier, prefixLocals?: boolean): SourceFile | ModuleDeclaration | EnumDeclaration {
node = getSourceTreeNodeOfType(node, isIdentifier);
node = getParseTreeNode(node, isIdentifier);
if (node) {
// When resolving the export container for the name of a module or enum
// declaration, we need to start resolution at the declaration's container.
@@ -17220,7 +17220,7 @@ namespace ts {
// When resolved as an expression identifier, if the given node references an import, return the declaration of
// that import. Otherwise, return undefined.
function getReferencedImportDeclaration(node: Identifier): Declaration {
node = getSourceTreeNodeOfType(node, isIdentifier);
node = getParseTreeNode(node, isIdentifier);
if (node) {
const symbol = getReferencedValueSymbol(node);
if (symbol && symbol.flags & SymbolFlags.Alias) {
@@ -17279,7 +17279,7 @@ namespace ts {
// return the declaration of that entity. Otherwise, return undefined.
function getReferencedDeclarationWithCollidingName(node: Identifier): Declaration {
if (!isGeneratedIdentifier(node)) {
node = getSourceTreeNodeOfType(node, isIdentifier);
node = getParseTreeNode(node, isIdentifier);
if (node) {
const symbol = getReferencedValueSymbol(node);
if (symbol && isSymbolOfDeclarationWithCollidingName(symbol)) {
@@ -17294,7 +17294,7 @@ namespace ts {
// Return true if the given node is a declaration of a nested block scoped entity with a name that either hides an
// existing name or might hide a name when compiled downlevel
function isDeclarationWithCollidingName(node: Declaration): boolean {
node = getSourceTreeNodeOfType(node, isDeclaration);
node = getParseTreeNode(node, isDeclaration);
if (node) {
const symbol = getSymbolOfNode(node);
if (symbol) {
@@ -17306,7 +17306,7 @@ namespace ts {
}
function isValueAliasDeclaration(node: Node): boolean {
node = getSourceTreeNode(node);
node = getParseTreeNode(node);
if (node === undefined) {
// A synthesized node comes from an emit transformation and is always a value.
return true;
@@ -17332,7 +17332,7 @@ namespace ts {
}
function isTopLevelValueImportEqualsWithEntityName(node: ImportEqualsDeclaration): boolean {
node = getSourceTreeNodeOfType(node, isImportEqualsDeclaration);
node = getParseTreeNode(node, isImportEqualsDeclaration);
if (node === undefined || node.parent.kind !== SyntaxKind.SourceFile || !isInternalModuleImportEqualsDeclaration(node)) {
// parent is not source file or it is not reference to internal module
return false;
@@ -17358,7 +17358,7 @@ namespace ts {
}
function isReferencedAliasDeclaration(node: Node, checkChildren?: boolean): boolean {
node = getSourceTreeNode(node);
node = getParseTreeNode(node);
if (isAliasSymbolDeclaration(node)) {
const symbol = getSymbolOfNode(node);
if (symbol && getSymbolLinks(symbol).referenced) {
@@ -17394,7 +17394,7 @@ namespace ts {
}
function getNodeCheckFlags(node: Node): NodeCheckFlags {
node = getSourceTreeNode(node);
node = getParseTreeNode(node);
return node ? getNodeLinks(node).flags : undefined;
}
@@ -17525,7 +17525,7 @@ namespace ts {
function getReferencedValueDeclaration(reference: Identifier): Declaration {
if (!isGeneratedIdentifier(reference)) {
reference = getSourceTreeNodeOfType(reference, isIdentifier);
reference = getParseTreeNode(reference, isIdentifier);
if (reference) {
const symbol = getReferencedValueSymbol(reference);
if (symbol) {
+28 -4
View File
@@ -26,6 +26,7 @@ namespace ts {
let hasWrittenComment = false;
let hasLastComment: boolean;
let lastCommentEnd: number;
let disabled: boolean = false;
return {
reset,
@@ -43,9 +44,15 @@ namespace ts {
if (node) {
const { pos, end } = node.commentRange || node;
const emitFlags = node.emitFlags;
if ((pos < 0 && end < 0) || (pos === end)) {
// Both pos and end are synthesized, so just emit the node without comments.
emitCallback(node);
if (emitFlags & NodeEmitFlags.NoNestedComments) {
disableCommentsAndEmit(node, emitCallback);
}
else {
emitCallback(node);
}
}
else {
let commentStart: number;
@@ -53,7 +60,6 @@ namespace ts {
commentStart = performance.mark();
}
const emitFlags = node.emitFlags;
const isEmittedNode = node.kind !== SyntaxKind.NotEmittedStatement;
const skipLeadingComments = pos < 0 || (emitFlags & NodeEmitFlags.NoLeadingComments) !== 0;
const skipTrailingComments = end < 0 || (emitFlags & NodeEmitFlags.NoTrailingComments) !== 0;
@@ -85,13 +91,19 @@ namespace ts {
if (extendedDiagnostics) {
performance.measure("commentTime", commentStart);
emitCallback(node);
commentStart = performance.mark();
}
if (emitFlags & NodeEmitFlags.NoNestedComments) {
disableCommentsAndEmit(node, emitCallback);
}
else {
emitCallback(node);
}
if (extendedDiagnostics) {
commentStart = performance.mark();
}
// Restore previous container state.
containerPos = savedContainerPos;
containerEnd = savedContainerEnd;
@@ -269,6 +281,18 @@ namespace ts {
currentText = currentSourceFile.text;
currentLineMap = getLineStarts(currentSourceFile);
detachedCommentsInfo = undefined;
disabled = false;
}
function disableCommentsAndEmit(node: Node, emitCallback: (node: Node) => void): void {
if (disabled) {
emitCallback(node);
}
else {
disabled = true;
emitCallback(node);
disabled = false;
}
}
function hasDetachedComments(pos: number) {
+5 -5
View File
@@ -1882,11 +1882,11 @@ namespace ts {
export function setOriginalNode<T extends Node>(node: T, original: Node): T {
node.original = original;
if (original && original.transformId && !node.transformId) {
node.transformId = original.transformId;
node.emitFlags = original.emitFlags;
node.commentRange = original.commentRange;
node.sourceMapRange = original.sourceMapRange;
if (original) {
const { emitFlags, commentRange, sourceMapRange } = original;
if (emitFlags) node.emitFlags = emitFlags;
if (commentRange) node.commentRange = commentRange;
if (sourceMapRange) node.sourceMapRange = sourceMapRange;
}
return node;
}
+2517 -2530
View File
File diff suppressed because it is too large Load Diff
+93 -49
View File
@@ -23,7 +23,52 @@ namespace ts {
EmitNotifications = 1 << 1,
}
/* @internal */
export interface TransformationResult {
/**
* Gets the transformed source files.
*/
getSourceFiles(): SourceFile[];
/**
* Gets the TextRange to use for source maps for a token of a node.
*/
getTokenSourceMapRange(node: Node, token: SyntaxKind): TextRange;
/**
* Determines whether expression substitutions are enabled for the provided node.
*/
isSubstitutionEnabled(node: Node): boolean;
/**
* Determines whether before/after emit notifications should be raised in the pretty
* printer when it emits a node.
*/
isEmitNotificationEnabled(node: Node): boolean;
/**
* Hook used by transformers to substitute expressions just before they
* are emitted by the pretty printer.
*
* @param node The node to substitute.
* @param isExpression A value indicating whether the node is in an expression context.
*/
onSubstituteNode(node: Node, isExpression: boolean): Node;
/**
* Hook used to allow transformers to capture state before or after
* the printer emits a node.
*
* @param node The node to emit.
* @param emitCallback A callback used to emit the node.
*/
onEmitNode(node: Node, emitCallback: (node: Node) => void): void;
/**
* Reset transient transformation properties on parse tree nodes.
*/
dispose(): void;
}
export interface TransformationContext extends LexicalEnvironment {
getCompilerOptions(): CompilerOptions;
getEmitResolver(): EmitResolver;
@@ -155,7 +200,7 @@ namespace ts {
* @param sourceFiles An array of source files
* @param transforms An array of Transformers.
*/
export function transformFiles(resolver: EmitResolver, host: EmitHost, sourceFiles: SourceFile[], transformers: Transformer[]) {
export function transformFiles(resolver: EmitResolver, host: EmitHost, sourceFiles: SourceFile[], transformers: Transformer[]): TransformationResult {
const transformId = nextTransformId;
nextTransformId++;
@@ -163,7 +208,7 @@ namespace ts {
const lexicalEnvironmentVariableDeclarationsStack: VariableDeclaration[][] = [];
const lexicalEnvironmentFunctionDeclarationsStack: FunctionDeclaration[][] = [];
const enabledSyntaxKindFeatures = new Array<SyntaxKindFeatureFlags>(SyntaxKind.Count);
const sourceTreeNodesWithAnnotations: Node[] = [];
const parseTreeNodesWithAnnotations: Node[] = [];
let lastTokenSourceMapRangeNode: Node;
let lastTokenSourceMapRangeToken: SyntaxKind;
@@ -171,7 +216,6 @@ namespace ts {
let lexicalEnvironmentStackOffset = 0;
let hoistedVariableDeclarations: VariableDeclaration[];
let hoistedFunctionDeclarations: FunctionDeclaration[];
let currentSourceFile: SourceFile;
let lexicalEnvironmentDisabled: boolean;
// The transformation context is provided to each transformer as part of transformer
@@ -204,7 +248,34 @@ namespace ts {
const transformation = chain(...transformers)(context);
// Transform each source file.
return map(sourceFiles, transformSourceFile);
const transformed = map(sourceFiles, transformSourceFile);
return {
getSourceFiles: () => transformed,
getTokenSourceMapRange,
isSubstitutionEnabled,
isEmitNotificationEnabled,
onSubstituteNode: context.onSubstituteNode,
onEmitNode: context.onEmitNode,
dispose() {
// During transformation we may need to annotate a parse tree node with transient
// transformation properties. As parse tree nodes live longer than transformation
// nodes, we need to make sure we reclaim any memory allocated for custom ranges
// from these nodes to ensure we do not hold onto entire subtrees just for position
// information. We also need to reset these nodes to a pre-transformation state
// for incremental parsing scenarios so that we do not impact later emit.
for (const node of parseTreeNodesWithAnnotations) {
if (node.transformId === transformId) {
node.transformId = 0;
node.emitFlags = 0;
node.commentRange = undefined;
node.sourceMapRange = undefined;
}
}
parseTreeNodesWithAnnotations.length = 0;
}
};
/**
* Transforms a source file.
@@ -216,21 +287,7 @@ namespace ts {
return sourceFile;
}
currentSourceFile = sourceFile;
sourceFile = transformation(sourceFile);
// Cleanup source tree nodes with annotations
for (const node of sourceTreeNodesWithAnnotations) {
if (node.transformId === transformId) {
node.transformId = 0;
node.emitFlags = 0;
node.commentRange = undefined;
node.sourceMapRange = undefined;
}
}
sourceTreeNodesWithAnnotations.length = 0;
return sourceFile;
return transformation(sourceFile);
}
/**
@@ -281,15 +338,6 @@ namespace ts {
* @param emit A callback used to emit the node in the printer.
*/
function onEmitNode(node: Node, emit: (node: Node) => void) {
// Ensure that lexical environment modifications are disabled during the print phase.
if (!lexicalEnvironmentDisabled) {
const savedLexicalEnvironmentDisabled = lexicalEnvironmentDisabled;
lexicalEnvironmentDisabled = true;
emit(node);
lexicalEnvironmentDisabled = savedLexicalEnvironmentDisabled;
return;
}
emit(node);
}
@@ -300,12 +348,12 @@ namespace ts {
* @param node The node.
*/
function beforeSetAnnotation(node: Node) {
node.transformId = transformId;
if ((node.flags & NodeFlags.Synthesized) === 0) {
if ((node.flags & NodeFlags.Synthesized) === 0 && node.transformId !== transformId) {
// To avoid holding onto transformation artifacts, we keep track of any
// source tree node we are annotating. This allows us to clean them up after
// parse tree node we are annotating. This allows us to clean them up after
// all transformations have completed.
sourceTreeNodesWithAnnotations.push(node);
parseTreeNodesWithAnnotations.push(node);
node.transformId = transformId;
}
}
@@ -318,7 +366,7 @@ namespace ts {
* @param node The node.
*/
function getNodeEmitFlags(node: Node) {
return node.emitFlags & ~NodeEmitFlags.HasNodeEmitFlags;
return node.emitFlags;
}
/**
@@ -329,7 +377,7 @@ namespace ts {
*/
function setNodeEmitFlags<T extends Node>(node: T, emitFlags: NodeEmitFlags) {
beforeSetAnnotation(node);
node.emitFlags = emitFlags | NodeEmitFlags.HasNodeEmitFlags;
node.emitFlags = emitFlags;
return node;
}
@@ -520,7 +568,11 @@ namespace ts {
function chain<T, U>(...args: ((t: T) => (u: U) => U)[]): (t: T) => (u: U) => U;
function chain<T, U>(a: (t: T) => (u: U) => U, b: (t: T) => (u: U) => U, c: (t: T) => (u: U) => U, d: (t: T) => (u: U) => U, e: (t: T) => (u: U) => U): (t: T) => (u: U) => U {
if (e) {
const args = arrayOf<(t: T) => (u: U) => U>(arguments);
const args: ((t: T) => (u: U) => U)[] = [];
for (let i = 0; i < arguments.length; i++) {
args[i] = arguments[i];
}
return t => compose(...map(args, f => f(t)));
}
else if (d) {
@@ -549,7 +601,11 @@ namespace ts {
function compose<T>(...args: ((t: T) => T)[]): (t: T) => T;
function compose<T>(a: (t: T) => T, b: (t: T) => T, c: (t: T) => T, d: (t: T) => T, e: (t: T) => T): (t: T) => T {
if (e) {
const args = arrayOf(arguments);
const args: ((t: T) => T)[] = [];
for (let i = 0; i < arguments.length; i++) {
args[i] = arguments[i];
}
return t => reduceLeft<(t: T) => T, T>(args, (u, f) => f(u), t);
}
else if (d) {
@@ -568,16 +624,4 @@ namespace ts {
return t => t;
}
}
/**
* Makes an array from an ArrayLike.
*/
function arrayOf<T>(arrayLike: ArrayLike<T>) {
const length = arrayLike.length;
const array: T[] = new Array<T>(length);
for (let i = 0; i < length; i++) {
array[i] = arrayLike[i];
}
return array;
}
}
+5 -7
View File
@@ -1425,15 +1425,13 @@ namespace ts {
// If we are here it is most likely because our expression is a destructuring assignment.
switch (node.expression.kind) {
case SyntaxKind.ParenthesizedExpression:
return createStatement(
visitParenthesizedExpression(<ParenthesizedExpression>node.expression, /*needsDestructuringValue*/ false),
/*location*/ node
return updateStatement(node,
visitParenthesizedExpression(<ParenthesizedExpression>node.expression, /*needsDestructuringValue*/ false)
);
case SyntaxKind.BinaryExpression:
return createStatement(
visitBinaryExpression(<BinaryExpression>node.expression, /*needsDestructuringValue*/ false),
/*location*/ node
return updateStatement(node,
visitBinaryExpression(<BinaryExpression>node.expression, /*needsDestructuringValue*/ false)
);
}
@@ -2831,7 +2829,7 @@ namespace ts {
// Only substitute the identifier if we have enabled substitutions for block-scoped
// bindings.
if (enabledSubstitutions & ES6SubstitutionFlags.BlockScopedBindings) {
const original = getSourceTreeNodeOfType(node, isIdentifier);
const original = getParseTreeNode(node, isIdentifier);
if (original && isNameOfDeclarationWithCollidingName(original)) {
return getGeneratedNameForNode(original);
}
+2 -6
View File
@@ -2767,11 +2767,6 @@ namespace ts {
&& resolver.isTopLevelValueImportEqualsWithEntityName(node));
}
function disableCommentsRecursive(node: Node) {
setNodeEmitFlags(node, NodeEmitFlags.NoComments | getNodeEmitFlags(node));
forEachChild(node, disableCommentsRecursive);
}
/**
* Visits an import equals declaration.
*
@@ -2787,7 +2782,8 @@ namespace ts {
}
const moduleReference = createExpressionFromEntityName(<EntityName>node.moduleReference);
disableCommentsRecursive(moduleReference);
setNodeEmitFlags(moduleReference, NodeEmitFlags.NoComments | NodeEmitFlags.NoNestedComments);
if (isNamedExternalModuleExport(node) || !isNamespaceExport(node)) {
// export var ${name} = ${moduleReference};
// var ${name} = ${moduleReference};
+14 -16
View File
@@ -2984,21 +2984,21 @@ namespace ts {
EmitSuperHelper = 1 << 2, // Emit the basic _super helper for async methods.
EmitAdvancedSuperHelper = 1 << 3, // Emit the advanced _super helper for async methods.
UMDDefine = 1 << 4, // This node should be replaced with the UMD define helper.
NoLexicalEnvironment = 1 << 5, // A new LexicalEnvironment should *not* be introduced when emitting this node, this is primarily used when printing a SystemJS module.
SingleLine = 1 << 6, // The contents of this node should be emitted on a single line.
AdviseOnEmitNode = 1 << 7, // The printer should invoke the onEmitNode callback when printing this node.
NoSubstitution = 1 << 8, // Disables further substitution of an expression.
CapturesThis = 1 << 9, // The function captures a lexical `this`
NoLeadingSourceMap = 1 << 10, // Do not emit a leading source map location for this node.
NoTrailingSourceMap = 1 << 11, // Do not emit a trailing source map location for this node.
SingleLine = 1 << 5, // The contents of this node should be emitted on a single line.
AdviseOnEmitNode = 1 << 6, // The printer should invoke the onEmitNode callback when printing this node.
NoSubstitution = 1 << 7, // Disables further substitution of an expression.
CapturesThis = 1 << 8, // The function captures a lexical `this`
NoLeadingSourceMap = 1 << 9, // Do not emit a leading source map location for this node.
NoTrailingSourceMap = 1 << 10, // Do not emit a trailing source map location for this node.
NoSourceMap = NoLeadingSourceMap | NoTrailingSourceMap, // Do not emit a source map location for this node.
NoNestedSourceMaps = 1 << 12, // Do not emit source map locations for children of this node.
NoTokenLeadingSourceMaps = 1 << 13, // Do not emit leading source map location for token nodes.
NoTokenTrailingSourceMaps = 1 << 14, // Do not emit trailing source map location for token nodes.
NoNestedSourceMaps = 1 << 11, // Do not emit source map locations for children of this node.
NoTokenLeadingSourceMaps = 1 << 12, // Do not emit leading source map location for token nodes.
NoTokenTrailingSourceMaps = 1 << 13, // Do not emit trailing source map location for token nodes.
NoTokenSourceMaps = NoTokenLeadingSourceMaps | NoTokenTrailingSourceMaps, // Do not emit source map locations for tokens of this node.
NoLeadingComments = 1 << 15, // Do not emit leading comments for this node.
NoTrailingComments = 1 << 16, // Do not emit trailing comments for this node.
NoLeadingComments = 1 << 14, // Do not emit leading comments for this node.
NoTrailingComments = 1 << 15, // Do not emit trailing comments for this node.
NoComments = NoLeadingComments | NoTrailingComments, // Do not emit comments for this node.
NoNestedComments = 1 << 16,
ExportName = 1 << 17, // Ensure an export prefix is added for an identifier that points to an exported declaration with a local name (see SymbolFlags.ExportHasLocal).
LocalName = 1 << 18, // Ensure an export prefix is not added for an identifier that points to an exported declaration.
Indented = 1 << 19, // Adds an explicit extra indentation level for class and function bodies when printing (used to match old emitter).
@@ -3007,10 +3007,8 @@ namespace ts {
// TODO(rbuckton): These should be removed once source maps are aligned with the old
// emitter and new baselines are taken. This exists solely to
// align with the old emitter.
SourceMapEmitOpenBraceAsToken = 1 << 21, // Emits the open brace of a block function body as a source mapped token.
SourceMapAdjustRestParameterLoop = 1 << 22, // Emits adjusted source map positions for a ForStatement generated when transforming a rest parameter for ES5/3.
HasNodeEmitFlags = 1 << 31, // Indicates the node has emit flags set.
SourceMapEmitOpenBraceAsToken = 1 << 20, // Emits the open brace of a block function body as a source mapped token.
SourceMapAdjustRestParameterLoop = 1 << 21, // Emits adjusted source map positions for a ForStatement generated when transforming a rest parameter for ES5/3.
}
/** Additional context provided to `visitEachChild` */
+109 -11
View File
@@ -1888,27 +1888,55 @@ namespace ts {
return node;
}
export function isSourceTreeNode(node: Node): boolean {
/**
* Gets a value indicating whether a node originated in the parse tree.
*
* @param node The node to test.
*/
export function isParseTreeNode(node: Node): boolean {
return (node.flags & NodeFlags.Synthesized) === 0;
}
export function getSourceTreeNode(node: Node): Node {
if (isSourceTreeNode(node)) {
/**
* Gets the original parse tree node for a node.
*
* @param node The original node.
* @returns The original parse tree node if found; otherwise, undefined.
*/
export function getParseTreeNode(node: Node): Node;
/**
* Gets the original parse tree node for a node.
*
* @param node The original node.
* @param nodeTest A callback used to ensure the correct type of parse tree node is returned.
* @returns The original parse tree node if found; otherwise, undefined.
*/
export function getParseTreeNode<T extends Node>(node: Node, nodeTest?: (node: Node) => node is T): T;
export function getParseTreeNode(node: Node, nodeTest?: (node: Node) => boolean): Node {
if (isParseTreeNode(node)) {
return node;
}
node = getOriginalNode(node);
if (isSourceTreeNode(node)) {
if (isParseTreeNode(node) && (!nodeTest || nodeTest(node))) {
return node;
}
return undefined;
}
export function getSourceTreeNodeOfType<T extends Node>(node: T, nodeTest: (node: Node) => node is T): T {
const source = getSourceTreeNode(node);
return source && nodeTest(source) ? source : undefined;
export function getOriginalSourceFiles(sourceFiles: SourceFile[]) {
const originalSourceFiles: SourceFile[] = [];
for (const sourceFile of sourceFiles) {
const originalSourceFile = getParseTreeNode(sourceFile, isSourceFile);
if (originalSourceFile) {
originalSourceFiles.push(originalSourceFile);
}
}
return originalSourceFiles;
}
export function getOriginalNodeId(node: Node) {
@@ -2419,6 +2447,80 @@ namespace ts {
declarationFilePath: string;
}
export function getSourceFilesToEmit(host: EmitHost, targetSourceFile?: SourceFile) {
const options = host.getCompilerOptions();
if (options.outFile || options.out) {
const moduleKind = getEmitModuleKind(options);
const moduleEmitEnabled = moduleKind === ModuleKind.AMD || moduleKind === ModuleKind.System;
const sourceFiles = host.getSourceFiles();
// Can emit only sources that are not declaration file and are either non module code or module with --module or --target es6 specified
return filter(sourceFiles, moduleEmitEnabled ? isNonDeclarationFile : isBundleEmitNonExternalModule);
}
else {
const sourceFiles = targetSourceFile === undefined ? host.getSourceFiles() : [targetSourceFile];
return filter(sourceFiles, isNonDeclarationFile);
}
}
function isNonDeclarationFile(sourceFile: SourceFile) {
return !isDeclarationFile(sourceFile);
}
function isBundleEmitNonExternalModule(sourceFile: SourceFile) {
return !isDeclarationFile(sourceFile) && !isExternalModule(sourceFile);
}
export function forEachEmitFile(host: EmitHost, sourceFiles: SourceFile[],
action: (jsFilePath: string, sourceMapFilePath: string, declarationFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean) => void) {
const options = host.getCompilerOptions();
// Emit on each source file
if (options.outFile || options.out) {
onBundledEmit(host, sourceFiles);
}
else {
for (const sourceFile of sourceFiles) {
if (!isDeclarationFile(sourceFile)) {
onSingleFileEmit(host, sourceFile);
}
}
}
function onSingleFileEmit(host: EmitHost, sourceFile: SourceFile) {
// JavaScript files are always LanguageVariant.JSX, as JSX syntax is allowed in .js files also.
// So for JavaScript files, '.jsx' is only emitted if the input was '.jsx', and JsxEmit.Preserve.
// For TypeScript, the only time to emit with a '.jsx' extension, is on JSX input, and JsxEmit.Preserve
let extension = ".js";
if (options.jsx === JsxEmit.Preserve) {
if (isSourceFileJavaScript(sourceFile)) {
if (fileExtensionIs(sourceFile.fileName, ".jsx")) {
extension = ".jsx";
}
}
else if (sourceFile.languageVariant === LanguageVariant.JSX) {
// TypeScript source file preserving JSX syntax
extension = ".jsx";
}
}
const jsFilePath = getOwnEmitOutputFilePath(sourceFile, host, extension);
const sourceMapFilePath = getSourceMapFilePath(jsFilePath, options);
const declarationFilePath = !isSourceFileJavaScript(sourceFile) ? getDeclarationEmitOutputFilePath(sourceFile, host) : undefined;
action(jsFilePath, sourceMapFilePath, declarationFilePath, [sourceFile], /*isBundledEmit*/ false);
}
function onBundledEmit(host: EmitHost, sourceFiles: SourceFile[]) {
if (sourceFiles.length) {
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);
}
}
}
function getSourceMapFilePath(jsFilePath: string, options: CompilerOptions) {
return options.sourceMap ? jsFilePath + ".map" : undefined;
}
export function forEachExpectedEmitFile(host: EmitHost,
action: (emitFileNames: EmitFileNames, sourceFiles: SourceFile[], isBundledEmit: boolean) => void,
targetSourceFile?: SourceFile) {
@@ -2479,10 +2581,6 @@ namespace ts {
action(emitFileNames, bundledSources, /*isBundledEmit*/true);
}
}
function getSourceMapFilePath(jsFilePath: string, options: CompilerOptions) {
return options.sourceMap ? jsFilePath + ".map" : undefined;
}
}
export function getSourceFilePathInNewDir(sourceFile: SourceFile, host: EmitHost, newDirPath: string) {