reactive-di
Version:
Reactive dependency injection
805 lines (616 loc) • 19.7 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var urc = require('urc');
function _inheritsLoose(subClass, superClass) {
subClass.prototype = Object.create(superClass.prototype);
subClass.prototype.constructor = subClass;
subClass.__proto__ = superClass;
}
var rdiInst = Symbol('rdi_inst');
var rdiProp = Symbol('rdi_prop');
var depId = 0;
var rdiId = Symbol('rdi_id');
var Alias = function Alias(dest) {
dest[rdiId] = '' + ++depId;
this.dest = dest;
};
var Injector =
/*#__PURE__*/
function () {
function Injector(contextAliases, sheetManager, state, displayName, instance, cache, flags) {
this.id = '';
this.props = undefined;
this._sheet = undefined;
this._resolved = false;
this._listeners = undefined;
this._state = state;
this.instance = instance || 0;
this.displayName = displayName || '';
if (Injector.parentContext === undefined) Injector.parentContext = this;
if (sheetManager) {
Injector.sheetManager = sheetManager;
}
this._flags = flags;
var map = this._cache = cache || Object.create(null);
if (contextAliases !== undefined) {
for (var i = 0; i < contextAliases.length; i++) {
var item = contextAliases[i];
if (item instanceof Array) {
var src = item[0];
if (typeof src === 'string') {
map[src] = item[1];
} else {
if (src[rdiId] === undefined) {
src[rdiId] = '' + ++depId;
}
var dest = item[1];
map[src[rdiId]] = typeof dest === 'function' && !(dest instanceof Alias) ? new Alias(dest) : dest;
}
} else {
var _src = item.constructor;
if (_src[rdiId] === undefined) {
_src[rdiId] = '' + ++depId;
}
map[_src[rdiId]] = item;
}
}
}
}
var _proto = Injector.prototype;
_proto.getClassName = function getClassName(data, debugName) {
var sheet = this._sheet;
var flags = this._flags;
if (sheet === undefined) {
sheet = this._sheet = Injector.sheetManager.createSheet(this.displayName + (flags && flags.isDynamic ? '_' + this.instance : ''));
}
if (data._dynamic !== undefined && flags) {
flags.isDynamic = true;
}
return sheet.addRule(data, debugName);
};
_proto.toString = function toString() {
return this.displayName + (this.instance ? '[' + this.instance + ']' : '');
};
_proto.toJSON = function toJSON() {
return this._cache;
};
_proto.value = function value(key) {
var id = key[rdiId];
if (key[rdiId] === undefined) {
id = key[rdiId] = '' + ++depId;
}
var value = this._cache[id];
if (value === undefined) {
value = this._cache[id] = this.invoke(key);
var depName = (key.displayName || key.name) + (this.instance > 0 ? '[' + this.instance + ']' : '');
value.displayName = this.displayName + "." + depName;
value[rdiInst] = this;
var state = this._state === undefined ? undefined : this._state[depName];
if (state && typeof state === 'object') {
for (var prop in state) {
value[prop] = state[prop];
}
}
} else if (value instanceof Alias) {
value = this._cache[id] = this.value(value.dest);
}
return value;
};
_proto.destructor = function destructor() {
if (this._sheet) this._sheet.destructor();
this._sheet = undefined;
this._cache = undefined;
this._listeners = undefined;
};
_proto.invoke = function invoke(key) {
var isFn = false;
var deps = key.deps;
if (key._r !== undefined) {
isFn = key._r[0] === 2;
deps = deps || key._r[1];
}
var a = this.resolve(deps);
if (isFn) {
switch (a.length) {
case 0:
return key();
case 1:
return key(a[0]);
case 2:
return key(a[0], a[1]);
case 3:
return key(a[0], a[1], a[2]);
case 4:
return key(a[0], a[1], a[2], a[3]);
case 5:
return key(a[0], a[1], a[2], a[3], a[4]);
case 6:
return key(a[0], a[1], a[2], a[3], a[4], a[5]);
default:
return key.apply(void 0, a);
}
}
switch (a.length) {
case 0:
return new key();
case 1:
return new key(a[0]);
case 2:
return new key(a[0], a[1]);
case 3:
return new key(a[0], a[1], a[2]);
case 4:
return new key(a[0], a[1], a[2], a[3]);
case 5:
return new key(a[0], a[1], a[2], a[3], a[4]);
case 6:
return new key(a[0], a[1], a[2], a[3], a[4], a[5]);
default:
return new (Function.prototype.bind.apply(key, [null].concat(a)))();
}
};
_proto.alias = function alias(key, rawId) {
var id = rawId;
if (id === undefined) {
id = key[rdiId];
if (id === undefined) {
id = key[rdiId] = '' + ++depId;
}
}
var newKey = this._cache[id];
if (newKey instanceof Alias) return newKey.dest;
if (newKey === undefined) return key;
return newKey;
};
_proto.getContext = function getContext(key, props) {
var deps = key.deps || (key._r === undefined ? undefined : key._r[1]);
if (deps === undefined) return undefined;
var a = this.resolve(deps);
var listeners = this._listeners;
if (props !== undefined && listeners !== undefined) {
for (var i = 0; i < listeners.length; i++) {
var listener = listeners[i];
listener[listener.constructor[rdiProp]] = props;
}
}
this._resolved = true;
return a[0];
};
_proto.copy = function copy(flags) {
return new Injector(flags.contextAliases, null, this._state, flags.displayName, flags.instance, Object.create(this._cache), flags);
};
_proto.resolve = function resolve(argDeps) {
var result = [];
if (argDeps === undefined) return result;
var listeners = this._listeners;
var resolved = this._resolved;
for (var i = 0, l = argDeps.length; i < l; i++) {
var argDep = argDeps[i];
if (typeof argDep === 'object') {
var obj = {};
for (var prop in argDep) {
// eslint-disable-line
var key = argDep[prop];
var dep = this.value(key);
if (resolved === false && key[rdiProp] !== undefined) {
if (listeners === undefined) {
this._listeners = listeners = [];
}
listeners.push(dep);
}
obj[prop] = dep;
}
result.push(obj);
} else {
var _dep = this.value(argDep);
if (resolved === false && argDep[rdiProp] !== undefined) {
if (listeners === undefined) {
this._listeners = listeners = [];
}
listeners.push(_dep);
}
result.push(_dep);
}
}
return result;
};
return Injector;
}();
function createReactWrapper(BaseComponent, renderError, ReactAtom, rootInjector) {
if (rootInjector === void 0) {
rootInjector = new Injector();
}
var names = new Map();
function normalizeClass(cls) {
var prefix = names.get(cls.displayName);
if (prefix !== undefined) {
prefix++;
names.set(cls.displayName, prefix);
cls.displayName = cls.displayName + prefix;
} else {
names.set(cls.displayName, 0);
}
return cls;
}
var MixinComponent =
/*#__PURE__*/
function (_CatchableComponent) {
_inheritsLoose(MixinComponent, _CatchableComponent);
function MixinComponent() {
return _CatchableComponent.apply(this, arguments) || this;
}
var _proto = MixinComponent.prototype;
_proto.componentWillMount = function componentWillMount() {
_CatchableComponent.prototype.componentWillMount.call(this);
var cns = this.constructor;
if (cns.instance === undefined) {
cns.instance = 0;
cns.isDynamic = false;
}
cns.instance++;
var injector = rootInjector;
var props = this.props;
if (props && props.__lom_ctx !== undefined) injector = props.__lom_ctx;
this._injector = injector.copy(cns);
this._injector.id = cns.displayName;
this._injector.props = props;
};
_proto.componentWillUnmount = function componentWillUnmount() {
this.constructor.instance--;
this._injector.destructor();
_CatchableComponent.prototype.componentWillUnmount.call(this);
};
_proto.__value = function __value(isPropsChanged) {
var oldInjector = Injector.parentContext;
Injector.parentContext = this._injector;
var value = _CatchableComponent.prototype.__value.call(this, isPropsChanged);
Injector.parentContext = oldInjector;
return value;
};
_proto._getContext = function _getContext(key, propsChanged) {
return this._injector.getContext(key, propsChanged ? this.props : undefined);
};
return MixinComponent;
}(urc.CatchableComponent);
return urc.createConnect({
ReactAtom: ReactAtom,
renderError: renderError,
BaseComponent: BaseComponent,
MixinComponent: MixinComponent,
normalizeClass: normalizeClass
});
}
function createCreateElement(atomize, createElement, modifyId) {
function lomCreateElement() {
var args = arguments;
var attrs = args[1];
var el = args[0];
var newEl;
var isAtomic = typeof el === 'function' && el.constructor.render === undefined;
var parentContext = Injector.parentContext;
var props = parentContext.props;
var id = undefined;
if (attrs) {
var pid = parentContext.id;
id = attrs.rdi_id || attrs.id;
var aClass = attrs.class;
if (typeof aClass === 'object') {
attrs.class = aClass = parentContext.getClassName(aClass, id);
}
if (attrs.rdi_theme === true) {
attrs.rdi_theme = undefined;
if (props) {
var pClass = props.class;
if (pClass !== undefined) {
attrs.class = aClass === undefined ? pClass : aClass + " " + pClass;
}
var pStyle = props.style;
if (pStyle !== undefined) {
var aStyle = attrs.style;
if (aStyle === undefined) {
attrs.style = pStyle;
} else {
for (var _key in pStyle) {
aStyle[_key] = pStyle[_key];
}
}
}
}
if (modifyId) attrs.id = pid;
} else if (modifyId && pid !== '' && attrs.id !== undefined) {
attrs.id = pid + '.' + attrs.id;
}
}
if (isAtomic) {
newEl = parentContext.alias(el, id);
if (newEl === null) return null;
if (newEl !== undefined) el = newEl;
if (!attrs) {
attrs = {
__lom_ctx: parentContext
};
} else {
attrs.__lom_ctx = parentContext;
}
if (el.__lom === undefined) {
el.__lom = atomize(el);
}
newEl = el.__lom;
} else {
if (id) {
newEl = parentContext.alias(el, id);
if (newEl === null) return null;
if (newEl !== undefined) el = newEl;
}
newEl = el;
}
switch (args.length) {
case 2:
return createElement(newEl, attrs);
case 3:
return createElement(newEl, attrs, args[2]);
case 4:
return createElement(newEl, attrs, args[2], args[3]);
case 5:
return createElement(newEl, attrs, args[2], args[3], args[4]);
case 6:
return createElement(newEl, attrs, args[2], args[3], args[4], args[5]);
case 7:
return createElement(newEl, attrs, args[2], args[3], args[4], args[5], args[6]);
case 8:
return createElement(newEl, attrs, args[2], args[3], args[4], args[5], args[6], args[7]);
case 9:
return createElement(newEl, attrs, args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
default:
if (isAtomic === false) {
return createElement.apply(null, args);
} else {
var newArgs = [newEl, attrs];
for (var i = 2, l = args.length; i < l; i++) {
newArgs.push(args[i]);
}
return createElement.apply(null, newArgs);
}
}
}
return lomCreateElement;
}
function dn(fn) {
if (!fn) return 'null';
if (typeof fn === 'object') {
var cons = fn.constructor;
return cons.displayName || cons.name;
}
if (typeof fn === 'function') {
return fn.displayName || fn.name;
}
return String(fn);
}
function provideMap(item) {
return item instanceof Array ? "[" + dn(item[0]) + ", " + dn(item[1]) + "]" : dn(item);
}
function cloneComponent(fn, contextAliases, name) {
var cloned = function cloned() {
var a = arguments;
switch (a.length) {
case 1:
return fn(a[0]);
case 2:
return fn(a[0], a[1]);
case 3:
return fn(a[0], a[1], a[2]);
case 4:
return fn(a[0], a[1], a[2], a[3]);
case 5:
return fn(a[0], a[1], a[2], a[3], a[4]);
default:
return fn.apply(null, a);
}
};
cloned.deps = fn.deps;
cloned._r = fn._r;
cloned.contextAliases = fn.contextAliases ? fn.contextAliases.concat(contextAliases) : contextAliases;
cloned.displayName = name || "cloneComponent(" + dn(fn) + ", [" + contextAliases.map(provideMap).join(', ') + "])";
return cloned;
}
function props(proto, name, descr) {
proto.constructor[rdiProp] = name;
if (!descr.value && !descr.set) {
descr.writable = true;
}
}
var subRulesId = Symbol('rdi_sub_rules');
var nameId = Symbol('rdi_theme_name');
var ruleId = Symbol('rdi_rule_id');
var BAD_CLASS_SYMBOLS = new RegExp('[^\\w\\d\\-\\_]', 'g');
var KEYFRAMES = '@keyframes ';
function replaceProps(obj, placeholder, replaceTo) {
for (var _key in obj) {
var val = obj[_key];
if (val && _key.indexOf('animation') === 0) {
obj[_key] = typeof val === 'object' ? replaceProps(val, placeholder, replaceTo) : val.replace(placeholder, replaceTo);
}
}
return obj;
}
var JssSheet =
/*#__PURE__*/
function () {
function JssSheet(jssSheet, owner, key) {
this.usageCount = 0;
this._scheduled = false;
this._lastAttached = new Set();
this._toDelete = new Set();
this.jssSheet = jssSheet;
this._owner = owner;
this.key = key;
}
var _proto = JssSheet.prototype;
_proto.addRule = function addRule(css, debugName) {
var sheet = this.jssSheet;
var id = css[ruleId];
var rule = undefined;
if (id === undefined) {
id = css[ruleId] = (css[nameId] || JSON.stringify(css)).replace(BAD_CLASS_SYMBOLS, '');
rule = sheet.getRule(id);
if (rule && css._dynamic === true) {
rule = undefined;
}
} else {
rule = sheet.getRule(id);
}
if (!rule) {
var prefix = sheet.options.classNamePrefix;
var placeholder = '@.';
var newCss = {};
var subRules = undefined;
for (var _key2 in css) {
var item = css[_key2];
if (item === true) continue; // _dynamic
if (_key2.indexOf(KEYFRAMES) === 0 && typeof item === 'object') {
if (subRules === undefined) subRules = [];
subRules.push(sheet.addRule(_key2.replace(placeholder, prefix), item));
} else {
newCss[_key2] = item !== null && typeof item === 'object' ? replaceProps(item, placeholder, prefix) : _key2.indexOf('animation') === 0 ? item.replace(placeholder, prefix) : item;
}
}
rule = sheet.addRule(id, newCss);
if (subRules) rule[subRulesId] = subRules;
if (!this._scheduled) this._owner.update(this);
this._scheduled = true;
}
this._lastAttached.add(rule);
this._toDelete.delete(rule);
return sheet.classes[id];
};
_proto._deleteRule = function _deleteRule(rule) {
var sheet = this.jssSheet;
var subRules = rule[subRulesId];
if (subRules !== undefined) {
for (var i = 0; i < subRules.length; i++) {
sheet.deleteRule(subRules[i].key);
}
}
sheet.deleteRule(rule.key);
};
_proto.attach = function attach() {
this._scheduled = false;
this._toDelete.forEach(this._deleteRule, this);
this._toDelete = this._lastAttached;
this._lastAttached = new Set();
this.jssSheet.attach();
};
_proto.destructor = function destructor() {
this.usageCount--;
if (this.usageCount !== 0) return;
this._toDelete = undefined;
this._lastAttached = undefined;
this._owner.update(this);
};
return JssSheet;
}();
function defaultSchedule(cb) {
setTimeout(cb, 16);
}
var JssSheetManager =
/*#__PURE__*/
function () {
function JssSheetManager(jss, schedule) {
if (schedule === void 0) {
schedule = defaultSchedule;
}
_initialiseProps.call(this);
this._jss = jss;
this._schedule = schedule;
}
JssSheetManager.createGenerateClassName = function createGenerateClassName() {
return function generateClassName(rule, sheet) {
return "" + (sheet ? sheet.options.classNamePrefix : '') + (rule.key ? "-" + rule.key : '');
};
};
var _proto2 = JssSheetManager.prototype;
_proto2.createSheet = function createSheet(sheetKey) {
var sheet = this._cache.get(sheetKey);
if (sheet === undefined) {
var _meta = sheetKey.replace(this._badClassSymbols, '');
var _options = {
meta: _meta,
classNamePrefix: _meta
};
sheet = new JssSheet(this._jss.createStyleSheet(undefined, _options), this, sheetKey);
this._cache.set(sheetKey, sheet);
}
sheet.usageCount++;
return sheet;
};
_proto2.update = function update(sheet) {
var scheduled = this._scheduled;
if (scheduled.length === 0) {
this._schedule(this._sync);
}
scheduled.push(sheet);
};
return JssSheetManager;
}();
var _initialiseProps = function _initialiseProps() {
var _this = this;
this._cache = new Map();
this._badClassSymbols = BAD_CLASS_SYMBOLS;
this._scheduled = [];
this._sync = function () {
var scheduled = _this._scheduled,
cache = _this._cache,
jss = _this._jss;
for (var i = 0; i < scheduled.length; i++) {
var _sheet = scheduled[i];
if (_sheet.usageCount === 0) {
cache.delete(_sheet.key);
jss.removeStyleSheet(_sheet.jssSheet);
} else {
_sheet.attach();
}
}
_this._scheduled = [];
};
};
function addDebugInfo(obj) {
if (obj[nameId] === undefined) {
for (var k in obj) {
var prop = obj[k];
if (prop && typeof prop === 'object') {
prop[nameId] = k;
}
}
}
return obj;
}
function themeProp(proto, name, descr) {
var className = proto.constructor.displayName || proto.constructor.name;
var getSheet = descr.get;
var value = descr.value;
if (getSheet === undefined && value === undefined) {
throw new Error("Need " + className + " { @theme get " + name + "() }");
}
if (getSheet) {
proto[name + "#"] = getSheet;
}
return {
enumerable: descr.enumerable,
configurable: descr.configurable,
get: function get() {
var obj = value || this[name + "#"]();
return addDebugInfo(obj);
}
};
}
function theme(proto, name, descr) {
return themeProp(proto, name, descr);
}
theme.fn = addDebugInfo;
exports.createReactWrapper = createReactWrapper;
exports.createCreateElement = createCreateElement;
exports.Injector = Injector;
exports.cloneComponent = cloneComponent;
exports.props = props;
exports.theme = theme;
exports.JssSheetManager = JssSheetManager;