golib/tools/jsontypes/jsdoc.go
AJ ONeal 89b1191fdd
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-03-07 14:34:01 -07:00

57 lines
1.2 KiB
Go

package jsontypes
import (
"fmt"
"strings"
)
// generateJSDoc converts formatted flat paths into JSDoc @typedef annotations.
func GenerateJSDoc(paths []string) string {
types, _ := buildGoTypes(paths)
if len(types) == 0 {
return ""
}
var buf strings.Builder
for i, t := range types {
if i > 0 {
buf.WriteByte('\n')
}
buf.WriteString(fmt.Sprintf("/**\n * @typedef {Object} %s\n", t.name))
for _, f := range t.fields {
jsType := goTypeToJSDoc(f.goType)
if f.optional {
buf.WriteString(fmt.Sprintf(" * @property {%s} [%s]\n", jsType, f.jsonName))
} else {
buf.WriteString(fmt.Sprintf(" * @property {%s} %s\n", jsType, f.jsonName))
}
}
buf.WriteString(" */\n")
}
return buf.String()
}
func goTypeToJSDoc(goTyp string) string {
goTyp = strings.TrimPrefix(goTyp, "*")
if strings.HasPrefix(goTyp, "[]") {
return goTypeToJSDoc(goTyp[2:]) + "[]"
}
if strings.HasPrefix(goTyp, "map[string]") {
return "Object<string, " + goTypeToJSDoc(goTyp[11:]) + ">"
}
switch goTyp {
case "string":
return "string"
case "int64", "float64":
return "number"
case "bool":
return "boolean"
case "any":
return "*"
default:
return goTyp
}
}