Comparing version 4.3.0 to 4.3.1
145
CHANGELOG.md
@@ -1,6 +0,7 @@ | ||
Change Log | ||
========== | ||
# Change Log | ||
Further change logs can be found on the [releases](https://github.com/jpex-js/jpex/releases) page | ||
### 4.0.0 | ||
- global dependencies such as `Window` and `Document` are now automatically resolved (unless you register your own dependency of the same name) | ||
@@ -21,2 +22,3 @@ - you can now control dependency resolution with config flags `nodeModules` and `globals` | ||
#### Breaking Changes | ||
- if you attempt to resolve a global like `Window` without registering it first, rather than throw an error, you will now get the global variable | ||
@@ -33,8 +35,11 @@ - You can no longer do `jpex.factory('foo', (depA, depB) => { ... })` as we no longer parse the function and extract the dependencies. | ||
### 3.5.1 | ||
- building with webpack was giving warnings about `require` being used which meant it couldn't make optimizations | ||
### 3.5.0 | ||
- add some deprecation warnings for pre-4.0.0 changes | ||
### 3.4.0 | ||
- clearCache now supports type inference | ||
@@ -45,20 +50,27 @@ - you can now pass `publicPath: true` and it will use the `name` property of your app's `package.json` as the public path | ||
### 3.3.3 | ||
- array dependencies were being incorrectly flattened | ||
### 3.3.1 | ||
- publicPath relative imports was checking the incorrect path property | ||
### 3.3.0 | ||
- add `jpex.extend` option: `inherit` (defaults to `true`). Determines if the extended container should inherit factories | ||
### 3.2.3 | ||
- publicPath should be operate on relative `.` imports | ||
### 3.2.2 | ||
- publicPath option was not working correctly for complex relative imports | ||
### 3.2.1 | ||
- support `useResolve` taking a dependency array | ||
## 3.2.0 | ||
- add `jpex.raw` function for extracting a factory function | ||
@@ -69,5 +81,7 @@ - add publicPath babel config option | ||
## 3.1.0 | ||
- global types like `Window` and `Document` can now be used to register dependencies | ||
## 3.0.1 | ||
- encase now caches the wrapped function for better performance | ||
@@ -79,2 +93,3 @@ - alias is now bidirectional, so it determines which is the alias and which is the original | ||
## 3.0.0 | ||
- Complete rewrite of the entire library | ||
@@ -94,2 +109,3 @@ - Typescript support | ||
## 2.1.0 | ||
- if an option in the `properties` config is null, jpex will no longer throw an error | ||
@@ -100,65 +116,82 @@ - Passing `$options` into a `Jpex as a Service` service now works | ||
## 2.0.0 | ||
### Features | ||
- Can now pass in a `config` option when extending a class. Any properties of the config option will be used as default values for that class and its descendants. | ||
- The default lifecycle for factories registered against a class can now be configured using the `defaultLifecycle` option. | ||
- Methods option has been added (which replaces the *prototype* option from v1). | ||
- Properties option has been added, allowing you to predefine getters, setters, and watchers on any instance properties. | ||
- the `bindToInstance` option can now accept a nested property name, i.e. `bindToInstance : 'foo.bah'` | ||
- Node-specific code has been isolated so the core *jpex* module can be included in any webpack/browserify build. (*see depcrecation of jpex-web below*) | ||
- Added a pre-compiled build of Jpex at `jpex/dist/jpex.js` and `jpex/dist/jpex.min.js` | ||
- Default factories (`$timeout`, `$promise`, etc.) have been separated from the core module. They now must be installed separately from the **jpex-defaults**, **jpex-node**, and **jpex-web** packages. | ||
- The `$resolve` method is now available as a static method on every class, so dependencies can be resolved with `Class.$resolve(name)`. This allows for **Jpex** to be used as a container rather than forcing the class instantiation pattern. | ||
- `$resolve` can be called with an array of dependencies to resolve instead of just one. | ||
- Cached factories (i.e. with a `class` or `application` lifecycle) can be cleared with `Class.$clearCache()`. | ||
- Added `decorators` that allow a factory to be altered before being resolved. Can be registered like normal factories i.e. `Class.register.decorator(name, fn)` | ||
- A complete plugin API has been created that allows plugins to hook into a number of lifecycle events. | ||
## 2.0.0 | ||
### Breaking Changes | ||
- The `prototype` option has been replaced with `methods` | ||
- The **jpex-web** version of Jpex has been deprecated. Instead, Jpex can be `required`'d with *webpack/browserify*, or a web-safe js file can be found at `jpex/dist/jpex.js/` | ||
- Internal variables have been renamed. e.g. `Class._factories` is now `Class.$$factories`. | ||
### Features | ||
- Can now pass in a `config` option when extending a class. Any properties of the config option will be used as default values for that class and its descendants. | ||
- The default lifecycle for factories registered against a class can now be configured using the `defaultLifecycle` option. | ||
- Methods option has been added (which replaces the _prototype_ option from v1). | ||
- Properties option has been added, allowing you to predefine getters, setters, and watchers on any instance properties. | ||
- the `bindToInstance` option can now accept a nested property name, i.e. `bindToInstance : 'foo.bah'` | ||
- Node-specific code has been isolated so the core _jpex_ module can be included in any webpack/browserify build. (_see depcrecation of jpex-web below_) | ||
- Added a pre-compiled build of Jpex at `jpex/dist/jpex.js` and `jpex/dist/jpex.min.js` | ||
- Default factories (`$timeout`, `$promise`, etc.) have been separated from the core module. They now must be installed separately from the **jpex-defaults**, **jpex-node**, and **jpex-web** packages. | ||
- After deprecating its use in v1.3.0, the `singleton` option has been removed from factory registration. `Class.register.factory(name, fn, true/false)` should now be written as `Class.register.factory(name, fn).lifecycle.application()` | ||
- Following depcrecation in v1.4.0, the static methods `Typeof` and `Copy` have been removed. | ||
- Factory registration methods have been renamed to camelCase: `Jpex.Register.Factory` becomes `Jpex.register.factory`, for example. | ||
- `Interfaces` have been completely removed from the module. This was an experimental feature that in the end was more overhead than it was worth. | ||
- A number of spurious factory types have been removed: *enum, errorType, file, folder, interface, nodeModule* - although the *nodeModule* factory type is still available via the **jpex-node** package as `Class.register.node_module`. | ||
- Ancestoral dependencies have been removed so depending on `["^someParentFactory"]` will no longer work. The equivalent can now be achieved with *decorators*. | ||
- The `$resolve` method is now available as a static method on every class, so dependencies can be resolved with `Class.$resolve(name)`. This allows for **Jpex** to be used as a container rather than forcing the class instantiation pattern. | ||
- `$resolve` can be called with an array of dependencies to resolve instead of just one. | ||
- Cached factories (i.e. with a `class` or `application` lifecycle) can be cleared with `Class.$clearCache()`. | ||
- Added `decorators` that allow a factory to be altered before being resolved. Can be registered like normal factories i.e. `Class.register.decorator(name, fn)` | ||
- A complete plugin API has been created that allows plugins to hook into a number of lifecycle events. | ||
## 1.4.1 | ||
### Bugs | ||
- `$copy.extend` no longer combines arrays, but instead replaces the previous array value. | ||
- `$timeout $immediate $interval $tick` bug fixed when attaching to a class instance. | ||
- Added a `clear()` method to the timer factories that clear the respective timeouts. | ||
### Breaking Changes | ||
## 1.4.0 | ||
### Features | ||
- $typeof factory is available which returns the type of an object. | ||
- $copy factory allows you create a deep or shallow copy of an object, or combine multiple objects. | ||
- $itypeof and $icopy interfaces | ||
- The static methods Jpex.Typeof and Jpex.Copy have been deprecated and will be removed in a future release. | ||
- $resolve factory which allows lazy loading of dependencies. | ||
### Breaking Changes | ||
- Calling `Class()` is now the same as calling `new Class()` so calls like `Class.call(obj)===obj` will no longer work. | ||
- The `prototype` option has been replaced with `methods` | ||
- The **jpex-web** version of Jpex has been deprecated. Instead, Jpex can be `required`'d with _webpack/browserify_, or a web-safe js file can be found at `jpex/dist/jpex.js/` | ||
- Internal variables have been renamed. e.g. `Class._factories` is now `Class.$$factories`. | ||
- Default factories (`$timeout`, `$promise`, etc.) have been separated from the core module. They now must be installed separately from the **jpex-defaults**, **jpex-node**, and **jpex-web** packages. | ||
- After deprecating its use in v1.3.0, the `singleton` option has been removed from factory registration. `Class.register.factory(name, fn, true/false)` should now be written as `Class.register.factory(name, fn).lifecycle.application()` | ||
- Following depcrecation in v1.4.0, the static methods `Typeof` and `Copy` have been removed. | ||
- Factory registration methods have been renamed to camelCase: `Jpex.Register.Factory` becomes `Jpex.register.factory`, for example. | ||
- `Interfaces` have been completely removed from the module. This was an experimental feature that in the end was more overhead than it was worth. | ||
- A number of spurious factory types have been removed: _enum, errorType, file, folder, interface, nodeModule_ - although the _nodeModule_ factory type is still available via the **jpex-node** package as `Class.register.node_module`. | ||
- Ancestoral dependencies have been removed so depending on `["^someParentFactory"]` will no longer work. The equivalent can now be achieved with _decorators_. | ||
## 1.3.1 | ||
### Bugs | ||
- Fixed issues where `require`-based functions were not requiring from the correct location. | ||
## 1.4.1 | ||
### Bugs | ||
- `$copy.extend` no longer combines arrays, but instead replaces the previous array value. | ||
- `$timeout $immediate $interval $tick` bug fixed when attaching to a class instance. | ||
- Added a `clear()` method to the timer factories that clear the respective timeouts. | ||
## 1.4.0 | ||
### Features | ||
- $typeof factory is available which returns the type of an object. | ||
- $copy factory allows you create a deep or shallow copy of an object, or combine multiple objects. | ||
- $itypeof and $icopy interfaces | ||
- The static methods Jpex.Typeof and Jpex.Copy have been deprecated and will be removed in a future release. | ||
- $resolve factory which allows lazy loading of dependencies. | ||
### Breaking Changes | ||
- Calling `Class()` is now the same as calling `new Class()` so calls like `Class.call(obj)===obj` will no longer work. | ||
## 1.3.1 | ||
### Bugs | ||
- Fixed issues where `require`-based functions were not requiring from the correct location. | ||
## 1.3.0 | ||
### Features | ||
- Interfaces functionality added | ||
- Registering a factory returns an object with additional option methods (currently only contains the *interface()* method) | ||
- It is now possible to specify the life cycle of a factory or service using the `.lifecycle.x()` syntax. Possible options are `application`, `class`, `instance`, `none` | ||
- Due to the introduction of life cycles, the *singleton* parameter has been deprecated. | ||
- Interfaces functionality added | ||
- Registering a factory returns an object with additional option methods (currently only contains the _interface()_ method) | ||
- It is now possible to specify the life cycle of a factory or service using the `.lifecycle.x()` syntax. Possible options are `application`, `class`, `instance`, `none` | ||
- Due to the introduction of life cycles, the _singleton_ parameter has been deprecated. | ||
### Breaking Changes | ||
- All $ factories now have interfaces (i.e. *$ipromise*). If you have overwritten a default factory that is used by another default factory, it will need to include the interface in order to work. i.e. *$fs* used to depend on *$promise* but it now depends on $ipromise. | ||
## 1.2.0 | ||
### Features | ||
- Added detailed documentation | ||
- $error factory and $errorFactory factory | ||
- ErrorType Factory i.e. `jpex.Register.ErrorType('Custom')` | ||
- Ancestoral dependencies i.e. `['^$errorFactory']` | ||
- Deprecated jpex-fs as it is now included in the standard jpex build | ||
- All $ factories now have interfaces (i.e. _$ipromise_). If you have overwritten a default factory that is used by another default factory, it will need to include the interface in order to work. i.e. _$fs_ used to depend on _$promise_ but it now depends on $ipromise. | ||
## 1.2.0 | ||
### Features | ||
- Added detailed documentation | ||
- $error factory and $errorFactory factory | ||
- ErrorType Factory i.e. `jpex.Register.ErrorType('Custom')` | ||
- Ancestoral dependencies i.e. `['^$errorFactory']` | ||
- Deprecated jpex-fs as it is now included in the standard jpex build |
@@ -5,31 +5,40 @@ 'use strict'; | ||
function constant(name, obj) { | ||
return this.factory(name, [], () => obj, { | ||
lifecycle: 'application' | ||
}); | ||
} | ||
const isString = obj => typeof obj === 'string'; | ||
const isFunction = obj => typeof obj === 'function'; | ||
const validateName = name => { | ||
if (!isString(name)) { | ||
throw new Error(`Name must be a string, but recevied ${typeof name}`); | ||
} | ||
}; | ||
const validateDependencies = dependencies => { | ||
if (!Array.isArray(dependencies)) { | ||
throw new Error(`Expected an array of dependencies, but was called with [${typeof dependencies}]`); | ||
} | ||
}; | ||
const validateFactory = (name, fn) => { | ||
if (!isFunction(fn)) { | ||
throw new Error(`Factory ${name} must be a [Function]`); | ||
} | ||
}; | ||
const validateArgs = (name, dependencies, fn) => { | ||
validateName(name); | ||
validateDependencies(dependencies); | ||
validateFactory(name, fn); | ||
}; | ||
const isPassive = (name, jpex, precedence) => { | ||
return (precedence || jpex.$$config.precedence) === 'passive' && jpex.$$factories[name] != null; | ||
}; | ||
const instantiate = (context, args) => { | ||
// eslint-disable-next-line new-parens | ||
return new (Function.prototype.bind.apply(context, args))(); | ||
}; | ||
const isNode = () => { | ||
let _process; // eslint-disable-line no-underscore-dangle | ||
let _process; | ||
try { | ||
// eslint-disable-next-line no-new-func | ||
_process = new Function('return process')(); | ||
} catch (e) {// No process | ||
} // eslint-disable-next-line max-len | ||
} catch (e) { | ||
} | ||
return typeof _process === 'object' && _process.toString && _process.toString() === '[object process]'; | ||
}; // eslint-disable-next-line no-new-func | ||
}; | ||
const doUnsafeRequire = new Function('require', 'target', 'return require.main.require(target)'); | ||
const unsafeRequire = target => { | ||
// eslint-disable-next-line no-eval | ||
return doUnsafeRequire(eval('require'), target); | ||
@@ -41,7 +50,5 @@ }; | ||
} | ||
if (Array.isArray(arr)) { | ||
return arr; | ||
} | ||
return [arr]; | ||
@@ -51,28 +58,24 @@ }; | ||
const validateArgs = (name, dependencies, fn) => { | ||
if (!isString(name)) { | ||
throw new Error(`Factories must be given a name, but was called with [${typeof name}]`); | ||
function constant(name, obj) { | ||
validateName(name); | ||
if (isPassive(name, this)) { | ||
return; | ||
} | ||
this.$$factories[name] = { | ||
fn: () => obj, | ||
lifecycle: 'application', | ||
value: obj, | ||
resolved: true | ||
}; | ||
} | ||
if (!Array.isArray(dependencies)) { | ||
throw new Error(`Expected an array of dependencies, but was called with [${typeof dependencies}]`); | ||
} | ||
if (!isFunction(fn)) { | ||
throw new Error(`Factory ${name} must be a [Function]`); | ||
} | ||
}; | ||
function factory(name, dependencies, fn, opts = {}) { | ||
validateArgs(name, dependencies, fn); | ||
if (!hasLength(dependencies)) { | ||
dependencies = null; | ||
} // eslint-disable-next-line max-len | ||
if ((opts.precedence || this.$$config.precedence) === 'passive' && this.$$factories[name] != null) { | ||
} | ||
if (isPassive(name, this, opts.precedence)) { | ||
return; | ||
} | ||
const f = { | ||
this.$$factories[name] = { | ||
fn, | ||
@@ -82,4 +85,2 @@ dependencies, | ||
}; | ||
this.$$factories[name] = f; | ||
if (opts.alias) { | ||
@@ -92,6 +93,4 @@ ensureArray(opts.alias).forEach(alias => this.alias(alias, name)); | ||
validateArgs(name, dependencies, fn); | ||
function factory(...args) { | ||
const context = {}; | ||
if (opts.bindToInstance) { | ||
@@ -102,6 +101,4 @@ dependencies.forEach((key, i) => { | ||
} | ||
return instantiate(fn, [context, ...args]); | ||
} | ||
return this.factory(name, dependencies, factory, opts); | ||
@@ -114,3 +111,2 @@ } | ||
} | ||
if (this.$$alias[name] == null || this.$$config.precedence === 'active') { | ||
@@ -126,9 +122,5 @@ this.$$alias[name] = alias; | ||
const getFromNodeModules = (jpex, target) => { | ||
// in order to stop webpack environments from including every possible | ||
// import source in the bundle, we have to stick all node require stuff | ||
// inside an eval setup | ||
if (!jpex.$$config.nodeModules || !isNode()) { | ||
return; | ||
} | ||
try { | ||
@@ -140,42 +132,26 @@ const value = unsafeRequire(target); | ||
var _e$message; | ||
if ((_e$message = e.message) != null && _e$message.includes != null && _e$message.includes(`Cannot find module '${target}'`)) { | ||
// not found in node modules, just continue | ||
return; | ||
} | ||
throw e; | ||
} | ||
}; | ||
const getGlobalObject = () => { | ||
if (typeof global !== VOID) { | ||
// eslint-disable-next-line no-undef | ||
return global; | ||
} | ||
if (typeof globalThis !== VOID) { | ||
// eslint-disable-next-line no-undef | ||
return globalThis; | ||
} | ||
if (typeof window !== VOID) { | ||
return window; | ||
} | ||
return {}; | ||
}; | ||
const getGlobalProperty = name => { | ||
const global = getGlobalObject(); | ||
if (global[name] !== void 0) { | ||
return global[name]; | ||
} // we need to handle inferred types as well | ||
// this gets a little bit hacky... | ||
} | ||
if (name.startsWith(GLOBAL_TYPE_PREFIX)) { | ||
// most global types will just be the name of the property in pascal case | ||
// i.e. window = Window / document = Document | ||
const len = GLOBAL_TYPE_PREFIX.length; | ||
@@ -186,3 +162,2 @@ const inferredName = name.charAt(len).toLowerCase() + name.substr(len + 1); | ||
}; | ||
const getFromGlobal = (jpex, name) => { | ||
@@ -192,5 +167,3 @@ if (!jpex.$$config.globals) { | ||
} | ||
const value = getGlobalProperty(name); | ||
if (value !== void 0) { | ||
@@ -201,12 +174,4 @@ jpex.constant(name, value); | ||
}; | ||
const validateArgs$1 = name => { | ||
if (!isString(name)) { | ||
throw new Error(`Name must be a string, but recevied ${typeof name}`); | ||
} | ||
}; | ||
const getFromAlias = (jpex, alias) => { | ||
const name = jpex.$$alias[alias]; | ||
if (name != null) { | ||
@@ -216,20 +181,14 @@ return jpex.$$factories[name]; | ||
}; | ||
const getFromResolved = (jpex, name) => { | ||
return jpex.$$resolved[name]; | ||
}; | ||
const getFromRegistry = (jpex, name) => { | ||
return jpex.$$factories[name]; | ||
}; | ||
const getFactory = (jpex, name, opts = {}) => { | ||
var _opts$optional; | ||
validateArgs$1(name); | ||
validateName(name); | ||
const fns = [getFromResolved, getFromRegistry, getFromAlias, getFromGlobal, getFromNodeModules]; | ||
while (fns.length) { | ||
const factory = fns.shift()(jpex, name); | ||
if (factory != null) { | ||
@@ -239,10 +198,8 @@ return factory; | ||
} | ||
if ((_opts$optional = opts.optional) != null ? _opts$optional : jpex.$$config.optional) { | ||
return; | ||
} | ||
throw new Error(`Unable to find required dependency [${name}]`); | ||
}; | ||
const cacheResult = (jpex, name, factory, value, namedParameters) => { | ||
const cacheResult = (jpex, name, factory, value, namedParameters, withArg) => { | ||
switch (factory.lifecycle) { | ||
@@ -252,41 +209,29 @@ case 'application': | ||
factory.value = value; | ||
factory.with = withArg; | ||
break; | ||
case 'class': | ||
jpex.$$resolved[name] = { | ||
jpex.$$resolved[name] = { ...factory, | ||
resolved: true, | ||
value | ||
value, | ||
with: withArg | ||
}; | ||
break; | ||
case 'none': | ||
break; | ||
case 'instance': | ||
default: | ||
// instance | ||
namedParameters[name] = value; | ||
break; | ||
} | ||
}; // Ensure we're not stuck in a recursive loop | ||
}; | ||
const checkStack = (jpex, name, stack) => { | ||
if (!hasLength(stack)) { | ||
// This is the first loop | ||
return false; | ||
} | ||
if (!stack.includes(name)) { | ||
// We've definitely not tried to resolve this one before | ||
return false; | ||
} | ||
if (stack[stack.length - 1] === name) { | ||
var _jpex$$$parent; | ||
// We've tried to resolve this one before, but... | ||
// if this factory has overridden a parent factory | ||
// we should assume it actually wants to resolve the parent | ||
const parent = (_jpex$$$parent = jpex.$$parent) == null ? void 0 : _jpex$$$parent.$$factories[name]; | ||
if (parent != null) { | ||
@@ -296,3 +241,2 @@ return true; | ||
} | ||
throw new Error(`Recursive loop for dependency ${name} encountered`); | ||
@@ -305,3 +249,2 @@ }; | ||
} | ||
if (opts.with) { | ||
@@ -311,67 +254,47 @@ return { ...opts.with | ||
} | ||
return {}; | ||
}; | ||
const isResolvedWithParams = (factory, opts = {}) => { | ||
if (!factory.with && !opts.with) { | ||
return true; | ||
} | ||
const keys = [...new Set([...Object.keys((opts == null ? void 0 : opts.with) || {}), ...Object.keys(factory.with || {})])]; | ||
return keys.every(key => { | ||
var _opts$with; | ||
return (opts == null ? void 0 : (_opts$with = opts.with) == null ? void 0 : _opts$with[key]) === factory.with[key]; | ||
}); | ||
}; | ||
const resolveFactory = (jpex, name, factory, namedParameters, opts, stack) => { | ||
if (factory == null) { | ||
return; | ||
} // Check if it's already been resolved | ||
if (factory.resolved) { | ||
} | ||
if (factory.resolved && isResolvedWithParams(factory, opts)) { | ||
return factory.value; | ||
} // Work out dependencies | ||
} | ||
let args = []; | ||
if (hasLength(factory.dependencies)) { | ||
// eslint-disable-next-line no-use-before-define | ||
args = resolveMany(jpex, factory, namedParameters, opts, [...stack, name]); | ||
} // Invoke the factory | ||
const value = factory.fn.apply(jpex, args); // Cache the result | ||
cacheResult(jpex, name, factory, value, namedParameters); | ||
} | ||
const value = factory.fn.apply(jpex, args); | ||
cacheResult(jpex, name, factory, value, namedParameters, opts == null ? void 0 : opts.with); | ||
return value; | ||
}; | ||
const resolveOne = (jpex, name, initialParameters, opts, stack) => { | ||
const namedParameters = getNamedParameters(initialParameters, opts); // Check named parameters | ||
// if we have a named parameter for this dependency | ||
// we don't need to do any resolution, we can just return the value | ||
const namedParameters = getNamedParameters(initialParameters, opts); | ||
if (Object.hasOwnProperty.call(namedParameters, name)) { | ||
return namedParameters[name]; | ||
} // Special keys | ||
} | ||
if (name === NAMED_PARAMS || name === "type:jpex/NamedParameters") { | ||
return namedParameters; | ||
} | ||
if (checkStack(jpex, name, stack)) { | ||
// Yes we have tried to resolve this one before, but we could | ||
// actually just be resolving an inherited factory | ||
return resolveOne(jpex.$$parent, name, namedParameters, opts, []); | ||
} // Get the factory | ||
// This will either return the factory, | ||
// return null (meaning it's an optional dependency) | ||
// or throw an error | ||
} | ||
const factory = getFactory(jpex, name, opts); | ||
return resolveFactory(jpex, name, factory, namedParameters, opts, stack); | ||
}; | ||
const resolveMany = (jpex, definition, namedParameters, opts, stack) => { | ||
const resolveMany = (jpex, definition, namedParameters, opts, stack = []) => { | ||
if (!hasLength(definition.dependencies)) { | ||
return []; | ||
} | ||
if (!stack) { | ||
stack = []; | ||
} | ||
const dependencies = ensureArray(definition.dependencies); | ||
@@ -392,11 +315,8 @@ const values = dependencies.map(dependency => { | ||
var _this$$$factories$dep; | ||
if (!isString(dependency)) { | ||
return false; | ||
} | ||
if (this.$$resolved[dependency] != null) { | ||
return true; | ||
} | ||
return ((_this$$$factories$dep = this.$$factories[dependency]) == null ? void 0 : _this$$$factories$dep.resolved) === true; | ||
@@ -411,9 +331,6 @@ } | ||
let result; | ||
const encased = function (...args) { | ||
/* eslint-disable no-invalid-this */ | ||
const encased = function encased(...args) { | ||
if (result && allResolved.call(jpex, dependencies)) { | ||
return result.apply(this, args); | ||
} | ||
const deps = resolveDependencies.call(jpex, { | ||
@@ -424,5 +341,3 @@ dependencies | ||
return result.apply(this, args); | ||
/* eslint-enable */ | ||
}; | ||
encased.encased = fn; | ||
@@ -434,3 +349,2 @@ return encased; | ||
names = ensureArray(names); | ||
for (const key in this.$$factories) { | ||
@@ -441,3 +355,2 @@ if (!hasLength(names) || names.includes(key)) { | ||
} | ||
for (const key in this.$$resolved) { | ||
@@ -477,7 +390,5 @@ if (!hasLength(names) || names.includes(key)) { | ||
clearCache, | ||
extend(config) { | ||
return makeJpex(config, this); | ||
}, | ||
resolveWith(name, namedParameters, opts) { | ||
@@ -489,7 +400,5 @@ return this.resolve(name, { | ||
}, | ||
raw(name) { | ||
return getFactory(this, name, {}).fn; | ||
}, | ||
infer: () => '' | ||
@@ -496,0 +405,0 @@ }; |
@@ -1,30 +0,39 @@ | ||
function constant(name, obj) { | ||
return this.factory(name, [], () => obj, { | ||
lifecycle: 'application' | ||
}); | ||
} | ||
const isString = obj => typeof obj === 'string'; | ||
const isFunction = obj => typeof obj === 'function'; | ||
const validateName = name => { | ||
if (!isString(name)) { | ||
throw new Error(`Name must be a string, but recevied ${typeof name}`); | ||
} | ||
}; | ||
const validateDependencies = dependencies => { | ||
if (!Array.isArray(dependencies)) { | ||
throw new Error(`Expected an array of dependencies, but was called with [${typeof dependencies}]`); | ||
} | ||
}; | ||
const validateFactory = (name, fn) => { | ||
if (!isFunction(fn)) { | ||
throw new Error(`Factory ${name} must be a [Function]`); | ||
} | ||
}; | ||
const validateArgs = (name, dependencies, fn) => { | ||
validateName(name); | ||
validateDependencies(dependencies); | ||
validateFactory(name, fn); | ||
}; | ||
const isPassive = (name, jpex, precedence) => { | ||
return (precedence || jpex.$$config.precedence) === 'passive' && jpex.$$factories[name] != null; | ||
}; | ||
const instantiate = (context, args) => { | ||
// eslint-disable-next-line new-parens | ||
return new (Function.prototype.bind.apply(context, args))(); | ||
}; | ||
const isNode = () => { | ||
let _process; // eslint-disable-line no-underscore-dangle | ||
let _process; | ||
try { | ||
// eslint-disable-next-line no-new-func | ||
_process = new Function('return process')(); | ||
} catch (e) {// No process | ||
} // eslint-disable-next-line max-len | ||
} catch (e) { | ||
} | ||
return typeof _process === 'object' && _process.toString && _process.toString() === '[object process]'; | ||
}; // eslint-disable-next-line no-new-func | ||
}; | ||
const doUnsafeRequire = new Function('require', 'target', 'return require.main.require(target)'); | ||
const unsafeRequire = target => { | ||
// eslint-disable-next-line no-eval | ||
return doUnsafeRequire(eval('require'), target); | ||
@@ -36,7 +45,5 @@ }; | ||
} | ||
if (Array.isArray(arr)) { | ||
return arr; | ||
} | ||
return [arr]; | ||
@@ -46,28 +53,24 @@ }; | ||
const validateArgs = (name, dependencies, fn) => { | ||
if (!isString(name)) { | ||
throw new Error(`Factories must be given a name, but was called with [${typeof name}]`); | ||
function constant(name, obj) { | ||
validateName(name); | ||
if (isPassive(name, this)) { | ||
return; | ||
} | ||
this.$$factories[name] = { | ||
fn: () => obj, | ||
lifecycle: 'application', | ||
value: obj, | ||
resolved: true | ||
}; | ||
} | ||
if (!Array.isArray(dependencies)) { | ||
throw new Error(`Expected an array of dependencies, but was called with [${typeof dependencies}]`); | ||
} | ||
if (!isFunction(fn)) { | ||
throw new Error(`Factory ${name} must be a [Function]`); | ||
} | ||
}; | ||
function factory(name, dependencies, fn, opts = {}) { | ||
validateArgs(name, dependencies, fn); | ||
if (!hasLength(dependencies)) { | ||
dependencies = null; | ||
} // eslint-disable-next-line max-len | ||
if ((opts.precedence || this.$$config.precedence) === 'passive' && this.$$factories[name] != null) { | ||
} | ||
if (isPassive(name, this, opts.precedence)) { | ||
return; | ||
} | ||
const f = { | ||
this.$$factories[name] = { | ||
fn, | ||
@@ -77,4 +80,2 @@ dependencies, | ||
}; | ||
this.$$factories[name] = f; | ||
if (opts.alias) { | ||
@@ -87,6 +88,4 @@ ensureArray(opts.alias).forEach(alias => this.alias(alias, name)); | ||
validateArgs(name, dependencies, fn); | ||
function factory(...args) { | ||
const context = {}; | ||
if (opts.bindToInstance) { | ||
@@ -97,6 +96,4 @@ dependencies.forEach((key, i) => { | ||
} | ||
return instantiate(fn, [context, ...args]); | ||
} | ||
return this.factory(name, dependencies, factory, opts); | ||
@@ -109,3 +106,2 @@ } | ||
} | ||
if (this.$$alias[name] == null || this.$$config.precedence === 'active') { | ||
@@ -121,9 +117,5 @@ this.$$alias[name] = alias; | ||
const getFromNodeModules = (jpex, target) => { | ||
// in order to stop webpack environments from including every possible | ||
// import source in the bundle, we have to stick all node require stuff | ||
// inside an eval setup | ||
if (!jpex.$$config.nodeModules || !isNode()) { | ||
return; | ||
} | ||
try { | ||
@@ -135,42 +127,26 @@ const value = unsafeRequire(target); | ||
var _e$message; | ||
if ((_e$message = e.message) != null && _e$message.includes != null && _e$message.includes(`Cannot find module '${target}'`)) { | ||
// not found in node modules, just continue | ||
return; | ||
} | ||
throw e; | ||
} | ||
}; | ||
const getGlobalObject = () => { | ||
if (typeof global !== VOID) { | ||
// eslint-disable-next-line no-undef | ||
return global; | ||
} | ||
if (typeof globalThis !== VOID) { | ||
// eslint-disable-next-line no-undef | ||
return globalThis; | ||
} | ||
if (typeof window !== VOID) { | ||
return window; | ||
} | ||
return {}; | ||
}; | ||
const getGlobalProperty = name => { | ||
const global = getGlobalObject(); | ||
if (global[name] !== void 0) { | ||
return global[name]; | ||
} // we need to handle inferred types as well | ||
// this gets a little bit hacky... | ||
} | ||
if (name.startsWith(GLOBAL_TYPE_PREFIX)) { | ||
// most global types will just be the name of the property in pascal case | ||
// i.e. window = Window / document = Document | ||
const len = GLOBAL_TYPE_PREFIX.length; | ||
@@ -181,3 +157,2 @@ const inferredName = name.charAt(len).toLowerCase() + name.substr(len + 1); | ||
}; | ||
const getFromGlobal = (jpex, name) => { | ||
@@ -187,5 +162,3 @@ if (!jpex.$$config.globals) { | ||
} | ||
const value = getGlobalProperty(name); | ||
if (value !== void 0) { | ||
@@ -196,12 +169,4 @@ jpex.constant(name, value); | ||
}; | ||
const validateArgs$1 = name => { | ||
if (!isString(name)) { | ||
throw new Error(`Name must be a string, but recevied ${typeof name}`); | ||
} | ||
}; | ||
const getFromAlias = (jpex, alias) => { | ||
const name = jpex.$$alias[alias]; | ||
if (name != null) { | ||
@@ -211,20 +176,14 @@ return jpex.$$factories[name]; | ||
}; | ||
const getFromResolved = (jpex, name) => { | ||
return jpex.$$resolved[name]; | ||
}; | ||
const getFromRegistry = (jpex, name) => { | ||
return jpex.$$factories[name]; | ||
}; | ||
const getFactory = (jpex, name, opts = {}) => { | ||
var _opts$optional; | ||
validateArgs$1(name); | ||
validateName(name); | ||
const fns = [getFromResolved, getFromRegistry, getFromAlias, getFromGlobal, getFromNodeModules]; | ||
while (fns.length) { | ||
const factory = fns.shift()(jpex, name); | ||
if (factory != null) { | ||
@@ -234,10 +193,8 @@ return factory; | ||
} | ||
if ((_opts$optional = opts.optional) != null ? _opts$optional : jpex.$$config.optional) { | ||
return; | ||
} | ||
throw new Error(`Unable to find required dependency [${name}]`); | ||
}; | ||
const cacheResult = (jpex, name, factory, value, namedParameters) => { | ||
const cacheResult = (jpex, name, factory, value, namedParameters, withArg) => { | ||
switch (factory.lifecycle) { | ||
@@ -247,41 +204,29 @@ case 'application': | ||
factory.value = value; | ||
factory.with = withArg; | ||
break; | ||
case 'class': | ||
jpex.$$resolved[name] = { | ||
jpex.$$resolved[name] = { ...factory, | ||
resolved: true, | ||
value | ||
value, | ||
with: withArg | ||
}; | ||
break; | ||
case 'none': | ||
break; | ||
case 'instance': | ||
default: | ||
// instance | ||
namedParameters[name] = value; | ||
break; | ||
} | ||
}; // Ensure we're not stuck in a recursive loop | ||
}; | ||
const checkStack = (jpex, name, stack) => { | ||
if (!hasLength(stack)) { | ||
// This is the first loop | ||
return false; | ||
} | ||
if (!stack.includes(name)) { | ||
// We've definitely not tried to resolve this one before | ||
return false; | ||
} | ||
if (stack[stack.length - 1] === name) { | ||
var _jpex$$$parent; | ||
// We've tried to resolve this one before, but... | ||
// if this factory has overridden a parent factory | ||
// we should assume it actually wants to resolve the parent | ||
const parent = (_jpex$$$parent = jpex.$$parent) == null ? void 0 : _jpex$$$parent.$$factories[name]; | ||
if (parent != null) { | ||
@@ -291,3 +236,2 @@ return true; | ||
} | ||
throw new Error(`Recursive loop for dependency ${name} encountered`); | ||
@@ -300,3 +244,2 @@ }; | ||
} | ||
if (opts.with) { | ||
@@ -306,67 +249,47 @@ return { ...opts.with | ||
} | ||
return {}; | ||
}; | ||
const isResolvedWithParams = (factory, opts = {}) => { | ||
if (!factory.with && !opts.with) { | ||
return true; | ||
} | ||
const keys = [...new Set([...Object.keys((opts == null ? void 0 : opts.with) || {}), ...Object.keys(factory.with || {})])]; | ||
return keys.every(key => { | ||
var _opts$with; | ||
return (opts == null ? void 0 : (_opts$with = opts.with) == null ? void 0 : _opts$with[key]) === factory.with[key]; | ||
}); | ||
}; | ||
const resolveFactory = (jpex, name, factory, namedParameters, opts, stack) => { | ||
if (factory == null) { | ||
return; | ||
} // Check if it's already been resolved | ||
if (factory.resolved) { | ||
} | ||
if (factory.resolved && isResolvedWithParams(factory, opts)) { | ||
return factory.value; | ||
} // Work out dependencies | ||
} | ||
let args = []; | ||
if (hasLength(factory.dependencies)) { | ||
// eslint-disable-next-line no-use-before-define | ||
args = resolveMany(jpex, factory, namedParameters, opts, [...stack, name]); | ||
} // Invoke the factory | ||
const value = factory.fn.apply(jpex, args); // Cache the result | ||
cacheResult(jpex, name, factory, value, namedParameters); | ||
} | ||
const value = factory.fn.apply(jpex, args); | ||
cacheResult(jpex, name, factory, value, namedParameters, opts == null ? void 0 : opts.with); | ||
return value; | ||
}; | ||
const resolveOne = (jpex, name, initialParameters, opts, stack) => { | ||
const namedParameters = getNamedParameters(initialParameters, opts); // Check named parameters | ||
// if we have a named parameter for this dependency | ||
// we don't need to do any resolution, we can just return the value | ||
const namedParameters = getNamedParameters(initialParameters, opts); | ||
if (Object.hasOwnProperty.call(namedParameters, name)) { | ||
return namedParameters[name]; | ||
} // Special keys | ||
} | ||
if (name === NAMED_PARAMS || name === "type:jpex/NamedParameters") { | ||
return namedParameters; | ||
} | ||
if (checkStack(jpex, name, stack)) { | ||
// Yes we have tried to resolve this one before, but we could | ||
// actually just be resolving an inherited factory | ||
return resolveOne(jpex.$$parent, name, namedParameters, opts, []); | ||
} // Get the factory | ||
// This will either return the factory, | ||
// return null (meaning it's an optional dependency) | ||
// or throw an error | ||
} | ||
const factory = getFactory(jpex, name, opts); | ||
return resolveFactory(jpex, name, factory, namedParameters, opts, stack); | ||
}; | ||
const resolveMany = (jpex, definition, namedParameters, opts, stack) => { | ||
const resolveMany = (jpex, definition, namedParameters, opts, stack = []) => { | ||
if (!hasLength(definition.dependencies)) { | ||
return []; | ||
} | ||
if (!stack) { | ||
stack = []; | ||
} | ||
const dependencies = ensureArray(definition.dependencies); | ||
@@ -387,11 +310,8 @@ const values = dependencies.map(dependency => { | ||
var _this$$$factories$dep; | ||
if (!isString(dependency)) { | ||
return false; | ||
} | ||
if (this.$$resolved[dependency] != null) { | ||
return true; | ||
} | ||
return ((_this$$$factories$dep = this.$$factories[dependency]) == null ? void 0 : _this$$$factories$dep.resolved) === true; | ||
@@ -406,9 +326,6 @@ } | ||
let result; | ||
const encased = function (...args) { | ||
/* eslint-disable no-invalid-this */ | ||
const encased = function encased(...args) { | ||
if (result && allResolved.call(jpex, dependencies)) { | ||
return result.apply(this, args); | ||
} | ||
const deps = resolveDependencies.call(jpex, { | ||
@@ -419,5 +336,3 @@ dependencies | ||
return result.apply(this, args); | ||
/* eslint-enable */ | ||
}; | ||
encased.encased = fn; | ||
@@ -429,3 +344,2 @@ return encased; | ||
names = ensureArray(names); | ||
for (const key in this.$$factories) { | ||
@@ -436,3 +350,2 @@ if (!hasLength(names) || names.includes(key)) { | ||
} | ||
for (const key in this.$$resolved) { | ||
@@ -472,7 +385,5 @@ if (!hasLength(names) || names.includes(key)) { | ||
clearCache, | ||
extend(config) { | ||
return makeJpex(config, this); | ||
}, | ||
resolveWith(name, namedParameters, opts) { | ||
@@ -484,7 +395,5 @@ return this.resolve(name, { | ||
}, | ||
raw(name) { | ||
return getFactory(this, name, {}).fn; | ||
}, | ||
infer: () => '' | ||
@@ -491,0 +400,0 @@ }; |
245
dist/es5.js
@@ -38,10 +38,2 @@ 'use strict'; | ||
function constant(name, obj) { | ||
return this.factory(name, [], function () { | ||
return obj; | ||
}, { | ||
lifecycle: 'application' | ||
}); | ||
} | ||
var isString = function isString(obj) { | ||
@@ -53,23 +45,38 @@ return typeof obj === 'string'; | ||
}; | ||
var validateName = function validateName(name) { | ||
if (!isString(name)) { | ||
throw new Error("Name must be a string, but recevied " + typeof name); | ||
} | ||
}; | ||
var validateDependencies = function validateDependencies(dependencies) { | ||
if (!Array.isArray(dependencies)) { | ||
throw new Error("Expected an array of dependencies, but was called with [" + typeof dependencies + "]"); | ||
} | ||
}; | ||
var validateFactory = function validateFactory(name, fn) { | ||
if (!isFunction(fn)) { | ||
throw new Error("Factory " + name + " must be a [Function]"); | ||
} | ||
}; | ||
var validateArgs = function validateArgs(name, dependencies, fn) { | ||
validateName(name); | ||
validateDependencies(dependencies); | ||
validateFactory(name, fn); | ||
}; | ||
var isPassive = function isPassive(name, jpex, precedence) { | ||
return (precedence || jpex.$$config.precedence) === 'passive' && jpex.$$factories[name] != null; | ||
}; | ||
var instantiate = function instantiate(context, args) { | ||
// eslint-disable-next-line new-parens | ||
return new (Function.prototype.bind.apply(context, args))(); | ||
}; | ||
var isNode = function isNode() { | ||
var _process; // eslint-disable-line no-underscore-dangle | ||
var _process; | ||
try { | ||
// eslint-disable-next-line no-new-func | ||
_process = new Function('return process')(); | ||
} catch (e) {// No process | ||
} // eslint-disable-next-line max-len | ||
} catch (e) { | ||
} | ||
return typeof _process === 'object' && _process.toString && _process.toString() === '[object process]'; | ||
}; // eslint-disable-next-line no-new-func | ||
}; | ||
var doUnsafeRequire = new Function('require', 'target', 'return require.main.require(target)'); | ||
var unsafeRequire = function unsafeRequire(target) { | ||
// eslint-disable-next-line no-eval | ||
return doUnsafeRequire(eval('require'), target); | ||
@@ -81,7 +88,5 @@ }; | ||
} | ||
if (Array.isArray(arr)) { | ||
return arr; | ||
} | ||
return [arr]; | ||
@@ -93,34 +98,30 @@ }; | ||
var validateArgs = function validateArgs(name, dependencies, fn) { | ||
if (!isString(name)) { | ||
throw new Error("Factories must be given a name, but was called with [" + typeof name + "]"); | ||
function constant(name, obj) { | ||
validateName(name); | ||
if (isPassive(name, this)) { | ||
return; | ||
} | ||
this.$$factories[name] = { | ||
fn: function fn() { | ||
return obj; | ||
}, | ||
lifecycle: 'application', | ||
value: obj, | ||
resolved: true | ||
}; | ||
} | ||
if (!Array.isArray(dependencies)) { | ||
throw new Error("Expected an array of dependencies, but was called with [" + typeof dependencies + "]"); | ||
} | ||
if (!isFunction(fn)) { | ||
throw new Error("Factory " + name + " must be a [Function]"); | ||
} | ||
}; | ||
function factory(name, dependencies, fn, opts) { | ||
var _this = this; | ||
if (opts === void 0) { | ||
opts = {}; | ||
} | ||
validateArgs(name, dependencies, fn); | ||
if (!hasLength(dependencies)) { | ||
dependencies = null; | ||
} // eslint-disable-next-line max-len | ||
if ((opts.precedence || this.$$config.precedence) === 'passive' && this.$$factories[name] != null) { | ||
} | ||
if (isPassive(name, this, opts.precedence)) { | ||
return; | ||
} | ||
var f = { | ||
this.$$factories[name] = { | ||
fn: fn, | ||
@@ -130,4 +131,2 @@ dependencies: dependencies, | ||
}; | ||
this.$$factories[name] = f; | ||
if (opts.alias) { | ||
@@ -144,5 +143,3 @@ ensureArray(opts.alias).forEach(function (alias) { | ||
} | ||
validateArgs(name, dependencies, fn); | ||
function factory() { | ||
@@ -152,5 +149,3 @@ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
} | ||
var context = {}; | ||
if (opts.bindToInstance) { | ||
@@ -161,6 +156,4 @@ dependencies.forEach(function (key, i) { | ||
} | ||
return instantiate(fn, [context].concat(args)); | ||
} | ||
return this.factory(name, dependencies, factory, opts); | ||
@@ -173,3 +166,2 @@ } | ||
} | ||
if (this.$$alias[name] == null || this.$$config.precedence === 'active') { | ||
@@ -185,9 +177,5 @@ this.$$alias[name] = alias; | ||
var getFromNodeModules = function getFromNodeModules(jpex, target) { | ||
// in order to stop webpack environments from including every possible | ||
// import source in the bundle, we have to stick all node require stuff | ||
// inside an eval setup | ||
if (!jpex.$$config.nodeModules || !isNode()) { | ||
return; | ||
} | ||
try { | ||
@@ -199,42 +187,26 @@ var value = unsafeRequire(target); | ||
var _e$message; | ||
if ((_e$message = e.message) != null && _e$message.includes != null && _e$message.includes("Cannot find module '" + target + "'")) { | ||
// not found in node modules, just continue | ||
return; | ||
} | ||
throw e; | ||
} | ||
}; | ||
var getGlobalObject = function getGlobalObject() { | ||
if (typeof global !== VOID) { | ||
// eslint-disable-next-line no-undef | ||
return global; | ||
} | ||
if (typeof globalThis !== VOID) { | ||
// eslint-disable-next-line no-undef | ||
return globalThis; | ||
} | ||
if (typeof window !== VOID) { | ||
return window; | ||
} | ||
return {}; | ||
}; | ||
var getGlobalProperty = function getGlobalProperty(name) { | ||
var global = getGlobalObject(); | ||
if (global[name] !== void 0) { | ||
return global[name]; | ||
} // we need to handle inferred types as well | ||
// this gets a little bit hacky... | ||
} | ||
if (name.startsWith(GLOBAL_TYPE_PREFIX)) { | ||
// most global types will just be the name of the property in pascal case | ||
// i.e. window = Window / document = Document | ||
var len = GLOBAL_TYPE_PREFIX.length; | ||
@@ -245,3 +217,2 @@ var inferredName = name.charAt(len).toLowerCase() + name.substr(len + 1); | ||
}; | ||
var getFromGlobal = function getFromGlobal(jpex, name) { | ||
@@ -251,5 +222,3 @@ if (!jpex.$$config.globals) { | ||
} | ||
var value = getGlobalProperty(name); | ||
if (value !== void 0) { | ||
@@ -260,12 +229,4 @@ jpex.constant(name, value); | ||
}; | ||
var validateArgs$1 = function validateArgs(name) { | ||
if (!isString(name)) { | ||
throw new Error("Name must be a string, but recevied " + typeof name); | ||
} | ||
}; | ||
var getFromAlias = function getFromAlias(jpex, alias) { | ||
var name = jpex.$$alias[alias]; | ||
if (name != null) { | ||
@@ -275,24 +236,17 @@ return jpex.$$factories[name]; | ||
}; | ||
var getFromResolved = function getFromResolved(jpex, name) { | ||
return jpex.$$resolved[name]; | ||
}; | ||
var getFromRegistry = function getFromRegistry(jpex, name) { | ||
return jpex.$$factories[name]; | ||
}; | ||
var getFactory = function getFactory(jpex, name, opts) { | ||
var _opts$optional; | ||
if (opts === void 0) { | ||
opts = {}; | ||
} | ||
validateArgs$1(name); | ||
validateName(name); | ||
var fns = [getFromResolved, getFromRegistry, getFromAlias, getFromGlobal, getFromNodeModules]; | ||
while (fns.length) { | ||
var factory = fns.shift()(jpex, name); | ||
if (factory != null) { | ||
@@ -302,10 +256,8 @@ return factory; | ||
} | ||
if ((_opts$optional = opts.optional) != null ? _opts$optional : jpex.$$config.optional) { | ||
return; | ||
} | ||
throw new Error("Unable to find required dependency [" + name + "]"); | ||
}; | ||
var cacheResult = function cacheResult(jpex, name, factory, value, namedParameters) { | ||
var cacheResult = function cacheResult(jpex, name, factory, value, namedParameters, withArg) { | ||
switch (factory.lifecycle) { | ||
@@ -315,41 +267,29 @@ case 'application': | ||
factory.value = value; | ||
factory.with = withArg; | ||
break; | ||
case 'class': | ||
jpex.$$resolved[name] = { | ||
jpex.$$resolved[name] = _extends({}, factory, { | ||
resolved: true, | ||
value: value | ||
}; | ||
value: value, | ||
with: withArg | ||
}); | ||
break; | ||
case 'none': | ||
break; | ||
case 'instance': | ||
default: | ||
// instance | ||
namedParameters[name] = value; | ||
break; | ||
} | ||
}; // Ensure we're not stuck in a recursive loop | ||
}; | ||
var checkStack = function checkStack(jpex, name, stack) { | ||
if (!hasLength(stack)) { | ||
// This is the first loop | ||
return false; | ||
} | ||
if (!stack.includes(name)) { | ||
// We've definitely not tried to resolve this one before | ||
return false; | ||
} | ||
if (stack[stack.length - 1] === name) { | ||
var _jpex$$$parent; | ||
// We've tried to resolve this one before, but... | ||
// if this factory has overridden a parent factory | ||
// we should assume it actually wants to resolve the parent | ||
var parent = (_jpex$$$parent = jpex.$$parent) == null ? void 0 : _jpex$$$parent.$$factories[name]; | ||
if (parent != null) { | ||
@@ -359,3 +299,2 @@ return true; | ||
} | ||
throw new Error("Recursive loop for dependency " + name + " encountered"); | ||
@@ -368,63 +307,50 @@ }; | ||
} | ||
if (namedParameters) { | ||
return namedParameters; | ||
} | ||
if (opts.with) { | ||
return _extends({}, opts.with); | ||
} | ||
return {}; | ||
}; | ||
var isResolvedWithParams = function isResolvedWithParams(factory, opts) { | ||
var _opts; | ||
if (opts === void 0) { | ||
opts = {}; | ||
} | ||
if (!factory.with && !opts.with) { | ||
return true; | ||
} | ||
var keys = [].concat(new Set([].concat(Object.keys(((_opts = opts) == null ? void 0 : _opts.with) || {}), Object.keys(factory.with || {})))); | ||
return keys.every(function (key) { | ||
var _opts2, _opts2$with; | ||
return ((_opts2 = opts) == null ? void 0 : (_opts2$with = _opts2.with) == null ? void 0 : _opts2$with[key]) === factory.with[key]; | ||
}); | ||
}; | ||
var resolveFactory = function resolveFactory(jpex, name, factory, namedParameters, opts, stack) { | ||
if (factory == null) { | ||
return; | ||
} // Check if it's already been resolved | ||
if (factory.resolved) { | ||
} | ||
if (factory.resolved && isResolvedWithParams(factory, opts)) { | ||
return factory.value; | ||
} // Work out dependencies | ||
} | ||
var args = []; | ||
if (hasLength(factory.dependencies)) { | ||
// eslint-disable-next-line no-use-before-define | ||
args = resolveMany(jpex, factory, namedParameters, opts, [].concat(stack, [name])); | ||
} // Invoke the factory | ||
var value = factory.fn.apply(jpex, args); // Cache the result | ||
cacheResult(jpex, name, factory, value, namedParameters); | ||
} | ||
var value = factory.fn.apply(jpex, args); | ||
cacheResult(jpex, name, factory, value, namedParameters, opts == null ? void 0 : opts.with); | ||
return value; | ||
}; | ||
var resolveOne = function resolveOne(jpex, name, initialParameters, opts, stack) { | ||
var namedParameters = getNamedParameters(initialParameters, opts); // Check named parameters | ||
// if we have a named parameter for this dependency | ||
// we don't need to do any resolution, we can just return the value | ||
var namedParameters = getNamedParameters(initialParameters, opts); | ||
if (Object.hasOwnProperty.call(namedParameters, name)) { | ||
return namedParameters[name]; | ||
} // Special keys | ||
} | ||
if (name === NAMED_PARAMS || name === "type:jpex/NamedParameters") { | ||
return namedParameters; | ||
} | ||
if (checkStack(jpex, name, stack)) { | ||
// Yes we have tried to resolve this one before, but we could | ||
// actually just be resolving an inherited factory | ||
return resolveOne(jpex.$$parent, name, namedParameters, opts, []); | ||
} // Get the factory | ||
// This will either return the factory, | ||
// return null (meaning it's an optional dependency) | ||
// or throw an error | ||
} | ||
var factory = getFactory(jpex, name, opts); | ||
@@ -434,10 +360,8 @@ return resolveFactory(jpex, name, factory, namedParameters, opts, stack); | ||
var resolveMany = function resolveMany(jpex, definition, namedParameters, opts, stack) { | ||
if (stack === void 0) { | ||
stack = []; | ||
} | ||
if (!hasLength(definition.dependencies)) { | ||
return []; | ||
} | ||
if (!stack) { | ||
stack = []; | ||
} | ||
var dependencies = ensureArray(definition.dependencies); | ||
@@ -458,11 +382,8 @@ var values = dependencies.map(function (dependency) { | ||
var _this$$$factories$dep; | ||
if (!isString(dependency)) { | ||
return false; | ||
} | ||
if (this.$$resolved[dependency] != null) { | ||
return true; | ||
} | ||
return ((_this$$$factories$dep = this.$$factories[dependency]) == null ? void 0 : _this$$$factories$dep.resolved) === true; | ||
@@ -477,3 +398,2 @@ } | ||
var result; | ||
var encased = function encased() { | ||
@@ -483,8 +403,5 @@ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
} | ||
/* eslint-disable no-invalid-this */ | ||
if (result && allResolved.call(jpex, dependencies)) { | ||
return result.apply(this, args); | ||
} | ||
var deps = resolveDependencies.call(jpex, { | ||
@@ -495,5 +412,3 @@ dependencies: dependencies | ||
return result.apply(this, args); | ||
/* eslint-enable */ | ||
}; | ||
encased.encased = fn; | ||
@@ -507,5 +422,3 @@ return encased; | ||
} | ||
names = ensureArray(names); | ||
for (var key in this.$$factories) { | ||
@@ -516,3 +429,2 @@ if (!hasLength(names) || names.includes(key)) { | ||
} | ||
for (var _key2 in this.$$resolved) { | ||
@@ -537,3 +449,2 @@ if (!hasLength(names) || names.includes(_key2)) { | ||
config = _objectWithoutPropertiesLoose(_ref, ["inherit"]); | ||
var jpex = { | ||
@@ -540,0 +451,0 @@ $$parent: parent, |
import type { JpexInstance, SetupConfig, NamedParameters, Lifecycle, Precedence, FactoryOpts, ResolveOpts, ServiceOpts, NodeModule, Global } from './types'; | ||
declare const jpex: JpexInstance; | ||
export { jpex, }; | ||
export { jpex }; | ||
export type { Lifecycle, JpexInstance, JpexInstance as Jpex, SetupConfig, NamedParameters, Precedence, FactoryOpts, ServiceOpts, ResolveOpts, NodeModule, Global, }; | ||
export default jpex; |
import { JpexInstance, Dependency, AnyFunction, FactoryOpts } from '../types'; | ||
export declare const validateArgs: (name: string, dependencies: Dependency[], fn: AnyFunction) => void; | ||
export default function factory<T>(this: JpexInstance, name: string, dependencies: Dependency[], fn: AnyFunction<T>, opts?: FactoryOpts): void; |
import { JpexInstance, Dependency, ServiceOpts } from '../types'; | ||
declare function service(this: JpexInstance, name: string, dependencies: Dependency[], fn: any, opts?: ServiceOpts): void; | ||
export default service; | ||
export default function service(this: JpexInstance, name: string, dependencies: Dependency[], fn: any, opts?: ServiceOpts): void; |
import { JpexInstance, Dependency, Definition, NamedParameters, ResolveOpts } from '../types'; | ||
export declare const resolveOne: <R extends unknown>(jpex: JpexInstance, name: Dependency, initialParameters: NamedParameters, opts: ResolveOpts, stack: string[]) => R; | ||
export declare const resolveMany: <R extends any[]>(jpex: JpexInstance, definition: Definition, namedParameters: NamedParameters, opts: ResolveOpts, stack: string[]) => R; | ||
export declare const resolveMany: <R extends any[]>(jpex: JpexInstance, definition: Definition, namedParameters: NamedParameters, opts: ResolveOpts, stack?: string[]) => R; |
import { Factory, JpexInstance, ResolveOpts, NamedParameters, Dependency } from '../types'; | ||
export declare const getFactory: (jpex: JpexInstance, name: string, opts?: ResolveOpts) => Factory; | ||
export declare const cacheResult: (jpex: JpexInstance, name: string, factory: Factory, value: any, namedParameters: NamedParameters) => void; | ||
export declare const getFactory: (jpex: JpexInstance, name: string, opts?: ResolveOpts) => import("../types/base").Factory; | ||
export declare const cacheResult: (jpex: JpexInstance, name: string, factory: Factory, value: any, namedParameters: NamedParameters, withArg: Record<string, any>) => void; | ||
export declare const checkStack: (jpex: JpexInstance, name: Dependency, stack: string[]) => boolean; |
@@ -0,1 +1,2 @@ | ||
export * from './base'; | ||
export * from './JpexInstance'; | ||
@@ -19,2 +20,3 @@ export * from './BuiltIns'; | ||
value?: any; | ||
with?: Record<string, any>; | ||
} |
@@ -1,2 +0,3 @@ | ||
import { Lifecycle, AnyFunction, Dependency, AnyConstructor, Factory, Precedence, NamedParameters } from './'; | ||
import type { Lifecycle, AnyFunction, Dependency, AnyConstructor, Factory, Precedence } from './base'; | ||
import { NamedParameters } from './BuiltIns'; | ||
export interface SetupConfig { | ||
@@ -3,0 +4,0 @@ inherit?: boolean; |
@@ -0,3 +1,9 @@ | ||
import { Dependency, JpexInstance, Precedence } from '../types'; | ||
export declare const isString: (obj: any) => obj is string; | ||
export declare const isFunction: (obj: any) => obj is Function; | ||
export declare const isFunction: (obj: any) => obj is (...args: any[]) => any; | ||
export declare const validateName: (name: string) => void; | ||
export declare const validateDependencies: (dependencies: Dependency[]) => void; | ||
export declare const validateFactory: (name: string, fn: (...args: any[]) => any) => void; | ||
export declare const validateArgs: (name: string, dependencies: Dependency[], fn: (...args: any[]) => any) => void; | ||
export declare const isPassive: (name: string, jpex: JpexInstance, precedence?: Precedence) => boolean; | ||
export declare const instantiate: (context: any, args: any[]) => any; | ||
@@ -4,0 +10,0 @@ export declare const isNode: () => boolean; |
{ | ||
"name": "jpex", | ||
"version": "4.3.0", | ||
"version": "4.3.1", | ||
"description": "Javascript Prototype Extension", | ||
@@ -10,9 +10,8 @@ "main": "dist/cjs/jpex.js", | ||
"clear-cache": "rm -rf node_modules/.cache", | ||
"test": "ava", | ||
"test:debug": "ava debug", | ||
"coverage": "nyc ava", | ||
"test": "jest", | ||
"coverage": "jest --coverage", | ||
"lint": "eslint './src/**/*.ts' --fix && tsc --noEmit", | ||
"build:prepare": "rm -rf dist", | ||
"build:js": "rollup --config ./rollup.config.js", | ||
"build:ts": "tsc -d --outDir dist/ts --emitDeclarationOnly ./src/index.ts", | ||
"build:ts": "tsc -d --outDir dist/ts --emitDeclarationOnly --downlevelIteration ./src/index.ts", | ||
"build:post": "node ./postbuild-checks.js", | ||
@@ -22,17 +21,10 @@ "build": "yarn build:prepare && yarn build:js && yarn build:ts && yarn build:post", | ||
"semantic-release": "semantic-release", | ||
"ci": "yarn lint && yarn test && yarn build" | ||
"ci": "yarn lint && yarn test && yarn build", | ||
"prepare": "husky install" | ||
}, | ||
"husky": { | ||
"hooks": { | ||
"pre-commit": "lint-staged", | ||
"commit-msg": "commitlint --edit" | ||
} | ||
}, | ||
"lint-staged": { | ||
"linters": { | ||
"src/**/*.{js,ts}": [ | ||
"eslint", | ||
"git add" | ||
] | ||
} | ||
"src/**/*.{js,ts}": [ | ||
"eslint", | ||
"prettier --write --ignore-unknown" | ||
] | ||
}, | ||
@@ -50,34 +42,25 @@ "repository": { | ||
"devDependencies": { | ||
"@ava/babel": "^1.0.1", | ||
"@babel/cli": "^7.8.4", | ||
"@babel/core": "^7.7.7", | ||
"@babel/plugin-external-helpers": "^7.8.3", | ||
"@babel/plugin-proposal-class-properties": "^7.8.3", | ||
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.8.3", | ||
"@babel/plugin-proposal-optional-chaining": "^7.8.3", | ||
"@babel/plugin-syntax-class-properties": "^7.8.3", | ||
"@babel/plugin-syntax-typescript": "^7.8.3", | ||
"@babel/preset-env": "^7.7.7", | ||
"@babel/preset-typescript": "^7.8.3", | ||
"@babel/register": "^7.7.7", | ||
"@commitlint/cli": "^8.3.4", | ||
"@commitlint/config-conventional": "^8.3.4", | ||
"@types/babel__core": "^7.1.9", | ||
"@types/mocha": "^8.0.0", | ||
"@types/jest": "^26.0.20", | ||
"@types/node": "^14.0.26", | ||
"@types/sinon": "^9.0.4", | ||
"@typescript-eslint/eslint-plugin": "^4.2.0", | ||
"@typescript-eslint/parser": "^4.2.0", | ||
"ava": "^3.0.0", | ||
"browser-env": "^3.3.0", | ||
"eslint": "^7.5.0", | ||
"eslint-config-airbnb-typescript-prettier": "^4.1.0", | ||
"eslint-plugin-import": "^2.22.1", | ||
"husky": "^4.0.3", | ||
"lint-staged": "^8.1.5", | ||
"nyc": "^15.1.0", | ||
"eslint-plugin-jest": "^24.1.5", | ||
"husky": "^5.1.3", | ||
"jest": "^26.6.3", | ||
"lint-staged": "^10.5.4", | ||
"prettier": "^2.2.1", | ||
"rollup": "^2.23.0", | ||
"rollup-plugin-babel": "^4.3.3", | ||
"rollup-plugin-cleanup": "^3.2.1", | ||
"rollup-plugin-node-resolve": "^5.2.0", | ||
"semantic-release": "^17.1.1", | ||
"sinon": "^9.0.2", | ||
"typescript": "^4.0.3" | ||
@@ -84,0 +67,0 @@ }, |
134
README.md
@@ -0,6 +1,4 @@ | ||
# ![Jpex](https://jpex-js.github.io/dist/jpex.svg) | ||
![Jpex](https://jpex-js.github.io/dist/jpex.svg) | ||
=========== | ||
Easy Dependency Injection | ||
-------------------------- | ||
## Easy Dependency Injection | ||
@@ -15,2 +13,3 @@ [![Build Status](https://travis-ci.org/jpex-js/jpex.svg?branch=master)](https://travis-ci.org/jackmellis/jpex) | ||
## Contents | ||
- [Getting Started](#getting-started) | ||
@@ -20,27 +19,27 @@ - [Registering Dependencies](#registering-dependencies) | ||
- [API](#api) | ||
+ [jpex](#jpex) | ||
- [jpex](#jpex) | ||
- [constant](#jpexconstant) | ||
- [factory](#jpexfactory) | ||
* [lifecycle](#lifecycle) | ||
* [precedence](#precedence) | ||
* [bindToInstance](#bindtoinstance) | ||
* [alias](#alias) | ||
- [lifecycle](#lifecycle) | ||
- [precedence](#precedence) | ||
- [bindToInstance](#bindtoinstance) | ||
- [alias](#alias) | ||
- [service](#jpexservice) | ||
- [alias](#jpexalias) | ||
- [resolve](#jpexresolve) | ||
* [optional](#optional) | ||
* [with](#with) | ||
- [optional](#optional) | ||
- [with](#with) | ||
- [resolveWith](#jpexresolvewith) | ||
- [encase](#jpexencase) | ||
- [extend](#jpexextend) | ||
* [inherit](#inherit) | ||
* [lifecycle](#lifecycle-1) | ||
* [precedence](#precedence-1) | ||
* [optional](#optional-1) | ||
* [nodeModules](#nodemodules) | ||
* [globals](#globals) | ||
- [inherit](#inherit) | ||
- [lifecycle](#lifecycle-1) | ||
- [precedence](#precedence-1) | ||
- [optional](#optional-1) | ||
- [nodeModules](#nodemodules) | ||
- [globals](#globals) | ||
- [raw](#jpexraw) | ||
- [clearCache](#jpexclearcache) | ||
- [infer](#jpexinfer) | ||
+ [Types](#types) | ||
- [Types](#types) | ||
- [Jpex](#jpex) | ||
@@ -56,2 +55,3 @@ - [NodeModule](#nodemodule) | ||
### Install | ||
``` | ||
@@ -62,2 +62,3 @@ npm install jpex | ||
### Plugin | ||
Jpex uses babel to infer type interfaces at build time. You can do this with one of several methods: | ||
@@ -69,2 +70,3 @@ [@jpex-js/babel-plugin](https://github.com/jpex-js/babel-plugin) | ||
Jpex comes bundled with the `@jpex-js/babel-plugin` so you can easily get started with a `.babelrc` like this: | ||
```js | ||
@@ -79,2 +81,3 @@ // .bablerc | ||
### Usage | ||
```ts | ||
@@ -89,8 +92,10 @@ import jpex from 'jpex'; | ||
------ | ||
--- | ||
## Registering Dependencies | ||
Services and factories are small modules or functions that provide a common piece of functionality. | ||
### factories | ||
```ts | ||
@@ -105,2 +110,3 @@ type MyFactory = {}; | ||
### services | ||
```ts | ||
@@ -117,2 +123,3 @@ class MyService = { | ||
### constants | ||
```ts | ||
@@ -123,7 +130,10 @@ type MyConstant = string; | ||
------ | ||
--- | ||
## Consuming Dependencies | ||
### resolve | ||
You can then resolve a dependency anywhere in your app: | ||
```ts | ||
@@ -134,3 +144,5 @@ const value = jpex.resolve<MyFactory>(); | ||
### dependent factories | ||
A factory can request another dependency and jpex will resolve it on the fly: | ||
```ts | ||
@@ -147,3 +159,5 @@ jpex.constant<MyConstant>('foo'); | ||
### encase | ||
Or you can *encase* a regular function so that dependencies are injected into it when called: | ||
Or you can _encase_ a regular function so that dependencies are injected into it when called: | ||
```ts | ||
@@ -157,16 +171,22 @@ const fn = jpex.encase((value: MyFactory) => (arg1, arg2) => { | ||
------- | ||
--- | ||
## API | ||
### jpex | ||
#### jpex.constant | ||
```ts | ||
<T>(obj: T): void | ||
``` | ||
Registers a constant value. | ||
#### jpex.factory | ||
```ts | ||
<T>(fn: (...deps: any[] => T), opts?: object): void | ||
``` | ||
Registers a factory function against the given type. Jpex works out the types of `deps` and injects them at resolution time, then returns the resulting value `T`. | ||
@@ -185,5 +205,7 @@ | ||
##### lifecycle | ||
```ts | ||
'application' | 'class' | 'instance' | 'none' | ||
'application' | 'class' | 'instance' | 'none'; | ||
``` | ||
Determines how long the factory is cached for once resolved. | ||
@@ -199,5 +221,7 @@ | ||
##### precedence | ||
```ts | ||
'active' | 'passive' | ||
'active' | 'passive'; | ||
``` | ||
Determines the behavior when the same factory is registered multiple times. | ||
@@ -211,17 +235,23 @@ | ||
##### bindToInstance | ||
```ts | ||
boolean | ||
boolean; | ||
``` | ||
Specifically for services, automatically binds all of the dependencies to the service instance. | ||
##### alias | ||
```ts | ||
string | string[] | ||
``` | ||
Creates aliases for the factory. This is essentially just shorthand for writing `jpex.factory(...); jpex.alias(...);` | ||
#### jpex.service | ||
```ts | ||
<T>(class: ClassWithConstructor, opts?: object): void | ||
``` | ||
Registers a service. A service is like a factory but instantiates a class instead. | ||
@@ -240,2 +270,3 @@ | ||
If a class `implements` an interface, you can actually use it to resolve the class: | ||
```ts | ||
@@ -252,11 +283,15 @@ interface IFoo {} | ||
#### jpex.alias | ||
```ts | ||
<T>(alias: string): void | ||
``` | ||
Creates an alias to another factory | ||
#### jpex.resolve | ||
```ts | ||
<T>(opts?: object): T | ||
``` | ||
Locates and resolves the desired factory. | ||
@@ -271,21 +306,27 @@ | ||
##### optional | ||
```ts | ||
boolean | ||
boolean; | ||
``` | ||
When `true` if the dependency cannot be found or resolved, it will just return `undefined` rather than throwing an error. | ||
#### jpex.resolveWith | ||
```ts | ||
<T, ...Rest[]>(values: Rest, opts?: object): T | ||
``` | ||
Resolves a factory while substituting dependencies for the given values | ||
```ts | ||
const foo = jpex.resolveWith<Foo, Bah, Baz>([ 'bah', 'baz' ]); | ||
const foo = jpex.resolveWith<Foo, Bah, Baz>(['bah', 'baz']); | ||
``` | ||
#### jpex.encase | ||
```ts | ||
(...deps: any[]): (...args: any[]) => any | ||
``` | ||
Wraps a function and injects values into it, it then returns the inner function for use. | ||
@@ -308,5 +349,7 @@ | ||
#### jpex.extend | ||
```ts | ||
(config?: object): Jpex | ||
``` | ||
creates a new container, using the current one as a base. | ||
@@ -319,2 +362,3 @@ | ||
##### inherit | ||
`boolean` | ||
@@ -325,2 +369,3 @@ | ||
##### lifecycle | ||
`'application' | 'class' | 'instance' | 'none'` | ||
@@ -331,2 +376,3 @@ | ||
##### precedence | ||
`'active' | 'passive'` | ||
@@ -337,2 +383,3 @@ | ||
##### optional | ||
`boolean` | ||
@@ -343,2 +390,3 @@ | ||
##### nodeModules | ||
`boolean` | ||
@@ -349,2 +397,3 @@ | ||
##### globals | ||
`boolean` | ||
@@ -355,4 +404,5 @@ | ||
#### jpex.raw | ||
```ts | ||
<T>() => (...deps: any[]) => T | ||
<T>() => (...deps: any[]) => T; | ||
``` | ||
@@ -363,2 +413,3 @@ | ||
#### jpex.clearCache | ||
```ts | ||
@@ -372,4 +423,5 @@ () => void | ||
#### jpex.infer | ||
```ts | ||
<T>() => string | ||
<T>() => string; | ||
``` | ||
@@ -380,9 +432,13 @@ | ||
### Types | ||
#### Jpex | ||
This is the type definition for the jpex container | ||
#### NodeModule | ||
This is a special type that lets you automatically inject a node module with type inference. | ||
For example: | ||
```ts | ||
@@ -396,2 +452,3 @@ import jpex, { NodeModule } from 'jpex'; | ||
The default return type will be `any` but you can specify one explicitly with the second type parameter: | ||
```ts | ||
@@ -405,5 +462,7 @@ import type fstype from 'fs'; | ||
#### Global | ||
This is another special type that lets you automatically inject a global property with type inference. | ||
For built-in types you can do this without any helpers: | ||
```ts | ||
@@ -416,2 +475,3 @@ import jpex from 'jpex'; | ||
But for custom globals, or properties that don't have built-in types, you can use the `Global` type: | ||
```ts | ||
@@ -424,3 +484,5 @@ import jpex, { Global } from 'jpex'; | ||
## caveats | ||
There are a few caveats to be aware of: | ||
- Only named types/interfaces are supported so you can't do `jpex.factory<{}>()` | ||
@@ -432,2 +494,3 @@ - There is not yet a concept of extending types, so if you do `interface Bah extends Foo {}` you can't then try to resolve `Foo` and expect to be given `Bah`, they are treated as 2 separate things | ||
## react | ||
Jpex is a really good fit with React as it offers a good way to inject impure effects into pure components. There is a `react-jpex` library that exposes a few hooks. | ||
@@ -447,3 +510,3 @@ | ||
<div> | ||
<MyForm/> | ||
<MyForm /> | ||
<button onClick={onSubmit}>Submit</button> | ||
@@ -466,7 +529,7 @@ </div> | ||
// register our stub dependency on an isolated container | ||
onMount={jpex => jpex.constant<SaveData>(saveData)} | ||
onMount={(jpex) => jpex.constant<SaveData>(saveData)} | ||
> | ||
{/* when we render MyComponent, it will be given our stubbed dependency */} | ||
<MyComponent/> | ||
</Provider> | ||
{/* when we render MyComponent, it will be given our stubbed dependency */} | ||
<MyComponent /> | ||
</Provider>, | ||
); | ||
@@ -481,2 +544,3 @@ | ||
## Vanilla JS mode | ||
Perhaps you hate typescript, or babel, or both. Or perhaps you don't have the luxury of a build pipeline in your application. That's fine because jpex supports vanilla js as well, you just have to explicitly state your dependencies up front: | ||
@@ -488,3 +552,3 @@ | ||
jpex.constant('foo', 'foo'); | ||
jpex.factory('bah', [ 'foo' ], (foo) => foo + 'bah'); | ||
jpex.factory('bah', ['foo'], (foo) => foo + 'bah'); | ||
@@ -491,0 +555,0 @@ const value = jpex.resolve('bah'); |
24
26
1358
520
68395