awilix 9.0.0 → 10.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
  [![JavaScript Style Guide](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com/)
10
10
 
11
11
  Extremely powerful, performant, & battle-tested **Dependency Injection** (DI) container for JavaScript/Node,
12
- written in [TypeScript](http://typescriptlang.org).
12
+ written in [TypeScript](http://typescriptlang.org).
13
13
 
14
14
  Awilix enables you to write **composable, testable software** using dependency injection **without special annotations**, which in turn decouples your core application code from the intricacies of the DI mechanism.
15
15
 
@@ -24,6 +24,7 @@ Awilix enables you to write **composable, testable software** using dependency i
24
24
  - [Usage](#usage)
25
25
  - [Lifetime management](#lifetime-management)
26
26
  - [Scoped lifetime](#scoped-lifetime)
27
+ - [Strict mode](#strict-mode)
27
28
  - [Injection modes](#injection-modes)
28
29
  - [Auto-loading modules](#auto-loading-modules)
29
30
  - [Per-module local injections](#per-module-local-injections)
@@ -39,6 +40,7 @@ Awilix enables you to write **composable, testable software** using dependency i
39
40
  - [`aliasTo()`](#aliasto)
40
41
  - [`listModules()`](#listmodules)
41
42
  - [`AwilixResolutionError`](#awilixresolutionerror)
43
+ - [`AwilixRegistrationError`](#awilixregistrationerror)
42
44
  - [The `AwilixContainer` object](#the-awilixcontainer-object)
43
45
  - [`container.cradle`](#containercradle)
44
46
  - [`container.registrations`](#containerregistrations)
@@ -74,9 +76,9 @@ yarn add awilix
74
76
  You can also use the [UMD](https://github.com/umdjs/umd) build from `unpkg`
75
77
 
76
78
  ```html
77
- <script src="https://unpkg.com/awilix/lib/awilix.umd.js"/>
79
+ <script src="https://unpkg.com/awilix/lib/awilix.umd.js" />
78
80
  <script>
79
- const container = Awilix.createContainer()
81
+ const container = Awilix.createContainer()
80
82
  </script>
81
83
  ```
82
84
 
@@ -95,8 +97,10 @@ minimum, you need to do 3 things:
95
97
  const awilix = require('awilix')
96
98
 
97
99
  // Create the container and set the injectionMode to PROXY (which is also the default).
100
+ // Enable strict mode for extra correctness checks (highly recommended).
98
101
  const container = awilix.createContainer({
99
- injectionMode: awilix.InjectionMode.PROXY
102
+ injectionMode: awilix.InjectionMode.PROXY,
103
+ strict: true,
100
104
  })
101
105
 
102
106
  // This is our app code... We can use
@@ -118,7 +122,7 @@ class UserController {
118
122
  container.register({
119
123
  // Here we are telling Awilix how to resolve a
120
124
  // userController: by instantiating a class.
121
- userController: awilix.asClass(UserController)
125
+ userController: awilix.asClass(UserController),
122
126
  })
123
127
 
124
128
  // Let's try with a factory function.
@@ -126,16 +130,16 @@ const makeUserService = ({ db }) => {
126
130
  // Notice how we can use destructuring
127
131
  // to access dependencies
128
132
  return {
129
- getUser: id => {
133
+ getUser: (id) => {
130
134
  return db.query(`select * from users where id=${id}`)
131
- }
135
+ },
132
136
  }
133
137
  }
134
138
 
135
139
  container.register({
136
140
  // the `userService` is resolved by
137
141
  // invoking the function.
138
- userService: awilix.asFunction(makeUserService)
142
+ userService: awilix.asFunction(makeUserService),
139
143
  })
140
144
 
141
145
  // Alright, now we need a database.
@@ -149,7 +153,7 @@ function Database(connectionString, timeout) {
149
153
  this.conn = connectToYourDatabaseSomehow(connectionString, timeout)
150
154
  }
151
155
 
152
- Database.prototype.query = function(sql) {
156
+ Database.prototype.query = function (sql) {
153
157
  // blah....
154
158
  return this.conn.rawSql(sql)
155
159
  }
@@ -159,7 +163,7 @@ Database.prototype.query = function(sql) {
159
163
  // We also want to use `CLASSIC` injection mode for this
160
164
  // registration. Read more about injection modes below.
161
165
  container.register({
162
- db: awilix.asClass(Database).classic()
166
+ db: awilix.asClass(Database).classic(),
163
167
  })
164
168
 
165
169
  // Lastly we register the connection string and timeout values
@@ -169,7 +173,7 @@ container.register({
169
173
  // limited to strings and numbers, it can be anything,
170
174
  // really - they will be passed through directly.
171
175
  connectionString: awilix.asValue(process.env.CONN_STR),
172
- timeout: awilix.asValue(1000)
176
+ timeout: awilix.asValue(1000),
173
177
  })
174
178
 
175
179
  // We have now wired everything up!
@@ -219,17 +223,17 @@ const { asClass, asFunction, asValue } = awilix
219
223
  class MailService {}
220
224
 
221
225
  container.register({
222
- mailService: asClass(MailService, { lifetime: Lifetime.SINGLETON })
226
+ mailService: asClass(MailService, { lifetime: Lifetime.SINGLETON }),
223
227
  })
224
228
 
225
229
  // or using the chaining configuration API..
226
230
  container.register({
227
- mailService: asClass(MailService).setLifetime(Lifetime.SINGLETON)
231
+ mailService: asClass(MailService).setLifetime(Lifetime.SINGLETON),
228
232
  })
229
233
 
230
234
  // or..
231
235
  container.register({
232
- mailService: asClass(MailService).singleton()
236
+ mailService: asClass(MailService).singleton(),
233
237
  })
234
238
 
235
239
  // or.......
@@ -260,7 +264,7 @@ class MessageService {
260
264
  }
261
265
 
262
266
  container.register({
263
- messageService: asClass(MessageService).scoped()
267
+ messageService: asClass(MessageService).scoped(),
264
268
  })
265
269
 
266
270
  // imagine middleware in some web framework..
@@ -270,7 +274,7 @@ app.use((req, res, next) => {
270
274
 
271
275
  // register some request-specific data..
272
276
  req.scope.register({
273
- currentUser: asValue(req.user)
277
+ currentUser: asValue(req.user),
274
278
  })
275
279
 
276
280
  next()
@@ -279,7 +283,7 @@ app.use((req, res, next) => {
279
283
  app.get('/messages', (req, res) => {
280
284
  // for each request we get a new message service!
281
285
  const messageService = req.scope.resolve('messageService')
282
- messageService.getMessages().then(messages => {
286
+ messageService.getMessages().then((messages) => {
283
287
  res.send(200, messages)
284
288
  })
285
289
  })
@@ -289,18 +293,26 @@ app.get('/messages', (req, res) => {
289
293
  ```
290
294
 
291
295
  **IMPORTANT!** If a singleton is resolved, and it depends on a scoped or
292
- transient registration, those will remain in the singleton for it's lifetime!
296
+ transient registration, those will remain in the singleton for its lifetime!
297
+ Similarly, if a scoped module is resolved, and it depends on a transient
298
+ registration, that remains in the scoped module for its lifetime.
299
+ In the example above, if `messageService` was a singleton, it would be cached
300
+ in the root container, and would always have the `currentUser` from the first
301
+ request. Modules should generally not have a longer lifetime than their
302
+ dependencies, as this can cause issues of stale data.
293
303
 
294
304
  ```js
295
- const makePrintTime = ({ time }) => () => {
296
- console.log('Time:', time)
297
- }
305
+ const makePrintTime =
306
+ ({ time }) =>
307
+ () => {
308
+ console.log('Time:', time)
309
+ }
298
310
 
299
311
  const getTime = () => new Date().toString()
300
312
 
301
313
  container.register({
302
314
  printTime: asFunction(makePrintTime).singleton(),
303
- time: asFunction(getTime).transient()
315
+ time: asFunction(getTime).transient(),
304
316
  })
305
317
 
306
318
  // Resolving `time` 2 times will
@@ -315,9 +327,34 @@ container.resolve('printTime')()
315
327
  container.resolve('printTime')()
316
328
  ```
317
329
 
330
+ If you want a mismatched configuration like this to error, set
331
+ `strict` in the container options. This will trigger
332
+ the following error at runtime when the singleton `printTime` is resolved:
333
+ `AwilixResolutionError: Could not resolve 'time'. Dependency 'time' has a shorter lifetime than its ancestor: 'printTime'`
334
+
335
+ In addition, registering a singleton on a scope other than the root container results in
336
+ unpredictable behavior. In particular, if two different singletons are registered on two different
337
+ scopes, they will share a cache entry and collide with each other. To throw a runtime error when a
338
+ singleton is registered on a scope other than the root container, enable [strict mode](#strict-mode).
339
+
318
340
  Read the documentation for [`container.createScope()`](#containercreatescope)
319
341
  for more examples.
320
342
 
343
+ # Strict mode
344
+
345
+ Strict mode is a new feature in Awilix 10. It enables additional correctness checks that can help
346
+ you catch bugs early.
347
+
348
+ In particular, strict mode enables the following checks:
349
+
350
+ - When a singleton or scoped registration depends on a transient non-value registration, an error is
351
+ thrown. This detects and prevents the issue where a shorter lifetime dependency can leak outside
352
+ its intended lifetime due to its preservation in a longer lifetime module.
353
+ - Singleton registrations on any scopes are disabled. This prevents the issue where a singleton is
354
+ registered on a scope other than the root container, which results in unpredictable behavior.
355
+ - Singleton resolution is performed using registrations from the root container only, which prevents
356
+ potential leaks in which scoped registrations are preserved in singletons.
357
+
321
358
  # Injection modes
322
359
 
323
360
  The injection mode determines how a function/constructor receives its
@@ -351,11 +388,11 @@ modes are available on `awilix.InjectionMode`
351
388
  ```
352
389
 
353
390
  - `InjectionMode.CLASSIC`: Parses the function/constructor parameters, and
354
- matches them with registrations in the container. `CLASSIC` mode has a
355
- slightly higher initialization cost as it has to parse the function/class
356
- to figure out the dependencies at the time of registration, however resolving
357
- them will be **much faster** than when using `PROXY`. _Don't use `CLASSIC` if
358
- you minify your code!_ We recommend using `CLASSIC` in Node and `PROXY` in
391
+ matches them with registrations in the container. `CLASSIC` mode has a
392
+ slightly higher initialization cost as it has to parse the function/class
393
+ to figure out the dependencies at the time of registration, however resolving
394
+ them will be **much faster** than when using `PROXY`. _Don't use `CLASSIC` if
395
+ you minify your code!_ We recommend using `CLASSIC` in Node and `PROXY` in
359
396
  environments where minification is needed.
360
397
 
361
398
  ```js
@@ -423,8 +460,8 @@ container.register({
423
460
  const container = createContainer()
424
461
  container.loadModules(['services/**/*.js', 'repositories/**/*.js'], {
425
462
  resolverOptions: {
426
- injectionMode: InjectionMode.CLASSIC
427
- }
463
+ injectionMode: InjectionMode.CLASSIC,
464
+ },
428
465
  })
429
466
  ```
430
467
 
@@ -464,7 +501,7 @@ function database({ connectionString, timeout, logger }) {
464
501
  const db = database({
465
502
  logger: new LoggerMock(),
466
503
  timeout: 4000,
467
- connectionString: 'localhost:1337;user=123...'
504
+ connectionString: 'localhost:1337;user=123...',
468
505
  })
469
506
  ```
470
507
 
@@ -521,35 +558,38 @@ const awilix = require('awilix')
521
558
  const container = awilix.createContainer()
522
559
 
523
560
  // Load our modules!
524
- container.loadModules([
525
- // Globs!
561
+ container.loadModules(
526
562
  [
527
- // To have different resolverOptions for specific modules.
528
- 'models/**/*.js',
529
- {
530
- register: awilix.asValue,
531
- lifetime: Lifetime.SINGLETON
532
- }
563
+ // Globs!
564
+ [
565
+ // To have different resolverOptions for specific modules.
566
+ 'models/**/*.js',
567
+ {
568
+ register: awilix.asValue,
569
+ lifetime: Lifetime.SINGLETON,
570
+ },
571
+ ],
572
+ 'services/**/*.js',
573
+ 'repositories/**/*.js',
533
574
  ],
534
- 'services/**/*.js',
535
- 'repositories/**/*.js'
536
- ], {
537
- // We want to register `UserService` as `userService` -
538
- // by default loaded modules are registered with the
539
- // name of the file (minus the extension)
540
- formatName: 'camelCase',
541
- // Apply resolver options to all modules.
542
- resolverOptions: {
543
- // We can give these auto-loaded modules
544
- // the deal of a lifetime! (see what I did there?)
545
- // By default it's `TRANSIENT`.
546
- lifetime: Lifetime.SINGLETON,
547
- // We can tell Awilix what to register everything as,
548
- // instead of guessing. If omitted, will inspect the
549
- // module to determine what to register as.
550
- register: awilix.asClass
551
- }
552
- })
575
+ {
576
+ // We want to register `UserService` as `userService` -
577
+ // by default loaded modules are registered with the
578
+ // name of the file (minus the extension)
579
+ formatName: 'camelCase',
580
+ // Apply resolver options to all modules.
581
+ resolverOptions: {
582
+ // We can give these auto-loaded modules
583
+ // the deal of a lifetime! (see what I did there?)
584
+ // By default it's `TRANSIENT`.
585
+ lifetime: Lifetime.SINGLETON,
586
+ // We can tell Awilix what to register everything as,
587
+ // instead of guessing. If omitted, will inspect the
588
+ // module to determine what to register as.
589
+ register: awilix.asClass,
590
+ },
591
+ },
592
+ )
553
593
 
554
594
  // We are now ready! We now have a userService, userRepository and emailService!
555
595
  container.resolve('userService').getUser(1)
@@ -575,10 +615,10 @@ export default function userRepository({ db, timeout }) {
575
615
  return Promise.race([
576
616
  db.query('select * from users'),
577
617
  Promise.delay(timeout).then(() =>
578
- Promise.reject(new Error('Timed out'))
579
- )
618
+ Promise.reject(new Error('Timed out')),
619
+ ),
580
620
  ])
581
- }
621
+ },
582
622
  }
583
623
  }
584
624
  ```
@@ -597,22 +637,22 @@ const container = createContainer()
597
637
  // Provide an injection function that returns an object with locals.
598
638
  // The function is called once per resolve of the registration
599
639
  // it is attached to.
600
- .inject(() => ({ timeout: 2000 }))
640
+ .inject(() => ({ timeout: 2000 })),
601
641
  })
602
642
 
603
643
  // Shorthand variants
604
644
  .register({
605
645
  userRepository: asFunction(createUserRepository, {
606
- injector: () => ({ timeout: 2000 })
607
- })
646
+ injector: () => ({ timeout: 2000 }),
647
+ }),
608
648
  })
609
649
 
610
650
  // Stringly-typed shorthand
611
651
  .register(
612
652
  'userRepository',
613
653
  asFunction(createUserRepository, {
614
- injector: () => ({ timeout: 2000 })
615
- })
654
+ injector: () => ({ timeout: 2000 }),
655
+ }),
616
656
  )
617
657
 
618
658
  // with `loadModules`
@@ -645,7 +685,7 @@ export default class AwesomeService {
645
685
  // `RESOLVER` is a Symbol.
646
686
  AwesomeService[RESOLVER] = {
647
687
  lifetime: Lifetime.SCOPED,
648
- injectionMode: InjectionMode.CLASSIC
688
+ injectionMode: InjectionMode.CLASSIC,
649
689
  }
650
690
  ```
651
691
 
@@ -656,7 +696,7 @@ import { createContainer, asClass } from 'awilix'
656
696
  import AwesomeService from './services/awesome-service.js'
657
697
 
658
698
  const container = createContainer().register({
659
- awesomeService: asClass(AwesomeService)
699
+ awesomeService: asClass(AwesomeService),
660
700
  })
661
701
 
662
702
  console.log(container.registrations.awesomeService.lifetime) // 'SCOPED'
@@ -720,7 +760,7 @@ function configureContainer() {
720
760
  .singleton()
721
761
  // This is called when the pool is going to be disposed.
722
762
  // If it returns a Promise, it will be awaited by `dispose`.
723
- .disposer(pool => pool.end())
763
+ .disposer((pool) => pool.end()),
724
764
  })
725
765
  }
726
766
 
@@ -796,18 +836,20 @@ pass in an object with the following props:
796
836
  [Per-module local injections](#per-module-local-injections)
797
837
  - `register`: Only used in `loadModules`, determines how to register a loaded
798
838
  module explicitly
839
+ - `isLeakSafe`: true if this resolver should be excluded from lifetime-leak checking performed in
840
+ [strict mode](#strict-mode). Defaults to false.
799
841
 
800
842
  **Examples of usage:**
801
843
 
802
844
  ```js
803
845
  container.register({
804
- stuff: asClass(MyClass, { injectionMode: InjectionMode.CLASSIC })
846
+ stuff: asClass(MyClass, { injectionMode: InjectionMode.CLASSIC }),
805
847
  })
806
848
 
807
849
  container.loadModules([['some/path/to/*.js', { register: asClass }]], {
808
850
  resolverOptions: {
809
- lifetime: Lifetime.SCOPED
810
- }
851
+ lifetime: Lifetime.SCOPED,
852
+ },
811
853
  })
812
854
  ```
813
855
 
@@ -830,6 +872,7 @@ Args:
830
872
  **_must_** be named exactly like they are in the registration. For
831
873
  example, a dependency registered as `repository` cannot be referenced in a
832
874
  class constructor as `repo`.
875
+ - `options.strict`: Enables [strict mode](#strict-mode). Defaults to `false`.
833
876
 
834
877
  ## `asFunction()`
835
878
 
@@ -869,7 +912,7 @@ Resolves the dependency specified.
869
912
  ```js
870
913
  container.register({
871
914
  val: asValue(123),
872
- aliasVal: aliasTo('val')
915
+ aliasVal: aliasTo('val'),
873
916
  })
874
917
 
875
918
  container.resolve('aliasVal') === container.resolve('val')
@@ -913,6 +956,11 @@ This is a special error thrown when Awilix is unable to resolve all dependencies
913
956
  `err instanceof AwilixResolutionError` if you wish. It will tell you what
914
957
  dependencies it could not find or which ones caused a cycle.
915
958
 
959
+ ## `AwilixRegistrationError`
960
+
961
+ This is a special error thrown when Awilix is unable to register a dependency due to a strict mode
962
+ violation. You can catch this error and use `err instanceof AwilixRegistrationError` if you wish.
963
+
916
964
  ## The `AwilixContainer` object
917
965
 
918
966
  The container returned from `createContainer` has some methods and properties.
@@ -942,7 +990,7 @@ Each scope has it's own cache, and checks the cache of it's ancestors.
942
990
  ```js
943
991
  let counter = 1
944
992
  container.register({
945
- count: asFunction(() => counter++).singleton()
993
+ count: asFunction(() => counter++).singleton(),
946
994
  })
947
995
 
948
996
  container.cradle.count === 1
@@ -958,7 +1006,7 @@ Options passed to `createContainer` are stored here.
958
1006
 
959
1007
  ```js
960
1008
  const container = createContainer({
961
- injectionMode: InjectionMode.CLASSIC
1009
+ injectionMode: InjectionMode.CLASSIC,
962
1010
  })
963
1011
 
964
1012
  console.log(container.options.injectionMode) // 'CLASSIC'
@@ -974,7 +1022,7 @@ Resolves the registration with the given name. Used by the cradle.
974
1022
 
975
1023
  ```js
976
1024
  container.register({
977
- leet: asFunction(() => 1337)
1025
+ leet: asFunction(() => 1337),
978
1026
  })
979
1027
 
980
1028
  container.resolve('leet') === 1337
@@ -1022,14 +1070,14 @@ container.register('context', asClass(SessionContext))
1022
1070
  container.register({
1023
1071
  connectionString: asValue('localhost:1433;user=...'),
1024
1072
  mailService: asFunction(makeMailService, { lifetime: Lifetime.SINGLETON }),
1025
- context: asClass(SessionContext, { lifetime: Lifetime.SCOPED })
1073
+ context: asClass(SessionContext, { lifetime: Lifetime.SCOPED }),
1026
1074
  })
1027
1075
 
1028
1076
  // `asClass` and `asFunction` also supports a fluid syntax.
1029
1077
  // This...
1030
1078
  container.register(
1031
1079
  'mailService',
1032
- asFunction(makeMailService).setLifetime(Lifetime.SINGLETON)
1080
+ asFunction(makeMailService).setLifetime(Lifetime.SINGLETON),
1033
1081
  )
1034
1082
  // .. is the same as this:
1035
1083
  container.register('context', asClass(SessionContext).singleton())
@@ -1070,9 +1118,9 @@ Args:
1070
1118
  pass the name through as-is. The 2nd parameter is a full module descriptor.
1071
1119
  - `opts.resolverOptions`: An `object` passed to the resolvers. Used to configure
1072
1120
  the lifetime, injection mode and more of the loaded modules.
1073
- - `opts.esModules`: Loads modules using Node's native ES modules.
1074
- **This makes `container.loadModules` asynchronous, and will therefore return a `Promise`!**
1075
- This is only supported on Node 14.0+ and should only be used if you're using
1121
+ - `opts.esModules`: Loads modules using Node's native ES modules.
1122
+ **This makes `container.loadModules` asynchronous, and will therefore return a `Promise`!**
1123
+ This is only supported on Node 14.0+ and should only be used if you're using
1076
1124
  the [Native Node ES modules](https://nodejs.org/api/esm.html)
1077
1125
 
1078
1126
  Example:
@@ -1149,7 +1197,7 @@ inside a scope. A scope is basically a "child" container.
1149
1197
  // Increments the counter every time it is resolved.
1150
1198
  let counter = 1
1151
1199
  container.register({
1152
- counterValue: asFunction(() => counter++).scoped()
1200
+ counterValue: asFunction(() => counter++).scoped(),
1153
1201
  })
1154
1202
  const scope1 = container.createScope()
1155
1203
  const scope2 = container.createScope()
@@ -1169,7 +1217,7 @@ A _Scope_ maintains it's own cache of `Lifetime.SCOPED` registrations, meaning i
1169
1217
  ```js
1170
1218
  let counter = 1
1171
1219
  container.register({
1172
- counterValue: asFunction(() => counter++).scoped()
1220
+ counterValue: asFunction(() => counter++).scoped(),
1173
1221
  })
1174
1222
  const scope1 = container.createScope()
1175
1223
  const scope2 = container.createScope()
@@ -1195,13 +1243,13 @@ that scope and it's children.
1195
1243
  // that returns the value of the scope-provided dependency.
1196
1244
  // For this example we could also use scoped lifetime.
1197
1245
  container.register({
1198
- scopedValue: asFunction(cradle => 'Hello ' + cradle.someValue)
1246
+ scopedValue: asFunction((cradle) => 'Hello ' + cradle.someValue),
1199
1247
  })
1200
1248
 
1201
1249
  // Create a scope and register a value.
1202
1250
  const scope = container.createScope()
1203
1251
  scope.register({
1204
- someValue: asValue('scope')
1252
+ someValue: asValue('scope'),
1205
1253
  })
1206
1254
 
1207
1255
  scope.cradle.scopedValue === 'Hello scope'
@@ -1211,27 +1259,36 @@ container.cradle.someValue
1211
1259
  // of the resolver.
1212
1260
  ```
1213
1261
 
1214
- Things registered in the scope take precedence over it's parent.
1262
+ Things registered in the scope take precedence over registrations in the parent scope(s). This
1263
+ applies to both the registration directly requested from the scope container, and any dependencies
1264
+ that the registration uses.
1215
1265
 
1216
1266
  ```js
1217
1267
  // It does not matter when the scope is created,
1218
1268
  // it will still have anything that is registered
1219
- // in it's parent.
1269
+ // in its parent.
1220
1270
  const scope = container.createScope()
1221
1271
 
1222
1272
  container.register({
1223
1273
  value: asValue('root'),
1224
- usedValue: asFunction(cradle => cradle.value)
1274
+ usedValue: asFunction((cradle) => `hello from ${cradle.value}`),
1225
1275
  })
1226
1276
 
1227
1277
  scope.register({
1228
- value: asValue('scope')
1278
+ value: asValue('scope'),
1229
1279
  })
1230
1280
 
1231
- container.cradle.usedValue === 'root'
1232
- scope.cradle.usedValue === 'scope'
1281
+ container.cradle.value === 'root'
1282
+ scope.cradle.value === 'scope'
1283
+ container.cradle.usedValue === 'hello from root'
1284
+ scope.cradle.usedValue === 'hello from scope'
1233
1285
  ```
1234
1286
 
1287
+ Registering singletons in a scope results in unpredictable behavior and should be avoided. Having
1288
+ more than one singleton with the same name in different scopes will result in them sharing a cache
1289
+ entry and colliding with each other. To disallow such registrations, enable
1290
+ [strict mode](#strict-mode) in the container options.
1291
+
1235
1292
  ### `container.build()`
1236
1293
 
1237
1294
  Builds an instance of a class (or a function) by injecting dependencies, but
@@ -1266,11 +1323,11 @@ class MyClass {
1266
1323
  }
1267
1324
 
1268
1325
  const createMyFunc = ({ ping }) => ({
1269
- pong: () => ping
1326
+ pong: () => ping,
1270
1327
  })
1271
1328
 
1272
1329
  container.register({
1273
- ping: asValue('pong')
1330
+ ping: asValue('pong'),
1274
1331
  })
1275
1332
 
1276
1333
  // Shorthand
@@ -1304,9 +1361,9 @@ const pg = require('pg')
1304
1361
 
1305
1362
  container.register({
1306
1363
  pool: asFunction(() => new pg.Pool())
1307
- .disposer(pool => pool.end())
1364
+ .disposer((pool) => pool.end())
1308
1365
  // IMPORTANT! Must be either singleton or scoped!
1309
- .singleton()
1366
+ .singleton(),
1310
1367
  })
1311
1368
 
1312
1369
  const pool = container.resolve('pool')
@@ -1348,11 +1405,11 @@ because they depend on Node-specific packages.
1348
1405
 
1349
1406
  # Ecosystem
1350
1407
 
1351
- * [`awilix-manager`](https://github.com/kibertoad/awilix-manager): Wrapper that allows eager injection, asynchronous init methods and dependency lookup by tags.
1352
- * [`awilix-express`](https://github.com/jeffijoe/awilix-express): Bindings for the Express HTTP library.
1353
- * [`awilix-koa`](https://github.com/jeffijoe/awilix-koa): Bindings for the Koa HTTP library.
1354
- * [`awilix-router-core`](https://github.com/jeffijoe/awilix-router-core): Library for building HTTP bindings for Awilix with routing.
1355
- * [`fastify-awilix`](https://github.com/fastify/fastify-awilix): Bindings for the Fastify framework.
1408
+ - [`awilix-manager`](https://github.com/kibertoad/awilix-manager): Wrapper that allows eager injection, asynchronous init methods and dependency lookup by tags.
1409
+ - [`awilix-express`](https://github.com/jeffijoe/awilix-express): Bindings for the Express HTTP library.
1410
+ - [`awilix-koa`](https://github.com/jeffijoe/awilix-koa): Bindings for the Koa HTTP library.
1411
+ - [`awilix-router-core`](https://github.com/jeffijoe/awilix-router-core): Library for building HTTP bindings for Awilix with routing.
1412
+ - [`fastify-awilix`](https://github.com/fastify/fastify-awilix): Bindings for the Fastify framework.
1356
1413
 
1357
1414
  # Contributing
1358
1415