index.js 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', { value: true });
  3. var CLASS_PATTERN = /^class /;
  4. function isClass(fn) {
  5. return CLASS_PATTERN.test(fn.toString());
  6. }
  7. function isArray(obj) {
  8. return Object.prototype.toString.call(obj) === '[object Array]';
  9. }
  10. function annotate() {
  11. var args = Array.prototype.slice.call(arguments);
  12. if (args.length === 1 && isArray(args[0])) {
  13. args = args[0];
  14. }
  15. var fn = args.pop();
  16. fn.$inject = args;
  17. return fn;
  18. }
  19. // Current limitations:
  20. // - can't put into "function arg" comments
  21. // function /* (no parenthesis like this) */ (){}
  22. // function abc( /* xx (no parenthesis like this) */ a, b) {}
  23. //
  24. // Just put the comment before function or inside:
  25. // /* (((this is fine))) */ function(a, b) {}
  26. // function abc(a) { /* (((this is fine))) */}
  27. //
  28. // - can't reliably auto-annotate constructor; we'll match the
  29. // first constructor(...) pattern found which may be the one
  30. // of a nested class, too.
  31. var CONSTRUCTOR_ARGS = /constructor\s*[^(]*\(\s*([^)]*)\)/m;
  32. var FN_ARGS = /^function\s*[^(]*\(\s*([^)]*)\)/m;
  33. var FN_ARG = /\/\*([^*]*)\*\//m;
  34. function parse(fn) {
  35. if (typeof fn !== 'function') {
  36. throw new Error('Cannot annotate "' + fn + '". Expected a function!');
  37. }
  38. var match = fn.toString().match(isClass(fn) ? CONSTRUCTOR_ARGS : FN_ARGS);
  39. // may parse class without constructor
  40. if (!match) {
  41. return [];
  42. }
  43. return match[1] && match[1].split(',').map(function (arg) {
  44. match = arg.match(FN_ARG);
  45. return match ? match[1].trim() : arg.trim();
  46. }) || [];
  47. }
  48. function Module() {
  49. var providers = [];
  50. this.factory = function (name, factory) {
  51. providers.push([name, 'factory', factory]);
  52. return this;
  53. };
  54. this.value = function (name, value) {
  55. providers.push([name, 'value', value]);
  56. return this;
  57. };
  58. this.type = function (name, type) {
  59. providers.push([name, 'type', type]);
  60. return this;
  61. };
  62. this.forEach = function (iterator) {
  63. providers.forEach(iterator);
  64. };
  65. }
  66. var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
  67. function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
  68. function Injector(modules, parent) {
  69. parent = parent || {
  70. get: function get(name, strict) {
  71. currentlyResolving.push(name);
  72. if (strict === false) {
  73. return null;
  74. } else {
  75. throw error('No provider for "' + name + '"!');
  76. }
  77. }
  78. };
  79. var currentlyResolving = [];
  80. var providers = this._providers = Object.create(parent._providers || null);
  81. var instances = this._instances = Object.create(null);
  82. var self = instances.injector = this;
  83. var error = function error(msg) {
  84. var stack = currentlyResolving.join(' -> ');
  85. currentlyResolving.length = 0;
  86. return new Error(stack ? msg + ' (Resolving: ' + stack + ')' : msg);
  87. };
  88. /**
  89. * Return a named service.
  90. *
  91. * @param {String} name
  92. * @param {Boolean} [strict=true] if false, resolve missing services to null
  93. *
  94. * @return {Object}
  95. */
  96. var get = function get(name, strict) {
  97. if (!providers[name] && name.indexOf('.') !== -1) {
  98. var parts = name.split('.');
  99. var pivot = get(parts.shift());
  100. while (parts.length) {
  101. pivot = pivot[parts.shift()];
  102. }
  103. return pivot;
  104. }
  105. if (hasProp(instances, name)) {
  106. return instances[name];
  107. }
  108. if (hasProp(providers, name)) {
  109. if (currentlyResolving.indexOf(name) !== -1) {
  110. currentlyResolving.push(name);
  111. throw error('Cannot resolve circular dependency!');
  112. }
  113. currentlyResolving.push(name);
  114. instances[name] = providers[name][0](providers[name][1]);
  115. currentlyResolving.pop();
  116. return instances[name];
  117. }
  118. return parent.get(name, strict);
  119. };
  120. var fnDef = function fnDef(fn) {
  121. var locals = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  122. if (typeof fn !== 'function') {
  123. if (isArray(fn)) {
  124. fn = annotate(fn.slice());
  125. } else {
  126. throw new Error('Cannot invoke "' + fn + '". Expected a function!');
  127. }
  128. }
  129. var inject = fn.$inject || parse(fn);
  130. var dependencies = inject.map(function (dep) {
  131. if (hasProp(locals, dep)) {
  132. return locals[dep];
  133. } else {
  134. return get(dep);
  135. }
  136. });
  137. return {
  138. fn: fn,
  139. dependencies: dependencies
  140. };
  141. };
  142. var instantiate = function instantiate(Type) {
  143. var _fnDef = fnDef(Type),
  144. dependencies = _fnDef.dependencies,
  145. fn = _fnDef.fn;
  146. return new (Function.prototype.bind.apply(fn, [null].concat(_toConsumableArray(dependencies))))();
  147. };
  148. var invoke = function invoke(func, context, locals) {
  149. var _fnDef2 = fnDef(func, locals),
  150. dependencies = _fnDef2.dependencies,
  151. fn = _fnDef2.fn;
  152. return fn.call.apply(fn, [context].concat(_toConsumableArray(dependencies)));
  153. };
  154. var createPrivateInjectorFactory = function createPrivateInjectorFactory(privateChildInjector) {
  155. return annotate(function (key) {
  156. return privateChildInjector.get(key);
  157. });
  158. };
  159. var createChild = function createChild(modules, forceNewInstances) {
  160. if (forceNewInstances && forceNewInstances.length) {
  161. var fromParentModule = Object.create(null);
  162. var matchedScopes = Object.create(null);
  163. var privateInjectorsCache = [];
  164. var privateChildInjectors = [];
  165. var privateChildFactories = [];
  166. var provider;
  167. var cacheIdx;
  168. var privateChildInjector;
  169. var privateChildInjectorFactory;
  170. for (var name in providers) {
  171. provider = providers[name];
  172. if (forceNewInstances.indexOf(name) !== -1) {
  173. if (provider[2] === 'private') {
  174. cacheIdx = privateInjectorsCache.indexOf(provider[3]);
  175. if (cacheIdx === -1) {
  176. privateChildInjector = provider[3].createChild([], forceNewInstances);
  177. privateChildInjectorFactory = createPrivateInjectorFactory(privateChildInjector);
  178. privateInjectorsCache.push(provider[3]);
  179. privateChildInjectors.push(privateChildInjector);
  180. privateChildFactories.push(privateChildInjectorFactory);
  181. fromParentModule[name] = [privateChildInjectorFactory, name, 'private', privateChildInjector];
  182. } else {
  183. fromParentModule[name] = [privateChildFactories[cacheIdx], name, 'private', privateChildInjectors[cacheIdx]];
  184. }
  185. } else {
  186. fromParentModule[name] = [provider[2], provider[1]];
  187. }
  188. matchedScopes[name] = true;
  189. }
  190. if ((provider[2] === 'factory' || provider[2] === 'type') && provider[1].$scope) {
  191. /* jshint -W083 */
  192. forceNewInstances.forEach(function (scope) {
  193. if (provider[1].$scope.indexOf(scope) !== -1) {
  194. fromParentModule[name] = [provider[2], provider[1]];
  195. matchedScopes[scope] = true;
  196. }
  197. });
  198. }
  199. }
  200. forceNewInstances.forEach(function (scope) {
  201. if (!matchedScopes[scope]) {
  202. throw new Error('No provider for "' + scope + '". Cannot use provider from the parent!');
  203. }
  204. });
  205. modules.unshift(fromParentModule);
  206. }
  207. return new Injector(modules, self);
  208. };
  209. var factoryMap = {
  210. factory: invoke,
  211. type: instantiate,
  212. value: function value(_value) {
  213. return _value;
  214. }
  215. };
  216. modules.forEach(function (module) {
  217. function arrayUnwrap(type, value) {
  218. if (type !== 'value' && isArray(value)) {
  219. value = annotate(value.slice());
  220. }
  221. return value;
  222. }
  223. // TODO(vojta): handle wrong inputs (modules)
  224. if (module instanceof Module) {
  225. module.forEach(function (provider) {
  226. var name = provider[0];
  227. var type = provider[1];
  228. var value = provider[2];
  229. providers[name] = [factoryMap[type], arrayUnwrap(type, value), type];
  230. });
  231. } else if ((typeof module === 'undefined' ? 'undefined' : _typeof(module)) === 'object') {
  232. if (module.__exports__) {
  233. var clonedModule = Object.keys(module).reduce(function (m, key) {
  234. if (key.substring(0, 2) !== '__') {
  235. m[key] = module[key];
  236. }
  237. return m;
  238. }, Object.create(null));
  239. var privateInjector = new Injector((module.__modules__ || []).concat([clonedModule]), self);
  240. var getFromPrivateInjector = annotate(function (key) {
  241. return privateInjector.get(key);
  242. });
  243. module.__exports__.forEach(function (key) {
  244. providers[key] = [getFromPrivateInjector, key, 'private', privateInjector];
  245. });
  246. } else {
  247. Object.keys(module).forEach(function (name) {
  248. if (module[name][2] === 'private') {
  249. providers[name] = module[name];
  250. return;
  251. }
  252. var type = module[name][0];
  253. var value = module[name][1];
  254. providers[name] = [factoryMap[type], arrayUnwrap(type, value), type];
  255. });
  256. }
  257. }
  258. });
  259. // public API
  260. this.get = get;
  261. this.invoke = invoke;
  262. this.instantiate = instantiate;
  263. this.createChild = createChild;
  264. }
  265. // helpers /////////////////
  266. function hasProp(obj, prop) {
  267. return Object.hasOwnProperty.call(obj, prop);
  268. }
  269. exports.annotate = annotate;
  270. exports.Module = Module;
  271. exports.Injector = Injector;