fix(compiler): don’t use `ng://` in AOT source maps, and never point to the original source file
This is important to not confuse users nor downstream tools that consume our source maps. For generated content for which we don’t have an original source file, we use the generated file now. Fixes #19538
This commit is contained in:
parent
5b5108363d
commit
01f711281c
|
@ -287,7 +287,7 @@ export class TsCompilerAotCompilerTypeCheckHostAdapter extends
|
||||||
`Invalid Argument: Expected a GenerateFile with statements. ${genFile.genFileUrl}`);
|
`Invalid Argument: Expected a GenerateFile with statements. ${genFile.genFileUrl}`);
|
||||||
}
|
}
|
||||||
const {sourceText, context} = this.emitter.emitStatementsAndContext(
|
const {sourceText, context} = this.emitter.emitStatementsAndContext(
|
||||||
genFile.srcFileUrl, genFile.genFileUrl, genFile.stmts, /* preamble */ '',
|
genFile.genFileUrl, genFile.stmts, /* preamble */ '',
|
||||||
/* emitSourceMaps */ false);
|
/* emitSourceMaps */ false);
|
||||||
const sf = ts.createSourceFile(
|
const sf = ts.createSourceFile(
|
||||||
genFile.genFileUrl, sourceText, this.options.target || ts.ScriptTarget.Latest);
|
genFile.genFileUrl, sourceText, this.options.target || ts.ScriptTarget.Latest);
|
||||||
|
|
|
@ -184,7 +184,7 @@ describe('ngc transformer command-line', () => {
|
||||||
const exitCode = main(['-p', basePath], errorSpy);
|
const exitCode = main(['-p', basePath], errorSpy);
|
||||||
expect(errorSpy).toHaveBeenCalledTimes(1);
|
expect(errorSpy).toHaveBeenCalledTimes(1);
|
||||||
expect(errorSpy.calls.mostRecent().args[0])
|
expect(errorSpy.calls.mostRecent().args[0])
|
||||||
.toContain('Error at ng://' + path.join(basePath, 'mymodule.ts.MyComp.html'));
|
.toContain('Error at ' + path.join(basePath, 'mymodule.ts.MyComp.html'));
|
||||||
expect(errorSpy.calls.mostRecent().args[0])
|
expect(errorSpy.calls.mostRecent().args[0])
|
||||||
.toContain(`Property 'unknownProp' does not exist on type 'MyComp'`);
|
.toContain(`Property 'unknownProp' does not exist on type 'MyComp'`);
|
||||||
|
|
||||||
|
@ -215,7 +215,7 @@ describe('ngc transformer command-line', () => {
|
||||||
const exitCode = main(['-p', basePath], errorSpy);
|
const exitCode = main(['-p', basePath], errorSpy);
|
||||||
expect(errorSpy).toHaveBeenCalledTimes(1);
|
expect(errorSpy).toHaveBeenCalledTimes(1);
|
||||||
expect(errorSpy.calls.mostRecent().args[0])
|
expect(errorSpy.calls.mostRecent().args[0])
|
||||||
.toContain('Error at ng://' + path.join(basePath, 'my.component.html(1,5):'));
|
.toContain('Error at ' + path.join(basePath, 'my.component.html(1,5):'));
|
||||||
expect(errorSpy.calls.mostRecent().args[0])
|
expect(errorSpy.calls.mostRecent().args[0])
|
||||||
.toContain(`Property 'unknownProp' does not exist on type 'MyComp'`);
|
.toContain(`Property 'unknownProp' does not exist on type 'MyComp'`);
|
||||||
|
|
||||||
|
|
|
@ -422,8 +422,8 @@ describe('TypeScriptNodeEmitter', () => {
|
||||||
it('should produce a source map that maps back to the source', () => {
|
it('should produce a source map that maps back to the source', () => {
|
||||||
const statement = someVar.set(o.literal(1)).toDeclStmt();
|
const statement = someVar.set(o.literal(1)).toDeclStmt();
|
||||||
const text = '<my-comp> a = 1 </my-comp>';
|
const text = '<my-comp> a = 1 </my-comp>';
|
||||||
const sourceName = 'ng://some.file.html';
|
const sourceName = '/some/file.html';
|
||||||
const sourceUrl = 'file:///ng:/some.file.html';
|
const sourceUrl = '../some/file.html';
|
||||||
const file = new ParseSourceFile(text, sourceName);
|
const file = new ParseSourceFile(text, sourceName);
|
||||||
const start = new ParseLocation(file, 0, 0, 0);
|
const start = new ParseLocation(file, 0, 0, 0);
|
||||||
const end = new ParseLocation(file, text.length, 0, text.length);
|
const end = new ParseLocation(file, text.length, 0, text.length);
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {CompileDirectiveMetadata, CompileDirectiveSummary, CompileIdentifierMetadata, CompileNgModuleMetadata, CompileNgModuleSummary, CompilePipeMetadata, CompilePipeSummary, CompileProviderMetadata, CompileStylesheetMetadata, CompileSummaryKind, CompileTypeMetadata, CompileTypeSummary, componentFactoryName, flatten, identifierName, sourceUrl, templateSourceUrl} from '../compile_metadata';
|
import {CompileDirectiveMetadata, CompileDirectiveSummary, CompileIdentifierMetadata, CompileNgModuleMetadata, CompileNgModuleSummary, CompilePipeMetadata, CompilePipeSummary, CompileProviderMetadata, CompileStylesheetMetadata, CompileSummaryKind, CompileTypeMetadata, CompileTypeSummary, componentFactoryName, flatten, identifierName, templateSourceUrl} from '../compile_metadata';
|
||||||
import {CompilerConfig} from '../config';
|
import {CompilerConfig} from '../config';
|
||||||
import {ViewEncapsulation} from '../core';
|
import {ViewEncapsulation} from '../core';
|
||||||
import {MessageBundle} from '../i18n/message_bundle';
|
import {MessageBundle} from '../i18n/message_bundle';
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {sourceUrl} from '../compile_metadata';
|
|
||||||
import {Statement, areAllEquivalent} from '../output/output_ast';
|
import {Statement, areAllEquivalent} from '../output/output_ast';
|
||||||
import {TypeScriptEmitter} from '../output/ts_emitter';
|
import {TypeScriptEmitter} from '../output/ts_emitter';
|
||||||
|
|
||||||
|
@ -45,6 +44,5 @@ export function toTypeScript(file: GeneratedFile, preamble: string = ''): string
|
||||||
if (!file.stmts) {
|
if (!file.stmts) {
|
||||||
throw new Error(`Illegal state: No stmts present on GeneratedFile ${file.genFileUrl}`);
|
throw new Error(`Illegal state: No stmts present on GeneratedFile ${file.genFileUrl}`);
|
||||||
}
|
}
|
||||||
return new TypeScriptEmitter().emitStatements(
|
return new TypeScriptEmitter().emitStatements(file.genFileUrl, file.stmts, preamble);
|
||||||
sourceUrl(file.srcFileUrl), file.genFileUrl, file.stmts, preamble);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -653,7 +653,7 @@ export function flatten<T>(list: Array<T|T[]>): T[] {
|
||||||
}, []);
|
}, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sourceUrl(url: string) {
|
function jitSourceUrl(url: string) {
|
||||||
// Note: We need 3 "/" so that ng shows up as a separate domain
|
// Note: We need 3 "/" so that ng shows up as a separate domain
|
||||||
// in the chrome dev tools.
|
// in the chrome dev tools.
|
||||||
return url.replace(/(\w+:\/\/[\w:-]+)?(\/+)?/, 'ng:///');
|
return url.replace(/(\w+:\/\/[\w:-]+)?(\/+)?/, 'ng:///');
|
||||||
|
@ -674,22 +674,21 @@ export function templateSourceUrl(
|
||||||
} else {
|
} else {
|
||||||
url = templateMeta.templateUrl !;
|
url = templateMeta.templateUrl !;
|
||||||
}
|
}
|
||||||
// always prepend ng:// to make angular resources easy to find and not clobber
|
return compMeta.type.reference instanceof StaticSymbol ? url : jitSourceUrl(url);
|
||||||
// user resources.
|
|
||||||
return sourceUrl(url);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sharedStylesheetJitUrl(meta: CompileStylesheetMetadata, id: number) {
|
export function sharedStylesheetJitUrl(meta: CompileStylesheetMetadata, id: number) {
|
||||||
const pathParts = meta.moduleUrl !.split(/\/\\/g);
|
const pathParts = meta.moduleUrl !.split(/\/\\/g);
|
||||||
const baseName = pathParts[pathParts.length - 1];
|
const baseName = pathParts[pathParts.length - 1];
|
||||||
return sourceUrl(`css/${id}${baseName}.ngstyle.js`);
|
return jitSourceUrl(`css/${id}${baseName}.ngstyle.js`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ngModuleJitUrl(moduleMeta: CompileNgModuleMetadata): string {
|
export function ngModuleJitUrl(moduleMeta: CompileNgModuleMetadata): string {
|
||||||
return sourceUrl(`${identifierName(moduleMeta.type)}/module.ngfactory.js`);
|
return jitSourceUrl(`${identifierName(moduleMeta.type)}/module.ngfactory.js`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function templateJitUrl(
|
export function templateJitUrl(
|
||||||
ngModuleType: CompileIdentifierMetadata, compMeta: CompileDirectiveMetadata): string {
|
ngModuleType: CompileIdentifierMetadata, compMeta: CompileDirectiveMetadata): string {
|
||||||
return sourceUrl(`${identifierName(ngModuleType)}/${identifierName(compMeta.type)}.ngfactory.js`);
|
return jitSourceUrl(
|
||||||
|
`${identifierName(ngModuleType)}/${identifierName(compMeta.type)}.ngfactory.js`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,9 +18,7 @@ export const CATCH_ERROR_VAR = o.variable('error', null, null);
|
||||||
export const CATCH_STACK_VAR = o.variable('stack', null, null);
|
export const CATCH_STACK_VAR = o.variable('stack', null, null);
|
||||||
|
|
||||||
export interface OutputEmitter {
|
export interface OutputEmitter {
|
||||||
emitStatements(
|
emitStatements(genFilePath: string, stmts: o.Statement[], preamble?: string|null): string;
|
||||||
srcFilePath: string, genFilePath: string, stmts: o.Statement[],
|
|
||||||
preamble?: string|null): string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _EmittedLine {
|
class _EmittedLine {
|
||||||
|
@ -96,8 +94,7 @@ export class EmitterVisitorContext {
|
||||||
.join('\n');
|
.join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
toSourceMapGenerator(sourceFilePath: string, genFilePath: string, startsAtLine: number = 0):
|
toSourceMapGenerator(genFilePath: string, startsAtLine: number = 0): SourceMapGenerator {
|
||||||
SourceMapGenerator {
|
|
||||||
const map = new SourceMapGenerator(genFilePath);
|
const map = new SourceMapGenerator(genFilePath);
|
||||||
|
|
||||||
let firstOffsetMapped = false;
|
let firstOffsetMapped = false;
|
||||||
|
@ -106,7 +103,7 @@ export class EmitterVisitorContext {
|
||||||
// Add a single space so that tools won't try to load the file from disk.
|
// Add a single space so that tools won't try to load the file from disk.
|
||||||
// Note: We are using virtual urls like `ng:///`, so we have to
|
// Note: We are using virtual urls like `ng:///`, so we have to
|
||||||
// provide a content here.
|
// provide a content here.
|
||||||
map.addSource(sourceFilePath, ' ').addMapping(0, sourceFilePath, 0, 0);
|
map.addSource(genFilePath, ' ').addMapping(0, genFilePath, 0, 0);
|
||||||
firstOffsetMapped = true;
|
firstOffsetMapped = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,9 +15,7 @@ import {AbstractJsEmitterVisitor} from './abstract_js_emitter';
|
||||||
import * as o from './output_ast';
|
import * as o from './output_ast';
|
||||||
|
|
||||||
export class JavaScriptEmitter implements OutputEmitter {
|
export class JavaScriptEmitter implements OutputEmitter {
|
||||||
emitStatements(
|
emitStatements(genFilePath: string, stmts: o.Statement[], preamble: string = ''): string {
|
||||||
srcFilePath: string, genFilePath: string, stmts: o.Statement[],
|
|
||||||
preamble: string = ''): string {
|
|
||||||
const converter = new JsEmitterVisitor();
|
const converter = new JsEmitterVisitor();
|
||||||
const ctx = EmitterVisitorContext.createRoot();
|
const ctx = EmitterVisitorContext.createRoot();
|
||||||
converter.visitAllStatements(stmts, ctx);
|
converter.visitAllStatements(stmts, ctx);
|
||||||
|
@ -30,8 +28,7 @@ export class JavaScriptEmitter implements OutputEmitter {
|
||||||
`uire('${importedModuleName}');`);
|
`uire('${importedModuleName}');`);
|
||||||
});
|
});
|
||||||
|
|
||||||
const sm =
|
const sm = ctx.toSourceMapGenerator(genFilePath, preambleLines.length).toJsComment();
|
||||||
ctx.toSourceMapGenerator(srcFilePath, genFilePath, preambleLines.length).toJsComment();
|
|
||||||
const lines = [...preambleLines, ctx.toSource(), sm];
|
const lines = [...preambleLines, ctx.toSource(), sm];
|
||||||
if (sm) {
|
if (sm) {
|
||||||
// always add a newline at the end, as some tools have bugs without it.
|
// always add a newline at the end, as some tools have bugs without it.
|
||||||
|
|
|
@ -31,7 +31,7 @@ function evalExpression(
|
||||||
// We don't want to hard code this fact, so we auto detect it via an empty function first.
|
// We don't want to hard code this fact, so we auto detect it via an empty function first.
|
||||||
const emptyFn = new Function(...fnArgNames.concat('return null;')).toString();
|
const emptyFn = new Function(...fnArgNames.concat('return null;')).toString();
|
||||||
const headerLines = emptyFn.slice(0, emptyFn.indexOf('return null;')).split('\n').length - 1;
|
const headerLines = emptyFn.slice(0, emptyFn.indexOf('return null;')).split('\n').length - 1;
|
||||||
fnBody += `\n${ctx.toSourceMapGenerator(sourceUrl, sourceUrl, headerLines).toJsComment()}`;
|
fnBody += `\n${ctx.toSourceMapGenerator(sourceUrl, headerLines).toJsComment()}`;
|
||||||
}
|
}
|
||||||
return new Function(...fnArgNames.concat(fnBody))(...fnArgValues);
|
return new Function(...fnArgNames.concat(fnBody))(...fnArgValues);
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ export type ReferenceFilter = (reference: o.ExternalReference) => boolean;
|
||||||
|
|
||||||
export class TypeScriptEmitter implements OutputEmitter {
|
export class TypeScriptEmitter implements OutputEmitter {
|
||||||
emitStatementsAndContext(
|
emitStatementsAndContext(
|
||||||
srcFilePath: string, genFilePath: string, stmts: o.Statement[], preamble: string = '',
|
genFilePath: string, stmts: o.Statement[], preamble: string = '',
|
||||||
emitSourceMaps: boolean = true,
|
emitSourceMaps: boolean = true,
|
||||||
referenceFilter?: ReferenceFilter): {sourceText: string, context: EmitterVisitorContext} {
|
referenceFilter?: ReferenceFilter): {sourceText: string, context: EmitterVisitorContext} {
|
||||||
const converter = new _TsEmitterVisitor(referenceFilter);
|
const converter = new _TsEmitterVisitor(referenceFilter);
|
||||||
|
@ -63,7 +63,7 @@ export class TypeScriptEmitter implements OutputEmitter {
|
||||||
});
|
});
|
||||||
|
|
||||||
const sm = emitSourceMaps ?
|
const sm = emitSourceMaps ?
|
||||||
ctx.toSourceMapGenerator(srcFilePath, genFilePath, preambleLines.length).toJsComment() :
|
ctx.toSourceMapGenerator(genFilePath, preambleLines.length).toJsComment() :
|
||||||
'';
|
'';
|
||||||
const lines = [...preambleLines, ctx.toSource(), sm];
|
const lines = [...preambleLines, ctx.toSource(), sm];
|
||||||
if (sm) {
|
if (sm) {
|
||||||
|
@ -74,9 +74,8 @@ export class TypeScriptEmitter implements OutputEmitter {
|
||||||
return {sourceText: lines.join('\n'), context: ctx};
|
return {sourceText: lines.join('\n'), context: ctx};
|
||||||
}
|
}
|
||||||
|
|
||||||
emitStatements(
|
emitStatements(genFilePath: string, stmts: o.Statement[], preamble: string = '') {
|
||||||
srcFilePath: string, genFilePath: string, stmts: o.Statement[], preamble: string = '') {
|
return this.emitStatementsAndContext(genFilePath, stmts, preamble).sourceText;
|
||||||
return this.emitStatementsAndContext(srcFilePath, genFilePath, stmts, preamble).sourceText;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ describe('compiler (unbundled Angular)', () => {
|
||||||
|
|
||||||
describe('aot source mapping', () => {
|
describe('aot source mapping', () => {
|
||||||
const componentPath = '/app/app.component.ts';
|
const componentPath = '/app/app.component.ts';
|
||||||
const ngComponentPath = 'ng:///app/app.component.ts';
|
const ngFactoryPath = '/app/app.component.ngfactory.ts';
|
||||||
|
|
||||||
let rootDir: MockDirectory;
|
let rootDir: MockDirectory;
|
||||||
let appDir: MockDirectory;
|
let appDir: MockDirectory;
|
||||||
|
@ -83,7 +83,7 @@ describe('compiler (unbundled Angular)', () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('inline templates', () => {
|
describe('inline templates', () => {
|
||||||
const ngUrl = `${ngComponentPath}.AppComponent.html`;
|
const ngUrl = `${componentPath}.AppComponent.html`;
|
||||||
|
|
||||||
function templateDecorator(template: string) { return `template: \`${template}\`,`; }
|
function templateDecorator(template: string) { return `template: \`${template}\`,`; }
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ describe('compiler (unbundled Angular)', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('external templates', () => {
|
describe('external templates', () => {
|
||||||
const ngUrl = 'ng:///app/app.component.html';
|
const ngUrl = '/app/app.component.html';
|
||||||
const templateUrl = '/app/app.component.html';
|
const templateUrl = '/app/app.component.html';
|
||||||
|
|
||||||
function templateDecorator(template: string) {
|
function templateDecorator(template: string) {
|
||||||
|
@ -129,14 +129,14 @@ describe('compiler (unbundled Angular)', () => {
|
||||||
const sourceMap = extractSourceMap(genSource) !;
|
const sourceMap = extractSourceMap(genSource) !;
|
||||||
expect(sourceMap.file).toEqual(genFile.genFileUrl);
|
expect(sourceMap.file).toEqual(genFile.genFileUrl);
|
||||||
|
|
||||||
// the generated file contains code that is not mapped to
|
// Note: the generated file also contains code that is not mapped to
|
||||||
// the template but rather to the original source file (e.g. import statements, ...)
|
// the template (e.g. import statements, ...)
|
||||||
const templateIndex = sourceMap.sources.indexOf(ngUrl);
|
const templateIndex = sourceMap.sources.indexOf(ngUrl);
|
||||||
expect(sourceMap.sourcesContent[templateIndex]).toEqual(template);
|
expect(sourceMap.sourcesContent[templateIndex]).toEqual(template);
|
||||||
|
|
||||||
// for the mapping to the original source file we don't store the source code
|
// for the mapping to the original source file we don't store the source code
|
||||||
// as we want to keep whatever TypeScript / ... produced for them.
|
// as we want to keep whatever TypeScript / ... produced for them.
|
||||||
const sourceIndex = sourceMap.sources.indexOf(ngComponentPath);
|
const sourceIndex = sourceMap.sources.indexOf(ngFactoryPath);
|
||||||
expect(sourceMap.sourcesContent[sourceIndex]).toBe(' ');
|
expect(sourceMap.sourcesContent[sourceIndex]).toBe(' ');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -176,14 +176,14 @@ describe('compiler (unbundled Angular)', () => {
|
||||||
.toEqual({line: 2, column: 9, source: ngUrl});
|
.toEqual({line: 2, column: 9, source: ngUrl});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should map non template parts to the source file', () => {
|
it('should map non template parts to the factory file', () => {
|
||||||
appDir['app.component.ts'] = createComponentSource(templateDecorator('Hello World!'));
|
appDir['app.component.ts'] = createComponentSource(templateDecorator('Hello World!'));
|
||||||
|
|
||||||
const genFile = compileApp();
|
const genFile = compileApp();
|
||||||
const genSource = toTypeScript(genFile);
|
const genSource = toTypeScript(genFile);
|
||||||
const sourceMap = extractSourceMap(genSource) !;
|
const sourceMap = extractSourceMap(genSource) !;
|
||||||
expect(originalPositionFor(sourceMap, {line: 1, column: 0}))
|
expect(originalPositionFor(sourceMap, {line: 1, column: 0}))
|
||||||
.toEqual({line: 1, column: 0, source: ngComponentPath});
|
.toEqual({line: 1, column: 0, source: ngFactoryPath});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -25,7 +25,7 @@ export function main() {
|
||||||
ctx.print(createSourceSpan(fileA, 1), 'o1');
|
ctx.print(createSourceSpan(fileA, 1), 'o1');
|
||||||
ctx.print(createSourceSpan(fileB, 0), 'o2');
|
ctx.print(createSourceSpan(fileB, 0), 'o2');
|
||||||
ctx.print(createSourceSpan(fileB, 1), 'o3');
|
ctx.print(createSourceSpan(fileB, 1), 'o3');
|
||||||
const sm = ctx.toSourceMapGenerator('o.ts', 'o.js').toJSON() !;
|
const sm = ctx.toSourceMapGenerator('o.ts').toJSON() !;
|
||||||
expect(sm.sources).toEqual([fileA.url, fileB.url]);
|
expect(sm.sources).toEqual([fileA.url, fileB.url]);
|
||||||
expect(sm.sourcesContent).toEqual([fileA.content, fileB.content]);
|
expect(sm.sourcesContent).toEqual([fileA.content, fileB.content]);
|
||||||
});
|
});
|
||||||
|
@ -43,7 +43,7 @@ export function main() {
|
||||||
it('should be able to shift the content', () => {
|
it('should be able to shift the content', () => {
|
||||||
ctx.print(createSourceSpan(fileA, 0), 'fileA-0');
|
ctx.print(createSourceSpan(fileA, 0), 'fileA-0');
|
||||||
|
|
||||||
const sm = ctx.toSourceMapGenerator('o.ts', 'o.js', 10).toJSON() !;
|
const sm = ctx.toSourceMapGenerator('o.ts', 10).toJSON() !;
|
||||||
expect(originalPositionFor(sm, {line: 11, column: 0})).toEqual({
|
expect(originalPositionFor(sm, {line: 11, column: 0})).toEqual({
|
||||||
line: 1,
|
line: 1,
|
||||||
column: 0,
|
column: 0,
|
||||||
|
@ -113,7 +113,7 @@ export function main() {
|
||||||
function expectMap(
|
function expectMap(
|
||||||
ctx: EmitterVisitorContext, genLine: number, genCol: number, source: string | null = null,
|
ctx: EmitterVisitorContext, genLine: number, genCol: number, source: string | null = null,
|
||||||
srcLine: number | null = null, srcCol: number | null = null) {
|
srcLine: number | null = null, srcCol: number | null = null) {
|
||||||
const sm = ctx.toSourceMapGenerator('o.ts', 'o.js').toJSON() !;
|
const sm = ctx.toSourceMapGenerator('o.ts').toJSON() !;
|
||||||
const genPosition = {line: genLine + 1, column: genCol};
|
const genPosition = {line: genLine + 1, column: genCol};
|
||||||
const origPosition = originalPositionFor(sm, genPosition);
|
const origPosition = originalPositionFor(sm, genPosition);
|
||||||
expect(origPosition.source).toEqual(source);
|
expect(origPosition.source).toEqual(source);
|
||||||
|
@ -123,7 +123,7 @@ function expectMap(
|
||||||
|
|
||||||
// returns the number of segments per line
|
// returns the number of segments per line
|
||||||
function nbSegmentsPerLine(ctx: EmitterVisitorContext) {
|
function nbSegmentsPerLine(ctx: EmitterVisitorContext) {
|
||||||
const sm = ctx.toSourceMapGenerator('o.ts', 'o.js').toJSON() !;
|
const sm = ctx.toSourceMapGenerator('o.ts').toJSON() !;
|
||||||
const lines = sm.mappings.split(';');
|
const lines = sm.mappings.split(';');
|
||||||
return lines.map(l => {
|
return lines.map(l => {
|
||||||
const m = l.match(/,/g);
|
const m = l.match(/,/g);
|
||||||
|
|
|
@ -16,7 +16,6 @@ import {ParseLocation, ParseSourceFile, ParseSourceSpan} from '@angular/compiler
|
||||||
import {extractSourceMap, originalPositionFor} from './source_map_util';
|
import {extractSourceMap, originalPositionFor} from './source_map_util';
|
||||||
|
|
||||||
const someGenFilePath = 'somePackage/someGenFile';
|
const someGenFilePath = 'somePackage/someGenFile';
|
||||||
const someSourceFilePath = 'somePackage/someSourceFile';
|
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('JavaScriptEmitter', () => {
|
describe('JavaScriptEmitter', () => {
|
||||||
|
@ -27,7 +26,7 @@ export function main() {
|
||||||
|
|
||||||
function emitSourceMap(stmt: o.Statement | o.Statement[], preamble?: string): SourceMap {
|
function emitSourceMap(stmt: o.Statement | o.Statement[], preamble?: string): SourceMap {
|
||||||
const stmts = Array.isArray(stmt) ? stmt : [stmt];
|
const stmts = Array.isArray(stmt) ? stmt : [stmt];
|
||||||
const source = emitter.emitStatements(someSourceFilePath, someGenFilePath, stmts, preamble);
|
const source = emitter.emitStatements(someGenFilePath, stmts, preamble);
|
||||||
return extractSourceMap(source) !;
|
return extractSourceMap(source) !;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +39,7 @@ export function main() {
|
||||||
const someVar = o.variable('someVar', null, sourceSpan);
|
const someVar = o.variable('someVar', null, sourceSpan);
|
||||||
const sm = emitSourceMap(someVar.toStmt(), '/* MyPreamble \n */');
|
const sm = emitSourceMap(someVar.toStmt(), '/* MyPreamble \n */');
|
||||||
|
|
||||||
expect(sm.sources).toEqual([someSourceFilePath, 'in.js']);
|
expect(sm.sources).toEqual([someGenFilePath, 'in.js']);
|
||||||
expect(sm.sourcesContent).toEqual([' ', ';;;var']);
|
expect(sm.sourcesContent).toEqual([' ', ';;;var']);
|
||||||
expect(originalPositionFor(sm, {line: 3, column: 0}))
|
expect(originalPositionFor(sm, {line: 3, column: 0}))
|
||||||
.toEqual({line: 1, column: 3, source: 'in.js'});
|
.toEqual({line: 1, column: 3, source: 'in.js'});
|
||||||
|
|
|
@ -13,7 +13,6 @@ import * as o from '@angular/compiler/src/output/output_ast';
|
||||||
import {stripSourceMapAndNewLine} from './abstract_emitter_spec';
|
import {stripSourceMapAndNewLine} from './abstract_emitter_spec';
|
||||||
|
|
||||||
const someGenFilePath = 'somePackage/someGenFile';
|
const someGenFilePath = 'somePackage/someGenFile';
|
||||||
const someSourceFilePath = 'somePackage/someSourceFile';
|
|
||||||
const anotherModuleUrl = 'somePackage/someOtherPath';
|
const anotherModuleUrl = 'somePackage/someOtherPath';
|
||||||
|
|
||||||
const sameModuleIdentifier = new o.ExternalReference(null, 'someLocalId', null);
|
const sameModuleIdentifier = new o.ExternalReference(null, 'someLocalId', null);
|
||||||
|
@ -35,7 +34,7 @@ export function main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
function emitStmt(stmt: o.Statement, preamble?: string): string {
|
function emitStmt(stmt: o.Statement, preamble?: string): string {
|
||||||
const source = emitter.emitStatements(someSourceFilePath, someGenFilePath, [stmt], preamble);
|
const source = emitter.emitStatements(someGenFilePath, [stmt], preamble);
|
||||||
return stripSourceMapAndNewLine(source);
|
return stripSourceMapAndNewLine(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@ import {ParseSourceSpan} from '@angular/compiler/src/parse_util';
|
||||||
import {extractSourceMap, originalPositionFor} from './source_map_util';
|
import {extractSourceMap, originalPositionFor} from './source_map_util';
|
||||||
|
|
||||||
const someGenFilePath = 'somePackage/someGenFile';
|
const someGenFilePath = 'somePackage/someGenFile';
|
||||||
const someSourceFilePath = 'somePackage/someSourceFile';
|
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
// Not supported features of our OutputAst in TS:
|
// Not supported features of our OutputAst in TS:
|
||||||
|
@ -34,7 +33,7 @@ export function main() {
|
||||||
|
|
||||||
function emitSourceMap(stmt: o.Statement | o.Statement[], preamble?: string): SourceMap {
|
function emitSourceMap(stmt: o.Statement | o.Statement[], preamble?: string): SourceMap {
|
||||||
const stmts = Array.isArray(stmt) ? stmt : [stmt];
|
const stmts = Array.isArray(stmt) ? stmt : [stmt];
|
||||||
const source = emitter.emitStatements(someSourceFilePath, someGenFilePath, stmts, preamble);
|
const source = emitter.emitStatements(someGenFilePath, stmts, preamble);
|
||||||
return extractSourceMap(source) !;
|
return extractSourceMap(source) !;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +46,7 @@ export function main() {
|
||||||
const someVar = o.variable('someVar', null, sourceSpan);
|
const someVar = o.variable('someVar', null, sourceSpan);
|
||||||
const sm = emitSourceMap(someVar.toStmt(), '/* MyPreamble \n */');
|
const sm = emitSourceMap(someVar.toStmt(), '/* MyPreamble \n */');
|
||||||
|
|
||||||
expect(sm.sources).toEqual([someSourceFilePath, 'in.js']);
|
expect(sm.sources).toEqual([someGenFilePath, 'in.js']);
|
||||||
expect(sm.sourcesContent).toEqual([' ', ';;;var']);
|
expect(sm.sourcesContent).toEqual([' ', ';;;var']);
|
||||||
expect(originalPositionFor(sm, {line: 3, column: 0}))
|
expect(originalPositionFor(sm, {line: 3, column: 0}))
|
||||||
.toEqual({line: 1, column: 3, source: 'in.js'});
|
.toEqual({line: 1, column: 3, source: 'in.js'});
|
||||||
|
|
|
@ -13,7 +13,6 @@ import {ParseLocation, ParseSourceFile, ParseSourceSpan} from '@angular/compiler
|
||||||
import {stripSourceMapAndNewLine} from './abstract_emitter_spec';
|
import {stripSourceMapAndNewLine} from './abstract_emitter_spec';
|
||||||
|
|
||||||
const someGenFilePath = 'somePackage/someGenFile';
|
const someGenFilePath = 'somePackage/someGenFile';
|
||||||
const someSourceFilePath = 'somePackage/someSourceFile';
|
|
||||||
const anotherModuleUrl = 'somePackage/someOtherPath';
|
const anotherModuleUrl = 'somePackage/someOtherPath';
|
||||||
|
|
||||||
const sameModuleIdentifier = new o.ExternalReference(null, 'someLocalId', null);
|
const sameModuleIdentifier = new o.ExternalReference(null, 'someLocalId', null);
|
||||||
|
@ -36,7 +35,7 @@ export function main() {
|
||||||
|
|
||||||
function emitStmt(stmt: o.Statement | o.Statement[], preamble?: string): string {
|
function emitStmt(stmt: o.Statement | o.Statement[], preamble?: string): string {
|
||||||
const stmts = Array.isArray(stmt) ? stmt : [stmt];
|
const stmts = Array.isArray(stmt) ? stmt : [stmt];
|
||||||
const source = emitter.emitStatements(someSourceFilePath, someGenFilePath, stmts, preamble);
|
const source = emitter.emitStatements(someGenFilePath, stmts, preamble);
|
||||||
return stripSourceMapAndNewLine(source);
|
return stripSourceMapAndNewLine(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -435,7 +434,7 @@ export function main() {
|
||||||
new o.ReturnStatement(o.variable('someVar', null, referenceSpan), returnSpan)
|
new o.ReturnStatement(o.variable('someVar', null, referenceSpan), returnSpan)
|
||||||
])])];
|
])])];
|
||||||
const {sourceText, context} =
|
const {sourceText, context} =
|
||||||
emitter.emitStatementsAndContext('a.ts', 'a.ts', statements, '/* some preamble /*\n\n');
|
emitter.emitStatementsAndContext('a.ts', statements, '/* some preamble /*\n\n');
|
||||||
const spanOf = (text: string, after: number = 0) => {
|
const spanOf = (text: string, after: number = 0) => {
|
||||||
const location = sourceText.indexOf(text, after);
|
const location = sourceText.indexOf(text, after);
|
||||||
const {line, col} = calculateLineCol(sourceText, location);
|
const {line, col} = calculateLineCol(sourceText, location);
|
||||||
|
|
Loading…
Reference in New Issue