Closed
Description
TypeScript Version: 2.9.0-rc
Search Terms: bundle transformer
Code
import * as ts from 'typescript';
import * as path from 'path';
const {cachedLibPath, cachedLib} = (() => {
const host = ts.createCompilerHost({});
const fn = host.getDefaultLibFileName({});
const p = ts.getDefaultLibFilePath({});
return {
// Normalize path to fix mixed/wrong directory separators on Windows.
cachedLibPath: path.normalize(p),
cachedLib: host.getSourceFile(fn, ts.ScriptTarget.Latest),
};
})();
const reproTransformer: (context: ts.TransformationContext) => ts.Transformer<ts.SourceFile> =
(context: ts.TransformationContext): ts.Transformer<ts.SourceFile> => {
return (sf: ts.SourceFile): ts.SourceFile => {
console.error(ts.SyntaxKind[sf.kind]);
return sf;
}
}
function createSourceCachingHost(
sources: Map<string, string>, options: ts.CompilerOptions): ts.CompilerHost {
const host = ts.createCompilerHost({});
host.getSourceFile = (fileName: string, languageVersion: ts.ScriptTarget,
onError?: (msg: string) => void): ts.SourceFile|undefined => {
// Normalize path to fix wrong directory separators on Windows which
// would break the equality check.
fileName = path.normalize(fileName);
if (fileName === cachedLibPath) return cachedLib;
if (path.isAbsolute(fileName)) fileName = path.relative(process.cwd(), fileName);
const contents = sources.get(fileName);
if (contents !== undefined) {
return ts.createSourceFile(fileName, contents, ts.ScriptTarget.Latest, true);
}
throw new Error(
'unexpected file read of ' + fileName + ' not in ' + Array.from(sources.keys()));
};
const originalFileExists = host.fileExists;
host.fileExists = (fileName: string): boolean => {
if (path.isAbsolute(fileName)) fileName = path.relative(process.cwd(), fileName);
if (sources.has(fileName)) {
return true;
}
// Typescript occasionally needs to look on disk for files we don't pass into
// the program as a source (eg to resolve a module that's in node_modules),
// but only .ts files explicitly passed in should be findable
if (/\.ts$/.test(fileName)) {
return false;
}
return originalFileExists.call(host, fileName);
};
return host;
}
function emit(sources: Map<string, string>, options: ts.CompilerOptions) {
const fileNames = Array.from(sources.keys());
const tsHost = createSourceCachingHost(sources, options);
const program = ts.createProgram(fileNames, options, tsHost);
const tsTransformers: ts.CustomTransformers = {
after: [reproTransformer],
}
program.emit(undefined, undefined, undefined, undefined, tsTransformers);
}
const one_source_file = new Map([['a.ts', 'const x = 1']]);
const two_source_files = new Map([['a.ts', 'const x = 1'], ['b.ts', 'const y = ""']]);
emit(one_source_file, {});
emit(two_source_files, {outFile: 'c.js'});
Expected behavior:
reproTransformer is a scheduled as an after transformer, and the type for ts.CustomTransformers says that it will only ever be called with a SourceFile, so the two emit calls should print out:
SourceFile
SourceFile
SourceFile
Actual behavior:
SourceFile
Bundle
I tested without the outFile flag, and I got the expected behavior, so the issue is to do with the outfile.