reactive-di
Advanced tools
Comparing version 4.0.12 to 4.0.13
@@ -5,2 +5,7 @@ # Change Log | ||
<a name="4.0.13"></a> | ||
## [4.0.13](https://github.com/zerkalica/reactive-di/compare/v4.0.12...v4.0.13) (2017-09-13) | ||
<a name="4.0.12"></a> | ||
@@ -7,0 +12,0 @@ ## [4.0.12](https://github.com/zerkalica/reactive-di/compare/v4.0.11...v4.0.12) (2017-09-10) |
@@ -1,2 +0,2 @@ | ||
import { defaultContext, detached, memkey } from 'lom_atom'; | ||
import { detached, memkey } from 'lom_atom'; | ||
@@ -21,3 +21,19 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { | ||
var createClass = function () { | ||
function defineProperties(target, props) { | ||
for (var i = 0; i < props.length; i++) { | ||
var descriptor = props[i]; | ||
descriptor.enumerable = descriptor.enumerable || false; | ||
descriptor.configurable = true; | ||
if ("value" in descriptor) descriptor.writable = true; | ||
Object.defineProperty(target, descriptor.key, descriptor); | ||
} | ||
} | ||
return function (Constructor, protoProps, staticProps) { | ||
if (protoProps) defineProperties(Constructor.prototype, protoProps); | ||
if (staticProps) defineProperties(Constructor, staticProps); | ||
return Constructor; | ||
}; | ||
}(); | ||
@@ -117,6 +133,4 @@ | ||
SheetManager.prototype._destroyProp = function _destroyProp(key, value) { | ||
if (value !== undefined) { | ||
value.detach(); | ||
} | ||
SheetManager.prototype.destroy = function destroy(value) { | ||
value.detach(); | ||
}; | ||
@@ -126,15 +140,17 @@ | ||
}(), (_applyDecoratedDescriptor$1(_class2.prototype, "sheet", [memkey], Object.getOwnPropertyDescriptor(_class2.prototype, "sheet"), _class2.prototype)), _class2); | ||
var depId = 0; | ||
var Alias = function Alias(dest) { | ||
dest.__rdi_id = '' + ++depId; | ||
this.dest = dest; | ||
}; | ||
var Injector = function () { | ||
function Injector(items, sheetProcessor, state, parent, displayName, instance, aliases) { | ||
function Injector(items, sheetProcessor, displayName, instance, cache) { | ||
this._resolved = false; | ||
this._listeners = undefined; | ||
this._aliases = aliases; | ||
this._instance = instance || 0; | ||
this._state = state || null; | ||
this.parent = parent; | ||
this.displayName = displayName || '$'; | ||
this._sheetManager = sheetProcessor instanceof SheetManager ? sheetProcessor : new SheetManager(sheetProcessor, this); | ||
var map = this._cache = new Map(); | ||
var sticked = undefined; | ||
var map = this._cache = cache || Object.create(null); | ||
@@ -146,57 +162,52 @@ if (items !== undefined) { | ||
if (item instanceof Array) { | ||
map.set(item[0], item[1]); | ||
} else if (typeof item === 'function') { | ||
if (sticked === undefined) { | ||
sticked = new Set(); | ||
var src = item[0]; | ||
if (typeof src === 'string') { | ||
map[src] = item[1]; | ||
} else { | ||
if (src.__rdi_id === undefined) { | ||
src.__rdi_id = '' + ++depId; | ||
} | ||
var dest = item[1]; | ||
map[src.__rdi_id] = typeof dest === 'function' && !(dest instanceof Alias) ? new Alias(dest) : dest; | ||
} | ||
} else { | ||
var _src = item.constructor; | ||
sticked.add(item); | ||
} else { | ||
map.set(item.constructor, item); | ||
if (_src.__rdi_id === undefined) { | ||
_src.__rdi_id = '' + ++depId; | ||
} | ||
map[_src.__rdi_id] = item; | ||
} | ||
} | ||
} | ||
this._sticked = sticked; | ||
} | ||
Injector.prototype.value = function value(rawKey) { | ||
var key = this._aliases === undefined ? rawKey : this._aliases.get(rawKey) || rawKey; | ||
Injector.prototype.toString = function toString() { | ||
return this.displayName; | ||
}; | ||
var value = this._cache.get(key); | ||
Injector.prototype.toJSON = function toJSON() { | ||
return this._cache; | ||
}; | ||
if (value === undefined) { | ||
if (this._sticked === undefined || !this._sticked.has(key)) { | ||
var current = this.parent; | ||
Injector.prototype.value = function value(key) { | ||
var id = key.__rdi_id; | ||
if (current !== undefined) { | ||
do { | ||
value = current._cache.get(key); | ||
if (key.__rdi_id === undefined) { | ||
id = key.__rdi_id = '' + ++depId; | ||
} | ||
if (value !== undefined) { | ||
this._cache.set(key, value); | ||
var value = this._cache[id]; | ||
return value; | ||
} | ||
if (value === undefined) { | ||
value = this._cache[id] = this._fastNew(key); | ||
current = current.parent; | ||
} while (current !== undefined); | ||
} | ||
if (!value.displayName) { | ||
value.displayName = this.displayName + '.' + (key.displayName || key.name) + (this._instance > 0 ? '[' + this._instance + ']' : ''); | ||
} | ||
value = this._fastNew(key); | ||
this._cache.set(key, value); | ||
var keyName = (key.displayName || key.name) + (this._instance > 0 ? '[' + this._instance + ']' : ''); | ||
value.displayName = this.displayName + '.' + keyName; | ||
var state = this._state; | ||
if (state && value.__lom_state !== undefined) { | ||
if (state[keyName] === undefined) { | ||
state[keyName] = Object.create(value.__lom_state); | ||
} | ||
defaultContext.setState(value, state[keyName], true); | ||
} | ||
} else if (value instanceof Alias) { | ||
value = this._cache[id] = this.value(value.dest); | ||
} | ||
@@ -208,5 +219,3 @@ | ||
Injector.prototype.destroy = function destroy() { | ||
this._state = undefined; | ||
this._cache = undefined; | ||
this.parent = undefined; | ||
this._listeners = undefined; | ||
@@ -276,7 +285,15 @@ this._sheetManager = undefined; | ||
Injector.prototype.alias = function alias(key) { | ||
if (this._aliases === undefined) return key; | ||
Injector.prototype.alias = function alias(key, rawId) { | ||
var id = rawId; | ||
var newKey = this._aliases.get(key); | ||
if (id === undefined) { | ||
id = key.__rdi_id; | ||
if (id === undefined) { | ||
id = key.__rdi_id = '' + ++depId; | ||
} | ||
} | ||
var newKey = this._cache[id]; | ||
if (newKey instanceof Alias) return newKey.dest; | ||
if (newKey === undefined) return key; | ||
@@ -338,4 +355,4 @@ return newKey; | ||
Injector.prototype.copy = function copy(items, displayName, instance, aliases) { | ||
return new Injector(items, this._sheetManager, this._state, this, this.displayName + '.' + displayName, instance, aliases); | ||
Injector.prototype.copy = function copy(items, displayName, instance) { | ||
return new Injector(items, this._sheetManager, this.displayName + '.' + displayName, instance, Object.create(this._cache)); | ||
}; | ||
@@ -431,6 +448,15 @@ | ||
var isAtomic = typeof el === 'function' && el.constructor.render === undefined; | ||
var id = attrs ? attrs.id : undefined; | ||
if (isAtomic) { | ||
if (!attrs) { | ||
attrs = { | ||
__lom_ctx: parentContext | ||
}; | ||
} else { | ||
attrs.__lom_ctx = parentContext; | ||
} | ||
if (parentContext !== undefined) { | ||
newEl = parentContext.alias(el); | ||
newEl = parentContext.alias(el, id); | ||
if (newEl === null) return null; | ||
@@ -445,12 +471,9 @@ if (newEl !== undefined) el = newEl; | ||
newEl = el.__lom; | ||
} else { | ||
if (parentContext !== undefined && id) { | ||
newEl = parentContext.alias(el, id); | ||
if (newEl === null) return null; | ||
if (newEl !== undefined) el = newEl; | ||
} | ||
if (!attrs) { | ||
attrs = { | ||
__lom_ctx: parentContext | ||
}; | ||
} else { | ||
// newEl.isKey = attrs.key !== undefined | ||
attrs.__lom_ctx = parentContext; | ||
} | ||
} else { | ||
newEl = el; | ||
@@ -512,3 +535,3 @@ } | ||
_this._el = undefined; | ||
_this._keys = Object.keys(props); | ||
_this._keys = props ? Object.keys(props) : undefined; | ||
var cns = _this.constructor; | ||
@@ -518,3 +541,3 @@ var parentInjector = props.__lom_ctx || rootInjector; | ||
var injectorName = cns.displayName + (cns.instance ? '[' + cns.instance + ']' : ''); | ||
_this._injector = parentInjector.copy(undefined, injectorName, cns.instance, _this._render.aliases); | ||
_this._injector = parentInjector.copy(_this._render.aliases, injectorName, cns.instance); | ||
cns.instance++; | ||
@@ -524,8 +547,12 @@ return _this; | ||
AtomizedComponent.prototype.toString = function toString() { | ||
return this._injector.displayName + "." + this.constructor.displayName; | ||
}; | ||
AtomizedComponent.prototype.shouldComponentUpdate = function shouldComponentUpdate(props) { | ||
var keys = this._keys; | ||
if (this._render === undefined) return false; | ||
if (!keys) return false; | ||
var oldProps = this.props; | ||
for (var i = 0; i < keys.length; i++) { | ||
for (var i = 0, l = keys.length; i < l; i++) { | ||
// eslint-disable-line | ||
@@ -540,11 +567,10 @@ var k = keys[i]; | ||
return false; // this._propsChanged = shouldUpdate(this.props, props) | ||
// return this._propsChanged | ||
return false; | ||
}; | ||
AtomizedComponent.prototype.componentWillUnmount = function componentWillUnmount() { | ||
defaultContext.getAtom('r', this).destroyed(true); | ||
this['r()'].destroyed(true); | ||
}; | ||
AtomizedComponent.prototype._destroy = function _destroy() { | ||
AtomizedComponent.prototype.destroy = function destroy() { | ||
this._el = undefined; | ||
@@ -593,2 +619,8 @@ this._keys = undefined; | ||
createClass(AtomizedComponent, [{ | ||
key: "displayName", | ||
get: function get$$1() { | ||
return this.toString(); | ||
} | ||
}]); | ||
return AtomizedComponent; | ||
@@ -626,3 +658,3 @@ }(BaseComponent), (_applyDecoratedDescriptor(_class.prototype, "r", [detached], Object.getOwnPropertyDescriptor(_class.prototype, "r"), _class.prototype)), _class); | ||
function provideMap(item) { | ||
return "[" + dn(item[0]) + ", " + dn(item[1]) + "]"; | ||
return item instanceof Array ? "[" + dn(item[0]) + ", " + dn(item[1]) + "]" : dn(item); | ||
} | ||
@@ -655,3 +687,3 @@ | ||
cloned._r = fn._r; | ||
cloned.aliases = aliases !== undefined ? new Map(aliases) : undefined; | ||
cloned.aliases = fn.aliases ? fn.aliases.concat(aliases) : aliases; | ||
cloned.displayName = name || "cloneComponent(" + dn(fn) + ", [" + aliases.map(provideMap).join(', ') + "])"; | ||
@@ -658,0 +690,0 @@ return cloned; |
@@ -25,3 +25,19 @@ 'use strict'; | ||
var createClass = function () { | ||
function defineProperties(target, props) { | ||
for (var i = 0; i < props.length; i++) { | ||
var descriptor = props[i]; | ||
descriptor.enumerable = descriptor.enumerable || false; | ||
descriptor.configurable = true; | ||
if ("value" in descriptor) descriptor.writable = true; | ||
Object.defineProperty(target, descriptor.key, descriptor); | ||
} | ||
} | ||
return function (Constructor, protoProps, staticProps) { | ||
if (protoProps) defineProperties(Constructor.prototype, protoProps); | ||
if (staticProps) defineProperties(Constructor, staticProps); | ||
return Constructor; | ||
}; | ||
}(); | ||
@@ -121,6 +137,4 @@ | ||
SheetManager.prototype._destroyProp = function _destroyProp(key, value) { | ||
if (value !== undefined) { | ||
value.detach(); | ||
} | ||
SheetManager.prototype.destroy = function destroy(value) { | ||
value.detach(); | ||
}; | ||
@@ -130,15 +144,17 @@ | ||
}(), (_applyDecoratedDescriptor$1(_class2.prototype, "sheet", [lom_atom.memkey], Object.getOwnPropertyDescriptor(_class2.prototype, "sheet"), _class2.prototype)), _class2); | ||
var depId = 0; | ||
var Alias = function Alias(dest) { | ||
dest.__rdi_id = '' + ++depId; | ||
this.dest = dest; | ||
}; | ||
var Injector = function () { | ||
function Injector(items, sheetProcessor, state, parent, displayName, instance, aliases) { | ||
function Injector(items, sheetProcessor, displayName, instance, cache) { | ||
this._resolved = false; | ||
this._listeners = undefined; | ||
this._aliases = aliases; | ||
this._instance = instance || 0; | ||
this._state = state || null; | ||
this.parent = parent; | ||
this.displayName = displayName || '$'; | ||
this._sheetManager = sheetProcessor instanceof SheetManager ? sheetProcessor : new SheetManager(sheetProcessor, this); | ||
var map = this._cache = new Map(); | ||
var sticked = undefined; | ||
var map = this._cache = cache || Object.create(null); | ||
@@ -150,57 +166,52 @@ if (items !== undefined) { | ||
if (item instanceof Array) { | ||
map.set(item[0], item[1]); | ||
} else if (typeof item === 'function') { | ||
if (sticked === undefined) { | ||
sticked = new Set(); | ||
var src = item[0]; | ||
if (typeof src === 'string') { | ||
map[src] = item[1]; | ||
} else { | ||
if (src.__rdi_id === undefined) { | ||
src.__rdi_id = '' + ++depId; | ||
} | ||
var dest = item[1]; | ||
map[src.__rdi_id] = typeof dest === 'function' && !(dest instanceof Alias) ? new Alias(dest) : dest; | ||
} | ||
} else { | ||
var _src = item.constructor; | ||
sticked.add(item); | ||
} else { | ||
map.set(item.constructor, item); | ||
if (_src.__rdi_id === undefined) { | ||
_src.__rdi_id = '' + ++depId; | ||
} | ||
map[_src.__rdi_id] = item; | ||
} | ||
} | ||
} | ||
this._sticked = sticked; | ||
} | ||
Injector.prototype.value = function value(rawKey) { | ||
var key = this._aliases === undefined ? rawKey : this._aliases.get(rawKey) || rawKey; | ||
Injector.prototype.toString = function toString() { | ||
return this.displayName; | ||
}; | ||
var value = this._cache.get(key); | ||
Injector.prototype.toJSON = function toJSON() { | ||
return this._cache; | ||
}; | ||
if (value === undefined) { | ||
if (this._sticked === undefined || !this._sticked.has(key)) { | ||
var current = this.parent; | ||
Injector.prototype.value = function value(key) { | ||
var id = key.__rdi_id; | ||
if (current !== undefined) { | ||
do { | ||
value = current._cache.get(key); | ||
if (key.__rdi_id === undefined) { | ||
id = key.__rdi_id = '' + ++depId; | ||
} | ||
if (value !== undefined) { | ||
this._cache.set(key, value); | ||
var value = this._cache[id]; | ||
return value; | ||
} | ||
if (value === undefined) { | ||
value = this._cache[id] = this._fastNew(key); | ||
current = current.parent; | ||
} while (current !== undefined); | ||
} | ||
if (!value.displayName) { | ||
value.displayName = this.displayName + '.' + (key.displayName || key.name) + (this._instance > 0 ? '[' + this._instance + ']' : ''); | ||
} | ||
value = this._fastNew(key); | ||
this._cache.set(key, value); | ||
var keyName = (key.displayName || key.name) + (this._instance > 0 ? '[' + this._instance + ']' : ''); | ||
value.displayName = this.displayName + '.' + keyName; | ||
var state = this._state; | ||
if (state && value.__lom_state !== undefined) { | ||
if (state[keyName] === undefined) { | ||
state[keyName] = Object.create(value.__lom_state); | ||
} | ||
lom_atom.defaultContext.setState(value, state[keyName], true); | ||
} | ||
} else if (value instanceof Alias) { | ||
value = this._cache[id] = this.value(value.dest); | ||
} | ||
@@ -212,5 +223,3 @@ | ||
Injector.prototype.destroy = function destroy() { | ||
this._state = undefined; | ||
this._cache = undefined; | ||
this.parent = undefined; | ||
this._listeners = undefined; | ||
@@ -280,7 +289,15 @@ this._sheetManager = undefined; | ||
Injector.prototype.alias = function alias(key) { | ||
if (this._aliases === undefined) return key; | ||
Injector.prototype.alias = function alias(key, rawId) { | ||
var id = rawId; | ||
var newKey = this._aliases.get(key); | ||
if (id === undefined) { | ||
id = key.__rdi_id; | ||
if (id === undefined) { | ||
id = key.__rdi_id = '' + ++depId; | ||
} | ||
} | ||
var newKey = this._cache[id]; | ||
if (newKey instanceof Alias) return newKey.dest; | ||
if (newKey === undefined) return key; | ||
@@ -342,4 +359,4 @@ return newKey; | ||
Injector.prototype.copy = function copy(items, displayName, instance, aliases) { | ||
return new Injector(items, this._sheetManager, this._state, this, this.displayName + '.' + displayName, instance, aliases); | ||
Injector.prototype.copy = function copy(items, displayName, instance) { | ||
return new Injector(items, this._sheetManager, this.displayName + '.' + displayName, instance, Object.create(this._cache)); | ||
}; | ||
@@ -435,6 +452,15 @@ | ||
var isAtomic = typeof el === 'function' && el.constructor.render === undefined; | ||
var id = attrs ? attrs.id : undefined; | ||
if (isAtomic) { | ||
if (!attrs) { | ||
attrs = { | ||
__lom_ctx: parentContext | ||
}; | ||
} else { | ||
attrs.__lom_ctx = parentContext; | ||
} | ||
if (parentContext !== undefined) { | ||
newEl = parentContext.alias(el); | ||
newEl = parentContext.alias(el, id); | ||
if (newEl === null) return null; | ||
@@ -449,12 +475,9 @@ if (newEl !== undefined) el = newEl; | ||
newEl = el.__lom; | ||
} else { | ||
if (parentContext !== undefined && id) { | ||
newEl = parentContext.alias(el, id); | ||
if (newEl === null) return null; | ||
if (newEl !== undefined) el = newEl; | ||
} | ||
if (!attrs) { | ||
attrs = { | ||
__lom_ctx: parentContext | ||
}; | ||
} else { | ||
// newEl.isKey = attrs.key !== undefined | ||
attrs.__lom_ctx = parentContext; | ||
} | ||
} else { | ||
newEl = el; | ||
@@ -516,3 +539,3 @@ } | ||
_this._el = undefined; | ||
_this._keys = Object.keys(props); | ||
_this._keys = props ? Object.keys(props) : undefined; | ||
var cns = _this.constructor; | ||
@@ -522,3 +545,3 @@ var parentInjector = props.__lom_ctx || rootInjector; | ||
var injectorName = cns.displayName + (cns.instance ? '[' + cns.instance + ']' : ''); | ||
_this._injector = parentInjector.copy(undefined, injectorName, cns.instance, _this._render.aliases); | ||
_this._injector = parentInjector.copy(_this._render.aliases, injectorName, cns.instance); | ||
cns.instance++; | ||
@@ -528,8 +551,12 @@ return _this; | ||
AtomizedComponent.prototype.toString = function toString() { | ||
return this._injector.displayName + "." + this.constructor.displayName; | ||
}; | ||
AtomizedComponent.prototype.shouldComponentUpdate = function shouldComponentUpdate(props) { | ||
var keys = this._keys; | ||
if (this._render === undefined) return false; | ||
if (!keys) return false; | ||
var oldProps = this.props; | ||
for (var i = 0; i < keys.length; i++) { | ||
for (var i = 0, l = keys.length; i < l; i++) { | ||
// eslint-disable-line | ||
@@ -544,11 +571,10 @@ var k = keys[i]; | ||
return false; // this._propsChanged = shouldUpdate(this.props, props) | ||
// return this._propsChanged | ||
return false; | ||
}; | ||
AtomizedComponent.prototype.componentWillUnmount = function componentWillUnmount() { | ||
lom_atom.defaultContext.getAtom('r', this).destroyed(true); | ||
this['r()'].destroyed(true); | ||
}; | ||
AtomizedComponent.prototype._destroy = function _destroy() { | ||
AtomizedComponent.prototype.destroy = function destroy() { | ||
this._el = undefined; | ||
@@ -597,2 +623,8 @@ this._keys = undefined; | ||
createClass(AtomizedComponent, [{ | ||
key: "displayName", | ||
get: function get$$1() { | ||
return this.toString(); | ||
} | ||
}]); | ||
return AtomizedComponent; | ||
@@ -630,3 +662,3 @@ }(BaseComponent), (_applyDecoratedDescriptor(_class.prototype, "r", [lom_atom.detached], Object.getOwnPropertyDescriptor(_class.prototype, "r"), _class.prototype)), _class); | ||
function provideMap(item) { | ||
return "[" + dn(item[0]) + ", " + dn(item[1]) + "]"; | ||
return item instanceof Array ? "[" + dn(item[0]) + ", " + dn(item[1]) + "]" : dn(item); | ||
} | ||
@@ -659,3 +691,3 @@ | ||
cloned._r = fn._r; | ||
cloned.aliases = aliases !== undefined ? new Map(aliases) : undefined; | ||
cloned.aliases = fn.aliases ? fn.aliases.concat(aliases) : aliases; | ||
cloned.displayName = name || "cloneComponent(" + dn(fn) + ", [" + aliases.map(provideMap).join(', ') + "])"; | ||
@@ -662,0 +694,0 @@ return cloned; |
@@ -25,3 +25,19 @@ (function (global, factory) { | ||
var createClass = function () { | ||
function defineProperties(target, props) { | ||
for (var i = 0; i < props.length; i++) { | ||
var descriptor = props[i]; | ||
descriptor.enumerable = descriptor.enumerable || false; | ||
descriptor.configurable = true; | ||
if ("value" in descriptor) descriptor.writable = true; | ||
Object.defineProperty(target, descriptor.key, descriptor); | ||
} | ||
} | ||
return function (Constructor, protoProps, staticProps) { | ||
if (protoProps) defineProperties(Constructor.prototype, protoProps); | ||
if (staticProps) defineProperties(Constructor, staticProps); | ||
return Constructor; | ||
}; | ||
}(); | ||
@@ -121,6 +137,4 @@ | ||
SheetManager.prototype._destroyProp = function _destroyProp(key, value) { | ||
if (value !== undefined) { | ||
value.detach(); | ||
} | ||
SheetManager.prototype.destroy = function destroy(value) { | ||
value.detach(); | ||
}; | ||
@@ -130,15 +144,17 @@ | ||
}(), (_applyDecoratedDescriptor$1(_class2.prototype, "sheet", [lom_atom.memkey], Object.getOwnPropertyDescriptor(_class2.prototype, "sheet"), _class2.prototype)), _class2); | ||
var depId = 0; | ||
var Alias = function Alias(dest) { | ||
dest.__rdi_id = '' + ++depId; | ||
this.dest = dest; | ||
}; | ||
var Injector = function () { | ||
function Injector(items, sheetProcessor, state, parent, displayName, instance, aliases) { | ||
function Injector(items, sheetProcessor, displayName, instance, cache) { | ||
this._resolved = false; | ||
this._listeners = undefined; | ||
this._aliases = aliases; | ||
this._instance = instance || 0; | ||
this._state = state || null; | ||
this.parent = parent; | ||
this.displayName = displayName || '$'; | ||
this._sheetManager = sheetProcessor instanceof SheetManager ? sheetProcessor : new SheetManager(sheetProcessor, this); | ||
var map = this._cache = new Map(); | ||
var sticked = undefined; | ||
var map = this._cache = cache || Object.create(null); | ||
@@ -150,57 +166,52 @@ if (items !== undefined) { | ||
if (item instanceof Array) { | ||
map.set(item[0], item[1]); | ||
} else if (typeof item === 'function') { | ||
if (sticked === undefined) { | ||
sticked = new Set(); | ||
var src = item[0]; | ||
if (typeof src === 'string') { | ||
map[src] = item[1]; | ||
} else { | ||
if (src.__rdi_id === undefined) { | ||
src.__rdi_id = '' + ++depId; | ||
} | ||
var dest = item[1]; | ||
map[src.__rdi_id] = typeof dest === 'function' && !(dest instanceof Alias) ? new Alias(dest) : dest; | ||
} | ||
} else { | ||
var _src = item.constructor; | ||
sticked.add(item); | ||
} else { | ||
map.set(item.constructor, item); | ||
if (_src.__rdi_id === undefined) { | ||
_src.__rdi_id = '' + ++depId; | ||
} | ||
map[_src.__rdi_id] = item; | ||
} | ||
} | ||
} | ||
this._sticked = sticked; | ||
} | ||
Injector.prototype.value = function value(rawKey) { | ||
var key = this._aliases === undefined ? rawKey : this._aliases.get(rawKey) || rawKey; | ||
Injector.prototype.toString = function toString() { | ||
return this.displayName; | ||
}; | ||
var value = this._cache.get(key); | ||
Injector.prototype.toJSON = function toJSON() { | ||
return this._cache; | ||
}; | ||
if (value === undefined) { | ||
if (this._sticked === undefined || !this._sticked.has(key)) { | ||
var current = this.parent; | ||
Injector.prototype.value = function value(key) { | ||
var id = key.__rdi_id; | ||
if (current !== undefined) { | ||
do { | ||
value = current._cache.get(key); | ||
if (key.__rdi_id === undefined) { | ||
id = key.__rdi_id = '' + ++depId; | ||
} | ||
if (value !== undefined) { | ||
this._cache.set(key, value); | ||
var value = this._cache[id]; | ||
return value; | ||
} | ||
if (value === undefined) { | ||
value = this._cache[id] = this._fastNew(key); | ||
current = current.parent; | ||
} while (current !== undefined); | ||
} | ||
if (!value.displayName) { | ||
value.displayName = this.displayName + '.' + (key.displayName || key.name) + (this._instance > 0 ? '[' + this._instance + ']' : ''); | ||
} | ||
value = this._fastNew(key); | ||
this._cache.set(key, value); | ||
var keyName = (key.displayName || key.name) + (this._instance > 0 ? '[' + this._instance + ']' : ''); | ||
value.displayName = this.displayName + '.' + keyName; | ||
var state = this._state; | ||
if (state && value.__lom_state !== undefined) { | ||
if (state[keyName] === undefined) { | ||
state[keyName] = Object.create(value.__lom_state); | ||
} | ||
lom_atom.defaultContext.setState(value, state[keyName], true); | ||
} | ||
} else if (value instanceof Alias) { | ||
value = this._cache[id] = this.value(value.dest); | ||
} | ||
@@ -212,5 +223,3 @@ | ||
Injector.prototype.destroy = function destroy() { | ||
this._state = undefined; | ||
this._cache = undefined; | ||
this.parent = undefined; | ||
this._listeners = undefined; | ||
@@ -280,7 +289,15 @@ this._sheetManager = undefined; | ||
Injector.prototype.alias = function alias(key) { | ||
if (this._aliases === undefined) return key; | ||
Injector.prototype.alias = function alias(key, rawId) { | ||
var id = rawId; | ||
var newKey = this._aliases.get(key); | ||
if (id === undefined) { | ||
id = key.__rdi_id; | ||
if (id === undefined) { | ||
id = key.__rdi_id = '' + ++depId; | ||
} | ||
} | ||
var newKey = this._cache[id]; | ||
if (newKey instanceof Alias) return newKey.dest; | ||
if (newKey === undefined) return key; | ||
@@ -342,4 +359,4 @@ return newKey; | ||
Injector.prototype.copy = function copy(items, displayName, instance, aliases) { | ||
return new Injector(items, this._sheetManager, this._state, this, this.displayName + '.' + displayName, instance, aliases); | ||
Injector.prototype.copy = function copy(items, displayName, instance) { | ||
return new Injector(items, this._sheetManager, this.displayName + '.' + displayName, instance, Object.create(this._cache)); | ||
}; | ||
@@ -435,6 +452,15 @@ | ||
var isAtomic = typeof el === 'function' && el.constructor.render === undefined; | ||
var id = attrs ? attrs.id : undefined; | ||
if (isAtomic) { | ||
if (!attrs) { | ||
attrs = { | ||
__lom_ctx: parentContext | ||
}; | ||
} else { | ||
attrs.__lom_ctx = parentContext; | ||
} | ||
if (parentContext !== undefined) { | ||
newEl = parentContext.alias(el); | ||
newEl = parentContext.alias(el, id); | ||
if (newEl === null) return null; | ||
@@ -449,12 +475,9 @@ if (newEl !== undefined) el = newEl; | ||
newEl = el.__lom; | ||
} else { | ||
if (parentContext !== undefined && id) { | ||
newEl = parentContext.alias(el, id); | ||
if (newEl === null) return null; | ||
if (newEl !== undefined) el = newEl; | ||
} | ||
if (!attrs) { | ||
attrs = { | ||
__lom_ctx: parentContext | ||
}; | ||
} else { | ||
// newEl.isKey = attrs.key !== undefined | ||
attrs.__lom_ctx = parentContext; | ||
} | ||
} else { | ||
newEl = el; | ||
@@ -516,3 +539,3 @@ } | ||
_this._el = undefined; | ||
_this._keys = Object.keys(props); | ||
_this._keys = props ? Object.keys(props) : undefined; | ||
var cns = _this.constructor; | ||
@@ -522,3 +545,3 @@ var parentInjector = props.__lom_ctx || rootInjector; | ||
var injectorName = cns.displayName + (cns.instance ? '[' + cns.instance + ']' : ''); | ||
_this._injector = parentInjector.copy(undefined, injectorName, cns.instance, _this._render.aliases); | ||
_this._injector = parentInjector.copy(_this._render.aliases, injectorName, cns.instance); | ||
cns.instance++; | ||
@@ -528,8 +551,12 @@ return _this; | ||
AtomizedComponent.prototype.toString = function toString() { | ||
return this._injector.displayName + "." + this.constructor.displayName; | ||
}; | ||
AtomizedComponent.prototype.shouldComponentUpdate = function shouldComponentUpdate(props) { | ||
var keys = this._keys; | ||
if (this._render === undefined) return false; | ||
if (!keys) return false; | ||
var oldProps = this.props; | ||
for (var i = 0; i < keys.length; i++) { | ||
for (var i = 0, l = keys.length; i < l; i++) { | ||
// eslint-disable-line | ||
@@ -544,11 +571,10 @@ var k = keys[i]; | ||
return false; // this._propsChanged = shouldUpdate(this.props, props) | ||
// return this._propsChanged | ||
return false; | ||
}; | ||
AtomizedComponent.prototype.componentWillUnmount = function componentWillUnmount() { | ||
lom_atom.defaultContext.getAtom('r', this).destroyed(true); | ||
this['r()'].destroyed(true); | ||
}; | ||
AtomizedComponent.prototype._destroy = function _destroy() { | ||
AtomizedComponent.prototype.destroy = function destroy() { | ||
this._el = undefined; | ||
@@ -597,2 +623,8 @@ this._keys = undefined; | ||
createClass(AtomizedComponent, [{ | ||
key: "displayName", | ||
get: function get$$1() { | ||
return this.toString(); | ||
} | ||
}]); | ||
return AtomizedComponent; | ||
@@ -630,3 +662,3 @@ }(BaseComponent), (_applyDecoratedDescriptor(_class.prototype, "r", [lom_atom.detached], Object.getOwnPropertyDescriptor(_class.prototype, "r"), _class.prototype)), _class); | ||
function provideMap(item) { | ||
return "[" + dn(item[0]) + ", " + dn(item[1]) + "]"; | ||
return item instanceof Array ? "[" + dn(item[0]) + ", " + dn(item[1]) + "]" : dn(item); | ||
} | ||
@@ -659,3 +691,3 @@ | ||
cloned._r = fn._r; | ||
cloned.aliases = aliases !== undefined ? new Map(aliases) : undefined; | ||
cloned.aliases = fn.aliases ? fn.aliases.concat(aliases) : aliases; | ||
cloned.displayName = name || "cloneComponent(" + dn(fn) + ", [" + aliases.map(provideMap).join(', ') + "])"; | ||
@@ -662,0 +694,0 @@ return cloned; |
{ | ||
"name": "reactive-di", | ||
"version": "4.0.12", | ||
"version": "4.0.13", | ||
"description": "Reactive dependency injection", | ||
@@ -76,4 +76,4 @@ "publishConfig": { | ||
"dependencies": { | ||
"lom_atom": "^1.1.1" | ||
"lom_atom": "^1.1.2" | ||
} | ||
} |
532
README.md
@@ -5,18 +5,32 @@ # Reactive DI [![Build Status](https://secure.travis-ci.org/zerkalica/reactive-di.png)](http://travis-ci.org/zerkalica/reactive-di) | ||
Dependency injection with reactivity, state-management, state-to-css, state-to-dom rendering. | ||
Dependency injection with reactivity, applied to react-like components, css-in-js, unobtrusive state-management. Compatible with flow, react, but free from framework lock-in (no React.createElement, Inferno.createVNode), etc. | ||
Examples: [source](https://github.com/zerkalica/rdi-examples), [demo](http://zerkalica.github.io/rdi-examples/) | ||
## Motivation | ||
<!-- TOC depthFrom:2 depthTo:6 withLinks:1 updateOnSave:1 orderedList:0 --> | ||
* Free from framework lock-in (React.createElement, Inferno.createVNode), etc | ||
* jsx-based zero-dependency component, which can be used in any jsx-compatible render-to-dom library | ||
* Use typesystem metadata to glue dependencies together (like in angular2 and typescript) | ||
* reduce boilerplate code, by maximally using flow-types. Many decorators are unnecessary: use reflection metadata for classes, functions and components | ||
* Any stream is wrapper on top of domain data. We need to automate and move most of all reactive-data stream manipulations behind the scene. For example, [mobx](http://mobxjs.github.io/mobx/) is good there. | ||
- [Install](#install) | ||
- [Debug](#debug) | ||
- [Hello world](#hello-world) | ||
- [Features](#features) | ||
- [Typesafe context in components](#typesafe-context-in-components) | ||
- [State management based on lom_atom](#state-management-based-on-lomatom) | ||
- [Asyncronous code](#asyncronous-code) | ||
- [Error handling](#error-handling) | ||
- [Loading status handing](#loading-status-handing) | ||
- [Registering default dependencies](#registering-default-dependencies) | ||
- [Components cloning](#components-cloning) | ||
- [Hierarchical dependency injection](#hierarchical-dependency-injection) | ||
- [Optional css-in-js support](#optional-css-in-js-support) | ||
- [Passing component props to its depenendencies](#passing-component-props-to-its-depenendencies) | ||
- [React compatible](#react-compatible) | ||
- [Logging](#logging) | ||
- [Credits](#credits) | ||
<!-- /TOC --> | ||
## Install | ||
``` | ||
npm install --save reactive-di lom_atom | ||
npm install --save reactive-di lom_atom babel-plugin-transform-metadata | ||
``` | ||
@@ -34,2 +48,3 @@ | ||
"plugins": [ | ||
"transform-metadata", | ||
"transform-decorators-legacy", | ||
@@ -41,2 +56,4 @@ ["transform-react-jsx", {"pragma": "lom_h"}] | ||
babel-plugin-transform-metadata is optional, used for metadata generation. | ||
## Debug | ||
@@ -56,3 +73,3 @@ | ||
// @flow | ||
import {mem} from 'lom_atom' | ||
import {mem, action} from 'lom_atom' | ||
import {createReactWrapper, createCreateElement, Injector} from 'reactive-di' | ||
@@ -98,14 +115,507 @@ import {render, h, Component} from 'preact' | ||
<br/><input value={context.name} onInput={ | ||
(e: Event) => { | ||
action((e: Event) => { | ||
context.name = (e.target: any).value | ||
} | ||
}) | ||
} /> | ||
</div> | ||
} | ||
render(<HelloView prefix="Hello" />, document.body) | ||
``` | ||
## Features | ||
### Typesafe context in components | ||
```js | ||
// @flow | ||
function HelloView( | ||
{prefix}: {prefix: string}, // props | ||
{context}: {context: HelloContext} // automatically injected reactive context | ||
) { | ||
return <div>...</div> | ||
} | ||
``` | ||
Or | ||
```js | ||
function HelloView( | ||
_: {}, | ||
context: HelloComponent | ||
) { | ||
/// ... | ||
} | ||
``` | ||
Context signature generated from component via [babel-plugin-transform-metadata](https://github.com/zerkalica/babel-plugin-transform-metadata). | ||
Classes as keys. Without plugin, we need to define metadata manually: | ||
```js | ||
HelloView.deps = [{context: HelloContext}] | ||
``` | ||
Injector in createElement (lom_h) automatically initializes HelloContext and pass it to HelloView in | ||
```js | ||
render(<HelloView prefix="Hello" />, document.body) | ||
``` | ||
### State management based on lom_atom | ||
Rdi based on [lom_atom](https://github.com/zerkalica/lom_atom), state management library, like mobx, but much simpler and with some killer features. Statefull or stateless components in rdi - pure functions. | ||
Modifying state: | ||
```js | ||
import {action, mem} from 'lom_atom' | ||
class HelloContext { | ||
@mem name = '' | ||
} | ||
function HelloView( | ||
_: {}, | ||
{context}: {context: HelloContext} | ||
) { | ||
return <input value={context.name} onInput={ | ||
action((e: Event) => { | ||
context.name = (e.target: any).value | ||
}) | ||
} /> | ||
} | ||
``` | ||
All state changes are asynchronous, but for prevent loosing cursor position in react input, action helper used. | ||
### Asyncronous code | ||
Loading actual state: | ||
```js | ||
import {mem, force} from 'lom_atom' | ||
class HelloContext { | ||
@force force: HelloContext | ||
@mem set name(next: string | Error) {} | ||
@mem get name(): string { | ||
fetch('/hello') | ||
.then((r: Response) => r.json()) | ||
.then((data: Object) => { | ||
this.name = data.name | ||
}) | ||
.catch((e: Error) => { | ||
this.name = e | ||
}) | ||
throw new mem.Wait() | ||
} | ||
} | ||
function HelloView( | ||
_: {}, | ||
context: HelloContext | ||
) { | ||
return <div> | ||
<input value={context.name} onInput={ | ||
action((e: Event) => { | ||
context.name = (e.target: any).value | ||
}) | ||
} /> | ||
<button onClick={() => { context.forced.name }}>Reload from server</button> | ||
</div> | ||
} | ||
``` | ||
First time ``` context.name ``` invokes fetch('/hello') and actualizes state, second time - ``` context.name ``` returns value from cache. | ||
``` context.forced.name ``` invokes fetch handler again. | ||
``` context.name = value ``` value sets directly into cache. | ||
``` context.forced.name = value ``` invokes set name handler in HelloContext and sets into cache. | ||
### Error handling | ||
```js | ||
class HelloContext { | ||
@mem get name() { | ||
throw new Error('oops') | ||
} | ||
} | ||
function HelloView( | ||
_: {}, | ||
{context}: {context: HelloContext} | ||
) { | ||
return <input value={context.name} onInput={ | ||
action((e: Event) => { | ||
context.name = (e.target: any).value | ||
}) | ||
} /> | ||
} | ||
``` | ||
Accessing ``` context.name ``` throws oops, try/catch in HelloView wrapper displays default ErrorableView, registered in rdi: | ||
```js | ||
// ... | ||
function ErrorableView({error}: {error: Error}) { | ||
return <div> | ||
{error instanceof mem.Wait | ||
? <div> | ||
Loading... | ||
</div> | ||
: <div> | ||
<h3>Fatal error !</h3> | ||
<div>{error.message}</div> | ||
<pre> | ||
{error.stack.toString()} | ||
</pre> | ||
</div> | ||
} | ||
</div> | ||
} | ||
const lomCreateElement = createCreateElement( | ||
createReactWrapper( | ||
Component, | ||
ErrorableView | ||
), | ||
h | ||
) | ||
global['lom_h'] = lomCreateElement | ||
``` | ||
We can manually handle error: | ||
```js | ||
function HelloView( | ||
_: {}, | ||
{context}: {context: HelloContext} | ||
) { | ||
let name: string | ||
try { | ||
name = context.name | ||
} catch (e) { | ||
name = 'Error:' + e.message | ||
} | ||
return <input value={name} onInput={ | ||
action((e: Event) => { | ||
context.name = (e.target: any).value | ||
}) | ||
} /> | ||
} | ||
``` | ||
### Loading status handing | ||
Looks like error handling. ``` throw new mem.Wait() ``` throws some specific exception. | ||
```js | ||
class HelloContext { | ||
@force force: HelloContext | ||
@mem set name(next: string | Error) {} | ||
@mem get name(): string { | ||
fetch('/hello') | ||
.then((r: Response) => r.json()) | ||
.then((data: Object) => { | ||
this.name = data.name | ||
}) | ||
.catch((e: Error) => { | ||
this.name = e | ||
}) | ||
throw new mem.Wait() | ||
} | ||
} | ||
``` | ||
Catched in HelloComponent wrapper and default ErrorableView shows loader instead of HelloView. | ||
```js | ||
function ErrorableView({error}: {error: Error}) { | ||
return <div> | ||
{error instanceof mem.Wait | ||
? <div> | ||
Loading... | ||
</div> | ||
: <div> | ||
<h3>Fatal error !</h3> | ||
<div>{error.message}</div> | ||
<pre> | ||
{error.stack.toString()} | ||
</pre> | ||
</div> | ||
} | ||
</div> | ||
} | ||
``` | ||
We can manually define loader in component, using try/catch: | ||
```js | ||
function HelloView( | ||
_: {}, | ||
{context}: {context: HelloContext} | ||
) { | ||
let name: string | ||
try { | ||
name = context.name | ||
} catch (e) { | ||
if (e instanceof mem.Wait) { name = 'Loading...' } | ||
else { throw e } | ||
} | ||
return <input value={name} onInput={ | ||
action((e: Event) => { | ||
context.name = (e.target: any).value | ||
}) | ||
} /> | ||
} | ||
``` | ||
### Registering default dependencies | ||
```js | ||
class SomeAbstract {} | ||
class SomeConcrete extends SomeAbstract {} | ||
class C { | ||
a: SomeAbstract | ||
constructor(a: SomeAbstract) { | ||
this.a = a | ||
} | ||
} | ||
const injector = new Injector( | ||
[ | ||
[SomeAbstract, new SomeConcrete()] | ||
] | ||
) | ||
injector.value(SomeAbstract).a instanceof SomeConcrete | ||
``` | ||
### Components cloning | ||
Creates slightly modified component. | ||
```js | ||
import {cloneComponent} from 'reactive-di' | ||
class FirstCounterService { | ||
@mem value = 0 | ||
} | ||
function CounterMessageView({value}: {value: string}) { | ||
return <div>count: {value}</div> | ||
} | ||
function FirstCounterView( | ||
_: {}, | ||
counter: FirstCounterService | ||
) { | ||
return <div> | ||
<CounterMessageView value={counter.value}/> | ||
<button id="FirstCounterAddButton" onClick={() => { counter.value++ }}>Add</button> | ||
</div> | ||
} | ||
class SecondCounterService { | ||
@mem value = 1 | ||
} | ||
// Create FirstCounterView copy, but remove FirstCounterAddButton and replace FirstCounterService to SecondCounterService. | ||
const SecondCounterView = cloneComponent(FirstCounterView, [ | ||
[FirstCounterService, SecondCounterService], | ||
['FirstCounterAddButton', null], | ||
], 'SecondCounterView') | ||
``` | ||
### Hierarchical dependency injection | ||
```js | ||
class SharedService {} | ||
function Parent( | ||
props: {}, | ||
context: {sharedService: SharedService} | ||
) { | ||
return <Child parentService={context.sharedService} /> | ||
} | ||
function Child( | ||
context: {sharedService: SharedService} | ||
) { | ||
// context.sharedService instance cached in parent | ||
} | ||
``` | ||
```js | ||
class SharedService {} | ||
function Parent() { | ||
return <Child/> | ||
} | ||
function Child( | ||
props: {}, | ||
context: {sharedService: SharedService} | ||
) { | ||
// sharedService - cached in child | ||
} | ||
``` | ||
### Optional css-in-js support | ||
Via adapters rdi supports css-in-js with reactivity and dependency injection power: | ||
Setup: | ||
```js | ||
// @flow | ||
import {mem} from 'lom_atom' | ||
import {createReactWrapper, createCreateElement, Injector} from 'reactive-di' | ||
import {h, Component} from 'preact' | ||
import {create as createJss} from 'jss' | ||
import ErrorableView from './ErrorableView' | ||
const jss = createJss() | ||
/* | ||
jss must implements IProcessor interface: | ||
export interface IProcessor { | ||
createStyleSheet<V: Object>(_cssObj: V, options: any): ISheet<V>; | ||
} | ||
export interface ISheet<V: Object> { | ||
update(name?: string, props: V): ISheet<V>; | ||
attach(): ISheet<V>; | ||
detach(): ISheet<V>; | ||
classes: {+[id: $Keys<V>]: string}; | ||
} | ||
*/ | ||
const defaultDeps = [] | ||
const injector = new Injector(defaultDeps, jss) | ||
const lomCreateElement = createCreateElement( | ||
createReactWrapper( | ||
Component, | ||
ErrorableView, | ||
injector | ||
), | ||
h | ||
) | ||
global['lom_h'] = lomCreateElement | ||
``` | ||
Usage: | ||
```js | ||
import {mem} from 'lom_atom' | ||
class ThemeVars { | ||
@mem color = 'red' | ||
} | ||
function MyTheme(vars: ThemeVars) { | ||
return { | ||
wrapper: { | ||
backgroundColor: vars.color | ||
} | ||
} | ||
} | ||
MyTheme.theme = true | ||
function MyView( | ||
props: {}, | ||
{theme, vars}: {theme: MyTheme, vars: ThemeVars} | ||
) { | ||
return <div class={theme.wrapper}>...<button onClick={() => vars.color = 'green'}>Change color</button></div> | ||
} | ||
``` | ||
Styles automatically mounts/unmounts with component. Changing ``` vars.color ``` automatically rebuild and remount css. | ||
### Passing component props to its depenendencies | ||
Sometimes we need to pass component properties to its services. | ||
```js | ||
import {mem, props} from 'lom_atom' | ||
interface MyProps { | ||
some: string; | ||
} | ||
class MyViewService { | ||
@props _props: MyProps; | ||
// @mem @props _props: MyProps; // for reactive props | ||
@mem get some(): string { | ||
return this._props.some + '-suffix' | ||
} | ||
} | ||
function MyView( | ||
props: MyProps, | ||
{service}: {service: MyViewService} | ||
) { | ||
return <div>{service.some}</div> | ||
} | ||
``` | ||
### React compatible | ||
We still can use any react/preact/inferno components together rdi components. | ||
### Logging | ||
```js | ||
import {defaultContext, BaseLogger} from 'lom_atom' | ||
import type {ILogger} from 'lom_atom' | ||
class Logger extends BaseLogger { | ||
/** | ||
* Invokes before atom creating | ||
* | ||
* @param host Object Object with atom | ||
* @param field string property name | ||
* @param key mixed | void for dictionary atoms - dictionary key | ||
*/ | ||
create<V>(host: Object, field: string, key?: mixed): V | void {} | ||
/** | ||
* After atom destroy | ||
*/ | ||
destroy(atom: IAtom<*>): void {} | ||
/** | ||
* Atom status changes | ||
- 'waiting' - atom fetching from server (mem.Wait throwed) | ||
- 'proposeToReap' - atom probably will be destroyed on next tick | ||
- 'proposeToPull' - atom will be actualized on next tick | ||
*/ | ||
status(status: ILoggerStatus, atom: IAtom<*>): void {} | ||
/** | ||
* Error while actualizing atom | ||
*/ | ||
error<V>(atom: IAtom<V>, err: Error): void {} | ||
/** | ||
* Atom value changed | ||
* @param isActualize bool if true - atom handler invoked, if false - only atom.cache value getted/setted | ||
*/ | ||
newValue<V>(atom: IAtom<V>, from?: V | Error, to: V, isActualize?: boolean): void {} | ||
} | ||
defaultContext.setLogger(new Logger()) | ||
``` | ||
## Credits | ||
@@ -112,0 +622,0 @@ |
@@ -20,7 +20,9 @@ // @flow | ||
function provideMap(item: [Function, Function]): string { | ||
return `[${dn(item[0])}, ${dn(item[1])}]` | ||
function provideMap(item: IProvideItem): string { | ||
return item instanceof Array | ||
? `[${dn(item[0])}, ${dn(item[1])}]` | ||
: dn(item) | ||
} | ||
export default function cloneComponent<V: Function>(fn: V, aliases: [Function, Function][], name?: string): V { | ||
export default function cloneComponent<V: Function>(fn: V, aliases: IProvideItem[], name?: string): V { | ||
const cloned = function () { | ||
@@ -38,5 +40,6 @@ switch (arguments.length) { | ||
cloned._r = fn._r | ||
cloned.aliases = aliases !== undefined ? new Map(aliases) : undefined | ||
cloned.aliases = fn.aliases ? fn.aliases.concat(aliases) : aliases | ||
cloned.displayName = name || `cloneComponent(${dn(fn)}, [${aliases.map(provideMap).join(', ')}])` | ||
return (cloned: any) | ||
} |
// @flow | ||
import {defaultContext, mem, detached} from 'lom_atom' | ||
import {mem, detached} from 'lom_atom' | ||
import type {NamesOf} from 'lom_atom' | ||
@@ -20,3 +20,3 @@ | ||
onError?: IFromError<IElement>; | ||
aliases?: Map<Function, Function>; | ||
aliases?: IProvideItem[]; | ||
} | ||
@@ -30,24 +30,2 @@ | ||
function shouldUpdate<Props: Object>(oldProps: Props, props: Props): boolean { | ||
if (oldProps === props) { | ||
return false | ||
} | ||
if ((!oldProps && props) || (!props && oldProps)) { | ||
return true | ||
} | ||
let lpKeys = 0 | ||
for (let k in oldProps) { // eslint-disable-line | ||
if (oldProps[k] !== props[k]) { | ||
return true | ||
} | ||
lpKeys++ | ||
} | ||
for (let k in props) { // eslint-disable-line | ||
lpKeys-- | ||
} | ||
return lpKeys !== 0 | ||
} | ||
let parentContext: Injector | void = undefined | ||
@@ -62,8 +40,13 @@ | ||
let attrs = arguments[1] | ||
let newEl | ||
const isAtomic = typeof el === 'function' && el.constructor.render === undefined | ||
const id = attrs ? attrs.id : undefined | ||
if (isAtomic) { | ||
if (!attrs) { | ||
attrs = {__lom_ctx: parentContext} | ||
} else { | ||
attrs.__lom_ctx = parentContext | ||
} | ||
if (parentContext !== undefined) { | ||
newEl = parentContext.alias(el) | ||
newEl = parentContext.alias(el, id) | ||
if (newEl === null) return null | ||
@@ -77,9 +60,8 @@ if (newEl !== undefined) el = newEl | ||
newEl = el.__lom | ||
if (!attrs) { | ||
attrs = {__lom_ctx: parentContext} | ||
} else { | ||
// newEl.isKey = attrs.key !== undefined | ||
attrs.__lom_ctx = parentContext | ||
} else { | ||
if (parentContext !== undefined && id) { | ||
newEl = parentContext.alias(el, id) | ||
if (newEl === null) return null | ||
if (newEl !== undefined) el = newEl | ||
} | ||
} else { | ||
newEl = el | ||
@@ -135,3 +117,3 @@ } | ||
_keys: string[] | ||
_keys: string[] | void | ||
_render: IRenderFn<IElement, State> | ||
@@ -144,3 +126,3 @@ | ||
super(props, reactContext) | ||
this._keys = Object.keys(props) | ||
this._keys = props ? Object.keys(props) : undefined | ||
const cns = this.constructor | ||
@@ -151,6 +133,5 @@ const parentInjector = props.__lom_ctx || rootInjector | ||
this._injector = parentInjector.copy( | ||
undefined, | ||
this._render.aliases, | ||
injectorName, | ||
cns.instance, | ||
this._render.aliases | ||
cns.instance | ||
) | ||
@@ -160,7 +141,15 @@ cns.instance++ | ||
toString() { | ||
return `${this._injector.displayName}.${this.constructor.displayName}` | ||
} | ||
get displayName() { | ||
return this.toString() | ||
} | ||
shouldComponentUpdate(props: IPropsWithContext) { | ||
const keys = this._keys | ||
if (this._render === undefined) return false | ||
if (!keys) return false | ||
const oldProps = this.props | ||
for (let i = 0; i < keys.length; i++) { // eslint-disable-line | ||
for (let i = 0, l = keys.length; i < l; i++) { // eslint-disable-line | ||
const k = keys[i] | ||
@@ -173,14 +162,11 @@ if (oldProps[k] !== props[k]) { | ||
return false | ||
// this._propsChanged = shouldUpdate(this.props, props) | ||
// return this._propsChanged | ||
} | ||
componentWillUnmount() { | ||
defaultContext.getAtom('r', this).destroyed(true) | ||
this['r()'].destroyed(true) | ||
} | ||
_destroy() { | ||
destroy() { | ||
this._el = undefined | ||
this._keys = (undefined: any) | ||
this._keys = undefined | ||
this.props = (undefined: any) | ||
@@ -222,5 +208,3 @@ if (this._render !== undefined) { | ||
render() { | ||
return this._el === undefined | ||
? this.r(undefined, this._propsChanged) | ||
: this._el | ||
return this._el === undefined ? this.r(undefined, this._propsChanged) : this._el | ||
} | ||
@@ -227,0 +211,0 @@ } |
@@ -6,3 +6,3 @@ // @flow | ||
export type IArg = Function | {+[id: string]: Function} | ||
export type IProvideItem = Function | Object | [Function, mixed] | ||
export type IProvideItem = Function | Object | [Function | string, Function | mixed] | ||
@@ -71,6 +71,4 @@ export type IPropsWithContext = { | ||
_destroyProp(key?: string | Function, value?: ISheet<*>) { | ||
if (value !== undefined) { | ||
value.detach() | ||
} | ||
destroy(value: ISheet<*>) { | ||
value.detach() | ||
} | ||
@@ -81,26 +79,27 @@ } | ||
type ICache = {[id: string]: any} | ||
let depId = 0 | ||
class Alias<T: Function> { | ||
dest: T | ||
constructor(dest: T) { | ||
dest.__rdi_id = '' + ++depId | ||
this.dest = dest | ||
} | ||
} | ||
export default class Injector { | ||
parent: Injector | void | ||
displayName: string | ||
_sheetManager: SheetManager | ||
_cache: Map<Function, any> | ||
_aliases: Map<Function, Function> | void | ||
_cache: ICache | ||
_instance: number | ||
_state: ?Object | ||
_sticked: Set<Function> | void | ||
constructor( | ||
items?: IProvideItem[], | ||
sheetProcessor?: IProcessor | SheetManager, | ||
state?: ?Object, | ||
parent?: Injector, | ||
displayName?: string, | ||
instance?: number, | ||
aliases?: Map<Function, Function> | ||
cache?: ICache | ||
) { | ||
this._aliases = aliases | ||
this._instance = instance || 0 | ||
this._state = state || null | ||
this.parent = parent | ||
this.displayName = displayName || '$' | ||
@@ -111,4 +110,3 @@ this._sheetManager = sheetProcessor instanceof SheetManager | ||
const map = this._cache = new Map() | ||
let sticked: Set<Function> | void = undefined | ||
const map = this._cache = cache || Object.create(null) | ||
if (items !== undefined) { | ||
@@ -118,45 +116,50 @@ for (let i = 0; i < items.length; i++) { | ||
if (item instanceof Array) { | ||
map.set(item[0], item[1]) | ||
} else if (typeof item === 'function') { | ||
if (sticked === undefined) { | ||
sticked = new Set() | ||
const src: string | Function = item[0] | ||
if (typeof src === 'string') { | ||
map[src] = item[1] | ||
} else { | ||
if (src.__rdi_id === undefined) { | ||
src.__rdi_id = '' + ++depId | ||
} | ||
const dest = item[1] | ||
map[src.__rdi_id] = typeof dest === 'function' && !(dest instanceof Alias) | ||
? new Alias(dest) | ||
: dest | ||
} | ||
sticked.add(item) | ||
} else { | ||
map.set(item.constructor, item) | ||
const src = item.constructor | ||
if (src.__rdi_id === undefined) { | ||
src.__rdi_id = '' + ++depId | ||
} | ||
map[src.__rdi_id] = item | ||
} | ||
} | ||
} | ||
this._sticked = sticked | ||
} | ||
value<V>(rawKey: Function): V { | ||
const key = this._aliases === undefined ? rawKey : (this._aliases.get(rawKey) || rawKey) | ||
let value = this._cache.get(key) | ||
toString() { | ||
return this.displayName | ||
} | ||
toJSON() { | ||
return this._cache | ||
} | ||
value<V>(key: Function): V { | ||
let id: string = key.__rdi_id | ||
if (key.__rdi_id === undefined) { | ||
id = key.__rdi_id = '' + ++depId | ||
} | ||
let value = this._cache[id] | ||
if (value === undefined) { | ||
if (this._sticked === undefined || !this._sticked.has(key)) { | ||
let current = this.parent | ||
if (current !== undefined) { | ||
do { | ||
value = current._cache.get(key) | ||
if (value !== undefined) { | ||
this._cache.set(key, value) | ||
return value | ||
} | ||
current = current.parent | ||
} while (current !== undefined) | ||
} | ||
value = this._cache[id] = this._fastNew(key) | ||
if (!value.displayName) { | ||
value.displayName = this.displayName | ||
+ '.' | ||
+ (key.displayName || key.name) | ||
+ (this._instance > 0 ? ('[' + this._instance + ']') : '') | ||
} | ||
value = this._fastNew(key) | ||
this._cache.set(key, value) | ||
const keyName = (key.displayName || key.name) + (this._instance > 0 ? ('[' + this._instance + ']') : '') | ||
value.displayName = this.displayName + '.' + keyName | ||
const state = this._state | ||
if (state && value.__lom_state !== undefined) { | ||
if (state[keyName] === undefined) { | ||
state[keyName] = Object.create(value.__lom_state) | ||
} | ||
defaultContext.setState(value, state[keyName], true) | ||
} | ||
} else if (value instanceof Alias) { | ||
value = this._cache[id] = this.value(value.dest) | ||
} | ||
@@ -168,5 +171,3 @@ | ||
destroy() { | ||
this._state = undefined | ||
this._cache = (undefined: any) | ||
this.parent = undefined | ||
this._listeners = undefined | ||
@@ -207,5 +208,12 @@ this._sheetManager = (undefined: any) | ||
alias(key: Function): ?Function { | ||
if (this._aliases === undefined) return key | ||
const newKey = this._aliases.get(key) | ||
alias(key: Function, rawId?: string): Function { | ||
let id: string | void = rawId | ||
if (id === undefined) { | ||
id = key.__rdi_id | ||
if (id === undefined) { | ||
id = key.__rdi_id = '' + ++depId | ||
} | ||
} | ||
const newKey = this._cache[id] | ||
if (newKey instanceof Alias) return newKey.dest | ||
if (newKey === undefined) return key | ||
@@ -245,11 +253,9 @@ | ||
copy(items?: IProvideItem[], displayName: string, instance?: number, aliases?: Map<Function, Function>): Injector { | ||
copy(items?: IProvideItem[], displayName: string, instance?: number): Injector { | ||
return new Injector( | ||
items, | ||
this._sheetManager, | ||
this._state, | ||
this, | ||
this.displayName + '.' + displayName, | ||
instance, | ||
aliases | ||
Object.create(this._cache) | ||
) | ||
@@ -256,0 +262,0 @@ } |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
194828
2085
623
Updatedlom_atom@^1.1.2