Skip to content

After Transformer called with a Bundle, not a Source file #24459

Closed
@LucasSloan

Description

@LucasSloan

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    APIRelates to the public API for TypeScriptBugA bug in TypeScriptHelp WantedYou can do this

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions