Skip to content

Commit

Permalink
feat(upgrade): Update NgMetadataUpgradeAdapter to support NgModule
Browse files Browse the repository at this point in the history
BREAKING CHANGE: NgMetadataUpgradeAdapter now accepts an already
instantiated @angular/upgrade UpgradeAdapter, which will have been
created using an Angular 2 NgModule.

**Before:**
```ts
import { NgMetadataUpgradeAdapter } from 'ng-metadata/upgrade'
import { UpgradeAdapter } from '@angular/upgrade'
import { Component } from 'ng-metadata/core'

const angular1Module = angular.module('ng1Module', [])

@component({
  selector: 'app'
})
class AppComponent {}

const upgradeAdapter = new NgMetadataUpgradeAdapter(UpgradeAdapter)

upgradeAdapter.bootstrap(AppComponent, ['ng1Module'])
```

**After:**
```ts
import { NgMetadataUpgradeAdapter } from 'ng-metadata/upgrade'
import { UpgradeAdapter } from '@angular/upgrade'
import { NgModule } from '@angular/core'

const angular1Module = angular.module('ng1Module', [])

@NgModule({
  selector: 'ng2'
})
class Ng2Module {}

const upgradeAdapter = new NgMetadataUpgradeAdapter( new
UpgradeAdapter(Ng2Module) )

upgradeAdapter.boostrap(document.body, ['ng1Module'])
```
  • Loading branch information
JamesHenry committed Sep 19, 2016
1 parent ed1c326 commit 0a81c13
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 86 deletions.
33 changes: 1 addition & 32 deletions src/upgrade/upgrade.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1 @@
/**
* `UgradeAdapterRef` controls a hybrid AngularJS v1 / Angular v2 application,
* but we don't have a use for it right now so no point in creating an interface for it...
*/
export type UgradeAdapterRef = void;

export interface UpgradeAdapter {
new (): UpgradeAdapterInstance;
}

export interface UpgradeAdapterInstance {
/**
* Allows Angular v2 Component to be used from AngularJS v1.
*/
downgradeNg2Component(type: Type): Function;
/**
* Bootstrap a hybrid AngularJS v1 / Angular v2 application.
*/
bootstrap(element: Element, modules?: any[], config?: angular.IAngularBootstrapConfig): UgradeAdapterRef;
/**
* Adds a provider to the top level environment of a hybrid AngularJS v1 / Angular v2 application.
*/
addProvider(provider: Type | any[] | any): void;
/**
* Allows Angular v2 service to be accessible from AngularJS v1.
*/
downgradeNg2Provider(token: any): Function;
/**
* Allows AngularJS v1 service to be accessible from Angular v2.
*/
upgradeNg1Provider(name: string, options?: { asToken: any; }): void;
}
export { NgMetadataUpgradeAdapter } from './upgrade_adapter';
57 changes: 32 additions & 25 deletions src/upgrade/upgrade_adapter.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,43 @@
import { UpgradeAdapter, UpgradeAdapterInstance } from './upgrade';
// import { createBootstrapFn } from '../platform/browser_utils';
import { reflector } from '../core/reflection/reflection';
import { getInjectableName, OpaqueToken } from '../core/di';
import { ProviderLiteral } from '../core/di/provider_util';
import { resolveDirectiveNameFromSelector } from '../facade/lang';

export class NgMetadataUpgradeAdapter {
/**
* `UpgradeAdapterRef` controls a hybrid AngularJS v1 / Angular v2 application,
* but we don't have a use for it right now so no point in creating an interface for it...
*/
export type UpgradeAdapterRef = void;

export interface UpgradeAdapterInstance {
/**
* Allows Angular v2 Component to be used from AngularJS v1.
*/
downgradeNg2Component(type: Type): Function;
/**
* Bootstrap a hybrid AngularJS v1 / Angular v2 application.
*/
bootstrap(element: Element, modules?: any[], config?: angular.IAngularBootstrapConfig): UpgradeAdapterRef;
/**
* Allows Angular v2 service to be accessible from AngularJS v1.
*/
downgradeNg2Provider(token: any): Function;
/**
* Allows AngularJS v1 service to be accessible from Angular v2.
*/
upgradeNg1Provider(name: string, options?: { asToken: any; }): void;
}

bootstrap: Function;
export interface UpgradeAdapter {
new (ng2AppModule: Type): UpgradeAdapterInstance;
}

_upgradeAdapter: UpgradeAdapterInstance;
export class NgMetadataUpgradeAdapter {

constructor( UpgradeAdapter: UpgradeAdapter ) {
/**
* Manage the @angular/upgrade singleton
*/
this._upgradeAdapter = new UpgradeAdapter();
/**
* Used to bootstrap a hybrid Angular 1 and Angular 2 application,
* using the same signature as `bootstrap` from ng-metadata/platform-browser-dynamic
*
* E.g. `upgradeAdapter.bootstrap(AppComponent, providers)`
*/
// this.bootstrap = createBootstrapFn(this._upgradeAdapter.bootstrap.bind(this._upgradeAdapter));
}
/**
* Store a reference to the instantiated upgradeAdapter
*/
constructor( public _upgradeAdapter: UpgradeAdapterInstance ) {}

/**
* Used to register an Angular 2 component as a directive on an Angular 1 module,
Expand Down Expand Up @@ -56,13 +70,6 @@ export class NgMetadataUpgradeAdapter {
return directiveFactory;
}

/**
* Adds an Angular 2 provider to the hybrid application.
*/
addProvider( provider: Type | any[] | any ): void {
return this._upgradeAdapter.addProvider( provider );
}

/**
* Downgrades an Angular 2 Provider so that it can be registered as an Angular 1
* factory. Either a string or an ng-metadata OpaqueToken can be used for the name.
Expand Down
43 changes: 14 additions & 29 deletions test/upgrade/upgrade_adapter.spec.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import { expect } from 'chai';
import * as sinon from 'sinon';
import { NgMetadataUpgradeAdapter } from '../../src/upgrade/upgrade_adapter'
import { Component, OpaqueToken, getInjectableName } from '../../core'
import { Component, OpaqueToken, getInjectableName, NgModule } from '../../core'
import { reflector } from '../../src/core/reflection/reflection';

class MockAngularUpgradeAdapter {
constructor(ngModule: Type) {}
bootstrap(element: Element, modules?: any[], config?: angular.IAngularBootstrapConfig): void {
return void 0
}
addProvider(provider: Type | any[] | any): void {
return void 0
}
downgradeNg2Provider(token: any): Function {
return (() => {})
}
Expand All @@ -22,46 +20,33 @@ class MockAngularUpgradeAdapter {
}
}

let instantiatedNgUpgradeAdapter: MockAngularUpgradeAdapter
let upgradeAdapter: NgMetadataUpgradeAdapter

describe( `upgrade`, () => {

describe( `NgMetadataUpgradeAdapter`, () => {

let sandbox: Sinon.SinonSandbox;
beforeEach( () => {
sandbox = sinon.sandbox.create();
} );
afterEach( () => {
sandbox.restore();
} );

beforeEach( () => {
upgradeAdapter = new NgMetadataUpgradeAdapter( MockAngularUpgradeAdapter );
} )

afterEach( () => {
sandbox.restore();
} );

it( `should set the internal _upgradeAdapter singleton`, () => {
expect( JSON.stringify( upgradeAdapter._upgradeAdapter ) ).to.equal( JSON.stringify( new MockAngularUpgradeAdapter() ) );
} );

describe( `#addProvider`, () => {

it( `should call the internal adapter's addProvider() method with the given provider`, () => {

sandbox.spy( upgradeAdapter._upgradeAdapter, 'addProvider' );
sandbox = sinon.sandbox.create();

class Ng2Provider {}
@NgModule({})
class AppModule {}

upgradeAdapter.addProvider( Ng2Provider );
instantiatedNgUpgradeAdapter = new MockAngularUpgradeAdapter(AppModule)
upgradeAdapter = new NgMetadataUpgradeAdapter(instantiatedNgUpgradeAdapter)

expect( (upgradeAdapter._upgradeAdapter.addProvider as Sinon.SinonSpy).calledWith( Ng2Provider ) ).to.equal( true );
} );

} );
afterEach( () => {
sandbox.restore();
} );

it( `should store a reference to the given upgradeAdapter singleton`, () => {
expect( JSON.stringify( upgradeAdapter._upgradeAdapter ) ).to.equal( JSON.stringify( instantiatedNgUpgradeAdapter ) );
} );

describe( `#upgradeNg1Provider`, () => {
Expand Down

0 comments on commit 0a81c13

Please sign in to comment.