json-pluck 0.1.0

Pluck a single value out of a serde_json::Value by dotted path or simple JSONPath. Lossy, forgiving, intended for LLM-emitted JSON.
Documentation
use json_pluck::pluck;
use serde_json::json;

fn sample() -> serde_json::Value {
    json!({
        "result": {
            "items": [
                { "value": 1, "name": "a" },
                { "value": 42, "name": "b" }
            ],
            "answer": "deep"
        },
        "answer": "shallow"
    })
}

#[test]
fn dotted_object_path() {
    assert_eq!(pluck(&sample(), "result.answer"), Some(&json!("deep")));
}

#[test]
fn array_index_positive() {
    assert_eq!(pluck(&sample(), "result.items[1].value"), Some(&json!(42)));
}

#[test]
fn array_index_negative() {
    assert_eq!(pluck(&sample(), "result.items[-1].value"), Some(&json!(42)));
}

#[test]
fn bfs_finds_shallowest_match() {
    // Both root.answer and result.answer exist; BFS sees root first.
    assert_eq!(pluck(&sample(), "**.answer"), Some(&json!("shallow")));
}

#[test]
fn bfs_descends_when_root_lacks_match() {
    let v = json!({ "wrap": { "found": 99 } });
    assert_eq!(pluck(&v, "**.found"), Some(&json!(99)));
}

#[test]
fn missing_path_returns_none() {
    assert_eq!(pluck(&sample(), "no.such.path"), None);
}

#[test]
fn array_out_of_bounds_is_none() {
    assert_eq!(pluck(&sample(), "result.items[99]"), None);
}