fix(compiler): make sourcemaps work in AOT mode
Inlcuded fixes: - include preamble in generated source map - always add a mapping for line/col 0 so that the generated sourcemap is not sparse - use a uniue sourceUrl for inline templates even in the AOT case
This commit is contained in:

committed by
Chuck Jazdzewski

parent
c0e05e6f03
commit
492153a986
@ -25,7 +25,7 @@ export function main() {
|
||||
ctx.print(createSourceSpan(fileA, 1), 'o1');
|
||||
ctx.print(createSourceSpan(fileB, 0), 'o2');
|
||||
ctx.print(createSourceSpan(fileB, 1), 'o3');
|
||||
const sm = ctx.toSourceMapGenerator('o.js').toJSON();
|
||||
const sm = ctx.toSourceMapGenerator('o.ts', 'o.js').toJSON();
|
||||
expect(sm.sources).toEqual([fileA.url, fileB.url]);
|
||||
expect(sm.sourcesContent).toEqual([fileA.content, fileB.content]);
|
||||
});
|
||||
@ -43,7 +43,7 @@ export function main() {
|
||||
it('should be able to shift the content', () => {
|
||||
ctx.print(createSourceSpan(fileA, 0), 'fileA-0');
|
||||
|
||||
const sm = ctx.toSourceMapGenerator(null, 10).toJSON();
|
||||
const sm = ctx.toSourceMapGenerator('o.ts', 'o.js', 10).toJSON();
|
||||
expect(originalPositionFor(sm, {line: 11, column: 0})).toEqual({
|
||||
line: 1,
|
||||
column: 0,
|
||||
@ -51,13 +51,23 @@ export function main() {
|
||||
});
|
||||
});
|
||||
|
||||
it('should not map leading segment without span', () => {
|
||||
it('should use the default source file for the first character', () => {
|
||||
ctx.print(null, 'fileA-0');
|
||||
expectMap(ctx, 0, 0, 'o.ts', 0, 0);
|
||||
});
|
||||
|
||||
it('should use an explicit mapping for the first character', () => {
|
||||
ctx.print(createSourceSpan(fileA, 0), 'fileA-0');
|
||||
expectMap(ctx, 0, 0, 'a.js', 0, 0);
|
||||
});
|
||||
|
||||
it('should map leading segment without span', () => {
|
||||
ctx.print(null, '....');
|
||||
ctx.print(createSourceSpan(fileA, 0), 'fileA-0');
|
||||
|
||||
expectMap(ctx, 0, 0);
|
||||
expectMap(ctx, 0, 0, 'o.ts', 0, 0);
|
||||
expectMap(ctx, 0, 4, 'a.js', 0, 0);
|
||||
expect(nbSegmentsPerLine(ctx)).toEqual([1]);
|
||||
expect(nbSegmentsPerLine(ctx)).toEqual([2]);
|
||||
});
|
||||
|
||||
it('should handle indent', () => {
|
||||
@ -68,7 +78,7 @@ export function main() {
|
||||
ctx.decIndent();
|
||||
ctx.println(createSourceSpan(fileA, 2), 'fileA-2');
|
||||
|
||||
expectMap(ctx, 0, 0);
|
||||
expectMap(ctx, 0, 0, 'o.ts', 0, 0);
|
||||
expectMap(ctx, 0, 2, 'a.js', 0, 0);
|
||||
expectMap(ctx, 1, 0);
|
||||
expectMap(ctx, 1, 2);
|
||||
@ -76,7 +86,7 @@ export function main() {
|
||||
expectMap(ctx, 2, 0);
|
||||
expectMap(ctx, 2, 2, 'a.js', 0, 4);
|
||||
|
||||
expect(nbSegmentsPerLine(ctx)).toEqual([1, 1, 1]);
|
||||
expect(nbSegmentsPerLine(ctx)).toEqual([2, 1, 1]);
|
||||
});
|
||||
|
||||
it('should coalesce identical span', () => {
|
||||
@ -103,7 +113,7 @@ export function main() {
|
||||
function expectMap(
|
||||
ctx: EmitterVisitorContext, genLine: number, genCol: number, source: string = null,
|
||||
srcLine: number = null, srcCol: number = null) {
|
||||
const sm = ctx.toSourceMapGenerator().toJSON();
|
||||
const sm = ctx.toSourceMapGenerator('o.ts', 'o.js').toJSON();
|
||||
const genPosition = {line: genLine + 1, column: genCol};
|
||||
const origPosition = originalPositionFor(sm, genPosition);
|
||||
expect(origPosition.source).toEqual(source);
|
||||
@ -113,7 +123,7 @@ function expectMap(
|
||||
|
||||
// returns the number of segments per line
|
||||
function nbSegmentsPerLine(ctx: EmitterVisitorContext) {
|
||||
const sm = ctx.toSourceMapGenerator().toJSON();
|
||||
const sm = ctx.toSourceMapGenerator('o.ts', 'o.js').toJSON();
|
||||
const lines = sm.mappings.split(';');
|
||||
return lines.map(l => {
|
||||
const m = l.match(/,/g);
|
||||
|
@ -16,7 +16,8 @@ import {ParseLocation, ParseSourceFile, ParseSourceSpan} from '@angular/compiler
|
||||
|
||||
import {extractSourceMap, originalPositionFor} from './source_map_util';
|
||||
|
||||
const someModuleUrl = 'somePackage/somePath';
|
||||
const someGenFilePath = 'somePackage/someGenFile';
|
||||
const someSourceFilePath = 'somePackage/someSourceFile';
|
||||
|
||||
class SimpleJsImportGenerator implements ImportResolver {
|
||||
fileNameToModuleName(importedUrlStr: string, moduleUrlStr: string): string {
|
||||
@ -38,9 +39,11 @@ export function main() {
|
||||
});
|
||||
|
||||
function emitSourceMap(
|
||||
stmt: o.Statement | o.Statement[], exportedVars: string[] = null): SourceMap {
|
||||
stmt: o.Statement | o.Statement[], exportedVars: string[] = null,
|
||||
preamble?: string): SourceMap {
|
||||
const stmts = Array.isArray(stmt) ? stmt : [stmt];
|
||||
const source = emitter.emitStatements(someModuleUrl, stmts, exportedVars || []);
|
||||
const source = emitter.emitStatements(
|
||||
someSourceFilePath, someGenFilePath, stmts, exportedVars || [], preamble);
|
||||
return extractSourceMap(source);
|
||||
}
|
||||
|
||||
@ -51,11 +54,11 @@ export function main() {
|
||||
const endLocation = new ParseLocation(source, 7, 0, 6);
|
||||
const sourceSpan = new ParseSourceSpan(startLocation, endLocation);
|
||||
const someVar = o.variable('someVar', null, sourceSpan);
|
||||
const sm = emitSourceMap(someVar.toStmt());
|
||||
const sm = emitSourceMap(someVar.toStmt(), [], '/* MyPreamble \n */');
|
||||
|
||||
expect(sm.sources).toEqual(['in.js']);
|
||||
expect(sm.sourcesContent).toEqual([';;;var']);
|
||||
expect(originalPositionFor(sm, {line: 1, column: 0}))
|
||||
expect(sm.sources).toEqual([someSourceFilePath, 'in.js']);
|
||||
expect(sm.sourcesContent).toEqual([null, ';;;var']);
|
||||
expect(originalPositionFor(sm, {line: 3, column: 0}))
|
||||
.toEqual({line: 1, column: 3, source: 'in.js'});
|
||||
});
|
||||
});
|
||||
|
@ -14,11 +14,12 @@ import {ImportResolver} from '@angular/compiler/src/output/path_util';
|
||||
|
||||
import {stripSourceMapAndNewLine} from './abstract_emitter_spec';
|
||||
|
||||
const someModuleUrl = 'somePackage/somePath';
|
||||
const someGenFilePath = 'somePackage/someGenFile';
|
||||
const someSourceFilePath = 'somePackage/someSourceFile';
|
||||
const anotherModuleUrl = 'somePackage/someOtherPath';
|
||||
|
||||
const sameModuleIdentifier: CompileIdentifierMetadata = {
|
||||
reference: new StaticSymbol(someModuleUrl, 'someLocalId', [])
|
||||
reference: new StaticSymbol(someGenFilePath, 'someLocalId', [])
|
||||
};
|
||||
const externalModuleIdentifier: CompileIdentifierMetadata = {
|
||||
reference: new StaticSymbol(anotherModuleUrl, 'someExternalId', [])
|
||||
@ -48,8 +49,9 @@ export function main() {
|
||||
someVar = o.variable('someVar');
|
||||
});
|
||||
|
||||
function emitStmt(stmt: o.Statement, exportedVars: string[] = null): string {
|
||||
const source = emitter.emitStatements(someModuleUrl, [stmt], exportedVars || []);
|
||||
function emitStmt(stmt: o.Statement, exportedVars: string[] = null, preamble?: string): string {
|
||||
const source = emitter.emitStatements(
|
||||
someSourceFilePath, someGenFilePath, [stmt], exportedVars || [], preamble);
|
||||
return stripSourceMapAndNewLine(source);
|
||||
}
|
||||
|
||||
@ -300,5 +302,11 @@ export function main() {
|
||||
].join('\n'));
|
||||
});
|
||||
});
|
||||
|
||||
it('should support a preamble', () => {
|
||||
expect(emitStmt(o.variable('a').toStmt(), [], '/* SomePreamble */')).toBe([
|
||||
'/* SomePreamble */', 'a;'
|
||||
].join('\n'));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -16,7 +16,8 @@ import {ParseSourceSpan} from '@angular/compiler/src/parse_util';
|
||||
|
||||
import {extractSourceMap, originalPositionFor} from './source_map_util';
|
||||
|
||||
const someModuleUrl = 'somePackage/somePath';
|
||||
const someGenFilePath = 'somePackage/someGenFile';
|
||||
const someSourceFilePath = 'somePackage/someSourceFile';
|
||||
|
||||
class SimpleJsImportGenerator implements ImportResolver {
|
||||
fileNameToModuleName(importedUrlStr: string, moduleUrlStr: string): string {
|
||||
@ -43,9 +44,11 @@ export function main() {
|
||||
});
|
||||
|
||||
function emitSourceMap(
|
||||
stmt: o.Statement | o.Statement[], exportedVars: string[] = null): SourceMap {
|
||||
stmt: o.Statement | o.Statement[], exportedVars: string[] = null,
|
||||
preamble?: string): SourceMap {
|
||||
const stmts = Array.isArray(stmt) ? stmt : [stmt];
|
||||
const source = emitter.emitStatements(someModuleUrl, stmts, exportedVars || []);
|
||||
const source = emitter.emitStatements(
|
||||
someSourceFilePath, someGenFilePath, stmts, exportedVars || [], preamble);
|
||||
return extractSourceMap(source);
|
||||
}
|
||||
|
||||
@ -56,11 +59,11 @@ export function main() {
|
||||
const endLocation = new ParseLocation(source, 7, 0, 6);
|
||||
const sourceSpan = new ParseSourceSpan(startLocation, endLocation);
|
||||
const someVar = o.variable('someVar', null, sourceSpan);
|
||||
const sm = emitSourceMap(someVar.toStmt());
|
||||
const sm = emitSourceMap(someVar.toStmt(), [], '/* MyPreamble \n */');
|
||||
|
||||
expect(sm.sources).toEqual(['in.js']);
|
||||
expect(sm.sourcesContent).toEqual([';;;var']);
|
||||
expect(originalPositionFor(sm, {line: 1, column: 0}))
|
||||
expect(sm.sources).toEqual([someSourceFilePath, 'in.js']);
|
||||
expect(sm.sourcesContent).toEqual([null, ';;;var']);
|
||||
expect(originalPositionFor(sm, {line: 3, column: 0}))
|
||||
.toEqual({line: 1, column: 3, source: 'in.js'});
|
||||
});
|
||||
});
|
||||
|
@ -14,11 +14,12 @@ import {TypeScriptEmitter} from '@angular/compiler/src/output/ts_emitter';
|
||||
|
||||
import {stripSourceMapAndNewLine} from './abstract_emitter_spec';
|
||||
|
||||
const someModuleUrl = 'somePackage/somePath';
|
||||
const someGenFilePath = 'somePackage/someGenFile';
|
||||
const someSourceFilePath = 'somePackage/someSourceFile';
|
||||
const anotherModuleUrl = 'somePackage/someOtherPath';
|
||||
|
||||
const sameModuleIdentifier: CompileIdentifierMetadata = {
|
||||
reference: new StaticSymbol(someModuleUrl, 'someLocalId', [])
|
||||
reference: new StaticSymbol(someGenFilePath, 'someLocalId', [])
|
||||
};
|
||||
|
||||
const externalModuleIdentifier: CompileIdentifierMetadata = {
|
||||
@ -49,9 +50,12 @@ export function main() {
|
||||
someVar = o.variable('someVar');
|
||||
});
|
||||
|
||||
function emitStmt(stmt: o.Statement | o.Statement[], exportedVars: string[] = null): string {
|
||||
function emitStmt(
|
||||
stmt: o.Statement | o.Statement[], exportedVars: string[] = null,
|
||||
preamble?: string): string {
|
||||
const stmts = Array.isArray(stmt) ? stmt : [stmt];
|
||||
const source = emitter.emitStatements(someModuleUrl, stmts, exportedVars || []);
|
||||
const source = emitter.emitStatements(
|
||||
someSourceFilePath, someGenFilePath, stmts, exportedVars || [], preamble);
|
||||
return stripSourceMapAndNewLine(source);
|
||||
}
|
||||
|
||||
@ -459,5 +463,11 @@ export function main() {
|
||||
expect(emitStmt(writeVarExpr.toDeclStmt(new o.MapType(o.INT_TYPE))))
|
||||
.toEqual('var a:{[key: string]:number} = (null as any);');
|
||||
});
|
||||
|
||||
it('should support a preamble', () => {
|
||||
expect(emitStmt(o.variable('a').toStmt(), [], '/* SomePreamble */')).toBe([
|
||||
'/* SomePreamble */', 'a;'
|
||||
].join('\n'));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
Reference in New Issue
Block a user