import * as camelcase from 'camelcase' ; import * as decamelize from 'decamelize' ; import { Router } from '../../router-deprecated/router' ; import * as utils from './index' ; import * as host from '../utils/host' ; import * as injector from '../utils/injector' ; import * as input from '../utils/input' ; import * as output from '../utils/output' ; let map = { } ; const states = { } ; export function bootstrap ( ngModule , target , parentState ? ) { const annotations = target . __annotations__ ; const component = annotations . component ; const name = camelcase ( component . selector || target . name ) ; const styleElements = [ ] ; const headEl = angular . element ( document ) . find ( 'head' ) ; if ( map [ target . name ] ) { return name ; } map [ target . name ] = decamelize ( component . selector || target . name , '-' ) ; ( component . providers || [ ] ) . forEach ( provider => utils . bootstrap ( ngModule , provider ) ) ; ( component . directives || [ ] ) . forEach ( directive => utils . bootstrap ( ngModule , directive ) ) ; ( component . pipes || [ ] ) . forEach ( pipe => utils . bootstrap ( ngModule , pipe ) ) ; ( component . styles || [ ] ) . forEach ( style => { styleElements . push ( angular . element ( '<style type="text/css">@charset "UTF-8";' + style + '</style>' ) ) ; } ) ; ( component . styleUrls || [ ] ) . forEach ( url => { styleElements . push ( angular . element ( '<link rel="stylesheet" href="' + url + '">' ) ) ; } ) ; injector . inject ( ngModule , target ) ; const hostBindings = host . parse ( component . host || { } ) ; ngModule . controller ( target . name , target ) . directive ( name , [ '$rootScope' , '$compile' , ( $rootScope , $compile ) => { const directive = { restrict : 'E' , scope : { } , bindToController : { } , controller : target . name , controllerAs : component . exportAs || '$ctrl' , transclude : true , compile : ( ) => { return { pre : ( scope , el ) => { styleElements . forEach ( el => headEl . prepend ( el ) ) ; host . bind ( scope , el , hostBindings , component . controllerAs ) ; if ( target . prototype . ngOnInit ) { const init = $compile ( `<div ng-init="${ directive . controllerAs }.ngOnInit();"></div>` ) ( scope ) ; el . append ( init ) ; } scope . $on ( '$destroy' , ( ) => { styleElements . forEach ( el => el . remove ( ) ) ; if ( target . prototype . ngOnDestroy ) { scope [ directive . controllerAs ] . ngOnDestroy ( ) ; } } ) ; } } ; } } ; input . bind ( target , directive ) ; output . bind ( $rootScope , target , directive ) ; if ( component . template ) { directive . template = component . template ; } else { directive . templateUrl = component . templateUrl ; } return directive ; } ] ) ; if ( annotations . routes ) { const cmpStates = [ ] ; annotations . routes . forEach ( route => { const name = route . name || route . as ; const routerAnnotations = route . component . __annotations__ && route . component . __annotations__ . router ; const state = { name , url : route . path , isDefault : route . useAsDefault === true } ; if ( route . component . name !== target . name ) { bootstrap ( ngModule , route . component , state ) ; } if ( state . url . substr ( - 4 ) === '/...' ) { state . url = state . url . substr ( 0 , state . url . length - 4 ) ; state . abstract = true ; } if ( parentState && parentState . url && parentState . url . substr ( - 4 ) === '/...' ) { state . parent = parentState . name ; } state . template = `<${ map [ route . component . name ] }></${ map [ route . component . name ] }>` ; cmpStates . push ( state . name ) ; states [ name ] = state ; if ( routerAnnotations && routerAnnotations . canActivate ) { const hook = [ 'Router' , '$state' , '$stateParams' ] ; if ( Object . keys ( routerAnnotations . canActivate . prototype ) . length > 0 ) { if ( ! routerAnnotations . canActivate . prototype . routerCanActivate ) { throw new Error ( '@CanActivate class does not implement the `CanActivate` interface.' ) ; } hook . push ( utils . bootstrap ( ngModule , routerAnnotations . canActivate ) ) ; } hook . push ( ( router , $state , $stateParams , handler ) => { const fn = handler ? handler . routerCanActivate : routerAnnotations . canActivate ; return Promise . all ( [ router . generate ( [ name , $stateParams ] ) , $state . current . name . length === 0 ? null : router . generate ( [ $state . current . name , $state . params ] ) ] ) . then ( instructions => { return Promise . resolve ( fn . apply ( handler , instructions ) ) ; } ) . then ( result => { if ( ! result ) { return Promise . reject ( 'could not activate' ) ; } } ) ; } ) ; states [ name ] . resolve = { routerCanActivate : hook } ; } } ) ; ngModule . config ( [ '$urlRouterProvider' , '$stateProvider' , ( $urlRouterProvider , $stateProvider ) => { cmpStates . forEach ( name => { const state = states [ name ] ; $stateProvider . state ( name , state ) ; if ( state . isDefault ) { if ( state . parent ) { let parentState = states [ state . parent ] ; let from = parentState . url ; while ( parentState . parent ) { parentState = states [ parentState . parent ] ; from = parentState . url + from ; } $urlRouterProvider . when ( from , from + state . url ) ; } else { $urlRouterProvider . otherwise ( state . url ) ; } } } ) ; } ] ) ; } return name ; }