Comparing version 0.3.2 to 0.4.0
{ | ||
"name": "baobab", | ||
"main": "build/baobab.min.js", | ||
"version": "0.3.2", | ||
"version": "0.4.0", | ||
"homepage": "https://github.com/Yomguithereal/baobab", | ||
@@ -6,0 +6,0 @@ "author": { |
@@ -12,3 +12,3 @@ /** | ||
Object.defineProperty(Baobab, 'version', { | ||
value: '0.3.2' | ||
value: '0.4.0' | ||
}); | ||
@@ -15,0 +15,0 @@ |
{ | ||
"name": "baobab", | ||
"version": "0.3.2", | ||
"version": "0.4.0", | ||
"description": "JavaScript data tree with cursors.", | ||
"main": "index.js", | ||
"dependencies": { | ||
"emmett": "^2.1.1", | ||
"emmett": "^2.1.2", | ||
"typology": "^0.3.1" | ||
@@ -22,3 +22,3 @@ }, | ||
"mocha": "^2.0.1", | ||
"react": "^0.12.2", | ||
"react": "^0.13.0", | ||
"vinyl-transform": "^1.0.0" | ||
@@ -25,0 +25,0 @@ }, |
@@ -14,5 +14,10 @@ /** | ||
mixins = require('./mixins.js'), | ||
defaults = require('../defaults.json'), | ||
defaults = require('../defaults.js'), | ||
type = require('./type.js'); | ||
function complexHash(type) { | ||
return type + '$' + | ||
(new Date()).getTime() + ('' + Math.random()).replace('0.', ''); | ||
} | ||
/** | ||
@@ -22,2 +27,4 @@ * Main Class | ||
function Baobab(initialData, opts) { | ||
if (arguments.length < 1) | ||
initialData = {}; | ||
@@ -39,6 +46,6 @@ // New keyword optional | ||
// Privates | ||
this._futureUpdate = {}; | ||
this._willUpdate = false; | ||
this._transaction = {}; | ||
this._future = undefined; | ||
this._history = []; | ||
this._registeredCursors = {}; | ||
this._cursors = {}; | ||
@@ -53,3 +60,3 @@ // Internal typology | ||
// Internal validation | ||
this.validate = this.options.validate || null; | ||
this.validate = this.options.validate || null; | ||
@@ -77,30 +84,2 @@ if (this.validate) | ||
*/ | ||
Baobab.prototype._stack = function(spec) { | ||
var self = this; | ||
if (!type.Object(spec)) | ||
throw Error('Baobab.update: wrong specification.'); | ||
this._futureUpdate = merge(spec, this._futureUpdate); | ||
// Should we let the user commit? | ||
if (!this.options.autoCommit) | ||
return this; | ||
// Should we update synchronously? | ||
if (!this.options.asynchronous) | ||
return this.commit(); | ||
// Updating asynchronously | ||
if (!this._willUpdate) { | ||
this._willUpdate = true; | ||
process.nextTick(function() { | ||
if (self._willUpdate) | ||
self.commit(); | ||
}); | ||
} | ||
return this; | ||
}; | ||
Baobab.prototype._archive = function() { | ||
@@ -144,3 +123,3 @@ if (this.options.maxHistory <= 0) | ||
var record = this._archive(); | ||
log = update(this.data, this._futureUpdate, this.options); | ||
log = update(this.data, this._transaction, this.options); | ||
@@ -182,5 +161,7 @@ if (record) | ||
// Resetting | ||
this._futureUpdate = {}; | ||
this._willUpdate = false; | ||
this._transaction = {}; | ||
if (this._future) | ||
this._future = clearTimeout(this._future); | ||
return this; | ||
@@ -212,11 +193,18 @@ }; | ||
else { | ||
var hash = path.join('λ'); | ||
var hash = path.map(function(step) { | ||
if (type.Function(step)) | ||
return complexHash('fn'); | ||
else if (type.Object(step)) | ||
return complexHash('ob'); | ||
else | ||
return step; | ||
}).join('λ'); | ||
if (!this._registeredCursors[hash]) { | ||
var cursor = new Cursor(this, path, solvedPath); | ||
this._registeredCursors[hash] = cursor; | ||
if (!this._cursors[hash]) { | ||
var cursor = new Cursor(this, path, solvedPath, hash); | ||
this._cursors[hash] = cursor; | ||
return cursor; | ||
} | ||
else { | ||
return this._registeredCursors[hash]; | ||
return this._cursors[hash]; | ||
} | ||
@@ -261,4 +249,33 @@ } | ||
Baobab.prototype.unset = function(key) { | ||
if (!key && key !== 0) | ||
throw Error('Baobab.unset: expects a valid key to unset.'); | ||
var spec = {}; | ||
spec[key] = {$unset: true}; | ||
return this.update(spec); | ||
}; | ||
Baobab.prototype.update = function(spec) { | ||
return this._stack(spec); | ||
var self = this; | ||
if (!type.Object(spec)) | ||
throw Error('Baobab.update: wrong specification.'); | ||
this._transaction = merge(spec, this._transaction); | ||
// Should we let the user commit? | ||
if (!this.options.autoCommit) | ||
return this; | ||
// Should we update synchronously? | ||
if (!this.options.asynchronous) | ||
return this.commit(); | ||
// Updating asynchronously | ||
if (!this._future) | ||
this._future = setTimeout(self.commit.bind(self, null), 0); | ||
return this; | ||
}; | ||
@@ -283,7 +300,11 @@ | ||
Baobab.prototype.release = function() { | ||
this.unbindAll(); | ||
this.kill(); | ||
delete this.data; | ||
delete this._futureUpdate; | ||
delete this._transaction; | ||
delete this._history; | ||
delete this._registeredCursors; | ||
// Releasing cursors | ||
for (var k in this._cursors) | ||
this._cursors[k].release(); | ||
delete this._cursors; | ||
}; | ||
@@ -290,0 +311,0 @@ |
@@ -65,3 +65,3 @@ /** | ||
shouldFire = self.operators[i - 1] === 'or' ? | ||
shouldFire || self.updates[i] : | ||
shouldFire || self.updates[i] : | ||
shouldFire && self.updates[i]; | ||
@@ -117,3 +117,3 @@ } | ||
// Dropping own listeners | ||
this.unbindAll(); | ||
this.kill(); | ||
@@ -120,0 +120,0 @@ // Dropping cursors listeners |
@@ -16,3 +16,3 @@ /** | ||
*/ | ||
function Cursor(root, path, solvedPath) { | ||
function Cursor(root, path, solvedPath, hash) { | ||
var self = this; | ||
@@ -24,3 +24,3 @@ | ||
// Enforcing array | ||
path = path || []; | ||
path = path || []; | ||
@@ -30,2 +30,3 @@ // Properties | ||
this.path = path; | ||
this.hash = hash; | ||
this.relevant = this.reference() !== undefined; | ||
@@ -82,3 +83,3 @@ | ||
} | ||
else { | ||
else if (!data) { | ||
self.emit('irrelevant'); | ||
@@ -107,10 +108,2 @@ self.relevant = false; | ||
/** | ||
* Private prototype | ||
*/ | ||
Cursor.prototype._stack = function(spec) { | ||
this.root._stack(helpers.pathObject(this.solvedPath, spec)); | ||
return this; | ||
}; | ||
/** | ||
* Predicates | ||
@@ -250,2 +243,15 @@ */ | ||
Cursor.prototype.unset = function(key) { | ||
if (!key && key !== 0) | ||
throw Error('baobab.Cursor.unset: expects a valid key to unset.'); | ||
var spec = {}; | ||
spec[key] = {$unset: true}; | ||
return this.update(spec); | ||
}; | ||
Cursor.prototype.remove = function() { | ||
return this.update({$unset: true}); | ||
}; | ||
Cursor.prototype.apply = function(fn) { | ||
@@ -298,3 +304,4 @@ if (typeof fn !== 'function') | ||
Cursor.prototype.update = function(spec) { | ||
return this._stack(spec); | ||
this.root.update(helpers.pathObject(this.solvedPath, spec)); | ||
return this; | ||
}; | ||
@@ -318,4 +325,6 @@ | ||
this.root.off('update', this.updateHandler); | ||
if (this.hash) | ||
delete this.root._cursors[this.hash]; | ||
this.root = null; | ||
this.unbindAll(); | ||
this.kill(); | ||
}; | ||
@@ -322,0 +331,0 @@ |
@@ -25,29 +25,22 @@ /** | ||
// Shallow clone | ||
function shallowClone(item) { | ||
if (!item || !(item instanceof Object)) | ||
return item; | ||
// Clone a regexp | ||
function cloneRegexp(re) { | ||
var pattern = re.source, | ||
flags = ''; | ||
// Array | ||
if (type.Array(item)) | ||
return item.slice(0); | ||
if (re.global) flags += 'g'; | ||
if (re.multiline) flags += 'm'; | ||
if (re.ignoreCase) flags += 'i'; | ||
if (re.sticky) flags += 'y'; | ||
if (re.unicode) flags += 'u'; | ||
// Date | ||
if (type.Date(item)) | ||
return new Date(item.getTime()); | ||
// Object | ||
if (type.Object(item)) { | ||
var k, o = {}; | ||
for (k in item) | ||
o[k] = item[k]; | ||
return o; | ||
} | ||
return item; | ||
return new RegExp(pattern, flags); | ||
} | ||
// Deep clone | ||
function deepClone(item) { | ||
if (!item || !(item instanceof Object)) | ||
// Cloning function | ||
function clone(deep, item) { | ||
if (!item || | ||
typeof item !== 'object' || | ||
item instanceof Error || | ||
item instanceof ArrayBuffer) | ||
return item; | ||
@@ -57,6 +50,11 @@ | ||
if (type.Array(item)) { | ||
var i, l, a = []; | ||
for (i = 0, l = item.length; i < l; i++) | ||
a.push(deepClone(item[i])); | ||
return a; | ||
if (deep) { | ||
var i, l, a = []; | ||
for (i = 0, l = item.length; i < l; i++) | ||
a.push(deepClone(item[i])); | ||
return a; | ||
} | ||
else { | ||
return item.slice(0); | ||
} | ||
} | ||
@@ -68,7 +66,16 @@ | ||
// RegExp | ||
if (item instanceof RegExp) | ||
return cloneRegexp(item); | ||
// Object | ||
if (type.Object(item)) { | ||
var k, o = {}; | ||
if (item.constructor && item.constructor !== Object) | ||
o = Object.create(item.constructor.prototype); | ||
for (k in item) | ||
o[k] = deepClone(item[k]); | ||
if (item.hasOwnProperty(k)) | ||
o[k] = deep ? deepClone(item[k]) : item[k]; | ||
return o; | ||
@@ -80,2 +87,6 @@ } | ||
// Shallow & deep cloning functions | ||
var shallowClone = clone.bind(null, false), | ||
deepClone = clone.bind(null, true); | ||
// Simplistic composition | ||
@@ -82,0 +93,0 @@ function compose(fn1, fn2) { |
@@ -32,2 +32,3 @@ /** | ||
// When solving conflicts, here is the priority to apply: | ||
// -- 0) $unset | ||
// -- 1) $set | ||
@@ -37,5 +38,12 @@ // -- 2) $merge | ||
// -- 4) $chain | ||
if (arguments[i].$set) { | ||
if (arguments[i].$unset) { | ||
delete res.$set; | ||
delete res.$apply; | ||
delete res.$merge; | ||
res.$unset = arguments[i].$unset; | ||
} | ||
else if (arguments[i].$set) { | ||
delete res.$apply; | ||
delete res.$merge; | ||
delete res.$unset; | ||
res.$set = arguments[i].$set; | ||
@@ -47,2 +55,3 @@ continue; | ||
delete res.$apply; | ||
delete res.$unset; | ||
res.$merge = arguments[i].$merge; | ||
@@ -54,2 +63,3 @@ continue; | ||
delete res.$merge; | ||
delete res.$unset; | ||
res.$apply = arguments[i].$apply; | ||
@@ -61,2 +71,3 @@ continue; | ||
delete res.$merge; | ||
delete res.$unset; | ||
@@ -63,0 +74,0 @@ if (res.$apply) |
@@ -73,3 +73,3 @@ /** | ||
this.__getCursorData = (function() { | ||
this.__getCursorData = (function() { | ||
var d = {}; | ||
@@ -76,0 +76,0 @@ for (k in this.cursors) |
@@ -7,2 +7,4 @@ /** | ||
* tests at runtime. | ||
* | ||
* @christianalfoni | ||
*/ | ||
@@ -99,11 +101,10 @@ | ||
var complexTypes = ['object', 'function']; | ||
var hasComplexTypes = false; | ||
for (var x = 0; x < value.length; x++) { | ||
if (complexTypes.indexOf(type(value[x])) >= 0) { | ||
hasComplexTypes = true; | ||
return true; | ||
} | ||
} | ||
return hasComplexTypes; | ||
return false; | ||
}; | ||
module.exports = type; |
@@ -24,3 +24,3 @@ /** | ||
function makeError(path, message) { | ||
var e = new Error('precursors.update: ' + message + ' at path /' + | ||
var e = new Error('baobab.update: ' + message + ' at path /' + | ||
path.toString()); | ||
@@ -34,3 +34,3 @@ | ||
function update(target, spec, opts) { | ||
opts = opts || {}; | ||
opts = opts || {}; | ||
var log = {}; | ||
@@ -80,3 +80,9 @@ | ||
if ('$set' in (spec[k] || {})) { | ||
if ('$unset' in (spec[k] || {})) { | ||
// Logging update | ||
log[h] = true; | ||
delete o[k]; | ||
} | ||
else if ('$set' in (spec[k] || {})) { | ||
v = spec[k].$set; | ||
@@ -83,0 +89,0 @@ |
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
No README
QualityPackage does not have a README. This may indicate a failed publish or a low quality package.
Found 1 instance in 1 package
58563
14
1339
0
779
Updatedemmett@^2.1.2