@@ -111,8 +111,9 @@ export class R3Injector {
111
111
const dedupStack : InjectorType < any > [ ] = [ ] ;
112
112
deepForEach ( [ def ] , injectorDef => this . processInjectorType ( injectorDef , [ ] , dedupStack ) ) ;
113
113
114
- additionalProviders &&
115
- deepForEach ( additionalProviders , provider => this . processProvider ( provider ) ) ;
114
+ additionalProviders && deepForEach (
115
+ additionalProviders , provider => this . processProvider (
116
+ provider , def , additionalProviders ) ) ;
116
117
117
118
118
119
// Make sure the INJECTOR token provides this injector.
@@ -270,25 +271,31 @@ export class R3Injector {
270
271
}
271
272
272
273
// Next, include providers listed on the definition itself.
273
- if ( def . providers != null && ! isDuplicate ) {
274
- deepForEach ( def . providers , provider => this . processProvider ( provider ) ) ;
274
+ const defProviders = def . providers ;
275
+ if ( defProviders != null && ! isDuplicate ) {
276
+ const injectorType = defOrWrappedDef as InjectorType < any > ;
277
+ deepForEach (
278
+ defProviders , provider => this . processProvider ( provider , injectorType , defProviders ) ) ;
275
279
}
276
280
277
281
// Finally, include providers from an InjectorDefTypeWithProviders if there was one.
278
- deepForEach ( providers , provider => this . processProvider ( provider ) ) ;
282
+ const ngModuleType = ( defOrWrappedDef as InjectorTypeWithProviders < any > ) . ngModule ;
283
+ deepForEach ( providers , provider => this . processProvider ( provider , ngModuleType , providers ) ) ;
279
284
}
280
285
281
286
/**
282
287
* Process a `SingleProvider` and add it.
283
288
*/
284
- private processProvider ( provider : SingleProvider ) : void {
289
+ private processProvider (
290
+ provider : SingleProvider , ngModuleType : InjectorType < any > , providers : any [ ] ) : void {
285
291
// Determine the token from the provider. Either it's its own token, or has a {provide: ...}
286
292
// property.
287
293
provider = resolveForwardRef ( provider ) ;
288
- let token : any = isTypeProvider ( provider ) ? provider : resolveForwardRef ( provider . provide ) ;
294
+ let token : any =
295
+ isTypeProvider ( provider ) ? provider : resolveForwardRef ( provider && provider . provide ) ;
289
296
290
297
// Construct a `Record` for the provider.
291
- const record = providerToRecord ( provider ) ;
298
+ const record = providerToRecord ( provider , ngModuleType , providers ) ;
292
299
293
300
if ( ! isTypeProvider ( provider ) && provider . multi === true ) {
294
301
// If the provider indicates that it's a multi-provider, process it specially.
@@ -317,7 +324,7 @@ export class R3Injector {
317
324
318
325
private hydrate < T > ( token : Type < T > | InjectionToken < T > , record : Record < T > ) : T {
319
326
if ( record . value === CIRCULAR ) {
320
- throw new Error ( `Circular dep for ${ stringify ( token ) } ` ) ;
327
+ throw new Error ( `Cannot instantiate cyclic dependency! ${ stringify ( token ) } ` ) ;
321
328
} else if ( record . value === NOT_YET ) {
322
329
record . value = CIRCULAR ;
323
330
record . value = record . factory ! ( ) ;
@@ -345,20 +352,25 @@ function injectableDefOrInjectorDefFactory(token: Type<any>| InjectionToken<any>
345
352
const injectorDef = getInjectorDef ( token as InjectorType < any > ) ;
346
353
if ( injectorDef !== null ) {
347
354
return injectorDef . factory ;
348
- }
349
-
350
- if ( token instanceof InjectionToken ) {
355
+ } else if ( token instanceof InjectionToken ) {
351
356
throw new Error ( `Token ${ stringify ( token ) } is missing an ngInjectableDef definition.` ) ;
357
+ } else if ( token instanceof Function ) {
358
+ const paramLength = token . length ;
359
+ if ( paramLength > 0 ) {
360
+ const args : string [ ] = new Array ( paramLength ) . fill ( '?' ) ;
361
+ throw new Error (
362
+ `Can't resolve all parameters for ${ stringify ( token ) } : (${ args . join ( ', ' ) } ).` ) ;
363
+ }
364
+ return ( ) => new ( token as Type < any > ) ( ) ;
352
365
}
353
- // TODO(alxhub): there should probably be a strict mode which throws here instead of assuming a
354
- // no-args constructor.
355
- return ( ) => new ( token as Type < any > ) ( ) ;
366
+ throw new Error ( 'unreachable' ) ;
356
367
}
357
368
return injectableDef . factory ;
358
369
}
359
370
360
- function providerToRecord ( provider : SingleProvider ) : Record < any > {
361
- let factory : ( ( ) => any ) | undefined = providerToFactory ( provider ) ;
371
+ function providerToRecord (
372
+ provider : SingleProvider , ngModuleType : InjectorType < any > , providers : any [ ] ) : Record < any > {
373
+ let factory : ( ( ) => any ) | undefined = providerToFactory ( provider , ngModuleType , providers ) ;
362
374
if ( isValueProvider ( provider ) ) {
363
375
return makeRecord ( undefined , provider . useValue ) ;
364
376
} else {
@@ -371,7 +383,8 @@ function providerToRecord(provider: SingleProvider): Record<any> {
371
383
*
372
384
* @param provider provider to convert to factory
373
385
*/
374
- export function providerToFactory ( provider : SingleProvider ) : ( ) => any {
386
+ export function providerToFactory (
387
+ provider : SingleProvider , ngModuleType ?: InjectorType < any > , providers ?: any [ ] ) : ( ) => any {
375
388
let factory : ( ( ) => any ) | undefined = undefined ;
376
389
if ( isTypeProvider ( provider ) ) {
377
390
return injectableDefOrInjectorDefFactory ( resolveForwardRef ( provider ) ) ;
@@ -384,7 +397,18 @@ export function providerToFactory(provider: SingleProvider): () => any {
384
397
factory = ( ) => provider . useFactory ( ...injectArgs ( provider . deps || [ ] ) ) ;
385
398
} else {
386
399
const classRef = resolveForwardRef (
387
- ( provider as StaticClassProvider | ClassProvider ) . useClass || provider . provide ) ;
400
+ provider &&
401
+ ( ( provider as StaticClassProvider | ClassProvider ) . useClass || provider . provide ) ) ;
402
+ if ( ! classRef ) {
403
+ let ngModuleDetail = '' ;
404
+ if ( ngModuleType && providers ) {
405
+ const providerDetail = providers . map ( v => v == provider ? '?' + provider + '?' : '...' ) ;
406
+ ngModuleDetail =
407
+ ` - only instances of Provider and Type are allowed, got: [${ providerDetail . join ( ', ' ) } ]` ;
408
+ }
409
+ throw new Error (
410
+ `Invalid provider for the NgModule '${ stringify ( ngModuleType ) } '` + ngModuleDetail ) ;
411
+ }
388
412
if ( hasDeps ( provider ) ) {
389
413
factory = ( ) => new ( classRef ) ( ...injectArgs ( provider . deps ) ) ;
390
414
} else {
@@ -409,15 +433,15 @@ function deepForEach<T>(input: (T | any[])[], fn: (value: T) => void): void {
409
433
}
410
434
411
435
function isValueProvider ( value : SingleProvider ) : value is ValueProvider {
412
- return USE_VALUE in value ;
436
+ return value && typeof value == 'object' && USE_VALUE in value ;
413
437
}
414
438
415
439
function isExistingProvider ( value : SingleProvider ) : value is ExistingProvider {
416
- return ! ! ( value as ExistingProvider ) . useExisting ;
440
+ return ! ! ( value && ( value as ExistingProvider ) . useExisting ) ;
417
441
}
418
442
419
443
function isFactoryProvider ( value : SingleProvider ) : value is FactoryProvider {
420
- return ! ! ( value as FactoryProvider ) . useFactory ;
444
+ return ! ! ( value && ( value as FactoryProvider ) . useFactory ) ;
421
445
}
422
446
423
447
export function isTypeProvider ( value : SingleProvider ) : value is TypeProvider {
0 commit comments