Skip to content

Commit

Permalink
fix(tsc-wrapped): use tsickle's new source map composition feature (#…
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
LucasSloan authored and mhevery committed Feb 7, 2017
1 parent 2e14130 commit 5bccff0
Show file tree
Hide file tree
Showing 8 changed files with 1,223 additions and 127 deletions.
465 changes: 462 additions & 3 deletions npm-shrinkwrap.clean.json

Large diffs are not rendered by default.

711 changes: 706 additions & 5 deletions npm-shrinkwrap.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
"source-map-support": "^0.4.2",
"systemjs": "0.18.10",
"ts-api-guardian": "0.1.4",
"tsickle": "^0.2.4",
"tsickle": "^0.2.6",
"tslint": "^4.1.1",
"tslint-eslint-rules": "^3.1.0",
"typescript": "^2.0.2",
Expand Down
2 changes: 1 addition & 1 deletion tools/@angular/tsc-wrapped/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

export {DecoratorDownlevelCompilerHost, MetadataWriterHost} from './src/compiler_host';
export {MetadataWriterHost} from './src/compiler_host';
export {CodegenExtension, UserError, main} from './src/main';

export {default as AngularCompilerOptions} from './src/options';
Expand Down
58 changes: 0 additions & 58 deletions tools/@angular/tsc-wrapped/src/compiler_host.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
35 changes: 27 additions & 8 deletions tools/@angular/tsc-wrapped/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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');
}

Expand Down
51 changes: 0 additions & 51 deletions tools/@angular/tsc-wrapped/test/compiler_host.spec.ts

This file was deleted.

26 changes: 26 additions & 0 deletions tools/@angular/tsc-wrapped/test/main.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,4 +238,30 @@ describe('tsc-wrapped', () => {
})
.catch(e => done.fail(e));
});

it('should produce valid source maps', (done) => {
write('tsconfig.json', `{
"compilerOptions": {
"experimentalDecorators": true,
"types": [],
"outDir": "built",
"declaration": true,
"moduleResolution": "node",
"target": "es2015",
"sourceMap": true
},
"angularCompilerOptions": {
"annotateForClosureCompiler": true
},
"files": ["test.ts"]
}`);

main(basePath, {basePath})
.then(() => {
const out = readOut('js.map');
expect(out).toContain('"sources":["../test.ts"]');
done();
})
.catch(e => done.fail(e));
});
});

0 comments on commit 5bccff0

Please sign in to comment.