| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @license | 
					
						
							|  |  |  |  * Copyright Google Inc. All Rights Reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Use of this source code is governed by an MIT-style license that can be | 
					
						
							|  |  |  |  * found in the LICENSE file at https://angular.io/license
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import * as ng from '@angular/compiler-cli'; | 
					
						
							|  |  |  | import * as fs from 'fs'; | 
					
						
							|  |  |  | import * as path from 'path'; | 
					
						
							|  |  |  | import * as ts from 'typescript'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-26 09:45:01 -07:00
										 |  |  | import {formatDiagnostics} from '../../src/perform_compile'; | 
					
						
							| 
									
										
										
										
											2017-10-24 11:26:04 -07:00
										 |  |  | import {CompilerHost, EmitFlags, LazyRoute} from '../../src/transformers/api'; | 
					
						
							| 
									
										
										
										
											2017-09-28 11:42:58 -07:00
										 |  |  | import {createSrcToOutPathMapper} from '../../src/transformers/program'; | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  | import {GENERATED_FILES, StructureIsReused, tsStructureIsReused} from '../../src/transformers/util'; | 
					
						
							|  |  |  | import {TestSupport, expectNoDiagnosticsInProgram, setup} from '../test_support'; | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | describe('ng program', () => { | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |   let testSupport: TestSupport; | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   let errorSpy: jasmine.Spy&((s: string) => void); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   beforeEach(() => { | 
					
						
							|  |  |  |     errorSpy = jasmine.createSpy('consoleError').and.callFake(console.error); | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |     testSupport = setup(); | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |   function createModuleAndCompSource(prefix: string, template: string = prefix + 'template') { | 
					
						
							|  |  |  |     const templateEntry = | 
					
						
							|  |  |  |         template.endsWith('.html') ? `templateUrl: '${template}'` : `template: \`${template}\``; | 
					
						
							|  |  |  |     return `
 | 
					
						
							|  |  |  |       import {Component, NgModule} from '@angular/core'; | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |       @Component({selector: '${prefix}', ${templateEntry}}) | 
					
						
							|  |  |  |       export class ${prefix}Comp {} | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |       @NgModule({declarations: [${prefix}Comp]}) | 
					
						
							|  |  |  |       export class ${prefix}Module {} | 
					
						
							|  |  |  |     `;
 | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |   function compileLib(libName: string) { | 
					
						
							|  |  |  |     testSupport.writeFiles({ | 
					
						
							|  |  |  |       [`${libName}_src/index.ts`]: createModuleAndCompSource(libName), | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     const options = testSupport.createCompilerOptions(); | 
					
						
							|  |  |  |     const program = ng.createProgram({ | 
					
						
							|  |  |  |       rootNames: [path.resolve(testSupport.basePath, `${libName}_src/index.ts`)], | 
					
						
							|  |  |  |       options, | 
					
						
							|  |  |  |       host: ng.createCompilerHost({options}), | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     expectNoDiagnosticsInProgram(options, program); | 
					
						
							|  |  |  |     fs.symlinkSync( | 
					
						
							|  |  |  |         path.resolve(testSupport.basePath, 'built', `${libName}_src`), | 
					
						
							|  |  |  |         path.resolve(testSupport.basePath, 'node_modules', libName)); | 
					
						
							|  |  |  |     program.emit({emitFlags: ng.EmitFlags.DTS | ng.EmitFlags.JS | ng.EmitFlags.Metadata}); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |   function compile( | 
					
						
							| 
									
										
										
										
											2017-09-29 15:02:11 -07:00
										 |  |  |       oldProgram?: ng.Program, overrideOptions?: ng.CompilerOptions, rootNames?: string[], | 
					
						
							| 
									
										
										
										
											2017-10-12 16:09:49 -07:00
										 |  |  |       host?: CompilerHost): {program: ng.Program, emitResult: ts.EmitResult} { | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     const options = testSupport.createCompilerOptions(overrideOptions); | 
					
						
							|  |  |  |     if (!rootNames) { | 
					
						
							|  |  |  |       rootNames = [path.resolve(testSupport.basePath, 'src/index.ts')]; | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-29 15:02:11 -07:00
										 |  |  |     if (!host) { | 
					
						
							|  |  |  |       host = ng.createCompilerHost({options}); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     const program = ng.createProgram({ | 
					
						
							|  |  |  |       rootNames: rootNames, | 
					
						
							|  |  |  |       options, | 
					
						
							| 
									
										
										
										
											2017-09-29 15:02:11 -07:00
										 |  |  |       host, | 
					
						
							|  |  |  |       oldProgram, | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     }); | 
					
						
							|  |  |  |     expectNoDiagnosticsInProgram(options, program); | 
					
						
							| 
									
										
										
										
											2017-10-12 16:09:49 -07:00
										 |  |  |     const emitResult = program.emit(); | 
					
						
							| 
									
										
										
										
											2017-10-02 13:38:04 -07:00
										 |  |  |     return {emitResult, program}; | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-30 16:03:22 -07:00
										 |  |  |   function resolveFiles(rootNames: string[]) { | 
					
						
							|  |  |  |     const preOptions = testSupport.createCompilerOptions(); | 
					
						
							|  |  |  |     const preHost = ts.createCompilerHost(preOptions); | 
					
						
							|  |  |  |     // don't resolve symlinks
 | 
					
						
							|  |  |  |     preHost.realpath = (f) => f; | 
					
						
							|  |  |  |     const preProgram = ts.createProgram(rootNames, preOptions, preHost); | 
					
						
							|  |  |  |     return preProgram.getSourceFiles().map(sf => sf.fileName); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |   describe('reuse of old program', () => { | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |     it('should reuse generated code for libraries from old programs', () => { | 
					
						
							|  |  |  |       compileLib('lib'); | 
					
						
							|  |  |  |       testSupport.writeFiles({ | 
					
						
							|  |  |  |         'src/main.ts': createModuleAndCompSource('main'), | 
					
						
							|  |  |  |         'src/index.ts': `
 | 
					
						
							|  |  |  |             export * from './main'; | 
					
						
							|  |  |  |             export * from 'lib/index'; | 
					
						
							|  |  |  |           `
 | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-10-02 13:38:04 -07:00
										 |  |  |       const p1 = compile().program; | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |       expect(p1.getTsProgram().getSourceFiles().some( | 
					
						
							|  |  |  |                  sf => /node_modules\/lib\/.*\.ngfactory\.ts$/.test(sf.fileName))) | 
					
						
							|  |  |  |           .toBe(true); | 
					
						
							|  |  |  |       expect(p1.getTsProgram().getSourceFiles().some( | 
					
						
							|  |  |  |                  sf => /node_modules\/lib2\/.*\.ngfactory.*$/.test(sf.fileName))) | 
					
						
							|  |  |  |           .toBe(false); | 
					
						
							| 
									
										
										
										
											2017-10-02 13:38:04 -07:00
										 |  |  |       const p2 = compile(p1).program; | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |       expect(p2.getTsProgram().getSourceFiles().some( | 
					
						
							|  |  |  |                  sf => /node_modules\/lib\/.*\.ngfactory.*$/.test(sf.fileName))) | 
					
						
							|  |  |  |           .toBe(false); | 
					
						
							|  |  |  |       expect(p2.getTsProgram().getSourceFiles().some( | 
					
						
							|  |  |  |                  sf => /node_modules\/lib2\/.*\.ngfactory.*$/.test(sf.fileName))) | 
					
						
							|  |  |  |           .toBe(false); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // import a library for which we didn't generate code before
 | 
					
						
							|  |  |  |       compileLib('lib2'); | 
					
						
							|  |  |  |       testSupport.writeFiles({ | 
					
						
							|  |  |  |         'src/index.ts': `
 | 
					
						
							|  |  |  |           export * from './main'; | 
					
						
							|  |  |  |           export * from 'lib/index'; | 
					
						
							|  |  |  |           export * from 'lib2/index'; | 
					
						
							|  |  |  |         `,
 | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-10-02 13:38:04 -07:00
										 |  |  |       const p3 = compile(p2).program; | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |       expect(p3.getTsProgram().getSourceFiles().some( | 
					
						
							|  |  |  |                  sf => /node_modules\/lib\/.*\.ngfactory.*$/.test(sf.fileName))) | 
					
						
							|  |  |  |           .toBe(false); | 
					
						
							|  |  |  |       expect(p3.getTsProgram().getSourceFiles().some( | 
					
						
							|  |  |  |                  sf => /node_modules\/lib2\/.*\.ngfactory\.ts$/.test(sf.fileName))) | 
					
						
							|  |  |  |           .toBe(true); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-02 13:38:04 -07:00
										 |  |  |       const p4 = compile(p3).program; | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |       expect(p4.getTsProgram().getSourceFiles().some( | 
					
						
							|  |  |  |                  sf => /node_modules\/lib\/.*\.ngfactory.*$/.test(sf.fileName))) | 
					
						
							|  |  |  |           .toBe(false); | 
					
						
							|  |  |  |       expect(p4.getTsProgram().getSourceFiles().some( | 
					
						
							|  |  |  |                  sf => /node_modules\/lib2\/.*\.ngfactory.*$/.test(sf.fileName))) | 
					
						
							|  |  |  |           .toBe(false); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-28 11:44:05 -07:00
										 |  |  |     // Note: this is the case for watch mode with declaration:false
 | 
					
						
							|  |  |  |     it('should reuse generated code from libraries from old programs with declaration:false', | 
					
						
							|  |  |  |        () => { | 
					
						
							|  |  |  |          compileLib('lib'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          testSupport.writeFiles({ | 
					
						
							|  |  |  |            'src/main.ts': createModuleAndCompSource('main'), | 
					
						
							|  |  |  |            'src/index.ts': `
 | 
					
						
							|  |  |  |             export * from './main'; | 
					
						
							|  |  |  |             export * from 'lib/index'; | 
					
						
							|  |  |  |           `
 | 
					
						
							|  |  |  |          }); | 
					
						
							| 
									
										
										
										
											2017-10-02 13:38:04 -07:00
										 |  |  |          const p1 = compile(undefined, {declaration: false}).program; | 
					
						
							| 
									
										
										
										
											2017-09-28 11:44:05 -07:00
										 |  |  |          expect(p1.getTsProgram().getSourceFiles().some( | 
					
						
							|  |  |  |                     sf => /node_modules\/lib\/.*\.ngfactory\.ts$/.test(sf.fileName))) | 
					
						
							|  |  |  |              .toBe(true); | 
					
						
							|  |  |  |          expect(p1.getTsProgram().getSourceFiles().some( | 
					
						
							|  |  |  |                     sf => /node_modules\/lib2\/.*\.ngfactory.*$/.test(sf.fileName))) | 
					
						
							|  |  |  |              .toBe(false); | 
					
						
							| 
									
										
										
										
											2017-10-02 13:38:04 -07:00
										 |  |  |          const p2 = compile(p1, {declaration: false}).program; | 
					
						
							| 
									
										
										
										
											2017-09-28 11:44:05 -07:00
										 |  |  |          expect(p2.getTsProgram().getSourceFiles().some( | 
					
						
							|  |  |  |                     sf => /node_modules\/lib\/.*\.ngfactory.*$/.test(sf.fileName))) | 
					
						
							|  |  |  |              .toBe(false); | 
					
						
							|  |  |  |          expect(p2.getTsProgram().getSourceFiles().some( | 
					
						
							|  |  |  |                     sf => /node_modules\/lib2\/.*\.ngfactory.*$/.test(sf.fileName))) | 
					
						
							|  |  |  |              .toBe(false); | 
					
						
							|  |  |  |        }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-29 15:02:11 -07:00
										 |  |  |     it('should only emit changed files', () => { | 
					
						
							|  |  |  |       testSupport.writeFiles({ | 
					
						
							|  |  |  |         'src/index.ts': createModuleAndCompSource('comp', 'index.html'), | 
					
						
							|  |  |  |         'src/index.html': `Start` | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       const options: ng.CompilerOptions = {declaration: false}; | 
					
						
							|  |  |  |       const host = ng.createCompilerHost({options}); | 
					
						
							|  |  |  |       const originalGetSourceFile = host.getSourceFile; | 
					
						
							|  |  |  |       const fileCache = new Map<string, ts.SourceFile>(); | 
					
						
							|  |  |  |       host.getSourceFile = (fileName: string) => { | 
					
						
							|  |  |  |         if (fileCache.has(fileName)) { | 
					
						
							|  |  |  |           return fileCache.get(fileName); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         const sf = originalGetSourceFile.call(host, fileName); | 
					
						
							|  |  |  |         fileCache.set(fileName, sf); | 
					
						
							|  |  |  |         return sf; | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const written = new Map<string, string>(); | 
					
						
							|  |  |  |       host.writeFile = (fileName: string, data: string) => written.set(fileName, data); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // compile libraries
 | 
					
						
							| 
									
										
										
										
											2017-10-02 13:38:04 -07:00
										 |  |  |       const p1 = compile(undefined, options, undefined, host).program; | 
					
						
							| 
									
										
										
										
											2017-09-29 15:02:11 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-03 09:53:58 -07:00
										 |  |  |       // compile without libraries
 | 
					
						
							| 
									
										
										
										
											2017-10-02 13:38:04 -07:00
										 |  |  |       const p2 = compile(p1, options, undefined, host).program; | 
					
						
							| 
									
										
										
										
											2017-09-29 15:02:11 -07:00
										 |  |  |       expect(written.has(path.resolve(testSupport.basePath, 'built/src/index.js'))).toBe(true); | 
					
						
							|  |  |  |       let ngFactoryContent = | 
					
						
							|  |  |  |           written.get(path.resolve(testSupport.basePath, 'built/src/index.ngfactory.js')); | 
					
						
							|  |  |  |       expect(ngFactoryContent).toMatch(/Start/); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // no change -> no emit
 | 
					
						
							|  |  |  |       written.clear(); | 
					
						
							| 
									
										
										
										
											2017-10-02 13:38:04 -07:00
										 |  |  |       const p3 = compile(p2, options, undefined, host).program; | 
					
						
							| 
									
										
										
										
											2017-09-29 15:02:11 -07:00
										 |  |  |       expect(written.size).toBe(0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // change a user file
 | 
					
						
							|  |  |  |       written.clear(); | 
					
						
							|  |  |  |       fileCache.delete(path.resolve(testSupport.basePath, 'src/index.ts')); | 
					
						
							| 
									
										
										
										
											2017-10-02 13:38:04 -07:00
										 |  |  |       const p4 = compile(p3, options, undefined, host).program; | 
					
						
							| 
									
										
										
										
											2017-09-29 15:02:11 -07:00
										 |  |  |       expect(written.size).toBe(1); | 
					
						
							|  |  |  |       expect(written.has(path.resolve(testSupport.basePath, 'built/src/index.js'))).toBe(true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // change a file that is input to generated files
 | 
					
						
							|  |  |  |       written.clear(); | 
					
						
							|  |  |  |       testSupport.writeFiles({'src/index.html': 'Hello'}); | 
					
						
							| 
									
										
										
										
											2017-10-03 09:53:58 -07:00
										 |  |  |       const p5 = compile(p4, options, undefined, host).program; | 
					
						
							| 
									
										
										
										
											2017-09-29 15:02:11 -07:00
										 |  |  |       expect(written.size).toBe(1); | 
					
						
							|  |  |  |       ngFactoryContent = | 
					
						
							|  |  |  |           written.get(path.resolve(testSupport.basePath, 'built/src/index.ngfactory.js')); | 
					
						
							|  |  |  |       expect(ngFactoryContent).toMatch(/Hello/); | 
					
						
							| 
									
										
										
										
											2017-10-03 09:53:58 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       // change a file and create an intermediate program that is not emitted
 | 
					
						
							|  |  |  |       written.clear(); | 
					
						
							|  |  |  |       fileCache.delete(path.resolve(testSupport.basePath, 'src/index.ts')); | 
					
						
							|  |  |  |       const p6 = ng.createProgram({ | 
					
						
							|  |  |  |         rootNames: [path.resolve(testSupport.basePath, 'src/index.ts')], | 
					
						
							|  |  |  |         options: testSupport.createCompilerOptions(options), host, | 
					
						
							|  |  |  |         oldProgram: p5 | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       const p7 = compile(p6, options, undefined, host).program; | 
					
						
							|  |  |  |       expect(written.size).toBe(1); | 
					
						
							| 
									
										
										
										
											2017-09-29 15:02:11 -07:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-02 13:38:04 -07:00
										 |  |  |     it('should set emitSkipped to false for full and incremental emit', () => { | 
					
						
							|  |  |  |       testSupport.writeFiles({ | 
					
						
							|  |  |  |         'src/index.ts': createModuleAndCompSource('main'), | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       const {emitResult: emitResult1, program: p1} = compile(); | 
					
						
							|  |  |  |       expect(emitResult1.emitSkipped).toBe(false); | 
					
						
							|  |  |  |       const {emitResult: emitResult2, program: p2} = compile(p1); | 
					
						
							|  |  |  |       expect(emitResult2.emitSkipped).toBe(false); | 
					
						
							|  |  |  |       const {emitResult: emitResult3, program: p3} = compile(p2); | 
					
						
							|  |  |  |       expect(emitResult3.emitSkipped).toBe(false); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     it('should store library summaries on emit', () => { | 
					
						
							|  |  |  |       compileLib('lib'); | 
					
						
							|  |  |  |       testSupport.writeFiles({ | 
					
						
							|  |  |  |         'src/main.ts': createModuleAndCompSource('main'), | 
					
						
							|  |  |  |         'src/index.ts': `
 | 
					
						
							|  |  |  |             export * from './main'; | 
					
						
							|  |  |  |             export * from 'lib/index'; | 
					
						
							|  |  |  |           `
 | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-10-02 13:38:04 -07:00
										 |  |  |       const p1 = compile().program; | 
					
						
							| 
									
										
										
										
											2017-09-29 15:02:11 -07:00
										 |  |  |       expect(Array.from(p1.getLibrarySummaries().values()) | 
					
						
							|  |  |  |                  .some(sf => /node_modules\/lib\/index\.ngfactory\.d\.ts$/.test(sf.fileName))) | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |           .toBe(true); | 
					
						
							| 
									
										
										
										
											2017-09-29 15:02:11 -07:00
										 |  |  |       expect(Array.from(p1.getLibrarySummaries().values()) | 
					
						
							|  |  |  |                  .some(sf => /node_modules\/lib\/index\.ngsummary\.json$/.test(sf.fileName))) | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |           .toBe(true); | 
					
						
							| 
									
										
										
										
											2017-09-29 15:02:11 -07:00
										 |  |  |       expect(Array.from(p1.getLibrarySummaries().values()) | 
					
						
							|  |  |  |                  .some(sf => /node_modules\/lib\/index\.d\.ts$/.test(sf.fileName))) | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |           .toBe(true); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-29 15:02:11 -07:00
										 |  |  |       expect(Array.from(p1.getLibrarySummaries().values()) | 
					
						
							|  |  |  |                  .some(sf => /src\/main.*$/.test(sf.fileName))) | 
					
						
							|  |  |  |           .toBe(false); | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |     it('should reuse the old ts program completely if nothing changed', () => { | 
					
						
							|  |  |  |       testSupport.writeFiles({'src/index.ts': createModuleAndCompSource('main')}); | 
					
						
							|  |  |  |       // Note: the second compile drops factories for library files,
 | 
					
						
							|  |  |  |       // and therefore changes the structure again
 | 
					
						
							| 
									
										
										
										
											2017-10-02 13:38:04 -07:00
										 |  |  |       const p1 = compile().program; | 
					
						
							|  |  |  |       const p2 = compile(p1).program; | 
					
						
							|  |  |  |       compile(p2); | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |       expect(tsStructureIsReused(p2.getTsProgram())).toBe(StructureIsReused.Completely); | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |     it('should reuse the old ts program completely if a template or a ts file changed', () => { | 
					
						
							|  |  |  |       testSupport.writeFiles({ | 
					
						
							|  |  |  |         'src/main.ts': createModuleAndCompSource('main', 'main.html'), | 
					
						
							|  |  |  |         'src/main.html': `Some template`, | 
					
						
							|  |  |  |         'src/util.ts': `export const x = 1`, | 
					
						
							|  |  |  |         'src/index.ts': `
 | 
					
						
							|  |  |  |           export * from './main'; | 
					
						
							|  |  |  |           export * from './util'; | 
					
						
							|  |  |  |         `
 | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       // Note: the second compile drops factories for library files,
 | 
					
						
							|  |  |  |       // and therefore changes the structure again
 | 
					
						
							| 
									
										
										
										
											2017-10-02 13:38:04 -07:00
										 |  |  |       const p1 = compile().program; | 
					
						
							|  |  |  |       const p2 = compile(p1).program; | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |       testSupport.writeFiles({ | 
					
						
							|  |  |  |         'src/main.html': `Another template`, | 
					
						
							|  |  |  |         'src/util.ts': `export const x = 2`, | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-10-02 13:38:04 -07:00
										 |  |  |       compile(p2); | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |       expect(tsStructureIsReused(p2.getTsProgram())).toBe(StructureIsReused.Completely); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should not reuse the old ts program if an import changed', () => { | 
					
						
							|  |  |  |       testSupport.writeFiles({ | 
					
						
							|  |  |  |         'src/main.ts': createModuleAndCompSource('main'), | 
					
						
							|  |  |  |         'src/util.ts': `export const x = 1`, | 
					
						
							|  |  |  |         'src/index.ts': `
 | 
					
						
							|  |  |  |           export * from './main'; | 
					
						
							|  |  |  |           export * from './util'; | 
					
						
							|  |  |  |         `
 | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       // Note: the second compile drops factories for library files,
 | 
					
						
							|  |  |  |       // and therefore changes the structure again
 | 
					
						
							| 
									
										
										
										
											2017-10-02 13:38:04 -07:00
										 |  |  |       const p1 = compile().program; | 
					
						
							|  |  |  |       const p2 = compile(p1).program; | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |       testSupport.writeFiles( | 
					
						
							|  |  |  |           {'src/util.ts': `import {Injectable} from '@angular/core'; export const x = 1;`}); | 
					
						
							| 
									
										
										
										
											2017-10-02 13:38:04 -07:00
										 |  |  |       compile(p2); | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |       expect(tsStructureIsReused(p2.getTsProgram())).toBe(StructureIsReused.SafeModules); | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-24 11:26:04 -07:00
										 |  |  |   it('should not typecheck templates if skipTemplateCodegen is set but fullTemplateTypeCheck is not', | 
					
						
							|  |  |  |      () => { | 
					
						
							|  |  |  |        testSupport.writeFiles({ | 
					
						
							|  |  |  |          'src/main.ts': `
 | 
					
						
							|  |  |  |         import {NgModule} from '@angular/core'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-15 22:33:30 -08:00
										 |  |  |         @NgModule((() => {if (1==1) return null as any;}) as any) | 
					
						
							| 
									
										
										
										
											2017-10-24 11:26:04 -07:00
										 |  |  |         export class SomeClassWithInvalidMetadata {} | 
					
						
							|  |  |  |       `,
 | 
					
						
							|  |  |  |        }); | 
					
						
							|  |  |  |        const options = testSupport.createCompilerOptions({skipTemplateCodegen: true}); | 
					
						
							|  |  |  |        const host = ng.createCompilerHost({options}); | 
					
						
							|  |  |  |        const program = ng.createProgram( | 
					
						
							|  |  |  |            {rootNames: [path.resolve(testSupport.basePath, 'src/main.ts')], options, host}); | 
					
						
							|  |  |  |        expectNoDiagnosticsInProgram(options, program); | 
					
						
							|  |  |  |        const emitResult = program.emit({emitFlags: EmitFlags.All}); | 
					
						
							|  |  |  |        expect(emitResult.diagnostics.length).toBe(0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |        testSupport.shouldExist('built/src/main.metadata.json'); | 
					
						
							|  |  |  |      }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should typecheck templates if skipTemplateCodegen and fullTemplateTypeCheck is set', () => { | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |     testSupport.writeFiles({ | 
					
						
							|  |  |  |       'src/main.ts': createModuleAndCompSource('main', `{{nonExistent}}`), | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2017-10-24 11:26:04 -07:00
										 |  |  |     const options = testSupport.createCompilerOptions({ | 
					
						
							|  |  |  |       skipTemplateCodegen: true, | 
					
						
							|  |  |  |       fullTemplateTypeCheck: true, | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     const host = ng.createCompilerHost({options}); | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |     const program = ng.createProgram( | 
					
						
							|  |  |  |         {rootNames: [path.resolve(testSupport.basePath, 'src/main.ts')], options, host}); | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     const diags = program.getNgSemanticDiagnostics(); | 
					
						
							|  |  |  |     expect(diags.length).toBe(1); | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |     expect(diags[0].messageText).toBe(`Property 'nonExistent' does not exist on type 'mainComp'.`); | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should be able to use asynchronously loaded resources', (done) => { | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |     testSupport.writeFiles({ | 
					
						
							|  |  |  |       'src/main.ts': createModuleAndCompSource('main', 'main.html'), | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |       // Note: we need to be able to resolve the template synchronously,
 | 
					
						
							|  |  |  |       // only the content is delivered asynchronously.
 | 
					
						
							|  |  |  |       'src/main.html': '', | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |     const options = testSupport.createCompilerOptions(); | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     const host = ng.createCompilerHost({options}); | 
					
						
							|  |  |  |     host.readResource = () => Promise.resolve('Hello world!'); | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |     const program = ng.createProgram( | 
					
						
							|  |  |  |         {rootNames: [path.resolve(testSupport.basePath, 'src/main.ts')], options, host}); | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     program.loadNgStructureAsync().then(() => { | 
					
						
							|  |  |  |       program.emit(); | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |       const factory = | 
					
						
							|  |  |  |           fs.readFileSync(path.resolve(testSupport.basePath, 'built/src/main.ngfactory.js')); | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |       expect(factory).toContain('Hello world!'); | 
					
						
							|  |  |  |       done(); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2017-09-20 16:27:29 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   it('should work with noResolve', () => { | 
					
						
							|  |  |  |     // create a temporary ts program to get the list of all files from angular...
 | 
					
						
							|  |  |  |     testSupport.writeFiles({ | 
					
						
							|  |  |  |       'src/main.ts': createModuleAndCompSource('main'), | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2017-10-30 16:03:22 -07:00
										 |  |  |     const allRootNames = resolveFiles([path.resolve(testSupport.basePath, 'src/main.ts')]); | 
					
						
							| 
									
										
										
										
											2017-09-20 16:27:29 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // now do the actual test with noResolve
 | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     const program = compile(undefined, {noResolve: true}, allRootNames); | 
					
						
							| 
									
										
										
										
											2017-09-20 16:27:29 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     testSupport.shouldExist('built/src/main.ngfactory.js'); | 
					
						
							|  |  |  |     testSupport.shouldExist('built/src/main.ngfactory.d.ts'); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-29 15:27:16 +08:00
										 |  |  |   it('should work with tsx files', () => { | 
					
						
							|  |  |  |     // create a temporary ts program to get the list of all files from angular...
 | 
					
						
							|  |  |  |     testSupport.writeFiles({ | 
					
						
							|  |  |  |       'src/main.tsx': createModuleAndCompSource('main'), | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     const allRootNames = resolveFiles([path.resolve(testSupport.basePath, 'src/main.tsx')]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const program = compile(undefined, {jsx: ts.JsxEmit.React}, allRootNames); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     testSupport.shouldExist('built/src/main.js'); | 
					
						
							|  |  |  |     testSupport.shouldExist('built/src/main.d.ts'); | 
					
						
							|  |  |  |     testSupport.shouldExist('built/src/main.ngfactory.js'); | 
					
						
							|  |  |  |     testSupport.shouldExist('built/src/main.ngfactory.d.ts'); | 
					
						
							|  |  |  |     testSupport.shouldExist('built/src/main.ngsummary.json'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |   it('should emit also empty generated files depending on the options', () => { | 
					
						
							|  |  |  |     testSupport.writeFiles({ | 
					
						
							|  |  |  |       'src/main.ts': `
 | 
					
						
							|  |  |  |         import {Component, NgModule} from '@angular/core'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         @Component({selector: 'main', template: '', styleUrls: ['main.css']}) | 
					
						
							|  |  |  |         export class MainComp {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         @NgModule({declarations: [MainComp]}) | 
					
						
							|  |  |  |         export class MainModule {} | 
					
						
							|  |  |  |       `,
 | 
					
						
							|  |  |  |       'src/main.css': ``, | 
					
						
							|  |  |  |       'src/util.ts': 'export const x = 1;', | 
					
						
							|  |  |  |       'src/index.ts': `
 | 
					
						
							|  |  |  |         export * from './util'; | 
					
						
							|  |  |  |         export * from './main'; | 
					
						
							|  |  |  |       `,
 | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2017-09-29 14:55:44 -07:00
										 |  |  |     const options = testSupport.createCompilerOptions({ | 
					
						
							|  |  |  |       allowEmptyCodegenFiles: true, | 
					
						
							|  |  |  |       enableSummariesForJit: true, | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     const host = ng.createCompilerHost({options}); | 
					
						
							|  |  |  |     const written = new Map < string, { | 
					
						
							| 
									
										
										
										
											2017-12-22 09:36:47 -08:00
										 |  |  |       original: ReadonlyArray<ts.SourceFile>|undefined; | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |       data: string; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     > (); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     host.writeFile = | 
					
						
							|  |  |  |         (fileName: string, data: string, writeByteOrderMark: boolean, | 
					
						
							| 
									
										
										
										
											2017-12-22 09:36:47 -08:00
										 |  |  |          onError: (message: string) => void|undefined, | 
					
						
							|  |  |  |          sourceFiles: ReadonlyArray<ts.SourceFile>) => { | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |           written.set(fileName, {original: sourceFiles, data}); | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  |     const program = ng.createProgram( | 
					
						
							|  |  |  |         {rootNames: [path.resolve(testSupport.basePath, 'src/index.ts')], options, host}); | 
					
						
							|  |  |  |     program.emit(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-08 08:59:25 -08:00
										 |  |  |     const enum ShouldBe { Empty, EmptyExport, NoneEmpty } | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     function assertGenFile( | 
					
						
							| 
									
										
										
										
											2018-02-08 08:59:25 -08:00
										 |  |  |         fileName: string, checks: {originalFileName: string, shouldBe: ShouldBe}) { | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |       const writeData = written.get(path.join(testSupport.basePath, fileName)); | 
					
						
							|  |  |  |       expect(writeData).toBeTruthy(); | 
					
						
							|  |  |  |       expect(writeData !.original !.some( | 
					
						
							|  |  |  |                  sf => sf.fileName === path.join(testSupport.basePath, checks.originalFileName))) | 
					
						
							|  |  |  |           .toBe(true); | 
					
						
							| 
									
										
										
										
											2018-02-08 08:59:25 -08:00
										 |  |  |       switch (checks.shouldBe) { | 
					
						
							|  |  |  |         case ShouldBe.Empty: | 
					
						
							|  |  |  |           expect(writeData !.data).toMatch(/^(\s*\/\*([^*]|\*[^/])*\*\/\s*)?$/); | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  |         case ShouldBe.EmptyExport: | 
					
						
							|  |  |  |           expect(writeData !.data) | 
					
						
							|  |  |  |               .toMatch(/^((\s*\/\*([^*]|\*[^/])*\*\/\s*)|(\s*export\s*{\s*}\s*;\s*)|())$/); | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  |         case ShouldBe.NoneEmpty: | 
					
						
							|  |  |  |           expect(writeData !.data).not.toBe(''); | 
					
						
							|  |  |  |           break; | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     assertGenFile( | 
					
						
							| 
									
										
										
										
											2018-02-08 08:59:25 -08:00
										 |  |  |         'built/src/util.ngfactory.js', {originalFileName: 'src/util.ts', shouldBe: ShouldBe.Empty}); | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     assertGenFile( | 
					
						
							| 
									
										
										
										
											2018-02-08 08:59:25 -08:00
										 |  |  |         'built/src/util.ngfactory.d.ts', | 
					
						
							|  |  |  |         {originalFileName: 'src/util.ts', shouldBe: ShouldBe.EmptyExport}); | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     assertGenFile( | 
					
						
							| 
									
										
										
										
											2018-02-08 08:59:25 -08:00
										 |  |  |         'built/src/util.ngsummary.js', {originalFileName: 'src/util.ts', shouldBe: ShouldBe.Empty}); | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     assertGenFile( | 
					
						
							| 
									
										
										
										
											2018-02-08 08:59:25 -08:00
										 |  |  |         'built/src/util.ngsummary.d.ts', | 
					
						
							|  |  |  |         {originalFileName: 'src/util.ts', shouldBe: ShouldBe.EmptyExport}); | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     assertGenFile( | 
					
						
							| 
									
										
										
										
											2018-02-08 08:59:25 -08:00
										 |  |  |         'built/src/util.ngsummary.json', | 
					
						
							|  |  |  |         {originalFileName: 'src/util.ts', shouldBe: ShouldBe.NoneEmpty}); | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Note: we always fill non shim and shim style files as they might
 | 
					
						
							|  |  |  |     // be shared by component with and without ViewEncapsulation.
 | 
					
						
							|  |  |  |     assertGenFile( | 
					
						
							| 
									
										
										
										
											2018-02-08 08:59:25 -08:00
										 |  |  |         'built/src/main.css.ngstyle.js', | 
					
						
							|  |  |  |         {originalFileName: 'src/main.ts', shouldBe: ShouldBe.NoneEmpty}); | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     assertGenFile( | 
					
						
							| 
									
										
										
										
											2018-02-08 08:59:25 -08:00
										 |  |  |         'built/src/main.css.ngstyle.d.ts', | 
					
						
							|  |  |  |         {originalFileName: 'src/main.ts', shouldBe: ShouldBe.EmptyExport}); | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     // Note: this file is not empty as we actually generated code for it
 | 
					
						
							|  |  |  |     assertGenFile( | 
					
						
							|  |  |  |         'built/src/main.css.shim.ngstyle.js', | 
					
						
							| 
									
										
										
										
											2018-02-08 08:59:25 -08:00
										 |  |  |         {originalFileName: 'src/main.ts', shouldBe: ShouldBe.NoneEmpty}); | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     assertGenFile( | 
					
						
							|  |  |  |         'built/src/main.css.shim.ngstyle.d.ts', | 
					
						
							| 
									
										
										
										
											2018-02-08 08:59:25 -08:00
										 |  |  |         {originalFileName: 'src/main.ts', shouldBe: ShouldBe.EmptyExport}); | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should not emit /// references in .d.ts files', () => { | 
					
						
							|  |  |  |     testSupport.writeFiles({ | 
					
						
							|  |  |  |       'src/main.ts': createModuleAndCompSource('main'), | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     compile(undefined, {declaration: true}, [path.resolve(testSupport.basePath, 'src/main.ts')]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const dts = | 
					
						
							|  |  |  |         fs.readFileSync(path.resolve(testSupport.basePath, 'built', 'src', 'main.d.ts')).toString(); | 
					
						
							|  |  |  |     expect(dts).toMatch('export declare class'); | 
					
						
							|  |  |  |     expect(dts).not.toMatch('///'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should not emit generated files whose sources are outside of the rootDir', () => { | 
					
						
							|  |  |  |     testSupport.writeFiles({ | 
					
						
							|  |  |  |       'src/main.ts': createModuleAndCompSource('main'), | 
					
						
							|  |  |  |       'src/index.ts': `
 | 
					
						
							|  |  |  |           export * from './main'; | 
					
						
							|  |  |  |         `
 | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2017-10-17 16:51:04 -07:00
										 |  |  |     const options = | 
					
						
							|  |  |  |         testSupport.createCompilerOptions({rootDir: path.resolve(testSupport.basePath, 'src')}); | 
					
						
							|  |  |  |     const host = ng.createCompilerHost({options}); | 
					
						
							|  |  |  |     const writtenFileNames: string[] = []; | 
					
						
							|  |  |  |     const oldWriteFile = host.writeFile; | 
					
						
							| 
									
										
										
										
											2017-12-22 09:36:47 -08:00
										 |  |  |     host.writeFile = (fileName, data, writeByteOrderMark, onError, sourceFiles) => { | 
					
						
							| 
									
										
										
										
											2017-10-17 16:51:04 -07:00
										 |  |  |       writtenFileNames.push(fileName); | 
					
						
							| 
									
										
										
										
											2017-12-22 09:36:47 -08:00
										 |  |  |       oldWriteFile(fileName, data, writeByteOrderMark, onError, sourceFiles); | 
					
						
							| 
									
										
										
										
											2017-10-17 16:51:04 -07:00
										 |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     compile(/*oldProgram*/ undefined, options, /*rootNames*/ undefined, host); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // no emit for files from node_modules as they are outside of rootDir
 | 
					
						
							|  |  |  |     expect(writtenFileNames.some(f => /node_modules/.test(f))).toBe(false); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // emit all gen files for files under src/
 | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     testSupport.shouldExist('built/main.js'); | 
					
						
							|  |  |  |     testSupport.shouldExist('built/main.d.ts'); | 
					
						
							|  |  |  |     testSupport.shouldExist('built/main.ngfactory.js'); | 
					
						
							|  |  |  |     testSupport.shouldExist('built/main.ngfactory.d.ts'); | 
					
						
							|  |  |  |     testSupport.shouldExist('built/main.ngsummary.json'); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2017-09-28 11:42:58 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   describe('createSrcToOutPathMapper', () => { | 
					
						
							|  |  |  |     it('should return identity mapping if no outDir is present', () => { | 
					
						
							|  |  |  |       const mapper = createSrcToOutPathMapper(undefined, undefined, undefined); | 
					
						
							|  |  |  |       expect(mapper('/tmp/b/y.js')).toBe('/tmp/b/y.js'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should return identity mapping if first src and out fileName have same dir', () => { | 
					
						
							|  |  |  |       const mapper = createSrcToOutPathMapper('/tmp', '/tmp/a/x.ts', '/tmp/a/x.js'); | 
					
						
							|  |  |  |       expect(mapper('/tmp/b/y.js')).toBe('/tmp/b/y.js'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should adjust the filename if the outDir is inside of the rootDir', () => { | 
					
						
							|  |  |  |       const mapper = createSrcToOutPathMapper('/tmp/out', '/tmp/a/x.ts', '/tmp/out/a/x.js'); | 
					
						
							|  |  |  |       expect(mapper('/tmp/b/y.js')).toBe('/tmp/out/b/y.js'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should adjust the filename if the outDir is outside of the rootDir', () => { | 
					
						
							| 
									
										
										
										
											2017-10-17 16:51:04 -07:00
										 |  |  |       const mapper = createSrcToOutPathMapper('/out', '/tmp/a/x.ts', '/out/a/x.js'); | 
					
						
							| 
									
										
										
										
											2017-09-28 11:42:58 -07:00
										 |  |  |       expect(mapper('/tmp/b/y.js')).toBe('/out/b/y.js'); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2017-10-06 15:12:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-17 16:51:04 -07:00
										 |  |  |     it('should adjust the filename if the common prefix of sampleSrc and sampleOut is outside of outDir', | 
					
						
							|  |  |  |        () => { | 
					
						
							|  |  |  |          const mapper = | 
					
						
							|  |  |  |              createSrcToOutPathMapper('/dist/common', '/src/common/x.ts', '/dist/common/x.js'); | 
					
						
							|  |  |  |          expect(mapper('/src/common/y.js')).toBe('/dist/common/y.js'); | 
					
						
							|  |  |  |        }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-06 15:12:32 -07:00
										 |  |  |     it('should work on windows with normalized paths', () => { | 
					
						
							|  |  |  |       const mapper = | 
					
						
							|  |  |  |           createSrcToOutPathMapper('c:/tmp/out', 'c:/tmp/a/x.ts', 'c:/tmp/out/a/x.js', path.win32); | 
					
						
							|  |  |  |       expect(mapper('c:/tmp/b/y.js')).toBe('c:\\tmp\\out\\b\\y.js'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should work on windows with non-normalized paths', () => { | 
					
						
							|  |  |  |       const mapper = createSrcToOutPathMapper( | 
					
						
							|  |  |  |           'c:\\tmp\\out', 'c:\\tmp\\a\\x.ts', 'c:\\tmp\\out\\a\\x.js', path.win32); | 
					
						
							|  |  |  |       expect(mapper('c:\\tmp\\b\\y.js')).toBe('c:\\tmp\\out\\b\\y.js'); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2017-09-28 11:42:58 -07:00
										 |  |  |   }); | 
					
						
							| 
									
										
										
										
											2017-10-20 09:46:41 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   describe('listLazyRoutes', () => { | 
					
						
							|  |  |  |     function writeSomeRoutes() { | 
					
						
							|  |  |  |       testSupport.writeFiles({ | 
					
						
							|  |  |  |         'src/main.ts': `
 | 
					
						
							|  |  |  |           import {NgModule} from '@angular/core'; | 
					
						
							|  |  |  |           import {RouterModule} from '@angular/router'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           @NgModule({ | 
					
						
							|  |  |  |             imports: [RouterModule.forRoot([{loadChildren: './child#ChildModule'}])] | 
					
						
							|  |  |  |           }) | 
					
						
							|  |  |  |           export class MainModule {} | 
					
						
							|  |  |  |         `,
 | 
					
						
							|  |  |  |         'src/child.ts': `
 | 
					
						
							|  |  |  |           import {NgModule} from '@angular/core'; | 
					
						
							|  |  |  |           import {RouterModule} from '@angular/router'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           @NgModule({ | 
					
						
							|  |  |  |             imports: [RouterModule.forChild([{loadChildren: './child2#ChildModule2'}])] | 
					
						
							|  |  |  |           }) | 
					
						
							|  |  |  |           export class ChildModule {} | 
					
						
							|  |  |  |         `,
 | 
					
						
							|  |  |  |         'src/child2.ts': `
 | 
					
						
							|  |  |  |           import {NgModule} from '@angular/core'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           @NgModule() | 
					
						
							|  |  |  |           export class ChildModule2 {} | 
					
						
							|  |  |  |         `,
 | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-24 12:52:14 -07:00
										 |  |  |     function createProgram(rootNames: string[], overrideOptions: ng.CompilerOptions = {}) { | 
					
						
							|  |  |  |       const options = testSupport.createCompilerOptions(overrideOptions); | 
					
						
							| 
									
										
										
										
											2017-10-20 09:46:41 -07:00
										 |  |  |       const host = ng.createCompilerHost({options}); | 
					
						
							|  |  |  |       const program = ng.createProgram( | 
					
						
							|  |  |  |           {rootNames: rootNames.map(p => path.resolve(testSupport.basePath, p)), options, host}); | 
					
						
							|  |  |  |       return {program, options}; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     function normalizeRoutes(lazyRoutes: LazyRoute[]) { | 
					
						
							|  |  |  |       return lazyRoutes.map( | 
					
						
							|  |  |  |           r => ({ | 
					
						
							|  |  |  |             route: r.route, | 
					
						
							|  |  |  |             module: {name: r.module.name, filePath: r.module.filePath}, | 
					
						
							|  |  |  |             referencedModule: | 
					
						
							|  |  |  |                 {name: r.referencedModule.name, filePath: r.referencedModule.filePath}, | 
					
						
							|  |  |  |           })); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should list all lazyRoutes', () => { | 
					
						
							|  |  |  |       writeSomeRoutes(); | 
					
						
							|  |  |  |       const {program, options} = createProgram(['src/main.ts', 'src/child.ts', 'src/child2.ts']); | 
					
						
							|  |  |  |       expectNoDiagnosticsInProgram(options, program); | 
					
						
							|  |  |  |       expect(normalizeRoutes(program.listLazyRoutes())).toEqual([ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           module: {name: 'MainModule', filePath: path.resolve(testSupport.basePath, 'src/main.ts')}, | 
					
						
							|  |  |  |           referencedModule: | 
					
						
							|  |  |  |               {name: 'ChildModule', filePath: path.resolve(testSupport.basePath, 'src/child.ts')}, | 
					
						
							|  |  |  |           route: './child#ChildModule' | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           module: | 
					
						
							|  |  |  |               {name: 'ChildModule', filePath: path.resolve(testSupport.basePath, 'src/child.ts')}, | 
					
						
							|  |  |  |           referencedModule: | 
					
						
							|  |  |  |               {name: 'ChildModule2', filePath: path.resolve(testSupport.basePath, 'src/child2.ts')}, | 
					
						
							|  |  |  |           route: './child2#ChildModule2' | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |       ]); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-25 16:51:12 -07:00
										 |  |  |     it('should emit correctly after listing lazyRoutes', () => { | 
					
						
							|  |  |  |       testSupport.writeFiles({ | 
					
						
							|  |  |  |         'src/main.ts': `
 | 
					
						
							|  |  |  |           import {NgModule} from '@angular/core'; | 
					
						
							|  |  |  |           import {RouterModule} from '@angular/router'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           @NgModule({ | 
					
						
							|  |  |  |             imports: [RouterModule.forRoot([{loadChildren: './lazy/lazy#LazyModule'}])] | 
					
						
							|  |  |  |           }) | 
					
						
							|  |  |  |           export class MainModule {} | 
					
						
							|  |  |  |         `,
 | 
					
						
							|  |  |  |         'src/lazy/lazy.ts': `
 | 
					
						
							|  |  |  |           import {NgModule} from '@angular/core'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           @NgModule() | 
					
						
							|  |  |  |           export class ChildModule {} | 
					
						
							|  |  |  |         `,
 | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       const {program, options} = createProgram(['src/main.ts', 'src/lazy/lazy.ts']); | 
					
						
							|  |  |  |       expectNoDiagnosticsInProgram(options, program); | 
					
						
							|  |  |  |       program.listLazyRoutes(); | 
					
						
							|  |  |  |       program.emit(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const lazyNgFactory = | 
					
						
							|  |  |  |           fs.readFileSync(path.resolve(testSupport.basePath, 'built/src/lazy/lazy.ngfactory.js')); | 
					
						
							|  |  |  |       expect(lazyNgFactory).toContain('import * as i1 from "./lazy";'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-20 09:46:41 -07:00
										 |  |  |     it('should list lazyRoutes given an entryRoute recursively', () => { | 
					
						
							|  |  |  |       writeSomeRoutes(); | 
					
						
							|  |  |  |       const {program, options} = createProgram(['src/main.ts']); | 
					
						
							|  |  |  |       expectNoDiagnosticsInProgram(options, program); | 
					
						
							|  |  |  |       expect(normalizeRoutes(program.listLazyRoutes('src/main#MainModule'))).toEqual([ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           module: {name: 'MainModule', filePath: path.resolve(testSupport.basePath, 'src/main.ts')}, | 
					
						
							|  |  |  |           referencedModule: | 
					
						
							|  |  |  |               {name: 'ChildModule', filePath: path.resolve(testSupport.basePath, 'src/child.ts')}, | 
					
						
							|  |  |  |           route: './child#ChildModule' | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           module: | 
					
						
							|  |  |  |               {name: 'ChildModule', filePath: path.resolve(testSupport.basePath, 'src/child.ts')}, | 
					
						
							|  |  |  |           referencedModule: | 
					
						
							|  |  |  |               {name: 'ChildModule2', filePath: path.resolve(testSupport.basePath, 'src/child2.ts')}, | 
					
						
							|  |  |  |           route: './child2#ChildModule2' | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |       ]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(normalizeRoutes(program.listLazyRoutes('src/child#ChildModule'))).toEqual([ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           module: | 
					
						
							|  |  |  |               {name: 'ChildModule', filePath: path.resolve(testSupport.basePath, 'src/child.ts')}, | 
					
						
							|  |  |  |           referencedModule: | 
					
						
							|  |  |  |               {name: 'ChildModule2', filePath: path.resolve(testSupport.basePath, 'src/child2.ts')}, | 
					
						
							|  |  |  |           route: './child2#ChildModule2' | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |       ]); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should list lazyRoutes pointing to a default export', () => { | 
					
						
							|  |  |  |       testSupport.writeFiles({ | 
					
						
							|  |  |  |         'src/main.ts': `
 | 
					
						
							|  |  |  |           import {NgModule} from '@angular/core'; | 
					
						
							|  |  |  |           import {RouterModule} from '@angular/router'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           @NgModule({ | 
					
						
							|  |  |  |             imports: [RouterModule.forRoot([{loadChildren: './child'}])] | 
					
						
							|  |  |  |           }) | 
					
						
							|  |  |  |           export class MainModule {} | 
					
						
							|  |  |  |         `,
 | 
					
						
							|  |  |  |         'src/child.ts': `
 | 
					
						
							|  |  |  |           import {NgModule} from '@angular/core'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           @NgModule() | 
					
						
							|  |  |  |           export default class ChildModule {} | 
					
						
							|  |  |  |         `,
 | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       const {program, options} = createProgram(['src/main.ts']); | 
					
						
							|  |  |  |       expect(normalizeRoutes(program.listLazyRoutes('src/main#MainModule'))).toEqual([ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           module: {name: 'MainModule', filePath: path.resolve(testSupport.basePath, 'src/main.ts')}, | 
					
						
							|  |  |  |           referencedModule: | 
					
						
							|  |  |  |               {name: undefined, filePath: path.resolve(testSupport.basePath, 'src/child.ts')}, | 
					
						
							|  |  |  |           route: './child' | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |       ]); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should list lazyRoutes from imported modules', () => { | 
					
						
							|  |  |  |       testSupport.writeFiles({ | 
					
						
							|  |  |  |         'src/main.ts': `
 | 
					
						
							|  |  |  |           import {NgModule} from '@angular/core'; | 
					
						
							|  |  |  |           import {RouterModule} from '@angular/router'; | 
					
						
							|  |  |  |           import {NestedMainModule} from './nested/main'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           @NgModule({ | 
					
						
							|  |  |  |             imports: [ | 
					
						
							|  |  |  |               RouterModule.forRoot([{loadChildren: './child#ChildModule'}]), | 
					
						
							|  |  |  |               NestedMainModule, | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |           }) | 
					
						
							|  |  |  |           export class MainModule {} | 
					
						
							|  |  |  |         `,
 | 
					
						
							|  |  |  |         'src/child.ts': `
 | 
					
						
							|  |  |  |           import {NgModule} from '@angular/core'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           @NgModule() | 
					
						
							|  |  |  |           export class ChildModule {} | 
					
						
							|  |  |  |         `,
 | 
					
						
							|  |  |  |         'src/nested/main.ts': `
 | 
					
						
							|  |  |  |           import {NgModule} from '@angular/core'; | 
					
						
							|  |  |  |           import {RouterModule} from '@angular/router'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           @NgModule({ | 
					
						
							|  |  |  |             imports: [RouterModule.forChild([{loadChildren: './child#NestedChildModule'}])] | 
					
						
							|  |  |  |           }) | 
					
						
							|  |  |  |           export class NestedMainModule {} | 
					
						
							|  |  |  |         `,
 | 
					
						
							|  |  |  |         'src/nested/child.ts': `
 | 
					
						
							|  |  |  |           import {NgModule} from '@angular/core'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           @NgModule() | 
					
						
							|  |  |  |           export class NestedChildModule {} | 
					
						
							|  |  |  |         `,
 | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       const {program, options} = createProgram(['src/main.ts']); | 
					
						
							|  |  |  |       expect(normalizeRoutes(program.listLazyRoutes('src/main#MainModule'))).toEqual([ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           module: { | 
					
						
							|  |  |  |             name: 'NestedMainModule', | 
					
						
							|  |  |  |             filePath: path.resolve(testSupport.basePath, 'src/nested/main.ts') | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |           referencedModule: { | 
					
						
							|  |  |  |             name: 'NestedChildModule', | 
					
						
							|  |  |  |             filePath: path.resolve(testSupport.basePath, 'src/nested/child.ts') | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |           route: './child#NestedChildModule' | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           module: {name: 'MainModule', filePath: path.resolve(testSupport.basePath, 'src/main.ts')}, | 
					
						
							|  |  |  |           referencedModule: | 
					
						
							|  |  |  |               {name: 'ChildModule', filePath: path.resolve(testSupport.basePath, 'src/child.ts')}, | 
					
						
							|  |  |  |           route: './child#ChildModule' | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |       ]); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should dedupe lazyRoutes given an entryRoute', () => { | 
					
						
							|  |  |  |       writeSomeRoutes(); | 
					
						
							|  |  |  |       testSupport.writeFiles({ | 
					
						
							|  |  |  |         'src/index.ts': `
 | 
					
						
							|  |  |  |           import {NgModule} from '@angular/core'; | 
					
						
							|  |  |  |           import {RouterModule} from '@angular/router'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           @NgModule({ | 
					
						
							|  |  |  |             imports: [ | 
					
						
							|  |  |  |               RouterModule.forRoot([{loadChildren: './main#MainModule'}]), | 
					
						
							|  |  |  |               RouterModule.forRoot([{loadChildren: './child#ChildModule'}]), | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |           }) | 
					
						
							|  |  |  |           export class MainModule {} | 
					
						
							|  |  |  |         `,
 | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       const {program, options} = createProgram(['src/index.ts']); | 
					
						
							|  |  |  |       expectNoDiagnosticsInProgram(options, program); | 
					
						
							|  |  |  |       expect(normalizeRoutes(program.listLazyRoutes('src/main#MainModule'))).toEqual([ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           module: {name: 'MainModule', filePath: path.resolve(testSupport.basePath, 'src/main.ts')}, | 
					
						
							|  |  |  |           referencedModule: | 
					
						
							|  |  |  |               {name: 'ChildModule', filePath: path.resolve(testSupport.basePath, 'src/child.ts')}, | 
					
						
							|  |  |  |           route: './child#ChildModule' | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           module: | 
					
						
							|  |  |  |               {name: 'ChildModule', filePath: path.resolve(testSupport.basePath, 'src/child.ts')}, | 
					
						
							|  |  |  |           referencedModule: | 
					
						
							|  |  |  |               {name: 'ChildModule2', filePath: path.resolve(testSupport.basePath, 'src/child2.ts')}, | 
					
						
							|  |  |  |           route: './child2#ChildModule2' | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |       ]); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should list lazyRoutes given an entryRoute even with static errors', () => { | 
					
						
							|  |  |  |       testSupport.writeFiles({ | 
					
						
							|  |  |  |         'src/main.ts': `
 | 
					
						
							|  |  |  |           import {NgModule, Component} from '@angular/core'; | 
					
						
							|  |  |  |           import {RouterModule} from '@angular/router'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           @Component({ | 
					
						
							|  |  |  |             selector: 'url-comp', | 
					
						
							|  |  |  |             // Non existent external template
 | 
					
						
							|  |  |  |             templateUrl: 'non-existent.html', | 
					
						
							|  |  |  |           }) | 
					
						
							|  |  |  |           export class ErrorComp {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           @Component({ | 
					
						
							|  |  |  |             selector: 'err-comp', | 
					
						
							|  |  |  |             // Error in template
 | 
					
						
							|  |  |  |             template: '<input/>{{', | 
					
						
							|  |  |  |           }) | 
					
						
							|  |  |  |           export class ErrorComp2 {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           // Component with metadata errors.
 | 
					
						
							|  |  |  |           @Component(() => {if (1==1) return null as any;}) | 
					
						
							|  |  |  |           export class ErrorComp3 {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           // Unused component
 | 
					
						
							|  |  |  |           @Component({ | 
					
						
							|  |  |  |             selector: 'unused-comp', | 
					
						
							|  |  |  |             template: '' | 
					
						
							|  |  |  |           }) | 
					
						
							|  |  |  |           export class UnusedComp {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           @NgModule({ | 
					
						
							|  |  |  |             declarations: [ErrorComp, ErrorComp2, ErrorComp3, NonExistentComp], | 
					
						
							|  |  |  |             imports: [RouterModule.forRoot([{loadChildren: './child#ChildModule'}])] | 
					
						
							|  |  |  |           }) | 
					
						
							|  |  |  |           export class MainModule {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           @NgModule({ | 
					
						
							|  |  |  |             // Component used in 2 NgModules
 | 
					
						
							|  |  |  |             declarations: [ErrorComp], | 
					
						
							|  |  |  |           }) | 
					
						
							|  |  |  |           export class Mod2 {} | 
					
						
							|  |  |  |         `,
 | 
					
						
							|  |  |  |         'src/child.ts': `
 | 
					
						
							|  |  |  |           import {NgModule} from '@angular/core'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           @NgModule() | 
					
						
							|  |  |  |           export class ChildModule {} | 
					
						
							|  |  |  |         `,
 | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-10-24 12:52:14 -07:00
										 |  |  |       const program = createProgram(['src/main.ts'], {collectAllErrors: true}).program; | 
					
						
							| 
									
										
										
										
											2017-10-20 09:46:41 -07:00
										 |  |  |       expect(normalizeRoutes(program.listLazyRoutes('src/main#MainModule'))).toEqual([{ | 
					
						
							|  |  |  |         module: {name: 'MainModule', filePath: path.resolve(testSupport.basePath, 'src/main.ts')}, | 
					
						
							|  |  |  |         referencedModule: | 
					
						
							|  |  |  |             {name: 'ChildModule', filePath: path.resolve(testSupport.basePath, 'src/child.ts')}, | 
					
						
							|  |  |  |         route: './child#ChildModule' | 
					
						
							|  |  |  |       }]); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2017-10-26 09:45:01 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   it('should report errors for ts and ng errors on emit with noEmitOnError=true', () => { | 
					
						
							|  |  |  |     testSupport.writeFiles({ | 
					
						
							|  |  |  |       'src/main.ts': `
 | 
					
						
							|  |  |  |         import {Component, NgModule} from '@angular/core'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Ts error
 | 
					
						
							|  |  |  |         let x: string = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Ng error
 | 
					
						
							|  |  |  |         @Component({selector: 'comp', templateUrl: './main.html'}) | 
					
						
							|  |  |  |         export class MyComp {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         @NgModule({declarations: [MyComp]}) | 
					
						
							|  |  |  |         export class MyModule {} | 
					
						
							|  |  |  |         `,
 | 
					
						
							|  |  |  |       'src/main.html': '{{nonExistent}}' | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     const options = testSupport.createCompilerOptions({noEmitOnError: true}); | 
					
						
							|  |  |  |     const host = ng.createCompilerHost({options}); | 
					
						
							|  |  |  |     const program1 = ng.createProgram( | 
					
						
							|  |  |  |         {rootNames: [path.resolve(testSupport.basePath, 'src/main.ts')], options, host}); | 
					
						
							|  |  |  |     const errorDiags = | 
					
						
							|  |  |  |         program1.emit().diagnostics.filter(d => d.category === ts.DiagnosticCategory.Error); | 
					
						
							|  |  |  |     expect(formatDiagnostics(errorDiags)) | 
					
						
							|  |  |  |         .toContain(`src/main.ts(5,13): error TS2322: Type '1' is not assignable to type 'string'.`); | 
					
						
							|  |  |  |     expect(formatDiagnostics(errorDiags)) | 
					
						
							|  |  |  |         .toContain( | 
					
						
							|  |  |  |             `src/main.html(1,1): error TS100: Property 'nonExistent' does not exist on type 'MyComp'.`); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2017-10-26 15:24:54 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-02 14:49:38 -07:00
										 |  |  |   it('should not report emit errors with noEmitOnError=false', () => { | 
					
						
							|  |  |  |     testSupport.writeFiles({ | 
					
						
							|  |  |  |       'src/main.ts': `
 | 
					
						
							|  |  |  |         @NgModule() | 
					
						
							|  |  |  |       `
 | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     const options = testSupport.createCompilerOptions({noEmitOnError: false}); | 
					
						
							|  |  |  |     const host = ng.createCompilerHost({options}); | 
					
						
							|  |  |  |     const program1 = ng.createProgram( | 
					
						
							|  |  |  |         {rootNames: [path.resolve(testSupport.basePath, 'src/main.ts')], options, host}); | 
					
						
							|  |  |  |     expect(program1.emit().diagnostics.length).toBe(0); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-26 15:24:54 -07:00
										 |  |  |   describe('errors', () => { | 
					
						
							|  |  |  |     const fileWithStructuralError = `
 | 
					
						
							|  |  |  |       import {NgModule} from '@angular/core'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @NgModule(() => (1===1 ? null as any : null as any)) | 
					
						
							|  |  |  |       export class MyModule {} | 
					
						
							|  |  |  |     `;
 | 
					
						
							|  |  |  |     const fileWithGoodContent = `
 | 
					
						
							|  |  |  |       import {NgModule} from '@angular/core'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @NgModule() | 
					
						
							|  |  |  |       export class MyModule {} | 
					
						
							|  |  |  |     `;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should not throw on structural errors but collect them', () => { | 
					
						
							|  |  |  |       testSupport.write('src/index.ts', fileWithStructuralError); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const options = testSupport.createCompilerOptions(); | 
					
						
							|  |  |  |       const host = ng.createCompilerHost({options}); | 
					
						
							|  |  |  |       const program = ng.createProgram( | 
					
						
							|  |  |  |           {rootNames: [path.resolve(testSupport.basePath, 'src/index.ts')], options, host}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const structuralErrors = program.getNgStructuralDiagnostics(); | 
					
						
							|  |  |  |       expect(structuralErrors.length).toBe(1); | 
					
						
							| 
									
										
										
										
											2017-11-14 17:49:47 -08:00
										 |  |  |       expect(structuralErrors[0].messageText).toContain('Function expressions are not supported'); | 
					
						
							| 
									
										
										
										
											2017-10-26 15:24:54 -07:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should not throw on structural errors but collect them (loadNgStructureAsync)', (done) => { | 
					
						
							|  |  |  |       testSupport.write('src/index.ts', fileWithStructuralError); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const options = testSupport.createCompilerOptions(); | 
					
						
							|  |  |  |       const host = ng.createCompilerHost({options}); | 
					
						
							|  |  |  |       const program = ng.createProgram( | 
					
						
							|  |  |  |           {rootNames: [path.resolve(testSupport.basePath, 'src/index.ts')], options, host}); | 
					
						
							|  |  |  |       program.loadNgStructureAsync().then(() => { | 
					
						
							|  |  |  |         const structuralErrors = program.getNgStructuralDiagnostics(); | 
					
						
							|  |  |  |         expect(structuralErrors.length).toBe(1); | 
					
						
							| 
									
										
										
										
											2017-11-14 17:49:47 -08:00
										 |  |  |         expect(structuralErrors[0].messageText).toContain('Function expressions are not supported'); | 
					
						
							| 
									
										
										
										
											2017-10-26 15:24:54 -07:00
										 |  |  |         done(); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-06 15:27:23 -08:00
										 |  |  |     it('should include non-formatted errors (e.g. invalid templateUrl)', () => { | 
					
						
							|  |  |  |       testSupport.write('src/index.ts', `
 | 
					
						
							|  |  |  |         import {Component, NgModule} from '@angular/core'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         @Component({ | 
					
						
							|  |  |  |           selector: 'my-component', | 
					
						
							|  |  |  |           templateUrl: 'template.html',   // invalid template url
 | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |         export class MyComponent {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         @NgModule({ | 
					
						
							|  |  |  |           declarations: [MyComponent] | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |         export class MyModule {} | 
					
						
							|  |  |  |       `);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const options = testSupport.createCompilerOptions(); | 
					
						
							|  |  |  |       const host = ng.createCompilerHost({options}); | 
					
						
							|  |  |  |       const program = ng.createProgram({ | 
					
						
							|  |  |  |         rootNames: [path.resolve(testSupport.basePath, 'src/index.ts')], | 
					
						
							|  |  |  |         options, | 
					
						
							|  |  |  |         host, | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const structuralErrors = program.getNgStructuralDiagnostics(); | 
					
						
							|  |  |  |       expect(structuralErrors.length).toBe(1); | 
					
						
							|  |  |  |       expect(structuralErrors[0].messageText).toContain('Couldn\'t resolve resource template.html'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-30 16:03:22 -07:00
										 |  |  |     it('should be able report structural errors with noResolve:true and generateCodeForLibraries:false ' + | 
					
						
							|  |  |  |            'even if getSourceFile throws for non existent files', | 
					
						
							|  |  |  |        () => { | 
					
						
							|  |  |  |          testSupport.write('src/index.ts', fileWithGoodContent); | 
					
						
							| 
									
										
										
										
											2017-10-26 15:24:54 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-30 16:03:22 -07:00
										 |  |  |          // compile angular and produce .ngsummary.json / ngfactory.d.ts files
 | 
					
						
							|  |  |  |          compile(); | 
					
						
							| 
									
										
										
										
											2017-10-26 15:24:54 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-30 16:03:22 -07:00
										 |  |  |          testSupport.write('src/ok.ts', fileWithGoodContent); | 
					
						
							|  |  |  |          testSupport.write('src/error.ts', fileWithStructuralError); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          // Make sure the ok.ts file is before the error.ts file,
 | 
					
						
							|  |  |  |          // so we added a .ngfactory.ts file for it.
 | 
					
						
							|  |  |  |          const allRootNames = resolveFiles( | 
					
						
							|  |  |  |              ['src/ok.ts', 'src/error.ts'].map(fn => path.resolve(testSupport.basePath, fn))); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          const options = testSupport.createCompilerOptions({ | 
					
						
							|  |  |  |            noResolve: true, | 
					
						
							|  |  |  |            generateCodeForLibraries: false, | 
					
						
							|  |  |  |          }); | 
					
						
							|  |  |  |          const host = ng.createCompilerHost({options}); | 
					
						
							|  |  |  |          const originalGetSourceFile = host.getSourceFile; | 
					
						
							|  |  |  |          host.getSourceFile = | 
					
						
							|  |  |  |              (fileName: string, languageVersion: ts.ScriptTarget, | 
					
						
							|  |  |  |               onError?: ((message: string) => void) | undefined): ts.SourceFile => { | 
					
						
							|  |  |  |                // We should never try to load .ngfactory.ts files
 | 
					
						
							|  |  |  |                if (fileName.match(/\.ngfactory\.ts$/)) { | 
					
						
							|  |  |  |                  throw new Error(`Non existent ngfactory file: ` + fileName); | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |                return originalGetSourceFile.call(host, fileName, languageVersion, onError); | 
					
						
							|  |  |  |              }; | 
					
						
							|  |  |  |          const program = ng.createProgram({rootNames: allRootNames, options, host}); | 
					
						
							|  |  |  |          const structuralErrors = program.getNgStructuralDiagnostics(); | 
					
						
							|  |  |  |          expect(structuralErrors.length).toBe(1); | 
					
						
							| 
									
										
										
										
											2017-11-14 17:49:47 -08:00
										 |  |  |          expect(structuralErrors[0].messageText) | 
					
						
							|  |  |  |              .toContain('Function expressions are not supported'); | 
					
						
							| 
									
										
										
										
											2017-10-30 16:03:22 -07:00
										 |  |  |        }); | 
					
						
							| 
									
										
										
										
											2017-10-26 15:24:54 -07:00
										 |  |  |   }); | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  | }); |