Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

baobab

Package Overview
Dependencies
Maintainers
1
Versions
64
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

baobab - npm Package Compare versions

Comparing version 0.1.0 to 0.2.0

2

defaults.json
{
"autoCommit": true,
"asynchronous": true,
"clone": false,
"cloningFunction": null,
"cursorSingletons": true,
"delay": true,
"maxHistory": 0,

@@ -8,0 +8,0 @@ "typology": null,

@@ -11,3 +11,3 @@ /**

Object.defineProperty(Baobab, 'version', {
value: '0.1.0'
value: '0.2.0'
});

@@ -14,0 +14,0 @@

{
"name": "baobab",
"version": "0.1.0",
"version": "0.2.0",
"description": "JavaScript data tree with cursors.",

@@ -8,3 +8,3 @@ "main": "index.js",

"emmett": "^2.1.1",
"typology": "^0.2.1"
"typology": "^0.3.0"
},

@@ -15,2 +15,3 @@ "devDependencies": {

"gulp": "^3.8.10",
"gulp-header": "^1.2.2",
"gulp-jshint": "^1.9.0",

@@ -17,0 +18,0 @@ "gulp-mocha": "^2.0.0",

@@ -7,6 +7,49 @@ [![Build Status](https://travis-ci.org/Yomguithereal/baobab.svg)](https://travis-ci.org/Yomguithereal/baobab)

It is mainly inspired by functional zippers such as Clojure's [ones](http://clojuredocs.org/clojure.zip/zipper) and by [Om](https://github.com/swannodette/om)'s cursors.
It is mainly inspired by functional [zippers](http://clojuredocs.org/clojure.zip/zipper) such as Clojure's ones and by [Om](https://github.com/swannodette/om)'s cursors.
It can be paired with React easily through mixins to provide a centralized model holding your application's state.
It can be paired with **React** easily through [mixins](#react-mixins) to provide a centralized model holding your application's state.
## Summary
* [Example](#example)
* [Installation](#installation)
* [Usage](#usage)
* [Basics](#basics)
* [Instantiation](#instantiation)
* [Cursors](#cursors)
* [Updates](#updates)
* [Events](#events)
* [React mixins](#react-mixins)
* [Advanced](#advanced)
* [Polymorphisms](#polymorphisms)
* [Traversal](#traversal)
* [Options](#options)
* [History](#history)
* [Update specifications](#update-specifications)
* [Chaining mutations](#chaining-mutations)
* [Data validation](#data-validation)
* [Contribution](#contribution)
* [License](#license)
## Example
```js
var Baobab = require('baobab');
var tree = new Baobab({
palette: {
colors: ['yellow', 'purple'],
name: 'Glorious colors'
}
});
var colorsCursor = tree.select('palette', 'colors');
colorsCursor.on('update', function() {
console.log('Selected colors have updated:', colorsCursor.get());
});
colorsCursor.push('orange');
```
## Installation

@@ -31,17 +74,2 @@

* [Basics](#basics)
* [Instantiation](#instantiation)
* [Cursors](#cursors)
* [Updates](#updates)
* [Events](#events)
* [React mixins](#react-mixins)
* [Advanced](#advanced)
* [Polymorphisms](#polymorphisms)
* [Traversal](#traversal)
* [Options](#options)
* [History](#history)
* [Update specifications](#update-specifications)
* [Chaining mutations](#chaining-mutations)
* [Data validation](#data-validation)
### Basics

@@ -116,3 +144,3 @@

```js
cursor.set({hello: 'world'});
cursor.edit({hello: 'world'});
```

@@ -154,3 +182,3 @@

Whenever an update is committed, events are fired to notify relevant parts of the tree that data was changed so that bound element, React components, for instance, can update.
Whenever an update is committed, events are fired to notify relevant parts of the tree that data was changed so that bound elements, React components, for instance, can update.

@@ -183,11 +211,5 @@ Note however that only relevant cursors will be notified of data change.

// If we update the users
usersCursor.update({
john: {
firstname: {$set: 'John the third'}
},
jack: {
firstname: {$set: 'Jack the second'}
}
});
// If we update both users
johnCursor.set('firstname', 'John the third');
jackCursor.set('firstname', 'Jack the second');
// Every cursor above will be notified of the update

@@ -197,3 +219,3 @@

johnCursor.set('firstname', 'John the third');
// Only the users and john cursor will be notified
// Only the users and john cursors will be notified
```

@@ -213,3 +235,3 @@

Will fire if a data-validation specification was passed at instance and if new data does not abide by those specifications.
Will fire if a data-validation specification was passed at instance and if new data does not abide by those specifications. For more information about this, see the [data validation](#data-validation) part of the documentation.

@@ -254,3 +276,3 @@ ```js

It is therefore really simple to bind this centralized model to React components by using the library's built-in mixins. Those will naturally bind components to one or more cursors watching over parts of the main state so they can update only when relevant data has been changed.
It is then really simple to bind this centralized model to React components by using the library's built-in mixins. Those will naturally bind components to one or more cursors watching over parts of the main state so they can update only when relevant data has been changed.

@@ -390,6 +412,8 @@ This basically makes the `shouldComponentUpdate` method useless in most of cases and ensures that your components will only re-render if they need to because of data changes.

var tree = new Baobab({
list: [[1, 2], [3, 4]]
list: [[1, 2], [3, 4]],
longList: ['one', 'two', 'three', 'four']
});
var listCursor = tree.select('list');
var listCursor = tree.select('list'),
twoCursor = tree.select('longList', 1);

@@ -401,2 +425,8 @@ listCursor.down().right().get();

>>> 3
twoCursor.leftmost().get();
>>> 'one'
twoCursor.rightmost().get();
>>> 'four'
```

@@ -428,7 +458,7 @@

* **autoCommit** *boolean* [`true`]: should the tree auto commit updates or should it let the user do so through the `commit` method?
* **clone** *boolean* [`false`]: by default, the tree will give access to references. Set to `true` to clone data when retrieving it from the tree.
* **asynchronous** *boolean* [`true`]: should the tree delay the update to the next frame or fire them synchronously?
* **clone** *boolean* [`false`]: by default, the tree will give access to references. Set to `true` to clone data when retrieving it from the tree if you feel paranoid and know you might mutate the references by accident or need a cloned object to handle.
* **cloningFunction** *function*: the library's cloning method is minimalist on purpose and won't cover edgy cases. You remain free to pass your own more complex cloning function to the tree if needed.
* **cursorSingletons** *boolean* [`true`]: by default, a *baobab* tree stashes the created cursor so only one would be created by path. You can override this behaviour by setting `cursorSingletons` to `false`.
* **delay** *boolean* [`true`]: should the tree delay the update to next frame or fire them synchronously?
* **maxHistory** *number* [`0`]: max number of records the tree is allowed to keep in its history.
* **maxHistory** *number* [`0`]: max number of records the tree is allowed to store within its internal history.
* **typology** *Typology|object*: a custom typology to be used to validate the tree's data.

@@ -439,3 +469,3 @@ * **validate** *object*: a [typology](https://github.com/jacomyal/typology) schema ensuring the tree's data is valid.

A *baobab* tree, given you pass it correct options, is able to record *n* of its passed states so you can go back in time whenever you want.
A *baobab* tree, given you instantiate it with the correct option, is able to record *n* of its passed states so you can go back in time whenever you want.

@@ -457,2 +487,13 @@ *Example*

*Related Methods*
```js
// Check whether our tree hold records
baobab.hasHistory();
>>> true
// Retrieving history records
baobab.getHistory();
```
#### Update specifications

@@ -539,4 +580,43 @@

WIP
Given you pass the correct parameters, a baobab tree is able to check whether its data is valid or not against the supplied specification.
This specification must be written in the [typology](https://github.com/jacomyal/typology) library's style.
*Example*
```js
var baobab = new Baobab(
// Initial state
{
hello: 'world',
colors: ['yellow', 'blue'],
counters: {
users: 3,
groups: 1
}
},
// Parameters
{
validate: {
hello: '?string',
colors: ['string'],
counters: {
users: 'number',
groups: 'number'
}
}
}
);
// If one updates the tree and does not respect the validation specification
baobab.set('hello', 42);
// Then the tree will fire an 'invalid' event containing a list of errors
baobab.on('invalid', function(e) {
console.log(e.data.errors);
});
```
## Contribution

@@ -543,0 +623,0 @@

@@ -5,3 +5,3 @@ /**

*
* Encloses an immutable set of data exposing useful cursors to its user.
* A handy data tree with cursors.
*/

@@ -37,5 +37,2 @@ var Cursor = require('./cursor.js'),

// Properties
this.data = this._cloner(initialData);
// Privates

@@ -57,5 +54,14 @@ this._futureUpdate = {};

if (!this.check())
throw Error('Baobab: instantiating with invalid data');
if (this.validate)
try {
this.typology.check(initialData, this.validate, true);
}
catch (e) {
e.message = '/' + e.path.join('/') + ': ' + e.message;
throw e;
}
// Properties
this.data = this._cloner(initialData);
// Mixin

@@ -83,3 +89,3 @@ this.mixin = mixins.baobab(this);

// Should we update synchronously?
if (!this.options.delay)
if (!this.options.asynchronous)
return this.commit();

@@ -118,8 +124,2 @@

*/
Baobab.prototype.check = function() {
return this.validate ?
this.typology.check(this.data, this.validate) :
true;
};
Baobab.prototype.commit = function(referenceRecord) {

@@ -145,5 +145,27 @@ var self = this,

if (!this.check())
this.emit('invalid');
if (this.validate) {
var errors = [],
l = log.length,
d,
i;
for (i = 0; i < l; i++) {
d = helpers.getIn(this.validate, log[i]);
if (!d)
continue;
try {
this.typology.check(this.get(log[i]), d, true);
}
catch (e) {
e.path = log[i].concat((e.path || []));
errors.push(e);
}
}
if (errors.length)
this.emit('invalid', {errors: errors});
}
// Baobab-level update event

@@ -150,0 +172,0 @@ this.emit('update', {

@@ -122,2 +122,11 @@ /**

Cursor.prototype.leftmost = function() {
var last = +this.path[this.path.length - 1];
if (isNaN(last))
throw Error('baobab.Cursor.leftmost: cannot go left on a non-list type.');
return this.root.select(this.path.slice(0, -1).concat(0));
};
Cursor.prototype.right = function() {

@@ -132,2 +141,13 @@ var last = +this.path[this.path.length - 1];

Cursor.prototype.rightmost = function() {
var last = +this.path[this.path.length - 1];
if (isNaN(last))
throw Error('baobab.Cursor.right: cannot go right on a non-list type.');
var list = this.up().reference();
return this.root.select(this.path.slice(0, -1).concat(list.length - 1));
};
Cursor.prototype.down = function() {

@@ -173,12 +193,14 @@ var last = +this.path[this.path.length - 1];

Cursor.prototype.set = function(key, value) {
if (arguments.length < 2) {
return this.update({$set: key});
}
else {
var spec = {};
spec[key] = {$set: value};
return this.update(spec);
}
if (arguments.length < 2)
throw Error('baobab.Cursor.set: expecting at least key/value.');
var spec = {};
spec[key] = {$set: value};
return this.update(spec);
};
Cursor.prototype.edit = function(value) {
return this.update({$set: value});
};
Cursor.prototype.apply = function(fn) {

@@ -199,3 +221,7 @@ if (typeof fn !== 'function')

// TODO: consider dropping the ahead testing
Cursor.prototype.push = function(value) {
if (!(this.reference() instanceof Array))
throw Error('baobab.Cursor.push: trying to push to non-array value.');
if (arguments.length > 1)

@@ -208,2 +234,5 @@ return this.update({$push: helpers.arrayOf(arguments)});

Cursor.prototype.unshift = function(value) {
if (!(this.reference() instanceof Array))
throw Error('baobab.Cursor.push: trying to push to non-array value.');
if (arguments.length > 1)

@@ -210,0 +239,0 @@ return this.update({$unshift: helpers.arrayOf(arguments)});

@@ -22,4 +22,4 @@ /**

function makeError(path, message) {
var e = new Error('precursors.update: ' + message + ' at path "/' +
path.toString() + '"');
var e = new Error('precursors.update: ' + message + ' at path /' +
path.toString());

@@ -26,0 +26,0 @@ e.path = path;

SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc