microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
99.06k stars 12.29k forks source link

Allow to emit sourcemaps when printing ast #51329

Open goloveychuk opened 1 year ago

goloveychuk commented 1 year ago

Suggestion

Add printFileWithSourceMaps to printer.

🔍 Search Terms

Ast, print, printer, source maps, emit, sourcemaps.

✅ Viability Checklist

My suggestion meets these guidelines:

⭐ Suggestion

Currently, when you construct AST with typescript api, you can print it by

const printer = ts.createPrinter(printerOptions)
const text = printer.printFile(sf)

Idea is to introduce printFileWithSourceMaps, which will return both source and sourcemap.

Implementation POC: https://github.com/goloveychuk/TypeScript/commit/be0924a62423f60b876bf80506ce5babfc6ea33e

📃 Motivating Example

if (!origNode.source) {
     origNode.source = origNode.getSourceFile(); // it's used in printer, needed to support multiple source files.
}
ts.setSourceMapRange(node, origNode);
//.....
const printer = ts.createPrinter(printerOptions)
const {output, sourceMapText} = printer.printFileWithSourceMaps(sf, {outputDir: ...})

💻 Use Cases

Developers who uses typescript api to construct an AST and needs sourcemaps support.

Alternative solution

Introduce emitSourceMapPos printer hook, or smth similar, and generate sourcemap in userland.

tmcw commented 1 year ago

Similarly I'd be very interested in this either being implemented or at least enough information emitted from the printFile method so that we could build sourcemaps.

Basically - I'm doing TypeScript-to-TypeScript transformations. It doesn't seem like there's any tool better for this than TypeScript itself, or ts-morph, which is built on TypeScript. And it doesn't seem like there's any way to generate sourcemaps from TypeScript for this - only transpile generates sourcemaps.

Maybe there's another tool that can do TS-to-TS transformations with sourcemaps, but if not - this is a place where folks doing that kind of work are pretty stuck, myself included, and it would be amazing if sourcemaps were supported.

maxpatiiuk commented 1 week ago

If you are willing to use undocumented api, here is the code that TypeScript uses internally during program.emit() to generate source maps:

const host = // your TypeScript CompilerHost
const sourceFile = // your TypeScript SourceFIle;

const compilerOptions = host.getCompilerOptions();
const printer = ts.createPrinter(compilerOptions);
const sourceMapGenerator = ts.createSourceMapGenerator(
  buildContext.typeScriptHost,
  basename(sourceFile.fileName),
  "",
  dirname(sourceFile.fileName),
  compilerOptions,
);
const transformedSourceFile = result.transformed[0];
const writer = ts.createTextWriter(ts.getNewLineCharacter(compilerOptions));

printer.writeFile(transformedSourceFile, writer, sourceMapGenerator);

const printedSourceCode = writer.getText();

const sourceMapAsJson = sourceMapGenerator.toJSON();
const sourceMapAsString = sourceMapGenerator.toString();

Really hoping there would be a public API for this. My use case: I am writing a Vite plugin that needs to transform the code and emit a source map for the transformation it did. I can not use program.emit() because:

ts.transpileModule() is even worse because it's just calling program.emit() underneath, but will have a lot of overhead of creating a new program and a new source file for each file.