|
Some checks failed
ci/woodpecker/push/rust-test/3 Pipeline was successful
ci/woodpecker/push/rust-test/1 Pipeline was successful
ci/woodpecker/push/rust-test/2 Pipeline was successful
ci/woodpecker/push/container/2 Pipeline was successful
ci/woodpecker/push/container-manifest unknown status
ci/woodpecker/push/container/1 Pipeline failed
Adds `jsaw schema <dir>` — scans a directory of structured files and infers a common schema with field coverage, semantic types, required detection and enum inference for low-cardinality fields. Core inference logic (FieldSchema IR, infer_schema, infer_schema_filtered) lives in jsaw-core::schema so downstream crates (e.g. mdq) can consume it without pulling in the TUI. The jsaw-bin command provides an interactive ratatui TUI with collapsible nested fields and a detail popup, plus CSV output when piped. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|---|---|---|
| .hooks | ||
| .woodpecker | ||
| jsaw-bin | ||
| jsaw-core | ||
| jsaw-gui | ||
| .gitignore | ||
| AGENTS.md | ||
| Cargo.lock | ||
| Cargo.toml | ||
| cog.toml | ||
| flake.lock | ||
| flake.nix | ||
| justfile | ||
| README.md | ||
| renovate.json | ||
jsaw
A universal runtime for structured data.
JSON, TOML, YAML, Markdown frontmatter, CSV — one tool to inspect, query, validate, convert, and browse them all. Unix-friendly by default; a rich TUI when you want to think.
Install
# Nix (recommended)
nix run github:yourusername/jsaw
# From source (CLI only)
cargo install --path jsaw-bin
CLI
Composable, pipeable, scriptable. Every command reads from a file or - for stdin.
jsaw inspect <file|-> # type tree: keys, depths, value types
jsaw validate <path> [--schema <f>] # JSON Schema validation; auto-detects $schema
[--recursive] # walk a whole directory
[--skip-unparseable] # silently skip unreadable files
[--quiet] # only print failures
jsaw query <file|-> <expr> # jq-style filter via jaq
[--raw] # raw string output, no JSON quoting
jsaw convert <file> --to <fmt> # json | toml | yaml
[--out <file>] # write to file instead of stdout
jsaw fmt <file> [--in-place] # pretty-print in original format
jsaw db <dir> [-c col] [-f filter] # directory as queryable table → TUI or CSV
[-s field] [-r] # sort, reverse
[--offset N] [-l N] # pagination
[--json] # output as JSON instead
Piping examples:
cat secrets.yaml | jsaw query - '.tokens[]'
jsaw db ./posts -c "title" -c "date" -f '.published == true' -s date -r
jsaw validate ./schemas/ --recursive --skip-unparseable --quiet
TUI
jsaw db <dir> launches a TUI automatically when stdout is a terminal. This is the primary interactive surface of jsaw — the place where you think with your data, not just read it.
Current state
The TUI launches automatically when jsaw db is run in a terminal. It is a full state machine with four modes:
Table mode — the default view:
j/k↑/↓— move row;g/G— first/last;PgUp/PgDn— pages/S— cycle sort column / reverse; active sort shown as↑/↓in header/— open live filter bar (jq predicate, applied instantly on Enter)Enter— open detail view for selected row?— help overlay;q/Esc— quit
Filter bar — activated with /:
- Type any jq predicate (e.g.
.active == true,.score > 50) Enterapplies;Esccancels;Ctrl+Uclears;Ctrl+Backspacedeletes word
Detail view — full record tree activated with Enter:
- Collapsible tree:
Space/Enterfold/unfold;j/kscroll;q/Escback - Virtual
filebranch shows filesystem metadata (name, path, size, mtime…) databranch shows the full record with type badges on the right
Semantic rendering — every value is classified and colored:
| Semantic type | Display |
|---|---|
| URL | cyan + underline |
| cyan | |
| DateTime | yellow |
| Date | yellow |
| Boolean | green ✓ / red ✗ |
| Integer / Float | magenta |
| UUID | blue |
Color (#rrggbb) |
rendered in its own RGB foreground color |
| SemVer | green |
| File path | yellow |
| IP address | blue |
| Base64 | dim, truncated to preview |
| Markdown | first line only + … |
| GeoJSON geometry | green badge with shape name |
| JSON Schema | cyan badge |
| Null | dim — |
The inference engine (jsaw-core::semantic) is value-first (URL scheme, ISO-8601, UUID format, GeoJSON shape check, base64 alphabet, markdown signals) with key-name heuristics as fallback (url/href/link → Url, email/mail → Email, date/created → Date, etc.).
Roadmap
Checked items are implemented. Everything else is planned.
Table view (jsaw db)
- Basic table rendering with auto-column detection
- Row navigation (vim keys + arrows, g/G, PgUp/PgDn)
- Status bar with row count and hints
- Live filter bar —
/opens a jq predicate bar; Enter applies, Esc cancels - Column sort —
scycles sort column,Sreverses;↑/↓shown in header - Semantic cell rendering — values colored and formatted by inferred type
- Row detail panel —
Enteropens full-screen collapsible tree for selected row - Help overlay —
?shows all keybindings in a centered popup - Column picker — press
Cto toggle visible columns interactively - Fuzzy search — press
ffor cross-column fuzzy match - Export — press
eto write current filtered/sorted view as JSON or CSV - Clipboard yank — press
yto copy selected cell value - Multi-sort — stack sort keys, not just one
- Column resize — keyboard-resize columns
Tree / inspect view (jsaw inspect)
Currently inspect only prints and exits. The goal: when stdout is a terminal, jsaw inspect should open a navigable tree TUI. The semantic engine and collapsible tree code from the detail view are already reusable for this.
- Semantic type inference — engine exists in
jsaw-core::semantic, shared with the TUI - Collapsible tree — implemented in detail view; needs to be the primary view for
inspect - Type-colored values — implemented in
styled_value() inspectlaunches TUI — opens the collapsible tree viewer when stdout is a terminal; falls back to plain-text print when piped- Search — press
/to jump-to-key or search values - Schema overlay — if
$schemais present, show field descriptions, required markers, enum hints - Clipboard yank —
ycopies the value at cursor as JSON - JQ bar — press
:to run a jq expression and show results in a result pane - Jump to path — press
gfollowed by a dot-path like.dependencies.ratatui
General TUI improvements
- Watch mode —
--watchflag, auto-reload and re-render when file changes on disk - Mouse support — click to select rows/cells, scroll with wheel
- Theme / color config — respect
NO_COLOR, allow minimal / full-color modes - Error pane — show parse or schema errors non-fatally in a dismissible panel
- Diff mode —
jsaw diff <file-a> <file-b>opens a side-by-side TUI diff
Longer-term / bigger ideas
- Multi-file pane — open multiple files as tabs, navigate between them
- Edit mode — press
ein tree view to edit a value inline; write back to file - Schema-driven edit — constrained editing when a schema is present (enums as pickers, required fields enforced)
- Cross-file linking — navigate from a foreign-key value to the referenced file/record
- HTTP source —
jsaw inspect https://api.example.com/datafetches and renders live - Graph view — detect graph-shaped data and render a force-directed node graph in the terminal (sixel / unicode blocks)
Philosophy
- Schema-first, not schema-required — schemas unlock contextual rendering, validation, and intelligent editing. jsaw degrades gracefully when none exists.
- The UI is a lens, never the owner — files stay files. TOMLs stay TOMLs. jsaw never holds your data hostage.
- Inference over annotation — a field named
urlwith a URI value doesn't need to be tagged as a link. It already is one. - Unix-friendly — every command pipes in, pipes out. The TUI is opt-in, not mandatory.
- TUI first — the terminal is the right home for a developer data tool. Fast to open, keyboard-driven, scriptable context around it.
GUI
There is a Dioxus desktop GUI (jsaw-gui) in this repo. It is currently experimental and secondary. The plan is to validate interactions and rendering ideas in the TUI first, then port proven patterns to the GUI. Don't rely on the GUI for production use yet.
Architecture
jsaw/
├── jsaw-core/ # shared logic: data loading, filtering, records, schema
├── jsaw-bin/ # CLI binary (clap); TUI lives here (ratatui + crossterm)
└── jsaw-gui/ # Dioxus desktop app (experimental)
jsaw-core has no UI dependencies. jsaw-bin and jsaw-gui both depend on it. TUI features implemented in jsaw-bin can be reasoned about and ported to jsaw-gui later — the core data model is shared.
Development
# Full workspace (requires Nix devshell for jsaw-gui's native deps)
just check
# CLI only (no Nix required, but needs libiconv on macOS)
cargo run -p jsaw-bin -- db ./some-dir
# TUI dev loop
cargo run -p jsaw-bin -- db ./testdata
# GUI (Nix devshell)
cd jsaw-gui && nix develop ..#default --command dx serve