@danielkalen/simplybind
Version:
Magically simple, framework-less one-way/two-way data binding for frontend/backend in ~5kb.
634 lines (516 loc) • 16.4 kB
JavaScript
var _dec, _class, _dec2, _class3, _dec3, _class5, _dec4, _class7, _dec5, _class9, _dec6, _class11, _dec7, _class13;
import { protocol, metadata } from 'aurelia-metadata';
import { AggregateError } from 'aurelia-pal';
export const resolver = protocol.create('aurelia:resolver', function (target) {
if (!(typeof target.get === 'function')) {
return 'Resolvers must implement: get(container: Container, key: any): any';
}
return true;
});
export let Lazy = (_dec = resolver(), _dec(_class = class Lazy {
constructor(key) {
this._key = key;
}
get(container) {
return () => container.get(this._key);
}
static of(key) {
return new Lazy(key);
}
}) || _class);
export let All = (_dec2 = resolver(), _dec2(_class3 = class All {
constructor(key) {
this._key = key;
}
get(container) {
return container.getAll(this._key);
}
static of(key) {
return new All(key);
}
}) || _class3);
export let Optional = (_dec3 = resolver(), _dec3(_class5 = class Optional {
constructor(key, checkParent = true) {
this._key = key;
this._checkParent = checkParent;
}
get(container) {
if (container.hasResolver(this._key, this._checkParent)) {
return container.get(this._key);
}
return null;
}
static of(key, checkParent = true) {
return new Optional(key, checkParent);
}
}) || _class5);
export let Parent = (_dec4 = resolver(), _dec4(_class7 = class Parent {
constructor(key) {
this._key = key;
}
get(container) {
return container.parent ? container.parent.get(this._key) : null;
}
static of(key) {
return new Parent(key);
}
}) || _class7);
export let StrategyResolver = (_dec5 = resolver(), _dec5(_class9 = class StrategyResolver {
constructor(strategy, state) {
this.strategy = strategy;
this.state = state;
}
get(container, key) {
switch (this.strategy) {
case 0:
return this.state;
case 1:
let singleton = container.invoke(this.state);
this.state = singleton;
this.strategy = 0;
return singleton;
case 2:
return container.invoke(this.state);
case 3:
return this.state(container, key, this);
case 4:
return this.state[0].get(container, key);
case 5:
return container.get(this.state);
default:
throw new Error('Invalid strategy: ' + this.strategy);
}
}
}) || _class9);
export let Factory = (_dec6 = resolver(), _dec6(_class11 = class Factory {
constructor(key) {
this._key = key;
}
get(container) {
return (...rest) => container.invoke(this._key, rest);
}
static of(key) {
return new Factory(key);
}
}) || _class11);
export let NewInstance = (_dec7 = resolver(), _dec7(_class13 = class NewInstance {
constructor(key) {
this.key = key;
this.asKey = key;
}
get(container) {
const instance = container.invoke(this.key);
container.registerInstance(this.asKey, instance);
return instance;
}
as(key) {
this.asKey = key;
return this;
}
static of(key) {
return new NewInstance(key);
}
}) || _class13);
export function getDecoratorDependencies(target, name) {
let dependencies = target.inject;
if (typeof dependencies === 'function') {
throw new Error('Decorator ' + name + ' cannot be used with "inject()". Please use an array instead.');
}
if (!dependencies) {
dependencies = metadata.getOwn(metadata.paramTypes, target).slice();
target.inject = dependencies;
}
return dependencies;
}
export function lazy(keyValue) {
return function (target, key, index) {
let params = getDecoratorDependencies(target, 'lazy');
params[index] = Lazy.of(keyValue);
};
}
export function all(keyValue) {
return function (target, key, index) {
let params = getDecoratorDependencies(target, 'all');
params[index] = All.of(keyValue);
};
}
export function optional(checkParentOrTarget = true) {
let deco = function (checkParent) {
return function (target, key, index) {
let params = getDecoratorDependencies(target, 'optional');
params[index] = Optional.of(params[index], checkParent);
};
};
if (typeof checkParentOrTarget === 'boolean') {
return deco(checkParentOrTarget);
}
return deco(true);
}
export function parent(target, key, index) {
let params = getDecoratorDependencies(target, 'parent');
params[index] = Parent.of(params[index]);
}
export function factory(keyValue, asValue) {
return function (target, key, index) {
let params = getDecoratorDependencies(target, 'factory');
let factory = Factory.of(keyValue);
params[index] = asValue ? factory.as(asValue) : factory;
};
}
export function newInstance(asKeyOrTarget) {
let deco = function (asKey) {
return function (target, key, index) {
let params = getDecoratorDependencies(target, 'newInstance');
params[index] = NewInstance.of(params[index]);
if (!!asKey) {
params[index].as(asKey);
}
};
};
if (arguments.length === 1) {
return deco(asKeyOrTarget);
}
return deco();
}
export function invoker(value) {
return function (target) {
metadata.define(metadata.invoker, value, target);
};
}
export function factory(potentialTarget) {
let deco = function (target) {
metadata.define(metadata.invoker, FactoryInvoker.instance, target);
};
return potentialTarget ? deco(potentialTarget) : deco;
}
export let FactoryInvoker = class FactoryInvoker {
invoke(container, fn, dependencies) {
let i = dependencies.length;
let args = new Array(i);
while (i--) {
args[i] = container.get(dependencies[i]);
}
return fn.apply(undefined, args);
}
invokeWithDynamicDependencies(container, fn, staticDependencies, dynamicDependencies) {
let i = staticDependencies.length;
let args = new Array(i);
while (i--) {
args[i] = container.get(staticDependencies[i]);
}
if (dynamicDependencies !== undefined) {
args = args.concat(dynamicDependencies);
}
return fn.apply(undefined, args);
}
};
FactoryInvoker.instance = new FactoryInvoker();
export function registration(value) {
return function (target) {
metadata.define(metadata.registration, value, target);
};
}
export function transient(key) {
return registration(new TransientRegistration(key));
}
export function singleton(keyOrRegisterInChild, registerInChild = false) {
return registration(new SingletonRegistration(keyOrRegisterInChild, registerInChild));
}
export let TransientRegistration = class TransientRegistration {
constructor(key) {
this._key = key;
}
registerResolver(container, key, fn) {
return container.registerTransient(this._key || key, fn);
}
};
export let SingletonRegistration = class SingletonRegistration {
constructor(keyOrRegisterInChild, registerInChild = false) {
if (typeof keyOrRegisterInChild === 'boolean') {
this._registerInChild = keyOrRegisterInChild;
} else {
this._key = keyOrRegisterInChild;
this._registerInChild = registerInChild;
}
}
registerResolver(container, key, fn) {
return this._registerInChild ? container.registerSingleton(this._key || key, fn) : container.root.registerSingleton(this._key || key, fn);
}
};
const badKeyError = 'key/value cannot be null or undefined. Are you trying to inject/register something that doesn\'t exist with DI?';
export const _emptyParameters = Object.freeze([]);
metadata.registration = 'aurelia:registration';
metadata.invoker = 'aurelia:invoker';
let resolverDecorates = resolver.decorates;
export let InvocationHandler = class InvocationHandler {
constructor(fn, invoker, dependencies) {
this.fn = fn;
this.invoker = invoker;
this.dependencies = dependencies;
}
invoke(container, dynamicDependencies) {
return dynamicDependencies !== undefined ? this.invoker.invokeWithDynamicDependencies(container, this.fn, this.dependencies, dynamicDependencies) : this.invoker.invoke(container, this.fn, this.dependencies);
}
};
function invokeWithDynamicDependencies(container, fn, staticDependencies, dynamicDependencies) {
let i = staticDependencies.length;
let args = new Array(i);
while (i--) {
args[i] = container.get(staticDependencies[i]);
}
if (dynamicDependencies !== undefined) {
args = args.concat(dynamicDependencies);
}
return Reflect.construct(fn, args);
}
let classInvokers = {
[0]: {
invoke(container, Type) {
return new Type();
},
invokeWithDynamicDependencies: invokeWithDynamicDependencies
},
[1]: {
invoke(container, Type, deps) {
return new Type(container.get(deps[0]));
},
invokeWithDynamicDependencies: invokeWithDynamicDependencies
},
[2]: {
invoke(container, Type, deps) {
return new Type(container.get(deps[0]), container.get(deps[1]));
},
invokeWithDynamicDependencies: invokeWithDynamicDependencies
},
[3]: {
invoke(container, Type, deps) {
return new Type(container.get(deps[0]), container.get(deps[1]), container.get(deps[2]));
},
invokeWithDynamicDependencies: invokeWithDynamicDependencies
},
[4]: {
invoke(container, Type, deps) {
return new Type(container.get(deps[0]), container.get(deps[1]), container.get(deps[2]), container.get(deps[3]));
},
invokeWithDynamicDependencies: invokeWithDynamicDependencies
},
[5]: {
invoke(container, Type, deps) {
return new Type(container.get(deps[0]), container.get(deps[1]), container.get(deps[2]), container.get(deps[3]), container.get(deps[4]));
},
invokeWithDynamicDependencies: invokeWithDynamicDependencies
},
fallback: {
invoke: invokeWithDynamicDependencies,
invokeWithDynamicDependencies: invokeWithDynamicDependencies
}
};
function getDependencies(f) {
if (!f.hasOwnProperty('inject')) {
return [];
}
if (typeof f.inject === 'function') {
return f.inject();
}
return f.inject;
}
export let Container = class Container {
constructor(configuration) {
if (configuration === undefined) {
configuration = {};
}
this._configuration = configuration;
this._onHandlerCreated = configuration.onHandlerCreated;
this._handlers = configuration.handlers || (configuration.handlers = new Map());
this._resolvers = new Map();
this.root = this;
this.parent = null;
}
makeGlobal() {
Container.instance = this;
return this;
}
setHandlerCreatedCallback(onHandlerCreated) {
this._onHandlerCreated = onHandlerCreated;
this._configuration.onHandlerCreated = onHandlerCreated;
}
registerInstance(key, instance) {
return this.registerResolver(key, new StrategyResolver(0, instance === undefined ? key : instance));
}
registerSingleton(key, fn) {
return this.registerResolver(key, new StrategyResolver(1, fn === undefined ? key : fn));
}
registerTransient(key, fn) {
return this.registerResolver(key, new StrategyResolver(2, fn === undefined ? key : fn));
}
registerHandler(key, handler) {
return this.registerResolver(key, new StrategyResolver(3, handler));
}
registerAlias(originalKey, aliasKey) {
return this.registerResolver(aliasKey, new StrategyResolver(5, originalKey));
}
registerResolver(key, resolver) {
if (key === null || key === undefined) {
throw new Error(badKeyError);
}
let allResolvers = this._resolvers;
let result = allResolvers.get(key);
if (result === undefined) {
allResolvers.set(key, resolver);
} else if (result.strategy === 4) {
result.state.push(resolver);
} else {
allResolvers.set(key, new StrategyResolver(4, [result, resolver]));
}
return resolver;
}
autoRegister(key, fn) {
fn = fn === undefined ? key : fn;
if (typeof fn === 'function') {
let registration = metadata.get(metadata.registration, fn);
if (registration === undefined) {
return this.registerResolver(key, new StrategyResolver(1, fn));
}
return registration.registerResolver(this, key, fn);
}
return this.registerResolver(key, new StrategyResolver(0, fn));
}
autoRegisterAll(fns) {
let i = fns.length;
while (i--) {
this.autoRegister(fns[i]);
}
}
unregister(key) {
this._resolvers.delete(key);
}
hasResolver(key, checkParent = false) {
if (key === null || key === undefined) {
throw new Error(badKeyError);
}
return this._resolvers.has(key) || checkParent && this.parent !== null && this.parent.hasResolver(key, checkParent);
}
get(key) {
if (key === null || key === undefined) {
throw new Error(badKeyError);
}
if (key === Container) {
return this;
}
if (resolverDecorates(key)) {
return key.get(this, key);
}
let resolver = this._resolvers.get(key);
if (resolver === undefined) {
if (this.parent === null) {
return this.autoRegister(key).get(this, key);
}
return this.parent._get(key);
}
return resolver.get(this, key);
}
_get(key) {
let resolver = this._resolvers.get(key);
if (resolver === undefined) {
if (this.parent === null) {
return this.autoRegister(key).get(this, key);
}
return this.parent._get(key);
}
return resolver.get(this, key);
}
getAll(key) {
if (key === null || key === undefined) {
throw new Error(badKeyError);
}
let resolver = this._resolvers.get(key);
if (resolver === undefined) {
if (this.parent === null) {
return _emptyParameters;
}
return this.parent.getAll(key);
}
if (resolver.strategy === 4) {
let state = resolver.state;
let i = state.length;
let results = new Array(i);
while (i--) {
results[i] = state[i].get(this, key);
}
return results;
}
return [resolver.get(this, key)];
}
createChild() {
let child = new Container(this._configuration);
child.root = this.root;
child.parent = this;
return child;
}
invoke(fn, dynamicDependencies) {
try {
let handler = this._handlers.get(fn);
if (handler === undefined) {
handler = this._createInvocationHandler(fn);
this._handlers.set(fn, handler);
}
return handler.invoke(this, dynamicDependencies);
} catch (e) {
throw new AggregateError(`Error invoking ${ fn.name }. Check the inner error for details.`, e, true);
}
}
_createInvocationHandler(fn) {
let dependencies;
if (fn.inject === undefined) {
dependencies = metadata.getOwn(metadata.paramTypes, fn) || _emptyParameters;
} else {
dependencies = [];
let ctor = fn;
while (typeof ctor === 'function') {
dependencies.push(...getDependencies(ctor));
ctor = Object.getPrototypeOf(ctor);
}
}
let invoker = metadata.getOwn(metadata.invoker, fn) || classInvokers[dependencies.length] || classInvokers.fallback;
let handler = new InvocationHandler(fn, invoker, dependencies);
return this._onHandlerCreated !== undefined ? this._onHandlerCreated(handler) : handler;
}
};
export function autoinject(potentialTarget) {
let deco = function (target) {
let previousInject = target.inject;
let autoInject = metadata.getOwn(metadata.paramTypes, target) || _emptyParameters;
if (!previousInject) {
target.inject = autoInject;
} else {
for (let i = 0; i++; i < autoInject.length) {
if (!previousInject[i]) {
previousInject[i] = autoInject[i];
}
}
}
};
return potentialTarget ? deco(potentialTarget) : deco;
}
export function inject(...rest) {
return function (target, key, descriptor) {
if (typeof descriptor === 'number' && rest.length === 1) {
let params = target.inject;
if (typeof params === 'function') {
throw new Error('Decorator inject cannot be used with "inject()". Please use an array instead.');
}
if (!params) {
params = metadata.getOwn(metadata.paramTypes, target).slice();
target.inject = params;
}
params[descriptor] = rest[0];
return;
}
if (descriptor) {
const fn = descriptor.value;
fn.inject = rest;
} else {
target.inject = rest;
}
};
}