{"id":19711596,"url":"https://github.com/wjsoftware/wj-merge","last_synced_at":"2026-06-12T11:31:27.479Z","repository":{"id":208180678,"uuid":"720312820","full_name":"WJSoftware/wj-merge","owner":"WJSoftware","description":"Object merger that creates a single object using objects from various data sources, applying them sequentially and conditionally.","archived":false,"fork":false,"pushed_at":"2024-09-27T04:22:53.000Z","size":100,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-02-27T19:55:31.689Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","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/WJSoftware.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-11-18T04:59:48.000Z","updated_at":"2024-09-27T04:22:51.000Z","dependencies_parsed_at":"2023-11-20T08:09:45.065Z","dependency_job_id":"96b4336e-a3b8-46b3-af23-79fee042d9ab","html_url":"https://github.com/WJSoftware/wj-merge","commit_stats":null,"previous_names":["wjsoftware/wj-merge"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/WJSoftware/wj-merge","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WJSoftware%2Fwj-merge","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WJSoftware%2Fwj-merge/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WJSoftware%2Fwj-merge/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WJSoftware%2Fwj-merge/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/WJSoftware","download_url":"https://codeload.github.com/WJSoftware/wj-merge/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WJSoftware%2Fwj-merge/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34243051,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-12T02:00:06.859Z","response_time":109,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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-11T22:12:37.288Z","updated_at":"2026-06-12T11:31:27.456Z","avatar_url":"https://github.com/WJSoftware.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# wj-merge\n\n\u003e Object merger that creates a single object using objects from various data sources, applying them sequentially and \n\u003e conditionally.\n\nThis package is a deep object merging algorithm that is also capable of tracing the origin of the data.  This is very \nhelpful for troubleshooting and for features for a more elaborate, more specific package or objective.\n\n## Package Description\n\nReview the information carefully to determine if this package is right for you.  Before proceeding, review the list of \nconcepts.\n\n| Concept | Relevant Type(s) | Description |\n| - | - | - |\n| Leaf Value | `LeafValue`, `SingleLeafValue` | A leaf value is a value that cannot contain other values; it is *the* value. |\n| Node | `SourceObject` | A node is a value that contains other values, be it leaf values or other nodes. |\n| Root Node | `SourceObject` | Represented by the same type as the node, the only difference is the semantics:  The root node is the data object. |\n| Source Object | `SourceObject` | Source objects (or sources) are the inputs that feed the merging algorithm; this is a synonym for nodes. |\n| Merge Result | `MergeResult\u003cT, B\u003e` | The output of the builder's `build()` method and the final goal. |\n| Dictionary | `Dictionary` | A dictionary is an object with a flat hierarchy:  Its properties are all leaf values. |\n\n### Leaf Values\n\nValues of type `string`, `number`, `Date`, `boolean`, `Function` and `null` are leaf values.  Leaf values cannot be \noverridden during the merging process by nodes, only by other leaf values.\n\nArrays of the aforementioned types are also leaf values.  This means that arrays are replaced entirely during the \nmerging process.\n\nConsider the following two JSON files representing two source objects (or root nodes):\n\n```json\n{\n    \"A\": \"a-value\",\n    \"B\": \"b-value\"\n}\n```\n\n```json\n{\n    \"A\": 1\n}\n```\n\nWhen feeding `wj-merge` these two sources in this order, the merge result will be:\n\n```json\n{\n    \"A\": 1,\n    \"B\": \"b-value\"\n}\n```\n\nThis happens because `A` in the first JSON is of type `string`, a leaf value type, and `A` in the second JSON is of \ntype `number`, also a leaf value type.\n\nIf the second JSON happened to be something like:\n\n```json\n{\n    \"A\": {\n        \"A+\": 1\n    }\n}\n```\n\nThen the merging algorithm would throw an error because once the nature of the property has been established, it \ncannot be changed:  The first JSON established that `A` was a leaf value, and the merging algorithm will make sure \nthis continues to be the case.\n\nThe inverse is also true:  Once a property's type has been established as a node, a subsequent source object cannot \nredefine this nature as a leaf value.\n\n## Data Sources\n\nSource objects are fed into the merging algorithm by using builder semantics and the concept of data sources.  Any \nobject that satisfies the `IDataSource` interface can be used to provide a source object.\n\nThe package provides 5 data sources out of the box:\n\n| Data Source | Class Name | Description |\n| - | - | - |\n| Dictionary | `DictionaryDataSource` | Injects a dictionary object as data source.  Property names in dictionaries follow a naming convention to specify the object's hierarchy.  This is useful when importing from environment variables or INI files. |\n| Fetched | `FetchedDataSource` | Executes a `fetch()` operation to obtain the source object. |\n| Json | `JsonDataSource` | Parses string data into a JSON object to be used as source. |\n| Object | `ObjectDataSource` | The simplest, yet most versatile data source:  Provides an object as source. |\n| SingleValue | `SingleValueDataSource` | Injects a source object with a single value.  The value's name must follow the naming convention of dictionaries. |\n\n## Quickstart\n\n1. Import the builder factory function, `wjMerge()`.\n2. Execute `wjMerge()` to obtain a builder.\n3. Add data using the appropriate data source.  The builder has corresponding helper functions for the out-of-box data \nsources.\n4. Execute and await `build()`.\n\n```typescript\nimport wjMerge from \"wj-merge\";\n\nconst result = await wjMerge()\n    .addDictionary(...)\n    .addFetched(...)\n    .addJson(...)\n    .addObject(...)\n    .addSingleValue(...)\n    .build();\n\n// Optionally, you can have this code in its own module, and export the result.\nexport default result;\n```\n\nYou can include as many sources as needed, and you can prepare your own data source if the out-of-the-box ones are \ninsufficient.  The most popular one, which isn't included in this package so it can be equally used in the browser and \nNodeJS, is a File data source that reads a file from disk (usually a JSON file, but the sky is the limit).\n\n```typescript\nimport { DataSource, type IDataSource, type SourceObject } from \"wj-merge\";\n\nexport class FileDataSource extends DataSource implements IDataSource {\n    #fileName: string;\n    constructor(fileName: string) {\n        super(`File: ${fileName}`);\n        this.#fileName = fileName;\n    }\n\n    getObject(): Promise\u003cSourceObject\u003e {} {\n        // Implementation goes here.  Recommendation: import { readFile } from 'fs/promises'.\n    }\n}\n```\n\nThe DataSource class is the base class for all data sources, but it is optional.  It simplifies development of new \nsources, though, so this is why it exists.  Furthermore, you can use the out-of-the-box data sources as base classes.\n\n## Documentation\n\nThe detailed documentation is found in [this repository's Wiki](./wiki).\n\n## Building Extensions\n\n2Do\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwjsoftware%2Fwj-merge","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwjsoftware%2Fwj-merge","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwjsoftware%2Fwj-merge/lists"}