Add anyOf props as required and error when required fields are not specified

This commit is contained in:
Shreyas Goenka 2024-01-24 12:10:55 +05:30
parent 769d092108
commit fca4729221
3 changed files with 44 additions and 15 deletions

View File

@ -73,12 +73,20 @@ func (s *Schema) validateAdditionalProperties(instance map[string]any) error {
return nil
}
type RequiredPropertyMissingError struct {
Name string
}
func (err RequiredPropertyMissingError) Error() string {
return fmt.Sprintf("no value provided for required property %s", err.Name)
}
// This function validates that all require properties in the schema have values
// in the instance.
func (s *Schema) validateRequired(instance map[string]any) error {
for _, name := range s.Required {
if _, ok := instance[name]; !ok {
return fmt.Errorf("no value provided for required property %s", name)
return RequiredPropertyMissingError{Name: name}
}
}
return nil

View File

@ -127,13 +127,27 @@ func (c *config) skipPrompt(p jsonschema.Property, r *renderer) (bool, error) {
// All fields referred to in a SkipPromptIf condition are implicitly made required and
// we diverge from strictly following the JSON schema because it makes the author UX better.
var keys []string
for k := range p.Schema.SkipPromptIf.Properties {
keys = append(keys, k)
required := make(map[string]struct{})
for _, k := range p.Schema.SkipPromptIf.Required {
required[k] = struct{}{}
}
p.Schema.SkipPromptIf.Required = append(keys, p.Schema.SkipPromptIf.Required...)
for k := range p.Schema.SkipPromptIf.Properties {
required[k] = struct{}{}
}
for _, schema := range p.Schema.SkipPromptIf.AnyOf {
for k := range schema.Properties {
required[k] = struct{}{}
}
}
p.Schema.SkipPromptIf.Required = maps.Keys(required)
// Validate the partial config against skip_prompt_if schema
validationErr := p.Schema.SkipPromptIf.ValidateInstance(c.values)
target := jsonschema.RequiredPropertyMissingError{}
if errors.As(validationErr, &target) {
return false, fmt.Errorf("property %s is used in skip_prompt_if but has no value assigned", target.Name)
}
if validationErr != nil {
return false, nil
}

View File

@ -451,8 +451,10 @@ func TestPromptIsSkippedAnyOf(t *testing.T) {
assert.False(t, skip)
// Values do not match skip condition. Prompt should not be skipped.
c.values["abc"] = "foobar"
c.values["def"] = 1234
c.values = map[string]any{
"abc": "foobar",
"def": 1234,
}
skip, err = c.skipPrompt(jsonschema.Property{
Name: "xyz",
Schema: c.schema.Properties["xyz"],
@ -462,19 +464,21 @@ func TestPromptIsSkippedAnyOf(t *testing.T) {
assert.NotContains(t, c.values, "xyz")
// Missing values. Prompt should not be skipped.
c.values["abc"] = "foobar"
skip, err = c.skipPrompt(jsonschema.Property{
c.values = map[string]any{
"abc": "foobar",
}
_, err = c.skipPrompt(jsonschema.Property{
Name: "xyz",
Schema: c.schema.Properties["xyz"],
}, testRenderer())
assert.NoError(t, err)
assert.False(t, skip)
assert.NotContains(t, c.values, "xyz")
assert.ErrorContains(t, err, "property def is used in skip_prompt_if but has no value assigned")
// Values match skip condition. Prompt should be skipped. Default value should
// be assigned to "xyz".
c.values["abc"] = "foobar"
c.values["def"] = 123
c.values = map[string]any{
"abc": "foobar",
"def": 123,
}
skip, err = c.skipPrompt(jsonschema.Property{
Name: "xyz",
Schema: c.schema.Properties["xyz"],
@ -485,7 +489,10 @@ func TestPromptIsSkippedAnyOf(t *testing.T) {
// Values match skip condition. Prompt should be skipped. Default value should
// be assigned to "xyz".
c.values["abc"] = "barfoo"
c.values = map[string]any{
"abc": "barfoo",
"def": 0,
}
skip, err = c.skipPrompt(jsonschema.Property{
Name: "xyz",
Schema: c.schema.Properties["xyz"],