# JSON Remix My small contribution to the _Rewrite it in Rust!_ ~bandwagon~ movement. The original was written in [Typescript](https://github.com/vimcommando/json-remix) ## About This is a Rust command-line interface (CLI) tool that provides four commands for manipulating JSON and NDJSON files: `split`, `merge`, `bundle`, and `unbundle`. Each command can accept input or output from files, directories, or from standard input/output wherever relevant. After being rewritten in Rust it is roughly 2x as fast as the Typescript implementation and can handle files larger than 512MB. ### Installation This is published to [crates.io](https://crates.io/crates/jsrmx) so you can simply do a global install with: ```sh cargo install jsrmx ``` Then `jsrmx` is executable from your shell ```sh jsrmx --help ``` ## Usage There are four commands: 1. `merge` - merges multiple JSON objects into a single large JSON object 2. `split` - splits a single JSON object into multiple JSON objects by top-level keys 3. `bundle` - bundles multiple JSON objects ito an NDJSON (newline-delimited JSON) series 4. `unbundle` - unbundles an NDJSON series into a collection of separate JSON objects ### merge ```sh jsrmx merge [output] ``` #### Arguments - `` - Required input directory - `[output]` - Optional output file name (default `-` for stdout) #### Options - `-c`, `--compact` - Compact single-line output objects - `-f`, `--filter` - regular expression to filter output keys - `-p`, `--pretty` - Pretty-print output objects (default) - `-t`, `--trim` - File extension to trim from object key names #### Examples Given a directory named `letters` with six files: ``` letters/alpha.json letters/bravo.json letters/charlie.json letters/delta.json letters/echo.json letters/foxtrot.json ``` Where each file contains a few properties: ```jsonc // cat alpha.json { "uppercase": "A", "lowercase": "a", "position": 1 } ``` We can `merge` all the files into a single file: ```sh jsrmx merge letters/ letters.json ``` So the contents of `letters.json` looks like: ```jsonc // cat letters.json { "alpha": { "lowercase": "a", "position": 1, "uppercase": "A" }, "bravo": { "lowercase": "b", "position": 2, "uppercase": "B" }, "charlie": { "lowercase": "c", "position": 3, "uppercase": "C" }, "delta": { "lowercase": "d", "position": 4, "uppercase": "D" }, "echo": { "lowercase": "e", "position": 5, "uppercase": "E" }, "foxtrot": { "lowercase": "f", "position": 6, "uppercase": "F" } } ``` Note the keys get sorted and have the `.json` extension trimmed from their names. ### split ```sh jsrmx split [input] [output] ``` #### Arguments - `[input]` - Optional input file name or `-` for `stdin` (default `-`) - `[output]` - Optional output directory or `-` for `stdout`(default `-`) #### Options - `-c`, `--compact` - Compact single-line output objects - `-f`, `--filter` - regular expression to filter output keys - `-p`, `--pretty` - Pretty-print output objects (default) #### Examples We can split one file (or object through `stdin`) into individually-named files: ```sh jsrmx split letters.json letters/ ``` Given a the following single-object JSON file: ```jsonc { "alpha": { "uppercase": "A", "lowercase": "a", "position": 1 }, "bravo": { "uppercase": "B", "lowercase": "b", "position": 2 }, // ... 3 entries omitted "foxtrot": { "uppercase": "F", "lowercase": "f", "position": 6 } } ``` The output files created will be: ``` letters/alpha.json letters/bravo.json letters/charlie.json letters/delta.json letters/echo.json letters/foxtrot.json ``` Where each file contents will be the value from the large JSON: ```jsonc // cat alpha.json { "uppercase": "A", "lowercase": "a", "position": 1 } ``` If output to `stdout` the object will keep the top-level key as a parent object. Using `--filter` can extract specific keys. ```sh jsrmx split --filter delta big_object.json - ``` ```jsonc { "delta": { "uppercase": "D", "lowercase": "d", "position": 4 } } ``` Combined with `--compact` this can convert a large object into an `.ndjson` file. ```sh jsrmx split --compact big_object.json > letters.ndjson ``` ```jsonc // cat letters.ndjson {"foxtrot":{"lowercase":"f","position":6,"uppercase":"F"}} {"bravo":{"lowercase":"b","position":2,"uppercase":"B"}} {"charlie":{"lowercase":"c","position":3,"uppercase":"C"}} {"delta":{"lowercase":"d","position":4,"uppercase":"D"}} {"echo":{"lowercase":"e","position":5,"uppercase":"E"}} {"alpha":{"lowercase":"a","position":1,"uppercase":"A"}} ``` ### bundle ```sh jsrmx bundle [output] ``` #### Arguments - `` - Required target input directory - `[output]` - Optional output filename or `-` for stdout (default `-`) #### Options - `-e`, `--escape` - List of field path to convert from nested JSON to an escaped string #### Examples We can convert a directory of `.json` files into a single `.ndjson` (newline-delimited JSON) file: ```sh jsrmx bundle letters/ letters.ndjson ``` Given the files in the input directory: ``` letters/alpha.json letters/bravo.json letters/charlie.json letters/delta.json letters/echo.json letters/foxtrot.json ``` With each file containing: ```jsonc // cat alpha.json { "letter": { "lowercase": "a", "uppercase": "A" }, "name": "alpha", "position": 1 } ``` The output `letters.ndjson` will contain: ```jsonc {"name":"alpha","letter":{"uppercase":"A","lowercase":"a"},"position":1} {"name":"bravo","letter":{"uppercase":"B","lowercase":"b"},"position":2} {"name":"charlie","letter":{"uppercase":"C","lowercase":"c"},"position":3} {"name":"delta","letter":{"uppercase":"D","lowercase":"d"},"position":4} {"name":"echo","letter":{"uppercase":"E","lowercase":"e"},"position":5} {"name":"foxtrot","letter":{"uppercase":"F","lowercase":"f"},"position":6} ``` > NOTE: the filenames are not retained when bundling `.ndjson` files. ### unbundle ```sh jsrmx unbundle [options] [intput] [output] ``` #### Arguments - `[input]` - Optional input file name (default `-` for stdin) - `[output]` - Optional output directory name (default `-` for stdout) #### Options - `-c`, `--compact` - Compact single-line output objects - `-n`, `--name` - A list of JSON paths to use for filenames (uses first non-null) - `-p`, `--pretty` - Pretty-print output objects (default) - `-t`, `--type` - A JSON path to use for filename suffix (before extension) - `-u`, `--unescape` - List of field paths to convert from escaped string to nested JSON #### Example Unbundling a file (or `stdin`) to a directory (or `stdout`): ```sh jsrmx unbundle letters.ndjson letters/ ``` Given the file `letters.ndjson`: ```jsonc {"name":"alpha","letter":{"uppercase":"A","lowercase":"a"},"position":1} {"name":"bravo","letter":{"uppercase":"B","lowercase":"b"},"position":2} {"name":"charlie","letter":{"uppercase":"C","lowercase":"c"},"position":3} {"name":"delta","letter":{"uppercase":"D","lowercase":"d"},"position":4} {"name":"echo","letter":{"uppercase":"E","lowercase":"e"},"position":5} {"name":"foxtrot","letter":{"uppercase":"F","lowercase":"f"},"position":6} ``` Unbundling with: ```sh jsrmx unbundle letters.ndjson letters/ ``` Will create these files: ```sh letters/object-000001.json letters/object-000002.json letters/object-000003.json letters/object-000004.json letters/object-000005.json letters/object-000006.json ``` The contents of each file will be pretty-printed by default: ```jsonc // cat letters/object-000001.json { "name": "alpha", "letter": { "uppercase": "A", "lowercase": "a" }, "position": 1 } ``` Using the `--compact` option we can keep them as single-line entries: ```sh jsrmx unbundle --compact letters.ndjson letters/ ``` ```jsonc // cat letter/object-000001.json {"name":"alpha","letter":{"uppercase":"A","lowercase":"a"},"position": 1} ``` For descriptive filenames, use the `--name` option. For a filename made of `${name}.json` run: ```sh jsrmx unbundle --name=name letters.ndjson letters/ ``` Will output `${name}.json` filenames: ``` letters/alpha.json letters/bravo.json letters/charlie.json letters/delta.json letters/echo.json letters/foxtrot.json ``` Name values will work on nested values as long as the JSON path is `.` delimited. Periods in the key names will not resolve properly. ```sh jsrmx unbundle --name=letter.lowercase letters.ndjson letters/ ``` Will output `${letter.lowercase}.json` filenames: ``` letters/a.json letters/b.json letters/c.json letters/d.json letters/e.json letters/f.json ```