{"id":18563118,"url":"https://github.com/compulim/simple-update-in","last_synced_at":"2025-04-10T03:32:34.320Z","repository":{"id":38184837,"uuid":"125946789","full_name":"compulim/simple-update-in","owner":"compulim","description":"Immutable update-in with zero dependencies","archived":false,"fork":false,"pushed_at":"2023-01-06T01:32:49.000Z","size":1015,"stargazers_count":3,"open_issues_count":13,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-18T13:53:37.665Z","etag":null,"topics":[],"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/compulim.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":"2018-03-20T02:06:17.000Z","updated_at":"2020-05-26T07:50:46.000Z","dependencies_parsed_at":"2023-02-05T01:32:40.180Z","dependency_job_id":null,"html_url":"https://github.com/compulim/simple-update-in","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/compulim%2Fsimple-update-in","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/compulim%2Fsimple-update-in/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/compulim%2Fsimple-update-in/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/compulim%2Fsimple-update-in/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/compulim","download_url":"https://codeload.github.com/compulim/simple-update-in/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248151329,"owners_count":21056071,"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":[],"created_at":"2024-11-06T22:11:51.644Z","updated_at":"2025-04-10T03:32:31.774Z","avatar_url":"https://github.com/compulim.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# simple-update-in\n\nA lightweight `updateIn` for immutable objects.\n\n[![npm version](https://badge.fury.io/js/simple-update-in.svg)](https://badge.fury.io/js/simple-update-in) [![Build Status](https://travis-ci.org/compulim/simple-update-in.svg?branch=master)](https://travis-ci.org/compulim/simple-update-in) [![Coverage Status](https://coveralls.io/repos/github/compulim/simple-update-in/badge.svg?branch=feat-coveralls)](https://coveralls.io/github/compulim/simple-update-in?branch=feat-coveralls)\n\nWe love [ImmutableJS](https://facebook.github.io/immutable-js). But sometimes, we want to start something from small. Thus, we created this package with zero dependencies.\n\nUnder the [cover](src/index.js), we use Rest Operator to do most of the heavylifting.\n\n# Install\n\nFor latest stable, run `npm install simple-update-in`.\n\nFor active development (`master` branch), run `npm install simple-update-in@master`.\n\n# How to use\n\nFor example, `obj.one.two = 1.2`, call `updateIn(obj, ['one', 'two'], () =\u003e 1.2)`. It will return a new object with changes in deep clone.\n\nWe share similar signature as [ImmutableJS.updateIn](https://facebook.github.io/immutable-js/docs/#/Map/updateIn):\n\n```js\nupdateIn\u003cT: Array|Map\u003e(\n  target: T,\n  path: (\n    Number|\n    String\n  )[],\n  updater?: (value: any) =\u003e any\n): T\n```\n\nOr the asynchronous version, which you can provide an asynchronous predicate or updater:\n\n```js\nupdateInAsync\u003cT: Array|Map\u003e(\n  target: T,\n  path: (\n    Number|\n    String|\n    (key: (Number|String), value: any) =\u003e Promise\u003cBoolean\u003e|Boolean\n  )[],\n  updater?: (value: any) =\u003e Promise\u003cany\u003e|any\n): Promise\u003cT\u003e\n```\n\nTo make `updateIn` efficient, especially, when paired with React. It will return a mixed deep/shallow clone of the `target`. It only deep clone on objects that it modified along the `path`, and shallow clone objects that it did not modify.\n\nLike other immutable framework, `updater` is expected to return a new object if there is a change. If the update do not result in a change (via [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is)), then, the original object is returned.\n\n\u003e Polyfill for `Object.is` is adopted from [`core-js`](https://npmjs.com/package/core-js) to maintain zero dependency.\n\n### Browser only\n\nYou can also use in the browser via unpkg.com:\n\n```html\n\u003cscript src=\"https://unpkg.com/simple-update-in/dist/simple-update-in.production.min.js\"\u003e\u003c/script\u003e\n\u003cscript\u003e\n  window.simpleUpdateIn({ abc: 123, def: 456 }, ['xyz'], () =\u003e 789);\n\u003c/script\u003e\n```\n\n## Example\n\nJust like ImmutableJS, we want to make both `Array` and `Map` a first-class citizen. To work on a map, use a `string` as key. For arrays, use a `number` as key.\n\n### Map\n\n```js\nimport updateIn from 'simple-update-in';\n\nconst from = { one: 1, two: { number: 2 }, thirty: 3 };\nconst actual = updateIn(from, ['thirty'], three =\u003e three * 10);\n\nexpect(actual).toEqual({ one: 1, two: { number: 2 }, thirty: 30 });\n\nexpect(actual).not.toBe(from);   // Something under this tree has changed\nexpect(actual.two).toBe(to.two); // Nothing under this tree has changed\nexpect(actual.thirty).toBe(30);  // We multiplied it by 10\n```\n\n\u003e This is in fact an \"upsert\" operation.\n\n\u003e Note: for security reason, we will skip paths containing `__proto__`, `constructor`, `prototype`. This includes [predicate paths](#using-predicate).\n\n### Array in map\n\n```js\nconst from = { one: [1.1, 1.2, 1.3], two: [2] };\nconst actual = updateIn(from, ['one', 1], value =\u003e 'one point two');\n\nexpect(actual).toEqual({ one: [1.1, 'one point two', 1.3], two: [2] });\n```\n\n## Remove a key\n\nYou can also use `updateIn` to remove a key by passing a falsy value to the `updater` argument, or return `undefined`.\n\n```js\nconst from = { one: 1, two: 2 };\nconst actual = updateIn(from, ['two']);\n\nexpect(actual).toEqual({ one: 1 });\n\nexpect(actual).not.toBe(from);\nexpect(actual).not.toHaveProperty('two');\n```\n\n\u003e When removing a non-existing key, the original object will be returned.\n\nThe sample code above also works with `updater` returning `undefined`, for example, `updateIn(from, ['two'], () =\u003e undefined)`.\n\n## Remove an item in array\n\n```js\nconst from = ['zero', 'one', 'two'];\nconst actual = updateIn(from, [1]);\n\nexpect(actual).toEqual(['zero', 'two']);\n```\n\n\u003e Also for `updater` returning `undefined`\n\n## Asynchronous update\n\nYou can also use an asynchronous updater to update the content. Instead of using the exported `default` function, you will need to use the `updateInAsync` function instead.\n\n```js\nimport { updateInAsync } from 'simple-update-in';\n\nconst from = { one: [1.1, 1.2, 1.3], two: [2] };\nconst actual = await updateInAsync(from, ['one', 1], value =\u003e Promise.resolve('one point two'));\n\nexpect(actual).toEqual({ one: [1.1, 'one point two', 1.3], two: [2] });\n```\n\n## Automatic expansion\n\n```js\nconst from = {};\nconst actual = updateIn(from, ['one', 'two'], 1.2);\n\nexpect(actual).toEqual({ one: { two: 1.2 } });\n```\n\n\u003e If the `updater` return `undefined`, the object will be untouched.\n\n## Replace incompatible types\n\nIf incompatible types is found along the walk, they will be replaced. For example, in the following example, an `Array` is replaced by a `Map`.\n\n```js\nconst from = [0, 1, 2];\nconst actual = updateIn(from, ['one'], 1);\n\nexpect(actual).toEqual({ one: 1 });\n```\n\n\u003e In the path, `'one'` is a string, it implies that user want a `Map` instead of `Array`\n\nIt will also replace `number` with `Map`.\n\n```js\nconst from = { one: 1 };\nconst actual = updateIn(from, ['one', 'two'], 1.2);\n\nexpect(actual).toEqual({ one: { two: 1.2 } });\n```\n\n### Corner case\n\nIf the target value is of incompatible type, we will convert it to correct type before setting it. In the following sample, the actual value is an empty map instead of the original array.\n\n```js\nconst from = [0, 1, 2];\nconst actual = updateIn(from, ['one']);\n\nexpect(actual).toEqual({});\n```\n\n## ~~Adding an item to array~~\n\nThis feature has been removed due to inconformity of the API. `-1` could means append, prepend, or it could means last value (item at `length - 1`).\n\nFor append, you can use the following code\n\n```js\nconst from = [0, 1];\nconst actual = updateIn(from, [], array =\u003e [...array, 2]);\n\nexpect(actual).toEqual([0, 1, 2]);\n```\n\n### Removed documentation\n\nYou can use special index value `-1` to indicate an append to the array.\n\n```js\nconst from = [0, 1];\nconst actual = updateIn(from, [-1], () =\u003e 2);\n\nexpect(actual).toEqual([0, 1, 2]);\n```\n\n\u003e If `updater` returned `undefined`, the value will not be appended.\n\nThere is no support on prepend or insertion, however, you can use Rest Operator for array manipulation.\n\n```js\nconst from = { numbers: ['one', 'two'] };\nconst actual = updateIn(from, ['numbers'], array =\u003e ['zero', ...array]);\n\nexpect(actual).toEqual({ numbers: ['zero', 'one', 'two'] });\n```\n\n## Using predicate\n\nFor path accessor, instead of `number` and `string`, you can also use `function`.\n\nPredicate for array has signature of `(value, index) =\u003e truthy/falsy`. And for map, `(value, key) =\u003e truthy/falsy`.\n\n```js\nconst from = [1, 2, 3, 4, 5];\nconst actual = updateIn(from, [value =\u003e value % 2], value =\u003e value * 10);\n\nexpect(actual).toEqual([10, 2, 30, 4, 50]);\n```\n\n### Branching with predicate\n\nYou can also use predicate to update multiple subsets at the same time.\n\n```js\nconst from = [{ v: 1 }, { v: 2 }, { v: 3 }];\nconst actual = updateIn(from, [() =\u003e true, 'v'], v =\u003e v * 10);\n\nexpect(actual).toEqual([{ v: 10 }, { v: 20 }, { v: 30 }]);\n```\n\n### Non-existing key/index with predicate\n\nSince it is impossible to guess if the predicate is performing on an array or map. [automatic expansion](#automatic-expansion) will not be performed if the key/index does not exists. Nevertheless, even we expand it into an empty array or map, it will not be enumerated thru the predicate since the new item is empty. Thus, nothing will change.\n\n```js\nconst from = {};\nconst actual = updateIn(from, ['Hello', () =\u003e true], () =\u003e 'World!']);\n\nexpect(actual).toBe(from);\n```\n\n```js\nconst from = [];\nconst actual = updateIn(from, [0, () =\u003e true], () =\u003e 'Aloha']);\n\nexpect(actual).toBe(from);\n```\n\n### Asynchronous predicate\n\nYou can also use asynchronous predicate. Instead of using the exported `default` function, you will need to use the `updateInAsync` function instead.\n\n```js\nimport { updateInAsync } from 'simple-update-in';\n\nconst from = [1, 2, 3, 4, 5];\nconst actual = await updateInAsync(from, [value =\u003e Promise.resolve(value % 2)], value =\u003e value * 10);\n\nexpect(actual).toEqual([10, 2, 30, 4, 50]);\n```\n\n# Contributions\n\nLike us? [Star](https://github.com/compulim/simple-update-in/stargazers) us.\n\nWant to make it better? [File](https://github.com/compulim/simple-update-in/issues) us an issue.\n\nDon't like something you see? [Submit](https://github.com/compulim/simple-update-in/pulls) a pull request.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcompulim%2Fsimple-update-in","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcompulim%2Fsimple-update-in","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcompulim%2Fsimple-update-in/lists"}