From d042c4afe05e34a45de75fa0ec60d70279656c16 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Wed, 24 Oct 2018 16:02:25 -0700 Subject: [PATCH] fix(core): Remove static dependency from @angular/core to @angular/compiler (#26734) PR Close #26734 --- .../src/ngtsc/annotations/src/directive.ts | 9 +- packages/compiler/package.json | 4 +- packages/compiler/src/compiler.ts | 12 + .../compiler/src/compiler_facade_interface.ts | 145 +++++++++ packages/compiler/src/jit_compiler_facade.ts | 294 ++++++++++++++++++ .../src/render3/r3_module_compiler.ts | 1 - packages/compiler/src/render3/view/api.ts | 2 +- packages/compiler/src/render3/view/t2_api.ts | 2 +- packages/compiler/src/util.ts | 16 + .../test/compiler_facade_interface_spec.ts | 100 ++++++ packages/core/BUILD.bazel | 1 - packages/core/package.json | 3 +- packages/core/src/render3/di.ts | 1 + .../core/src/render3/jit/compiler_facade.ts | 22 ++ .../render3/jit/compiler_facade_interface.ts | 145 +++++++++ packages/core/src/render3/jit/directive.ts | 175 +++-------- packages/core/src/render3/jit/injectable.ts | 67 ++-- packages/core/src/render3/jit/module.ts | 57 ++-- packages/core/src/render3/jit/pipe.ts | 23 +- packages/core/src/render3/jit/util.ts | 33 +- .../bundle.golden_symbols.json | 10 +- .../test/bundling/hello_world/BUILD.bazel | 1 + .../hello_world/bundle.golden_symbols.json | 6 +- .../bundling/hello_world/treeshaking_spec.ts | 1 + .../test/bundling/hello_world_r2/BUILD.bazel | 1 + .../hello_world_r2/bundle.golden_symbols.json | 44 +-- .../hello_world_r2/treeshaking_spec.ts | 1 + .../core/test/bundling/injection/BUILD.bazel | 1 + .../injection/bundle.golden_symbols.json | 8 +- .../bundling/injection/treeshaking_spec.ts | 8 +- packages/core/test/bundling/todo/BUILD.bazel | 1 + .../bundling/todo/bundle.golden_symbols.json | 10 +- .../core/test/bundling/todo/todo_e2e_spec.ts | 2 +- .../core/test/bundling/todo_r2/BUILD.bazel | 1 + .../todo_r2/bundle.golden_symbols.json | 36 +-- .../test/bundling/todo_r2/todo_e2e_spec.ts | 2 +- packages/core/test/render3/BUILD.bazel | 1 + .../back_patch_types_specs.ts | 138 -------- .../compiler_canonical/patch_types_spec.ts | 78 ----- .../compiler_canonical/small_app_spec.ts | 2 +- packages/core/test/render3/ivy/jit_spec.ts | 1 - .../core/test/render3/jit/directive_spec.ts | 4 +- packages/core/test/render3/load_domino.ts | 1 + tools/testing/BUILD.bazel | 2 + tools/testing/init_browser_spec.ts | 1 + tools/testing/init_node_spec.ts | 1 + 46 files changed, 923 insertions(+), 551 deletions(-) create mode 100644 packages/compiler/src/compiler_facade_interface.ts create mode 100644 packages/compiler/src/jit_compiler_facade.ts create mode 100644 packages/compiler/test/compiler_facade_interface_spec.ts create mode 100644 packages/core/src/render3/jit/compiler_facade.ts create mode 100644 packages/core/src/render3/jit/compiler_facade_interface.ts delete mode 100644 packages/core/test/render3/compiler_canonical/back_patch_types_specs.ts delete mode 100644 packages/core/test/render3/compiler_canonical/patch_types_spec.ts diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts b/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts index bec4029165..cb9a8bf5a7 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts @@ -332,8 +332,9 @@ function parseFieldToPropertyMapping( */ function parseDecoratedFields( fields: {member: ClassMember, decorators: Decorator[]}[], reflector: ReflectionHost, - checker: ts.TypeChecker, mapValueResolver: (publicName: string, internalName: string) => - string | string[]): {[field: string]: string | string[]} { + checker: ts.TypeChecker, + mapValueResolver: (publicName: string, internalName: string) => + string | [string, string]): {[field: string]: string | [string, string]} { return fields.reduce( (results, field) => { const fieldName = field.member.name; @@ -356,10 +357,10 @@ function parseDecoratedFields( }); return results; }, - {} as{[field: string]: string | string[]}); + {} as{[field: string]: string | [string, string]}); } -function resolveInput(publicName: string, internalName: string) { +function resolveInput(publicName: string, internalName: string): [string, string] { return [publicName, internalName]; } diff --git a/packages/compiler/package.json b/packages/compiler/package.json index bb7d8a1961..84f1b83ae1 100644 --- a/packages/compiler/package.json +++ b/packages/compiler/package.json @@ -22,5 +22,5 @@ "ng-update": { "packageGroup": "NG_UPDATE_PACKAGE_GROUP" }, - "sideEffects": false -} + "sideEffects": true +} \ No newline at end of file diff --git a/packages/compiler/src/compiler.ts b/packages/compiler/src/compiler.ts index 8a859d6236..5155c670c1 100644 --- a/packages/compiler/src/compiler.ts +++ b/packages/compiler/src/compiler.ts @@ -6,6 +6,11 @@ * found in the LICENSE file at https://angular.io/license */ +////////////////////////////////////// +// THIS FILE HAS GLOBAL SIDE EFFECT // +// (see bottom of file) // +////////////////////////////////////// + /** * @module * @description @@ -23,6 +28,8 @@ */ import * as core from './core'; +import {publishFacade} from './jit_compiler_facade'; +import {global} from './util'; export {core}; @@ -91,4 +98,9 @@ export {compilePipeFromMetadata, R3PipeMetadata} from './render3/r3_pipe_compile export {makeBindingParser, parseTemplate} from './render3/view/template'; export {R3Reference} from './render3/util'; export {compileBaseDefFromMetadata, R3BaseRefMetaData, compileComponentFromMetadata, compileDirectiveFromMetadata, parseHostBindings} from './render3/view/compiler'; +export {publishFacade} from './jit_compiler_facade'; // This file only reexports content of the `src` folder. Keep it that way. + +// This function call has a global side effects and publishes the compiler into global namespace for +// the late binding of the Compiler to the @angular/core for jit compilation. +publishFacade(global); \ No newline at end of file diff --git a/packages/compiler/src/compiler_facade_interface.ts b/packages/compiler/src/compiler_facade_interface.ts new file mode 100644 index 0000000000..c23539ddd2 --- /dev/null +++ b/packages/compiler/src/compiler_facade_interface.ts @@ -0,0 +1,145 @@ +/** + * @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 + */ + + +/** + * A set of interfaces which are shared between `@angular/core` and `@angular/compiler` to allow + * for late binding of `@angular/compiler` for JIT purposes. + * + * This file has two copies. Please ensure that they are in sync: + * - packages/compiler/src/compiler_facade_interface.ts (master) + * - packages/core/src/render3/jit/compiler_facade_interface.ts (copy) + * + * Please ensure that the two files are in sync using this command: + * ``` + * cp packages/compiler/src/compiler_facade_interface.ts \ + * packages/core/src/render3/jit/compiler_facade_interface.ts + * ``` + */ + +export interface ExportedCompilerFacade { ɵcompilerFacade: CompilerFacade; } + +export interface CompilerFacade { + compilePipe(angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3PipeMetadataFacade): + any; + compileInjectable( + angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3InjectableMetadataFacade): any; + compileInjector( + angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3InjectorMetadataFacade): any; + compileNgModule( + angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3NgModuleMetadataFacade): any; + compileDirective( + angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3DirectiveMetadataFacade): any; + compileComponent( + angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3ComponentMetadataFacade): any; + + R3ResolvedDependencyType: typeof R3ResolvedDependencyType; +} + +export interface CoreEnvironment { [name: string]: Function; } + +export type StringMap = { + [key: string]: string; +}; + +export type StringMapWithRename = { + [key: string]: string | [string, string]; +}; + +export type Provider = any; + +export enum R3ResolvedDependencyType { + Token = 0, + Attribute = 1, +} + +export interface R3DependencyMetadataFacade { + token: any; + resolved: R3ResolvedDependencyType; + host: boolean; + optional: boolean; + self: boolean; + skipSelf: boolean; +} + +export interface R3PipeMetadataFacade { + name: string; + type: any; + pipeName: string; + deps: R3DependencyMetadataFacade[]|null; + pure: boolean; +} + +export interface R3InjectableMetadataFacade { + name: string; + type: any; + ctorDeps: R3DependencyMetadataFacade[]|null; + providedIn: any; + useClass?: any; + useFactory?: any; + useExisting?: any; + useValue?: any; + userDeps?: R3DependencyMetadataFacade[]; +} + +export interface R3NgModuleMetadataFacade { + type: any; + bootstrap: Function[]; + declarations: Function[]; + imports: Function[]; + exports: Function[]; + emitInline: boolean; +} + +export interface R3InjectorMetadataFacade { + name: string; + type: any; + deps: R3DependencyMetadataFacade[]|null; + providers: any; + imports: any; +} + +export interface R3DirectiveMetadataFacade { + name: string; + type: any; + typeArgumentCount: number; + typeSourceSpan: null; + deps: R3DependencyMetadataFacade[]|null; + selector: string|null; + queries: R3QueryMetadataFacade[]; + host: {[key: string]: string}; + propMetadata: {[key: string]: any[]}; + lifecycle: {usesOnChanges: boolean;}; + inputs: string[]; + outputs: string[]; + usesInheritance: boolean; + exportAs: string|null; + providers: Provider[]|null; +} + +export interface R3ComponentMetadataFacade extends R3DirectiveMetadataFacade { + template: string; + preserveWhitespaces: boolean; + animations: any[]|undefined; + viewQueries: R3QueryMetadataFacade[]; + pipes: Map; + directives: Map; + styles: string[]; + encapsulation: ViewEncapsulation; + viewProviders: Provider[]|null; +} + +export type ViewEncapsulation = number; + +export interface R3QueryMetadataFacade { + propertyName: string; + first: boolean; + predicate: any|string[]; + descendants: boolean; + read: any|null; +} diff --git a/packages/compiler/src/jit_compiler_facade.ts b/packages/compiler/src/jit_compiler_facade.ts new file mode 100644 index 0000000000..06156ef0a7 --- /dev/null +++ b/packages/compiler/src/jit_compiler_facade.ts @@ -0,0 +1,294 @@ +/** + * @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 {CompilerFacade, CoreEnvironment, ExportedCompilerFacade, R3ComponentMetadataFacade, R3DependencyMetadataFacade, R3DirectiveMetadataFacade, R3InjectableMetadataFacade, R3InjectorMetadataFacade, R3NgModuleMetadataFacade, R3PipeMetadataFacade, R3QueryMetadataFacade, StringMap, StringMapWithRename} from './compiler_facade_interface'; +import {ConstantPool} from './constant_pool'; +import {HostBinding, HostListener, Input, Output, Type} from './core'; +import {compileInjectable} from './injectable_compiler_2'; +import {Expression, LiteralExpr, WrappedNodeExpr} from './output/output_ast'; +import {R3DependencyMetadata, R3ResolvedDependencyType} from './render3/r3_factory'; +import {jitExpression} from './render3/r3_jit'; +import {R3InjectorMetadata, R3NgModuleMetadata, compileInjector, compileNgModule} from './render3/r3_module_compiler'; +import {compilePipeFromMetadata} from './render3/r3_pipe_compiler'; +import {R3Reference} from './render3/util'; +import {R3DirectiveMetadata, R3QueryMetadata} from './render3/view/api'; +import {compileComponentFromMetadata, compileDirectiveFromMetadata, parseHostBindings} from './render3/view/compiler'; +import {makeBindingParser, parseTemplate} from './render3/view/template'; + +export class CompilerFacadeImpl implements CompilerFacade { + R3ResolvedDependencyType = R3ResolvedDependencyType as any; + + compilePipe(angularCoreEnv: CoreEnvironment, sourceMapUrl: string, facade: R3PipeMetadataFacade): + any { + const res = compilePipeFromMetadata({ + name: facade.name, + type: new WrappedNodeExpr(facade.type), + deps: convertR3DependencyMetadataArray(facade.deps), + pipeName: facade.pipeName, + pure: facade.pure, + }); + return jitExpression(res.expression, angularCoreEnv, sourceMapUrl, res.statements); + } + + compileInjectable( + angularCoreEnv: CoreEnvironment, sourceMapUrl: string, + facade: R3InjectableMetadataFacade): any { + const {expression, statements} = compileInjectable({ + name: facade.name, + type: new WrappedNodeExpr(facade.type), + providedIn: computeProvidedIn(facade.providedIn), + useClass: wrapExpression(facade, USE_CLASS), + useFactory: wrapExpression(facade, USE_FACTORY), + useValue: wrapExpression(facade, USE_VALUE), + useExisting: wrapExpression(facade, USE_EXISTING), + ctorDeps: convertR3DependencyMetadataArray(facade.ctorDeps), + userDeps: convertR3DependencyMetadataArray(facade.userDeps) || undefined, + }); + + return jitExpression(expression, angularCoreEnv, sourceMapUrl, statements); + } + + compileInjector( + angularCoreEnv: CoreEnvironment, sourceMapUrl: string, + facade: R3InjectorMetadataFacade): any { + const meta: R3InjectorMetadata = { + name: facade.name, + type: new WrappedNodeExpr(facade.type), + deps: convertR3DependencyMetadataArray(facade.deps), + providers: new WrappedNodeExpr(facade.providers), + imports: new WrappedNodeExpr(facade.imports), + }; + const res = compileInjector(meta); + return jitExpression(res.expression, angularCoreEnv, sourceMapUrl, res.statements); + } + + compileNgModule( + angularCoreEnv: CoreEnvironment, sourceMapUrl: string, + facade: R3NgModuleMetadataFacade): any { + const meta: R3NgModuleMetadata = { + type: new WrappedNodeExpr(facade.type), + bootstrap: facade.bootstrap.map(wrapReference), + declarations: facade.declarations.map(wrapReference), + imports: facade.imports.map(wrapReference), + exports: facade.exports.map(wrapReference), + emitInline: true, + }; + const res = compileNgModule(meta); + return jitExpression(res.expression, angularCoreEnv, sourceMapUrl, []); + } + + compileDirective( + angularCoreEnv: CoreEnvironment, sourceMapUrl: string, + facade: R3DirectiveMetadataFacade): any { + const constantPool = new ConstantPool(); + const bindingParser = makeBindingParser(); + + const meta: R3DirectiveMetadata = convertDirectiveFacadeToMetadata(facade); + const res = compileDirectiveFromMetadata(meta, constantPool, bindingParser); + const preStatements = [...constantPool.statements, ...res.statements]; + return jitExpression(res.expression, angularCoreEnv, sourceMapUrl, preStatements); + } + + compileComponent( + angularCoreEnv: CoreEnvironment, sourceMapUrl: string, + facade: R3ComponentMetadataFacade): any { + // The ConstantPool is a requirement of the JIT'er. + const constantPool = new ConstantPool(); + + // Parse the template and check for errors. + const template = parseTemplate( + facade.template, sourceMapUrl, { + preserveWhitespaces: facade.preserveWhitespaces || false, + }, + ''); + if (template.errors !== undefined) { + const errors = template.errors.map(err => err.toString()).join(', '); + throw new Error(`Errors during JIT compilation of template for ${facade.name}: ${errors}`); + } + + // Compile the component metadata, including template, into an expression. + // TODO(alxhub): implement inputs, outputs, queries, etc. + const res = compileComponentFromMetadata( + { + ...facade as R3ComponentMetadataFacadeNoPropAndWhitespace, + ...convertDirectiveFacadeToMetadata(facade), + template, + viewQueries: facade.viewQueries.map(convertToR3QueryMetadata), + wrapDirectivesAndPipesInClosure: false, + styles: facade.styles || [], + encapsulation: facade.encapsulation as any, + animations: facade.animations != null ? new WrappedNodeExpr(facade.animations) : null, + viewProviders: facade.viewProviders != null ? new WrappedNodeExpr(facade.viewProviders) : + null, + }, + constantPool, makeBindingParser()); + const preStatements = [...constantPool.statements, ...res.statements]; + + return jitExpression(res.expression, angularCoreEnv, sourceMapUrl, preStatements); + } +} + +// This seems to be needed to placate TS v3.0 only +type R3ComponentMetadataFacadeNoPropAndWhitespace = Pick< + R3ComponentMetadataFacade, + Exclude, 'propMetadata'>>; + +const USE_CLASS = Object.keys({useClass: null})[0]; +const USE_FACTORY = Object.keys({useFactory: null})[0]; +const USE_VALUE = Object.keys({useValue: null})[0]; +const USE_EXISTING = Object.keys({useExisting: null})[0]; + +const wrapReference = function(value: Type): R3Reference { + const wrapped = new WrappedNodeExpr(value); + return {value: wrapped, type: wrapped}; +}; + +function convertToR3QueryMetadata(facade: R3QueryMetadataFacade): R3QueryMetadata { + return { + ...facade, + predicate: Array.isArray(facade.predicate) ? facade.predicate : + new WrappedNodeExpr(facade.predicate), + read: facade.read ? new WrappedNodeExpr(facade.read) : null, + }; +} + +function convertDirectiveFacadeToMetadata(facade: R3DirectiveMetadataFacade): R3DirectiveMetadata { + const inputsFromMetadata = parseInputOutputs(facade.inputs || []); + const outputsFromMetadata = parseInputOutputs(facade.outputs || []); + const propMetadata = facade.propMetadata; + const inputsFromType: StringMapWithRename = {}; + const outputsFromType: StringMap = {}; + for (const field in propMetadata) { + if (propMetadata.hasOwnProperty(field)) { + propMetadata[field].forEach(ann => { + if (isInput(ann)) { + inputsFromType[field] = + ann.bindingPropertyName ? [ann.bindingPropertyName, field] : field; + } else if (isOutput(ann)) { + outputsFromType[field] = ann.bindingPropertyName || field; + } + }); + } + } + + return { + ...facade as R3DirectiveMetadataFacadeNoPropAndWhitespace, + typeSourceSpan: null !, + type: new WrappedNodeExpr(facade.type), + deps: convertR3DependencyMetadataArray(facade.deps), + host: extractHostBindings(facade.host, facade.propMetadata), + inputs: {...inputsFromMetadata, ...inputsFromType}, + outputs: {...outputsFromMetadata, ...outputsFromType}, + providers: facade.providers != null ? new WrappedNodeExpr(facade.providers) : null, + }; +} + +// This seems to be needed to placate TS v3.0 only +type R3DirectiveMetadataFacadeNoPropAndWhitespace = + Pick>; + +function wrapExpression(obj: any, property: string): WrappedNodeExpr|undefined { + if (obj.hasOwnProperty(property)) { + return new WrappedNodeExpr(obj[property]); + } else { + return undefined; + } +} + +function computeProvidedIn(providedIn: Type | string | null | undefined): Expression { + if (providedIn == null || typeof providedIn === 'string') { + return new LiteralExpr(providedIn); + } else { + return new WrappedNodeExpr(providedIn); + } +} + +function convertR3DependencyMetadata(facade: R3DependencyMetadataFacade): R3DependencyMetadata { + let tokenExpr; + if (facade.token === null) { + tokenExpr = new LiteralExpr(null); + } else if (facade.resolved === R3ResolvedDependencyType.Attribute) { + tokenExpr = new LiteralExpr(facade.token); + } else { + tokenExpr = new WrappedNodeExpr(facade.token); + } + return { + token: tokenExpr, + resolved: facade.resolved, + host: facade.host, + optional: facade.optional, + self: facade.self, + skipSelf: facade.skipSelf + }; +} + +function convertR3DependencyMetadataArray(facades: R3DependencyMetadataFacade[] | null | undefined): + R3DependencyMetadata[]|null { + return facades == null ? null : facades.map(convertR3DependencyMetadata); +} + +function extractHostBindings(host: {[key: string]: string}, propMetadata: {[key: string]: any[]}): { + attributes: StringMap, + listeners: StringMap, + properties: StringMap, +} { + // First parse the declarations from the metadata. + const {attributes, listeners, properties, animations} = parseHostBindings(host || {}); + + if (Object.keys(animations).length > 0) { + throw new Error(`Animation bindings are as-of-yet unsupported in Ivy`); + } + + // Next, loop over the properties of the object, looking for @HostBinding and @HostListener. + for (const field in propMetadata) { + if (propMetadata.hasOwnProperty(field)) { + propMetadata[field].forEach(ann => { + if (isHostBinding(ann)) { + properties[ann.hostPropertyName || field] = field; + } else if (isHostListener(ann)) { + listeners[ann.eventName || field] = `${field}(${(ann.args || []).join(',')})`; + } + }); + } + } + + return {attributes, listeners, properties}; +} + +function isHostBinding(value: any): value is HostBinding { + return value.ngMetadataName === 'HostBinding'; +} + +function isHostListener(value: any): value is HostListener { + return value.ngMetadataName === 'HostListener'; +} + + +function isInput(value: any): value is Input { + return value.ngMetadataName === 'Input'; +} + +function isOutput(value: any): value is Output { + return value.ngMetadataName === 'Output'; +} + +function parseInputOutputs(values: string[]): StringMap { + return values.reduce( + (map, value) => { + const [field, property] = value.split(',').map(piece => piece.trim()); + map[field] = property || field; + return map; + }, + {} as StringMap); +} + +export function publishFacade(global: any) { + const ng: ExportedCompilerFacade = global.ng || (global.ng = {}); + ng.ɵcompilerFacade = new CompilerFacadeImpl(); +} \ No newline at end of file diff --git a/packages/compiler/src/render3/r3_module_compiler.ts b/packages/compiler/src/render3/r3_module_compiler.ts index 64c3f86a1e..0ec1b38555 100644 --- a/packages/compiler/src/render3/r3_module_compiler.ts +++ b/packages/compiler/src/render3/r3_module_compiler.ts @@ -6,7 +6,6 @@ * found in the LICENSE file at https://angular.io/license */ -import {StaticSymbol} from '../aot/static_symbol'; import {CompileShallowModuleMetadata, identifierName} from '../compile_metadata'; import {InjectableCompiler} from '../injectable_compiler'; import {mapLiteral} from '../output/map_util'; diff --git a/packages/compiler/src/render3/view/api.ts b/packages/compiler/src/render3/view/api.ts index 57ab37e1d8..89f032c6f0 100644 --- a/packages/compiler/src/render3/view/api.ts +++ b/packages/compiler/src/render3/view/api.ts @@ -86,7 +86,7 @@ export interface R3DirectiveMetadata { /** * A mapping of input field names to the property names. */ - inputs: {[field: string]: string | string[]}; + inputs: {[field: string]: string | [string, string]}; /** * A mapping of output field names to the property names. diff --git a/packages/compiler/src/render3/view/t2_api.ts b/packages/compiler/src/render3/view/t2_api.ts index 4d6adcae71..0b6f104316 100644 --- a/packages/compiler/src/render3/view/t2_api.ts +++ b/packages/compiler/src/render3/view/t2_api.ts @@ -44,7 +44,7 @@ export interface DirectiveMeta { * * Goes from property names to field names. */ - inputs: {[property: string]: string | string[]}; + inputs: {[property: string]: string | [string, string]}; /** * Set of outputs which this directive claims. diff --git a/packages/compiler/src/util.ts b/packages/compiler/src/util.ts index cb167e14fe..5fb3982005 100644 --- a/packages/compiler/src/util.ts +++ b/packages/compiler/src/util.ts @@ -233,3 +233,19 @@ export interface Console { log(message: string): void; warn(message: string): void; } + + +declare var WorkerGlobalScope: any; +// CommonJS / Node have global context exposed as "global" variable. +// We don't want to include the whole node.d.ts this this compilation unit so we'll just fake +// the global "global" var for now. +declare var global: any; +const __window = typeof window !== 'undefined' && window; +const __self = typeof self !== 'undefined' && typeof WorkerGlobalScope !== 'undefined' && + self instanceof WorkerGlobalScope && self; +const __global = typeof global !== 'undefined' && global; + +// Check __global first, because in Node tests both __global and __window may be defined and _global +// should be __global in that case. +const _global: {[name: string]: any} = __global || __window || __self; +export {_global as global}; diff --git a/packages/compiler/test/compiler_facade_interface_spec.ts b/packages/compiler/test/compiler_facade_interface_spec.ts new file mode 100644 index 0000000000..070131f036 --- /dev/null +++ b/packages/compiler/test/compiler_facade_interface_spec.ts @@ -0,0 +1,100 @@ +/** + * @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 core from '../../core/src/render3/jit/compiler_facade_interface'; +import {R3ResolvedDependencyType} from '../public_api'; +import * as compiler from '../src/compiler_facade_interface'; + +/** + * This file is compiler level file which asserts that the set of interfaces in `@angular/core` and + * `@angular/compiler` match. (Build time failure.) + * + * If this file fails to compile it means these two files when out of sync: + * - packages/compiler/src/compiler_facade_interface.ts (master) + * - packages/core/src/render3/jit/compiler_facade_interface.ts (copy) + * + * Please ensure that the two files are in sync using this command: + * ``` + * cp packages/compiler/src/compiler_facade_interface.ts \ + * packages/core/src/render3/jit/compiler_facade_interface.ts + * ``` + */ + +const coreExportedCompilerFacade1: core.ExportedCompilerFacade = + null !as compiler.ExportedCompilerFacade; +const compilerExportedCompilerFacade2: compiler.ExportedCompilerFacade = + null !as core.ExportedCompilerFacade; + +const coreCompilerFacade: core.CompilerFacade = null !as compiler.CompilerFacade; +const compilerCompilerFacade: compiler.CompilerFacade = null !as core.CompilerFacade; + +const coreCoreEnvironment: core.CoreEnvironment = null !as compiler.CoreEnvironment; +const compilerCoreEnvironment: compiler.CoreEnvironment = null !as core.CoreEnvironment; + +const coreStringMap: core.StringMap = null !as compiler.StringMap; +const compilerStringMap: compiler.StringMap = null !as core.StringMap; + +const coreProvider: core.Provider = null !as compiler.Provider; +const compilerProvider: compiler.Provider = null !as core.Provider; + +const coreR3ResolvedDependencyType: core.R3ResolvedDependencyType = + null !as compiler.R3ResolvedDependencyType; +const compilerR3ResolvedDependencyType: compiler.R3ResolvedDependencyType = + null !as core.R3ResolvedDependencyType; + +const coreR3ResolvedDependencyType2: R3ResolvedDependencyType = + null !as core.R3ResolvedDependencyType; +const compilerR3ResolvedDependencyType2: R3ResolvedDependencyType = + null !as core.R3ResolvedDependencyType; + +const coreR3ResolvedDependencyType3: core.R3ResolvedDependencyType = + null !as R3ResolvedDependencyType; +const compilerR3ResolvedDependencyType3: compiler.R3ResolvedDependencyType = + null !as R3ResolvedDependencyType; + +const coreR3DependencyMetadataFacade: core.R3DependencyMetadataFacade = + null !as compiler.R3DependencyMetadataFacade; +const compilerR3DependencyMetadataFacade: compiler.R3DependencyMetadataFacade = + null !as core.R3DependencyMetadataFacade; + +const coreR3PipeMetadataFacade: core.R3PipeMetadataFacade = null !as compiler.R3PipeMetadataFacade; +const compilerR3PipeMetadataFacade: compiler.R3PipeMetadataFacade = + null !as core.R3PipeMetadataFacade; + +const coreR3InjectableMetadataFacade: core.R3InjectableMetadataFacade = + null !as compiler.R3InjectableMetadataFacade; +const compilerR3InjectableMetadataFacade: compiler.R3InjectableMetadataFacade = + null !as core.R3InjectableMetadataFacade; + +const coreR3NgModuleMetadataFacade: core.R3NgModuleMetadataFacade = + null !as compiler.R3NgModuleMetadataFacade; +const compilerR3NgModuleMetadataFacade: compiler.R3NgModuleMetadataFacade = + null !as core.R3NgModuleMetadataFacade; + +const coreR3InjectorMetadataFacade: core.R3InjectorMetadataFacade = + null !as compiler.R3InjectorMetadataFacade; +const compilerR3InjectorMetadataFacade: compiler.R3InjectorMetadataFacade = + null !as core.R3InjectorMetadataFacade; + +const coreR3DirectiveMetadataFacade: core.R3DirectiveMetadataFacade = + null !as compiler.R3DirectiveMetadataFacade; +const compilerR3DirectiveMetadataFacade: compiler.R3DirectiveMetadataFacade = + null !as core.R3DirectiveMetadataFacade; + +const coreR3ComponentMetadataFacade: core.R3ComponentMetadataFacade = + null !as compiler.R3ComponentMetadataFacade; +const compilerR3ComponentMetadataFacade: compiler.R3ComponentMetadataFacade = + null !as core.R3ComponentMetadataFacade; + +const coreViewEncapsulation: core.ViewEncapsulation = null !as compiler.ViewEncapsulation; +const compilerViewEncapsulation: compiler.ViewEncapsulation = null !as core.ViewEncapsulation; + +const coreR3QueryMetadataFacade: core.R3QueryMetadataFacade = + null !as compiler.R3QueryMetadataFacade; +const compilerR3QueryMetadataFacade: compiler.R3QueryMetadataFacade = + null !as core.R3QueryMetadataFacade; diff --git a/packages/core/BUILD.bazel b/packages/core/BUILD.bazel index e5aca73e63..5262f2c4d1 100644 --- a/packages/core/BUILD.bazel +++ b/packages/core/BUILD.bazel @@ -13,7 +13,6 @@ ng_module( module_name = "@angular/core", deps = [ "//packages:types", - "//packages/compiler", "@ngdeps//zone.js", "@rxjs", "@rxjs//operators", diff --git a/packages/core/package.json b/packages/core/package.json index d6285f166c..cf624f468d 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -16,7 +16,6 @@ "tslib": "^1.9.0" }, "peerDependencies": { - "@angular/compiler": "0.0.0-PLACEHOLDER", "rxjs": "^6.0.0", "zone.js": "~0.8.26" }, @@ -28,4 +27,4 @@ "packageGroup": "NG_UPDATE_PACKAGE_GROUP" }, "sideEffects": false -} +} \ No newline at end of file diff --git a/packages/core/src/render3/di.ts b/packages/core/src/render3/di.ts index 3dbd19d7e6..bba6b5cf22 100644 --- a/packages/core/src/render3/di.ts +++ b/packages/core/src/render3/di.ts @@ -480,6 +480,7 @@ export function getNodeInjectable( */ export function bloomHashBitOrFactory(token: Type| InjectionToken): number|Function| undefined { + ngDevMode && assertDefined(token, 'token must be defined'); const tokenId: number|undefined = (token as any)[NG_ELEMENT_ID]; return typeof tokenId === 'number' ? tokenId & BLOOM_MASK : tokenId; } diff --git a/packages/core/src/render3/jit/compiler_facade.ts b/packages/core/src/render3/jit/compiler_facade.ts new file mode 100644 index 0000000000..91a4b269c7 --- /dev/null +++ b/packages/core/src/render3/jit/compiler_facade.ts @@ -0,0 +1,22 @@ +/** + * @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 {global} from '../../util'; +import {CompilerFacade, ExportedCompilerFacade} from './compiler_facade_interface'; +export * from './compiler_facade_interface'; + +export function getCompilerFacade(): CompilerFacade { + const globalNg: ExportedCompilerFacade = global.ng; + if (!globalNg || !globalNg.ɵcompilerFacade) { + throw new Error( + `Angular JIT compilation failed: '@angular/compiler' not loaded!\n` + + ` - JIT compilation is discouraged for production use-cases! Consider AOT mode instead.\n` + + ` - Did you bootstrap using '@angular/platform-browser-dynamic' or '@angular/platform-server'?\n` + + ` - Alternatively provide the compiler with 'import "@angular/compiler";' before bootstrapping.`); + } + return globalNg.ɵcompilerFacade; +} diff --git a/packages/core/src/render3/jit/compiler_facade_interface.ts b/packages/core/src/render3/jit/compiler_facade_interface.ts new file mode 100644 index 0000000000..c23539ddd2 --- /dev/null +++ b/packages/core/src/render3/jit/compiler_facade_interface.ts @@ -0,0 +1,145 @@ +/** + * @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 + */ + + +/** + * A set of interfaces which are shared between `@angular/core` and `@angular/compiler` to allow + * for late binding of `@angular/compiler` for JIT purposes. + * + * This file has two copies. Please ensure that they are in sync: + * - packages/compiler/src/compiler_facade_interface.ts (master) + * - packages/core/src/render3/jit/compiler_facade_interface.ts (copy) + * + * Please ensure that the two files are in sync using this command: + * ``` + * cp packages/compiler/src/compiler_facade_interface.ts \ + * packages/core/src/render3/jit/compiler_facade_interface.ts + * ``` + */ + +export interface ExportedCompilerFacade { ɵcompilerFacade: CompilerFacade; } + +export interface CompilerFacade { + compilePipe(angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3PipeMetadataFacade): + any; + compileInjectable( + angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3InjectableMetadataFacade): any; + compileInjector( + angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3InjectorMetadataFacade): any; + compileNgModule( + angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3NgModuleMetadataFacade): any; + compileDirective( + angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3DirectiveMetadataFacade): any; + compileComponent( + angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3ComponentMetadataFacade): any; + + R3ResolvedDependencyType: typeof R3ResolvedDependencyType; +} + +export interface CoreEnvironment { [name: string]: Function; } + +export type StringMap = { + [key: string]: string; +}; + +export type StringMapWithRename = { + [key: string]: string | [string, string]; +}; + +export type Provider = any; + +export enum R3ResolvedDependencyType { + Token = 0, + Attribute = 1, +} + +export interface R3DependencyMetadataFacade { + token: any; + resolved: R3ResolvedDependencyType; + host: boolean; + optional: boolean; + self: boolean; + skipSelf: boolean; +} + +export interface R3PipeMetadataFacade { + name: string; + type: any; + pipeName: string; + deps: R3DependencyMetadataFacade[]|null; + pure: boolean; +} + +export interface R3InjectableMetadataFacade { + name: string; + type: any; + ctorDeps: R3DependencyMetadataFacade[]|null; + providedIn: any; + useClass?: any; + useFactory?: any; + useExisting?: any; + useValue?: any; + userDeps?: R3DependencyMetadataFacade[]; +} + +export interface R3NgModuleMetadataFacade { + type: any; + bootstrap: Function[]; + declarations: Function[]; + imports: Function[]; + exports: Function[]; + emitInline: boolean; +} + +export interface R3InjectorMetadataFacade { + name: string; + type: any; + deps: R3DependencyMetadataFacade[]|null; + providers: any; + imports: any; +} + +export interface R3DirectiveMetadataFacade { + name: string; + type: any; + typeArgumentCount: number; + typeSourceSpan: null; + deps: R3DependencyMetadataFacade[]|null; + selector: string|null; + queries: R3QueryMetadataFacade[]; + host: {[key: string]: string}; + propMetadata: {[key: string]: any[]}; + lifecycle: {usesOnChanges: boolean;}; + inputs: string[]; + outputs: string[]; + usesInheritance: boolean; + exportAs: string|null; + providers: Provider[]|null; +} + +export interface R3ComponentMetadataFacade extends R3DirectiveMetadataFacade { + template: string; + preserveWhitespaces: boolean; + animations: any[]|undefined; + viewQueries: R3QueryMetadataFacade[]; + pipes: Map; + directives: Map; + styles: string[]; + encapsulation: ViewEncapsulation; + viewProviders: Provider[]|null; +} + +export type ViewEncapsulation = number; + +export interface R3QueryMetadataFacade { + propertyName: string; + first: boolean; + predicate: any|string[]; + descendants: boolean; + read: any|null; +} diff --git a/packages/core/src/render3/jit/directive.ts b/packages/core/src/render3/jit/directive.ts index 17a42c748a..c69ab96bb0 100644 --- a/packages/core/src/render3/jit/directive.ts +++ b/packages/core/src/render3/jit/directive.ts @@ -6,23 +6,22 @@ * found in the LICENSE file at https://angular.io/license */ -import {ConstantPool, Expression, R3DirectiveMetadata, R3QueryMetadata, WrappedNodeExpr, compileComponentFromMetadata as compileR3Component, compileDirectiveFromMetadata as compileR3Directive, jitExpression, makeBindingParser, parseHostBindings, parseTemplate} from '@angular/compiler'; - import {Query} from '../../metadata/di'; -import {Component, Directive, HostBinding, HostListener, Input, Output} from '../../metadata/directives'; +import {Component, Directive} from '../../metadata/directives'; import {componentNeedsResolution, maybeQueueResolutionOfComponentResources} from '../../metadata/resource_loading'; import {ViewEncapsulation} from '../../metadata/view'; import {Type} from '../../type'; import {stringify} from '../../util'; +import {EMPTY_ARRAY} from '../definition'; import {NG_COMPONENT_DEF, NG_DIRECTIVE_DEF} from '../fields'; +import {R3DirectiveMetadataFacade, getCompilerFacade} from './compiler_facade'; +import {R3ComponentMetadataFacade, R3QueryMetadataFacade} from './compiler_facade_interface'; import {angularCoreEnv} from './environment'; import {patchComponentDefWithScope, transitiveScopesFor} from './module'; import {getReflect, reflectDependencies} from './util'; -type StringMap = { - [key: string]: string -}; + /** * Compile an Angular component according to its decorator metadata, and patch the resulting @@ -39,6 +38,7 @@ export function compileComponent(type: Type, metadata: Component): void { maybeQueueResolutionOfComponentResources(metadata); Object.defineProperty(type, NG_COMPONENT_DEF, { get: () => { + const compiler = getCompilerFacade(); if (ngComponentDef === null) { if (componentNeedsResolution(metadata)) { const error = [`Component '${stringify(type)}' is not resolved:`]; @@ -51,43 +51,20 @@ export function compileComponent(type: Type, metadata: Component): void { error.push(`Did you run and wait for 'resolveComponentResources()'?`); throw new Error(error.join('\n')); } - // The ConstantPool is a requirement of the JIT'er. - const constantPool = new ConstantPool(); - - // Parse the template and check for errors. - const template = parseTemplate( - metadata.template !, `ng://${stringify(type)}/template.html`, { - preserveWhitespaces: metadata.preserveWhitespaces || false, - }, - ''); - if (template.errors !== undefined) { - const errors = template.errors.map(err => err.toString()).join(', '); - throw new Error( - `Errors during JIT compilation of template for ${stringify(type)}: ${errors}`); - } - - const animations = - metadata.animations !== null ? new WrappedNodeExpr(metadata.animations) : null; - - // Compile the component metadata, including template, into an expression. - const res = compileR3Component( - { - ...directiveMetadata(type, metadata), - template, - directives: new Map(), - pipes: new Map(), - viewQueries: extractQueriesMetadata(getReflect().propMetadata(type), isViewQuery), - wrapDirectivesAndPipesInClosure: false, - styles: metadata.styles || [], - encapsulation: metadata.encapsulation || ViewEncapsulation.Emulated, animations, - viewProviders: metadata.viewProviders ? new WrappedNodeExpr(metadata.viewProviders) : - null - }, - constantPool, makeBindingParser()); - const preStatements = [...constantPool.statements, ...res.statements]; - - ngComponentDef = jitExpression( - res.expression, angularCoreEnv, `ng://${type.name}/ngComponentDef.js`, preStatements); + const meta: R3ComponentMetadataFacade = { + ...directiveMetadata(type, metadata), + template: metadata.template || '', + preserveWhitespaces: metadata.preserveWhitespaces || false, + styles: metadata.styles || EMPTY_ARRAY, + animations: metadata.animations, + viewQueries: extractQueriesMetadata(getReflect().propMetadata(type), isViewQuery), + directives: new Map(), + pipes: new Map(), + encapsulation: metadata.encapsulation || ViewEncapsulation.Emulated, + viewProviders: metadata.viewProviders || null, + }; + ngComponentDef = compiler.compileComponent( + angularCoreEnv, `ng://${stringify(type)}/template.html`, meta); // If component compilation is async, then the @NgModule annotation which declares the // component may execute and set an ngSelectorScope property on the component type. This @@ -122,12 +99,9 @@ export function compileDirective(type: Type, directive: Directive): void { Object.defineProperty(type, NG_DIRECTIVE_DEF, { get: () => { if (ngDirectiveDef === null) { - const constantPool = new ConstantPool(); - const sourceMapUrl = `ng://${type && type.name}/ngDirectiveDef.js`; - const res = compileR3Directive( - directiveMetadata(type, directive), constantPool, makeBindingParser()); - const preStatements = [...constantPool.statements, ...res.statements]; - ngDirectiveDef = jitExpression(res.expression, angularCoreEnv, sourceMapUrl, preStatements); + const facade = directiveMetadata(type, directive); + ngDirectiveDef = getCompilerFacade().compileDirective( + angularCoreEnv, `ng://${type && type.name}/ngDirectiveDef.js`, facade); } return ngDirectiveDef; }, @@ -144,38 +118,20 @@ export function extendsDirectlyFromObject(type: Type): boolean { * Extract the `R3DirectiveMetadata` for a particular directive (either a `Directive` or a * `Component`). */ -function directiveMetadata(type: Type, metadata: Directive): R3DirectiveMetadata { +function directiveMetadata(type: Type, metadata: Directive): R3DirectiveMetadataFacade { // Reflect inputs and outputs. const propMetadata = getReflect().propMetadata(type); - const host = extractHostBindings(metadata, propMetadata); - - const inputsFromMetadata = parseInputOutputs(metadata.inputs || []); - const outputsFromMetadata = parseInputOutputs(metadata.outputs || []); - - const inputsFromType: {[key: string]: string | string[]} = {}; - const outputsFromType: StringMap = {}; - for (const field in propMetadata) { - if (propMetadata.hasOwnProperty(field)) { - propMetadata[field].forEach(ann => { - if (isInput(ann)) { - inputsFromType[field] = - ann.bindingPropertyName ? [ann.bindingPropertyName, field] : field; - } else if (isOutput(ann)) { - outputsFromType[field] = ann.bindingPropertyName || field; - } - }); - } - } - return { name: type.name, - type: new WrappedNodeExpr(type), + type: type, typeArgumentCount: 0, selector: metadata.selector !, - deps: reflectDependencies(type), host, - inputs: {...inputsFromMetadata, ...inputsFromType}, - outputs: {...outputsFromMetadata, ...outputsFromType}, + deps: reflectDependencies(type), + host: metadata.host || EMPTY_OBJ, + propMetadata: propMetadata, + inputs: metadata.inputs || EMPTY_ARRAY, + outputs: metadata.outputs || EMPTY_ARRAY, queries: extractQueriesMetadata(propMetadata, isContentQuery), lifecycle: { usesOnChanges: type.prototype.ngOnChanges !== undefined, @@ -183,57 +139,29 @@ function directiveMetadata(type: Type, metadata: Directive): R3DirectiveMet typeSourceSpan: null !, usesInheritance: !extendsDirectlyFromObject(type), exportAs: metadata.exportAs || null, - providers: metadata.providers ? new WrappedNodeExpr(metadata.providers) : null + providers: metadata.providers || null, }; } -function extractHostBindings(metadata: Directive, propMetadata: {[key: string]: any[]}): { - attributes: StringMap, - listeners: StringMap, - properties: StringMap, -} { - // First parse the declarations from the metadata. - const {attributes, listeners, properties, animations} = parseHostBindings(metadata.host || {}); +const EMPTY_OBJ = {}; - if (Object.keys(animations).length > 0) { - throw new Error(`Animation bindings are as-of-yet unsupported in Ivy`); - } - - // Next, loop over the properties of the object, looking for @HostBinding and @HostListener. - for (const field in propMetadata) { - if (propMetadata.hasOwnProperty(field)) { - propMetadata[field].forEach(ann => { - if (isHostBinding(ann)) { - properties[ann.hostPropertyName || field] = field; - } else if (isHostListener(ann)) { - listeners[ann.eventName || field] = `${field}(${(ann.args || []).join(',')})`; - } - }); - } - } - - return {attributes, listeners, properties}; +function convertToR3QueryPredicate(selector: any): any|string[] { + return typeof selector === 'string' ? splitByComma(selector) : selector; } -function convertToR3QueryPredicate(selector: any): Expression|string[] { - return typeof selector === 'string' ? splitByComma(selector) : new WrappedNodeExpr(selector); -} - -export function convertToR3QueryMetadata(propertyName: string, ann: Query): R3QueryMetadata { +export function convertToR3QueryMetadata(propertyName: string, ann: Query): R3QueryMetadataFacade { return { propertyName: propertyName, predicate: convertToR3QueryPredicate(ann.selector), descendants: ann.descendants, first: ann.first, - read: ann.read ? new WrappedNodeExpr(ann.read) : null + read: ann.read ? ann.read : null }; } - function extractQueriesMetadata( propMetadata: {[key: string]: any[]}, - isQueryAnn: (ann: any) => ann is Query): R3QueryMetadata[] { - const queriesMeta: R3QueryMetadata[] = []; - + isQueryAnn: (ann: any) => ann is Query): R3QueryMetadataFacade[] { + const queriesMeta: R3QueryMetadataFacade[] = []; for (const field in propMetadata) { if (propMetadata.hasOwnProperty(field)) { propMetadata[field].forEach(ann => { @@ -243,26 +171,9 @@ function extractQueriesMetadata( }); } } - return queriesMeta; } -function isInput(value: any): value is Input { - return value.ngMetadataName === 'Input'; -} - -function isOutput(value: any): value is Output { - return value.ngMetadataName === 'Output'; -} - -function isHostBinding(value: any): value is HostBinding { - return value.ngMetadataName === 'HostBinding'; -} - -function isHostListener(value: any): value is HostListener { - return value.ngMetadataName === 'HostListener'; -} - function isContentQuery(value: any): value is Query { const name = value.ngMetadataName; return name === 'ContentChild' || name === 'ContentChildren'; @@ -276,13 +187,3 @@ function isViewQuery(value: any): value is Query { function splitByComma(value: string): string[] { return value.split(',').map(piece => piece.trim()); } - -function parseInputOutputs(values: string[]): StringMap { - return values.reduce( - (map, value) => { - const [field, property] = splitByComma(value); - map[field] = property || field; - return map; - }, - {} as StringMap); -} diff --git a/packages/core/src/render3/jit/injectable.ts b/packages/core/src/render3/jit/injectable.ts index cd1ea9af77..0e77c9a3f5 100644 --- a/packages/core/src/render3/jit/injectable.ts +++ b/packages/core/src/render3/jit/injectable.ts @@ -6,14 +6,13 @@ * found in the LICENSE file at https://angular.io/license */ -import {Expression, LiteralExpr, R3DependencyMetadata, R3InjectableMetadata, WrappedNodeExpr, compileInjectable as compileR3Injectable, jitExpression} from '@angular/compiler'; - import {Injectable} from '../../di/injectable'; -import {ClassSansProvider, ExistingSansProvider, FactorySansProvider, StaticClassSansProvider, ValueProvider, ValueSansProvider} from '../../di/provider'; +import {ClassSansProvider, ExistingSansProvider, FactorySansProvider, ValueProvider, ValueSansProvider} from '../../di/provider'; import {Type} from '../../type'; import {getClosureSafeProperty} from '../../util/property'; import {NG_INJECTABLE_DEF} from '../fields'; +import {R3InjectableMetadataFacade, getCompilerFacade} from './compiler_facade'; import {angularCoreEnv} from './environment'; import {convertDependencies, reflectDependencies} from './util'; @@ -31,84 +30,60 @@ export function compileInjectable(type: Type, srcMeta?: Injectable): void { Object.defineProperty(type, NG_INJECTABLE_DEF, { get: () => { if (def === null) { - // Check whether the injectable metadata includes a provider specification. + const meta: Injectable = srcMeta || {providedIn: null}; const hasAProvider = isUseClassProvider(meta) || isUseFactoryProvider(meta) || isUseValueProvider(meta) || isUseExistingProvider(meta); - const ctorDeps = reflectDependencies(type); - let userDeps: R3DependencyMetadata[]|undefined = undefined; + const compilerMeta: R3InjectableMetadataFacade = { + name: type.name, + type: type, + providedIn: meta.providedIn, + ctorDeps: reflectDependencies(type), + userDeps: undefined + }; if ((isUseClassProvider(meta) || isUseFactoryProvider(meta)) && meta.deps !== undefined) { - userDeps = convertDependencies(meta.deps); + compilerMeta.userDeps = convertDependencies(meta.deps); } - - // Decide which flavor of factory to generate, based on the provider specified. - // Only one of the use* fields should be set. - let useClass: Expression|undefined = undefined; - let useFactory: Expression|undefined = undefined; - let useValue: Expression|undefined = undefined; - let useExisting: Expression|undefined = undefined; - if (!hasAProvider) { // In the case the user specifies a type provider, treat it as {provide: X, useClass: X}. // The deps will have been reflected above, causing the factory to create the class by // calling // its constructor with injected deps. - useClass = new WrappedNodeExpr(type); + compilerMeta.useClass = type; } else if (isUseClassProvider(meta)) { // The user explicitly specified useClass, and may or may not have provided deps. - useClass = new WrappedNodeExpr(meta.useClass); + compilerMeta.useClass = meta.useClass; } else if (isUseValueProvider(meta)) { // The user explicitly specified useValue. - useValue = new WrappedNodeExpr(meta.useValue); + compilerMeta.useValue = meta.useValue; } else if (isUseFactoryProvider(meta)) { // The user explicitly specified useFactory. - useFactory = new WrappedNodeExpr(meta.useFactory); + compilerMeta.useFactory = meta.useFactory; } else if (isUseExistingProvider(meta)) { // The user explicitly specified useExisting. - useExisting = new WrappedNodeExpr(meta.useExisting); + compilerMeta.useExisting = meta.useExisting; } else { // Can't happen - either hasAProvider will be false, or one of the providers will be set. throw new Error(`Unreachable state.`); } - - const {expression, statements} = compileR3Injectable({ - name: type.name, - type: new WrappedNodeExpr(type), - providedIn: computeProvidedIn(meta.providedIn), - useClass, - useFactory, - useValue, - useExisting, - ctorDeps, - userDeps, - }); - - def = jitExpression( - expression, angularCoreEnv, `ng://${type.name}/ngInjectableDef.js`, statements); + def = getCompilerFacade().compileInjectable( + angularCoreEnv, `ng://${type.name}/ngInjectableDef.js`, compilerMeta); } return def; }, }); } -function computeProvidedIn(providedIn: Type| string | null | undefined): Expression { - if (providedIn == null || typeof providedIn === 'string') { - return new LiteralExpr(providedIn); - } else { - return new WrappedNodeExpr(providedIn); - } -} - type UseClassProvider = Injectable & ClassSansProvider & {deps?: any[]}; +const USE_VALUE = + getClosureSafeProperty({provide: String, useValue: getClosureSafeProperty}); + function isUseClassProvider(meta: Injectable): meta is UseClassProvider { return (meta as UseClassProvider).useClass !== undefined; } -const USE_VALUE = - getClosureSafeProperty({provide: String, useValue: getClosureSafeProperty}); - function isUseValueProvider(meta: Injectable): meta is Injectable&ValueSansProvider { return USE_VALUE in meta; } diff --git a/packages/core/src/render3/jit/module.ts b/packages/core/src/render3/jit/module.ts index a427389cf1..9a89e55a83 100644 --- a/packages/core/src/render3/jit/module.ts +++ b/packages/core/src/render3/jit/module.ts @@ -6,14 +6,13 @@ * found in the LICENSE file at https://angular.io/license */ -import {Expression, R3InjectorMetadata, R3NgModuleMetadata, R3Reference, WrappedNodeExpr, compileInjector, compileNgModule as compileR3NgModule, jitExpression} from '@angular/compiler'; - import {ModuleWithProviders, NgModule, NgModuleDef, NgModuleTransitiveScopes} from '../../metadata/ng_module'; import {Type} from '../../type'; import {getComponentDef, getDirectiveDef, getNgModuleDef, getPipeDef} from '../definition'; import {NG_COMPONENT_DEF, NG_DIRECTIVE_DEF, NG_INJECTOR_DEF, NG_MODULE_DEF, NG_PIPE_DEF} from '../fields'; import {ComponentDef} from '../interfaces/definition'; +import {R3InjectorMetadataFacade, getCompilerFacade} from './compiler_facade'; import {angularCoreEnv} from './environment'; import {reflectDependencies} from './util'; @@ -37,48 +36,39 @@ export function compileNgModuleDefs(moduleType: Type, ngModule: NgModule): let ngModuleDef: any = null; Object.defineProperty(moduleType, NG_MODULE_DEF, { + configurable: true, get: () => { if (ngModuleDef === null) { - const meta: R3NgModuleMetadata = { - type: wrap(moduleType), - bootstrap: flatten(ngModule.bootstrap || EMPTY_ARRAY).map(wrapReference), - declarations: declarations.map(wrapReference), - imports: flatten(ngModule.imports || EMPTY_ARRAY) - .map(expandModuleWithProviders) - .map(wrapReference), - exports: flatten(ngModule.exports || EMPTY_ARRAY) - .map(expandModuleWithProviders) - .map(wrapReference), - emitInline: true, - }; - const res = compileR3NgModule(meta); - ngModuleDef = jitExpression( - res.expression, angularCoreEnv, `ng://${moduleType.name}/ngModuleDef.js`, []); + ngModuleDef = getCompilerFacade().compileNgModule( + angularCoreEnv, `ng://${moduleType.name}/ngModuleDef.js`, { + type: moduleType, + bootstrap: flatten(ngModule.bootstrap || EMPTY_ARRAY), + declarations: declarations, + imports: flatten(ngModule.imports || EMPTY_ARRAY).map(expandModuleWithProviders), + exports: flatten(ngModule.exports || EMPTY_ARRAY).map(expandModuleWithProviders), + emitInline: true, + }); } return ngModuleDef; - }, - // Make the property configurable in dev mode to allow overriding in tests - configurable: !!ngDevMode, + } }); let ngInjectorDef: any = null; Object.defineProperty(moduleType, NG_INJECTOR_DEF, { get: () => { if (ngInjectorDef === null) { - const meta: R3InjectorMetadata = { + const meta: R3InjectorMetadataFacade = { name: moduleType.name, - type: wrap(moduleType), + type: moduleType, deps: reflectDependencies(moduleType), - providers: new WrappedNodeExpr(ngModule.providers || EMPTY_ARRAY), - imports: new WrappedNodeExpr([ + providers: ngModule.providers || EMPTY_ARRAY, + imports: [ ngModule.imports || EMPTY_ARRAY, ngModule.exports || EMPTY_ARRAY, - ]), + ], }; - const res = compileInjector(meta); - ngInjectorDef = jitExpression( - res.expression, angularCoreEnv, `ng://${moduleType.name}/ngInjectorDef.js`, - res.statements); + ngInjectorDef = getCompilerFacade().compileInjector( + angularCoreEnv, `ng://${moduleType.name}/ngInjectorDef.js`, meta); } return ngInjectorDef; }, @@ -235,15 +225,6 @@ function expandModuleWithProviders(value: Type| ModuleWithProviders<{}>): T return value; } -function wrap(value: Type): Expression { - return new WrappedNodeExpr(value); -} - -function wrapReference(value: Type): R3Reference { - const wrapped = wrap(value); - return {value: wrapped, type: wrapped}; -} - function isModuleWithProviders(value: any): value is ModuleWithProviders<{}> { return (value as{ngModule?: any}).ngModule !== undefined; } diff --git a/packages/core/src/render3/jit/pipe.ts b/packages/core/src/render3/jit/pipe.ts index 1cbb26a684..01ef332667 100644 --- a/packages/core/src/render3/jit/pipe.ts +++ b/packages/core/src/render3/jit/pipe.ts @@ -6,13 +6,12 @@ * found in the LICENSE file at https://angular.io/license */ -import {WrappedNodeExpr, compilePipeFromMetadata, jitExpression} from '@angular/compiler'; - import {Pipe} from '../../metadata/directives'; import {Type} from '../../type'; import {NG_PIPE_DEF} from '../fields'; import {stringify} from '../util'; +import {getCompilerFacade} from './compiler_facade'; import {angularCoreEnv} from './environment'; import {reflectDependencies} from './util'; @@ -21,18 +20,14 @@ export function compilePipe(type: Type, meta: Pipe): void { Object.defineProperty(type, NG_PIPE_DEF, { get: () => { if (ngPipeDef === null) { - const sourceMapUrl = `ng://${stringify(type)}/ngPipeDef.js`; - - const name = type.name; - const res = compilePipeFromMetadata({ - name, - type: new WrappedNodeExpr(type), - deps: reflectDependencies(type), - pipeName: meta.name, - pure: meta.pure !== undefined ? meta.pure : true, - }); - - ngPipeDef = jitExpression(res.expression, angularCoreEnv, sourceMapUrl, res.statements); + ngPipeDef = getCompilerFacade().compilePipe( + angularCoreEnv, `ng://${stringify(type)}/ngPipeDef.js`, { + type: type, + name: type.name, + deps: reflectDependencies(type), + pipeName: meta.name, + pure: meta.pure !== undefined ? meta.pure : true + }); } return ngPipeDef; }, diff --git a/packages/core/src/render3/jit/util.ts b/packages/core/src/render3/jit/util.ts index 74a4840c2c..c46504baef 100644 --- a/packages/core/src/render3/jit/util.ts +++ b/packages/core/src/render3/jit/util.ts @@ -6,44 +6,41 @@ * found in the LICENSE file at https://angular.io/license */ -import {LiteralExpr, R3DependencyMetadata, R3ResolvedDependencyType, WrappedNodeExpr} from '@angular/compiler'; - -import {Injector} from '../../di/injector'; import {Host, Inject, Optional, Self, SkipSelf} from '../../di/metadata'; -import {ElementRef} from '../../linker/element_ref'; -import {TemplateRef} from '../../linker/template_ref'; -import {ViewContainerRef} from '../../linker/view_container_ref'; import {Attribute} from '../../metadata/di'; import {ReflectionCapabilities} from '../../reflection/reflection_capabilities'; import {Type} from '../../type'; +import {CompilerFacade, R3DependencyMetadataFacade, getCompilerFacade} from './compiler_facade'; + let _reflect: ReflectionCapabilities|null = null; export function getReflect(): ReflectionCapabilities { return (_reflect = _reflect || new ReflectionCapabilities()); } -export function reflectDependencies(type: Type): R3DependencyMetadata[] { +export function reflectDependencies(type: Type): R3DependencyMetadataFacade[] { return convertDependencies(getReflect().parameters(type)); } -export function convertDependencies(deps: any[]): R3DependencyMetadata[] { - return deps.map(dep => reflectDependency(dep)); +export function convertDependencies(deps: any[]): R3DependencyMetadataFacade[] { + const compiler = getCompilerFacade(); + return deps.map(dep => reflectDependency(compiler, dep)); } -function reflectDependency(dep: any | any[]): R3DependencyMetadata { - const meta: R3DependencyMetadata = { - token: new LiteralExpr(null), +function reflectDependency(compiler: CompilerFacade, dep: any | any[]): R3DependencyMetadataFacade { + const meta: R3DependencyMetadataFacade = { + token: null, host: false, optional: false, - resolved: R3ResolvedDependencyType.Token, + resolved: compiler.R3ResolvedDependencyType.Token, self: false, skipSelf: false, }; function setTokenAndResolvedType(token: any): void { - meta.resolved = R3ResolvedDependencyType.Token; - meta.token = new WrappedNodeExpr(token); + meta.resolved = compiler.R3ResolvedDependencyType.Token; + meta.token = token; } if (Array.isArray(dep)) { @@ -61,13 +58,13 @@ function reflectDependency(dep: any | any[]): R3DependencyMetadata { } else if (param instanceof Host || param.__proto__.ngMetadataName === 'Host') { meta.host = true; } else if (param instanceof Inject) { - meta.token = new WrappedNodeExpr(param.token); + meta.token = param.token; } else if (param instanceof Attribute) { if (param.attributeName === undefined) { throw new Error(`Attribute name must be defined.`); } - meta.token = new LiteralExpr(param.attributeName); - meta.resolved = R3ResolvedDependencyType.Attribute; + meta.token = param.attributeName; + meta.resolved = compiler.R3ResolvedDependencyType.Attribute; } else { setTokenAndResolvedType(param); } diff --git a/packages/core/test/bundling/animation_world/bundle.golden_symbols.json b/packages/core/test/bundling/animation_world/bundle.golden_symbols.json index bc9465b06f..01881d8832 100644 --- a/packages/core/test/bundling/animation_world/bundle.golden_symbols.json +++ b/packages/core/test/bundling/animation_world/bundle.golden_symbols.json @@ -54,7 +54,7 @@ "name": "EMPTY_ARR" }, { - "name": "EMPTY_ARRAY$1" + "name": "EMPTY_ARRAY" }, { "name": "EMPTY_OBJ" @@ -216,7 +216,7 @@ "name": "ViewContainerRef" }, { - "name": "ViewEncapsulation$1" + "name": "ViewEncapsulation" }, { "name": "ViewRef" @@ -396,7 +396,7 @@ "name": "createNodeAtIndex" }, { - "name": "createOutput$1" + "name": "createOutput" }, { "name": "createRootComponent" @@ -1122,10 +1122,10 @@ "name": "storeCleanupWithContext" }, { - "name": "stringify$1" + "name": "stringify" }, { - "name": "stringify$2" + "name": "stringify$1" }, { "name": "swapMultiContextEntries" diff --git a/packages/core/test/bundling/hello_world/BUILD.bazel b/packages/core/test/bundling/hello_world/BUILD.bazel index 2283f9775d..52f9b24e75 100644 --- a/packages/core/test/bundling/hello_world/BUILD.bazel +++ b/packages/core/test/bundling/hello_world/BUILD.bazel @@ -45,6 +45,7 @@ ts_library( ], deps = [ "//packages:types", + "//packages/compiler", "//packages/core/testing", "//packages/private/testing", ], diff --git a/packages/core/test/bundling/hello_world/bundle.golden_symbols.json b/packages/core/test/bundling/hello_world/bundle.golden_symbols.json index c2b73322a4..ccccc901c6 100644 --- a/packages/core/test/bundling/hello_world/bundle.golden_symbols.json +++ b/packages/core/test/bundling/hello_world/bundle.golden_symbols.json @@ -27,7 +27,7 @@ "name": "EMPTY" }, { - "name": "EMPTY_ARRAY$1" + "name": "EMPTY_ARRAY" }, { "name": "EmptyErrorImpl" @@ -117,7 +117,7 @@ "name": "VIEWS" }, { - "name": "ViewEncapsulation$1" + "name": "ViewEncapsulation" }, { "name": "_renderCompCount" @@ -438,7 +438,7 @@ "name": "setUpAttributes" }, { - "name": "stringify$2" + "name": "stringify$1" }, { "name": "syncViewWithBlueprint" diff --git a/packages/core/test/bundling/hello_world/treeshaking_spec.ts b/packages/core/test/bundling/hello_world/treeshaking_spec.ts index 9cd1469051..f4a76c7dc6 100644 --- a/packages/core/test/bundling/hello_world/treeshaking_spec.ts +++ b/packages/core/test/bundling/hello_world/treeshaking_spec.ts @@ -6,6 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ +import '@angular/compiler'; import {withBody} from '@angular/private/testing'; import * as fs from 'fs'; import * as path from 'path'; diff --git a/packages/core/test/bundling/hello_world_r2/BUILD.bazel b/packages/core/test/bundling/hello_world_r2/BUILD.bazel index 39fff073dd..a0a82e3ce5 100644 --- a/packages/core/test/bundling/hello_world_r2/BUILD.bazel +++ b/packages/core/test/bundling/hello_world_r2/BUILD.bazel @@ -47,6 +47,7 @@ ts_library( ], deps = [ "//packages:types", + "//packages/compiler", "//packages/core/testing", "//packages/private/testing", ], diff --git a/packages/core/test/bundling/hello_world_r2/bundle.golden_symbols.json b/packages/core/test/bundling/hello_world_r2/bundle.golden_symbols.json index a053553523..095ee683a5 100644 --- a/packages/core/test/bundling/hello_world_r2/bundle.golden_symbols.json +++ b/packages/core/test/bundling/hello_world_r2/bundle.golden_symbols.json @@ -240,7 +240,7 @@ "name": "BINDING_INDEX" }, { - "name": "BIND_NAME_REGEXP" + "name": "BIND_NAME_REGEXP$1" }, { "name": "BLOCK_PLACEHOLDER" @@ -813,16 +813,16 @@ "name": "IDENT" }, { - "name": "IDENT_BANANA_BOX_IDX" + "name": "IDENT_BANANA_BOX_IDX$1" }, { - "name": "IDENT_EVENT_IDX" + "name": "IDENT_EVENT_IDX$1" }, { - "name": "IDENT_KW_IDX" + "name": "IDENT_KW_IDX$1" }, { - "name": "IDENT_PROPERTY_IDX" + "name": "IDENT_PROPERTY_IDX$1" }, { "name": "ID_SEPARATOR" @@ -939,22 +939,22 @@ "name": "KEY_CONTEXT" }, { - "name": "KW_AT_IDX" + "name": "KW_AT_IDX$1" }, { - "name": "KW_BINDON_IDX" + "name": "KW_BINDON_IDX$1" }, { - "name": "KW_BIND_IDX" + "name": "KW_BIND_IDX$1" }, { - "name": "KW_LET_IDX" + "name": "KW_LET_IDX$1" }, { - "name": "KW_ON_IDX" + "name": "KW_ON_IDX$1" }, { - "name": "KW_REF_IDX" + "name": "KW_REF_IDX$1" }, { "name": "KeyVisitor" @@ -1116,7 +1116,7 @@ "name": "NG_TOKEN_PATH" }, { - "name": "NON_BINDABLE_VISITOR" + "name": "NON_BINDABLE_VISITOR$1" }, { "name": "NOOP" @@ -1209,7 +1209,7 @@ "name": "NodeInjectorFactory" }, { - "name": "NonBindableVisitor" + "name": "NonBindableVisitor$1" }, { "name": "NonNullAssert" @@ -1410,7 +1410,7 @@ "name": "RecurseVisitor" }, { - "name": "RecursiveAstVisitor" + "name": "RecursiveAstVisitor$1" }, { "name": "RefCountOperator" @@ -1629,7 +1629,7 @@ "name": "TAIL" }, { - "name": "TEMPLATE_ATTR_PREFIX" + "name": "TEMPLATE_ATTR_PREFIX$1" }, { "name": "TEXT_CSS_SELECTOR" @@ -1704,10 +1704,10 @@ "name": "Text" }, { - "name": "Text$1" + "name": "Text$2" }, { - "name": "Text$2" + "name": "Text$3" }, { "name": "TextAst" @@ -1770,7 +1770,7 @@ "name": "URL_WITH_SCHEMA_REGEXP" }, { - "name": "USE_VALUE$1" + "name": "USE_VALUE$2" }, { "name": "UnsubscriptionError" @@ -1782,7 +1782,7 @@ "name": "UrlResolver" }, { - "name": "VERSION$1" + "name": "VERSION" }, { "name": "VERSION$2" @@ -2151,7 +2151,7 @@ "name": "__read" }, { - "name": "__self" + "name": "__self$1" }, { "name": "__spread" @@ -2163,7 +2163,7 @@ "name": "__values" }, { - "name": "__window" + "name": "__window$1" }, { "name": "_addDebugContext" @@ -2283,7 +2283,7 @@ "name": "_getViewQueries" }, { - "name": "_global" + "name": "_global$1" }, { "name": "_isClosingComment" diff --git a/packages/core/test/bundling/hello_world_r2/treeshaking_spec.ts b/packages/core/test/bundling/hello_world_r2/treeshaking_spec.ts index 45ea9d78ce..9f9eedd375 100644 --- a/packages/core/test/bundling/hello_world_r2/treeshaking_spec.ts +++ b/packages/core/test/bundling/hello_world_r2/treeshaking_spec.ts @@ -6,6 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ +import '@angular/compiler'; import * as fs from 'fs'; import * as path from 'path'; diff --git a/packages/core/test/bundling/injection/BUILD.bazel b/packages/core/test/bundling/injection/BUILD.bazel index 2efe0be33a..005ed32931 100644 --- a/packages/core/test/bundling/injection/BUILD.bazel +++ b/packages/core/test/bundling/injection/BUILD.bazel @@ -48,6 +48,7 @@ ts_library( deps = [ ":injection", "//packages:types", + "//packages/compiler", "//packages/core/testing", "//packages/private/testing", ], diff --git a/packages/core/test/bundling/injection/bundle.golden_symbols.json b/packages/core/test/bundling/injection/bundle.golden_symbols.json index 98a5b5820e..394c3df49b 100644 --- a/packages/core/test/bundling/injection/bundle.golden_symbols.json +++ b/packages/core/test/bundling/injection/bundle.golden_symbols.json @@ -6,7 +6,7 @@ "name": "CIRCULAR$1" }, { - "name": "EMPTY_ARRAY$2" + "name": "EMPTY_ARRAY$1" }, { "name": "EmptyErrorImpl" @@ -60,7 +60,7 @@ "name": "THROW_IF_NOT_FOUND" }, { - "name": "USE_VALUE$1" + "name": "USE_VALUE" }, { "name": "UnsubscriptionErrorImpl" @@ -159,12 +159,12 @@ "name": "providerToRecord" }, { - "name": "resolveForwardRef$1" + "name": "resolveForwardRef" }, { "name": "setCurrentInjector" }, { - "name": "stringify$1" + "name": "stringify" } ] \ No newline at end of file diff --git a/packages/core/test/bundling/injection/treeshaking_spec.ts b/packages/core/test/bundling/injection/treeshaking_spec.ts index 8ff300a520..03a82172d0 100644 --- a/packages/core/test/bundling/injection/treeshaking_spec.ts +++ b/packages/core/test/bundling/injection/treeshaking_spec.ts @@ -6,15 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ -import * as fs from 'fs'; -import * as path from 'path'; - +import '@angular/compiler'; import {INJECTOR, ScopedService} from './usage'; -const UTF8 = { - encoding: 'utf-8' -}; -const PACKAGE = 'angular/packages/core/test/bundling/hello_world'; describe('functional test for injection system bundling', () => { it('should be able to inject the scoped service', diff --git a/packages/core/test/bundling/todo/BUILD.bazel b/packages/core/test/bundling/todo/BUILD.bazel index 814cf7653c..4a998a1590 100644 --- a/packages/core/test/bundling/todo/BUILD.bazel +++ b/packages/core/test/bundling/todo/BUILD.bazel @@ -50,6 +50,7 @@ ts_library( ], deps = [ "//packages:types", + "//packages/compiler", "//packages/core", "//packages/core/testing", "//packages/private/testing", diff --git a/packages/core/test/bundling/todo/bundle.golden_symbols.json b/packages/core/test/bundling/todo/bundle.golden_symbols.json index 21ecf48c5c..e80290b619 100644 --- a/packages/core/test/bundling/todo/bundle.golden_symbols.json +++ b/packages/core/test/bundling/todo/bundle.golden_symbols.json @@ -45,7 +45,7 @@ "name": "EMPTY" }, { - "name": "EMPTY_ARRAY$1" + "name": "EMPTY_ARRAY" }, { "name": "ElementRef" @@ -231,7 +231,7 @@ "name": "ViewContainerRef" }, { - "name": "ViewEncapsulation$1" + "name": "ViewEncapsulation" }, { "name": "ViewRef" @@ -453,7 +453,7 @@ "name": "createNodeAtIndex" }, { - "name": "createOutput$1" + "name": "createOutput" }, { "name": "createRootComponent" @@ -1143,10 +1143,10 @@ "name": "storeCleanupWithContext" }, { - "name": "stringify$1" + "name": "stringify" }, { - "name": "stringify$2" + "name": "stringify$1" }, { "name": "syncViewWithBlueprint" diff --git a/packages/core/test/bundling/todo/todo_e2e_spec.ts b/packages/core/test/bundling/todo/todo_e2e_spec.ts index b3d2d7896e..924210b50e 100644 --- a/packages/core/test/bundling/todo/todo_e2e_spec.ts +++ b/packages/core/test/bundling/todo/todo_e2e_spec.ts @@ -6,9 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ +import '@angular/compiler'; import {ɵwhenRendered as whenRendered} from '@angular/core'; import {withBody} from '@angular/private/testing'; -import * as fs from 'fs'; import * as path from 'path'; const UTF8 = { diff --git a/packages/core/test/bundling/todo_r2/BUILD.bazel b/packages/core/test/bundling/todo_r2/BUILD.bazel index 21777fb09d..c54d6affb5 100644 --- a/packages/core/test/bundling/todo_r2/BUILD.bazel +++ b/packages/core/test/bundling/todo_r2/BUILD.bazel @@ -54,6 +54,7 @@ ts_library( ], deps = [ "//packages:types", + "//packages/compiler", "//packages/core", "//packages/core/testing", "//packages/platform-browser", diff --git a/packages/core/test/bundling/todo_r2/bundle.golden_symbols.json b/packages/core/test/bundling/todo_r2/bundle.golden_symbols.json index 35900a82fc..7667eda429 100644 --- a/packages/core/test/bundling/todo_r2/bundle.golden_symbols.json +++ b/packages/core/test/bundling/todo_r2/bundle.golden_symbols.json @@ -99,13 +99,13 @@ "name": "COMPONENT_REGEX" }, { - "name": "COMPONENT_VARIABLE$1" + "name": "COMPONENT_VARIABLE" }, { "name": "CONTAINER_INDEX" }, { - "name": "CONTENT_ATTR$1" + "name": "CONTENT_ATTR" }, { "name": "CONTEXT" @@ -252,10 +252,10 @@ "name": "EMPTY$1" }, { - "name": "EMPTY_ARRAY$1" + "name": "EMPTY_ARRAY" }, { - "name": "EMPTY_ARRAY$2" + "name": "EMPTY_ARRAY$1" }, { "name": "EMPTY_PAYLOAD" @@ -330,7 +330,7 @@ "name": "HOST" }, { - "name": "HOST_ATTR$1" + "name": "HOST_ATTR" }, { "name": "HOST_NODE" @@ -792,7 +792,7 @@ "name": "SanitizingHtmlSerializer" }, { - "name": "SecurityContext$1" + "name": "SecurityContext" }, { "name": "Self" @@ -906,7 +906,7 @@ "name": "URL_RE" }, { - "name": "USE_VALUE$1" + "name": "USE_VALUE" }, { "name": "UnsubscriptionError" @@ -930,13 +930,13 @@ "name": "VOID_ELEMENTS" }, { - "name": "Version$1" + "name": "Version" }, { "name": "ViewContainerRef" }, { - "name": "ViewEncapsulation$1" + "name": "ViewEncapsulation" }, { "name": "ViewRef" @@ -1341,7 +1341,7 @@ "name": "createNodeAtIndex" }, { - "name": "createOutput$1" + "name": "createOutput" }, { "name": "createPlatform" @@ -2118,10 +2118,10 @@ "name": "isProceduralRenderer" }, { - "name": "isPromise$1" + "name": "isPromise" }, { - "name": "isPromise$2" + "name": "isPromise$1" }, { "name": "isRootView" @@ -2244,10 +2244,10 @@ "name": "noSideEffects" }, { - "name": "noop$2" + "name": "noop$1" }, { - "name": "noop$3" + "name": "noop$2" }, { "name": "noopScope" @@ -2274,7 +2274,7 @@ "name": "parseCookieValue" }, { - "name": "parseIntAutoRadix$1" + "name": "parseIntAutoRadix" }, { "name": "parseNumber" @@ -2400,7 +2400,7 @@ "name": "resolveDirectives" }, { - "name": "resolveForwardRef$1" + "name": "resolveForwardRef" }, { "name": "resolveProvider" @@ -2550,10 +2550,10 @@ "name": "strToNumber" }, { - "name": "stringify$1" + "name": "stringify" }, { - "name": "stringify$2" + "name": "stringify$1" }, { "name": "subscribeTo" diff --git a/packages/core/test/bundling/todo_r2/todo_e2e_spec.ts b/packages/core/test/bundling/todo_r2/todo_e2e_spec.ts index c3e38ea1d1..45133a50da 100644 --- a/packages/core/test/bundling/todo_r2/todo_e2e_spec.ts +++ b/packages/core/test/bundling/todo_r2/todo_e2e_spec.ts @@ -6,9 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ +import '@angular/compiler'; import {ɵwhenRendered as whenRendered} from '@angular/core'; import {withBody} from '@angular/private/testing'; -import * as fs from 'fs'; import * as path from 'path'; const UTF8 = { diff --git a/packages/core/test/render3/BUILD.bazel b/packages/core/test/render3/BUILD.bazel index 00d3de3f88..797e87702e 100644 --- a/packages/core/test/render3/BUILD.bazel +++ b/packages/core/test/render3/BUILD.bazel @@ -38,6 +38,7 @@ ts_library( "load_domino.ts", ], deps = [ + "//packages/compiler", "//packages/platform-browser", "//packages/platform-server", "@ngdeps//zone.js", diff --git a/packages/core/test/render3/compiler_canonical/back_patch_types_specs.ts b/packages/core/test/render3/compiler_canonical/back_patch_types_specs.ts deleted file mode 100644 index 28b0a35282..0000000000 --- a/packages/core/test/render3/compiler_canonical/back_patch_types_specs.ts +++ /dev/null @@ -1,138 +0,0 @@ -/** - * @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 {Component, ContentChild, Directive, Injectable, Injector, Input, NgModule, NgModuleFactory, NgModuleRef, OnDestroy, Optional, Pipe, PipeTransform, QueryList, SimpleChanges, TemplateRef, Type, ViewChild, ViewContainerRef, defineInjector} from '../../../src/core'; -import * as r3 from '../../../src/render3/index'; - -const details_elided = { - type: Object, -} as any; -export type $ComponentDef$ = any; - -/////////// -// Lib A - Compiled pre-Ivy -// "enableIvy": false -////////// - -// BEGIN FILE: node_modules/libA/module.ts (Compiled without Ivy) -@Component({}) -export class LibAComponent { -} - -@NgModule({declarations: [LibAComponent], imports: []}) -export class LibAModule { -} -// END FILE: node_modules/libA/module.ts -// BEGIN FILE: node_modules/libA/module.metadata.json -// Abridged version of metadata -const node_modules_libA_module_metadata = { - 'LibAModule': { - refs: ['LibAComponent'], - constructorDes: [], - }, - 'LibAComponent': { - constructorDes: [], - } -}; -// END FILE: node_modules/libA/module.metadata.json - - -/////////// -// Lib B - Compiled with Ivy -// "enableIvy": true -////////// - - -// BEGIN FILE: node_modules/libB/module.ts (Compiled with Ivy) -@Component({}) -export class LibBComponent { - // COMPILER GENERATED - static ngComponentDef: $ComponentDef$ = r3.defineComponent(details_elided); -} - -@NgModule({declarations: [LibAComponent], imports: []}) -export class LibBModule { - // COMPILER GENERATED - static ngInjectorDef = defineInjector(details_elided); -} -// END FILE: node_modules/libB/module.ts -// BEGIN FILE: node_modules/libB/module.metadata.json -// Abridged version of metadata -// Must still generate metadata in case it should be consumed with non-ivy application -// Must mark the metadata with `hasNgDef: true` so that Ivy knows to ignore it. -const node_modules_libB_module_metadata = { - 'LibBModule': {refs: ['LibBComponent'], constructorDes: [], hasNgDef: true}, - 'LibBComponent': {constructorDes: [], hasNgDef: true} -}; -// END FILE: node_modules/libA/module.metadata.json - - - -/////////// -// Lib B - Compiled with Ivy -// "enableIvy": true -// "enableIvyBackPatch": true -////////// - - -// BEGIN FILE: src/app.ts (Compiled with Ivy) -@Component({}) -export class AppComponent { - // COMPILER GENERATED - static ngComponentDef: $ComponentDef$ = r3.defineComponent(details_elided); -} - -@NgModule({declarations: [LibAComponent], imports: []}) -export class AppModule { - // COMPILER GENERATED - static ngInjectorDef = defineInjector(details_elided); -} -// END FILE: src/app.ts - -// BEGIN FILE: src/main.ts -// platformBrowserDynamic().bootstrapModule(AppModule); -// CLI rewrites it later to: -// platformBrowser().bootstrapModuleFactory(AppModuleFactory); -// END FILE: src/main.ts - -// BEGIN FILE: src/app.ngfactory.ts -function ngBackPatch_node_modules_libB_module() { - ngBackPatch_node_modules_libB_module_LibAComponent(); - ngBackPatch_node_modules_libB_module_LibAModule(); -} - -function ngBackPatch_node_modules_libB_module_LibAComponent() { - (LibAComponent as any).ngComponentDef = r3.defineComponent(details_elided); -} - -function ngBackPatch_node_modules_libB_module_LibAModule() { - (LibAModule as any).ngInjectorDef = defineInjector(details_elided); -} - -export const AppModuleFactory: NgModuleFactory&{patchedDeps: boolean} = { - moduleType: AppModule, - patchedDeps: false, create(parentInjector: Injector | null): NgModuleRef{ - if (!this.patchedDeps) { - ngBackPatch_node_modules_libB_module(); - this.patchedDeps = true; - } return details_elided; - } -}; -// BEGIN FILE: src/app.ngfactory.ts - - -// ISSUE: I don't think this works. The issue is that multiple modules get flattened into single -// module and hence we can't patch transitively. -// ISSUE: can non-ivy @NgModule import Ivy @NgModule? I assume no, since the flattening of modules -// happens during compilation. - -// BEGIN FILE: src/main.ts -// platformBrowserDynamic().bootstrapModule(AppModule); -// CLI rewrites it to: -// platformBrowser().bootstrapModuleFactory(AppModuleFactory); -// END FILE: src/main.ts diff --git a/packages/core/test/render3/compiler_canonical/patch_types_spec.ts b/packages/core/test/render3/compiler_canonical/patch_types_spec.ts deleted file mode 100644 index 85e42f5724..0000000000 --- a/packages/core/test/render3/compiler_canonical/patch_types_spec.ts +++ /dev/null @@ -1,78 +0,0 @@ -/** - * @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 {Component, ContentChild, Directive, Injectable, Input, NgModule, OnDestroy, Optional, Pipe, PipeTransform, QueryList, SimpleChanges, TemplateRef, Type, ViewChild, ViewContainerRef, defineInjectable, defineInjector} from '../../../src/core'; -import * as r3 from '../../../src/render3/index'; - - -/** - * GOALS: - * - Patch types in tree shakable way - * - Generate these types for files which have `metadata.json` (since those are the files which - * have not been compiled with Ivy) - * - Have build optimizer hoist the patch functions into corresponding types to allow tree-shaking. - */ - -// File: node_modules/some_library/path/public.ts -// Implies metadata: node_modules/some_library/path/public.metadata.json -// Assume: node_modules/some_library/index.js re-exports ./path/public.ts#ThirdPartyClass -@Injectable() -class ThirdPartyClass { -} - - -@Injectable() -class CompiledWithIvy { - // NORMATIVE - static ngInjectableDef = defineInjectable( - {factory: function CompileWithIvy_Factory() { return new CompiledWithIvy(); }}); - // /NORMATIVE -} - -// import { CompiledWithIvy } from 'some_library'; -@NgModule({providers: [ThirdPartyClass, CompiledWithIvy]}) -class CompiledWithIvyModule { - // NORMATIVE - static ngInjectorDef = defineInjector({ - providers: [ThirdPartyClass, CompiledWithIvy], - factory: function CompiledWithIvyModule_Factory() { return new CompiledWithIvyModule(); } - }); - // /NORMATIVE -} - -/** - * Below is a function which should be generated right next to the `@NgModule` which - * imports types which have `.metadata.json` files. - * - * # JIT Mode - * - Because the `ngPatch_CompiledWithIvyModule` is invoked all parts get patched. - * - * # AOT Mode - * - Build Optimizer detects `@__BUILD_OPTIMIZER_COLOCATE__` annotation and moves the - * code from the current location to the destination. - * - The resulting `ngPatch_CompiledWithIvyModule` becomes empty and eligible for tree-shaking. - * - Uglify removes the `ngPatch_CompiledWithIvyModule` since it is empty. - * - * # AOT Closure Mode - * - Option A: not supported. (Preferred option) - * - Externally very few people use closure they will just have to wait until all of their - * libraries are Ivy. - * - Internally (g3) we build from source hence everyone switches to Ivy at the same time. - * - Option B: Write a closure pass similar to Build Optimizer which would move the code. - */ -// NORMATIVE -ngPatch_depsOf_CompiledWithIvyModule(); -function ngPatch_depsOf_CompiledWithIvyModule() { - ngPatch_node_modules_some_library_path_public_CompileWithIvy(); -} -function ngPatch_node_modules_some_library_path_public_CompileWithIvy() { - /** @__BUILD_OPTIMIZER_COLOCATE__ */ - (ThirdPartyClass as any).ngInjectableDef = defineInjectable( - {factory: function CompileWithIvy_Factory() { return new ThirdPartyClass(); }}); -} -// /NORMATIVE diff --git a/packages/core/test/render3/compiler_canonical/small_app_spec.ts b/packages/core/test/render3/compiler_canonical/small_app_spec.ts index 683069b836..a241433383 100644 --- a/packages/core/test/render3/compiler_canonical/small_app_spec.ts +++ b/packages/core/test/render3/compiler_canonical/small_app_spec.ts @@ -109,7 +109,7 @@ class ToDoAppComponent { selector: 'todo', template: `
- + {{todo.text}}
diff --git a/packages/core/test/render3/ivy/jit_spec.ts b/packages/core/test/render3/ivy/jit_spec.ts index 21e9bfb2d5..d88c37c6dd 100644 --- a/packages/core/test/render3/ivy/jit_spec.ts +++ b/packages/core/test/render3/ivy/jit_spec.ts @@ -5,7 +5,6 @@ * 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 'reflect-metadata'; import {ElementRef, QueryList} from '@angular/core'; diff --git a/packages/core/test/render3/jit/directive_spec.ts b/packages/core/test/render3/jit/directive_spec.ts index 01d055c3c7..d0e4e9c6c5 100644 --- a/packages/core/test/render3/jit/directive_spec.ts +++ b/packages/core/test/render3/jit/directive_spec.ts @@ -88,8 +88,8 @@ describe('jit directive helper functions', () => { read: Directive }); - expect(converted.predicate).toEqual(jasmine.any(WrappedNodeExpr)); - expect(converted.read).toEqual(jasmine.any(WrappedNodeExpr)); + expect(converted.predicate).toEqual(Directive); + expect(converted.read).toEqual(Directive); }); }); diff --git a/packages/core/test/render3/load_domino.ts b/packages/core/test/render3/load_domino.ts index d8aeb80d3e..86b74c7d65 100644 --- a/packages/core/test/render3/load_domino.ts +++ b/packages/core/test/render3/load_domino.ts @@ -9,6 +9,7 @@ // Needed to run animation tests require('zone.js/dist/zone-node.js'); +import '@angular/compiler'; // For JIT mode. Must be in front of any other @angular/* imports. import {DominoAdapter} from '@angular/platform-server/src/domino_adapter'; import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter'; diff --git a/tools/testing/BUILD.bazel b/tools/testing/BUILD.bazel index c8a3c44a81..0af43b2a7a 100644 --- a/tools/testing/BUILD.bazel +++ b/tools/testing/BUILD.bazel @@ -7,6 +7,7 @@ ts_library( testonly = 1, srcs = ["init_browser_spec.ts"], deps = [ + "//packages/compiler", "//packages/core/testing", "//packages/platform-browser-dynamic/testing", "//packages/platform-browser/animations", @@ -18,6 +19,7 @@ ts_library( testonly = 1, srcs = ["init_node_spec.ts"], deps = [ + "//packages/compiler", "//packages/core/testing", "//packages/platform-server", "//packages/platform-server/testing", diff --git a/tools/testing/init_browser_spec.ts b/tools/testing/init_browser_spec.ts index 138328b734..ef158df3ef 100644 --- a/tools/testing/init_browser_spec.ts +++ b/tools/testing/init_browser_spec.ts @@ -6,6 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ +import '@angular/compiler'; // For JIT mode. Must be in front of any other @angular/* imports. import {TestBed} from '@angular/core/testing'; import {BrowserDynamicTestingModule, platformBrowserDynamicTesting} from '@angular/platform-browser-dynamic/testing'; import {NoopAnimationsModule} from '@angular/platform-browser/animations'; diff --git a/tools/testing/init_node_spec.ts b/tools/testing/init_node_spec.ts index 4af10e28e9..78a29fdcea 100644 --- a/tools/testing/init_node_spec.ts +++ b/tools/testing/init_node_spec.ts @@ -36,6 +36,7 @@ import 'zone.js/dist/jasmine-patch.js'; (global as any).isNode = true; (global as any).isBrowser = false; +import '@angular/compiler'; // For JIT mode. Must be in front of any other @angular/* imports. // Init TestBed import {TestBed} from '@angular/core/testing'; import {ServerTestingModule, platformServerTesting} from '@angular/platform-server/testing/src/server';