diff --git a/libs/jsonschema/instance.go b/libs/jsonschema/instance.go index 091822da1e..0b060cfff4 100644 --- a/libs/jsonschema/instance.go +++ b/libs/jsonschema/instance.go @@ -122,7 +122,7 @@ func (s *Schema) validatePattern(instance map[string]any) error { if !ok { continue } - err := ValidatePatternMatch(k, v, fieldInfo) + err := validatePatternMatch(k, v, fieldInfo) if err != nil { return err } diff --git a/libs/jsonschema/schema.go b/libs/jsonschema/schema.go index f1a89e7bfb..57082dc840 100644 --- a/libs/jsonschema/schema.go +++ b/libs/jsonschema/schema.go @@ -58,6 +58,22 @@ type Schema struct { Extension } +// Default value defined in a JSON Schema, represented as a string. +func (s *Schema) DefaultString() (string, error) { + return toString(s.Default, s.Type) +} + +// Allowed enum values defined in a JSON Schema, represented as a slice of strings. +func (s *Schema) EnumStringSlice() ([]string, error) { + return toStringSlice(s.Enum, s.Type) +} + +// Parses a string as a Go primitive value. The type of the value is determined +// by the type defined in the JSON Schema. +func (s *Schema) ParseString(v string) (any, error) { + return fromString(v, s.Type) +} + type Type string const ( diff --git a/libs/jsonschema/utils.go b/libs/jsonschema/utils.go index 7bb666c7a3..9e65ed069d 100644 --- a/libs/jsonschema/utils.go +++ b/libs/jsonschema/utils.go @@ -39,7 +39,7 @@ func toInteger(v any) (int64, error) { } } -func ToString(v any, T Type) (string, error) { +func toString(v any, T Type) (string, error) { switch T { case BooleanType: boolVal, ok := v.(bool) @@ -72,10 +72,10 @@ func ToString(v any, T Type) (string, error) { } } -func ToStringSlice(arr []any, T Type) ([]string, error) { +func toStringSlice(arr []any, T Type) ([]string, error) { res := []string{} for _, v := range arr { - s, err := ToString(v, T) + s, err := toString(v, T) if err != nil { return nil, err } @@ -84,7 +84,7 @@ func ToStringSlice(arr []any, T Type) ([]string, error) { return res, nil } -func FromString(s string, T Type) (any, error) { +func fromString(s string, T Type) (any, error) { if T == StringType { return s, nil } @@ -113,7 +113,7 @@ func FromString(s string, T Type) (any, error) { return v, err } -func ValidatePatternMatch(name string, value any, propertySchema *Schema) error { +func validatePatternMatch(name string, value any, propertySchema *Schema) error { if propertySchema.Pattern == "" { // Return early if no pattern is specified return nil diff --git a/libs/jsonschema/utils_test.go b/libs/jsonschema/utils_test.go index 4c43e57d87..b036a23f0c 100644 --- a/libs/jsonschema/utils_test.go +++ b/libs/jsonschema/utils_test.go @@ -49,82 +49,82 @@ func TestTemplateToInteger(t *testing.T) { } func TestTemplateToString(t *testing.T) { - s, err := ToString(true, BooleanType) + s, err := toString(true, BooleanType) assert.NoError(t, err) assert.Equal(t, "true", s) - s, err = ToString("abc", StringType) + s, err = toString("abc", StringType) assert.NoError(t, err) assert.Equal(t, "abc", s) - s, err = ToString(1.1, NumberType) + s, err = toString(1.1, NumberType) assert.NoError(t, err) assert.Equal(t, "1.1", s) - s, err = ToString(2, IntegerType) + s, err = toString(2, IntegerType) assert.NoError(t, err) assert.Equal(t, "2", s) - _, err = ToString([]string{}, ArrayType) + _, err = toString([]string{}, ArrayType) assert.EqualError(t, err, "cannot format object of type array as a string. Value of object: []string{}") - _, err = ToString("true", BooleanType) + _, err = toString("true", BooleanType) assert.EqualError(t, err, "expected bool, got: \"true\"") - _, err = ToString(123, StringType) + _, err = toString(123, StringType) assert.EqualError(t, err, "expected string, got: 123") - _, err = ToString(false, NumberType) + _, err = toString(false, NumberType) assert.EqualError(t, err, "expected float, got: false") - _, err = ToString("abc", IntegerType) + _, err = toString("abc", IntegerType) assert.EqualError(t, err, "cannot convert \"abc\" to an integer") - _, err = ToString("abc", "foobar") + _, err = toString("abc", "foobar") assert.EqualError(t, err, "unknown json schema type: \"foobar\"") } func TestTemplateFromString(t *testing.T) { - v, err := FromString("true", BooleanType) + v, err := fromString("true", BooleanType) assert.NoError(t, err) assert.Equal(t, true, v) - v, err = FromString("abc", StringType) + v, err = fromString("abc", StringType) assert.NoError(t, err) assert.Equal(t, "abc", v) - v, err = FromString("1.1", NumberType) + v, err = fromString("1.1", NumberType) assert.NoError(t, err) // Floating point conversions are not perfect assert.True(t, (v.(float64)-1.1) < 0.000001) - v, err = FromString("12345", IntegerType) + v, err = fromString("12345", IntegerType) assert.NoError(t, err) assert.Equal(t, int64(12345), v) - v, err = FromString("123", NumberType) + v, err = fromString("123", NumberType) assert.NoError(t, err) assert.Equal(t, float64(123), v) - _, err = FromString("qrt", ArrayType) + _, err = fromString("qrt", ArrayType) assert.EqualError(t, err, "cannot parse string as object of type array. Value of string: \"qrt\"") - _, err = FromString("abc", IntegerType) + _, err = fromString("abc", IntegerType) assert.EqualError(t, err, "could not parse \"abc\" as a integer: strconv.ParseInt: parsing \"abc\": invalid syntax") - _, err = FromString("1.0", IntegerType) + _, err = fromString("1.0", IntegerType) assert.EqualError(t, err, "could not parse \"1.0\" as a integer: strconv.ParseInt: parsing \"1.0\": invalid syntax") - _, err = FromString("1.0", "foobar") + _, err = fromString("1.0", "foobar") assert.EqualError(t, err, "unknown json schema type: \"foobar\"") } func TestTemplateToStringSlice(t *testing.T) { - s, err := ToStringSlice([]any{"a", "b", "c"}, StringType) + s, err := toStringSlice([]any{"a", "b", "c"}, StringType) assert.NoError(t, err) assert.Equal(t, []string{"a", "b", "c"}, s) - s, err = ToStringSlice([]any{1.1, 2.2, 3.3}, NumberType) + s, err = toStringSlice([]any{1.1, 2.2, 3.3}, NumberType) assert.NoError(t, err) assert.Equal(t, []string{"1.1", "2.2", "3.3"}, s) } @@ -133,23 +133,23 @@ func TestValidatePropertyPatternMatch(t *testing.T) { var err error // Expect no error if no pattern is specified. - err = ValidatePatternMatch("foo", 1, &Schema{Type: "integer"}) + err = validatePatternMatch("foo", 1, &Schema{Type: "integer"}) assert.NoError(t, err) // Expect error because value is not a string. - err = ValidatePatternMatch("bar", 1, &Schema{Type: "integer", Pattern: "abc"}) + err = validatePatternMatch("bar", 1, &Schema{Type: "integer", Pattern: "abc"}) assert.EqualError(t, err, "invalid value for bar: 1. Expected a value of type string") // Expect error because the pattern is invalid. - err = ValidatePatternMatch("bar", "xyz", &Schema{Type: "string", Pattern: "(abc"}) + err = validatePatternMatch("bar", "xyz", &Schema{Type: "string", Pattern: "(abc"}) assert.EqualError(t, err, "error parsing regexp: missing closing ): `(abc`") // Expect no error because the pattern matches. - err = ValidatePatternMatch("bar", "axyzd", &Schema{Type: "string", Pattern: "(a*.d)"}) + err = validatePatternMatch("bar", "axyzd", &Schema{Type: "string", Pattern: "(a*.d)"}) assert.NoError(t, err) // Expect custom error message on match fail - err = ValidatePatternMatch("bar", "axyze", &Schema{ + err = validatePatternMatch("bar", "axyze", &Schema{ Type: "string", Pattern: "(a*.d)", Extension: Extension{ @@ -159,7 +159,7 @@ func TestValidatePropertyPatternMatch(t *testing.T) { assert.EqualError(t, err, "invalid value for bar: \"axyze\". my custom msg") // Expect generic message on match fail - err = ValidatePatternMatch("bar", "axyze", &Schema{ + err = validatePatternMatch("bar", "axyze", &Schema{ Type: "string", Pattern: "(a*.d)", }) diff --git a/libs/template/config.go b/libs/template/config.go index 8ace307bee..58b671fbfd 100644 --- a/libs/template/config.go +++ b/libs/template/config.go @@ -75,7 +75,7 @@ func (c *config) assignDefaultValues(r *renderer) error { if property.Default == nil { continue } - defaultVal, err := jsonschema.ToString(property.Default, property.Type) + defaultVal, err := property.DefaultString() if err != nil { return err } @@ -83,7 +83,7 @@ func (c *config) assignDefaultValues(r *renderer) error { if err != nil { return err } - defaultValTyped, err := jsonschema.FromString(defaultVal, property.Type) + defaultValTyped, err := property.ParseString(defaultVal) if err != nil { return err } @@ -107,7 +107,7 @@ func (c *config) promptForValues(r *renderer) error { var defaultVal string var err error if property.Default != nil { - defaultValRaw, err := jsonschema.ToString(property.Default, property.Type) + defaultValRaw, err := property.DefaultString() if err != nil { return err } @@ -126,7 +126,7 @@ func (c *config) promptForValues(r *renderer) error { var userInput string if property.Enum != nil { // convert list of enums to string slice - enums, err := jsonschema.ToStringSlice(property.Enum, property.Type) + enums, err := property.EnumStringSlice() if err != nil { return err } @@ -142,7 +142,7 @@ func (c *config) promptForValues(r *renderer) error { } // Convert user input string back to a value - c.values[name], err = jsonschema.FromString(userInput, property.Type) + c.values[name], err = property.ParseString(userInput) if err != nil { return err }