{"id":22423347,"url":"https://github.com/prantlf/changed","last_synced_at":"2025-03-27T05:40:45.519Z","repository":{"id":57196898,"uuid":"115328349","full_name":"prantlf/changed","owner":"prantlf","description":"Library for updating JavaScript objects and arrays (directly) by string or array paths.","archived":false,"fork":false,"pushed_at":"2022-02-20T15:52:54.000Z","size":778,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-01T10:42:56.494Z","etag":null,"topics":["json-path","update"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/prantlf.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-12-25T10:08:57.000Z","updated_at":"2022-02-20T15:52:58.000Z","dependencies_parsed_at":"2022-09-16T00:10:31.209Z","dependency_job_id":null,"html_url":"https://github.com/prantlf/changed","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prantlf%2Fchanged","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prantlf%2Fchanged/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prantlf%2Fchanged/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prantlf%2Fchanged/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/prantlf","download_url":"https://codeload.github.com/prantlf/changed/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245791898,"owners_count":20672667,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["json-path","update"],"created_at":"2024-12-05T18:10:25.711Z","updated_at":"2025-03-27T05:40:45.497Z","avatar_url":"https://github.com/prantlf.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# changed\n\n[![NPM version](https://badge.fury.io/js/changed.js.png)](http://badge.fury.io/js/changed.js)\n[![Build Status](https://travis-ci.org/prantlf/changed.png)](https://travis-ci.org/prantlf/changed)\n[![dependencies Status](https://david-dm.org/prantlf/changed/status.svg)](https://david-dm.org/prantlf/changed)\n[![devDependencies Status](https://david-dm.org/prantlf/changed/dev-status.svg)](https://david-dm.org/prantlf/changed?type=dev)\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n\n[![NPM Downloads](https://nodei.co/npm/changed.js.png?downloads=true\u0026stars=true)](https://www.npmjs.com/package/changed.js)\n\nA 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.\n\nSupports 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.\n\n## Table of contents\n\n* [Motivation](#motivation)\n* [Installation](#installation)\n* [Usage](#usage)\n* [Methods](#methods)\n  * [has](#has)\n  * [get](#get)\n  * [set](#set)\n  * [remove](#remove)\n  * [add](#add)\n  * [merge](#merge)\n* [Development](#development)\n\n## Motivation\n\nObjects 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.\n\nThis 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.\n\n# Installation\n\nYou will need [node] version \u003e= 6 and [npm] to install and use this module:\n\n    npm install changed.js\n\nBrowser users will find non-minified and minified UMD-compliant scripts in the `dist` directory.\n\n## Usage\n\n```javascript\nimport {has, get, set, remove, add, merge} from 'changed';\n\nconst object = {\n  foo: 'foo',\n  bar: [\n    {\n      baz: 'quz'\n    }\n  ]\n};\n\n// handle standard properties\nconst foo = get('foo', object);\n\n// or nested properties\nconst baz = set('bar[0].baz', 'not quz', object);\n\n// all methods are curriable\nconst removeBaz = remove('bar[0].baz');\nconst sansBaz = removeBaz(object);\n```\n\nNOTE: There is no `default` export, so if you want to import all methods to a single namespace you should use the `import *` syntax:\n\n```javascript\nimport * as c from 'changed';\n```\n\n## Methods\n\n#### has\n\n`has(path: (Array\u003cnumber|string\u003e|number|string), object: (Array\u003cany\u003e|Object)): any`\n\nChecks if there is a property defined on the `object` passed and on the `path` specified.\n\n```javascript\nconst object = {\n  foo: [\n    {\n      bar: 'baz'\n    }\n  ]\n};\n\nconsole.log(get('foo[0].bar', object)); // baz\nconsole.log(get(['foo', 0, 'bar'], object)); // baz\n```\n\n#### get\n\n`get(path: (Array\u003cnumber|string\u003e|number|string), object: (Array\u003cany\u003e|Object)): any`\n\nGetter function for properties on the `object` passed and on the `path` specified.\n\n```javascript\nconst object = {\n  foo: [\n    {\n      bar: 'baz'\n    }\n  ]\n};\n\nconsole.log(get('foo[0].bar', object)); // baz\nconsole.log(get(['foo', 0, 'bar'], object)); // baz\n```\n\n#### set\n\n`set(path: (Array\u003cnumber|string\u003e|number|string), value: any, object: (Array\u003cany\u003e|object)): (Array\u003cany\u003e|Object)`\n\nReturns the `object` passed, with the `value` assigned to the final key on the `path` specified.\n\n```javascript\nconst object = {\n  foo: [\n    {\n      bar: 'baz'\n    }\n  ]\n};\n\nconsole.log(set('foo[0].bar', 'quz', object)); // {foo: [{bar: 'quz'}]}\nconsole.log(set(['foo', 0, 'bar'], 'quz', object)); // {foo: [{bar: 'quz'}]}\n```\n\n#### remove\n\n`remove(path: (Array\u003cnumber|string\u003e|number|string), object: (Array\u003cany\u003e|object)): (Array\u003cany\u003e|Object)`\n\nReturns a new clone of the `object` passed, with the final key on the `path` removed if it exists.\n\n```javascript\nconst object = {\n  foo: [\n    {\n      bar: 'baz'\n    }\n  ]\n};\n\nconsole.log(remove('foo[0].bar', object)); // {foo: [{}]}\nconsole.log(remove(['foo', 0, 'bar'], object)); // {foo: [{}]}\n```\n\n#### add\n\n`add(path: (Array\u003cnumber|string\u003e|number|string), value: any, object: (Array\u003cany\u003e|object)): (Array\u003cany\u003e|Object)`\n\nReturns 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`.\n\n```javascript\nconst object = {\n  foo: [\n    {\n      bar: 'baz'\n    }\n  ]\n};\n\n// object\nconsole.log(add('foo', 'added value' object)); // {foo: [{bar: 'baz'}, 'added value']}\nconsole.log(add(['foo'], 'added value', object)); // {foo: [{bar: 'baz'}, 'added value']}\n\n// array\nconsole.log(add('foo[0].quz', 'added value' object)); // {foo: [{bar: 'baz', quz: 'added value'}]}\nconsole.log(add(['foo', 0, 'quz'], 'added value', object)); // {foo: [{bar: 'baz', quz: 'added value'}]}\n```\n\nNotice 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.\n\nNOTE: If you want to add an item to a top-level array, pass `null` as the key:\n\n```javascript\nconst object = ['foo'];\n\nconsole.log(add(null, 'bar', object)); // ['foo', 'bar']\n```\n\n#### merge\n\n`merge(path: (Array\u003cnumber|string\u003e|number|string), value: any, object: (Array\u003cany\u003e|object)): (Array\u003cany\u003e|Object)`\n\nReturns the `object` passed, after performing a deep merge with the `value` (an object) at the `path` specified.\n\n```javascript\nconst object1 = {\n  oneSpecific: 'value',\n  object: {\n    one: 'value1',\n    two: 'value2'\n  }\n};\nconst object2 = {\n  one: 'new value',\n  three: 'value3'\n};\n\nconsole.log(merge('object', object2, object1)); // {oneSpecific: 'value', object: {one: 'new value', two: 'value1', three: 'value3'}}\n```\n\nNOTE: If you want to merge the entirety of both objects, pass `null` as the key:\n\n```javascript\nconst object1 = {\n  oneSpecific: 'value',\n  object: {\n    one: 'value1',\n    two: 'value2'\n  }\n};\nconst object2 = {\n  one: 'new value',\n  three: 'value3'\n};\n\nconsole.log(merge(null, object2, object1)); // {one: 'new value', oneSpecific: 'value', object: {one: 'value1', two: 'value1'}, three: 'value3'}\n```\n\n## Development\n\nStandard stuff, clone the repo and `npm install` dependencies. The npm scripts available:\n\n* `build` =\u003e run webpack to build development `dist` file with NODE_ENV=development\n* `build:minified` =\u003e run webpack to build production `dist` file with NODE_ENV=production\n* `dev` =\u003e run webpack dev server to run example app / playground\n* `dist` =\u003e runs `build` and `build-minified`\n* `lint` =\u003e run ESLint against all files in the `src` folder\n* `prepublish` =\u003e runs `compile-for-publish`\n* `prepublish:compile` =\u003e run `lint`, `test:coverage`, `transpile:es`, `transpile:lib`, `dist`\n* `test` =\u003e run AVA test functions with `NODE_ENV=test`\n* `test:coverage` =\u003e run `test` but with `nyc` for coverage checker\n* `test:watch` =\u003e run `test`, but with persistent watcher\n* `transpile:lib` =\u003e run babel against all files in `src` to create files in `lib`\n* `transpile:es` =\u003e run babel against all files in `src` to create files in `es`, preserving ES2015 modules (for\n  [`pkg.module`](https://github.com/rollup/rollup/wiki/pkg.module))\n\n## Contributing\n\nIn lieu of a formal style guide, take care to maintain the existing coding style.\n\n## License\n\nCopyright (c) 2017-2019 Ferdinand Prantl\n\n[node]: https://nodejs.org\n[npm]: https://npmjs.org\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprantlf%2Fchanged","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fprantlf%2Fchanged","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprantlf%2Fchanged/lists"}