refactor: move angular source to /packages rather than modules/@angular

This commit is contained in:
Jason Aden
2017-03-02 10:48:42 -08:00
parent 5ad5301a3e
commit 3e51a19983
1051 changed files with 18 additions and 18 deletions

View File

@ -0,0 +1,16 @@
/**
* @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 './init';
import './animate_spec';
import './basic_spec';
import './entry_components_spec';
import './i18n_spec';
import './ng_module_spec';
import './projection_spec';
import './query_spec';

View File

@ -0,0 +1,72 @@
/**
* @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 './init';
import {DebugElement} from '@angular/core';
import {AnimateCmp} from '../src/animate';
import {createComponent} from './util';
// TODO(matsko): make this green again...
xdescribe('template codegen output', () => {
function findTargetElement(elm: DebugElement): DebugElement {
// the open-close-container is a child of the main container
// if the template changes then please update the location below
return elm.children[4];
}
it('should apply the animate states to the element', (done) => {
const compFixture = createComponent(AnimateCmp);
const debugElement = compFixture.debugElement;
const targetDebugElement = findTargetElement(<DebugElement>debugElement);
compFixture.componentInstance.setAsOpen();
compFixture.detectChanges();
setTimeout(() => {
expect(targetDebugElement.styles['height']).toEqual(null);
expect(targetDebugElement.styles['borderColor']).toEqual('green');
expect(targetDebugElement.styles['color']).toEqual('green');
compFixture.componentInstance.setAsClosed();
compFixture.detectChanges();
setTimeout(() => {
expect(targetDebugElement.styles['height']).toEqual('0px');
expect(targetDebugElement.styles['borderColor']).toEqual('maroon');
expect(targetDebugElement.styles['color']).toEqual('maroon');
done();
}, 0);
}, 0);
});
it('should apply the default animate state to the element', (done) => {
const compFixture = createComponent(AnimateCmp);
const debugElement = compFixture.debugElement;
const targetDebugElement = findTargetElement(<DebugElement>debugElement);
compFixture.componentInstance.setAsSomethingElse();
compFixture.detectChanges();
setTimeout(() => {
expect(targetDebugElement.styles['height']).toEqual(null);
expect(targetDebugElement.styles['borderColor']).toEqual('black');
expect(targetDebugElement.styles['color']).toEqual('black');
compFixture.componentInstance.setAsClosed();
compFixture.detectChanges();
setTimeout(() => {
expect(targetDebugElement.styles['height']).not.toEqual(null);
expect(targetDebugElement.styles['borderColor']).not.toEqual('grey');
expect(targetDebugElement.styles['color']).not.toEqual('grey');
done();
}, 0);
}, 0);
});
});

View File

@ -0,0 +1,92 @@
/**
* @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 './init';
import * as fs from 'fs';
import * as path from 'path';
import {MultipleComponentsMyComp} from '../src/a/multiple_components';
import {BasicComp} from '../src/basic';
import {createComponent} from './util';
describe('template codegen output', () => {
const outDir = 'src';
it('should lower Decorators without reflect-metadata', () => {
const jsOutput = path.join(outDir, 'basic.js');
expect(fs.existsSync(jsOutput)).toBeTruthy();
expect(fs.readFileSync(jsOutput, {encoding: 'utf-8'})).not.toContain('Reflect.decorate');
});
it('should produce metadata.json outputs', () => {
const metadataOutput = path.join(outDir, 'basic.metadata.json');
expect(fs.existsSync(metadataOutput)).toBeTruthy();
const output = fs.readFileSync(metadataOutput, {encoding: 'utf-8'});
expect(output).toContain('"decorators":');
expect(output).toContain('"module":"@angular/core","name":"Component"');
});
it('should write .d.ts files', () => {
const dtsOutput = path.join(outDir, 'basic.d.ts');
expect(fs.existsSync(dtsOutput)).toBeTruthy();
expect(fs.readFileSync(dtsOutput, {encoding: 'utf-8'})).toContain('Basic');
});
it('should write .ngfactory.ts for .d.ts inputs', () => {
const factoryOutput =
path.join('node_modules', '@angular2-material', 'button', 'button.ngfactory.ts');
expect(fs.existsSync(factoryOutput)).toBeTruthy();
});
it('should be able to create the basic component', () => {
const compFixture = createComponent(BasicComp);
expect(compFixture.componentInstance).toBeTruthy();
});
it('should support ngIf', () => {
const compFixture = createComponent(BasicComp);
const debugElement = compFixture.debugElement;
expect(debugElement.children.length).toBe(3);
compFixture.componentInstance.ctxBool = true;
compFixture.detectChanges();
expect(debugElement.children.length).toBe(4);
expect(debugElement.children[2].injector.get(MultipleComponentsMyComp)).toBeTruthy();
});
it('should support ngFor', () => {
const compFixture = createComponent(BasicComp);
const debugElement = compFixture.debugElement;
expect(debugElement.children.length).toBe(3);
// test NgFor
compFixture.componentInstance.ctxArr = [1, 2];
compFixture.detectChanges();
expect(debugElement.children.length).toBe(5);
expect(debugElement.children[2].attributes['value']).toBe('1');
expect(debugElement.children[3].attributes['value']).toBe('2');
});
describe('i18n', () => {
it('should inject the locale into the component', () => {
const compFixture = createComponent(BasicComp);
expect(compFixture.componentInstance.localeId).toEqual('fi');
});
it('should inject the translations format into the component', () => {
const compFixture = createComponent(BasicComp);
expect(compFixture.componentInstance.translationsFormat).toEqual('xlf');
});
it('should support i18n for content tags', () => {
const containerElement = createComponent(BasicComp).nativeElement;
const pElement = containerElement.children.find((c: any) => c.name == 'p');
const pText = pElement.children.map((c: any) => c.data).join('').trim();
expect(pText).toBe('tervetuloa');
});
});
});

View File

@ -0,0 +1,34 @@
/**
* @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 './init';
import {BasicComp} from '../src/basic';
import {CompWithAnalyzeEntryComponentsProvider, CompWithEntryComponents} from '../src/entry_components';
import {createComponent} from './util';
describe('content projection', () => {
it('should support entryComponents in components', () => {
const compFixture = createComponent(CompWithEntryComponents);
const cf = compFixture.componentInstance.cfr.resolveComponentFactory(BasicComp);
expect(cf.componentType).toBe(BasicComp);
});
it('should support entryComponents via the ANALYZE_FOR_ENTRY_COMPONENTS provider and function providers in components',
() => {
const compFixture = createComponent(CompWithAnalyzeEntryComponentsProvider);
const cf = compFixture.componentInstance.cfr.resolveComponentFactory(BasicComp);
expect(cf.componentType).toBe(BasicComp);
// check that the function call that created the provider for ANALYZE_FOR_ENTRY_COMPONENTS
// worked.
expect(compFixture.componentInstance.providedValue).toEqual([
{a: 'b', component: BasicComp}
]);
});
});

View File

@ -0,0 +1,88 @@
/**
* @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 './init';
import * as fs from 'fs';
import * as path from 'path';
const EXPECTED_XMB = `<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE messagebundle [
<!ELEMENT messagebundle (msg)*>
<!ATTLIST messagebundle class CDATA #IMPLIED>
<!ELEMENT msg (#PCDATA|ph|source)*>
<!ATTLIST msg id CDATA #IMPLIED>
<!ATTLIST msg seq CDATA #IMPLIED>
<!ATTLIST msg name CDATA #IMPLIED>
<!ATTLIST msg desc CDATA #IMPLIED>
<!ATTLIST msg meaning CDATA #IMPLIED>
<!ATTLIST msg obsolete (obsolete) #IMPLIED>
<!ATTLIST msg xml:space (default|preserve) "default">
<!ATTLIST msg is_hidden CDATA #IMPLIED>
<!ELEMENT source (#PCDATA)>
<!ELEMENT ph (#PCDATA|ex)*>
<!ATTLIST ph name CDATA #REQUIRED>
<!ELEMENT ex (#PCDATA)>
]>
<messagebundle>
<msg id="8136548302122759730" desc="desc" meaning="meaning">translate me</msg>
<msg id="3492007542396725315">Welcome</msg>
<msg id="3772663375917578720">other-3rdP-component</msg>
</messagebundle>
`;
const EXPECTED_XLIFF = `<?xml version="1.0" encoding="UTF-8" ?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file source-language="fr" datatype="plaintext" original="ng2.template">
<body>
<trans-unit id="76e1eccb1b772fa9f294ef9c146ea6d0efa8a2d4" datatype="html">
<source>translate me</source>
<target/>
<note priority="1" from="description">desc</note>
<note priority="1" from="meaning">meaning</note>
</trans-unit>
<trans-unit id="65cc4ab3b4c438e07c89be2b677d08369fb62da2" datatype="html">
<source>Welcome</source>
<target/>
</trans-unit>
<trans-unit id="63a85808f03b8181e36a952e0fa38202c2304862" datatype="html">
<source>other-3rdP-component</source>
<target/>
</trans-unit>
</body>
</file>
</xliff>
`;
describe('template i18n extraction output', () => {
const outDir = '';
const genDir = 'out';
it('should extract i18n messages as xmb', () => {
const xmbOutput = path.join(outDir, 'custom_file.xmb');
expect(fs.existsSync(xmbOutput)).toBeTruthy();
const xmb = fs.readFileSync(xmbOutput, {encoding: 'utf-8'});
expect(xmb).toEqual(EXPECTED_XMB);
});
it('should extract i18n messages as xliff', () => {
const xlfOutput = path.join(outDir, 'messages.xlf');
expect(fs.existsSync(xlfOutput)).toBeTruthy();
const xlf = fs.readFileSync(xlfOutput, {encoding: 'utf-8'});
expect(xlf).toEqual(EXPECTED_XLIFF);
});
it('should not emit js', () => {
const genOutput = path.join(genDir, '');
expect(fs.existsSync(genOutput)).toBeFalsy();
});
});

View File

@ -0,0 +1,17 @@
/**
* @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
*/
// Only needed to satisfy the check in core/src/util/decorators.ts
// TODO(alexeagle): maybe remove that check?
require('reflect-metadata');
require('zone.js/dist/zone-node.js');
require('zone.js/dist/long-stack-trace-zone.js');
require('zone.js/dist/sync-test.js');
require('zone.js/dist/proxy.js');
require('zone.js/dist/jasmine-patch.js');

View File

@ -0,0 +1,83 @@
/**
* @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 './init';
import {ComponentUsingThirdParty} from '../src/comp_using_3rdp';
import {MainModule} from '../src/module';
import {CompUsingLibModuleDirectiveAndPipe, CompUsingRootModuleDirectiveAndPipe, SOME_TOKEN, ServiceUsingLibModule, SomeLibModule, SomeService} from '../src/module_fixtures';
import {createComponent, createModule} from './util';
describe('NgModule', () => {
it('should support providers', () => {
const moduleRef = createModule();
expect(moduleRef.instance instanceof MainModule).toEqual(true);
expect(moduleRef.injector.get(MainModule) instanceof MainModule).toEqual(true);
expect(moduleRef.injector.get(SomeService) instanceof SomeService).toEqual(true);
});
it('should support entryComponents components', () => {
const moduleRef = createModule();
const cf = moduleRef.componentFactoryResolver.resolveComponentFactory(
CompUsingRootModuleDirectiveAndPipe);
expect(cf.componentType).toBe(CompUsingRootModuleDirectiveAndPipe);
const compRef = cf.create(moduleRef.injector);
expect(compRef.instance instanceof CompUsingRootModuleDirectiveAndPipe).toEqual(true);
});
it('should support entryComponents via the ANALYZE_FOR_ENTRY_COMPONENTS provider and function providers in components',
() => {
const moduleRef = createModule();
const cf = moduleRef.componentFactoryResolver.resolveComponentFactory(
CompUsingRootModuleDirectiveAndPipe);
expect(cf.componentType).toBe(CompUsingRootModuleDirectiveAndPipe);
// check that the function call that created the provider for ANALYZE_FOR_ENTRY_COMPONENTS
// worked.
expect(moduleRef.injector.get(SOME_TOKEN)).toEqual([
{a: 'b', component: CompUsingLibModuleDirectiveAndPipe}
]);
});
describe('third-party modules', () => {
// https://github.com/angular/angular/issues/11889
it('should support third party entryComponents components', () => {
const fixture = createComponent(ComponentUsingThirdParty);
const thirdPComps = fixture.nativeElement.children;
expect(thirdPComps[0].children[0].children[0].data).toEqual('3rdP-component');
expect(thirdPComps[1].children[0].children[0].data).toEqual('other-3rdP-component');
});
// https://github.com/angular/angular/issues/12428
it('should support third party directives', () => {
const fixture = createComponent(ComponentUsingThirdParty);
const debugElement = fixture.debugElement;
fixture.detectChanges();
expect(debugElement.children[0].properties['title']).toEqual('from 3rd party');
});
});
it('should support module directives and pipes', () => {
const compFixture = createComponent(CompUsingRootModuleDirectiveAndPipe);
compFixture.detectChanges();
const debugElement = compFixture.debugElement;
expect(debugElement.children[0].properties['title']).toEqual('transformed someValue');
});
it('should support module directives and pipes on lib modules', () => {
const compFixture = createComponent(CompUsingLibModuleDirectiveAndPipe);
compFixture.detectChanges();
const debugElement = compFixture.debugElement;
expect(debugElement.children[0].properties['title']).toEqual('transformed someValue');
expect(debugElement.injector.get(SomeLibModule) instanceof SomeLibModule).toEqual(true);
expect(debugElement.injector.get(ServiceUsingLibModule) instanceof ServiceUsingLibModule)
.toEqual(true);
});
});

View File

@ -0,0 +1,23 @@
/**
* @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 './init';
import {By} from '@angular/platform-browser';
import {CompWithNgContent, ProjectingComp} from '../src/projection';
import {createComponent} from './util';
describe('content projection', () => {
it('should support basic content projection', () => {
const mainCompFixture = createComponent(ProjectingComp);
const debugElement = mainCompFixture.debugElement;
const compWithProjection = debugElement.query(By.directive(CompWithNgContent));
expect(compWithProjection.children.length).toBe(1);
expect(compWithProjection.children[0].attributes['greeting']).toEqual('Hello world!');
});
});

View File

@ -0,0 +1,35 @@
/**
* @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 './init';
import {DebugElement, QueryList} from '@angular/core';
import {By} from '@angular/platform-browser';
import {CompForChildQuery, CompWithChildQuery} from '../src/queries';
import {createComponent} from './util';
describe('child queries', () => {
it('should support compiling child queries', () => {
const childQueryCompFixture = createComponent(CompWithChildQuery);
const debugElement = childQueryCompFixture.debugElement;
const compWithChildren = debugElement.query(By.directive(CompWithChildQuery));
expect(childQueryCompFixture.componentInstance.child).toBeDefined();
expect(childQueryCompFixture.componentInstance.child instanceof CompForChildQuery).toBe(true);
});
it('should support compiling children queries', () => {
const childQueryCompFixture = createComponent(CompWithChildQuery);
const debugElement = childQueryCompFixture.debugElement;
const compWithChildren = debugElement.query(By.directive(CompWithChildQuery));
childQueryCompFixture.detectChanges();
expect(childQueryCompFixture.componentInstance.children).toBeDefined();
expect(childQueryCompFixture.componentInstance.children instanceof QueryList).toBe(true);
});
});

View File

@ -0,0 +1,219 @@
#!/usr/bin/env node
/**
* @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
*/
/* tslint:disable:no-console */
// Must be imported first, because angular2 decorators throws on load.
import 'reflect-metadata';
import * as path from 'path';
import * as ts from 'typescript';
import * as assert from 'assert';
import {tsc} from '@angular/tsc-wrapped/src/tsc';
import {AngularCompilerOptions, CodeGenerator, CompilerHostContext, NodeCompilerHostContext, __NGTOOLS_PRIVATE_API_2} from '@angular/compiler-cli';
const glob = require('glob');
/**
* Main method.
* Standalone program that executes codegen using the ngtools API and tests that files were
* properly read and wrote.
*/
function main() {
console.log(`testing ngtools API...`);
Promise.resolve()
.then(() => codeGenTest())
.then(() => i18nTest())
.then(() => lazyRoutesTest())
.then(() => {
console.log('All done!');
process.exit(0);
})
.catch((err) => {
console.error(err.stack);
console.error('Test failed');
process.exit(1);
});
}
function codeGenTest() {
const basePath = path.join(__dirname, '../ngtools_src');
const project = path.join(basePath, 'tsconfig-build.json');
const readResources: string[] = [];
const wroteFiles: string[] = [];
const config = tsc.readConfiguration(project, basePath);
const hostContext = new NodeCompilerHostContext();
const delegateHost = ts.createCompilerHost(config.parsed.options, true);
const host: ts.CompilerHost = Object.assign(
{}, delegateHost,
{writeFile: (fileName: string, ...rest: any[]) => { wroteFiles.push(fileName); }});
const program = ts.createProgram(config.parsed.fileNames, config.parsed.options, host);
config.ngOptions.basePath = basePath;
console.log(`>>> running codegen for ${project}`);
return __NGTOOLS_PRIVATE_API_2
.codeGen({
basePath,
compilerOptions: config.parsed.options, program, host,
angularCompilerOptions: config.ngOptions,
// i18n options.
i18nFormat: null,
i18nFile: null,
locale: null,
readResource: (fileName: string) => {
readResources.push(fileName);
return hostContext.readResource(fileName);
}
})
.then(() => {
console.log(`>>> codegen done, asserting read and wrote files`);
// Assert for each file that it has been read and each `ts` has a written file associated.
const allFiles = glob.sync(path.join(basePath, '**/*'), {nodir: true});
allFiles.forEach((fileName: string) => {
// Skip tsconfig.
if (fileName.match(/tsconfig-build.json$/)) {
return;
}
// Assert that file was read.
if (fileName.match(/\.module\.ts$/)) {
const factory = fileName.replace(/\.module\.ts$/, '.module.ngfactory.ts');
assert(wroteFiles.indexOf(factory) != -1, `Expected file "${factory}" to be written.`);
} else if (fileName.match(/\.css$/) || fileName.match(/\.html$/)) {
assert(
readResources.indexOf(fileName) != -1,
`Expected resource "${fileName}" to be read.`);
}
});
console.log(`done, no errors.`);
})
.catch((e: any) => {
console.error(e.stack);
console.error('Compilation failed');
throw e;
});
}
function i18nTest() {
const basePath = path.join(__dirname, '../ngtools_src');
const project = path.join(basePath, 'tsconfig-build.json');
const readResources: string[] = [];
const wroteFiles: string[] = [];
const config = tsc.readConfiguration(project, basePath);
const hostContext = new NodeCompilerHostContext();
const delegateHost = ts.createCompilerHost(config.parsed.options, true);
const host: ts.CompilerHost = Object.assign(
{}, delegateHost,
{writeFile: (fileName: string, ...rest: any[]) => { wroteFiles.push(fileName); }});
const program = ts.createProgram(config.parsed.fileNames, config.parsed.options, host);
config.ngOptions.basePath = basePath;
console.log(`>>> running i18n extraction for ${project}`);
return __NGTOOLS_PRIVATE_API_2
.extractI18n({
basePath,
compilerOptions: config.parsed.options, program, host,
angularCompilerOptions: config.ngOptions,
i18nFormat: 'xlf',
locale: null,
outFile: null,
readResource: (fileName: string) => {
readResources.push(fileName);
return hostContext.readResource(fileName);
},
})
.then(() => {
console.log(`>>> i18n extraction done, asserting read and wrote files`);
const allFiles = glob.sync(path.join(basePath, '**/*'), {nodir: true});
assert(wroteFiles.length == 1, `Expected a single message bundle file.`);
assert(
wroteFiles[0].endsWith('/ngtools_src/messages.xlf'),
`Expected the bundle file to be "message.xlf".`);
allFiles.forEach((fileName: string) => {
// Skip tsconfig.
if (fileName.match(/tsconfig-build.json$/)) {
return;
}
// Assert that file was read.
if (fileName.match(/\.css$/) || fileName.match(/\.html$/)) {
assert(
readResources.indexOf(fileName) != -1,
`Expected resource "${fileName}" to be read.`);
}
});
console.log(`done, no errors.`);
})
.catch((e: any) => {
console.error(e.stack);
console.error('Extraction failed');
throw e;
});
}
function lazyRoutesTest() {
const basePath = path.join(__dirname, '../ngtools_src');
const project = path.join(basePath, 'tsconfig-build.json');
const config = tsc.readConfiguration(project, basePath);
const host = ts.createCompilerHost(config.parsed.options, true);
const program = ts.createProgram(config.parsed.fileNames, config.parsed.options, host);
config.ngOptions.basePath = basePath;
const lazyRoutes = __NGTOOLS_PRIVATE_API_2.listLazyRoutes({
program,
host,
angularCompilerOptions: config.ngOptions,
entryModule: 'app.module#AppModule'
});
const expectations: {[route: string]: string} = {
'./lazy.module#LazyModule': 'lazy.module.ts',
'./feature/feature.module#FeatureModule': 'feature/feature.module.ts',
'./feature/lazy-feature.module#LazyFeatureModule': 'feature/lazy-feature.module.ts',
'./feature.module#FeatureModule': 'feature/feature.module.ts',
'./lazy-feature-nested.module#LazyFeatureNestedModule': 'feature/lazy-feature-nested.module.ts',
'feature2/feature2.module#Feature2Module': 'feature2/feature2.module.ts',
'./default.module': 'feature2/default.module.ts',
'feature/feature.module#FeatureModule': 'feature/feature.module.ts'
};
Object.keys(lazyRoutes).forEach((route: string) => {
assert(route in expectations, `Found a route that was not expected: "${route}".`);
assert(
lazyRoutes[route] == path.join(basePath, expectations[route]),
`Route "${route}" does not point to the expected absolute path ` +
`"${path.join(basePath, expectations[route])}". It points to "${lazyRoutes[route]}"`);
});
// Verify that all expectations were met.
assert.deepEqual(
Object.keys(lazyRoutes), Object.keys(expectations), `Expected routes listed to be: \n` +
` ${JSON.stringify(Object.keys(expectations))}\n` +
`Actual:\n` +
` ${JSON.stringify(Object.keys(lazyRoutes))}\n`);
}
main();

View File

@ -0,0 +1,126 @@
#!/usr/bin/env node
/**
* @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
*/
/* tslint:disable:no-console */
// Must be imported first, because angular2 decorators throws on load.
import 'reflect-metadata';
import * as path from 'path';
import * as ts from 'typescript';
import * as assert from 'assert';
import {tsc} from '@angular/tsc-wrapped/src/tsc';
import {AngularCompilerOptions, CodeGenerator, CompilerHostContext, NodeCompilerHostContext} from '@angular/compiler-cli';
/**
* Main method.
* Standalone program that executes the real codegen and tests that
* ngsummary.json files are used for libraries.
*/
function main() {
console.log(`testing usage of ngsummary.json files in libraries...`);
const basePath = path.resolve(__dirname, '..');
const project = path.resolve(basePath, 'tsconfig-build.json');
const readFiles: string[] = [];
const writtenFiles: {fileName: string, content: string}[] = [];
class AssertingHostContext extends NodeCompilerHostContext {
readFile(fileName: string): string {
if (/.*\/node_modules\/.*/.test(fileName) && !/.*ngsummary\.json$/.test(fileName) &&
!/package\.json$/.test(fileName)) {
// Only allow to read summaries and package.json files from node_modules
return null;
}
readFiles.push(path.relative(basePath, fileName));
return super.readFile(fileName);
}
readResource(s: string): Promise<string> {
readFiles.push(path.relative(basePath, s));
return super.readResource(s);
}
}
const config = tsc.readConfiguration(project, basePath);
config.ngOptions.basePath = basePath;
// This flag tells ngc do not recompile libraries.
config.ngOptions.generateCodeForLibraries = false;
console.log(`>>> running codegen for ${project}`);
codegen(
config,
(host) => {
host.writeFile = (fileName: string, content: string) => {
fileName = path.relative(basePath, fileName);
writtenFiles.push({fileName, content});
};
return new AssertingHostContext();
})
.then((exitCode: any) => {
console.log(`>>> codegen done, asserting read files`);
assertSomeFileMatch(readFiles, /^node_modules\/.*\.ngsummary\.json$/);
assertNoFileMatch(readFiles, /^node_modules\/.*\.metadata.json$/);
assertNoFileMatch(readFiles, /^node_modules\/.*\.html$/);
assertNoFileMatch(readFiles, /^node_modules\/.*\.css$/);
assertNoFileMatch(readFiles, /^src\/.*\.ngsummary\.json$/);
assertSomeFileMatch(readFiles, /^src\/.*\.html$/);
assertSomeFileMatch(readFiles, /^src\/.*\.css$/);
console.log(`>>> asserting written files`);
assertWrittenFile(writtenFiles, /^src\/module\.ngfactory\.ts$/, /class MainModuleInjector/);
console.log(`done, no errors.`);
process.exit(exitCode);
})
.catch((e: any) => {
console.error(e.stack);
console.error('Compilation failed');
process.exit(1);
});
}
/**
* Simple adaption of tsc-wrapped main to just run codegen with a CompilerHostContext
*/
function codegen(
config: {parsed: ts.ParsedCommandLine, ngOptions: AngularCompilerOptions},
hostContextFactory: (host: ts.CompilerHost) => CompilerHostContext) {
const host = ts.createCompilerHost(config.parsed.options, true);
// HACK: patch the realpath to solve symlink issue here:
// https://github.com/Microsoft/TypeScript/issues/9552
// todo(misko): remove once facade symlinks are removed
host.realpath = (path) => path;
const program = ts.createProgram(config.parsed.fileNames, config.parsed.options, host);
return CodeGenerator.create(config.ngOptions, {
} as any, program, host, hostContextFactory(host)).codegen();
}
function assertSomeFileMatch(fileNames: string[], pattern: RegExp) {
assert(
fileNames.some(fileName => pattern.test(fileName)),
`Expected some read files match ${pattern}`);
}
function assertNoFileMatch(fileNames: string[], pattern: RegExp) {
const matches = fileNames.filter(fileName => pattern.test(fileName));
assert(
matches.length === 0,
`Expected no read files match ${pattern}, but found: \n${matches.join('\n')}`);
}
function assertWrittenFile(
files: {fileName: string, content: string}[], filePattern: RegExp, contentPattern: RegExp) {
assert(
files.some(file => filePattern.test(file.fileName) && contentPattern.test(file.content)),
`Expected some written files for ${filePattern} and content ${contentPattern}`);
}
main();

View File

@ -0,0 +1,33 @@
/**
* @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 {NgModuleFactory, NgModuleRef} from '@angular/core';
import {ComponentFixture} from '@angular/core/testing';
import {platformServer} from '@angular/platform-server';
import {MainModule} from '../src/module';
import {MainModuleNgFactory} from '../src/module.ngfactory';
let mainModuleRef: NgModuleRef<MainModule> = null;
beforeEach((done) => {
platformServer().bootstrapModuleFactory(MainModuleNgFactory).then((moduleRef: any) => {
mainModuleRef = moduleRef;
done();
});
});
export function createModule(): NgModuleRef<MainModule> {
return mainModuleRef;
}
export function createComponent<C>(comp: {new (...args: any[]): C}): ComponentFixture<C> {
const moduleRef = createModule();
const compRef =
moduleRef.componentFactoryResolver.resolveComponentFactory(comp).create(moduleRef.injector);
return new ComponentFixture(compRef, null, null);
}