refactor(compiler): split compiler and core (#18683)

After this, neither @angular/compiler nor @angular/comnpiler-cli depend
on @angular/core.

This add a duplication of some interfaces and enums which is stored
in @angular/compiler/src/core.ts

BREAKING CHANGE:
- `@angular/platform-server` now additionally depends on
  `@angular/platform-browser-dynamic` as a peer dependency.


PR Close #18683
This commit is contained in:
Tobias Bosch
2017-08-16 09:00:03 -07:00
committed by Miško Hevery
parent a0ca01d580
commit 0cc77b4a69
107 changed files with 1504 additions and 1564 deletions

View File

@ -0,0 +1,106 @@
/**
* @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 {CompileReflector, DirectiveResolver, ERROR_COMPONENT_TYPE, NgModuleResolver, PipeResolver} from '@angular/compiler';
import {MockDirectiveResolver, MockNgModuleResolver, MockPipeResolver} from '@angular/compiler/testing';
import {Compiler, CompilerFactory, CompilerOptions, Component, ComponentFactory, Directive, Injectable, Injector, ModuleWithComponentFactories, NgModule, NgModuleFactory, Pipe, PlatformRef, StaticProvider, Type, createPlatformFactory, ɵstringify} from '@angular/core';
import {MetadataOverride, ɵTestingCompiler as TestingCompiler, ɵTestingCompilerFactory as TestingCompilerFactory} from '@angular/core/testing';
import {ɵCompilerImpl as CompilerImpl, ɵplatformCoreDynamic as platformCoreDynamic} from '@angular/platform-browser-dynamic';
import {MetadataOverrider} from './metadata_overrider';
export const COMPILER_PROVIDERS: StaticProvider[] = [
{provide: MockPipeResolver, deps: [CompileReflector]},
{provide: PipeResolver, useExisting: MockPipeResolver},
{provide: MockDirectiveResolver, deps: [CompileReflector]},
{provide: DirectiveResolver, useExisting: MockDirectiveResolver},
{provide: MockNgModuleResolver, deps: [CompileReflector]},
{provide: NgModuleResolver, useExisting: MockNgModuleResolver},
];
export class TestingCompilerFactoryImpl implements TestingCompilerFactory {
constructor(private _injector: Injector, private _compilerFactory: CompilerFactory) {}
createTestingCompiler(options: CompilerOptions[]): TestingCompiler {
const compiler = <CompilerImpl>this._compilerFactory.createCompiler(options);
return new TestingCompilerImpl(
compiler, compiler.injector.get(MockDirectiveResolver),
compiler.injector.get(MockPipeResolver), compiler.injector.get(MockNgModuleResolver));
}
}
export class TestingCompilerImpl implements TestingCompiler {
private _overrider = new MetadataOverrider();
constructor(
private _compiler: CompilerImpl, private _directiveResolver: MockDirectiveResolver,
private _pipeResolver: MockPipeResolver, private _moduleResolver: MockNgModuleResolver) {}
get injector(): Injector { return this._compiler.injector; }
compileModuleSync<T>(moduleType: Type<T>): NgModuleFactory<T> {
return this._compiler.compileModuleSync(moduleType);
}
compileModuleAsync<T>(moduleType: Type<T>): Promise<NgModuleFactory<T>> {
return this._compiler.compileModuleAsync(moduleType);
}
compileModuleAndAllComponentsSync<T>(moduleType: Type<T>): ModuleWithComponentFactories<T> {
return this._compiler.compileModuleAndAllComponentsSync(moduleType);
}
compileModuleAndAllComponentsAsync<T>(moduleType: Type<T>):
Promise<ModuleWithComponentFactories<T>> {
return this._compiler.compileModuleAndAllComponentsAsync(moduleType);
}
getNgContentSelectors(component: Type<any>): string[] {
return this._compiler.getNgContentSelectors(component);
}
getComponentFactory<T>(component: Type<T>): ComponentFactory<T> {
return this._compiler.getComponentFactory(component);
}
checkOverrideAllowed(type: Type<any>) {
if (this._compiler.hasAotSummary(type)) {
throw new Error(`${ɵstringify(type)} was AOT compiled, so its metadata cannot be changed.`);
}
}
overrideModule(ngModule: Type<any>, override: MetadataOverride<NgModule>): void {
this.checkOverrideAllowed(ngModule);
const oldMetadata = this._moduleResolver.resolve(ngModule, false);
this._moduleResolver.setNgModule(
ngModule, this._overrider.overrideMetadata(NgModule, oldMetadata, override));
this.clearCacheFor(ngModule);
}
overrideDirective(directive: Type<any>, override: MetadataOverride<Directive>): void {
this.checkOverrideAllowed(directive);
const oldMetadata = this._directiveResolver.resolve(directive, false);
this._directiveResolver.setDirective(
directive, this._overrider.overrideMetadata(Directive, oldMetadata !, override));
this.clearCacheFor(directive);
}
overrideComponent(component: Type<any>, override: MetadataOverride<Component>): void {
this.checkOverrideAllowed(component);
const oldMetadata = this._directiveResolver.resolve(component, false);
this._directiveResolver.setDirective(
component, this._overrider.overrideMetadata(Component, oldMetadata !, override));
this.clearCacheFor(component);
}
overridePipe(pipe: Type<any>, override: MetadataOverride<Pipe>): void {
this.checkOverrideAllowed(pipe);
const oldMetadata = this._pipeResolver.resolve(pipe, false);
this._pipeResolver.setPipe(pipe, this._overrider.overrideMetadata(Pipe, oldMetadata, override));
this.clearCacheFor(pipe);
}
loadAotSummaries(summaries: () => any[]) { this._compiler.loadAotSummaries(summaries); }
clearCache(): void { this._compiler.clearCache(); }
clearCacheFor(type: Type<any>) { this._compiler.clearCacheFor(type); }
getComponentFromError(error: Error) { return (error as any)[ERROR_COMPONENT_TYPE] || null; }
}

View File

@ -0,0 +1,131 @@
/**
* @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 {ɵstringify as stringify} from '@angular/core';
import {MetadataOverride} from '@angular/core/testing';
type StringMap = {
[key: string]: any
};
let _nextReferenceId = 0;
export class MetadataOverrider {
private _references = new Map<any, string>();
/**
* Creates a new instance for the given metadata class
* based on an old instance and overrides.
*/
overrideMetadata<C extends T, T>(
metadataClass: {new (options: T): C;}, oldMetadata: C, override: MetadataOverride<T>): C {
const props: StringMap = {};
if (oldMetadata) {
_valueProps(oldMetadata).forEach((prop) => props[prop] = (<any>oldMetadata)[prop]);
}
if (override.set) {
if (override.remove || override.add) {
throw new Error(`Cannot set and add/remove ${stringify(metadataClass)} at the same time!`);
}
setMetadata(props, override.set);
}
if (override.remove) {
removeMetadata(props, override.remove, this._references);
}
if (override.add) {
addMetadata(props, override.add);
}
return new metadataClass(<any>props);
}
}
function removeMetadata(metadata: StringMap, remove: any, references: Map<any, string>) {
const removeObjects = new Set<string>();
for (const prop in remove) {
const removeValue = remove[prop];
if (removeValue instanceof Array) {
removeValue.forEach(
(value: any) => { removeObjects.add(_propHashKey(prop, value, references)); });
} else {
removeObjects.add(_propHashKey(prop, removeValue, references));
}
}
for (const prop in metadata) {
const propValue = metadata[prop];
if (propValue instanceof Array) {
metadata[prop] = propValue.filter(
(value: any) => !removeObjects.has(_propHashKey(prop, value, references)));
} else {
if (removeObjects.has(_propHashKey(prop, propValue, references))) {
metadata[prop] = undefined;
}
}
}
}
function addMetadata(metadata: StringMap, add: any) {
for (const prop in add) {
const addValue = add[prop];
const propValue = metadata[prop];
if (propValue != null && propValue instanceof Array) {
metadata[prop] = propValue.concat(addValue);
} else {
metadata[prop] = addValue;
}
}
}
function setMetadata(metadata: StringMap, set: any) {
for (const prop in set) {
metadata[prop] = set[prop];
}
}
function _propHashKey(propName: any, propValue: any, references: Map<any, string>): string {
const replacer = (key: any, value: any) => {
if (typeof value === 'function') {
value = _serializeReference(value, references);
}
return value;
};
return `${propName}:${JSON.stringify(propValue, replacer)}`;
}
function _serializeReference(ref: any, references: Map<any, string>): string {
let id = references.get(ref);
if (!id) {
id = `${stringify(ref)}${_nextReferenceId++}`;
references.set(ref, id);
}
return id;
}
function _valueProps(obj: any): string[] {
const props: string[] = [];
// regular public props
Object.keys(obj).forEach((prop) => {
if (!prop.startsWith('_')) {
props.push(prop);
}
});
// getters
let proto = obj;
while (proto = Object.getPrototypeOf(proto)) {
Object.keys(proto).forEach((protoProp) => {
const desc = Object.getOwnPropertyDescriptor(proto, protoProp);
if (!protoProp.startsWith('_') && desc && 'get' in desc) {
props.push(protoProp);
}
});
}
return props;
}

View File

@ -0,0 +1,27 @@
/**
* @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 {COMPILER_OPTIONS, CompilerFactory, Injector, PlatformRef, StaticProvider, createPlatformFactory} from '@angular/core';
import {TestComponentRenderer, ɵTestingCompilerFactory as TestingCompilerFactory} from '@angular/core/testing';
import {ɵplatformCoreDynamic as platformCoreDynamic} from '@angular/platform-browser-dynamic';
import {COMPILER_PROVIDERS, TestingCompilerFactoryImpl} from './compiler_factory';
/**
* Platform for dynamic tests
*
* @experimental
*/
export const platformCoreDynamicTesting: (extraProviders?: any[]) => PlatformRef =
createPlatformFactory(platformCoreDynamic, 'coreDynamicTesting', [
{provide: COMPILER_OPTIONS, useValue: {providers: COMPILER_PROVIDERS}, multi: true}, {
provide: TestingCompilerFactory,
useClass: TestingCompilerFactoryImpl,
deps: [Injector, CompilerFactory]
}
]);

View File

@ -7,3 +7,4 @@
*/
export {DOMTestComponentRenderer as ɵDOMTestComponentRenderer} from './dom_test_component_renderer';
export {platformCoreDynamicTesting as ɵplatformCoreDynamicTesting} from './platform_core_dynamic_testing';

View File

@ -6,13 +6,13 @@
* found in the LICENSE file at https://angular.io/license
*/
import {platformCoreDynamicTesting} from '@angular/compiler/testing';
import {NgModule, PlatformRef, StaticProvider, createPlatformFactory} from '@angular/core';
import {TestComponentRenderer} from '@angular/core/testing';
import {ɵINTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS as INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS} from '@angular/platform-browser-dynamic';
import {BrowserTestingModule} from '@angular/platform-browser/testing';
import {DOMTestComponentRenderer} from './dom_test_component_renderer';
import {platformCoreDynamicTesting} from './platform_core_dynamic_testing';
export * from './private_export_testing'