UNPKG

json-merger

Version:

Merge JSON (or YAML) files and objects with indicators like $import $remove $replace $merge etc

1,952 lines (1,504 loc) 30.5 kB
# json-merger Merge JSON (or YAML) files and objects with operations like $import $remove $replace $merge and more. ## Table of Contents: - [API](#api) - [`.mergeFile(file: string, config?: Config)`](#mergefilefile-string-config-config) - [`.mergeFiles(files: string[], config?: Config)`](#mergefilesfiles-string-config-config) - [`.mergeObject(object: object, config?: Config)`](#mergeobjectobject-object-config-config) - [`.mergeObjects(objects: object[], config?: Config)`](#mergeobjectsobjects-object-config-config) - [`Merger(config?: Config)`](#mergerconfig-config) - [Config](#config) - [`cwd: string`](#cwd-string) - [`enableExpressionOperation: boolean`](#enableexpressionoperation-boolean) - [`errorOnFileNotFound: boolean`](#erroronfilenotfound-boolean) - [`errorOnRefNotFound: boolean`](#erroronrefnotfound-boolean) - [`operationPrefix: string`](#operationprefix-string) - [`params: object`](#params-object) - [`stringify: boolean`](#stringify-boolean--pretty) - [`defaultArrayMergeOperation: "combine" | "replace" | "concat"`](#defaultarraymergeoperation-combine--replace--concat) - [`spaces?: number`](#spaces-number) - [Operations](#operations) - [`$import`](#import) - [`$merge`](#merge) - [`$remove`](#remove) - [`$replace`](#replace) - [`$concat`](#concat) - [`$combine`](#combine) - [`$append`](#append) - [`$prepend`](#prepend) - [`$insert`](#insert) - [`$match`](#match) - [`$move`](#move) - [`$select`](#select) - [`$repeat`](#repeat) - [`$include`](#include) - [`$expression`](#expression) - [Scopes](#scopes) - [Command line interface `json-merger`](#command-line-interface-json-merger) - [Changelog](#changelog) - [Roadmap](#roadmap) ## API ### `.mergeFile(file: string, config?: Config)` **javascript** ```javascript var jsonMerger = require("json-merger"); var result = jsonMerger.mergeFile("a.json"); ``` **a.json:** ```json { "$merge": { "source": { "$import": "b.json" }, "with": { "prop1": { "$replace": { "prop1a": "this will replace b.json's property prop1" } }, "prop2": { "prop2a": "this will merge with b.json's property prop2" } } } } ``` **b.json:** ```json { "prop1": { "prop1b": "will be replaced" }, "prop2": { "prop2b": "will be merged" } } ``` **result** ```json { "prop1": { "prop1a": "this will replace b.json's property prop1" }, "prop2": { "prop2a": "this will merge with b.json's property prop2", "prop2b": "will be merged" } } ``` ### `.mergeFiles(files: string[], config?: Config)` **javascript** ```javascript var jsonMerger = require("json-merger"); var result = jsonMerger.mergeFiles(["a.json", "b.json"]); ``` **a.json:** ```json { "a": "some value" } ``` **b.json:** ```json { "b": "some other value" } ``` **result** ```json { "a": "some value", "b": "some other value" } ``` ### `.mergeObject(object: object, config?: Config)` **javascript** ```javascript var jsonMerger = require("json-merger"); var object = { a: { aa: "some value", }, b: { $import: "b.json", }, }; var result = jsonMerger.mergeObject(object); ``` **b.json:** ```json { "bb": "some other value" } ``` **result** ```json { "a": { "aa": "some value" }, "b": { "bb": "some other value" } } ``` ### `.mergeObjects(objects: object[], config?: Config)` **javascript** ```javascript var jsonMerger = require("json-merger"); var object1 = { a: [1, 1, 1, 1], }; var object2 = { a: [2, 2], }; var result = jsonMerger.mergeObjects([object1, object2]); ``` **result** ```json { "a": [2, 2, 1, 1] } ``` ### `Merger(config?: Config)` The actual `Merger` class is also exported. The other exports are just shortcut methods. Using one `Merger` instance has some performance advantages because it will cache previously loaded and processed files. **javascript** ```javascript var Merger = require("json-merger").Merger; var merger = new Merger(); // the first call will load and process "a.json" var result1 = merger.mergeFile("a.json"); // the second call will return the cached result var result2 = merger.mergeFile("a.json"); // clear the caches merger.clearCaches(); ``` ## Config ```typescript interface Config { cwd?: string; enableExpressionOperation?: boolean; errorOnFileNotFound?: boolean; errorOnRefNotFound?: boolean; operationPrefix?: string; params?: object; stringify?: boolean | "pretty"; defaultArrayMergeOperation: "combine" | "replace" | "concat"; } ``` ### `cwd: string` The current working directory when importing files. Defaults to process.cwd(). ### `enableExpressionOperation: boolean` Set this property to `true` to enable the $expression operation. IMPORTANT: Do not use it to run untrusted code because it uses the node:vm module. ### `errorOnFileNotFound: boolean` Set this property to `false` to disable throwing errors when an imported file does not exist. ### `errorOnRefNotFound: boolean` Set this property to `false` to disable throwing errors when an JSON pointer or JSON path does not exist. ### `operationPrefix: string` Use this property to override the prefix to indicate a property is an operation like $import. The default prefix is `$`but it is possible to change this to for example`@`to use keywords like`@import`. ### `params: object` Object that will be available in [`$expression`](#expression) operations as `$params` variable. ### `stringify: boolean | "pretty"` Set this property to `true` to stringify the JSON result. Set the property to `"pretty"` if the output should be pretty printed. ### `defaultArrayMergeOperation: "combine" | "replace" | "concat"` Set this property to override default merge operation. Default value is set to [`"combine"`](#combine). Possible values are: - [`"replace"`](#replace) - [`"concat"`](#concat) - [`"combine"`](#combine) ### `spaces?: number` Set this property to indent with spaces instead of tabs when prettifying json. Invalid numbers disables the configuration and resets to tab character. Supports numbers between 0 and 10. Lower than 0 assumes 0 and higher than 10 assumes 10. ## Operations ### `$import` Use `$import` to import other JSON or YAML files. Files imported with `$import` are processed before the result is returned. ```json { "$import": "a.json" } ``` [JSON reference](https://tools.ietf.org/html/draft-pbryan-zyp-json-ref-03) syntax is supported. The following example will import the first array item from the `someArray` property in `a.json`. ```json { "$import": "a.json#/someArray/0" } ``` When defined as an array, `$import` will process and merge the files in order before returning the result. ```json { "$import": ["a.json", "b.yaml", "c.json"] } ``` When importing a file it is also possible to provide a different `$params` object. Setting this property will override the `Config.params` property. ```json { "$import": { "path": "a.json", "params": { "prop": "some value that will be available in a.json as $params.prop" } } } ``` The object syntax is also supported in an array. ```json { "$import": [ { "path": "a.json", "params": { "prop": "value1" } }, { "path": "a.json", "params": { "prop": "value2" } } ] } ``` Use [`$include`](#include) to process a file in the current scope. ### `$merge` Use the `$merge` operation to merge objects and arrays. **javascript** ```javascript var result = jsonMerger.mergeFile("a.json"); ``` **a.json** ```json { "$merge": { "source": { "a": { "aa": "some value" } }, "with": { "a": { "bb": "some other value" } } } } ``` **result** ```json { "a": { "aa": "some value", "bb": "some other value" } } ``` #### Merging with other files The `$merge` operation is often used with the `$import` operation to merge other files from within the JSON itself. **javascript** ```javascript var result = jsonMerger.mergeFile("a.json"); ``` **a.json** ```json { "$merge": { "source": { "$import": "b.json" }, "with": { "a": { "bb": "some other value" } } } } ``` **b.json** ```json { "a": { "aa": "some value" } } ``` **result** ```json { "a": { "aa": "some value", "bb": "some other value" } } ``` ### `$remove` Use the `$remove` operation to remove properties and array items. #### Remove object properties **javascript** ```javascript var result = jsonMerger.mergeFiles(["a.json", "b.json"]); ``` **a.json** ```json { "prop1": { "prop1a": "some value" }, "prop2": { "prop2a": "some other value" } } ``` **b.json** ```json { "prop2": { "$remove": true } } ``` **result** ```json { "prop1": { "prop1a": "some value" } } ``` #### Remove array items **javascript** ```javascript var result = jsonMerger.mergeFiles(["a.json", "b.json"]); ``` **a.json** ```json { "someArray": [1, 2, 3] } ``` **b.json** ```json { "someArray": [ { "$remove": true }, { "$remove": true } ] } ``` **result** ```json { "someArray": [3] } ``` ### `$replace` Use the `$replace` operation to replace properties and array items. #### Replace object properties **javascript** ```javascript var result = jsonMerger.mergeFiles(["a.json", "b.json"]); ``` **a.json** ```json { "prop1": { "prop1a": "some value" }, "prop2": { "prop2a": "some other value" } } ``` **b.json** ```json { "prop2": { "$replace": { "prop2b": "replaced value" } } } ``` **result** ```json { "prop1": { "prop1a": "some value" }, "prop2": { "prop2b": "replaced value" } } ``` #### Replace array items **javascript** ```javascript var result = jsonMerger.mergeFiles(["a.json", "b.json"]); ``` **a.json** ```json { "someArray": [ { "a": 1 }, { "b": 2 } ] } ``` **b.json** ```json { "someArray": [ { "$replace": { "c": 3 } } ] } ``` **result** ```json { "someArray": [ { "c": 3 }, { "b": 2 } ] } ``` ### `$concat` Use the `$concat` operation to concatenate two arrays. **javascript** ```javascript var result = jsonMerger.mergeFiles(["a.json", "b.json"]); ``` **a.json** ```json { "someArray": [1] } ``` **b.json** ```json { "someArray": { "$concat": [2] } } ``` **result** ```json { "someArray": [1, 2] } ``` ### `$combine` Use the `$combine` operation to combine two arrays. **javascript** ```javascript var result = jsonMerger.mergeFiles(["a.json", "b.json"]); ``` **a.json** ```json { "someArray": [1, 2, 3] } ``` **b.json** ```json { "someArray": { "$combine": [3, 3] } } ``` **result** ```json { "someArray": [3, 3, 3] } ``` ### `$append` Use the `$append` operation to append an item to an array. **javascript** ```javascript var result = jsonMerger.mergeFiles(["a.json", "b.json"]); ``` **a.json** ```json { "someArray": [1, 2, 3] } ``` **b.json** ```json { "someArray": [ { "$append": 4 } ] } ``` **result** ```json { "someArray": [1, 2, 3, 4] } ``` ### `$prepend` Use the `$prepend` operation to prepend an item to an array. **javascript** ```javascript var result = jsonMerger.mergeFiles(["a.json", "b.json"]); ``` **a.json** ```json { "someArray": [1, 2, 3] } ``` **b.json** ```json { "someArray": [ { "$prepend": 4 } ] } ``` **result** ```json { "someArray": [4, 1, 2, 3] } ``` ### `$insert` Use the `$insert` operation to insert an item to an array. **javascript** ```javascript var result = jsonMerger.mergeFiles(["a.json", "b.json"]); ``` **a.json** ```json { "someArray": [1, 2, 3] } ``` **b.json** ```json { "someArray": [ { "$insert": { "index": 1, "value": 4 } } ] } ``` **result** ```json { "someArray": [1, 4, 2, 3] } ``` #### Insert as last item Set `$insert.index` to `-` to insert an item at the end of the array. **javascript** ```javascript var result = jsonMerger.mergeFiles(["a.json", "b.json"]); ``` **a.json** ```json { "someArray": [1, 2, 3] } ``` **b.json** ```json { "someArray": [ { "$insert": { "index": "-", "value": 4 } } ] } ``` **result** ```json { "someArray": [1, 2, 3, 4] } ``` #### Insert before the last item A negative `$insert.index` can be used, indicating an offset from the end of the array. **javascript** ```javascript var result = jsonMerger.mergeFiles(["a.json", "b.json"]); ``` **a.json** ```json { "someArray": [1, 2, 3] } ``` **b.json** ```json { "someArray": [ { "$insert": { "index": -1, "value": 4 } } ] } ``` **result** ```json { "someArray": [1, 2, 4, 3] } ``` ### `$match` Use the `$match` operation to search for a specific array item and merge with that item. #### Match by index Use `$match.index` to match an array item by index. **javascript** ```javascript var result = jsonMerger.mergeFiles(["a.json", "b.json"]); ``` **a.json** ```json { "someArray": [1, 2, 3] } ``` **b.json** ```json { "someArray": [ { "$match": { "index": 1, "value": 4 } } ] } ``` **result** ```json { "someArray": [1, 4, 3] } ``` #### Match by JSON pointer Use `$match.path` to match an array item with a JSON pointer. **javascript** ```javascript var result = jsonMerger.mergeFiles(["a.json", "b.json"]); ``` **a.json** ```json { "someArray": [1, 2, 3] } ``` **b.json** ```json { "someArray": [ { "$match": { "path": "/1", "value": 4 } } ] } ``` **result** ```json { "someArray": [1, 4, 3] } ``` #### Match by JSON path query Use `$match.query` to match an array item with a [JSON path](https://www.npmjs.com/package/jsonpath) query. The following example will search for an array item containing the value `2` and merge it with the value `4`. **javascript** ```javascript var result = jsonMerger.mergeFiles(["a.json", "b.json"]); ``` **a.json** ```json { "someArray": [1, 2, 3] } ``` **b.json** ```json { "someArray": [ { "$match": { "query": "$[?(@ == 2)]", "value": 4 } } ] } ``` **result** ```json { "someArray": [1, 4, 3] } ``` ### `$move` Use the `$move` operation to move an array item. **javascript** ```javascript var result = jsonMerger.mergeFiles(["a.json", "b.json"]); ``` **a.json** ```json { "someArray": [1, 2, 3] } ``` **b.json** ```json { "someArray": [ { "$move": 1 } ] } ``` **result** ```json { "someArray": [2, 1, 3] } ``` #### Move a matched array item Use the `$match` operation in conjunction with the `$move` operation to move a specific array item. **javascript** ```javascript var result = jsonMerger.mergeFiles(["a.json", "b.json"]); ``` **a.json** ```json { "someArray": [1, 2, 3] } ``` **b.json** ```json { "someArray": [ { "$match": { "index": 0, "value": { "$move": 1 } } } ] } ``` **result** ```json { "someArray": [2, 1, 3] } ``` #### Move a matched array item to the end Use `-` as `$move.index` value to move an array item to the end. **javascript** ```javascript var result = jsonMerger.mergeFiles(["a.json", "b.json"]); ``` **a.json** ```json { "someArray": [1, 2, 3] } ``` **b.json** ```json { "someArray": [ { "$match": { "index": 0, "value": { "$move": "-" } } } ] } ``` **result** ```json { "someArray": [2, 3, 1] } ``` #### Move and merge a matched array item Use `$move.value` to not only move the item but also merge it with a value. **javascript** ```javascript var result = jsonMerger.mergeFiles(["a.json", "b.json"]); ``` **a.json** ```json { "someArray": [ { "a": 1 }, { "a": 2 }, { "a": 3 } ] } ``` **b.json** ```json { "someArray": [ { "$match": { "query": "$[?(@.a == 3)]", "value": { "$move": { "index": 0, "value": { "b": 3 } } } } } ] } ``` **result** ```json { "someArray": [ { "a": 3, "b": 3 }, { "a": 1 }, { "a": 2 } ] } ``` ### `$select` Use the `$select` operation to select one or multiple values. Be careful not to create an endless loop by selecting a parent property. #### Select by JSON pointer More information about JSON pointers can be found in the [JSON pointer specification](https://tools.ietf.org/html/rfc6901). **javascript** ```javascript var result = jsonMerger.mergeFile("a.json"); ``` **a.json** ```json { "prop": { "$select": "/otherProp" }, "otherProp": "Should be the value of prop" } ``` **result** ```json { "prop": "Should be the value of prop", "otherProp": "Should be the value of prop" } ``` #### Use `$select.query` to select by JSON path query More information about JSON path queries can be found in the [JSON path documentation](https://www.npmjs.com/package/jsonpath). **javascript** ```javascript var result = jsonMerger.mergeFile("a.json"); ``` **a.json** ```json { "prop": { "$select": { "query": "$.someArray[*]" } }, "someArray": [1, 2, 3] } ``` **result** ```json { "prop": 1, "someArray": [1, 2, 3] } ``` #### Use `$select.multiple` to select multiple values **javascript** ```javascript var result = jsonMerger.mergeFile("a.json"); ``` **a.json** ```json { "prop": { "$select": { "query": "$.someArray[?(@ < 3)]", "multiple": true } }, "someArray": [1, 2, 3] } ``` **result** ```json { "prop": [1, 2] } ``` #### Use `$select.from` to select from an object **javascript** ```javascript var result = jsonMerger.mergeFile("a.json"); ``` **a.json** ```json { "prop": { "$select": { "from": { "$import": "b.json" }, "path": "/someArray/2" } } } ``` **b.json** ```json { "someArray": [1, 2, 3] } ``` **result** ```json { "prop": 3 } ``` ### `$repeat` Use the `$repeat` operation to repeat a value. #### Repeat with `$repeat.to` **operation** ```json { "$repeat": { "from": 1, "to": 4, "value": "repeat" } } ``` **result** ```json ["repeat", "repeat", "repeat"] ``` #### Repeat with `$repeat.through` The current value is available on the scope as `$repeat.value` variable. **operation** ```json { "$repeat": { "from": 1, "through": 4, "value": { "$expression": "$repeat.value" } } } ``` **result** ```json [1, 2, 3, 4] ``` #### Repeat with `$repeat.step` **operation** ```json { "$repeat": { "from": 0, "through": 10, "step": 5, "value": { "$expression": "$repeat.value" } } } ``` **result** ```json [0, 5, 10] ``` #### Repeat with `$repeat.range` **operation** ```json { "$repeat": { "range": "0:-2, 10, 20:30:5", "value": { "$expression": "$repeat.value" } } } ``` **result** ```json [0, -1, -2, 10, 20, 25, 30] ``` #### Repeat with `$repeat.in` as array **operation** ```json { "$repeat": { "in": ["a", "b"], "value": { "$expression": "$repeat.value" } } } ``` **result** ```json ["a", "b"] ``` #### Repeat with `$repeat.in` as object The current key is available on the scope as `$repeat.key` variable. **operation** ```json { "$repeat": { "in": { "keyA": "valueA", "keyB": "valueB" }, "value": { "$expression": "{key: $repeat.key, value: $repeat.value}" } } } ``` **result** ```json [ { "key": "keyA", "value": "valueA" }, { "key": "keyB", "value": "valueB" } ] ``` #### Getting the current index The current index is available on the scope as `$repeat.index` variable. **operation** ```json { "$repeat": { "range": "1:2", "value": { "$expression": "$repeat.index" } } } ``` **result** ```json [0, 1] ``` #### Nested repeat Use `$parent` to get to the parent scope containing the parent `$repeat`. **operation** ```json { "$repeat": { "range": "0:1", "value": { "$repeat": { "range": "0:1", "value": { "$expression": "$parent.$repeat.index + '.' + $repeat.index" } } } } } ``` **result** ```json ["0.0", "0.1", "1.0", "1.1"] ``` ### `$include` Use `$include` to load other JSON or YAML files and process them in the current scope. **javascript** ```javascript var result = jsonMerger.mergeFiles(["a.json", "b.json"]); ``` **a.json** ```json { "someArray": [1, 2, 3] } ``` **b.json** ```json { "someArray": [ { "$include": "remove.json" } ] } ``` **remove.json** ```json { "$remove": true } ``` **result** ```json { "someArray": [2, 3] } ``` ### `$expression` Use the `$expression` operation to calculate a value with the help of a JavaScript expression. The expression has access to the standard built-in JavaScript objects, the current [scope](#scopes) and optionally an `$input` variable. By default this operation is disabled because it allows executing untrusted code which could introduce a security risk. It can be enabled by setting the [`enableExpressionOperation`](#enableexpressionoperation-boolean) option. #### Calculate a value **javascript** ```javascript var result = jsonMerger.mergeFile("a.json"); ``` **a.json** ```json { "prop": { "$expression": "1 + 2" } } ``` **result** ```json { "prop": 3 } ``` #### Calculate a value using `$expression.input` **javascript** ```javascript var result = jsonMerger.mergeFile("b.json"); ``` **a.json** ```json { "add": 2 } ``` **b.json** ```json { "prop": { "$expression": { "expression": "1 + $input", "input": { "$import": "a.json#/add" } } } } ``` **result** ```json { "prop": 3 } ``` #### Calculate a value using the scope $targetProperty **javascript** ```javascript var result = jsonMerger.mergeFiles(["a.json", "b.json"]); ``` **a.json** ```json { "prop": 1 } ``` **b.json** ```json { "prop": { "$expression": "$targetProperty + 2" } } ``` **result** ```json { "prop": 3 } ``` #### Calculate a value using the scope $params **javascript** ```javascript var result = jsonMerger.mergeFile("a.json", { params: { add: 2, }, }); ``` **a.json** ```json { "prop": { "$expression": "1 + $params.add" } } ``` **result** ```json { "prop": 3 } ``` ## Scopes Scopes can be created while processing operation properties. If for example a `$merge.with` is being processed then the merger will create a new scope for the `$merge.with` property. Or if a `$repeat.value` property is being processed a new scope is created for the `$repeat.value` property. A scope always has a `$source` property but not necessarily a `$target` property. When we are merging object A with object B, then the `$target` property in the scope of object A is `undefined` because object A is not merged with anything. It does have a `$source` property referring to object A itself. Object B on the other hand has the processed object A as `$target` because object B is being merged with object A. The `$source` property in the scope of object B refers to object B. If object B had defined a `$merge` operation, then the merger would create a new scope for the `$merge.source` property and a new scope for the `$merge.with` property. The `$target` within the `$merge.source` scope would be `undefined` because `$merge.source` is not merged with anything. The `$target` within the `$merge.with` scope is the processed `$merge.source` because `$merge.with` is being merged with `$merge.source`. The result of the `$merge` operation will eventually be merged with object A. When in the `$merge.source` scope it is possible to get to the root (object B) scope using the `$root` property or to a parent scope using the `$parent` property. ```typescript interface Scope { $params?: any; // $params properties in current scope $parent?: Scope; // reference to parent scope $repeat?: ScopeRepeat; // $repeat properties in current scope $root: Scope; // reference to root scope $source: any; // reference to the source object $target?: any; // reference to the target object } ``` #### Example **javascript** ```javascript var result = jsonMerger.mergeFiles(["a.json", "b.json"]); ``` **a.json** ```js // this is the root scope { "prop1": { "$expression": "$target" // refers to undefined because a.json has no target }, "prop2": { "$expression": "$targetProperty" // refers to undefined because a.json has no target }, "prop3": { "$expression": "$source" // refers to the unprocessed a.json }, "prop4": { "$expression": "$sourceProperty" // refers to the unprocessed a.json#/prop4 }, "prop5": { "$expression": "$root.$target" // refers to undefined because a.json has no target }, "prop6": { "$expression": "$root.$source" // refers to the unprocessed a.json }, "prop7": { "$expression": "$parent" // refers to undefined because the current scope has no parent scope }, } ``` **b.json** ```js // this is the root scope { "prop1": { "$expression": "$target" // refers to the processed a.json }, "prop2": { "$expression": "$targetProperty" // refers to the processed a.json#/prop2 }, "prop3": { "$expression": "$source" // refers to the unprocessed b.json }, "prop4": { "$expression": "$sourceProperty" // refers to the unprocessed b.json#/prop4 }, "prop5": { "$merge": { "source": { // $merge.source creates a new scope "prop1": { "$expression": "$target" // refers to undefined because b.json#/prop5/$merge/source has no target }, "prop2": { "$expression": "$targetProperty" // refers to undefined because b.json#/prop5/$merge/source has no target }, "prop3": { "$expression": "$source" // refers to the unprocessed b.json#/prop5/$merge/source }, "prop4": { "$expression": "$sourceProperty" // refers to the unprocessed b.json#/prop5/$merge/source/prop4 } "prop5": { "$expression": "$root.$target" // refers to the processed a.json } "prop6": { "$expression": "$root.$source" // refers to the unprocessed b.json }, "prop7": { "$expression": "$parent.$target" // refers to the processed a.json } "prop8": { "$expression": "$parent.$source" // refers to the unprocessed b.json } }, "with": { // $merge.with creates a new scope "prop1": { "$expression": "$target" // refers to the processed b.json#/prop5/$merge/source }, "prop2": { "$expression": "$targetProperty" // refers to the processed b.json#/prop5/$merge/source/prop2 }, "prop3": { "$expression": "$source" // refers to the unprocessed b.json#/prop5/$merge/with }, "prop4": { "$expression": "$sourceProperty" // refers to the unprocessed b.json#/prop5/$merge/with/prop4 }, "prop5": { "$expression": "$root.$target" // refers to the processed a.json }, "prop6": { "$expression": "$root.source" // refers to the unprocessed b.json }, "prop7": { "$expression": "$parent.$target" // refers to the processed a.json }, "prop8": { "$expression": "$parent.source" // refers to the unprocessed b.json } } } }, "prop6": { "$repeat": { "range": "0:1", "value": { // $repeat.value creates a new scope with a $repeat property on it "$repeat": { "range": "0:1", "value": { // $repeat.value creates a new scope with a $repeat property on it "$expression": "'This is item ' + $parent.$repeat.index + '.' + $repeat.index" } } } } } } ``` --- ## Command line interface `json-merger` You can use `json-merger` as a command line tool: ``` Usage: json-merger [options] <file ...> Options: -V, --version output the version number -p, --pretty pretty-print the output json -o, --output [file] the output file. Defaults to stdout --op, --operation-prefix [prefix] the operation prefix. Defaults to $ --am, --default-array-merge-operation [operation] the default array merge operation. Defaults to combine -s, --spaces <value> Use number of spaces instead of tab when pretty-printing json. --enable-expression-operation [value] enables expressions. Do not use it to run untrusted code because it uses the node:vm module. Defaults to false --error-on-file-not-found [value] throw an error if a file is not found. Defaults to true --error-on-ref-not-found [value] throw an error if a JSON pointer or JSON path is not found. Defaults to true -h, --help output usage information ``` Usage: ```sh json-merger a.json > result.json json-merger --output result.json a.json json-merger --output result.json --pretty a.json ``` Install `json-merger` globally to be able to use the command line interface. ```sh npm install -g json-merger ``` ## Changelog ### 2.0.0 - Changed emitted JavaScript target to ES6. - The `$expression` operation is using the `node:vm` package instead of the deprecated `vm2` package. - The `$expression` operation is disabled by default because it allows executing untrusted code. - Added the `enableExpressionOperation` configuration option to enable the `$expression` operation. - Added the `--enable-expression-operation` CLI option to enable the `$expression` operation. ### 2.1.0 - Added the `--spaces` CLI option to allow pretty formatting with spaces instead of tabs. ### 3.0.0 - The `-op` and `-am` CLI options have been renamed to `--op` and `--am`. ## Roadmap - Add configurable file resolvers to import files from different sources. - Add configurable (de)serializers to import and export different file formats.