Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

feat($injector): print caller name in "unknown provider" errors (when available) #ngEurope #9721

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions src/auto/injector.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ function annotate(fn, strictDi, name) {
* Return an instance of the service.
*
* @param {string} name The name of the instance to retrieve.
* @param {string} caller An optional string to provide the origin of the function call for error messages.
* @return {*} The instance.
*/

Expand Down Expand Up @@ -622,14 +623,17 @@ function createInjector(modulesToLoad, strictDi) {
}
},
providerInjector = (providerCache.$injector =
createInternalInjector(providerCache, function() {
createInternalInjector(providerCache, function(serviceName, caller) {
if (angular.isString(caller)) {
path.push(caller);
}
throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
})),
instanceCache = {},
instanceInjector = (instanceCache.$injector =
createInternalInjector(instanceCache, function(servicename) {
var provider = providerInjector.get(servicename + providerSuffix);
return instanceInjector.invoke(provider.$get, provider, undefined, servicename);
createInternalInjector(instanceCache, function(serviceName, caller) {
var provider = providerInjector.get(serviceName + providerSuffix, caller);
return instanceInjector.invoke(provider.$get, provider, undefined, serviceName);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neat!

}));


Expand Down Expand Up @@ -664,7 +668,7 @@ function createInjector(modulesToLoad, strictDi) {

function enforceReturnValue(name, factory) {
return function enforcedReturnValue() {
var result = instanceInjector.invoke(factory, this, undefined, name);
var result = instanceInjector.invoke(factory, this);
if (isUndefined(result)) {
throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name);
}
Expand Down Expand Up @@ -759,7 +763,7 @@ function createInjector(modulesToLoad, strictDi) {

function createInternalInjector(cache, factory) {

function getService(serviceName) {
function getService(serviceName, caller) {
if (cache.hasOwnProperty(serviceName)) {
if (cache[serviceName] === INSTANTIATING) {
throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
Expand All @@ -770,7 +774,7 @@ function createInjector(modulesToLoad, strictDi) {
try {
path.unshift(serviceName);
cache[serviceName] = INSTANTIATING;
return cache[serviceName] = factory(serviceName);
return cache[serviceName] = factory(serviceName, caller);
} catch (err) {
if (cache[serviceName] === INSTANTIATING) {
delete cache[serviceName];
Expand Down Expand Up @@ -802,7 +806,7 @@ function createInjector(modulesToLoad, strictDi) {
args.push(
locals && locals.hasOwnProperty(key)
? locals[key]
: getService(key)
: getService(key, serviceName)
);
}
if (isArray(fn)) {
Expand Down
20 changes: 19 additions & 1 deletion test/auto/injectorSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ describe('injector', function() {
var providers;
var injector;
var providerInjector;
var controllerProvider;

beforeEach(module(function($provide, $injector) {
beforeEach(module(function($provide, $injector, $controllerProvider) {
providers = function(name, factory, annotations) {
$provide.factory(name, extend(factory, annotations||{}));
};
providerInjector = $injector;
controllerProvider = $controllerProvider;
}));
beforeEach(inject(function($injector){
injector = $injector;
Expand Down Expand Up @@ -74,6 +76,22 @@ describe('injector', function() {
});


it('should provide the caller name if given', function(done) {
expect(function() {
injector.get('idontexist', 'callerName');
}).toThrowMinErr("$injector", "unpr", "Unknown provider: idontexistProvider <- idontexist <- callerName");
});


it('should provide the caller name for controllers', function(done) {
controllerProvider.register('myCtrl', function(idontexist) {});
var $controller = injector.get('$controller');
expect(function() {
$controller('myCtrl', {$scope: {}});
}).toThrowMinErr("$injector", "unpr", "Unknown provider: idontexistProvider <- idontexist <- myCtrl");
});


it('should not corrupt the cache when an object fails to get instantiated', function() {
expect(function() {
injector.get('idontexist');
Expand Down