Comparing version 3.5.1 to 4.0.0
@@ -1,3 +0,1 @@ | ||
const plugin = require('./plugin/index'); | ||
module.exports = plugin; | ||
module.exports = require('@jpex-js/babel-plugin'); |
Change Log | ||
========== | ||
### 4.0.0 | ||
- global dependencies such as `Window` and `Document` are now automatically resolved (unless you register your own dependency of the same name) | ||
- you can now control dependency resolution with config flags `nodeModules` and `globals` | ||
- you can also specify whether dependencies should be optional-by-default with an `optional` flag | ||
- dependencies are no longer determined by reading the factory function. Either use `TS` inference, or explicitly pass an array of deps | ||
- changed format of `.factory` `.service` and `.resolve` | ||
- you can now pass an `opts` parameter when registering a factory i.e. `.factory<A>(fn, { lifecycle: 'none' })` | ||
- you can now pass an `opts` parameter when resolving i.e. `.resolve<A>({ optional: true })` | ||
- `resolveWith` now has a nicer syntax for ts inference: `.resolveWith<Foo, Dep1, Dep2>([ 'val1', 'val2' ])`. The original syntax i.e. `.resolveWith({ dep1: 'val1' })` is still valid. | ||
- removed the built-in dependency `$options`. You can no longer do `.resolve({ foo: 'someValue' })` | ||
- removed the built-in dependency `$resolve` | ||
- `precedence` option lets you determine if a factory should overwrite an existing factory or not | ||
- Support for IE11 has been dropped by default. If you want a fully ES5-compatible version, you can import `jpex/dist/es5.js` | ||
- You can now alias 2 types i.e. `jpex.alias<From, To>()` | ||
#### 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 | ||
- You can no longer do `jpex.factory('foo', (depA, depB) => { ... })` as we no longer parse the function and extract the dependencies. | ||
- rather than calling `.factory<A>(fn).lifecycle.application()` you must now do `.factory<A>(fn, { lifecycle: 'application' })` | ||
- clearCache now takes an arity of names, i.e. `clearCache('a', 'b', 'c')` whereas previous it took an array | ||
- you can no longer mix ts and js modes i.e. you cannot do `.factory<A>([ 'b' ], fn)` | ||
- `Lifecycle` is now a type rather than an enum | ||
- wrapping a name in `__` will no longer make it optional, you must explicitly pass the optional flag | ||
- `$options` and `$resolve` functionality have been removed | ||
- If you want to support IE11 you will need to import `jpex/dist/es5.js` or create an alias for it | ||
### 3.5.1 | ||
@@ -4,0 +30,0 @@ - building with webpack was giving warnings about `require` being used which meant it couldn't make optimizations |
@@ -20,203 +20,19 @@ 'use strict'; | ||
function ownKeys(object, enumerableOnly) { | ||
var keys = Object.keys(object); | ||
if (Object.getOwnPropertySymbols) { | ||
var symbols = Object.getOwnPropertySymbols(object); | ||
if (enumerableOnly) symbols = symbols.filter(function (sym) { | ||
return Object.getOwnPropertyDescriptor(object, sym).enumerable; | ||
}); | ||
keys.push.apply(keys, symbols); | ||
} | ||
return keys; | ||
} | ||
function _objectSpread2(target) { | ||
for (var i = 1; i < arguments.length; i++) { | ||
var source = arguments[i] != null ? arguments[i] : {}; | ||
if (i % 2) { | ||
ownKeys(Object(source), true).forEach(function (key) { | ||
_defineProperty(target, key, source[key]); | ||
}); | ||
} else if (Object.getOwnPropertyDescriptors) { | ||
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); | ||
} else { | ||
ownKeys(Object(source)).forEach(function (key) { | ||
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); | ||
}); | ||
} | ||
} | ||
return target; | ||
} | ||
function _inheritsLoose(subClass, superClass) { | ||
subClass.prototype = Object.create(superClass.prototype); | ||
subClass.prototype.constructor = subClass; | ||
subClass.__proto__ = superClass; | ||
} | ||
function _getPrototypeOf(o) { | ||
_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { | ||
return o.__proto__ || Object.getPrototypeOf(o); | ||
}; | ||
return _getPrototypeOf(o); | ||
} | ||
function _setPrototypeOf(o, p) { | ||
_setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { | ||
o.__proto__ = p; | ||
return o; | ||
}; | ||
return _setPrototypeOf(o, p); | ||
} | ||
function _isNativeReflectConstruct() { | ||
if (typeof Reflect === "undefined" || !Reflect.construct) return false; | ||
if (Reflect.construct.sham) return false; | ||
if (typeof Proxy === "function") return true; | ||
try { | ||
Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); | ||
return true; | ||
} catch (e) { | ||
return false; | ||
} | ||
} | ||
function _construct(Parent, args, Class) { | ||
if (_isNativeReflectConstruct()) { | ||
_construct = Reflect.construct; | ||
} else { | ||
_construct = function _construct(Parent, args, Class) { | ||
var a = [null]; | ||
a.push.apply(a, args); | ||
var Constructor = Function.bind.apply(Parent, a); | ||
var instance = new Constructor(); | ||
if (Class) _setPrototypeOf(instance, Class.prototype); | ||
return instance; | ||
}; | ||
} | ||
return _construct.apply(null, arguments); | ||
} | ||
function _isNativeFunction(fn) { | ||
return Function.toString.call(fn).indexOf("[native code]") !== -1; | ||
} | ||
function _wrapNativeSuper(Class) { | ||
var _cache = typeof Map === "function" ? new Map() : undefined; | ||
_wrapNativeSuper = function _wrapNativeSuper(Class) { | ||
if (Class === null || !_isNativeFunction(Class)) return Class; | ||
if (typeof Class !== "function") { | ||
throw new TypeError("Super expression must either be null or a function"); | ||
} | ||
if (typeof _cache !== "undefined") { | ||
if (_cache.has(Class)) return _cache.get(Class); | ||
_cache.set(Class, Wrapper); | ||
} | ||
function Wrapper() { | ||
return _construct(Class, arguments, _getPrototypeOf(this).constructor); | ||
} | ||
Wrapper.prototype = Object.create(Class.prototype, { | ||
constructor: { | ||
value: Wrapper, | ||
enumerable: false, | ||
writable: true, | ||
configurable: true | ||
} | ||
}); | ||
return _setPrototypeOf(Wrapper, Class); | ||
}; | ||
return _wrapNativeSuper(Class); | ||
} | ||
var Lifecycle; | ||
(function (Lifecycle) { | ||
Lifecycle[Lifecycle["APPLICATION"] = 1] = "APPLICATION"; | ||
Lifecycle[Lifecycle["CLASS"] = 2] = "CLASS"; | ||
Lifecycle[Lifecycle["INSTANCE"] = 3] = "INSTANCE"; | ||
Lifecycle[Lifecycle["NONE"] = 4] = "NONE"; | ||
})(Lifecycle || (Lifecycle = {})); | ||
function constant(jpex, name, obj) { | ||
return jpex.factory(name, [], function () { | ||
return obj; | ||
}).lifecycle.application(); | ||
return jpex.factory(name, [], () => obj, { | ||
lifecycle: 'application' | ||
}); | ||
} | ||
var wrapper = function wrapper(factory) { | ||
var wrapper = { | ||
lifecycle: { | ||
application: function application() { | ||
factory.lifecycle = Lifecycle.APPLICATION; | ||
return wrapper; | ||
}, | ||
class: function _class() { | ||
factory.lifecycle = Lifecycle.CLASS; | ||
return wrapper; | ||
}, | ||
instance: function instance() { | ||
factory.lifecycle = Lifecycle.INSTANCE; | ||
return wrapper; | ||
}, | ||
none: function none() { | ||
factory.lifecycle = Lifecycle.NONE; | ||
return wrapper; | ||
} | ||
}, | ||
bindToInstance: function bindToInstance() { | ||
if (factory.fn) { | ||
// @ts-ignore | ||
factory.fn.bindToInstance = true; | ||
} | ||
return wrapper; | ||
}, | ||
dependencies: function dependencies() { | ||
for (var _len = arguments.length, deps = new Array(_len), _key = 0; _key < _len; _key++) { | ||
deps[_key] = arguments[_key]; | ||
} | ||
factory.dependencies = deps; | ||
return wrapper; | ||
} | ||
}; | ||
return wrapper; | ||
}; | ||
var getType = function getType(obj) { | ||
return Object.prototype.toString.call(obj); | ||
}; | ||
var isObject = function isObject(obj) { | ||
return getType(obj) === '[object Object]'; | ||
}; | ||
var isString = function isString(obj) { | ||
return typeof obj === 'string'; | ||
}; | ||
var isFunction = function isFunction(obj) { | ||
return typeof obj === 'function'; | ||
}; | ||
var hasOwn = function hasOwn(obj, name) { | ||
const isString = obj => typeof obj === 'string'; | ||
const isFunction = obj => typeof obj === 'function'; | ||
const hasOwn = (obj, name) => { | ||
return Object.hasOwnProperty.call(obj, name); | ||
}; | ||
var instantiate = function instantiate(context, args) { | ||
const instantiate = (context, args) => { | ||
// eslint-disable-next-line new-parens | ||
return new (Function.prototype.bind.apply(context, args))(); | ||
}; | ||
var isNode = function () { | ||
var _process; // eslint-disable-line no-underscore-dangle | ||
const isNode = (() => { | ||
let _process; // eslint-disable-line no-underscore-dangle | ||
@@ -232,49 +48,14 @@ | ||
return typeof _process === 'object' && _process.toString && _process.toString() === '[object process]'; | ||
}(); // eslint-disable-next-line no-new-func | ||
})(); // eslint-disable-next-line no-new-func | ||
var doUnsafeRequire = new Function('require', 'target', 'return require.main.require(target)'); | ||
var unsafeRequire = function unsafeRequire(target) { | ||
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); | ||
}; | ||
var REG_COMMENTS = /\/\/(.*?)\n|\/\*([\S\s]*?)\*\//g; | ||
var extractParameters = function extractParameters(fn) { | ||
var CHR_OPEN = '('; | ||
var CHR_CLOSE = ')'; | ||
var CHR_ARROW = '=>'; | ||
var CHR_DELIMETER = ','; | ||
var str = fn.toString(); // Remove comments | ||
const getLast = arr => arr[arr.length - 1]; | ||
str = str.replace(REG_COMMENTS, ''); // Find the start and end of the parameters | ||
function factory(jpex, name, dependencies, fn, opts) { | ||
var _opts$precedence, _opts$lifecycle; | ||
var open = str.indexOf(CHR_OPEN); | ||
var close = str.indexOf(CHR_CLOSE); | ||
var arrow = str.indexOf(CHR_ARROW); // Arrow functions may or may not contain brackets | ||
if (arrow > -1 && (arrow < open || open < 0)) { | ||
str = str.substring(0, arrow).trim(); | ||
if (!str) { | ||
return []; | ||
} | ||
return [str]; | ||
} // Pull out the parameters | ||
str = str.substring(open + 1, close); | ||
if (!str) { | ||
return []; | ||
} | ||
return str.split(CHR_DELIMETER).map(function (s) { | ||
return s.trim(); | ||
}); | ||
}; | ||
var getLast = function getLast(arr) { | ||
return arr[arr.length - 1]; | ||
}; | ||
function factory(jpex, name, dependencies, fn) { | ||
if (!isString(name)) { | ||
@@ -284,5 +65,4 @@ throw new Error("Factories must be given a name, but was called with [" + typeof name + "]"); | ||
if (isFunction(dependencies)) { | ||
fn = dependencies; | ||
dependencies = void 0; | ||
if (!Array.isArray(dependencies)) { | ||
throw new Error("Expected an array of dependencies, but was called with [" + typeof dependencies + "]"); | ||
} | ||
@@ -294,8 +74,2 @@ | ||
if (dependencies) { | ||
dependencies = [].concat(dependencies); | ||
} else { | ||
dependencies = extractParameters(fn); | ||
} | ||
if (!dependencies.length) { | ||
@@ -305,17 +79,17 @@ dependencies = null; | ||
var f = { | ||
fn: fn, | ||
dependencies: dependencies, | ||
lifecycle: jpex.$$defaultLifecycle | ||
const precedence = (_opts$precedence = opts == null ? void 0 : opts.precedence) != null ? _opts$precedence : jpex.$$config.precedence; | ||
if (precedence === 'passive' && jpex.$$factories[name] != null) { | ||
return; | ||
} | ||
const f = { | ||
fn, | ||
dependencies, | ||
lifecycle: (_opts$lifecycle = opts == null ? void 0 : opts.lifecycle) != null ? _opts$lifecycle : jpex.$$config.lifecycle | ||
}; | ||
jpex.$$factories[name] = f; | ||
return wrapper(f); | ||
} | ||
function service(jpex, name, dependencies, fn) { | ||
if (isFunction(dependencies)) { | ||
fn = dependencies; | ||
dependencies = void 0; | ||
} | ||
function service(jpex, name, dependencies, fn, opts) { | ||
if (!isFunction(fn)) { | ||
@@ -325,17 +99,7 @@ throw new Error("Service " + name + " must be a [Function]"); | ||
if (dependencies) { | ||
dependencies = [].concat(dependencies); | ||
} else { | ||
dependencies = extractParameters(fn); | ||
} | ||
function factory(...args) { | ||
const context = {}; | ||
function factory() { | ||
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
var context = {}; | ||
if (factory.bindToInstance) { | ||
dependencies.forEach(function (key, i) { | ||
if (opts == null ? void 0 : opts.bindToInstance) { | ||
dependencies.forEach((key, i) => { | ||
context[key] = args[i]; | ||
@@ -349,32 +113,23 @@ }); | ||
factory.bindToInstance = false; | ||
return jpex.factory(name, dependencies, factory); | ||
return jpex.factory(name, dependencies, factory, opts); | ||
} | ||
var JpexError = /*#__PURE__*/function (_Error) { | ||
_inheritsLoose(JpexError, _Error); | ||
function JpexError() { | ||
return _Error.apply(this, arguments) || this; | ||
function alias(jpex, alias, name) { | ||
if (jpex.$$factories[name] != null) { | ||
jpex.$$factories[alias] = jpex.$$factories[name]; | ||
return; | ||
} | ||
return JpexError; | ||
}( /*#__PURE__*/_wrapNativeSuper(Error)); | ||
var isValidFactory = function isValidFactory(factory) { | ||
if (!factory) { | ||
return false; | ||
if (jpex.$$factories[alias] != null) { | ||
jpex.$$factories[name] = jpex.$$factories[alias]; | ||
return; | ||
} | ||
if (factory.resolved) { | ||
return true; | ||
} | ||
throw new Error("Cannot create an alias for [" + name + "|" + alias + "] as it does not exist"); | ||
} | ||
if (factory.fn && typeof factory.fn === 'function') { | ||
return true; | ||
} | ||
const GLOBAL_TYPE_PREFIX = 'type:global:'; | ||
const NAMED_PARAMS = '$namedParameters'; | ||
return false; | ||
}; | ||
var getFromNodeModules = function getFromNodeModules(jpex, target) { | ||
const getFromNodeModules = (jpex, target) => { | ||
// in order to stop webpack environments from including every possible | ||
@@ -387,4 +142,8 @@ // import source in the bundle, we have to stick all node require stuff | ||
if (!jpex.$$config.nodeModules) { | ||
return; | ||
} | ||
try { | ||
var value = unsafeRequire(target); | ||
const value = unsafeRequire(target); | ||
jpex.constant(target, value); | ||
@@ -401,10 +160,61 @@ return jpex.$$factories[target]; | ||
}; | ||
var getFactory = function getFactory(jpex, name, optional) { | ||
const getGlobalObject = () => { | ||
if (typeof global !== 'undefined') { | ||
// eslint-disable-next-line no-undef | ||
return global; | ||
} | ||
if (typeof globalThis !== 'undefined') { | ||
// eslint-disable-next-line no-undef | ||
return globalThis; | ||
} | ||
if (typeof window !== 'undefined') { | ||
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 inferredName = name.charAt(12).toLowerCase() + name.substr(13); | ||
return global[inferredName]; | ||
} | ||
}; | ||
const getFromGlobal = (jpex, name) => { | ||
if (!jpex.$$config.globals) { | ||
return; | ||
} | ||
const value = getGlobalProperty(name); | ||
if (value !== void 0) { | ||
jpex.constant(name, value); | ||
return jpex.$$factories[name]; | ||
} | ||
}; | ||
const getFactory = (jpex, name, opts) => { | ||
var _opts$optional; | ||
if (typeof name !== 'string') { | ||
throw new JpexError("Name must be a string, but recevied " + typeof name); | ||
throw new Error("Name must be a string, but recevied " + typeof name); | ||
} | ||
var factory = jpex.$$resolved[name]; | ||
let factory = jpex.$$resolved[name]; | ||
if (isValidFactory(factory)) { | ||
if (factory != null) { | ||
return factory; | ||
@@ -415,19 +225,27 @@ } | ||
if (isValidFactory(factory)) { | ||
if (factory != null) { | ||
return factory; | ||
} | ||
factory = getFromGlobal(jpex, name); | ||
if (factory != null) { | ||
return factory; | ||
} | ||
factory = getFromNodeModules(jpex, name); | ||
if (isValidFactory(factory)) { | ||
if (factory != null) { | ||
return factory; | ||
} | ||
if (!optional) { | ||
throw new JpexError("Unable to find required dependency [" + name + "]"); | ||
if ((_opts$optional = opts == null ? void 0 : 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) { | ||
const cacheResult = (jpex, name, factory, value, namedParameters) => { | ||
switch (factory.lifecycle) { | ||
case Lifecycle.APPLICATION: | ||
case 'application': | ||
factory.resolved = true; | ||
@@ -437,13 +255,13 @@ factory.value = value; | ||
case Lifecycle.CLASS: | ||
case 'class': | ||
jpex.$$resolved[name] = { | ||
resolved: true, | ||
value: value | ||
value | ||
}; | ||
break; | ||
case Lifecycle.NONE: | ||
case 'none': | ||
break; | ||
case Lifecycle.INSTANCE: | ||
case 'instance': | ||
default: | ||
@@ -453,49 +271,37 @@ namedParameters[name] = value; | ||
} | ||
}; | ||
var checkOptional = function checkOptional(name) { | ||
if (!isString(name)) { | ||
}; // Ensure we're not stuck in a recursive loop | ||
const checkStack = (jpex, name, stack) => { | ||
if (!stack.length) { | ||
// This is the first loop | ||
return false; | ||
} | ||
var first = name[0]; | ||
var last = getLast(name); | ||
if (!stack.includes(name)) { | ||
// We've definitely not tried to resolve this one before | ||
return false; | ||
} | ||
if (first === '_' && last === '_') { | ||
return name.substring(1, name.length - 1); | ||
if (getLast(stack) === 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) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
throw new Error("Recursive loop for dependency " + name + " encountered"); | ||
}; | ||
function alias(jpex, alias, name) { | ||
if (isValidFactory(jpex.$$factories[name])) { | ||
jpex.$$factories[alias] = jpex.$$factories[name]; | ||
} else if (isValidFactory(jpex.$$factories[alias])) { | ||
jpex.$$factories[name] = jpex.$$factories[alias]; | ||
} else { | ||
throw new Error("Cannot create an alias for [" + name + "|" + alias + "] as it does not exist"); | ||
} | ||
} | ||
var resolveOne = function resolveOne(jpex, name, localOptions, namedParameters, stack) { | ||
const resolveOne = (jpex, name, namedParameters, opts, stack) => { | ||
var _factory$dependencies; | ||
if (isObject(name)) { | ||
console.warn('jpex: $options style has been deprecated and will be removed in v4.0.0'); | ||
var _key = Object.keys(name)[0]; | ||
return resolveOne(jpex, _key, name[_key], namedParameters, stack); | ||
} | ||
if (!namedParameters) { | ||
namedParameters = {}; | ||
} // Optional dependencies | ||
var optional = false; | ||
var optionalCheck = checkOptional(name); | ||
if (optionalCheck) { | ||
console.warn('jpex: __ optional syntax has been deprecated and will be removed in v4.0.0'); | ||
name = optionalCheck; | ||
optional = true; | ||
namedParameters = { ...(opts == null ? void 0 : opts.with) | ||
}; | ||
} // Check named parameters | ||
@@ -511,25 +317,10 @@ // if we have a named parameter for this dependency | ||
switch (name) { | ||
case '$options': | ||
case "type:jpex/Options": | ||
console.warn('jpex: $options style has been deprecated and will be removed in v4.0.0'); | ||
return localOptions; | ||
if (name === NAMED_PARAMS || name === "type:jpex/NamedParameters") { | ||
return namedParameters; | ||
} | ||
case '$namedParameters': | ||
case "type:jpex/NamedParameters": | ||
// @ts-ignore | ||
return namedParameters; | ||
} // Ensure we're not stuck in a recursive loop | ||
if (stack.indexOf(name) > -1) { | ||
if (getLast(stack) === name) { | ||
var _jpex$$$parent; | ||
if ((_jpex$$$parent = jpex.$$parent) == null ? void 0 : _jpex$$$parent.$$factories[name]) { | ||
return resolveOne(jpex.$$parent, name, localOptions, namedParameters, []); | ||
} | ||
} | ||
throw new JpexError("Recursive loop for dependency " + name + " encountered"); | ||
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 | ||
@@ -541,5 +332,5 @@ // This will either return the factory, | ||
var factory = getFactory(jpex, name, optional); | ||
const factory = getFactory(jpex, name, opts); | ||
if (!factory) { | ||
if (factory == null) { | ||
return; | ||
@@ -554,19 +345,11 @@ } // Check if it's already been resolved | ||
var args = []; | ||
let args = []; | ||
if (factory == null ? void 0 : (_factory$dependencies = factory.dependencies) == null ? void 0 : _factory$dependencies.length) { | ||
try { | ||
// eslint-disable-next-line no-use-before-define | ||
args = resolveMany(jpex, factory, namedParameters, localOptions, stack.concat(name)); | ||
} catch (e) { | ||
if (!optional) { | ||
throw e; | ||
} | ||
return; | ||
} | ||
if ((_factory$dependencies = factory.dependencies) == null ? void 0 : _factory$dependencies.length) { | ||
// eslint-disable-next-line no-use-before-define | ||
args = resolveMany(jpex, factory, namedParameters, opts, stack.concat(name)); | ||
} // Invoke the factory | ||
var value = factory.fn.apply(jpex, args); // Cache the result | ||
const value = factory.fn.apply(jpex, args); // Cache the result | ||
@@ -576,4 +359,6 @@ cacheResult(jpex, name, factory, value, namedParameters); | ||
}; | ||
var resolveMany = function resolveMany(jpex, definition, namedParameters, globalOptions, stack) { | ||
if (!(definition == null ? void 0 : definition.dependencies)) { | ||
const resolveMany = (jpex, definition, namedParameters, opts, stack) => { | ||
var _definition$dependenc; | ||
if (!(definition == null ? void 0 : (_definition$dependenc = definition.dependencies) == null ? void 0 : _definition$dependenc.length)) { | ||
return []; | ||
@@ -586,22 +371,5 @@ } | ||
if (!namedParameters) { | ||
namedParameters = {}; | ||
} | ||
var dependencies = [].concat(definition.dependencies); | ||
var values = dependencies.reduce(function (value, dependency) { | ||
if (isObject(dependency)) { | ||
console.warn('jpex: $options style has been deprecated and will be removed in v4.0.0'); | ||
var keys = Object.keys(dependency); | ||
var _x = keys.reduce(function (value, key) { | ||
var options = dependency[key]; | ||
var y = resolveOne(jpex, key, options, namedParameters, stack); | ||
return value.concat(y); | ||
}, []); | ||
return value.concat(_x); | ||
} | ||
var x = resolveOne(jpex, dependency, globalOptions, namedParameters, stack); | ||
const dependencies = [].concat(definition.dependencies); | ||
const values = dependencies.reduce((value, dependency) => { | ||
const x = resolveOne(jpex, dependency, namedParameters, opts, stack); | ||
return value.concat([x]); | ||
@@ -612,9 +380,7 @@ }, []); | ||
var resolve = function resolve(jpex, name, namedParameters) { | ||
return resolveOne(jpex, name, null, namedParameters, []); | ||
const resolve = (jpex, name, opts) => resolveOne(jpex, name, void 0, opts, []); | ||
const resolveDependencies = (jpex, definition, opts) => { | ||
return resolveMany(jpex, definition, void 0, opts, []); | ||
}; | ||
var resolveDependencies = function resolveDependencies(jpex, definition, namedParameters) { | ||
return resolveMany(jpex, definition, namedParameters, void 0, []); | ||
}; | ||
var isResolved = function isResolved(jpex, dependency) { | ||
const isResolved = (jpex, dependency) => { | ||
var _jpex$$$factories$dep; | ||
@@ -626,3 +392,3 @@ | ||
if (jpex.$$resolved[dependency]) { | ||
if (jpex.$$resolved[dependency] != null) { | ||
return true; | ||
@@ -637,17 +403,56 @@ } | ||
}; | ||
var allResolved = function allResolved(jpex, dependencies) { | ||
const allResolved = (jpex, dependencies) => { | ||
return dependencies.every(isResolved.bind(null, jpex)); | ||
}; | ||
var Jpex = /*#__PURE__*/function () { | ||
function Jpex(options, parent) { | ||
var _ref; | ||
const encase = (jpex, dependencies, fn) => { | ||
let result; | ||
if (options === void 0) { | ||
options = {}; | ||
const encased = function (...args) { | ||
/* eslint-disable no-invalid-this */ | ||
if (result && allResolved(jpex, dependencies)) { | ||
return result.apply(this, args); | ||
} | ||
const deps = resolveDependencies(jpex, { | ||
dependencies | ||
}); | ||
result = fn.apply(this, deps); | ||
return result.apply(this, args); | ||
/* eslint-enable */ | ||
}; | ||
encased.encased = fn; | ||
return encased; | ||
}; | ||
const clearCache = (jpex, names) => { | ||
names = [].concat(names || []); | ||
for (const key in jpex.$$factories) { | ||
if (!names.length || names.indexOf(key) > -1) { | ||
jpex.$$factories[key].resolved = false; | ||
} | ||
} | ||
for (const key in jpex.$$resolved) { | ||
if (!names.length || names.indexOf(key) > -1) { | ||
delete jpex.$$resolved[key]; | ||
} | ||
} | ||
}; | ||
const defaultConfig = { | ||
lifecycle: 'class', | ||
precedence: 'active', | ||
globals: true, | ||
nodeModules: true, | ||
optional: false | ||
}; | ||
class Jpex { | ||
constructor(options = {}, parent) { | ||
_defineProperty(this, "decorate", void 0); | ||
_defineProperty(this, "$$defaultLifecycle", void 0); | ||
_defineProperty(this, "$$config", void 0); | ||
@@ -660,9 +465,11 @@ _defineProperty(this, "$$parent", void 0); | ||
var _options = options, | ||
_options$inherit = _options.inherit, | ||
inherit = _options$inherit === void 0 ? true : _options$inherit, | ||
_options$lifecycle = _options.lifecycle, | ||
lifecycle = _options$lifecycle === void 0 ? (_ref = inherit ? parent == null ? void 0 : parent.$$defaultLifecycle : void 0) != null ? _ref : Lifecycle.CLASS : _options$lifecycle; | ||
const { | ||
inherit = true, | ||
...config | ||
} = options; | ||
this.$$parent = parent; | ||
this.$$defaultLifecycle = lifecycle; | ||
this.$$config = { ...defaultConfig, | ||
...(inherit ? parent == null ? void 0 : parent.$$config : {}), | ||
...config | ||
}; | ||
@@ -674,120 +481,55 @@ if (parent && inherit) { | ||
var _proto = Jpex.prototype; | ||
_proto.extend = function extend(config) { | ||
extend(config) { | ||
return new Jpex(config, this); | ||
}; | ||
} | ||
_proto.constant = function constant$1(name, obj) { | ||
constant(name, obj) { | ||
return constant(this, name, obj); | ||
}; | ||
} | ||
_proto.factory = function factory$1(name, deps, fn) { | ||
return factory(this, name, deps, fn); | ||
}; | ||
factory(name, deps, fn, opts) { | ||
return factory(this, name, deps, fn, opts); | ||
} | ||
_proto.service = function service$1(name, deps, fn) { | ||
return service(this, name, deps, fn); | ||
}; | ||
service(name, deps, fn, opts) { | ||
return service(this, name, deps, fn, opts); | ||
} | ||
_proto.alias = function alias$1(_alias, name) { | ||
return alias(this, _alias, name); | ||
}; | ||
alias(alias$1, name) { | ||
return alias(this, alias$1, name); | ||
} | ||
_proto.resolve = function resolve$1(name) { | ||
return resolve(this, name); | ||
}; | ||
resolve(name, opts) { | ||
return resolve(this, name, opts); | ||
} | ||
_proto.resolveWith = function resolveWith(name, namedParameters) { | ||
return resolve(this, name, namedParameters); | ||
}; | ||
resolveWith(name, namedParameters, opts) { | ||
return resolve(this, name, { | ||
with: namedParameters, | ||
...opts | ||
}); | ||
} | ||
_proto.raw = function raw(name) { | ||
return getFactory(this, name, false).fn; | ||
}; | ||
raw(name) { | ||
return getFactory(this, name, {}).fn; | ||
} // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
_proto.encase = function encase(_deps, _fn) { | ||
var _ref2 = function () { | ||
if (typeof _deps === 'function') { | ||
return [extractParameters(_deps), _deps]; | ||
} | ||
return [_deps, _fn]; | ||
}(), | ||
dependencies = _ref2[0], | ||
fn = _ref2[1]; | ||
encase(deps, fn) { | ||
return encase(this, deps, fn); | ||
} | ||
var result; | ||
var jpex = this; | ||
clearCache(...names) { | ||
return clearCache(this, names); | ||
} | ||
var encased = function encased() { | ||
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
/* eslint-disable no-invalid-this */ | ||
if (result && allResolved(jpex, dependencies)) { | ||
return result.apply(this, args); | ||
} | ||
var deps = resolveDependencies(jpex, { | ||
dependencies: dependencies | ||
}); | ||
result = fn.apply(this, deps); | ||
return result.apply(this, args); | ||
/* eslint-enable */ | ||
}; | ||
encased.encased = fn; | ||
return encased; | ||
}; | ||
_proto.clearCache = function clearCache(names) { | ||
names = [].concat(names || []); | ||
for (var _key2 in this.$$factories) { | ||
if (!names.length || names.indexOf(_key2) > -1) { | ||
this.$$factories[_key2].resolved = false; | ||
} | ||
} | ||
for (var _key3 in this.$$resolved) { | ||
if (!names.length || names.indexOf(_key3) > -1) { | ||
delete this.$$resolved[_key3]; | ||
} | ||
} | ||
}; | ||
_proto.infer = function infer() { | ||
infer() { | ||
return ''; | ||
}; | ||
} | ||
return Jpex; | ||
}(); | ||
} | ||
var registerResolveFactory = (function (jpex) { | ||
jpex.factory('$resolve', ['$namedParameters'], function ($namedParameters) { | ||
var _this = this; | ||
const jpex = new Jpex(); | ||
return function (name, namedParameters) { | ||
var allParams = _objectSpread2(_objectSpread2({}, $namedParameters), namedParameters); | ||
if (Array.isArray(name)) { | ||
return resolveDependencies(_this, // eslint-disable-line no-invalid-this | ||
{ | ||
dependencies: name | ||
}, allParams); | ||
} | ||
return resolve(_this, // eslint-disable-line no-invalid-this | ||
name, allParams); | ||
}; | ||
}); | ||
jpex.alias("type:jpex/Resolve", '$resolve'); | ||
}); | ||
var jpex = new Jpex(); | ||
registerResolveFactory(jpex); | ||
exports.default = jpex; | ||
exports.jpex = jpex; |
@@ -1,6 +0,2 @@ | ||
export declare enum Lifecycle { | ||
APPLICATION = 1, | ||
CLASS = 2, | ||
INSTANCE = 3, | ||
NONE = 4 | ||
} | ||
export declare const GLOBAL_TYPE_PREFIX = "type:global:"; | ||
export declare const NAMED_PARAMS = "$namedParameters"; |
@@ -1,6 +0,5 @@ | ||
import type { JpexInstance, SetupConfig, Options, NamedParameters, Resolve } from './types'; | ||
import { Lifecycle } from './constants'; | ||
import type { JpexInstance, SetupConfig, NamedParameters, Lifecycle, Precedence, FactoryOpts, ResolveOpts, ServiceOpts } from './types'; | ||
declare const jpex: JpexInstance; | ||
export { jpex, }; | ||
export type { JpexInstance, SetupConfig, Lifecycle, Options, NamedParameters, Resolve, }; | ||
export type { Lifecycle, JpexInstance, SetupConfig, NamedParameters, Precedence, FactoryOpts, ServiceOpts, ResolveOpts, }; | ||
export default jpex; |
import { JpexInstance as IJpex, AnyFunction, Factory, SetupConfig } from './types'; | ||
import { Lifecycle } from './constants'; | ||
declare class Jpex implements IJpex { | ||
decorate: any; | ||
$$defaultLifecycle: Lifecycle; | ||
$$config: IJpex['$$config']; | ||
$$parent: IJpex; | ||
@@ -15,13 +14,13 @@ $$factories: { | ||
extend(config?: SetupConfig): IJpex; | ||
constant(name: any, obj?: any): any; | ||
factory(name: any, deps?: any, fn?: any): any; | ||
service(name: any, deps?: any, fn?: any): any; | ||
constant(name: string, obj?: any): void; | ||
factory(name: any, deps?: any, fn?: any, opts?: any): any; | ||
service(name: any, deps?: any, fn?: any, opts?: any): any; | ||
alias(alias?: any, name?: any): any; | ||
resolve(name?: any): any; | ||
resolveWith(name: any, namedParameters?: any): any; | ||
resolve(name?: any, opts?: any): any; | ||
resolveWith(name: any, namedParameters?: any, opts?: any): any; | ||
raw(name?: any): any; | ||
encase<F extends AnyFunction, G extends AnyFunction<F>>(_deps: any, _fn?: any): any; | ||
clearCache(names?: any): any; | ||
encase<F extends AnyFunction, G extends AnyFunction<F>>(deps: any, fn?: any): any; | ||
clearCache(...names: any[]): any; | ||
infer(): string; | ||
} | ||
export default Jpex; |
@@ -16,203 +16,19 @@ function _defineProperty(obj, key, value) { | ||
function ownKeys(object, enumerableOnly) { | ||
var keys = Object.keys(object); | ||
if (Object.getOwnPropertySymbols) { | ||
var symbols = Object.getOwnPropertySymbols(object); | ||
if (enumerableOnly) symbols = symbols.filter(function (sym) { | ||
return Object.getOwnPropertyDescriptor(object, sym).enumerable; | ||
}); | ||
keys.push.apply(keys, symbols); | ||
} | ||
return keys; | ||
} | ||
function _objectSpread2(target) { | ||
for (var i = 1; i < arguments.length; i++) { | ||
var source = arguments[i] != null ? arguments[i] : {}; | ||
if (i % 2) { | ||
ownKeys(Object(source), true).forEach(function (key) { | ||
_defineProperty(target, key, source[key]); | ||
}); | ||
} else if (Object.getOwnPropertyDescriptors) { | ||
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); | ||
} else { | ||
ownKeys(Object(source)).forEach(function (key) { | ||
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); | ||
}); | ||
} | ||
} | ||
return target; | ||
} | ||
function _inheritsLoose(subClass, superClass) { | ||
subClass.prototype = Object.create(superClass.prototype); | ||
subClass.prototype.constructor = subClass; | ||
subClass.__proto__ = superClass; | ||
} | ||
function _getPrototypeOf(o) { | ||
_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { | ||
return o.__proto__ || Object.getPrototypeOf(o); | ||
}; | ||
return _getPrototypeOf(o); | ||
} | ||
function _setPrototypeOf(o, p) { | ||
_setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { | ||
o.__proto__ = p; | ||
return o; | ||
}; | ||
return _setPrototypeOf(o, p); | ||
} | ||
function _isNativeReflectConstruct() { | ||
if (typeof Reflect === "undefined" || !Reflect.construct) return false; | ||
if (Reflect.construct.sham) return false; | ||
if (typeof Proxy === "function") return true; | ||
try { | ||
Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); | ||
return true; | ||
} catch (e) { | ||
return false; | ||
} | ||
} | ||
function _construct(Parent, args, Class) { | ||
if (_isNativeReflectConstruct()) { | ||
_construct = Reflect.construct; | ||
} else { | ||
_construct = function _construct(Parent, args, Class) { | ||
var a = [null]; | ||
a.push.apply(a, args); | ||
var Constructor = Function.bind.apply(Parent, a); | ||
var instance = new Constructor(); | ||
if (Class) _setPrototypeOf(instance, Class.prototype); | ||
return instance; | ||
}; | ||
} | ||
return _construct.apply(null, arguments); | ||
} | ||
function _isNativeFunction(fn) { | ||
return Function.toString.call(fn).indexOf("[native code]") !== -1; | ||
} | ||
function _wrapNativeSuper(Class) { | ||
var _cache = typeof Map === "function" ? new Map() : undefined; | ||
_wrapNativeSuper = function _wrapNativeSuper(Class) { | ||
if (Class === null || !_isNativeFunction(Class)) return Class; | ||
if (typeof Class !== "function") { | ||
throw new TypeError("Super expression must either be null or a function"); | ||
} | ||
if (typeof _cache !== "undefined") { | ||
if (_cache.has(Class)) return _cache.get(Class); | ||
_cache.set(Class, Wrapper); | ||
} | ||
function Wrapper() { | ||
return _construct(Class, arguments, _getPrototypeOf(this).constructor); | ||
} | ||
Wrapper.prototype = Object.create(Class.prototype, { | ||
constructor: { | ||
value: Wrapper, | ||
enumerable: false, | ||
writable: true, | ||
configurable: true | ||
} | ||
}); | ||
return _setPrototypeOf(Wrapper, Class); | ||
}; | ||
return _wrapNativeSuper(Class); | ||
} | ||
var Lifecycle; | ||
(function (Lifecycle) { | ||
Lifecycle[Lifecycle["APPLICATION"] = 1] = "APPLICATION"; | ||
Lifecycle[Lifecycle["CLASS"] = 2] = "CLASS"; | ||
Lifecycle[Lifecycle["INSTANCE"] = 3] = "INSTANCE"; | ||
Lifecycle[Lifecycle["NONE"] = 4] = "NONE"; | ||
})(Lifecycle || (Lifecycle = {})); | ||
function constant(jpex, name, obj) { | ||
return jpex.factory(name, [], function () { | ||
return obj; | ||
}).lifecycle.application(); | ||
return jpex.factory(name, [], () => obj, { | ||
lifecycle: 'application' | ||
}); | ||
} | ||
var wrapper = function wrapper(factory) { | ||
var wrapper = { | ||
lifecycle: { | ||
application: function application() { | ||
factory.lifecycle = Lifecycle.APPLICATION; | ||
return wrapper; | ||
}, | ||
class: function _class() { | ||
factory.lifecycle = Lifecycle.CLASS; | ||
return wrapper; | ||
}, | ||
instance: function instance() { | ||
factory.lifecycle = Lifecycle.INSTANCE; | ||
return wrapper; | ||
}, | ||
none: function none() { | ||
factory.lifecycle = Lifecycle.NONE; | ||
return wrapper; | ||
} | ||
}, | ||
bindToInstance: function bindToInstance() { | ||
if (factory.fn) { | ||
// @ts-ignore | ||
factory.fn.bindToInstance = true; | ||
} | ||
return wrapper; | ||
}, | ||
dependencies: function dependencies() { | ||
for (var _len = arguments.length, deps = new Array(_len), _key = 0; _key < _len; _key++) { | ||
deps[_key] = arguments[_key]; | ||
} | ||
factory.dependencies = deps; | ||
return wrapper; | ||
} | ||
}; | ||
return wrapper; | ||
}; | ||
var getType = function getType(obj) { | ||
return Object.prototype.toString.call(obj); | ||
}; | ||
var isObject = function isObject(obj) { | ||
return getType(obj) === '[object Object]'; | ||
}; | ||
var isString = function isString(obj) { | ||
return typeof obj === 'string'; | ||
}; | ||
var isFunction = function isFunction(obj) { | ||
return typeof obj === 'function'; | ||
}; | ||
var hasOwn = function hasOwn(obj, name) { | ||
const isString = obj => typeof obj === 'string'; | ||
const isFunction = obj => typeof obj === 'function'; | ||
const hasOwn = (obj, name) => { | ||
return Object.hasOwnProperty.call(obj, name); | ||
}; | ||
var instantiate = function instantiate(context, args) { | ||
const instantiate = (context, args) => { | ||
// eslint-disable-next-line new-parens | ||
return new (Function.prototype.bind.apply(context, args))(); | ||
}; | ||
var isNode = function () { | ||
var _process; // eslint-disable-line no-underscore-dangle | ||
const isNode = (() => { | ||
let _process; // eslint-disable-line no-underscore-dangle | ||
@@ -228,49 +44,14 @@ | ||
return typeof _process === 'object' && _process.toString && _process.toString() === '[object process]'; | ||
}(); // eslint-disable-next-line no-new-func | ||
})(); // eslint-disable-next-line no-new-func | ||
var doUnsafeRequire = new Function('require', 'target', 'return require.main.require(target)'); | ||
var unsafeRequire = function unsafeRequire(target) { | ||
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); | ||
}; | ||
var REG_COMMENTS = /\/\/(.*?)\n|\/\*([\S\s]*?)\*\//g; | ||
var extractParameters = function extractParameters(fn) { | ||
var CHR_OPEN = '('; | ||
var CHR_CLOSE = ')'; | ||
var CHR_ARROW = '=>'; | ||
var CHR_DELIMETER = ','; | ||
var str = fn.toString(); // Remove comments | ||
const getLast = arr => arr[arr.length - 1]; | ||
str = str.replace(REG_COMMENTS, ''); // Find the start and end of the parameters | ||
function factory(jpex, name, dependencies, fn, opts) { | ||
var _opts$precedence, _opts$lifecycle; | ||
var open = str.indexOf(CHR_OPEN); | ||
var close = str.indexOf(CHR_CLOSE); | ||
var arrow = str.indexOf(CHR_ARROW); // Arrow functions may or may not contain brackets | ||
if (arrow > -1 && (arrow < open || open < 0)) { | ||
str = str.substring(0, arrow).trim(); | ||
if (!str) { | ||
return []; | ||
} | ||
return [str]; | ||
} // Pull out the parameters | ||
str = str.substring(open + 1, close); | ||
if (!str) { | ||
return []; | ||
} | ||
return str.split(CHR_DELIMETER).map(function (s) { | ||
return s.trim(); | ||
}); | ||
}; | ||
var getLast = function getLast(arr) { | ||
return arr[arr.length - 1]; | ||
}; | ||
function factory(jpex, name, dependencies, fn) { | ||
if (!isString(name)) { | ||
@@ -280,5 +61,4 @@ throw new Error("Factories must be given a name, but was called with [" + typeof name + "]"); | ||
if (isFunction(dependencies)) { | ||
fn = dependencies; | ||
dependencies = void 0; | ||
if (!Array.isArray(dependencies)) { | ||
throw new Error("Expected an array of dependencies, but was called with [" + typeof dependencies + "]"); | ||
} | ||
@@ -290,8 +70,2 @@ | ||
if (dependencies) { | ||
dependencies = [].concat(dependencies); | ||
} else { | ||
dependencies = extractParameters(fn); | ||
} | ||
if (!dependencies.length) { | ||
@@ -301,17 +75,17 @@ dependencies = null; | ||
var f = { | ||
fn: fn, | ||
dependencies: dependencies, | ||
lifecycle: jpex.$$defaultLifecycle | ||
const precedence = (_opts$precedence = opts == null ? void 0 : opts.precedence) != null ? _opts$precedence : jpex.$$config.precedence; | ||
if (precedence === 'passive' && jpex.$$factories[name] != null) { | ||
return; | ||
} | ||
const f = { | ||
fn, | ||
dependencies, | ||
lifecycle: (_opts$lifecycle = opts == null ? void 0 : opts.lifecycle) != null ? _opts$lifecycle : jpex.$$config.lifecycle | ||
}; | ||
jpex.$$factories[name] = f; | ||
return wrapper(f); | ||
} | ||
function service(jpex, name, dependencies, fn) { | ||
if (isFunction(dependencies)) { | ||
fn = dependencies; | ||
dependencies = void 0; | ||
} | ||
function service(jpex, name, dependencies, fn, opts) { | ||
if (!isFunction(fn)) { | ||
@@ -321,17 +95,7 @@ throw new Error("Service " + name + " must be a [Function]"); | ||
if (dependencies) { | ||
dependencies = [].concat(dependencies); | ||
} else { | ||
dependencies = extractParameters(fn); | ||
} | ||
function factory(...args) { | ||
const context = {}; | ||
function factory() { | ||
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
var context = {}; | ||
if (factory.bindToInstance) { | ||
dependencies.forEach(function (key, i) { | ||
if (opts == null ? void 0 : opts.bindToInstance) { | ||
dependencies.forEach((key, i) => { | ||
context[key] = args[i]; | ||
@@ -345,32 +109,23 @@ }); | ||
factory.bindToInstance = false; | ||
return jpex.factory(name, dependencies, factory); | ||
return jpex.factory(name, dependencies, factory, opts); | ||
} | ||
var JpexError = /*#__PURE__*/function (_Error) { | ||
_inheritsLoose(JpexError, _Error); | ||
function JpexError() { | ||
return _Error.apply(this, arguments) || this; | ||
function alias(jpex, alias, name) { | ||
if (jpex.$$factories[name] != null) { | ||
jpex.$$factories[alias] = jpex.$$factories[name]; | ||
return; | ||
} | ||
return JpexError; | ||
}( /*#__PURE__*/_wrapNativeSuper(Error)); | ||
var isValidFactory = function isValidFactory(factory) { | ||
if (!factory) { | ||
return false; | ||
if (jpex.$$factories[alias] != null) { | ||
jpex.$$factories[name] = jpex.$$factories[alias]; | ||
return; | ||
} | ||
if (factory.resolved) { | ||
return true; | ||
} | ||
throw new Error("Cannot create an alias for [" + name + "|" + alias + "] as it does not exist"); | ||
} | ||
if (factory.fn && typeof factory.fn === 'function') { | ||
return true; | ||
} | ||
const GLOBAL_TYPE_PREFIX = 'type:global:'; | ||
const NAMED_PARAMS = '$namedParameters'; | ||
return false; | ||
}; | ||
var getFromNodeModules = function getFromNodeModules(jpex, target) { | ||
const getFromNodeModules = (jpex, target) => { | ||
// in order to stop webpack environments from including every possible | ||
@@ -383,4 +138,8 @@ // import source in the bundle, we have to stick all node require stuff | ||
if (!jpex.$$config.nodeModules) { | ||
return; | ||
} | ||
try { | ||
var value = unsafeRequire(target); | ||
const value = unsafeRequire(target); | ||
jpex.constant(target, value); | ||
@@ -397,10 +156,61 @@ return jpex.$$factories[target]; | ||
}; | ||
var getFactory = function getFactory(jpex, name, optional) { | ||
const getGlobalObject = () => { | ||
if (typeof global !== 'undefined') { | ||
// eslint-disable-next-line no-undef | ||
return global; | ||
} | ||
if (typeof globalThis !== 'undefined') { | ||
// eslint-disable-next-line no-undef | ||
return globalThis; | ||
} | ||
if (typeof window !== 'undefined') { | ||
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 inferredName = name.charAt(12).toLowerCase() + name.substr(13); | ||
return global[inferredName]; | ||
} | ||
}; | ||
const getFromGlobal = (jpex, name) => { | ||
if (!jpex.$$config.globals) { | ||
return; | ||
} | ||
const value = getGlobalProperty(name); | ||
if (value !== void 0) { | ||
jpex.constant(name, value); | ||
return jpex.$$factories[name]; | ||
} | ||
}; | ||
const getFactory = (jpex, name, opts) => { | ||
var _opts$optional; | ||
if (typeof name !== 'string') { | ||
throw new JpexError("Name must be a string, but recevied " + typeof name); | ||
throw new Error("Name must be a string, but recevied " + typeof name); | ||
} | ||
var factory = jpex.$$resolved[name]; | ||
let factory = jpex.$$resolved[name]; | ||
if (isValidFactory(factory)) { | ||
if (factory != null) { | ||
return factory; | ||
@@ -411,19 +221,27 @@ } | ||
if (isValidFactory(factory)) { | ||
if (factory != null) { | ||
return factory; | ||
} | ||
factory = getFromGlobal(jpex, name); | ||
if (factory != null) { | ||
return factory; | ||
} | ||
factory = getFromNodeModules(jpex, name); | ||
if (isValidFactory(factory)) { | ||
if (factory != null) { | ||
return factory; | ||
} | ||
if (!optional) { | ||
throw new JpexError("Unable to find required dependency [" + name + "]"); | ||
if ((_opts$optional = opts == null ? void 0 : 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) { | ||
const cacheResult = (jpex, name, factory, value, namedParameters) => { | ||
switch (factory.lifecycle) { | ||
case Lifecycle.APPLICATION: | ||
case 'application': | ||
factory.resolved = true; | ||
@@ -433,13 +251,13 @@ factory.value = value; | ||
case Lifecycle.CLASS: | ||
case 'class': | ||
jpex.$$resolved[name] = { | ||
resolved: true, | ||
value: value | ||
value | ||
}; | ||
break; | ||
case Lifecycle.NONE: | ||
case 'none': | ||
break; | ||
case Lifecycle.INSTANCE: | ||
case 'instance': | ||
default: | ||
@@ -449,49 +267,37 @@ namedParameters[name] = value; | ||
} | ||
}; | ||
var checkOptional = function checkOptional(name) { | ||
if (!isString(name)) { | ||
}; // Ensure we're not stuck in a recursive loop | ||
const checkStack = (jpex, name, stack) => { | ||
if (!stack.length) { | ||
// This is the first loop | ||
return false; | ||
} | ||
var first = name[0]; | ||
var last = getLast(name); | ||
if (!stack.includes(name)) { | ||
// We've definitely not tried to resolve this one before | ||
return false; | ||
} | ||
if (first === '_' && last === '_') { | ||
return name.substring(1, name.length - 1); | ||
if (getLast(stack) === 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) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
throw new Error("Recursive loop for dependency " + name + " encountered"); | ||
}; | ||
function alias(jpex, alias, name) { | ||
if (isValidFactory(jpex.$$factories[name])) { | ||
jpex.$$factories[alias] = jpex.$$factories[name]; | ||
} else if (isValidFactory(jpex.$$factories[alias])) { | ||
jpex.$$factories[name] = jpex.$$factories[alias]; | ||
} else { | ||
throw new Error("Cannot create an alias for [" + name + "|" + alias + "] as it does not exist"); | ||
} | ||
} | ||
var resolveOne = function resolveOne(jpex, name, localOptions, namedParameters, stack) { | ||
const resolveOne = (jpex, name, namedParameters, opts, stack) => { | ||
var _factory$dependencies; | ||
if (isObject(name)) { | ||
console.warn('jpex: $options style has been deprecated and will be removed in v4.0.0'); | ||
var _key = Object.keys(name)[0]; | ||
return resolveOne(jpex, _key, name[_key], namedParameters, stack); | ||
} | ||
if (!namedParameters) { | ||
namedParameters = {}; | ||
} // Optional dependencies | ||
var optional = false; | ||
var optionalCheck = checkOptional(name); | ||
if (optionalCheck) { | ||
console.warn('jpex: __ optional syntax has been deprecated and will be removed in v4.0.0'); | ||
name = optionalCheck; | ||
optional = true; | ||
namedParameters = { ...(opts == null ? void 0 : opts.with) | ||
}; | ||
} // Check named parameters | ||
@@ -507,25 +313,10 @@ // if we have a named parameter for this dependency | ||
switch (name) { | ||
case '$options': | ||
case "type:jpex/Options": | ||
console.warn('jpex: $options style has been deprecated and will be removed in v4.0.0'); | ||
return localOptions; | ||
if (name === NAMED_PARAMS || name === "type:jpex/NamedParameters") { | ||
return namedParameters; | ||
} | ||
case '$namedParameters': | ||
case "type:jpex/NamedParameters": | ||
// @ts-ignore | ||
return namedParameters; | ||
} // Ensure we're not stuck in a recursive loop | ||
if (stack.indexOf(name) > -1) { | ||
if (getLast(stack) === name) { | ||
var _jpex$$$parent; | ||
if ((_jpex$$$parent = jpex.$$parent) == null ? void 0 : _jpex$$$parent.$$factories[name]) { | ||
return resolveOne(jpex.$$parent, name, localOptions, namedParameters, []); | ||
} | ||
} | ||
throw new JpexError("Recursive loop for dependency " + name + " encountered"); | ||
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 | ||
@@ -537,5 +328,5 @@ // This will either return the factory, | ||
var factory = getFactory(jpex, name, optional); | ||
const factory = getFactory(jpex, name, opts); | ||
if (!factory) { | ||
if (factory == null) { | ||
return; | ||
@@ -550,19 +341,11 @@ } // Check if it's already been resolved | ||
var args = []; | ||
let args = []; | ||
if (factory == null ? void 0 : (_factory$dependencies = factory.dependencies) == null ? void 0 : _factory$dependencies.length) { | ||
try { | ||
// eslint-disable-next-line no-use-before-define | ||
args = resolveMany(jpex, factory, namedParameters, localOptions, stack.concat(name)); | ||
} catch (e) { | ||
if (!optional) { | ||
throw e; | ||
} | ||
return; | ||
} | ||
if ((_factory$dependencies = factory.dependencies) == null ? void 0 : _factory$dependencies.length) { | ||
// eslint-disable-next-line no-use-before-define | ||
args = resolveMany(jpex, factory, namedParameters, opts, stack.concat(name)); | ||
} // Invoke the factory | ||
var value = factory.fn.apply(jpex, args); // Cache the result | ||
const value = factory.fn.apply(jpex, args); // Cache the result | ||
@@ -572,4 +355,6 @@ cacheResult(jpex, name, factory, value, namedParameters); | ||
}; | ||
var resolveMany = function resolveMany(jpex, definition, namedParameters, globalOptions, stack) { | ||
if (!(definition == null ? void 0 : definition.dependencies)) { | ||
const resolveMany = (jpex, definition, namedParameters, opts, stack) => { | ||
var _definition$dependenc; | ||
if (!(definition == null ? void 0 : (_definition$dependenc = definition.dependencies) == null ? void 0 : _definition$dependenc.length)) { | ||
return []; | ||
@@ -582,22 +367,5 @@ } | ||
if (!namedParameters) { | ||
namedParameters = {}; | ||
} | ||
var dependencies = [].concat(definition.dependencies); | ||
var values = dependencies.reduce(function (value, dependency) { | ||
if (isObject(dependency)) { | ||
console.warn('jpex: $options style has been deprecated and will be removed in v4.0.0'); | ||
var keys = Object.keys(dependency); | ||
var _x = keys.reduce(function (value, key) { | ||
var options = dependency[key]; | ||
var y = resolveOne(jpex, key, options, namedParameters, stack); | ||
return value.concat(y); | ||
}, []); | ||
return value.concat(_x); | ||
} | ||
var x = resolveOne(jpex, dependency, globalOptions, namedParameters, stack); | ||
const dependencies = [].concat(definition.dependencies); | ||
const values = dependencies.reduce((value, dependency) => { | ||
const x = resolveOne(jpex, dependency, namedParameters, opts, stack); | ||
return value.concat([x]); | ||
@@ -608,9 +376,7 @@ }, []); | ||
var resolve = function resolve(jpex, name, namedParameters) { | ||
return resolveOne(jpex, name, null, namedParameters, []); | ||
const resolve = (jpex, name, opts) => resolveOne(jpex, name, void 0, opts, []); | ||
const resolveDependencies = (jpex, definition, opts) => { | ||
return resolveMany(jpex, definition, void 0, opts, []); | ||
}; | ||
var resolveDependencies = function resolveDependencies(jpex, definition, namedParameters) { | ||
return resolveMany(jpex, definition, namedParameters, void 0, []); | ||
}; | ||
var isResolved = function isResolved(jpex, dependency) { | ||
const isResolved = (jpex, dependency) => { | ||
var _jpex$$$factories$dep; | ||
@@ -622,3 +388,3 @@ | ||
if (jpex.$$resolved[dependency]) { | ||
if (jpex.$$resolved[dependency] != null) { | ||
return true; | ||
@@ -633,17 +399,56 @@ } | ||
}; | ||
var allResolved = function allResolved(jpex, dependencies) { | ||
const allResolved = (jpex, dependencies) => { | ||
return dependencies.every(isResolved.bind(null, jpex)); | ||
}; | ||
var Jpex = /*#__PURE__*/function () { | ||
function Jpex(options, parent) { | ||
var _ref; | ||
const encase = (jpex, dependencies, fn) => { | ||
let result; | ||
if (options === void 0) { | ||
options = {}; | ||
const encased = function (...args) { | ||
/* eslint-disable no-invalid-this */ | ||
if (result && allResolved(jpex, dependencies)) { | ||
return result.apply(this, args); | ||
} | ||
const deps = resolveDependencies(jpex, { | ||
dependencies | ||
}); | ||
result = fn.apply(this, deps); | ||
return result.apply(this, args); | ||
/* eslint-enable */ | ||
}; | ||
encased.encased = fn; | ||
return encased; | ||
}; | ||
const clearCache = (jpex, names) => { | ||
names = [].concat(names || []); | ||
for (const key in jpex.$$factories) { | ||
if (!names.length || names.indexOf(key) > -1) { | ||
jpex.$$factories[key].resolved = false; | ||
} | ||
} | ||
for (const key in jpex.$$resolved) { | ||
if (!names.length || names.indexOf(key) > -1) { | ||
delete jpex.$$resolved[key]; | ||
} | ||
} | ||
}; | ||
const defaultConfig = { | ||
lifecycle: 'class', | ||
precedence: 'active', | ||
globals: true, | ||
nodeModules: true, | ||
optional: false | ||
}; | ||
class Jpex { | ||
constructor(options = {}, parent) { | ||
_defineProperty(this, "decorate", void 0); | ||
_defineProperty(this, "$$defaultLifecycle", void 0); | ||
_defineProperty(this, "$$config", void 0); | ||
@@ -656,9 +461,11 @@ _defineProperty(this, "$$parent", void 0); | ||
var _options = options, | ||
_options$inherit = _options.inherit, | ||
inherit = _options$inherit === void 0 ? true : _options$inherit, | ||
_options$lifecycle = _options.lifecycle, | ||
lifecycle = _options$lifecycle === void 0 ? (_ref = inherit ? parent == null ? void 0 : parent.$$defaultLifecycle : void 0) != null ? _ref : Lifecycle.CLASS : _options$lifecycle; | ||
const { | ||
inherit = true, | ||
...config | ||
} = options; | ||
this.$$parent = parent; | ||
this.$$defaultLifecycle = lifecycle; | ||
this.$$config = { ...defaultConfig, | ||
...(inherit ? parent == null ? void 0 : parent.$$config : {}), | ||
...config | ||
}; | ||
@@ -670,120 +477,55 @@ if (parent && inherit) { | ||
var _proto = Jpex.prototype; | ||
_proto.extend = function extend(config) { | ||
extend(config) { | ||
return new Jpex(config, this); | ||
}; | ||
} | ||
_proto.constant = function constant$1(name, obj) { | ||
constant(name, obj) { | ||
return constant(this, name, obj); | ||
}; | ||
} | ||
_proto.factory = function factory$1(name, deps, fn) { | ||
return factory(this, name, deps, fn); | ||
}; | ||
factory(name, deps, fn, opts) { | ||
return factory(this, name, deps, fn, opts); | ||
} | ||
_proto.service = function service$1(name, deps, fn) { | ||
return service(this, name, deps, fn); | ||
}; | ||
service(name, deps, fn, opts) { | ||
return service(this, name, deps, fn, opts); | ||
} | ||
_proto.alias = function alias$1(_alias, name) { | ||
return alias(this, _alias, name); | ||
}; | ||
alias(alias$1, name) { | ||
return alias(this, alias$1, name); | ||
} | ||
_proto.resolve = function resolve$1(name) { | ||
return resolve(this, name); | ||
}; | ||
resolve(name, opts) { | ||
return resolve(this, name, opts); | ||
} | ||
_proto.resolveWith = function resolveWith(name, namedParameters) { | ||
return resolve(this, name, namedParameters); | ||
}; | ||
resolveWith(name, namedParameters, opts) { | ||
return resolve(this, name, { | ||
with: namedParameters, | ||
...opts | ||
}); | ||
} | ||
_proto.raw = function raw(name) { | ||
return getFactory(this, name, false).fn; | ||
}; | ||
raw(name) { | ||
return getFactory(this, name, {}).fn; | ||
} // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
_proto.encase = function encase(_deps, _fn) { | ||
var _ref2 = function () { | ||
if (typeof _deps === 'function') { | ||
return [extractParameters(_deps), _deps]; | ||
} | ||
return [_deps, _fn]; | ||
}(), | ||
dependencies = _ref2[0], | ||
fn = _ref2[1]; | ||
encase(deps, fn) { | ||
return encase(this, deps, fn); | ||
} | ||
var result; | ||
var jpex = this; | ||
clearCache(...names) { | ||
return clearCache(this, names); | ||
} | ||
var encased = function encased() { | ||
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
/* eslint-disable no-invalid-this */ | ||
if (result && allResolved(jpex, dependencies)) { | ||
return result.apply(this, args); | ||
} | ||
var deps = resolveDependencies(jpex, { | ||
dependencies: dependencies | ||
}); | ||
result = fn.apply(this, deps); | ||
return result.apply(this, args); | ||
/* eslint-enable */ | ||
}; | ||
encased.encased = fn; | ||
return encased; | ||
}; | ||
_proto.clearCache = function clearCache(names) { | ||
names = [].concat(names || []); | ||
for (var _key2 in this.$$factories) { | ||
if (!names.length || names.indexOf(_key2) > -1) { | ||
this.$$factories[_key2].resolved = false; | ||
} | ||
} | ||
for (var _key3 in this.$$resolved) { | ||
if (!names.length || names.indexOf(_key3) > -1) { | ||
delete this.$$resolved[_key3]; | ||
} | ||
} | ||
}; | ||
_proto.infer = function infer() { | ||
infer() { | ||
return ''; | ||
}; | ||
} | ||
return Jpex; | ||
}(); | ||
} | ||
var registerResolveFactory = (function (jpex) { | ||
jpex.factory('$resolve', ['$namedParameters'], function ($namedParameters) { | ||
var _this = this; | ||
const jpex = new Jpex(); | ||
return function (name, namedParameters) { | ||
var allParams = _objectSpread2(_objectSpread2({}, $namedParameters), namedParameters); | ||
if (Array.isArray(name)) { | ||
return resolveDependencies(_this, // eslint-disable-line no-invalid-this | ||
{ | ||
dependencies: name | ||
}, allParams); | ||
} | ||
return resolve(_this, // eslint-disable-line no-invalid-this | ||
name, allParams); | ||
}; | ||
}); | ||
jpex.alias("type:jpex/Resolve", '$resolve'); | ||
}); | ||
var jpex = new Jpex(); | ||
registerResolveFactory(jpex); | ||
export default jpex; | ||
export { jpex }; |
@@ -1,10 +0,6 @@ | ||
import { JpexInstance, Definition, Dependency } from '../types'; | ||
import { JpexInstance, Definition, Dependency, ResolveOpts } from '../types'; | ||
export { getFactory } from './utils'; | ||
export declare const resolve: (jpex: JpexInstance, name: Dependency, namedParameters?: { | ||
[key: string]: any; | ||
}) => unknown; | ||
export declare const resolveDependencies: (jpex: JpexInstance, definition: Definition, namedParameters?: { | ||
[key: string]: any; | ||
}) => any[]; | ||
export declare const resolve: (jpex: JpexInstance, name: Dependency, opts?: ResolveOpts) => unknown; | ||
export declare const resolveDependencies: (jpex: JpexInstance, definition: Definition, opts?: ResolveOpts) => any[]; | ||
export declare const isResolved: (jpex: JpexInstance, dependency: Dependency) => boolean; | ||
export declare const allResolved: (jpex: JpexInstance, dependencies: Dependency[]) => boolean; |
@@ -1,7 +0,3 @@ | ||
import { JpexInstance, Dependency, Definition } from '../types'; | ||
export declare const resolveOne: <R extends unknown>(jpex: JpexInstance, name: Dependency, localOptions: any, namedParameters: { | ||
[key: string]: any; | ||
}, stack: string[]) => R; | ||
export declare const resolveMany: <R extends any[]>(jpex: JpexInstance, definition: Definition, namedParameters: { | ||
[key: string]: any; | ||
}, globalOptions: any, stack: string[]) => R; | ||
import { JpexInstance, Dependency, Definition, NamedParameters, ResolveOpts } from '../types'; | ||
export declare const resolveOne: <R extends unknown>(jpex: JpexInstance, name: Dependency, 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; |
@@ -1,8 +0,4 @@ | ||
import { Factory, JpexInstance } from '../types'; | ||
export declare const isValidFactory: (factory: Factory) => boolean; | ||
export declare const getFromNodeModules: (jpex: JpexInstance, target: string) => Factory; | ||
export declare const getFactory: (jpex: JpexInstance, name: string, optional: boolean) => Factory; | ||
export declare const cacheResult: (jpex: JpexInstance, name: string, factory: Factory, value: any, namedParameters: { | ||
[key: string]: any; | ||
}) => void; | ||
export declare const checkOptional: (name: string) => string | false; | ||
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 checkStack: (jpex: JpexInstance, name: Dependency, stack: string[]) => boolean; |
@@ -1,6 +0,3 @@ | ||
import { Dependency } from './'; | ||
export interface NamedParameters { | ||
[key: string]: any; | ||
} | ||
export declare type Resolve = <T = any>(name: Dependency | Dependency[], namedParametres?: NamedParameters) => T; | ||
export declare type Options<T = any> = T; |
@@ -1,4 +0,5 @@ | ||
import { Lifecycle } from '../constants'; | ||
export * from './JpexInstance'; | ||
export * from './BuiltIns'; | ||
export declare type Lifecycle = 'application' | 'class' | 'instance' | 'none'; | ||
export declare type Precedence = 'active' | 'passive'; | ||
export declare type AnyFunction<R = any> = (...args: any[]) => R; | ||
@@ -8,9 +9,3 @@ export interface AnyConstructor<T = any> { | ||
} | ||
export interface SetupConfig { | ||
lifecycle?: Lifecycle; | ||
inherit?: boolean; | ||
} | ||
export declare type Dependency = string | { | ||
[key: string]: any; | ||
}; | ||
export declare type Dependency = string; | ||
export interface Definition { | ||
@@ -20,6 +15,6 @@ dependencies?: Dependency[]; | ||
export interface Factory extends Definition { | ||
fn: <T, R>(...args: T[]) => R; | ||
fn: AnyFunction; | ||
lifecycle: Lifecycle; | ||
resolved?: boolean; | ||
value?: any; | ||
lifecycle?: Lifecycle; | ||
} |
@@ -1,40 +0,68 @@ | ||
import { Lifecycle } from '../constants'; | ||
import { Wrapper } from '../deps/wrapper'; | ||
import { AnyFunction, Dependency, AnyConstructor, SetupConfig, Factory } from './'; | ||
import { Lifecycle, AnyFunction, Dependency, AnyConstructor, Factory, Precedence, NamedParameters } from './'; | ||
export interface SetupConfig { | ||
inherit?: boolean; | ||
lifecycle?: Lifecycle; | ||
precedence?: Precedence; | ||
optional?: boolean; | ||
nodeModules?: boolean; | ||
globals?: boolean; | ||
} | ||
export interface FactoryOpts { | ||
lifecycle?: Lifecycle; | ||
precedence?: Precedence; | ||
} | ||
export interface ServiceOpts extends FactoryOpts { | ||
bindToInstance?: boolean; | ||
} | ||
export interface ResolveOpts { | ||
optional?: boolean; | ||
with?: NamedParameters; | ||
} | ||
export interface JpexInstance { | ||
constant<T = any>(name: string, obj: T): Wrapper; | ||
constant<T>(obj: T): Wrapper; | ||
factory<T = any>(name: string, fn: AnyFunction<T>): Wrapper; | ||
factory<T = any>(name: string, deps: Dependency[], fn: AnyFunction<T>): Wrapper; | ||
factory<T>(fn: AnyFunction<T>): Wrapper; | ||
factory<T>(deps: Dependency[], fn: AnyFunction<T>): Wrapper; | ||
service<T = any>(name: string, fn: AnyConstructor<T> | AnyFunction): Wrapper; | ||
service<T = any>(name: string, deps: Dependency[], fn: AnyConstructor | AnyFunction): Wrapper; | ||
service<T>(fn: AnyConstructor<T> | AnyFunction): Wrapper; | ||
alias<T = any>(alias: string, name: string): void; | ||
constant(name: string, obj: any): void; | ||
constant<T>(obj: T): void; | ||
constant<T>(name: string, obj: T): void; | ||
factory(name: string, deps: Dependency[], fn: AnyFunction, opts?: FactoryOpts): void; | ||
factory<T>(fn: AnyFunction<T>, opts?: FactoryOpts): void; | ||
factory<T>(name: string, deps: Dependency[], fn: AnyFunction<T>, opts?: FactoryOpts): void; | ||
service(name: string, deps: Dependency[], fn: AnyConstructor | AnyFunction, opts?: ServiceOpts): void; | ||
service<T>(fn: AnyConstructor<T> | AnyFunction, opts?: ServiceOpts): void; | ||
service<T>(name: string, deps: Dependency[], fn: AnyConstructor<T> | AnyFunction, opts?: ServiceOpts): void; | ||
alias(alias: string, name: string): void; | ||
alias<T>(alias: string): void; | ||
resolve<T = any>(name: Dependency): T; | ||
resolve<T>(): T; | ||
resolveWith<T = any>(name: Dependency, namedParameters: { | ||
[key: string]: any; | ||
}): T; | ||
resolveWith<T>(namedParameters: { | ||
[key: string]: any; | ||
}): T; | ||
encase<F extends AnyFunction<AnyFunction>>(fn: F): ReturnType<F> & { | ||
alias<T, U>(): void; | ||
alias<T>(alias: string, name: string): void; | ||
alias<T, U>(alias: string, name: string): void; | ||
resolve(name: Dependency, opts?: ResolveOpts): any; | ||
resolve<T>(opts?: ResolveOpts): T; | ||
resolve<T>(name: Dependency, opts?: ResolveOpts): T; | ||
resolveWith(name: Dependency, namedParameters: NamedParameters, opts?: ResolveOpts): any; | ||
resolveWith<T>(namedParameters: NamedParameters, opts?: ResolveOpts): T; | ||
resolveWith<T, A>(namedParameters: NamedParameters, opts?: ResolveOpts): T; | ||
resolveWith<T, A, B>(namedParameters: NamedParameters, opts?: ResolveOpts): T; | ||
resolveWith<T, A, B, C>(namedParameters: NamedParameters, opts?: ResolveOpts): T; | ||
resolveWith<T, A, B, C, D>(namedParameters: NamedParameters, opts?: ResolveOpts): T; | ||
resolveWith<T, A, B, C, D, E>(namedParameters: NamedParameters, opts?: ResolveOpts): T; | ||
resolveWith<T, A, B, C, D, E, F>(namedParameters: NamedParameters, opts?: ResolveOpts): T; | ||
resolveWith<T, A>(namedParameters: NamedParameters, opts?: ResolveOpts): T; | ||
resolveWith<T, A, B>(namedParameters: NamedParameters, opts?: ResolveOpts): T; | ||
resolveWith<T, A, B, C>(namedParameters: NamedParameters, opts?: ResolveOpts): T; | ||
resolveWith<T, A, B, C, D>(namedParameters: NamedParameters, opts?: ResolveOpts): T; | ||
resolveWith<T, A, B, C, D, E>(namedParameters: NamedParameters, opts?: ResolveOpts): T; | ||
resolveWith<T, A, B, C, D, E, F>(namedParameters: NamedParameters, opts?: ResolveOpts): T; | ||
encase<F extends AnyFunction<AnyFunction>>(dependencies: Dependency[], fn: F): ReturnType<F> & { | ||
encased: F; | ||
}; | ||
encase<F extends AnyFunction<AnyFunction>>(dependencies: Dependency[], fn: F): ReturnType<F> & { | ||
encase<F extends AnyFunction<AnyFunction>>(fn: F): ReturnType<F> & { | ||
encased: F; | ||
}; | ||
raw<T = any>(name: Dependency): AnyFunction<T>; | ||
raw(name: Dependency): AnyFunction; | ||
raw<T>(): AnyFunction<T>; | ||
raw<T>(name: Dependency): AnyFunction<T>; | ||
clearCache<T = any>(): void; | ||
clearCache(name: string): void; | ||
clearCache(names: string[]): void; | ||
extend(): JpexInstance; | ||
extend(config: SetupConfig): JpexInstance; | ||
clearCache(...names: string[]): void; | ||
clearCache<T = any>(...names: string[]): void; | ||
extend(config?: SetupConfig): JpexInstance; | ||
infer<T>(): string; | ||
$$parent: JpexInstance; | ||
$$defaultLifecycle: Lifecycle; | ||
$$factories: { | ||
@@ -44,4 +72,11 @@ [key: string]: Factory; | ||
$$resolved: { | ||
[key: string]: any; | ||
[key: string]: Factory; | ||
}; | ||
$$config: { | ||
lifecycle: Lifecycle; | ||
precedence: Precedence; | ||
optional: boolean; | ||
nodeModules: boolean; | ||
globals: boolean; | ||
}; | ||
} |
@@ -1,2 +0,1 @@ | ||
import { AnyFunction } from '../types'; | ||
export declare const isObject: (obj: any) => obj is object; | ||
@@ -10,3 +9,2 @@ export declare const isSymbol: (obj: any) => boolean; | ||
export declare const unsafeRequire: (target: string) => any; | ||
export declare const extractParameters: (fn: AnyFunction) => string[]; | ||
interface GetLast { | ||
@@ -13,0 +11,0 @@ (str: string): string; |
{ | ||
"name": "jpex", | ||
"version": "3.5.1", | ||
"version": "4.0.0", | ||
"description": "Javascript Prototype Extension", | ||
@@ -9,3 +9,5 @@ "main": "dist/cjs/jpex.js", | ||
"scripts": { | ||
"clear-cache": "rm -rf node_modules/.cache", | ||
"test": "ava", | ||
"test:debug": "ava debug", | ||
"coverage": "nyc ava", | ||
@@ -17,4 +19,5 @@ "lint": "eslint './src/**/*.ts' && tsc --noEmit", | ||
"build:post": "node ./postbuild-checks.js", | ||
"build": "yarn build:prepare && yarn build:js && yarn build:ts", | ||
"prepublishOnly": "yarn build" | ||
"build": "yarn build:prepare && yarn build:js && yarn build:ts && yarn build:post", | ||
"prepublishOnly": "yarn build", | ||
"semantic-release": "semantic-release" | ||
}, | ||
@@ -37,3 +40,3 @@ "husky": { | ||
"type": "git", | ||
"url": "git+https://github.com/jackmellis/jpex.git" | ||
"url": "https://github.com/jpex-js/jpex.git" | ||
}, | ||
@@ -43,5 +46,5 @@ "author": "Jack Ellis", | ||
"bugs": { | ||
"url": "https://github.com/jackmellis/jpex/issues" | ||
"url": "https://github.com/jpex-js/jpex/issues" | ||
}, | ||
"homepage": "https://jpex-js.github.io", | ||
"homepage": "https://github.com/jpex-js/jpex", | ||
"devDependencies": { | ||
@@ -54,3 +57,2 @@ "@ava/babel": "^1.0.1", | ||
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.8.3", | ||
"@babel/plugin-proposal-object-rest-spread": "^7.7.7", | ||
"@babel/plugin-proposal-optional-chaining": "^7.8.3", | ||
@@ -65,7 +67,8 @@ "@babel/plugin-syntax-class-properties": "^7.8.3", | ||
"@team-griffin/eslint-config": "^3.2.0", | ||
"@types/babel__core": "^7.1.9", | ||
"@types/mocha": "^8.0.0", | ||
"@types/node": "^14.0.26", | ||
"@types/sinon": "^9.0.4", | ||
"@typescript-eslint/eslint-plugin": "^3.7.1", | ||
"@typescript-eslint/parser": "^3.7.1", | ||
"@typescript-eslint/eslint-plugin": "^4.2.0", | ||
"@typescript-eslint/parser": "^4.2.0", | ||
"ava": "^3.0.0", | ||
@@ -80,5 +83,9 @@ "browser-env": "^3.3.0", | ||
"rollup-plugin-node-resolve": "^5.2.0", | ||
"semantic-release": "^17.1.1", | ||
"sinon": "^9.0.2", | ||
"typescript": "^3.8.2" | ||
"typescript": "^4.0.3" | ||
}, | ||
"dependencies": { | ||
"@jpex-js/babel-plugin": "^1.0.0" | ||
} | ||
} |
387
README.md
@@ -12,4 +12,14 @@ | ||
Jpex is an Inversion of Control framework. | ||
Jpex is an Inversion of Control framework. Register dependencies on a container, then resolve them anywhere in your application. The real magic of jpex is its ability to infer dependencies using the magic of babel and typescript... | ||
## Contents | ||
- [Getting Started](#getting-started) | ||
- [Registering Dependencies](#registering-dependencies) | ||
- [Consuming Dependencies](#consuming-dependencies) | ||
- [API](#api) | ||
- [jpex](#jpex) | ||
- [caveats](#caveats) | ||
- [react](#react) | ||
- [Vanilla JS mode](#vanilla-js-mode) | ||
## Getting Started | ||
@@ -22,2 +32,17 @@ | ||
### Plugin | ||
Jpex uses babel to infer type interfaces at build time. You can do this with one of several methods: | ||
[@jpex-js/babel-plugin](https://github.com/jpex-js/babel-plugin) | ||
[@jpex-js/rollup-plugin](https://github.com/jpex-js/rollup-plugin) | ||
[@jpex-js/webpack-plugin](https://github.com/jpex-js/webpack-loader) | ||
Jpex comes bundled with the `@jpex-js/babel-plugin` so you can easily get started with a `.babelrc` like this: | ||
```js | ||
// .bablerc | ||
{ | ||
presets: [ '@babel/preset-typescript' ], | ||
plugins: [ 'jpex/babel-plugin' ] | ||
} | ||
``` | ||
### Usage | ||
@@ -35,12 +60,19 @@ ```ts | ||
### Registering Dependencies | ||
Services and factories are small modules or functions that provide a reusable or common piece of functionality. In Jpex, you can register **factories**: | ||
## Registering Dependencies | ||
Services and factories are small modules or functions that provide a reusable or common piece of functionality. | ||
### factories | ||
```ts | ||
jpex.factory('myFactory', () => { | ||
type MyFactory = {}; | ||
jpex.factory<MyFactory>(() => { | ||
return {}; | ||
}); | ||
``` | ||
**services**: | ||
### services | ||
```ts | ||
jpex.service('myService', function(){ | ||
type MyService = { method: () => any }; | ||
jpex.service<MyService>(function(){ | ||
this.method = function(){ | ||
@@ -51,21 +83,6 @@ ... | ||
``` | ||
and **constants**: | ||
```ts | ||
jpex.constant('myConstant', 'foo'); | ||
``` | ||
If you're using typescript you can use type inference to automatically register factories: | ||
### constants | ||
```ts | ||
jpex.factory<MyFactory>(() => { | ||
return {}; | ||
}); | ||
``` | ||
```ts | ||
jpex.service<IMyService>(class MyService implements IMyService { | ||
method() {} | ||
}); | ||
``` | ||
```ts | ||
type MyConstant = string; | ||
jpex.constant<MyConstant>('foo'); | ||
@@ -76,41 +93,25 @@ ``` | ||
### Consuming Dependencies | ||
## Consuming Dependencies | ||
### resolve | ||
You can then resolve a dependency anywhere in your app: | ||
```ts | ||
const myFactory = jpex.resolve('myFactory'); | ||
const value = jpex.resolve<MyFactory>(); | ||
``` | ||
### dependent factories | ||
You can also request a dependency from within another factory: | ||
```ts | ||
jpex.constant('myConstant', 'foo'); | ||
jpex.constant<MyConstant>('foo'); | ||
jpex.factory('myFactory', (myConstant) => { | ||
return { | ||
injectedValue : myConstant | ||
}; | ||
jpex.factory<MyFactory>((myConstant: MyConstant) => { | ||
return `my constant is ${myConstant}`; | ||
}); | ||
jpex.service('myService', function(myFactory){ | ||
this.method = function(){ | ||
return myFactory.injectedValue; | ||
}; | ||
}); | ||
jpex.resolve('myService').method(); // returns 'foo'! | ||
``` | ||
Again, with typescript you can use types to automatically pull in your dependencies: | ||
### encase | ||
Or you can *encase* a function so that dependencies are injected into it on-the-fly: | ||
```ts | ||
jpex.factory<MyFactory>((myConstant: MyConstant) => { | ||
return { | ||
injectedValue: myConstant, | ||
}; | ||
const myFn = jpex.encase((value: MyFactory) => (arg1, arg2) => { | ||
return value + arg1 + arg2; | ||
}); | ||
jpex.service<MyService>(function(myFactory: MyFactory) { | ||
this.method = function(){ | ||
return myFactory.injectedValue; | ||
}; | ||
}); | ||
jpex.resolve<MyService>().method(); | ||
``` | ||
@@ -120,110 +121,108 @@ | ||
## Babel | ||
In order to use the inferred typescript functionality, you need to run your code through babel using the plugin in this package. You can import it from `jpex/babel-plugin` | ||
## API | ||
### jpex | ||
#### jpex.constant | ||
```ts | ||
<T>(obj: T): void | ||
``` | ||
Registers a constant value. | ||
```js | ||
plugins: [ 'jpex/babel-plugin' ] | ||
#### jpex.factory | ||
```ts | ||
<T>(fn: (...deps: any[] => T), opts?: object): void | ||
``` | ||
By default it only checks for an object named `jpex`. If you decide to rename it to anything else, or have multiple containers, you can pass an identifier option in. | ||
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`. | ||
By default the types are converted to strings based on the path where they originate from i.e. `type:/src/types/index/MyType`. You can optionally pass in a `publicPath` which will override this behaviour, instead returning `type:myPublicPath/MyType`. This is useful if you want to expose factories via an npm package, for example. | ||
```ts | ||
type GetStuff = () => Promise<string>; | ||
```js | ||
plugins: [ | ||
[ | ||
'jpex/babel-plugin', | ||
{ | ||
identifier: [ 'jpex', 'ioc' ], | ||
publicPath: 'my-library' | ||
} | ||
] | ||
] | ||
jpex.factory<GetStuff>((window: Window) => () => window.fetch('/stuff)); | ||
``` | ||
You can also set this to `true` which will automatically use your library's `name` property from its `package.json` as the public path. | ||
The following options can be provided for both factories and services: | ||
There are a number of caveats to this method, however: | ||
- The plugin only supports named types so you can't do `jpex.factory<{}>()` | ||
- 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 | ||
- Registering a dependency inside a node_module or in an aliased import will likely not work | ||
##### lifecycle | ||
```ts | ||
'application' | 'class' | 'instance' | 'none' | ||
``` | ||
Determines how long the factory is cached for once resolved. | ||
This is still a work in progress so hopefully more in depth type inferrence will be added in the future. | ||
- `application` is resolved forever across all containers | ||
- `class` is resolved for the current jpex container, if you `.extend()` the new container will resolve it again | ||
- `instance` if you request the same dependency multiple times in the same `resolve` call, this will use the same value, but the next time you call `resolve` it will start again | ||
- `none` never caches anything | ||
For more information, see the full documentation at [https://jpex-js.github.io](https://jpex-js.github.io) | ||
The default lifecycle is `class` | ||
## API | ||
### jpex | ||
#### jpex.constant | ||
##### precedence | ||
```ts | ||
jpex.constant(name: string, obj: any) | ||
jpex.constant<T>(obj: T) | ||
'active' | 'passive' | ||
``` | ||
Registers a constant value | ||
Determines the behavior when the same factory is registered multiple times. | ||
#### jpex.factory | ||
- `active` overwrites the existing factory | ||
- `passive` prefers the existing factory | ||
Defaults to `active` | ||
##### bindToInstance | ||
```ts | ||
jpex.factory(name: string, deps?: string[], fn: (...deps: any[]) => any) | ||
jpex.factory<T>(fn(...deps: any[]) => T) | ||
boolean | ||
``` | ||
Registers a factory function. | ||
Specifically for services, automatically binds all of the dependencies to the service instance. | ||
#### jpex.service | ||
```ts | ||
jpex.service(name: string, deps?: string[], c: ClassType) | ||
jpex.service<T>(c: ClassType<T>) | ||
<T>(class: ClassWithConstructor, opts?: object): void | ||
``` | ||
Registers a service, the dependencies will be passed in to the constructor function. It is possible to pass in a regular function instead of an ES6 class. | ||
Registers a service. A service is like a factory but instantiates a class instead. | ||
##### .lifecycle | ||
```ts | ||
jpex.factory(...args).lifecycle.application(); | ||
jpex.factory(...args).lifecycle.class(); | ||
jpex.factory(...args).lifecycle.instance(); | ||
jpex.factory(...args).lifecycle.none(); | ||
class Foo { | ||
constructor(window: Window) { | ||
// ... | ||
} | ||
} | ||
jpex.service<Foo>(Foo); | ||
``` | ||
sets the lifecycle of the factory. This determines how long a resolved factory is cached for. | ||
- Application is forever | ||
- Class is for the entire container (creating a new container via `jpex.extend` will require the factory to be resolved again) | ||
- Instance will cache the dependency through a single "call" (i.e. if multiple nested dependencies rely on the same factory). But each separate call will re-resolve | ||
- None never caches | ||
#### jpex.alias | ||
```ts | ||
<T>(alias: string): void | ||
``` | ||
Creates an alias to another factory | ||
##### .bindToInstance | ||
#### jpex.resolve | ||
```ts | ||
jpex.service(...args).bindToInstance(); | ||
<T>(opts?: object): T | ||
``` | ||
Automatically binds dependencies to a service's instance. | ||
Locates and resolves the desired factory. | ||
##### .dependencies | ||
```ts | ||
jpex.factory(...args).dependencies('foo', 'bah'); | ||
const foo = jpex.resolve<Foo>(); | ||
``` | ||
Allows you to set a factory's dependencies after-the-fact. | ||
#### jpex.alias | ||
The following options can be provided for both `resolve` and `resolveWith`: | ||
##### optional | ||
```ts | ||
jpex.alias(alias: string, factory: string): void | ||
jpex.alias<T>(alias: string): void | ||
boolean | ||
``` | ||
#### jpex.resolve | ||
When `true` if the dependency cannot be found or resolved, it will just return `undefined` rather than throwing an error. | ||
##### with | ||
```ts | ||
jpex.resolve<T>(name: string): T | ||
jpex.resolve<T>(): T | ||
object | ||
``` | ||
Resolves a specified dependency. You can omit the `name` parameter if using the babel plugin | ||
Lets you pass in static values to use when resolving dependencies. This should be used as an escape hatch, as `resolveWith` was created specifically for this purpose. | ||
#### jpex.resolveWith | ||
```ts | ||
jpex.resolveWith<T>(name: string, namedParameters: object): T | ||
jpex.resolveWith<T>(namedParameters: object): T | ||
<T, ...Rest[]>(values: Rest, opts?: object): T | ||
``` | ||
allows you to pass in values for specific dependencies. Rather than attempting to resolve those dependencies, it will use the given value instead. | ||
Resolves a factory while substituting dependencies for the given values | ||
```ts | ||
jpex.constant('myConstant', 'foo'); | ||
jpex.factory('myFactory', [ 'myConstant' ], (c) => c); | ||
const x = jpex.resolveWith('myFactory', { myConstant: 'bah' }); | ||
// x -> bah | ||
const foo = jpex.resolveWith<Foo, Bah, Baz>([ 'bah', 'baz' ]); | ||
``` | ||
@@ -233,14 +232,6 @@ | ||
```ts | ||
jpex.encase( | ||
dependencies: string[], | ||
fn: (...deps: any[]) => Function | ||
): Function | ||
jpex.encase( | ||
fn: (...deps: any[]) => Function | ||
) => Function | ||
(...deps: any[]): (...args: any[]) => any | ||
``` | ||
Wraps a function and injects values into it, it then returns the inner function for use. It supports type inference. | ||
Wraps a function and injects values into it, it then returns the inner function for use. | ||
The easiest way to explain this method is with an example: | ||
```ts | ||
@@ -254,4 +245,4 @@ const getStuff = jpex.encase((http: Http) => (thing: string) => { | ||
##### .encased | ||
For testing purposes, you can access the wrapper function of your encased method using this property. | ||
To help with testing, the returned function also has an `encased` property containng the outer function | ||
```ts | ||
@@ -261,41 +252,131 @@ getStuff.encased(fakeHttp)('my-thing'); | ||
#### jpex.clearCache | ||
#### jpex.extend | ||
```ts | ||
(): void | ||
<T>(): void | ||
(name: string): void | ||
(name: string[]): void | ||
(config?: object): Jpex | ||
``` | ||
Clears the cache. If you provide a name or a type, it will only clear that dependency's cache. If you omit name altogether, it will clear the entire cache. | ||
creates a new container, using the current one as a base. | ||
#### jpex.extend | ||
This is useful for creating isolated contexts or not poluting the global container. | ||
The default behavior is to pass down all config options and factories to the new container. | ||
##### inherit | ||
`boolean` | ||
Whether or not to inherit config and factories from its parent | ||
##### lifecycle | ||
`'application' | 'class' | 'instance' | 'none'` | ||
The default lifecycle for factories. `class` by default | ||
##### precedence | ||
`'active' | 'passive'` | ||
The default precedence for factories. `active` by default | ||
##### optional | ||
`boolean` | ||
Whether factories should be optional by default | ||
##### nodeModules | ||
`boolean` | ||
When trying to resolve a tdependency, should it attempt to import the dependency from node modules? | ||
##### globals | ||
`boolean` | ||
When trying to resolve a dependency, should it check for it on the global object? | ||
#### jpex.raw | ||
```ts | ||
jpex.extend(config?: { | ||
lifecycle?: Lifecycle, | ||
inherit?: boolean, | ||
}): Jpex | ||
<T>() => (...deps: any[]) => T | ||
``` | ||
Creates a new container. You will still have access to all factories registered on the parent container. | ||
If you pass `inherit: false` you will not get any of the parent's factories, you will just get a clearn instance. | ||
Returns the raw factory function, useful for testing. | ||
#### jpex.infer | ||
#### jpex.clearCache | ||
```ts | ||
jpex.infer<T>(): string | ||
() => void | ||
<T>() => void | ||
``` | ||
If you're working with typescript inference, you can use this function to get the inferred name of a type. | ||
Clears the cache of resolved factories. If you provide a type, that specific factory will be cleared, otherwise it will clear all factories. | ||
#### jpex.infer | ||
```ts | ||
const dependencyName = jpex.infer<IFactory>(); // something like src/types/IFactory | ||
<T>() => string | ||
``` | ||
#### jpex.raw | ||
```ts | ||
jpex.raw<T>(): (...args: any[]) => T | ||
Under the hood jpex converts types into strings for runtime resolution. If you want to get that calculated string for whatever reason, you can use `jpex.infer` | ||
## caveats | ||
There are a few caveats to be aware of: | ||
- Only named types/interfaces are supported so you can't do `jpex.factory<{}>()` | ||
- 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 | ||
- The check for a jpex instance is based on the variable name, so you can't do `const jpex2 = jpex; jpex2.constant<Foo>(foo);` without explicitly adding `jpex2` to the plugin config | ||
- Similiarly you can't do `const { factory } = jpex` | ||
## 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. | ||
```tsx | ||
import React from 'react'; | ||
import { useResolve } from 'react-jpex'; | ||
import { SaveData } from '../types'; | ||
const MyComponent = (props) => { | ||
const saveData = useResolve<SaveData>(); | ||
const onSubmit = () => saveData(props.values); | ||
return ( | ||
<div> | ||
<MyForm/> | ||
<button onClick={onSubmit}>Submit</button> | ||
</div> | ||
); | ||
}; | ||
``` | ||
returns the raw factory function | ||
And this pattern also makes it really easy to isolate a component from its side effects when writing tests: | ||
```tsx | ||
import { Provider, useJpex } from 'jpex'; | ||
// create a stub for the SaveData dependency | ||
const saveData = stub(); | ||
render( | ||
// the Provider component will create a new jpex instance | ||
<Provider> | ||
{() => { | ||
// grab jpex - it will be isolated to this context only | ||
const jpex = useJpex(); | ||
// register our stub dependency | ||
jpex.constant<SaveData>(saveData); | ||
// when we render MyComponent, it will be given our stubbed dependency | ||
return (<MyComponent/>); | ||
}} | ||
</Provider> | ||
); | ||
// trigger the compnent's onClick | ||
doOnClick(); | ||
expect(saveData.called).to.be.true; | ||
``` | ||
## 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: | ||
```ts | ||
const factory = jpex.raw<IFactory>; | ||
jpex.constant('foo', 'foo'); | ||
jpex.factory('bah', [ 'foo' ], (foo) => foo + 'bah'); | ||
const result = factory(dep1, dep2)('my-thing'); | ||
const value = jpex.resolve('bah'); | ||
``` | ||
Jpex uses language features supported by the latest browsers, but if you need to support IE11 et al. you can import from 'jpex/dist/es5` (or create an alias in your build process) |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
374
0
71240
1
33
24
1410
1
+ Added@jpex-js/babel-plugin@^1.0.0
+ Added@jpex-js/babel-plugin@1.9.0(transitive)