123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331 |
- var CLASS_PATTERN = /^class /;
- function isClass(fn) {
- return CLASS_PATTERN.test(fn.toString());
- }
- function isArray(obj) {
- return Object.prototype.toString.call(obj) === '[object Array]';
- }
- function annotate() {
- var args = Array.prototype.slice.call(arguments);
- if (args.length === 1 && isArray(args[0])) {
- args = args[0];
- }
- var fn = args.pop();
- fn.$inject = args;
- return fn;
- }
- // Current limitations:
- // - can't put into "function arg" comments
- // function /* (no parenthesis like this) */ (){}
- // function abc( /* xx (no parenthesis like this) */ a, b) {}
- //
- // Just put the comment before function or inside:
- // /* (((this is fine))) */ function(a, b) {}
- // function abc(a) { /* (((this is fine))) */}
- //
- // - can't reliably auto-annotate constructor; we'll match the
- // first constructor(...) pattern found which may be the one
- // of a nested class, too.
- var CONSTRUCTOR_ARGS = /constructor\s*[^(]*\(\s*([^)]*)\)/m;
- var FN_ARGS = /^function\s*[^(]*\(\s*([^)]*)\)/m;
- var FN_ARG = /\/\*([^*]*)\*\//m;
- function parse(fn) {
- if (typeof fn !== 'function') {
- throw new Error('Cannot annotate "' + fn + '". Expected a function!');
- }
- var match = fn.toString().match(isClass(fn) ? CONSTRUCTOR_ARGS : FN_ARGS);
- // may parse class without constructor
- if (!match) {
- return [];
- }
- return match[1] && match[1].split(',').map(function (arg) {
- match = arg.match(FN_ARG);
- return match ? match[1].trim() : arg.trim();
- }) || [];
- }
- function Module() {
- var providers = [];
- this.factory = function (name, factory) {
- providers.push([name, 'factory', factory]);
- return this;
- };
- this.value = function (name, value) {
- providers.push([name, 'value', value]);
- return this;
- };
- this.type = function (name, type) {
- providers.push([name, 'type', type]);
- return this;
- };
- this.forEach = function (iterator) {
- providers.forEach(iterator);
- };
- }
- 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; };
- 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); } }
- function Injector(modules, parent) {
- parent = parent || {
- get: function get(name, strict) {
- currentlyResolving.push(name);
- if (strict === false) {
- return null;
- } else {
- throw error('No provider for "' + name + '"!');
- }
- }
- };
- var currentlyResolving = [];
- var providers = this._providers = Object.create(parent._providers || null);
- var instances = this._instances = Object.create(null);
- var self = instances.injector = this;
- var error = function error(msg) {
- var stack = currentlyResolving.join(' -> ');
- currentlyResolving.length = 0;
- return new Error(stack ? msg + ' (Resolving: ' + stack + ')' : msg);
- };
- /**
- * Return a named service.
- *
- * @param {String} name
- * @param {Boolean} [strict=true] if false, resolve missing services to null
- *
- * @return {Object}
- */
- var get = function get(name, strict) {
- if (!providers[name] && name.indexOf('.') !== -1) {
- var parts = name.split('.');
- var pivot = get(parts.shift());
- while (parts.length) {
- pivot = pivot[parts.shift()];
- }
- return pivot;
- }
- if (hasProp(instances, name)) {
- return instances[name];
- }
- if (hasProp(providers, name)) {
- if (currentlyResolving.indexOf(name) !== -1) {
- currentlyResolving.push(name);
- throw error('Cannot resolve circular dependency!');
- }
- currentlyResolving.push(name);
- instances[name] = providers[name][0](providers[name][1]);
- currentlyResolving.pop();
- return instances[name];
- }
- return parent.get(name, strict);
- };
- var fnDef = function fnDef(fn) {
- var locals = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
- if (typeof fn !== 'function') {
- if (isArray(fn)) {
- fn = annotate(fn.slice());
- } else {
- throw new Error('Cannot invoke "' + fn + '". Expected a function!');
- }
- }
- var inject = fn.$inject || parse(fn);
- var dependencies = inject.map(function (dep) {
- if (hasProp(locals, dep)) {
- return locals[dep];
- } else {
- return get(dep);
- }
- });
- return {
- fn: fn,
- dependencies: dependencies
- };
- };
- var instantiate = function instantiate(Type) {
- var _fnDef = fnDef(Type),
- dependencies = _fnDef.dependencies,
- fn = _fnDef.fn;
- return new (Function.prototype.bind.apply(fn, [null].concat(_toConsumableArray(dependencies))))();
- };
- var invoke = function invoke(func, context, locals) {
- var _fnDef2 = fnDef(func, locals),
- dependencies = _fnDef2.dependencies,
- fn = _fnDef2.fn;
- return fn.call.apply(fn, [context].concat(_toConsumableArray(dependencies)));
- };
- var createPrivateInjectorFactory = function createPrivateInjectorFactory(privateChildInjector) {
- return annotate(function (key) {
- return privateChildInjector.get(key);
- });
- };
- var createChild = function createChild(modules, forceNewInstances) {
- if (forceNewInstances && forceNewInstances.length) {
- var fromParentModule = Object.create(null);
- var matchedScopes = Object.create(null);
- var privateInjectorsCache = [];
- var privateChildInjectors = [];
- var privateChildFactories = [];
- var provider;
- var cacheIdx;
- var privateChildInjector;
- var privateChildInjectorFactory;
- for (var name in providers) {
- provider = providers[name];
- if (forceNewInstances.indexOf(name) !== -1) {
- if (provider[2] === 'private') {
- cacheIdx = privateInjectorsCache.indexOf(provider[3]);
- if (cacheIdx === -1) {
- privateChildInjector = provider[3].createChild([], forceNewInstances);
- privateChildInjectorFactory = createPrivateInjectorFactory(privateChildInjector);
- privateInjectorsCache.push(provider[3]);
- privateChildInjectors.push(privateChildInjector);
- privateChildFactories.push(privateChildInjectorFactory);
- fromParentModule[name] = [privateChildInjectorFactory, name, 'private', privateChildInjector];
- } else {
- fromParentModule[name] = [privateChildFactories[cacheIdx], name, 'private', privateChildInjectors[cacheIdx]];
- }
- } else {
- fromParentModule[name] = [provider[2], provider[1]];
- }
- matchedScopes[name] = true;
- }
- if ((provider[2] === 'factory' || provider[2] === 'type') && provider[1].$scope) {
- /* jshint -W083 */
- forceNewInstances.forEach(function (scope) {
- if (provider[1].$scope.indexOf(scope) !== -1) {
- fromParentModule[name] = [provider[2], provider[1]];
- matchedScopes[scope] = true;
- }
- });
- }
- }
- forceNewInstances.forEach(function (scope) {
- if (!matchedScopes[scope]) {
- throw new Error('No provider for "' + scope + '". Cannot use provider from the parent!');
- }
- });
- modules.unshift(fromParentModule);
- }
- return new Injector(modules, self);
- };
- var factoryMap = {
- factory: invoke,
- type: instantiate,
- value: function value(_value) {
- return _value;
- }
- };
- modules.forEach(function (module) {
- function arrayUnwrap(type, value) {
- if (type !== 'value' && isArray(value)) {
- value = annotate(value.slice());
- }
- return value;
- }
- // TODO(vojta): handle wrong inputs (modules)
- if (module instanceof Module) {
- module.forEach(function (provider) {
- var name = provider[0];
- var type = provider[1];
- var value = provider[2];
- providers[name] = [factoryMap[type], arrayUnwrap(type, value), type];
- });
- } else if ((typeof module === 'undefined' ? 'undefined' : _typeof(module)) === 'object') {
- if (module.__exports__) {
- var clonedModule = Object.keys(module).reduce(function (m, key) {
- if (key.substring(0, 2) !== '__') {
- m[key] = module[key];
- }
- return m;
- }, Object.create(null));
- var privateInjector = new Injector((module.__modules__ || []).concat([clonedModule]), self);
- var getFromPrivateInjector = annotate(function (key) {
- return privateInjector.get(key);
- });
- module.__exports__.forEach(function (key) {
- providers[key] = [getFromPrivateInjector, key, 'private', privateInjector];
- });
- } else {
- Object.keys(module).forEach(function (name) {
- if (module[name][2] === 'private') {
- providers[name] = module[name];
- return;
- }
- var type = module[name][0];
- var value = module[name][1];
- providers[name] = [factoryMap[type], arrayUnwrap(type, value), type];
- });
- }
- }
- });
- // public API
- this.get = get;
- this.invoke = invoke;
- this.instantiate = instantiate;
- this.createChild = createChild;
- }
- // helpers /////////////////
- function hasProp(obj, prop) {
- return Object.hasOwnProperty.call(obj, prop);
- }
- export { annotate, Module, Injector };
|