mirror of
https://github.com/therootcompany/golib.git
synced 2026-03-13 12:27:59 +00:00
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
143 lines
4.7 KiB
Go
143 lines
4.7 KiB
Go
package jsontypes
|
|
|
|
// DecisionKind identifies the type of decision being requested.
|
|
type DecisionKind int
|
|
|
|
const (
|
|
// DecideMapOrStruct asks whether a JSON object is a map (dynamic keys)
|
|
// or a struct (fixed fields).
|
|
// Relevant Decision fields: Fields.
|
|
// Response: set IsMap=true, or set Name to a PascalCase type name.
|
|
DecideMapOrStruct DecisionKind = iota
|
|
|
|
// DecideTypeName asks what a struct type should be called.
|
|
// Relevant Decision fields: Fields.
|
|
// Response: set Name to a PascalCase type name.
|
|
DecideTypeName
|
|
|
|
// DecideTupleOrList asks whether a short mixed-type array is a tuple
|
|
// (fixed positional types) or a homogeneous list.
|
|
// Relevant Decision fields: Elements.
|
|
// Response: set IsTuple.
|
|
DecideTupleOrList
|
|
|
|
// DecideUnifyShapes asks whether multiple object shapes at the same
|
|
// JSON position represent the same type (with optional fields) or
|
|
// different types.
|
|
// Relevant Decision fields: Shapes, SharedFields.
|
|
// Response: set IsNewType to treat each shape as a separate type.
|
|
DecideUnifyShapes
|
|
|
|
// DecideShapeName asks what a specific shape variant should be called
|
|
// when the user chose "different types" for a UnifyShapes decision.
|
|
// Relevant Decision fields: ShapeIndex, Fields.
|
|
// Response: set Name to a PascalCase type name.
|
|
DecideShapeName
|
|
|
|
// DecideNameCollision asks what to do when a chosen type name is
|
|
// already registered with overlapping but incompatible fields.
|
|
// Relevant Decision fields: Fields (new), ExistingFields.
|
|
// Response: set Extend=true to merge fields, or set Name to a
|
|
// different PascalCase type name.
|
|
DecideNameCollision
|
|
)
|
|
|
|
// Decision represents a question posed during JSON analysis.
|
|
// The Kind field determines which context fields are populated.
|
|
type Decision struct {
|
|
Kind DecisionKind
|
|
Path string // JSON path being analyzed
|
|
Default Response // heuristic suggestion
|
|
|
|
// Fields describes the object's keys and value types.
|
|
// Populated for MapOrStruct, TypeName, ShapeName, NameCollision.
|
|
Fields []FieldSummary
|
|
|
|
// Elements describes array element values.
|
|
// Populated for TupleOrList.
|
|
Elements []ElementSummary
|
|
|
|
// Shapes describes multiple object shapes at the same position.
|
|
// Populated for UnifyShapes.
|
|
Shapes []ShapeSummary
|
|
|
|
// SharedFields lists field names common to all shapes.
|
|
// Populated for UnifyShapes.
|
|
SharedFields []string
|
|
|
|
// ShapeIndex identifies which shape is being named (0-based).
|
|
// Populated for ShapeName.
|
|
ShapeIndex int
|
|
|
|
// ExistingFields lists the fields of the already-registered type
|
|
// whose name collides with the requested name.
|
|
// Populated for NameCollision.
|
|
ExistingFields []string
|
|
|
|
// Response is set by the Resolver to communicate the decision.
|
|
Response Response
|
|
}
|
|
|
|
// Response carries the answer to a Decision.
|
|
// Which fields are meaningful depends on the Decision.Kind.
|
|
type Response struct {
|
|
// Name is a PascalCase type name.
|
|
// Used by MapOrStruct (when not a map), TypeName, ShapeName,
|
|
// and NameCollision (when not extending).
|
|
Name string
|
|
|
|
// IsMap indicates the object should be treated as a map.
|
|
// Used by MapOrStruct.
|
|
IsMap bool
|
|
|
|
// IsTuple indicates the array is a tuple.
|
|
// Used by TupleOrList.
|
|
IsTuple bool
|
|
|
|
// IsNewType indicates each shape should be a separate type rather than
|
|
// unifying into one type with optional fields.
|
|
// Used by UnifyShapes. Zero value (false) means unify into one type.
|
|
IsNewType bool
|
|
|
|
// Extend indicates the existing type should be extended with merged
|
|
// fields rather than choosing a new name.
|
|
// Used by NameCollision.
|
|
Extend bool
|
|
}
|
|
|
|
// FieldSummary describes a single field in a JSON object.
|
|
type FieldSummary struct {
|
|
Name string // JSON field name
|
|
Kind string // "string", "number", "bool", "null", "object", "array"
|
|
Preview string // human-readable value summary
|
|
}
|
|
|
|
// ElementSummary describes a single element in a JSON array.
|
|
type ElementSummary struct {
|
|
Index int
|
|
Kind string
|
|
Preview string
|
|
}
|
|
|
|
// ShapeSummary describes one shape group in a multi-shape decision.
|
|
type ShapeSummary struct {
|
|
Index int // 0-based shape index
|
|
Instances int // how many objects have this shape
|
|
Fields []string // all field names in this shape
|
|
UniqueFields []string // fields unique to this shape (not in other shapes)
|
|
}
|
|
|
|
// Resolver is called during analysis when a decision is needed.
|
|
// The resolver reads the Decision's context fields and sets
|
|
// Decision.Response before returning. If an error is returned,
|
|
// heuristic defaults are used for that decision.
|
|
//
|
|
// To accept the heuristic default: d.Response = d.Default.
|
|
type Resolver func(d *Decision) error
|
|
|
|
// defaultResolver accepts heuristic defaults for all decisions.
|
|
func defaultResolver(d *Decision) error {
|
|
d.Response = d.Default
|
|
return nil
|
|
}
|