didi.umd.js 9.7 KB

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