fracturedjson 0.1.1

Rust port of FracturedJsonJs: human-friendly JSON formatter with optional comment support.
Documentation
# fracturedjson

A Rust port of [FracturedJson](https://github.com/j-brooke/FracturedJson) — a JSON formatter that produces human-readable output with smart line breaks, table-like alignment, and optional comment support.

## Overview

FracturedJson formats JSON data in a way that's easy for humans to read while remaining fairly compact. Arrays and objects are written on single lines when they're short and simple enough. When several lines have similar structure, their fields are aligned like a table. Long arrays are written with multiple items per line.

This crate is part of the FracturedJson family:

- [Home Page and Browser-based Formatter]https://j-brooke.github.io/FracturedJson/
- [FracturedJson (C#)]https://github.com/j-brooke/FracturedJson
- [FracturedJsonJs (JavaScript/npm)]https://github.com/j-brooke/FracturedJsonJs
- [VS Code Extension]https://marketplace.visualstudio.com/items?itemName=j-brooke.fracturedjsonvsc

## Installation

### Command-Line Tool

Install the `fjson` CLI:

```sh
cargo install fracturedjson
```

### Library

Add to your `Cargo.toml`:

```toml
[dependencies]
fracturedjson = "0.1"
```

## Command-Line Usage

The `fjson` command works like `jq` but focuses on producing beautifully formatted output:

```sh
# Format JSON from stdin
echo '{"name":"Alice","scores":[95,87,92]}' | fjson

# Format a file
fjson input.json

# Write to a file
fjson input.json -o output.json

# Minify JSON
fjson --compact < input.json

# Custom formatting
fjson --indent 2 --max-width 80 < input.json

# Handle JSON with comments
fjson --comments preserve < config.jsonc
```

### CLI Options

| Option | Description |
|--------|-------------|
| `-c, --compact` | Minify output |
| `-w, --max-width N` | Maximum line length (default: 120) |
| `-i, --indent N` | Spaces per indentation level (default: 4) |
| `-t, --tabs` | Use tabs instead of spaces |
| `-o, --output FILE` | Write to file instead of stdout |
| `--comments MODE` | Handle comments: `error`, `remove`, `preserve` |
| `--number-align STYLE` | Number alignment: `left`, `right`, `decimal`, `normalize` |
| `--trailing-commas` | Allow trailing commas in input |

Run `fjson --help` for all options.

## Library Usage

### Reformat JSON Text

```rust
use fracturedjson::Formatter;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let input = r#"{"name":"Alice","scores":[95,87,92],"active":true}"#;

    let mut formatter = Formatter::new();
    let output = formatter.reformat(input, 0)?;

    println!("{}", output);
    Ok(())
}
```

### Serialize Rust Values

```rust
use fracturedjson::Formatter;
use serde::Serialize;

#[derive(Serialize)]
struct Player {
    name: String,
    scores: Vec<i32>,
    active: bool,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let player = Player {
        name: "Alice".into(),
        scores: vec![95, 87, 92],
        active: true,
    };

    let mut formatter = Formatter::new();
    let output = formatter.serialize(&player, 0, 100)?;

    println!("{}", output);
    Ok(())
}
```

### Serialize `serde_json::Value`

```rust
use fracturedjson::Formatter;
use serde_json::json;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let value = json!({
        "name": "Alice",
        "scores": [95, 87, 92],
        "active": true
    });

    let mut formatter = Formatter::new();
    let output = formatter.serialize_value(&value, 0, 100)?;

    println!("{}", output);
    Ok(())
}
```

### Minify JSON

```rust
use fracturedjson::Formatter;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let input = r#"{
        "name": "Alice",
        "scores": [95, 87, 92]
    }"#;

    let mut formatter = Formatter::new();
    let output = formatter.minify(input)?;

    println!("{}", output);
    // Output: {"name":"Alice","scores":[95,87,92]}
    Ok(())
}
```

## Configuration

Customize formatting behavior via `FracturedJsonOptions`:

```rust
use fracturedjson::{
    Formatter, FracturedJsonOptions, EolStyle,
    NumberListAlignment, CommentPolicy,
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut formatter = Formatter::new();

    formatter.options.max_total_line_length = 80;
    formatter.options.max_inline_complexity = 1;
    formatter.options.indent_spaces = 2;
    formatter.options.json_eol_style = EolStyle::Lf;
    formatter.options.number_list_alignment = NumberListAlignment::Decimal;

    // Enable comment support (JSON with comments)
    formatter.options.comment_policy = CommentPolicy::Preserve;

    let input = r#"{"values": [1, 2, 3]}"#;
    let output = formatter.reformat(input, 0)?;

    println!("{}", output);
    Ok(())
}
```

### Available Options

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `max_total_line_length` | `usize` | 120 | Maximum line length before wrapping |
| `max_inline_complexity` | `isize` | 2 | Max nesting depth for inline formatting |
| `max_compact_array_complexity` | `isize` | 2 | Max complexity for compact array rows |
| `max_table_row_complexity` | `isize` | 2 | Max complexity for table row formatting |
| `indent_spaces` | `usize` | 4 | Spaces per indentation level |
| `use_tab_to_indent` | `bool` | false | Use tabs instead of spaces |
| `json_eol_style` | `EolStyle` | `Lf` | Line ending style (`Lf` or `Crlf`) |
| `number_list_alignment` | `NumberListAlignment` | `Decimal` | Number alignment in arrays |
| `comment_policy` | `CommentPolicy` | `TreatAsError` | How to handle comments |
| `preserve_blank_lines` | `bool` | false | Keep blank lines from input |
| `allow_trailing_commas` | `bool` | false | Allow trailing commas in input |

## Example Output

```json
{
    "BasicObject"   : {
        "ModuleId"   : "armor",
        "Name"       : "",
        "Locations"  : [
            [11,  2], [11,  3], [11,  4], [11,  5], [11,  6], [11,  7], [11,  8], [11,  9],
            [11, 10], [11, 11], [11, 12], [11, 13], [11, 14], [ 1, 14], [ 1, 13], [ 1, 12],
            [ 1, 11], [ 1, 10], [ 1,  9], [ 1,  8], [ 1,  7], [ 1,  6], [ 1,  5], [ 1,  4],
            [ 1,  3], [ 1,  2], [ 4,  2], [ 5,  2], [ 6,  2], [ 7,  2], [ 8,  2], [ 8,  3],
            [ 7,  3], [ 6,  3], [ 5,  3], [ 4,  3], [ 0,  4], [ 0,  5], [ 0,  6], [ 0,  7],
            [ 0,  8], [12,  8], [12,  7], [12,  6], [12,  5], [12,  4]
        ],
        "Orientation": "Fore",
        "Seed"       : 272691529
    },
    "SimilarArrays" : {
        "Katherine": ["blue",       "lightblue", "black"       ],
        "Logan"    : ["yellow",     "blue",      "black", "red"],
        "Erik"     : ["red",        "purple"                   ],
        "Jean"     : ["lightgreen", "yellow",    "black"       ]
    },
    "SimilarObjects": [
        { "type": "turret",    "hp": 400, "loc": {"x": 47, "y":  -4}, "flags": "S"   },
        { "type": "assassin",  "hp":  80, "loc": {"x": 12, "y":   6}, "flags": "Q"   },
        { "type": "berserker", "hp": 150, "loc": {"x":  0, "y":   0}                 },
        { "type": "pittrap",              "loc": {"x": 10, "y": -14}, "flags": "S,I" }
    ]
}
```

With comment support enabled (`CommentPolicy::Preserve`):

```jsonc
{
    /*
     * Multi-line comments
     * are fun!
     */
    "NumbersWithHex": [
          254 /*00FE*/,  1450 /*5AA*/,      0 /*0000*/, 36000 /*8CA0*/,    10 /*000A*/,
          199 /*00C7*/, 15001 /*3A99*/,  6540 /*198C*/
    ],
    /* Elements are keen */
    "Elements"      : [
        { /*Carbon*/   "Symbol": "C",  "Number":  6, "Isotopes": [11, 12, 13, 14] },
        { /*Oxygen*/   "Symbol": "O",  "Number":  8, "Isotopes": [16, 18, 17    ] },
        { /*Hydrogen*/ "Symbol": "H",  "Number":  1, "Isotopes": [ 1,  2,  3    ] },
        { /*Iron*/     "Symbol": "Fe", "Number": 26, "Isotopes": [56, 54, 57, 58] }
        // Not a complete list...
    ]
}
```

## License

MIT