package seatdef import "strings" // ResolveRefs is a schema (its all-string lists as []string, StringLists) with every `{"$ref": "#/defs/"}` replaced by the definition's named type, as the seat // list's readers need it (a verb's input and answer are one schema each, not a schema and its types). A reference to a // name the definition does not define stays as it is; nesting deeper than 32 levels stops there. func ResolveRefs(schema map[string]any, defs map[string]map[string]any) map[string]any { if schema == nil { return nil } m, _ := StringLists(resolveValue(schema, defs, 0)).(map[string]any) return m } func resolveValue(v any, defs map[string]map[string]any, depth int) any { if depth > 32 { return v } switch x := v.(type) { case map[string]any: if r, ok := x["$ref"].(string); ok { if d, ok := defs[strings.TrimPrefix(r, "#/defs/")]; ok { return resolveValue(d, defs, depth+1) } } out := make(map[string]any, len(x)) for k, e := range x { out[k] = resolveValue(e, defs, depth+1) } return out case []any: out := make([]any, len(x)) for i, e := range x { out[i] = resolveValue(e, defs, depth+1) } return out } return v } // StringLists is a schema with every list whose items are all strings (`required`, `enum`) as a []string, the form the // compiled seat list wrote them in; a JSON decoder reads them as []any. func StringLists(v any) any { switch x := v.(type) { case map[string]any: out := make(map[string]any, len(x)) for k, e := range x { out[k] = StringLists(e) } return out case []any: strs := make([]string, 0, len(x)) for _, e := range x { s, ok := e.(string) if !ok { strs = nil break } strs = append(strs, s) } if strs != nil && len(x) > 0 { return strs } out := make([]any, len(x)) for i, e := range x { out[i] = StringLists(e) } return out } return v }