@nfd/model

0.3.0 • Public • Published

model

Installation · Usage

import model from '@nfd/model'

const vivian = model({name: 'Vivian', job: 'Software Engineer', age: 23})

vivian.on('change', console.log)

++vivian.age
/* { target: vivian,
     name: 'age',
     value: 24,
     oldValue: 23 } */

vivian.favoriteColor = 'blue'
/* { target: vivian,
     name: 'favoriteColor',
     value: 'blue',
     oldValue: undefined } */

Object.defineProperty(vivian, 'favoriteBook', {
  value: 'The Sun Also Rises',
  configurable: true,
  writable: true,
})
/* { target: vivian,
     name: 'favoriteBook',
     value: 'The Sun Also Rises',
     oldValue: undefined } */

vivian.on('favoriteBookChange', e =>
  console.log(`Favorite book was: ${e.oldValue}`))

delete vivian.favoriteBook
/* Favorite book was: The Sun Also Rises */
/* { target: vivian,
     name: 'favoriteBook',
     value: undefined,
     oldValue: 'The Sun Also Rises' } */

Installation

$ npm i @nfd/model

Usage

model(…) · class extends model { … } · new model · model.is(…) · model.deep(…) · model.tree(…) · model.fullTree(…)

model([object = {}[, {deep = false, tree = false, fullTree = false}]])

Returns a proxy for object which emits events when its properties are created, deleted, or changed. Each change emits a change event and a nameChange event, both with event object {target, name, value, oldValue}, where:

  • target is the model proxy;
  • name is the property name;
  • value is the new property value; and
  • oldValue is the previous property value.
const kate = model({name: 'Kate', age: 31})
kate.on('change', console.log)
++kate.age
/* { target: kate, name: 'age', value: 32, oldValue: 31 } */

Arrays — in addition to the normal change and nameChange events, models based on Arrays emit splice events describing high-level structural changes to their contents. Each event object comprises {target, index, removed, added}, where:

  • target is the model proxy;
  • index is the index of the first removed or added element;
  • removed is an array of the removed elements; and
  • added is the number of elements added in their place.
const fruits = model([])
fruits.on('splice', console.log)

fruits.push('apple', 'pear', 'mango', 'banana', 'kiwi')
/* { target: fruits, index: 0, removed: [], added: 3 } */

fruits.shift()
/* { target: fruits, index: 0, removed: ['apple'], added: 0 } */

fruits.splice(1, 2, 'guava')
/* { target: fruits, index: 1, removed: [ 'mango', 'banana' ], added: 1 } */

fruits[0] = 'orange'
/* { target: fruits, index: 0, removed: [ 'pear' ], added: 1 } */

fruits.length = 0
/* { target: fruits, index: 0, removed: [ 'orange', 'guava', 'kiwi' ], added: 0 } */

deep or model.deep(…) — if true, all properties with object values will be automatically coerced on creation and assignment to model proxies.

const olivia = model({
  name: 'Olivia',
  favoriteBook: {title: 'Anna Karenina', author: 'Leo Tolstoy'},
})
olivia.favoriteBook = {title: 'The Grapes of Wrath', author: 'John Steinbeck'}
olivia.favoriteBook.on('change', console.log)

olivia.favoriteBook.year = 1939
/* { target: olivia.favoriteBook,
     name: 'year',
     value: 1939,
     oldValue: undefined }

tree or model.tree(…) (implies deep) — if true, the root model proxy will emit mutate events for all mutations to itself and its subtree. Each event object comprises {target, localTarget, path, name, value, oldValue}, where:

  • target is the root model proxy;
  • localTarget is the subtree proxy whose property changed;
  • path is the key path from the root to the changed property, with keys separated by .s;
  • names is the list of property names in path;
  • depth is number of intermediate objects in the path, starting at 0 for direct mutations to the root;
  • name is the property name;
  • value is the new property value; and
  • oldValue is the previous property value.
const olivia = model({
  name: 'Olivia',
  favoriteColor: 'blue',
  favoriteBook: {title: 'The Sun Also Rises', authors: [{name: 'Ernest Hemingway'}]},
}, {tree: true})

olivia.on('mutate', console.log)

olivia.favoriteColor = 'red'
/* { target: olivia,
     localTarget: olivia,
     path: 'favoriteColor',
     names: ['favoriteColor'],
     depth: 0,
     name: 'favoriteColor',
     value: 'red',
     oldValue: 'blue' } */

olivia.favoriteBook.authors[0].born = 1899
/* { target: olivia,
     localTarget: olivia.favoriteBook.authors[0],
     path: 'favoriteBook.authors.0.born',
     names: ['favoriteBook', 'authors', '0', 'born'],
     depth: 3,
     name: 'born',
     value: 1899,
     oldValue: undefined } */

fullTree or model.fullTree(…) (implies deep and tree) — if true, in addition to the root object, all subtree model proxies will also emit mutate events for mutations to themselves and their respective subtrees.

const olivia = model({
  name: 'Olivia',
  favoriteColor: 'blue',
  favoriteBook: {title: 'The Sun Also Rises', authors: [{name: 'Ernest Hemingway'}]},
}, {fullTree: true})

olivia.favoriteBook.on('mutate', console.log)

olivia.favoriteBook.authors[0].born = 1899
/* { target: olivia.favoriteBook,
     localTarget: olivia.favoriteBook.authors[0],
     path: 'authors.0.born',
     names: ['authors', '0', 'born'],
     depth: 2,
     name: 'born',
     value: 1899,
     oldValue: undefined } */

class extends model { … }

The model function can also be used as a base class.

class Person extends model {/* … */}
const kate = new Person('Kate', 31)
kate.on('change', console.log)
++kate.age
/* { target: kate, name: 'age', value: 32, oldValue: 31 } */

new model

Constructs a new, empty model.

const kate = new model
kate.on('change', console.log)
kate.name = 'Kate'
/* { target: kate, name: 'name', value: 'Kate', oldValue: undefined } */
kate.age = 31
/* { target: kate, name: 'age', value: 31, oldValue: undefined } */

model.is(object)

Returns true if object is a model proxy.

model.is({name: 'Kate', age: 31}) /* false */
model.is(model({name: 'Kate', age: 31})) /* true */
model.is(model([])) /* true */

const fruits = model([{fruit: 'kiwi', quantity: 3}])
models.is(fruits[0]) /* false */

const fruits = model([{fruit: 'kiwi', quantity: 3}], {deep: true})
model.is(fruits[0]) /* true */

model.deep

Alias function for model(object, {deep: true}). Can be used:

  • As a function: model.deep([object = {}])
  • As a base class: class extends model.deep {…}
  • As a constructor: new model.deep

model.tree

Alias function for model(object, {tree: true}). Can be used:

  • As a function: model.tree([object = {}])
  • As a base class: class extends model.tree {…}
  • As a constructor: new model.tree

model.fullTree

Alias function for model(object, {fullTree: true}). Can be used:

  • As a function: model.fullTree([object = {}])
  • As a base class: class extends model.fullTree {…}
  • As a constructor: new model.fullTree

Package Sidebar

Install

npm i @nfd/model

Weekly Downloads

0

Version

0.3.0

License

MIT

Unpacked Size

20.3 kB

Total Files

4

Last publish

Collaborators

  • nfd