\n '));
- expect(() => compileApp())
- .toThrowError(new RegExp(`Template parse errors[\\s\\S]*${templateUrl}@1:2`));
+ expectPromiseToThrow(
+ compileApp(), new RegExp(`Template parse errors[\\s\\S]*${templateUrl}@1:2`));
}));
- it('should use the right source url in template parse errors', fakeAsync(() => {
+ it('should use the right source url in template parse errors', async(() => {
appDir['app.component.ts'] = createComponentSource(
templateDecorator('
\n
'));
- expect(() => compileApp())
- .toThrowError(new RegExp(`Template parse errors[\\s\\S]*${templateUrl}@1:7`));
+ expectPromiseToThrow(
+ compileApp(), new RegExp(`Template parse errors[\\s\\S]*${templateUrl}@1:7`));
}));
- it('should create a sourceMap for the template', fakeAsync(() => {
+ it('should create a sourceMap for the template', async(() => {
const template = 'Hello World!';
appDir['app.component.ts'] = createComponentSource(templateDecorator(template));
- const genFile = compileApp();
- const sourceMap = extractSourceMap(genFile.source);
- expect(sourceMap.file).toEqual(genFile.genFileUrl);
- // the generated file contains the host view and the component view.
- // we are only interested in the component view.
- const sourceIndex = sourceMap.sources.indexOf(templateUrl);
- expect(sourceMap.sourcesContent[sourceIndex]).toEqual(template);
+ compileApp().then((genFile) => {
+ const sourceMap = extractSourceMap(genFile.source);
+ expect(sourceMap.file).toEqual(genFile.genFileUrl);
+
+ // the generated file contains code that is not mapped to
+ // the template but rather to the original source file (e.g. import statements, ...)
+ const templateIndex = sourceMap.sources.indexOf(templateUrl);
+ expect(sourceMap.sourcesContent[templateIndex]).toEqual(template);
+
+ // 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.
+ const sourceIndex = sourceMap.sources.indexOf(componentPath);
+ expect(sourceMap.sourcesContent[sourceIndex]).toBe(null);
+ });
}));
- it('should map elements correctly to the source', fakeAsync(() => {
+ it('should map elements correctly to the source', async(() => {
const template = '
\n
';
appDir['app.component.ts'] = createComponentSource(templateDecorator(template));
- const genFile = compileApp();
- const sourceMap = extractSourceMap(genFile.source);
- expect(originalPositionFor(sourceMap, findLineAndColumn(genFile.source, `'span'`)))
- .toEqual({line: 2, column: 3, source: templateUrl});
+ compileApp().then((genFile) => {
+ const sourceMap = extractSourceMap(genFile.source);
+ expect(originalPositionFor(sourceMap, findLineAndColumn(genFile.source, `'span'`)))
+ .toEqual({line: 2, column: 3, source: templateUrl});
+ });
}));
- it('should map bindings correctly to the source', fakeAsync(() => {
+ it('should map bindings correctly to the source', async(() => {
const template = `
\n
`;
appDir['app.component.ts'] = createComponentSource(templateDecorator(template));
- const genFile = compileApp();
- const sourceMap = extractSourceMap(genFile.source);
- expect(originalPositionFor(sourceMap, findLineAndColumn(genFile.source, `someMethod()`)))
- .toEqual({line: 2, column: 9, source: templateUrl});
+ compileApp().then((genFile) => {
+ const sourceMap = extractSourceMap(genFile.source);
+ expect(
+ originalPositionFor(sourceMap, findLineAndColumn(genFile.source, `someMethod()`)))
+ .toEqual({line: 2, column: 9, source: templateUrl});
+ });
}));
- it('should map events correctly to the source', fakeAsync(() => {
+ it('should map events correctly to the source', async(() => {
const template = `
\n
`;
appDir['app.component.ts'] = createComponentSource(templateDecorator(template));
- const genFile = compileApp();
- const sourceMap = extractSourceMap(genFile.source);
- expect(originalPositionFor(sourceMap, findLineAndColumn(genFile.source, `someMethod()`)))
- .toEqual({line: 2, column: 9, source: templateUrl});
+ compileApp().then((genFile) => {
+ const sourceMap = extractSourceMap(genFile.source);
+ expect(
+ originalPositionFor(sourceMap, findLineAndColumn(genFile.source, `someMethod()`)))
+ .toEqual({line: 2, column: 9, source: templateUrl});
+ });
+ }));
+
+ it('should map non template parts to the source file', async(() => {
+ appDir['app.component.ts'] = createComponentSource(templateDecorator('Hello World!'));
+
+ compileApp().then((genFile) => {
+ const sourceMap = extractSourceMap(genFile.source);
+ expect(originalPositionFor(sourceMap, {line: 1, column: 0}))
+ .toEqual({line: 1, column: 0, source: componentPath});
+ });
}));
}
});
describe('errors', () => {
it('should only warn if not all arguments of an @Injectable class can be resolved',
- fakeAsync(() => {
+ async(() => {
const FILES: MockData = {
app: {
'app.ts': `
@@ -237,17 +258,40 @@ describe('compiler (unbundled Angular)', () => {
};
const host = new MockCompilerHost(['/app/app.ts'], FILES, angularFiles);
const aotHost = new MockAotCompilerHost(host);
- let ok = false;
const warnSpy = spyOn(console, 'warn');
- compile(host, aotHost, expectNoDiagnostics).then(() => ok = true);
+ compile(host, aotHost, expectNoDiagnostics).then(() => {
+ expect(warnSpy).toHaveBeenCalledWith(
+ `Warning: Can't resolve all parameters for MyService in /app/app.ts: (?). This will become an error in Angular v5.x`);
+ });
- tick();
-
- expect(ok).toBe(true);
- expect(warnSpy).toHaveBeenCalledWith(
- `Warning: Can't resolve all parameters for MyService in /app/app.ts: (?). This will become an error in Angular v5.x`);
}));
});
+
+ it('should add the preamble to generated files', async(() => {
+ const FILES: MockData = {
+ app: {
+ 'app.ts': `
+ import { NgModule, Component } from '@angular/core';
+
+ @Component({ template: '' })
+ export class AppComponent {}
+
+ @NgModule({ declarations: [ AppComponent ] })
+ export class AppModule { }
+ `
+ }
+ };
+ const host = new MockCompilerHost(['/app/app.ts'], FILES, angularFiles);
+ const aotHost = new MockAotCompilerHost(host);
+ const genFilePreamble = '/* Hello world! */';
+ compile(host, aotHost, expectNoDiagnostics, expectNoDiagnostics, {genFilePreamble})
+ .then((generatedFiles) => {
+ const genFile = generatedFiles.find(
+ gf => gf.srcFileUrl === '/app/app.ts' && gf.genFileUrl.endsWith('.ts'));
+ expect(genFile.source.startsWith(genFilePreamble)).toBe(true);
+ });
+
+ }));
});
describe('compiler (bundled Angular)', () => {
@@ -426,3 +470,8 @@ const FILES: MockData = {
}
}
};
+
+function expectPromiseToThrow(p: Promise
, msg: RegExp) {
+ p.then(
+ () => { throw new Error('Expected to throw'); }, (e) => { expect(e.message).toMatch(msg); });
+}
\ No newline at end of file
diff --git a/packages/compiler/test/output/abstract_emitter_node_only_spec.ts b/packages/compiler/test/output/abstract_emitter_node_only_spec.ts
index 103a593614..3a76348f49 100644
--- a/packages/compiler/test/output/abstract_emitter_node_only_spec.ts
+++ b/packages/compiler/test/output/abstract_emitter_node_only_spec.ts
@@ -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);
diff --git a/packages/compiler/test/output/js_emitter_node_only_spec.ts b/packages/compiler/test/output/js_emitter_node_only_spec.ts
index 61c529e92a..c5bcf79ac2 100644
--- a/packages/compiler/test/output/js_emitter_node_only_spec.ts
+++ b/packages/compiler/test/output/js_emitter_node_only_spec.ts
@@ -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'});
});
});
diff --git a/packages/compiler/test/output/js_emitter_spec.ts b/packages/compiler/test/output/js_emitter_spec.ts
index 6af6f22491..582bcb881d 100644
--- a/packages/compiler/test/output/js_emitter_spec.ts
+++ b/packages/compiler/test/output/js_emitter_spec.ts
@@ -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'));
+ });
});
}
diff --git a/packages/compiler/test/output/ts_emitter_node_only_spec.ts b/packages/compiler/test/output/ts_emitter_node_only_spec.ts
index 050bfe1c49..2c1a2869b8 100644
--- a/packages/compiler/test/output/ts_emitter_node_only_spec.ts
+++ b/packages/compiler/test/output/ts_emitter_node_only_spec.ts
@@ -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'});
});
});
diff --git a/packages/compiler/test/output/ts_emitter_spec.ts b/packages/compiler/test/output/ts_emitter_spec.ts
index 70b5b33887..6d4bb0f1ba 100644
--- a/packages/compiler/test/output/ts_emitter_spec.ts
+++ b/packages/compiler/test/output/ts_emitter_spec.ts
@@ -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'));
+ });
});
}
diff --git a/packages/core/test/linker/source_map_integration_node_only_spec.ts b/packages/core/test/linker/source_map_integration_node_only_spec.ts
index bdcb4d4b6e..ad53d8fa10 100644
--- a/packages/core/test/linker/source_map_integration_node_only_spec.ts
+++ b/packages/core/test/linker/source_map_integration_node_only_spec.ts
@@ -125,8 +125,10 @@ export function main() {
compileAndCreateComponent(MyComp);
const sourceMap = getSourceMap('ng:///DynamicTestModule/MyComp.ngfactory.js');
- expect(sourceMap.sources).toEqual([templateUrl]);
- expect(sourceMap.sourcesContent).toEqual([template]);
+ expect(sourceMap.sources).toEqual([
+ 'ng:///DynamicTestModule/MyComp.ngfactory.js', templateUrl
+ ]);
+ expect(sourceMap.sourcesContent).toEqual([null, template]);
}));
diff --git a/scripts/ci/offline_compiler_test.sh b/scripts/ci/offline_compiler_test.sh
index b0cef0f2d9..db0a29daeb 100755
--- a/scripts/ci/offline_compiler_test.sh
+++ b/scripts/ci/offline_compiler_test.sh
@@ -17,6 +17,7 @@ PKGS=(
@types/{node@6.0.38,jasmine@2.2.33}
jasmine@2.4.1
webpack@2.1.0-beta.21
+ source-map-loader@0.2.0
@angular2-material/{core,button}@2.0.0-alpha.8-1
)