jsonschema: options for inference (#185)

- Add ForOptions to hold options for schema inference.

- Replace ForLax with ForOptions.IgnoreBadTypes.

- Add an option to provide schemas for arbitrary types.

- Provide a default mapping from types to schemas that includes stdlib
types with MarshalJSON methods.

- Add Schema.CloneSchemas. This is needed to make copies of the schemas
in the above map: a schema cannot appear twice in a parent schema,
because schema addresses matter when resolving internal references.
This commit is contained in:
Jonathan Amsterdam 2025-08-04 10:50:57 -04:00 • committed by GitHub
commit 1e40ede369
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -152,6 +152,42 @@ func (s *Schema) String() string {
return "<anonymous schema>"
}
// CloneSchemas returns a copy of s.
// The copy is shallow except for sub-schemas, which are themelves copied with CloneSchemas.
// This allows both s and s.CloneSchemas() to appear as sub-schemas in the same parent.
func (s *Schema) CloneSchemas() *Schema {
if s == nil {
return nil
}
s2 := *s
v := reflect.ValueOf(&s2)
for _, info := range schemaFieldInfos {
fv := v.Elem().FieldByIndex(info.sf.Index)
switch info.sf.Type {
case schemaType:
sscss := fv.Interface().(*Schema)
fv.Set(reflect.ValueOf(sscss.CloneSchemas()))
case schemaSliceType:
slice := fv.Interface().([]*Schema)
slice = slices.Clone(slice)
for i, ss := range slice {
slice[i] = ss.CloneSchemas()
}
fv.Set(reflect.ValueOf(slice))
case schemaMapType:
m := fv.Interface().(map[string]*Schema)
m = maps.Clone(m)
for k, ss := range m {
m[k] = ss.CloneSchemas()
}
fv.Set(reflect.ValueOf(m))
}
}
return &s2
}
func (s *Schema) basicChecks() error {
if s.Type != "" && s.Types != nil {
return errors.New("both Type and Types are set; at most one should be")