diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/GOLDEN_PARTIAL.js b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/GOLDEN_PARTIAL.js new file mode 100644 index 0000000000..4b39181e10 --- /dev/null +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/GOLDEN_PARTIAL.js @@ -0,0 +1,373 @@ +/**************************************************************************************************** + * PARTIAL FILE: component_factory.js + ****************************************************************************************************/ +import { Attribute, Component, Host, Injectable, NgModule, Optional, Self, SkipSelf } from '@angular/core'; +import * as i0 from "@angular/core"; +export class MyService { +} +MyService.ɵfac = function MyService_Factory(t) { return new (t || MyService)(); }; +MyService.ɵprov = i0.ɵɵdefineInjectable({ token: MyService, factory: MyService.ɵfac }); +/*@__PURE__*/ (function () { i0.ɵsetClassMetadata(MyService, [{ + type: Injectable + }], null, null); })(); +export class MyComponent { + constructor(name, s1, s2, s4, s3, s5, s6) { } +} +MyComponent.ɵfac = function MyComponent_Factory(t) { return new (t || MyComponent)(i0.ɵɵinjectAttribute('name'), i0.ɵɵdirectiveInject(MyService), i0.ɵɵdirectiveInject(MyService, 1), i0.ɵɵdirectiveInject(MyService, 2), i0.ɵɵdirectiveInject(MyService, 4), i0.ɵɵdirectiveInject(MyService, 8), i0.ɵɵdirectiveInject(MyService, 10)); }; +MyComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: 1, type: MyComponent, selector: "my-component", ngImport: i0, template: { source: ``, isInline: true } }); +/*@__PURE__*/ (function () { i0.ɵsetClassMetadata(MyComponent, [{ + type: Component, + args: [{ selector: 'my-component', template: `` }] + }], function () { return [{ type: undefined, decorators: [{ + type: Attribute, + args: ['name'] + }] }, { type: MyService }, { type: MyService, decorators: [{ + type: Host + }] }, { type: MyService, decorators: [{ + type: Self + }] }, { type: MyService, decorators: [{ + type: SkipSelf + }] }, { type: MyService, decorators: [{ + type: Optional + }] }, { type: MyService, decorators: [{ + type: Self + }, { + type: Optional + }] }]; }, null); })(); +export class MyModule { +} +MyModule.ɵmod = i0.ɵɵdefineNgModule({ type: MyModule }); +MyModule.ɵinj = i0.ɵɵdefineInjector({ factory: function MyModule_Factory(t) { return new (t || MyModule)(); }, providers: [MyService] }); +(function () { (typeof ngJitMode === "undefined" || ngJitMode) && i0.ɵɵsetNgModuleScope(MyModule, { declarations: [MyComponent] }); })(); +/*@__PURE__*/ (function () { i0.ɵsetClassMetadata(MyModule, [{ + type: NgModule, + args: [{ declarations: [MyComponent], providers: [MyService] }] + }], null, null); })(); + +/**************************************************************************************************** + * PARTIAL FILE: component_factory.d.ts + ****************************************************************************************************/ +import * as i0 from "@angular/core"; +export declare class MyService { + static ɵfac: i0.ɵɵFactoryDef; + static ɵprov: i0.ɵɵInjectableDef; +} +export declare class MyComponent { + constructor(name: string, s1: MyService, s2: MyService, s4: MyService, s3: MyService, s5: MyService, s6: MyService); + static ɵfac: i0.ɵɵFactoryDef; + static ɵcmp: i0.ɵɵComponentDefWithMeta; +} +export declare class MyModule { + static ɵmod: i0.ɵɵNgModuleDefWithMeta; + static ɵinj: i0.ɵɵInjectorDef; +} + +/**************************************************************************************************** + * PARTIAL FILE: injectable_factory.js + ****************************************************************************************************/ +import { Injectable } from '@angular/core'; +import * as i0 from "@angular/core"; +class MyDependency { +} +export class MyService { + constructor(dep) { } +} +MyService.ɵfac = function MyService_Factory(t) { return new (t || MyService)(i0.ɵɵinject(MyDependency)); }; +MyService.ɵprov = i0.ɵɵdefineInjectable({ token: MyService, factory: MyService.ɵfac }); +/*@__PURE__*/ (function () { i0.ɵsetClassMetadata(MyService, [{ + type: Injectable + }], function () { return [{ type: MyDependency }]; }, null); })(); + +/**************************************************************************************************** + * PARTIAL FILE: injectable_factory.d.ts + ****************************************************************************************************/ +import * as i0 from "@angular/core"; +declare class MyDependency { +} +export declare class MyService { + constructor(dep: MyDependency); + static ɵfac: i0.ɵɵFactoryDef; + static ɵprov: i0.ɵɵInjectableDef; +} +export {}; + +/**************************************************************************************************** + * PARTIAL FILE: ctor_overload.js + ****************************************************************************************************/ +import { Injectable, Optional } from '@angular/core'; +import * as i0 from "@angular/core"; +class MyDependency { +} +class MyOptionalDependency { +} +export class MyService { + constructor(dep, optionalDep) { } +} +MyService.ɵfac = function MyService_Factory(t) { return new (t || MyService)(i0.ɵɵinject(MyDependency), i0.ɵɵinject(MyOptionalDependency, 8)); }; +MyService.ɵprov = i0.ɵɵdefineInjectable({ token: MyService, factory: MyService.ɵfac }); +/*@__PURE__*/ (function () { i0.ɵsetClassMetadata(MyService, [{ + type: Injectable + }], function () { return [{ type: MyDependency }, { type: MyOptionalDependency, decorators: [{ + type: Optional + }] }]; }, null); })(); + +/**************************************************************************************************** + * PARTIAL FILE: ctor_overload.d.ts + ****************************************************************************************************/ +import * as i0 from "@angular/core"; +declare class MyDependency { +} +export declare class MyService { + constructor(dep: MyDependency); + static ɵfac: i0.ɵɵFactoryDef; + static ɵprov: i0.ɵɵInjectableDef; +} +export {}; + +/**************************************************************************************************** + * PARTIAL FILE: usefactory_without_deps.js + ****************************************************************************************************/ +import { Injectable } from '@angular/core'; +import * as i0 from "@angular/core"; +class MyAlternateService { +} +function alternateFactory() { + return new MyAlternateService(); +} +export class MyService { +} +MyService.ɵfac = function MyService_Factory(t) { return new (t || MyService)(); }; +MyService.ɵprov = i0.ɵɵdefineInjectable({ token: MyService, factory: function () { return alternateFactory(); }, providedIn: 'root' }); +/*@__PURE__*/ (function () { i0.ɵsetClassMetadata(MyService, [{ + type: Injectable, + args: [{ providedIn: 'root', useFactory: alternateFactory }] + }], null, null); })(); + +/**************************************************************************************************** + * PARTIAL FILE: usefactory_without_deps.d.ts + ****************************************************************************************************/ +import * as i0 from "@angular/core"; +export declare class MyService { + static ɵfac: i0.ɵɵFactoryDef; + static ɵprov: i0.ɵɵInjectableDef; +} + +/**************************************************************************************************** + * PARTIAL FILE: usefactory_with_deps.js + ****************************************************************************************************/ +import { Injectable } from '@angular/core'; +import * as i0 from "@angular/core"; +class SomeDep { +} +class MyAlternateService { +} +export class MyService { +} +MyService.ɵfac = function MyService_Factory(t) { return new (t || MyService)(); }; +MyService.ɵprov = i0.ɵɵdefineInjectable({ token: MyService, factory: function MyService_Factory(t) { let r = null; if (t) { + r = new t(); + } + else { + r = (() => new MyAlternateService())(i0.ɵɵinject(SomeDep)); + } return r; }, providedIn: 'root' }); +/*@__PURE__*/ (function () { i0.ɵsetClassMetadata(MyService, [{ + type: Injectable, + args: [{ providedIn: 'root', useFactory: () => new MyAlternateService(), deps: [SomeDep] }] + }], null, null); })(); + +/**************************************************************************************************** + * PARTIAL FILE: usefactory_with_deps.d.ts + ****************************************************************************************************/ +import * as i0 from "@angular/core"; +export declare class MyService { + static ɵfac: i0.ɵɵFactoryDef; + static ɵprov: i0.ɵɵInjectableDef; +} + +/**************************************************************************************************** + * PARTIAL FILE: useclass_without_deps.js + ****************************************************************************************************/ +import { Injectable } from '@angular/core'; +import * as i0 from "@angular/core"; +class MyAlternateService { +} +MyAlternateService.ɵfac = function MyAlternateService_Factory(t) { return new (t || MyAlternateService)(); }; +MyAlternateService.ɵprov = i0.ɵɵdefineInjectable({ token: MyAlternateService, factory: MyAlternateService.ɵfac }); +/*@__PURE__*/ (function () { i0.ɵsetClassMetadata(MyAlternateService, [{ + type: Injectable + }], null, null); })(); +export class MyService { +} +MyService.ɵfac = function MyService_Factory(t) { return new (t || MyService)(); }; +MyService.ɵprov = i0.ɵɵdefineInjectable({ token: MyService, factory: function (t) { return MyAlternateService.ɵfac(t); }, providedIn: 'root' }); +/*@__PURE__*/ (function () { i0.ɵsetClassMetadata(MyService, [{ + type: Injectable, + args: [{ providedIn: 'root', useClass: MyAlternateService }] + }], null, null); })(); + +/**************************************************************************************************** + * PARTIAL FILE: useclass_without_deps.d.ts + ****************************************************************************************************/ +import * as i0 from "@angular/core"; +export declare class MyService { + static ɵfac: i0.ɵɵFactoryDef; + static ɵprov: i0.ɵɵInjectableDef; +} + +/**************************************************************************************************** + * PARTIAL FILE: useclass_with_deps.js + ****************************************************************************************************/ +import { Injectable } from '@angular/core'; +import * as i0 from "@angular/core"; +class SomeDep { +} +class MyAlternateService { +} +MyAlternateService.ɵfac = function MyAlternateService_Factory(t) { return new (t || MyAlternateService)(); }; +MyAlternateService.ɵprov = i0.ɵɵdefineInjectable({ token: MyAlternateService, factory: MyAlternateService.ɵfac }); +/*@__PURE__*/ (function () { i0.ɵsetClassMetadata(MyAlternateService, [{ + type: Injectable + }], null, null); })(); +export class MyService { +} +MyService.ɵfac = function MyService_Factory(t) { return new (t || MyService)(); }; +MyService.ɵprov = i0.ɵɵdefineInjectable({ token: MyService, factory: function MyService_Factory(t) { let r = null; if (t) { + r = new t(); + } + else { + r = new MyAlternateService(i0.ɵɵinject(SomeDep)); + } return r; }, providedIn: 'root' }); +/*@__PURE__*/ (function () { i0.ɵsetClassMetadata(MyService, [{ + type: Injectable, + args: [{ providedIn: 'root', useClass: MyAlternateService, deps: [SomeDep] }] + }], null, null); })(); + +/**************************************************************************************************** + * PARTIAL FILE: useclass_with_deps.d.ts + ****************************************************************************************************/ +import * as i0 from "@angular/core"; +export declare class MyService { + static ɵfac: i0.ɵɵFactoryDef; + static ɵprov: i0.ɵɵInjectableDef; +} + +/**************************************************************************************************** + * PARTIAL FILE: useclass_forwardref.js + ****************************************************************************************************/ +import { forwardRef, Injectable } from '@angular/core'; +import * as i0 from "@angular/core"; +class SomeProvider { +} +SomeProvider.ɵfac = function SomeProvider_Factory(t) { return new (t || SomeProvider)(); }; +SomeProvider.ɵprov = i0.ɵɵdefineInjectable({ token: SomeProvider, factory: function (t) { return SomeProviderImpl.ɵfac(t); }, providedIn: 'root' }); +/*@__PURE__*/ (function () { i0.ɵsetClassMetadata(SomeProvider, [{ + type: Injectable, + args: [{ providedIn: 'root', useClass: forwardRef(() => SomeProviderImpl) }] + }], null, null); })(); +class SomeProviderImpl extends SomeProvider { +} +SomeProviderImpl.ɵfac = function SomeProviderImpl_Factory(t) { return ɵSomeProviderImpl_BaseFactory(t || SomeProviderImpl); }; +SomeProviderImpl.ɵprov = i0.ɵɵdefineInjectable({ token: SomeProviderImpl, factory: SomeProviderImpl.ɵfac }); +const ɵSomeProviderImpl_BaseFactory = /*@__PURE__*/ i0.ɵɵgetInheritedFactory(SomeProviderImpl); +/*@__PURE__*/ (function () { i0.ɵsetClassMetadata(SomeProviderImpl, [{ + type: Injectable + }], null, null); })(); + +/**************************************************************************************************** + * PARTIAL FILE: useclass_forwardref.d.ts + ****************************************************************************************************/ +export {}; + +/**************************************************************************************************** + * PARTIAL FILE: pipe_and_injectable.js + ****************************************************************************************************/ +import { Component, Injectable, NgModule, Pipe } from '@angular/core'; +import * as i0 from "@angular/core"; +class Service { +} +Service.ɵfac = function Service_Factory(t) { return new (t || Service)(); }; +Service.ɵprov = i0.ɵɵdefineInjectable({ token: Service, factory: Service.ɵfac }); +/*@__PURE__*/ (function () { i0.ɵsetClassMetadata(Service, [{ + type: Injectable + }], null, null); })(); +export class MyPipe { + constructor(service) { } + transform(value, ...args) { + return value; + } +} +MyPipe.ɵfac = function MyPipe_Factory(t) { return new (t || MyPipe)(i0.ɵɵdirectiveInject(Service)); }; +MyPipe.ɵpipe = i0.ɵɵdefinePipe({ name: "myPipe", type: MyPipe, pure: true }); +MyPipe.ɵprov = i0.ɵɵdefineInjectable({ token: MyPipe, factory: MyPipe.ɵfac }); +/*@__PURE__*/ (function () { i0.ɵsetClassMetadata(MyPipe, [{ + type: Injectable + }, { + type: Pipe, + args: [{ name: 'myPipe' }] + }], function () { return [{ type: Service }]; }, null); })(); +export class MyOtherPipe { + constructor(service) { } + transform(value, ...args) { + return value; + } +} +MyOtherPipe.ɵfac = function MyOtherPipe_Factory(t) { return new (t || MyOtherPipe)(i0.ɵɵdirectiveInject(Service)); }; +MyOtherPipe.ɵpipe = i0.ɵɵdefinePipe({ name: "myOtherPipe", type: MyOtherPipe, pure: true }); +MyOtherPipe.ɵprov = i0.ɵɵdefineInjectable({ token: MyOtherPipe, factory: MyOtherPipe.ɵfac }); +/*@__PURE__*/ (function () { i0.ɵsetClassMetadata(MyOtherPipe, [{ + type: Pipe, + args: [{ name: 'myOtherPipe' }] + }, { + type: Injectable + }], function () { return [{ type: Service }]; }, null); })(); +export class MyApp { +} +MyApp.ɵfac = function MyApp_Factory(t) { return new (t || MyApp)(); }; +MyApp.ɵcmp = i0.ɵɵngDeclareComponent({ version: 1, type: MyApp, selector: "my-app", ngImport: i0, template: { source: '{{0 | myPipe | myOtherPipe}}', isInline: true }, pipes: { "myOtherPipe": MyOtherPipe, "myPipe": MyPipe } }); +/*@__PURE__*/ (function () { i0.ɵsetClassMetadata(MyApp, [{ + type: Component, + args: [{ selector: 'my-app', template: '{{0 | myPipe | myOtherPipe}}' }] + }], null, null); })(); +export class MyModule { +} +MyModule.ɵmod = i0.ɵɵdefineNgModule({ type: MyModule }); +MyModule.ɵinj = i0.ɵɵdefineInjector({ factory: function MyModule_Factory(t) { return new (t || MyModule)(); }, providers: [Service] }); +(function () { (typeof ngJitMode === "undefined" || ngJitMode) && i0.ɵɵsetNgModuleScope(MyModule, { declarations: [MyPipe, MyOtherPipe, MyApp] }); })(); +/*@__PURE__*/ (function () { i0.ɵsetClassMetadata(MyModule, [{ + type: NgModule, + args: [{ declarations: [MyPipe, MyOtherPipe, MyApp], providers: [Service] }] + }], null, null); })(); + +/**************************************************************************************************** + * PARTIAL FILE: pipe_and_injectable.d.ts + ****************************************************************************************************/ +import { PipeTransform } from '@angular/core'; +import * as i0 from "@angular/core"; +declare class Service { + static ɵfac: i0.ɵɵFactoryDef; + static ɵprov: i0.ɵɵInjectableDef; +} +export declare class MyPipe implements PipeTransform { + constructor(service: Service); + transform(value: any, ...args: any[]): any; + static ɵfac: i0.ɵɵFactoryDef; + static ɵpipe: i0.ɵɵPipeDefWithMeta; + static ɵprov: i0.ɵɵInjectableDef; +} +export declare class MyOtherPipe implements PipeTransform { + constructor(service: Service); + transform(value: any, ...args: any[]): any; + static ɵfac: i0.ɵɵFactoryDef; + static ɵpipe: i0.ɵɵPipeDefWithMeta; + static ɵprov: i0.ɵɵInjectableDef; +} +export declare class MyApp { + static ɵfac: i0.ɵɵFactoryDef; + static ɵcmp: i0.ɵɵComponentDefWithMeta; +} +export declare class MyModule { + static ɵmod: i0.ɵɵNgModuleDefWithMeta; + static ɵinj: i0.ɵɵInjectorDef; +} +export {}; + diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/TEST_CASES.json b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/TEST_CASES.json new file mode 100644 index 0000000000..7968fc1008 --- /dev/null +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/TEST_CASES.json @@ -0,0 +1,179 @@ +{ + "$schema": "../../test_case_schema.json", + "cases": [ + { + "description": "should create factory methods", + "inputFiles": [ + "component_factory.ts" + ], + "expectations": [ + { + "failureMessage": "Incorrect factory", + "files": [ + "component_factory.js" + ] + } + ] + }, + { + "description": "should create a factory definition for an injectable", + "inputFiles": [ + "injectable_factory.ts" + ], + "expectations": [ + { + "failureMessage": "Incorrect factory definition", + "files": [ + { + "expected": "injectable_factory_fac.js", + "generated": "injectable_factory.js" + } + ] + }, + { + "failureMessage": "Incorrect injectable definition", + "files": [ + { + "expected": "injectable_factory_prov.js", + "generated": "injectable_factory.js" + } + ] + } + ] + }, + { + "description": "should create a factory definition for an injectable with an overloaded constructor", + "inputFiles": [ + "ctor_overload.ts" + ], + "expectations": [ + { + "failureMessage": "Incorrect factory definition", + "files": [ + { + "expected": "ctor_overload_fac.js", + "generated": "ctor_overload.js" + } + ] + }, + { + "failureMessage": "Incorrect injectable definition", + "files": [ + { + "expected": "ctor_overload_prov.js", + "generated": "ctor_overload.js" + } + ] + } + ] + }, + { + "description": "should delegate directly to the alternate factory when setting `useFactory` without `deps`", + "inputFiles": [ + "usefactory_without_deps.ts" + ], + "expectations": [ + { + "failureMessage": "Incorrect injectable definition", + "files": [ + "usefactory_without_deps.js" + ] + } + ] + }, + { + "description": "should not delegate directly to the alternate factory when setting `useFactory` with `deps`", + "inputFiles": [ + "usefactory_with_deps.ts" + ], + "expectations": [ + { + "failureMessage": "Incorrect injectable definition", + "files": [ + "usefactory_with_deps.js" + ] + } + ] + }, + { + "description": "should delegate directly to the alternate class factory when setting `useClass` without `deps`", + "inputFiles": [ + "useclass_without_deps.ts" + ], + "expectations": [ + { + "failureMessage": "Incorrect factory definition", + "files": [ + "useclass_without_deps.js" + ] + } + ] + }, + { + "description": "should not delegate directly to the alternate class when setting `useClass` with `deps`", + "inputFiles": [ + "useclass_with_deps.ts" + ], + "expectations": [ + { + "failureMessage": "Incorrect factory definition", + "files": [ + "useclass_with_deps.js" + ] + } + ] + }, + { + "description": "should unwrap forward refs when delegating to a different class", + "inputFiles": [ + "useclass_forwardref.ts" + ], + "expectations": [ + { + "failureMessage": "Incorrect factory definition", + "files": [ + "useclass_forwardref.js" + ] + } + ] + }, + { + "description": "should have the pipe factory take precedence over the injectable factory, if a class has multiple decorators", + "inputFiles": [ + "pipe_and_injectable.ts" + ], + "expectations": [ + { + "failureMessage": "Invalid pipe factory function", + "files": [ + { + "expected": "pipe_and_injectable_pipe_last.js", + "generated": "pipe_and_injectable.js" + } + ], + "extraChecks": [ + [ + "verifyUniqueFactory", + "MyPipe" + ] + ] + }, + { + "failureMessage": "Invalid pipe factory function", + "files": [ + { + "expected": "pipe_and_injectable_pipe_first.js", + "generated": "pipe_and_injectable.js" + } + ], + "extraChecks": [ + [ + "verifyUniqueFactory", + "MyOtherPipe" + ] + ] + } + ] + } + ] +} diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/component_factory.js b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/component_factory.js new file mode 100644 index 0000000000..8fa4c3e930 --- /dev/null +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/component_factory.js @@ -0,0 +1,12 @@ + +MyComponent.ɵfac = function MyComponent_Factory(t) { + return new (t || MyComponent)( + $r3$.ɵɵinjectAttribute('name'), + $r3$.ɵɵdirectiveInject(MyService), + $r3$.ɵɵdirectiveInject(MyService, 1), + $r3$.ɵɵdirectiveInject(MyService, 2), + $r3$.ɵɵdirectiveInject(MyService, 4), + $r3$.ɵɵdirectiveInject(MyService, 8), + $r3$.ɵɵdirectiveInject(MyService, 10) + ); +} \ No newline at end of file diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/component_factory.ts b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/component_factory.ts new file mode 100644 index 0000000000..fa992ec008 --- /dev/null +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/component_factory.ts @@ -0,0 +1,22 @@ +import {Attribute, Component, Host, Injectable, NgModule, Optional, Self, SkipSelf} from '@angular/core'; + +@Injectable() +export class MyService { +} + +@Component({selector: 'my-component', template: ``}) +export class MyComponent { + constructor( + @Attribute('name') name: string, + s1: MyService, + @Host() s2: MyService, + @Self() s4: MyService, + @SkipSelf() s3: MyService, + @Optional() s5: MyService, + @Self() @Optional() s6: MyService, + ) {} +} + +@NgModule({declarations: [MyComponent], providers: [MyService]}) +export class MyModule { +} diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/ctor_overload.ts b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/ctor_overload.ts new file mode 100644 index 0000000000..ccbdc2cdf6 --- /dev/null +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/ctor_overload.ts @@ -0,0 +1,10 @@ +import {Injectable, Optional} from '@angular/core'; + +class MyDependency {} +class MyOptionalDependency {} + +@Injectable() +export class MyService { + constructor(dep: MyDependency); + constructor(dep: MyDependency, @Optional() optionalDep?: MyOptionalDependency) {} +} diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/ctor_overload_fac.js b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/ctor_overload_fac.js new file mode 100644 index 0000000000..465fb48a16 --- /dev/null +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/ctor_overload_fac.js @@ -0,0 +1,3 @@ +MyService.ɵfac = function MyService_Factory(t) { + return new (t || MyService)($r3$.ɵɵinject(MyDependency), $r3$.ɵɵinject(MyOptionalDependency, 8)); +} diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/ctor_overload_prov.js b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/ctor_overload_prov.js new file mode 100644 index 0000000000..1ee1909bb2 --- /dev/null +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/ctor_overload_prov.js @@ -0,0 +1,4 @@ +MyService.ɵprov = $r3$.ɵɵdefineInjectable({ + token: MyService, + factory: MyService.ɵfac +}); diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/injectable_factory.ts b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/injectable_factory.ts new file mode 100644 index 0000000000..ee10539855 --- /dev/null +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/injectable_factory.ts @@ -0,0 +1,8 @@ +import {Injectable} from '@angular/core'; + +class MyDependency {} + +@Injectable() +export class MyService { + constructor(dep: MyDependency) {} +} diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/injectable_factory_fac.js b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/injectable_factory_fac.js new file mode 100644 index 0000000000..f6c3dbe787 --- /dev/null +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/injectable_factory_fac.js @@ -0,0 +1,3 @@ +MyService.ɵfac = function MyService_Factory(t) { + return new (t || MyService)($r3$.ɵɵinject(MyDependency)); +} diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/injectable_factory_prov.js b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/injectable_factory_prov.js new file mode 100644 index 0000000000..1ee1909bb2 --- /dev/null +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/injectable_factory_prov.js @@ -0,0 +1,4 @@ +MyService.ɵprov = $r3$.ɵɵdefineInjectable({ + token: MyService, + factory: MyService.ɵfac +}); diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/pipe_and_injectable.ts b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/pipe_and_injectable.ts new file mode 100644 index 0000000000..8865aded71 --- /dev/null +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/pipe_and_injectable.ts @@ -0,0 +1,31 @@ +import {Component, Injectable, NgModule, Pipe, PipeTransform} from '@angular/core'; + +@Injectable() +class Service { +} + +@Injectable() +@Pipe({name: 'myPipe'}) +export class MyPipe implements PipeTransform { + constructor(service: Service) {} + transform(value: any, ...args: any[]) { + return value; + } +} + +@Pipe({name: 'myOtherPipe'}) +@Injectable() +export class MyOtherPipe implements PipeTransform { + constructor(service: Service) {} + transform(value: any, ...args: any[]) { + return value; + } +} + +@Component({selector: 'my-app', template: '{{0 | myPipe | myOtherPipe}}'}) +export class MyApp { +} + +@NgModule({declarations: [MyPipe, MyOtherPipe, MyApp], providers: [Service]}) +export class MyModule { +} diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/pipe_and_injectable_pipe_first.js b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/pipe_and_injectable_pipe_first.js new file mode 100644 index 0000000000..17ad44d0cf --- /dev/null +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/pipe_and_injectable_pipe_first.js @@ -0,0 +1,4 @@ +// NOTE The prov definition must be last so MyOtherPipe.fac is defined +MyOtherPipe.ɵfac = function MyOtherPipe_Factory(t) { return new (t || MyOtherPipe)($r3$.ɵɵdirectiveInject(Service)); }; +MyOtherPipe.ɵpipe = i0.ɵɵdefinePipe({ name: "myOtherPipe", type: MyOtherPipe, pure: true }); +MyOtherPipe.ɵprov = i0.ɵɵdefineInjectable({ token: MyOtherPipe, factory: MyOtherPipe.ɵfac }); diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/pipe_and_injectable_pipe_last.js b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/pipe_and_injectable_pipe_last.js new file mode 100644 index 0000000000..60855ff121 --- /dev/null +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/pipe_and_injectable_pipe_last.js @@ -0,0 +1,4 @@ +// NOTE The prov definition must be last so MyPipe.fac is defined +MyPipe.ɵfac = function MyPipe_Factory(t) { return new (t || MyPipe)(i0.ɵɵdirectiveInject(Service)); }; +MyPipe.ɵpipe = i0.ɵɵdefinePipe({ name: "myPipe", type: MyPipe, pure: true }); +MyPipe.ɵprov = i0.ɵɵdefineInjectable({ token: MyPipe, factory: MyPipe.ɵfac }); diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/useclass_forwardref.js b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/useclass_forwardref.js new file mode 100644 index 0000000000..c55e0f0fd7 --- /dev/null +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/useclass_forwardref.js @@ -0,0 +1,7 @@ +SomeProvider.ɵprov = $r3$.ɵɵdefineInjectable({ + token: SomeProvider, + factory: function(t) { + return SomeProviderImpl.ɵfac(t); + }, + providedIn: 'root' +}); diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/useclass_forwardref.ts b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/useclass_forwardref.ts new file mode 100644 index 0000000000..b2e58f9684 --- /dev/null +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/useclass_forwardref.ts @@ -0,0 +1,9 @@ +import {forwardRef, Injectable} from '@angular/core'; + +@Injectable({providedIn: 'root', useClass: forwardRef(() => SomeProviderImpl)}) +abstract class SomeProvider { +} + +@Injectable() +class SomeProviderImpl extends SomeProvider { +} diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/useclass_with_deps.js b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/useclass_with_deps.js new file mode 100644 index 0000000000..ba5c55a499 --- /dev/null +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/useclass_with_deps.js @@ -0,0 +1,13 @@ +MyService.ɵprov = $r3$.ɵɵdefineInjectable({ + token: MyService, + factory: function MyService_Factory(t) { + let r = null; + if (t) { + r = new t(); + } else { + r = new MyAlternateService($r3$.ɵɵinject(SomeDep)); + } + return r; + }, + providedIn: 'root' +}); diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/useclass_with_deps.ts b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/useclass_with_deps.ts new file mode 100644 index 0000000000..687bdf0247 --- /dev/null +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/useclass_with_deps.ts @@ -0,0 +1,11 @@ +import {Injectable} from '@angular/core'; + +class SomeDep {} + +@Injectable() +class MyAlternateService { +} + +@Injectable({providedIn: 'root', useClass: MyAlternateService, deps: [SomeDep]}) +export class MyService { +} diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/useclass_without_deps.js b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/useclass_without_deps.js new file mode 100644 index 0000000000..49c93b9752 --- /dev/null +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/useclass_without_deps.js @@ -0,0 +1,7 @@ +MyService.ɵprov = $r3$.ɵɵdefineInjectable({ + token: MyService, + factory: function(t) { + return MyAlternateService.ɵfac(t); + }, + providedIn: 'root' +}); diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/useclass_without_deps.ts b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/useclass_without_deps.ts new file mode 100644 index 0000000000..c0c6af10b0 --- /dev/null +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/useclass_without_deps.ts @@ -0,0 +1,9 @@ +import {Injectable} from '@angular/core'; + +@Injectable() +class MyAlternateService { +} + +@Injectable({providedIn: 'root', useClass: MyAlternateService}) +export class MyService { +} diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/usefactory_with_deps.js b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/usefactory_with_deps.js new file mode 100644 index 0000000000..8679010746 --- /dev/null +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/usefactory_with_deps.js @@ -0,0 +1,13 @@ +MyService.ɵprov = $r3$.ɵɵdefineInjectable({ + token: MyService, + factory: function MyService_Factory(t) { + let r = null; + if (t) { + r = new t(); + } else { + r = (() => new MyAlternateService())($r3$.ɵɵinject(SomeDep)); + } + return r; + }, + providedIn: 'root' +}); diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/usefactory_with_deps.ts b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/usefactory_with_deps.ts new file mode 100644 index 0000000000..c4821e3e6b --- /dev/null +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/usefactory_with_deps.ts @@ -0,0 +1,8 @@ +import {Injectable} from '@angular/core'; + +class SomeDep {} +class MyAlternateService {} + +@Injectable({providedIn: 'root', useFactory: () => new MyAlternateService(), deps: [SomeDep]}) +export class MyService { +} diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/usefactory_without_deps.js b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/usefactory_without_deps.js new file mode 100644 index 0000000000..5a23d004e1 --- /dev/null +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/usefactory_without_deps.js @@ -0,0 +1,7 @@ +MyService.ɵprov = $r3$.ɵɵdefineInjectable({ + token: MyService, + factory: function() { + return alternateFactory(); + }, + providedIn: 'root' +}); diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/usefactory_without_deps.ts b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/usefactory_without_deps.ts new file mode 100644 index 0000000000..d538ce18f0 --- /dev/null +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/usefactory_without_deps.ts @@ -0,0 +1,11 @@ +import {Injectable} from '@angular/core'; + +class MyAlternateService {} + +function alternateFactory() { + return new MyAlternateService(); +} + +@Injectable({providedIn: 'root', useFactory: alternateFactory}) +export class MyService { +} diff --git a/packages/compiler-cli/test/compliance/test_helpers/check_expectations.ts b/packages/compiler-cli/test/compliance/test_helpers/check_expectations.ts index 7fc6512675..9d49645775 100644 --- a/packages/compiler-cli/test/compliance/test_helpers/check_expectations.ts +++ b/packages/compiler-cli/test/compliance/test_helpers/check_expectations.ts @@ -8,6 +8,7 @@ import {FileSystem} from '../../../src/ngtsc/file_system'; import {getBuildOutputDirectory, getRootDirectory} from './compile_test'; +import {verifyUniqueFactory} from './di_checks'; import {expectEmit} from './expect_emit'; import {replaceMacros} from './expected_file_macros'; import {ExpectedFile, ExtraCheck} from './get_compliance_tests'; @@ -17,6 +18,7 @@ type ExtraCheckFunction = (generated: string, ...extraArgs: any[]) => boolean; const EXTRA_CHECK_FUNCTIONS: Record = { verifyPlaceholdersIntegrity, verifyUniqueConsts, + verifyUniqueFactory, }; /** diff --git a/packages/compiler-cli/test/compliance/test_helpers/di_checks.ts b/packages/compiler-cli/test/compliance/test_helpers/di_checks.ts new file mode 100644 index 0000000000..2c983dbc40 --- /dev/null +++ b/packages/compiler-cli/test/compliance/test_helpers/di_checks.ts @@ -0,0 +1,18 @@ +/** + * @license + * Copyright Google LLC 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 + */ + +/** + * Verifies that there is exactly one factory definition for the provided type. + */ +export function verifyUniqueFactory(output: string, type: string): boolean { + const matches = output.match(new RegExp(type + '\.ɵfac =', 'g')); + if (matches === null) { + return false; + } + return matches.length === 1; +}