New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

jpex

Package Overview
Dependencies
Maintainers
1
Versions
42
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

jpex - npm Package Compare versions

Comparing version 3.5.1 to 4.0.0

dist/es/clearCache.d.ts

4

babel-plugin.js

@@ -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"
}
}

@@ -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)
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc