{"id":13608276,"url":"https://github.com/ruzicka/immutable-custom-merge","last_synced_at":"2025-03-19T02:08:55.778Z","repository":{"id":57272762,"uuid":"83164476","full_name":"ruzicka/immutable-custom-merge","owner":"ruzicka","description":"Allows deep merging of Immutable objects with custom per-property merging strategy","archived":false,"fork":false,"pushed_at":"2017-08-20T21:31:24.000Z","size":12,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-02-26T14:03:31.660Z","etag":null,"topics":["immutability","immutable","immutablejs","merge"],"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/ruzicka.png","metadata":{"files":{"readme":"README.md","changelog":null,"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-02-25T21:35:00.000Z","updated_at":"2021-06-11T13:43:22.000Z","dependencies_parsed_at":"2022-09-08T23:20:39.659Z","dependency_job_id":null,"html_url":"https://github.com/ruzicka/immutable-custom-merge","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ruzicka%2Fimmutable-custom-merge","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ruzicka%2Fimmutable-custom-merge/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ruzicka%2Fimmutable-custom-merge/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ruzicka%2Fimmutable-custom-merge/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ruzicka","download_url":"https://codeload.github.com/ruzicka/immutable-custom-merge/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244339043,"owners_count":20437168,"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":["immutability","immutable","immutablejs","merge"],"created_at":"2024-08-01T19:01:25.817Z","updated_at":"2025-03-19T02:08:55.715Z","avatar_url":"https://github.com/ruzicka.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"[![npm version](https://badge.fury.io/js/immutable-custom-merge.svg)](https://badge.fury.io/js/immutable-custom-merge)\n[![Build Status](https://travis-ci.org/ruzicka/immutable-custom-merge.svg?branch=master)](https://travis-ci.org/ruzicka/immutable-custom-merge)\n[![Coverage Status](https://coveralls.io/repos/github/ruzicka/immutable-custom-merge/badge.svg?branch=master)](https://coveralls.io/github/ruzicka/immutable-custom-merge?branch=master)\n\n# immutable-custom-merge\n\nDeep merging of Immutable structures with custom per-property merging strategy.\n\n## Install\n\n```\nnpm install immutable-custom-merge\n```\n\n\n## Example usage\n```javascript\nimport {fromJS} from 'immutable'\nimport merge from 'immutable-custom-merge'\n\nconst object1 = fromJS({\n  a: [1, 2, 3],\n  b: {\n    x: [1, 2, 3],\n    y: ['a', 'b'],\n  },\n  c: [1, 2, 3],\n  d: 4,\n  e: 5\n  \n})\n\nconst object2 = fromJS({\n  a: [3, 4],\n  b: {\n    x: [3, 4],\n    y: ['b', 'c'],\n  },\n  c: [3, 4],\n  d: 8,\n  e: 6\n})\n\n// defines how properties should be merged in case of collisions\nconst mergeSchema = {\n  a: 'append',        // colliding iterables should be appended\n  b: {\n    '*': 'union',     // 'union' function will be applied on every key under `b`\n  },\n  e: (a, b) =\u003e a + b  // use custom defined function to merge values under this key\n}\n\n// merge two immutable Maps using the schema\nconst result = merge(object1, object2, mergeSchema)\n```\n\nResult of the above merging would be Immutable Map having this structure:\n\n```javascript\n{\n  a: [1, 2, 3, 3, 4],   // colliding array was appended\n  b: {\n    x: [1, 2, 3, 4],    // union of items\n    y: ['a', 'b', 'c']  // union of items\n  },\n  c: [3, 4, 3],         // no rule - default Immutable merge\n  d: 8,                 // no rule for property means later overrides former\n  e: 11                 // custom function to solve collisions\n}\n```\n\n## `mergeDeep(val1, val2, schema)`\n\n`immutable-custom-merge` exports just one function. It performs deep merge of `val1` into `val2`, using provided `schema` to determine how to\nmerge specific keys if there's a collision.\n\n* `val1`: **required** Immutable structure (most typically \n[Map](https://facebook.github.io/immutable-js/docs/#/Map)) to be merged with \nsecond argument. Beyond Maps it supports other Immutable types where deep \nmerging makes sense.\n* `val2`: **required** Immutable structure to be merged into `val1`\n* `schema`: structured js object defining merge strategy for specific keys \nof input parameters. String with the name of one of pre-defined merge \nfunctions or custom merge function. If `schema` is string or function, \nfirst two arguments doesn't need to be immutables. If schema is not supplied\nat all, it falls back to standard immutable `mergeDeep` function. \nIf schema is not supplied and first argument is non-immutable, it just\nreturns second argument.   \n\n## Defining merge schema\n\nBasically, you need to specify merge function for certain (sub)keys of your input\ndata that you want to merge differently from how native immutable merge function does it. \n\nSchema bellow only defines special behaviour for sub-key `messages`. Every other key\nwill be treated as it would be merged by native `mergeDeep` function.\n```javascript\nconst mergeSchema = {\n  result: {\n    messages: 'append'\n  } \n}\n```\n\nThere are two kinds of merge functions that can be specified in the schema. _Pre-defined_ and _custom_ merge functions. \nMerge function is called when key (for which it is defined in _merge schema_) is present in both `val1`\nand `val2`. Merging function receives values of this keys as it's arguments (first one is `val1's`, second one is `val2's`).\n \n### Wildcard key\nIf you need to apply some merge function on every (sub)item, you can specify `'*'` instead of a\nkey. This is quite usefull in situation when you store similar structured records\nin Map-like objects (maybe you use `normalizr`?): \n \n```javascript\nconst object1 = fromJS({\n  books: {\n    '111': {\n      id: '111',\n      author: '888' \n    },  \n    '222': {\n      id: '222',\n      author: '999' \n    }  \n  },\n  authors: {\n    ...\n  }\n  \n})\n```\n\nYou may want to merge book records into your store, but some sources may list a book\nwith more authors so you might need to keep all of them. You would use this schema\nto merge in new data:\n\n```javascript\nconst mergeSchema = {\n  books: {\n    '*': {\n      author: 'union'\n    }\n  } \n}\n```\n \n### Pre-defined merging functions\nThere are some pre-defined function to choose from:\n#### append\nWorks with Immutable Iterables. Appends items of second parameter to the end of the first one\n```javascript\nconst object1 = fromJS({ a: [1, 2, 3] })\nconst object2 = fromJS({ a: [3, 4] })\nconst mergeSchema = { a: 'append' }\nconst result = merge(object1, object2, mergeSchema)\n\n// result: { a: [1, 2, 3, 3, 4] }\n```\n\n#### prepend\nSame as append but items are prepended\n```javascript\nconst object1 = fromJS({ a: [1, 2, 3] })\nconst object2 = fromJS({ a: [3, 4] })\nconst mergeSchema = { a: 'prepend' }\nconst result = merge(object1, object2, mergeSchema)\n\n// result: { a: [3, 4, 1, 2, 3] }\n```\n\n#### union\n\nSame as append but only items that are not already in the list are appended\n```javascript\nconst object1 = fromJS({ a: [1, 2, 3] })\nconst object2 = fromJS({ a: [3, 4] })\nconst mergeSchema = { a: 'union' }\nconst result = merge(object1, object2, mergeSchema)\n\n// result: { a: [1, 2, 3, 4] }\n```\n\n### Custom merging functions\n\nInstead of using predefined function, you can supply your own. It will receive two\narguments, conflicting values.\n\n```javascript\nconst object1 = fromJS({ a: 3 })\nconst object2 = fromJS({ a: 5 })\nconst mergeSchema = { a: (a, b) =\u003e a + b }\nconst result = merge(object1, object2, mergeSchema)\n\n// result: { a: 8 }\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fruzicka%2Fimmutable-custom-merge","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fruzicka%2Fimmutable-custom-merge","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fruzicka%2Fimmutable-custom-merge/lists"}