|
| 1 | +module Angular.DI ( |
| 2 | + Dependency |
| 3 | + , Service |
| 4 | + , RootScope(..) |
| 5 | + , RootElement(..) |
| 6 | + , get |
| 7 | + , Injectable |
| 8 | + , Annotated() |
| 9 | + , annotate |
| 10 | + ) where |
| 11 | + |
| 12 | +import Control.Monad.Eff (Eff()) |
| 13 | +import Data.Function |
| 14 | +import Angular.Injector (Injector(), InjEff()) |
| 15 | +import Angular.Animate (Animate()) |
| 16 | +import Angular.Cache (CacheFactory()) |
| 17 | +import Angular.Http (Http()) |
| 18 | +import Angular.Interpolate (Interpolate()) |
| 19 | +import Angular.Interval (Interval()) |
| 20 | +import Angular.Location (Location()) |
| 21 | +import Angular.Log (Log()) |
| 22 | +import Angular.Parse (Parse()) |
| 23 | +import Angular.Q (Q()) |
| 24 | +import Angular.Timeout (Timeout()) |
| 25 | +import Angular.Scope (Scope()) |
| 26 | +import Angular.Element (Element()) |
| 27 | +import Angular.Attributes (Attributes()) |
| 28 | +import Angular.This (This()) |
| 29 | + |
| 30 | +-- | A type which can by provided by dependency injection. |
| 31 | +class Dependency a where |
| 32 | + name :: String |
| 33 | + |
| 34 | +-- | Services which can be retrieved with get |
| 35 | +class (Dependency a) <= Service a |
| 36 | + |
| 37 | +instance dependencyInjector :: Dependency Injector where |
| 38 | + name = "$injector" |
| 39 | +instance serviceInjector :: Service Injector |
| 40 | + |
| 41 | +instance dependencyAnimate :: Dependency Animate where |
| 42 | + name = "$animate" |
| 43 | +instance serviceAnimate :: Service Animate |
| 44 | + |
| 45 | +instance dependencyCacheFactory :: Dependency CacheFactory where |
| 46 | + name = "$cacheFactory" |
| 47 | +instance serviceCacheFactory :: Service CacheFactory |
| 48 | + |
| 49 | +instance dependencyHttp :: Dependency Http where |
| 50 | + name = "$http" |
| 51 | +instance serviceHttp :: Service Http |
| 52 | + |
| 53 | +instance dependencyInterpolate :: Dependency Interpolate where |
| 54 | + name = "$interpolate" |
| 55 | +instance serviceInterpolate :: Service Interpolate |
| 56 | + |
| 57 | +instance dependencyInterval :: Dependency Interval where |
| 58 | + name = "$interval" |
| 59 | +instance serviceInterval :: Service Interval |
| 60 | + |
| 61 | +instance dependencyLocation :: Dependency Location where |
| 62 | + name = "$location" |
| 63 | +instance serviceLocation :: Service Location |
| 64 | + |
| 65 | +instance dependencyLog :: Dependency Log where |
| 66 | + name = "$log" |
| 67 | +instance serviceLog :: Service Log |
| 68 | + |
| 69 | +instance dependencyParse :: Dependency Parse where |
| 70 | + name = "$parse" |
| 71 | +instance serviceParse :: Service Parse |
| 72 | + |
| 73 | +instance dependencyQ :: Dependency Q where |
| 74 | + name = "$q" |
| 75 | +instance serviceQ :: Service Q |
| 76 | + |
| 77 | +instance dependencyTimeout :: Dependency Timeout where |
| 78 | + name = "$timeout" |
| 79 | +instance serviceTimeout :: Service Timeout |
| 80 | + |
| 81 | +newtype RootScope a = RootScope (Scope a) |
| 82 | + |
| 83 | +instance dependencyRootScope :: Dependency (RootScope a) where |
| 84 | + name = "$rootScope" |
| 85 | +instance serviceRootScope :: Service (RootScope a) |
| 86 | + |
| 87 | +instance dependencyScope :: Dependency (Scope a) where |
| 88 | + name = "$scope" |
| 89 | + |
| 90 | +newtype RootElement = RootElement Element |
| 91 | + |
| 92 | +instance dependencyRootElement :: Dependency RootElement where |
| 93 | + name = "$rootElement" |
| 94 | +instance serviceRootElement :: Service RootElement |
| 95 | + |
| 96 | +instance dependencyElement :: Dependency Element where |
| 97 | + name = "$element" |
| 98 | + |
| 99 | +instance dependencyAttributes :: Dependency Attributes where |
| 100 | + name = "$attrs" |
| 101 | + |
| 102 | +instance dependencyThis :: Dependency (This a) where |
| 103 | + -- it would be nice to make a dummy service to avoid the special handling |
| 104 | + -- in annotate, but there is nowhere to do so |
| 105 | + name = "$this" |
| 106 | + |
| 107 | + |
| 108 | +foreign import getDependency |
| 109 | + "function get(dependency) {\ |
| 110 | + \ dependency = dependency.name;\ |
| 111 | + \ return function ($injector) {\ |
| 112 | + \ return function () {\ |
| 113 | + \ return $injector.get(dependency);\ |
| 114 | + \ };\ |
| 115 | + \ };\ |
| 116 | + \}" :: forall e a . (Dependency a) => Injector -> InjEff e a |
| 117 | + |
| 118 | +get :: forall e a . (Service a) => Injector -> InjEff e a |
| 119 | +get = getDependency |
| 120 | + |
| 121 | + |
| 122 | +class Injectable a where |
| 123 | + dependencies :: a -> [String] |
| 124 | + |
| 125 | +instance injectableEff :: Injectable (Eff e r) where |
| 126 | + dependencies _ = [] |
| 127 | + |
| 128 | +foreign import dependenciesFn |
| 129 | + "function dependenciesFn(dependency) {\ |
| 130 | + \ dependency = [dependency.name];\ |
| 131 | + \ return function (injectable) {\ |
| 132 | + \ return function (/*f*/) {\ |
| 133 | + \ return dependency.concat(injectable.dependencies(/*f(a)*/));\ |
| 134 | + \ };\ |
| 135 | + \ };\ |
| 136 | + \}" :: forall a b . (Dependency a, Injectable b) => (a -> b) -> [String] |
| 137 | + |
| 138 | +instance injectableFn :: (Dependency a, Injectable b) => Injectable (a -> b) where |
| 139 | + dependencies f = dependenciesFn f |
| 140 | + |
| 141 | + |
| 142 | +-- | An Eff function with added dependency injection annotations. |
| 143 | +foreign import data Annotated :: * -> * |
| 144 | + |
| 145 | +-- | Infer and annotate a function with its dependencies, that can provided by Injector.invoke or Module functions. |
| 146 | +foreign import annotate |
| 147 | + "function annotate(injectable) {\ |
| 148 | + \ return function (fun) {\ |
| 149 | + \ var inject = injectable.dependencies(fun);\ |
| 150 | + \ function g(/*...*/) {\ |
| 151 | + \ var f = fun;\ |
| 152 | + \ for (var i = 0, a = 0; i < inject.length; i++)\ |
| 153 | + \ f = f(inject[i] === '$this' ? this : arguments[a++]);\ |
| 154 | + \ return f();\ |
| 155 | + \ }\ |
| 156 | + \ g.prototype = fun.prototype;\ |
| 157 | + \ g.$inject = inject.filter(function (d) { return d !== '$this'; });\ |
| 158 | + \ return g;\ |
| 159 | + \ };\ |
| 160 | + \}" :: forall a . (Injectable a) => a -> Annotated a |
0 commit comments