https://github.com/prantlf/changed
Library for updating JavaScript objects and arrays (directly) by string or array paths.
https://github.com/prantlf/changed
json-path update
Last synced: about 1 year ago
JSON representation
Library for updating JavaScript objects and arrays (directly) by string or array paths.
- Host: GitHub
- URL: https://github.com/prantlf/changed
- Owner: prantlf
- License: mit
- Created: 2017-12-25T10:08:57.000Z (over 8 years ago)
- Default Branch: master
- Last Pushed: 2022-02-20T15:52:54.000Z (over 4 years ago)
- Last Synced: 2025-02-01T10:42:56.494Z (over 1 year ago)
- Topics: json-path, update
- Language: JavaScript
- Homepage:
- Size: 760 KB
- Stars: 1
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# changed
[](http://badge.fury.io/js/changed.js)
[](https://travis-ci.org/prantlf/changed)
[](https://david-dm.org/prantlf/changed)
[](https://david-dm.org/prantlf/changed?type=dev)
[](https://github.com/semantic-release/semantic-release)
[](https://www.npmjs.com/package/changed.js)
A tiny (~1.5kb minified+gzipped) and [fast](https://github.com/prantlf/changed/blob/master/benchmark_results.csv), library for updating JavaScript objects and arrays directly.
Supports nested key paths via path arrays or [dot-bracket syntax](https://github.com/planttheidea/pathington), and all methods are curriable (with placeholder support) for composability. Can support typical changes of view-model attributes by methods `has`, `get`, `set`, `remove`, `add` and `merge` with a small footprint.
## Table of contents
* [Motivation](#motivation)
* [Installation](#installation)
* [Usage](#usage)
* [Methods](#methods)
* [has](#has)
* [get](#get)
* [set](#set)
* [remove](#remove)
* [add](#add)
* [merge](#merge)
* [Development](#development)
## Motivation
Objects with nested properties and arrays are used to store application state. Libraries like [Backbone](backbonejs.org) provide functions for inspecting and manipulating the state as methods of specialized objects like [`Backbone.Model`](http://backbonejs.org/#Model). This library provides only such methods without having to include the rest of the functionality of a bigger library. You can use other libraries to make your application complete; for example [*on-change*](https://github.com/prantlf/on-change) for property change notifications.
This library has been inspired by [*unchanged*](https://github.com/planttheidea/unchanged), which has been used for the initial design and imnplementation. On the contrary to the immutable *unchanged*, this library supports mutable application states.
# Installation
You will need [node] version >= 6 and [npm] to install and use this module:
npm install changed.js
Browser users will find non-minified and minified UMD-compliant scripts in the `dist` directory.
## Usage
```javascript
import {has, get, set, remove, add, merge} from 'changed';
const object = {
foo: 'foo',
bar: [
{
baz: 'quz'
}
]
};
// handle standard properties
const foo = get('foo', object);
// or nested properties
const baz = set('bar[0].baz', 'not quz', object);
// all methods are curriable
const removeBaz = remove('bar[0].baz');
const sansBaz = removeBaz(object);
```
NOTE: There is no `default` export, so if you want to import all methods to a single namespace you should use the `import *` syntax:
```javascript
import * as c from 'changed';
```
## Methods
#### has
`has(path: (Array|number|string), object: (Array|Object)): any`
Checks if there is a property defined on the `object` passed and on the `path` specified.
```javascript
const object = {
foo: [
{
bar: 'baz'
}
]
};
console.log(get('foo[0].bar', object)); // baz
console.log(get(['foo', 0, 'bar'], object)); // baz
```
#### get
`get(path: (Array|number|string), object: (Array|Object)): any`
Getter function for properties on the `object` passed and on the `path` specified.
```javascript
const object = {
foo: [
{
bar: 'baz'
}
]
};
console.log(get('foo[0].bar', object)); // baz
console.log(get(['foo', 0, 'bar'], object)); // baz
```
#### set
`set(path: (Array|number|string), value: any, object: (Array|object)): (Array|Object)`
Returns the `object` passed, with the `value` assigned to the final key on the `path` specified.
```javascript
const object = {
foo: [
{
bar: 'baz'
}
]
};
console.log(set('foo[0].bar', 'quz', object)); // {foo: [{bar: 'quz'}]}
console.log(set(['foo', 0, 'bar'], 'quz', object)); // {foo: [{bar: 'quz'}]}
```
#### remove
`remove(path: (Array|number|string), object: (Array|object)): (Array|Object)`
Returns a new clone of the `object` passed, with the final key on the `path` removed if it exists.
```javascript
const object = {
foo: [
{
bar: 'baz'
}
]
};
console.log(remove('foo[0].bar', object)); // {foo: [{}]}
console.log(remove(['foo', 0, 'bar'], object)); // {foo: [{}]}
```
#### add
`add(path: (Array|number|string), value: any, object: (Array|object)): (Array|Object)`
Returns the `object` passed, with the `value` added at the `path` specified. This can have different behavior depending on whether the item is an `Object` or an `Array`.
```javascript
const object = {
foo: [
{
bar: 'baz'
}
]
};
// object
console.log(add('foo', 'added value' object)); // {foo: [{bar: 'baz'}, 'added value']}
console.log(add(['foo'], 'added value', object)); // {foo: [{bar: 'baz'}, 'added value']}
// array
console.log(add('foo[0].quz', 'added value' object)); // {foo: [{bar: 'baz', quz: 'added value'}]}
console.log(add(['foo', 0, 'quz'], 'added value', object)); // {foo: [{bar: 'baz', quz: 'added value'}]}
```
Notice that the `Object` usage is idential to the `set` method, where a key needs to be specified for assignment. In the case of an `Array`, however, the value is pushed to the array at that key.
NOTE: If you want to add an item to a top-level array, pass `null` as the key:
```javascript
const object = ['foo'];
console.log(add(null, 'bar', object)); // ['foo', 'bar']
```
#### merge
`merge(path: (Array|number|string), value: any, object: (Array|object)): (Array|Object)`
Returns the `object` passed, after performing a deep merge with the `value` (an object) at the `path` specified.
```javascript
const object1 = {
oneSpecific: 'value',
object: {
one: 'value1',
two: 'value2'
}
};
const object2 = {
one: 'new value',
three: 'value3'
};
console.log(merge('object', object2, object1)); // {oneSpecific: 'value', object: {one: 'new value', two: 'value1', three: 'value3'}}
```
NOTE: If you want to merge the entirety of both objects, pass `null` as the key:
```javascript
const object1 = {
oneSpecific: 'value',
object: {
one: 'value1',
two: 'value2'
}
};
const object2 = {
one: 'new value',
three: 'value3'
};
console.log(merge(null, object2, object1)); // {one: 'new value', oneSpecific: 'value', object: {one: 'value1', two: 'value1'}, three: 'value3'}
```
## Development
Standard stuff, clone the repo and `npm install` dependencies. The npm scripts available:
* `build` => run webpack to build development `dist` file with NODE_ENV=development
* `build:minified` => run webpack to build production `dist` file with NODE_ENV=production
* `dev` => run webpack dev server to run example app / playground
* `dist` => runs `build` and `build-minified`
* `lint` => run ESLint against all files in the `src` folder
* `prepublish` => runs `compile-for-publish`
* `prepublish:compile` => run `lint`, `test:coverage`, `transpile:es`, `transpile:lib`, `dist`
* `test` => run AVA test functions with `NODE_ENV=test`
* `test:coverage` => run `test` but with `nyc` for coverage checker
* `test:watch` => run `test`, but with persistent watcher
* `transpile:lib` => run babel against all files in `src` to create files in `lib`
* `transpile:es` => run babel against all files in `src` to create files in `es`, preserving ES2015 modules (for
[`pkg.module`](https://github.com/rollup/rollup/wiki/pkg.module))
## Contributing
In lieu of a formal style guide, take care to maintain the existing coding style.
## License
Copyright (c) 2017-2019 Ferdinand Prantl
[node]: https://nodejs.org
[npm]: https://npmjs.org