18 Commits

Author SHA1 Message Date
fabd193884
jsonpaths: auto-enable anonymous mode when no TTY
When input is piped (CI, scripts, AI agents), /dev/tty won't exist.
Previously this crashed with 'cannot open /dev/tty'. Now we detect
the absence of a TTY and auto-enable --anonymous mode.
2026-06-11 16:38:34 -06:00
aab60c7ac2
jsontypes/cmd: migrate to flag.FlagSet, add version info
- Use flag.FlagSet with config struct instead of global flag
- Add version vars (name, version, commit, date, licenseYear, licenseOwner, licenseType)
- Add printVersion() with copyright and license
- Handle -V/--version/version/help/-help/--help before fs.Parse
- Handle flag.ErrHelp and fs.NArg() > 1 checks
2026-06-11 16:23:34 -06:00
5676790d03
chore: goimports -w . && go fix ./... 2026-06-11 16:14:38 -06:00
4dc269f0c2
feat(jsontypes): wire jsonpaths CLI to use RawPaths→Coalesce pipeline
In anonymous mode (-anonymous), jsonpaths now uses the deterministic
pipeline (RawPaths → Coalesce → Generate) instead of the legacy
analyzer. Interactive mode still uses the old analyzer with resolver.
2026-06-11 16:14:38 -06:00
f2045c7831
fix(jsontypes): handle hyphenated JSON keys in PascalCase conversion
snakeToPascal now splits on both underscores and hyphens, producing
valid Go identifiers like GenerationI, RubySapphire, BlackWhite instead
of invalid ones like Generation-i, Ruby-sapphire, Black-white.
2026-06-11 16:14:38 -06:00
e7c6d25bed
fix(jsontypes): handle sample format in Go struct generator and path parser
- parsePath now uses brace-depth matching to correctly parse nested JSON
  in sample type intros like {Root:{"name":"pikachu","id":25}}
- cleanTypeName strips sample data from type intros (Root:{...} → Root)
- isPrimitiveType recognizes sample leaf values (quoted strings, numbers)
- primitiveToGo maps sample values to proper Go types (string, int64, etc.)
- All three pipeline tests pass: raw→Go, coalesced→Go, and sample→Go
2026-06-11 16:14:38 -06:00
2129157f8d
feat(jsontypes): add jsonsample CLI and sample format support
jsonsample emits the same flat path format as jsonrawpaths but with
actual JSON values at leaf nodes and compact JSON samples at type intro
lines (e.g., {Root:{"name":"pikachu","id":25,...}}). Output is auto-
coalesced: types deduplicated by key set, one sample per primitive type.

Updated coalescer to handle TypeName:Sample format in type intros,
using first { instead of last { for parsing (handles nested JSON braces).
Sample output is valid input for jsoncoalesce (idempotent round-trip).
2026-06-11 16:14:38 -06:00
6d43b07f3f
feat(jsontypes): add two-pass coalescer for raw path output
Coalesce merges streamer output by deduplicating types with identical
key sets, collapsing {null} into nullable annotations ({string?}),
cleaning up type names (removing unnecessary numbers, deriving names
from keys when many types share a shape), and eliding duplicate type
definitions. Preserves {undefined} distinct from {null} per the
three-stage pipeline design.

Pokemon fixture: 241 raw lines → 140 coalesced lines.
2026-06-11 16:14:38 -06:00
2b7f3f137b
feat(jsontypes): add -samples flag and {undefined} sentinel to raw paths
Add RawPathsConfig with SampleLen to show truncated sample values
instead of type names at leaf nodes (e.g., {"Alice Anglerso..."} instead
of {string}). Add absentValue sentinel to distinguish fields absent
from a struct instance ({undefined}) vs explicitly null ({null}).
2026-06-11 16:14:38 -06:00
ffed4a5e17
fix(jsontypes): use {empty} instead of {any} for empty collections
{any} implies we inspected values and found mixed types. {empty} is
honest: we saw an empty array or object and have no type information.
2026-06-11 16:14:38 -06:00
a346049cc4
feat(jsontypes): short raw paths — type name only on intro line
Type names now appear once on the intro line, and subsequent fields
use the bare path without repeating the type. Root no longer has a
leading dot.

Before: .{Root0}.rooms[]{RoomsItem1}._timing{Timing2}.account_ms{int}
After:  .rooms[]._timing.account_ms{int}

The type intro line declares the type, making the path structure
cleaner and more readable while remaining lossless.
2026-06-11 16:14:38 -06:00
69d757bc69
feat(jsontypes): tier word detection by key count for map heuristic
With ≤3 keys, one word-like key is enough to call it a struct.
With 4+ keys, a majority must be word-like — prevents a single
coincidental match (e.g., "beef" in hex keys) from misclassifying.

Also fixes short segment handling: 2-char abbreviations like "ms" in
"account_ms" are neutral rather than causing the whole key to fail
word detection.
2026-06-11 16:14:38 -06:00
439558a8ac
feat(jsontypes): simplify map detection to 3 rules, add API test fixtures
Rewrote looksLikeMap from 6 layered heuristics down to 3 simple rules:
1. All numeric keys → map (certain)
2. Any key composed of words → struct (certain)
3. Everything else → map (safe default)

The asymmetry is deliberate: a map misidentified as a struct explodes
into hundreds of fields, while a struct misidentified as a map is
compact and easy to fix.

Word detection splits keys on _ and camelCase, checks segments for
pronounceability (vowel/consonant rhythm). Short words (id, at, on)
only count when paired with a strong 3+ char word.

Also adds raw path type naming with Item suffix for collections
(FriendsItem instead of Friend), real API test fixtures from PokeAPI
and SWAPI, and UUID-based test data replacing synthetic abc123 keys.
2026-06-11 16:14:38 -06:00
767115586c
feat(jsontypes): replace base64 check with pronounceability heuristic
isBase64 matched common field names like "name" — too loose for map
detection. Replace with isPronounceable which checks vowel/consonant
rhythm: real field names have natural syllable structure (15-80% vowels,
no 5+ consonant runs), while tokens and IDs don't.

Also fix allLookLikeIDs to reject keys that don't match any ID pattern
instead of silently accepting them.
2026-06-11 16:14:38 -06:00
b58c09350b
feat(jsontypes): add RawPaths and jsonrawpaths CLI
RawPaths walks JSON depth-first and emits flat paths with monotonically
numbered type names (Root0, People2, etc.). Each type intro immediately
precedes its fields, making the output streamable and order-stable.

Also improves map detection heuristics:
- All-numeric keys are always maps (even with 1-2 keys)
- Keys containing digits detected as IDs (e.g., emp_101)
- New isKnownFieldName with broad list of common field names
  (timestamps, flags, relations, etc.) as strong struct signal
2026-06-11 16:14:38 -06:00
1fbaef9caf
ref(jsontypes): replace Prompter with Resolver callback pattern
Separate library from CLI concerns:
- Add Resolver callback type with Decision/Response structs for all
  interactive decisions (map/struct, type name, tuple/list, shape
  unification, shape naming, name collision)
- Move terminal I/O (Prompter) from library to cmd/jsonpaths
- Add public API: New(), ParseFormat(), Generate(), AutoGenerate()
- Add Format type with aliases (ts, py, json-paths, etc.)
- Fix godoc comments to match exported function names
- Update tests to use scriptedResolver instead of Prompter internals
- Update doc.go and README with current API
2026-06-11 16:14:38 -06:00
60de770b63
fix(jsontypes): spell 'tools' correctly 2026-06-11 16:14:38 -06:00
57014ff1dd
feat(jsontypes): infer types from JSON, generate code in 9 formats
Add tools/jsontypes library and tools/jsontypes/cmd/jsonpaths CLI.

Given a JSON sample (file, URL, or stdin), walks the structure,
detects maps vs structs, infers optional fields from multiple
instances, and produces typed definitions.

Output formats (--format):
- json-paths: flat type path notation (default)
- go: struct definitions with json tags and union support
- typescript: interfaces with optional/nullable fields
- jsdoc: @typedef annotations
- zod: validation schemas with type inference
- python: TypedDict classes
- sql: CREATE TABLE with FK relationships
- json-schema: draft 2020-12
- json-typedef: RFC 8927

Features:
- Interactive prompts for ambiguous structure (map vs struct, same
  vs different types), with --anonymous mode for non-interactive use
- Answer replay: saves prompt answers to .answers files for iterative
  refinement
- URL fetching with local caching and sensitive param stripping
- Curl-like auth: -H, --bearer, --user, --cookie, --cookie-jar
- Discriminated union support with sealed interfaces, unique-field
  probing, and CHANGE ME comments for type/kind discriminators
- Extensive round-trip compilation tests for generated Go code
2026-06-11 16:14:38 -06:00