awilix 5.0.1 → 6.0.0

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
@@ -53,7 +53,7 @@ written in [TypeScript](http://typescriptlang.org). **Make IoC great again!**
53
53
  - [`container.build()`](#containerbuild)
54
54
  - [`container.dispose()`](#containerdispose)
55
55
  - [Universal Module (Browser Support)](#universal-module-browser-support)
56
- - [Contributing](#contributing)
56
+ - [Contributing](#contributing)
57
57
  - [What's in a name?](#whats-in-a-name)
58
58
  - [Author](#author)
59
59
 
@@ -351,8 +351,12 @@ modes are available on `awilix.InjectionMode`
351
351
  ```
352
352
 
353
353
  - `InjectionMode.CLASSIC`: Parses the function/constructor parameters, and
354
- matches them with registrations in the container. _Don't use this if you
355
- minify your code!_
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
359
+ environments where minification is needed.
356
360
 
357
361
  ```js
358
362
  class UserService {
@@ -363,7 +367,8 @@ modes are available on `awilix.InjectionMode`
363
367
  }
364
368
  ```
365
369
 
366
- Additionally, if the class has a base class but does not report any dependencies, the base class dependencies are passed in.
370
+ Additionally, if the class has a base class but does not declare a constructor of its own, Awilix
371
+ simply invokes the base constructor with whatever dependencies it requires.
367
372
 
368
373
  ```js
369
374
  class Car {
@@ -373,9 +378,8 @@ modes are available on `awilix.InjectionMode`
373
378
  }
374
379
 
375
380
  class Porsche extends Car {
376
- constructor() {
377
- super(...arguments)
378
- console.log(arguments[0]) // whatever "engine" is
381
+ vroom() {
382
+ console.log(this.engine) // whatever "engine" is
379
383
  }
380
384
  }
381
385
  ```
@@ -1064,7 +1068,8 @@ Args:
1064
1068
  pass the name through as-is. The 2nd parameter is a full module descriptor.
1065
1069
  - `opts.resolverOptions`: An `object` passed to the resolvers. Used to configure
1066
1070
  the lifetime, injection mode and more of the loaded modules.
1067
- - `opts.esModules`: Loads modules using Node's native ES modules. This is only supported on Node 14.0+ and should only be used if you're using the [Native Node ES modules](https://nodejs.org/api/esm.html)
1071
+ - `opts.esModules`: Loads modules using Node's native ES modules. This is only
1072
+ supported on Node 14.0+ and should only be used if you're using the [Native Node ES modules](https://nodejs.org/api/esm.html)
1068
1073
 
1069
1074
  Example:
1070
1075
 
@@ -1337,16 +1342,9 @@ because they depend on Node-specific packages.
1337
1342
  - Safari >= 10
1338
1343
  - Internet Explorer is not supported
1339
1344
 
1340
- # Contributing
1345
+ ## Contributing
1341
1346
 
1342
- Clone repo, run `npm install` to install all dependencies, run `npm run build` to create an initial build, and then
1343
- `npm run test -- --watchAll` to start writing code.
1344
-
1345
- For code coverage, run `npm run cover`.
1346
-
1347
- If you submit a PR, please aim for 100% code coverage and no linting errors.
1348
- Travis will fail if there are linting errors. Thank you for considering
1349
- contributing. :)
1347
+ Please see our [contributing.md](./CONTRIBUTING.md)
1350
1348
 
1351
1349
  # What's in a name?
1352
1350
 
@@ -416,7 +416,7 @@ function createTokenizer(source) {
416
416
  * Determines if the given character is a whitespace character.
417
417
  *
418
418
  * @param {string} ch
419
- * @return {Boolean}
419
+ * @return {boolean}
420
420
  */
421
421
  function isWhiteSpace(ch) {
422
422
  switch (ch) {
@@ -430,7 +430,7 @@ function isWhiteSpace(ch) {
430
430
  /**
431
431
  * Determines if the specified character is a string quote.
432
432
  * @param {string} ch
433
- * @return {Boolean}
433
+ * @return {boolean}
434
434
  */
435
435
  function isStringQuote(ch) {
436
436
  switch (ch) {
@@ -494,7 +494,7 @@ function last(arr) {
494
494
  * Determines if the given function is a class.
495
495
  *
496
496
  * @param {Function} fn
497
- * @return {Boolean}
497
+ * @return {boolean}
498
498
  */
499
499
  function isClass(fn) {
500
500
  /*tslint:disable-next-line*/
@@ -521,7 +521,7 @@ function isClass(fn) {
521
521
  * @param {Any} val
522
522
  * Any value to check if it's a function.
523
523
  *
524
- * @return {Boolean}
524
+ * @return {boolean}
525
525
  * true if the value is a function, false otherwise.
526
526
  */
527
527
  function isFunction(val) {
@@ -585,8 +585,9 @@ var InjectionMode = {
585
585
  * @param {string} source
586
586
  * The source of a function to extract the parameter list from
587
587
  *
588
- * @return {Array<Parameter>}
589
- * Returns an array of parameters.
588
+ * @return {Array<Parameter> | null}
589
+ * Returns an array of parameters, or `null` if no
590
+ * constructor was found for a class.
590
591
  */
591
592
  function parseParameterList(source) {
592
593
  var _a = createTokenizer(source), _next = _a.next, done = _a.done;
@@ -597,6 +598,11 @@ function parseParameterList(source) {
597
598
  switch (t.type) {
598
599
  case 'class':
599
600
  skipUntilConstructor();
601
+ // If we didn't find a constructor token, then we know that there
602
+ // are no dependencies in the defined class.
603
+ if (!isConstructorToken()) {
604
+ return null;
605
+ }
600
606
  // Next token is the constructor identifier.
601
607
  nextToken();
602
608
  break;
@@ -676,6 +682,7 @@ function parseParameterList(source) {
676
682
  }
677
683
  /**
678
684
  * Determines if the current token represents a constructor, and the next token after it is a paren
685
+ * @return {boolean}
679
686
  */
680
687
  function isConstructorToken() {
681
688
  return t.type === 'ident' && t.value === 'constructor';
@@ -893,7 +900,7 @@ function wrapWithLocals(container, locals) {
893
900
  */
894
901
  function createInjectorProxy(container, injector) {
895
902
  var locals = injector(container);
896
- var allKeys = uniq(__spreadArray(__spreadArray([], Reflect.ownKeys(container.cradle)), Reflect.ownKeys(locals)));
903
+ var allKeys = uniq(__spreadArray(__spreadArray([], Reflect.ownKeys(container.cradle), true), Reflect.ownKeys(locals)));
897
904
  // TODO: Lots of duplication here from the container proxy.
898
905
  // Need to refactor.
899
906
  var proxy = new Proxy({}, {
@@ -1027,29 +1034,30 @@ function generateResolve(fn, dependencyParseTarget) {
1027
1034
  }
1028
1035
  /**
1029
1036
  * Parses the dependencies from the given function.
1030
- * If it's a class and has an extends clause, and no reported dependencies, attempt to parse it's super constructor.
1037
+ * If it's a class that extends another class, and it does
1038
+ * not have a defined constructor, attempt to parse it's super constructor.
1031
1039
  */
1032
1040
  function parseDependencies(fn) {
1033
1041
  var result = parseParameterList(fn.toString());
1034
- if (result.length > 0) {
1035
- return result;
1036
- }
1037
- var parent = Object.getPrototypeOf(fn);
1038
- if (typeof parent === 'function' && parent !== Function.prototype) {
1039
- // Try to parse the parent
1040
- return parseDependencies(parent);
1042
+ if (!result) {
1043
+ // No defined constructor for a class, check if there is a parent
1044
+ // we can parse.
1045
+ var parent = Object.getPrototypeOf(fn);
1046
+ if (typeof parent === 'function' && parent !== Function.prototype) {
1047
+ // Try to parse the parent
1048
+ return parseDependencies(parent);
1049
+ }
1050
+ return [];
1041
1051
  }
1042
1052
  return result;
1043
1053
  }
1044
1054
 
1045
1055
  /**
1046
1056
  * Family tree symbol.
1047
- * @type {Symbol}
1048
1057
  */
1049
1058
  var FAMILY_TREE = Symbol('familyTree');
1050
1059
  /**
1051
1060
  * Roll Up Registrations symbol.
1052
- * @type {Symbol}
1053
1061
  */
1054
1062
  var ROLL_UP_REGISTRATIONS = Symbol('rollUpRegistrations');
1055
1063
  /**
@@ -1061,7 +1069,7 @@ var ROLL_UP_REGISTRATIONS = Symbol('rollUpRegistrations');
1061
1069
  * @param {string} options.injectionMode
1062
1070
  * The mode used by the container to resolve dependencies. Defaults to 'Proxy'.
1063
1071
  *
1064
- * @return {object}
1072
+ * @return {AwilixContainer<T>}
1065
1073
  * The container.
1066
1074
  */
1067
1075
  function createContainer(options, parentContainer) {
@@ -1072,9 +1080,6 @@ function createContainer(options, parentContainer) {
1072
1080
  // an error occurs, we have something to present
1073
1081
  // to the poor developer who fucked up.
1074
1082
  var resolutionStack = [];
1075
- // For performance reasons, we store
1076
- // the rolled-up registrations when starting a resolve.
1077
- var computedRegistrations = null;
1078
1083
  // Internal registration store for this container.
1079
1084
  var registrations = {};
1080
1085
  /**
@@ -1088,7 +1093,7 @@ function createContainer(options, parentContainer) {
1088
1093
  /**
1089
1094
  * The `get` handler is invoked whenever a get-call for `container.cradle.*` is made.
1090
1095
  *
1091
- * @param {object} target
1096
+ * @param {object} _target
1092
1097
  * The proxy target. Irrelevant.
1093
1098
  *
1094
1099
  * @param {string} name
@@ -1097,14 +1102,14 @@ function createContainer(options, parentContainer) {
1097
1102
  * @return {*}
1098
1103
  * Whatever the resolve call returns.
1099
1104
  */
1100
- get: function (target, name) { return resolve(name); },
1105
+ get: function (_target, name) { return resolve(name); },
1101
1106
  /**
1102
1107
  * Setting things on the cradle throws an error.
1103
1108
  *
1104
1109
  * @param {object} target
1105
1110
  * @param {string} name
1106
1111
  */
1107
- set: function (_target, name, value) {
1112
+ set: function (_target, name) {
1108
1113
  throw new Error("Attempted setting property \"" + name + "\" on container cradle - this is not allowed.");
1109
1114
  },
1110
1115
  /**
@@ -1138,8 +1143,9 @@ function createContainer(options, parentContainer) {
1138
1143
  register: register,
1139
1144
  build: build,
1140
1145
  resolve: resolve,
1141
- has: has,
1142
- dispose: dispose
1146
+ hasRegistration: hasRegistration,
1147
+ dispose: dispose,
1148
+ getRegistration: getRegistration
1143
1149
  },
1144
1150
  /* removed in browser build */
1145
1151
  // tslint:disable-next-line
@@ -1164,12 +1170,15 @@ function createContainer(options, parentContainer) {
1164
1170
  /**
1165
1171
  * Used by util.inspect (which is used by console.log).
1166
1172
  */
1167
- function inspect(depth, opts) {
1173
+ function inspect() {
1168
1174
  return "[AwilixContainer (" + (parentContainer ? 'scoped, ' : '') + "registrations: " + Object.keys(container.registrations).length + ")]";
1169
1175
  }
1170
1176
  /**
1171
1177
  * Rolls up registrations from the family tree.
1172
- * This is cached until `bustCache` clears it.
1178
+ *
1179
+ * This can get pretty expensive. Only used when
1180
+ * iterating the cradle proxy, which is not something
1181
+ * that should be done in day-to-day use, mostly for debugging.
1173
1182
  *
1174
1183
  * @param {boolean} bustCache
1175
1184
  * Forces a recomputation.
@@ -1177,19 +1186,13 @@ function createContainer(options, parentContainer) {
1177
1186
  * @return {object}
1178
1187
  * The merged registrations object.
1179
1188
  */
1180
- function rollUpRegistrations(bustCache) {
1181
- if (bustCache === void 0) { bustCache = false; }
1182
- if (computedRegistrations && !bustCache) {
1183
- return computedRegistrations;
1184
- }
1185
- computedRegistrations = __assign(__assign({}, (parentContainer &&
1186
- parentContainer[ROLL_UP_REGISTRATIONS](bustCache))), registrations);
1187
- return computedRegistrations;
1189
+ function rollUpRegistrations() {
1190
+ return __assign(__assign({}, (parentContainer && parentContainer[ROLL_UP_REGISTRATIONS]())), registrations);
1188
1191
  }
1189
1192
  /**
1190
1193
  * Used for providing an iterator to the cradle.
1191
1194
  */
1192
- function registrationNamesIterator() {
1195
+ function cradleIterator() {
1193
1196
  var registrations, _a, _b, _i, registrationName;
1194
1197
  return __generator(this, function (_c) {
1195
1198
  switch (_c.label) {
@@ -1228,14 +1231,12 @@ function createContainer(options, parentContainer) {
1228
1231
  */
1229
1232
  function register(arg1, arg2) {
1230
1233
  var obj = nameValueToObject(arg1, arg2);
1231
- var keys = __spreadArray(__spreadArray([], Object.keys(obj)), Object.getOwnPropertySymbols(obj));
1234
+ var keys = __spreadArray(__spreadArray([], Object.keys(obj), true), Object.getOwnPropertySymbols(obj));
1232
1235
  for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
1233
1236
  var key = keys_1[_i];
1234
1237
  var value = obj[key];
1235
1238
  registrations[key] = value;
1236
1239
  }
1237
- // Invalidates the computed registrations.
1238
- computedRegistrations = null;
1239
1240
  return container;
1240
1241
  }
1241
1242
  /**
@@ -1245,6 +1246,22 @@ function createContainer(options, parentContainer) {
1245
1246
  function inspectCradle() {
1246
1247
  return '[AwilixContainer.cradle]';
1247
1248
  }
1249
+ /**
1250
+ * Recursively gets a registration by name if it exists in the
1251
+ * current container or any of its' parents.
1252
+ *
1253
+ * @param name {string | symbol} The registration name.
1254
+ */
1255
+ function getRegistration(name) {
1256
+ var resolver = registrations[name];
1257
+ if (resolver) {
1258
+ return resolver;
1259
+ }
1260
+ if (parentContainer) {
1261
+ return parentContainer.getRegistration(name);
1262
+ }
1263
+ return null;
1264
+ }
1248
1265
  /**
1249
1266
  * Resolves the registration with the given name.
1250
1267
  *
@@ -1259,13 +1276,9 @@ function createContainer(options, parentContainer) {
1259
1276
  */
1260
1277
  function resolve(name, resolveOpts) {
1261
1278
  resolveOpts = resolveOpts || {};
1262
- if (!resolutionStack.length) {
1263
- // Root resolve busts the registration cache.
1264
- rollUpRegistrations(true);
1265
- }
1266
1279
  try {
1267
1280
  // Grab the registration by name.
1268
- var resolver = computedRegistrations[name];
1281
+ var resolver = getRegistration(name);
1269
1282
  if (resolutionStack.indexOf(name) > -1) {
1270
1283
  throw new AwilixResolutionError(name, resolutionStack, 'Cyclic dependencies detected.');
1271
1284
  }
@@ -1278,20 +1291,20 @@ function createContainer(options, parentContainer) {
1278
1291
  return createContainer;
1279
1292
  }
1280
1293
  if (!resolver) {
1281
- // The following checks ensure that console.log on the cradle does not
1282
- // throw an error (issue #7).
1283
- if (name === 'inspect') {
1284
- return inspectCradle;
1285
- }
1286
- // Edge case: Promise unwrapping will look for a "then" property and attempt to call it.
1287
- // Return undefined so that we won't cause a resolution error. (issue #109)
1288
- if (name === 'then') {
1289
- return undefined;
1290
- }
1291
- // When using `Array.from` or spreading the cradle, this will
1292
- // return the registration names.
1293
- if (name === Symbol.iterator) {
1294
- return registrationNamesIterator;
1294
+ // Checks for some edge cases.
1295
+ switch (name) {
1296
+ // The following checks ensure that console.log on the cradle does not
1297
+ // throw an error (issue #7).
1298
+ case 'inspect':
1299
+ return inspectCradle;
1300
+ // Edge case: Promise unwrapping will look for a "then" property and attempt to call it.
1301
+ // Return undefined so that we won't cause a resolution error. (issue #109)
1302
+ case 'then':
1303
+ return undefined;
1304
+ // When using `Array.from` or spreading the cradle, this will
1305
+ // return the registration names.
1306
+ case Symbol.iterator:
1307
+ return cradleIterator;
1295
1308
  }
1296
1309
  if (resolveOpts.allowUnregistered) {
1297
1310
  return undefined;
@@ -1356,8 +1369,8 @@ function createContainer(options, parentContainer) {
1356
1369
  * @return {boolean}
1357
1370
  * Whether or not the registration exists.
1358
1371
  */
1359
- function has(name) {
1360
- return name in rollUpRegistrations();
1372
+ function hasRegistration(name) {
1373
+ return !!getRegistration(name);
1361
1374
  }
1362
1375
  /**
1363
1376
  * Given a registration, class or function, builds it up and returns it.