fix(tsc-wrapped): use tsickle's new source map composition feature (#14150)
Tsickle transforms typescript code, which can change the location of code. This can cause issues such as runtime stack traces reporting that errors were raised on the incorrect line in the orginal source. This change replaces the DecoratorDownlevelCompilerHost and the TsickleCompilerHost with tsickle's TsickleCompilerHost, which automatically composes tsickle's source maps with typescript's source maps, so that line numbers are correctly reported at runtime. PR Close #14150
This commit is contained in:

committed by
Miško Hevery

parent
2e1413016e
commit
5bccff0d7a
@ -50,64 +50,6 @@ export abstract class DelegatingHost implements ts.CompilerHost {
|
||||
directoryExists = (directoryName: string) => this.delegate.directoryExists(directoryName);
|
||||
}
|
||||
|
||||
export class DecoratorDownlevelCompilerHost extends DelegatingHost {
|
||||
private ANNOTATION_SUPPORT = `
|
||||
interface DecoratorInvocation {
|
||||
type: Function;
|
||||
args?: any[];
|
||||
}
|
||||
`;
|
||||
/** Error messages produced by tsickle, if any. */
|
||||
public diagnostics: ts.Diagnostic[] = [];
|
||||
|
||||
constructor(delegate: ts.CompilerHost, private program: ts.Program) { super(delegate); }
|
||||
|
||||
getSourceFile =
|
||||
(fileName: string, languageVersion: ts.ScriptTarget, onError?: (message: string) => void) => {
|
||||
const originalContent = this.delegate.readFile(fileName);
|
||||
let newContent = originalContent;
|
||||
if (!/\.d\.ts$/.test(fileName)) {
|
||||
try {
|
||||
const converted = tsickle.convertDecorators(
|
||||
this.program.getTypeChecker(), this.program.getSourceFile(fileName));
|
||||
if (converted.diagnostics) {
|
||||
this.diagnostics.push(...converted.diagnostics);
|
||||
}
|
||||
newContent = converted.output + this.ANNOTATION_SUPPORT;
|
||||
} catch (e) {
|
||||
console.error('Cannot convertDecorators on file', fileName);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return ts.createSourceFile(fileName, newContent, languageVersion, true);
|
||||
}
|
||||
}
|
||||
|
||||
export class TsickleCompilerHost extends DelegatingHost {
|
||||
/** Error messages produced by tsickle, if any. */
|
||||
public diagnostics: ts.Diagnostic[] = [];
|
||||
|
||||
constructor(
|
||||
delegate: ts.CompilerHost, private oldProgram: ts.Program, private options: NgOptions) {
|
||||
super(delegate);
|
||||
}
|
||||
|
||||
getSourceFile =
|
||||
(fileName: string, languageVersion: ts.ScriptTarget, onError?: (message: string) => void) => {
|
||||
let sourceFile = this.oldProgram.getSourceFile(fileName);
|
||||
let isDefinitions = /\.d\.ts$/.test(fileName);
|
||||
// Don't tsickle-process any d.ts that isn't a compilation target;
|
||||
// this means we don't process e.g. lib.d.ts.
|
||||
if (isDefinitions) return sourceFile;
|
||||
const es2015Target = this.options.target == ts.ScriptTarget.ES2015; // This covers ES6 too
|
||||
let {output, externs, diagnostics} = tsickle.annotate(
|
||||
this.oldProgram, sourceFile, {untyped: true, convertIndexImportShorthand: es2015Target},
|
||||
this.delegate, this.options);
|
||||
this.diagnostics = diagnostics;
|
||||
return ts.createSourceFile(fileName, output, languageVersion, true);
|
||||
}
|
||||
}
|
||||
|
||||
const IGNORED_FILES = /\.ngfactory\.js$|\.ngstyle\.js$/;
|
||||
|
||||
export class MetadataWriterHost extends DelegatingHost {
|
||||
|
@ -8,12 +8,13 @@
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as tsickle from 'tsickle';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {check, tsc} from './tsc';
|
||||
|
||||
import NgOptions from './options';
|
||||
import {MetadataWriterHost, DecoratorDownlevelCompilerHost, TsickleCompilerHost} from './compiler_host';
|
||||
import {MetadataWriterHost} from './compiler_host';
|
||||
import {CliOptions} from './cli_options';
|
||||
import {VinylFile, isVinylFile} from './vinyl_file';
|
||||
|
||||
@ -77,22 +78,40 @@ export function main(
|
||||
let preprocessHost = host;
|
||||
let programForJsEmit = programWithCodegen;
|
||||
|
||||
|
||||
const tsickleCompilerHostOptions: tsickle.Options = {
|
||||
googmodule: false,
|
||||
untyped: true,
|
||||
convertIndexImportShorthand:
|
||||
ngOptions.target === ts.ScriptTarget.ES2015, // This covers ES6 too
|
||||
};
|
||||
|
||||
const tsickleHost: tsickle.TsickleHost = {
|
||||
shouldSkipTsickleProcessing: (fileName) => false,
|
||||
pathToModuleName: (context, importPath) => '',
|
||||
shouldIgnoreWarningsForPath: (filePath) => false,
|
||||
fileNameToModuleId: (fileName) => fileName,
|
||||
};
|
||||
|
||||
const tsickleCompilerHost = new tsickle.TsickleCompilerHost(
|
||||
preprocessHost, ngOptions, tsickleCompilerHostOptions, tsickleHost);
|
||||
|
||||
if (ngOptions.annotationsAs !== 'decorators') {
|
||||
if (diagnostics) console.time('NG downlevel');
|
||||
const downlevelHost = new DecoratorDownlevelCompilerHost(preprocessHost, programForJsEmit);
|
||||
tsickleCompilerHost.reconfigureForRun(programForJsEmit, tsickle.Pass.DECORATOR_DOWNLEVEL);
|
||||
// A program can be re-used only once; save the programWithCodegen to be reused by
|
||||
// metadataWriter
|
||||
programForJsEmit = createProgram(downlevelHost);
|
||||
check(downlevelHost.diagnostics);
|
||||
preprocessHost = downlevelHost;
|
||||
programForJsEmit = createProgram(tsickleCompilerHost);
|
||||
check(tsickleCompilerHost.diagnostics);
|
||||
preprocessHost = tsickleCompilerHost;
|
||||
if (diagnostics) console.timeEnd('NG downlevel');
|
||||
}
|
||||
|
||||
if (ngOptions.annotateForClosureCompiler) {
|
||||
if (diagnostics) console.time('NG JSDoc');
|
||||
const tsickleHost = new TsickleCompilerHost(preprocessHost, programForJsEmit, ngOptions);
|
||||
programForJsEmit = createProgram(tsickleHost);
|
||||
check(tsickleHost.diagnostics);
|
||||
tsickleCompilerHost.reconfigureForRun(programForJsEmit, tsickle.Pass.CLOSURIZE);
|
||||
programForJsEmit = createProgram(tsickleCompilerHost);
|
||||
check(tsickleCompilerHost.diagnostics);
|
||||
if (diagnostics) console.timeEnd('NG JSDoc');
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user