diff --git a/internal/module/collection.go b/internal/module/collection.go index 6786eee..ff8e13c 100644 --- a/internal/module/collection.go +++ b/internal/module/collection.go @@ -13,11 +13,11 @@ import ( func (m *Module) schemaForMap(value pgs.FieldTypeElem, rules *validate.MapRules) jsonschema.Schema { m.Debug("schemaForMap") schema := jsonschema.NewObjectSchema() - schema.AdditionalProperties, _ = m.schemaForElement(value, rules.GetValues()) + schema.AdditionalProperties = m.schemaForElement(value, rules.GetValues()) if rules != nil { if rules.GetKeys().GetString_() != nil { - schema.PropertyNames, _ = m.schemaForString(rules.GetKeys().GetString_(), false) // TODO + schema.PropertyNames = m.schemaForString(rules.GetKeys().GetString_()) } if rules.MaxPairs != nil { @@ -35,7 +35,7 @@ func (m *Module) schemaForMap(value pgs.FieldTypeElem, rules *validate.MapRules) func (m *Module) schemaForRepeated(item pgs.FieldTypeElem, rules *validate.RepeatedRules) jsonschema.Schema { m.Debug("schemaForRepeated") schema := jsonschema.NewArraySchema() - schema.Items, _ = m.schemaForElement(item, rules.GetItems()) + schema.Items = m.schemaForElement(item, rules.GetItems()) if rules != nil { if rules.MaxItems != nil { @@ -54,7 +54,7 @@ func (m *Module) schemaForRepeated(item pgs.FieldTypeElem, rules *validate.Repea return schema } -func (m *Module) schemaForElement(element pgs.FieldTypeElem, constraints *validate.FieldConstraints) (jsonschema.Schema, bool) { +func (m *Module) schemaForElement(element pgs.FieldTypeElem, constraints *validate.FieldConstraints) jsonschema.Schema { m.Debug("schemaForElement") if element.IsEmbed() { return m.schemaForEmbed(element.Embed(), constraints) diff --git a/internal/module/enum.go b/internal/module/enum.go index 7285b49..4d8eb75 100644 --- a/internal/module/enum.go +++ b/internal/module/enum.go @@ -20,7 +20,7 @@ func (m *Module) defineEnum(enum pgs.Enum) *jsonschema.StringSchema { return schema } -func (m *Module) schemaForEnum(enum pgs.Enum, rules *validate.EnumRules) (jsonschema.Schema, bool) { +func (m *Module) schemaForEnum(enum pgs.Enum, rules *validate.EnumRules) jsonschema.Schema { m.Debug("schemaForEnum") if rules != nil { switch { @@ -33,31 +33,28 @@ func (m *Module) schemaForEnum(enum pgs.Enum, rules *validate.EnumRules) (jsonsc } } - return m.enumRef(enum), false + return m.enumRef(enum) } -func (m *Module) schemaForEnumConst(enum pgs.Enum, value int32) (*jsonschema.StringSchema, bool) { +func (m *Module) schemaForEnumConst(enum pgs.Enum, value int32) *jsonschema.StringSchema { m.Debug("schemaForEnumConst") schema := jsonschema.NewStringSchema() schema.Const = jsonschema.String(m.lookUpEnumName(enum, value)) - return schema, value != 0 + + return schema } -func (m *Module) schemaForEnumIn(enum pgs.Enum, values []int32) (*jsonschema.StringSchema, bool) { +func (m *Module) schemaForEnumIn(enum pgs.Enum, values []int32) *jsonschema.StringSchema { m.Debug("schemaForEnumIn") schema := jsonschema.NewStringSchema() - required := true - for _, value := range values { schema.Enum = append(schema.Enum, m.lookUpEnumName(enum, value)) - if value == 0 { - required = false - } } - return schema, required + + return schema } -func (m *Module) schemaForEnumNotIn(enum pgs.Enum, values []int32) (*jsonschema.StringSchema, bool) { +func (m *Module) schemaForEnumNotIn(enum pgs.Enum, values []int32) *jsonschema.StringSchema { m.Debug("schemaForEnumNotIn") exclude := make(map[int32]struct{}, len(values)) for _, v := range values { @@ -65,19 +62,14 @@ func (m *Module) schemaForEnumNotIn(enum pgs.Enum, values []int32) (*jsonschema. } schema := jsonschema.NewStringSchema() - required := true - for _, v := range enum.Values() { value := v.Value() if _, ok := exclude[value]; !ok { schema.Enum = append(schema.Enum, v.Name().String()) - if value == 0 { - required = false - } } } - return schema, required + return schema } func (m *Module) lookUpEnumName(enum pgs.Enum, value int32) string { diff --git a/internal/module/message.go b/internal/module/message.go index c064ca4..9a57a71 100644 --- a/internal/module/message.go +++ b/internal/module/message.go @@ -54,32 +54,35 @@ func (m *Module) schemaForField(field pgs.Field) (jsonschema.Schema, bool) { _, err := field.Extension(validate.E_Field, constraints) m.CheckErr(err, "unable to read validation constraints from field") + required := constraints.Required + if constraints.IgnoreEmpty { + required = false + } + var schema jsonschema.Schema - var required bool switch { case field.Type().IsEmbed(): - schema, required = m.schemaForEmbed(field.Type().Embed(), constraints) + schema = m.schemaForEmbed(field.Type().Embed(), constraints) case field.Type().IsEnum(): - schema, required = m.schemaForEnum(field.Type().Enum(), constraints.GetEnum()) + schema = m.schemaForEnum(field.Type().Enum(), constraints.GetEnum()) case field.Type().IsMap(): schema = m.schemaForMap(field.Type().Element(), constraints.GetMap()) case field.Type().IsRepeated(): schema = m.schemaForRepeated(field.Type().Element(), constraints.GetRepeated()) - required = constraints.Required default: - schema, required = m.schemaForScalar(field.Type().ProtoType(), constraints) + schema = m.schemaForScalar(field.Type().ProtoType(), constraints) } return schema, required && !field.InOneOf() } -func (m *Module) schemaForEmbed(embed pgs.Message, constraints *validate.FieldConstraints) (jsonschema.Schema, bool) { +func (m *Module) schemaForEmbed(embed pgs.Message, constraints *validate.FieldConstraints) jsonschema.Schema { m.Debug("schemaForEmbed") if embed.IsWellKnown() { return m.schemaForWellKnownType(embed.WellKnownType(), constraints) } - return m.schemaForMessage(embed), false + return m.schemaForMessage(embed) } func (m *Module) schemaForMessage(message pgs.Message) jsonschema.Schema { diff --git a/internal/module/numeric.go b/internal/module/numeric.go index 47406cf..6ed1c49 100644 --- a/internal/module/numeric.go +++ b/internal/module/numeric.go @@ -30,9 +30,8 @@ type numericRules struct { IgnoreEmpty bool `json:"ignore_empty,omitempty"` } -func (m *Module) schemaForNumericScalar(numeric pgs.ProtoType, constraints *validate.FieldConstraints) (jsonschema.Schema, bool) { +func (m *Module) schemaForNumericScalar(numeric pgs.ProtoType, constraints *validate.FieldConstraints) jsonschema.Schema { m.Debug("schemaForNumericScalar") - required := false value := m.valueSchemaForNumericScalar(numeric) schemas := []jsonschema.NonTrivialSchema{m.stringValueSchemaForNumericScalar(numeric, value)} rules := m.numericRules(numeric, constraints) @@ -41,40 +40,26 @@ func (m *Module) schemaForNumericScalar(numeric pgs.ProtoType, constraints *vali if rules != nil { if rules.Const != nil { value.Const = rules.Const - required = !rules.IgnoreEmpty } if rules.Gt != nil { value.ExclusiveMinimum = rules.Gt - if !rules.Gt.IsNegative() { - required = !rules.IgnoreEmpty - } } if rules.Gte != nil { value.Minimum = rules.Gte - if rules.Gte.IsPositive() { - required = !rules.IgnoreEmpty - } } if len(rules.In) > 0 { value.Enum = rules.In - required = !rules.IgnoreEmpty } if rules.Lt != nil { value.ExclusiveMaximum = rules.Lt - if !rules.Lt.IsPositive() { - required = !rules.IgnoreEmpty - } } if rules.Lte != nil { value.Maximum = rules.Lte - if rules.Lte.IsNegative() { - required = !rules.IgnoreEmpty - } } if len(rules.NotIn) > 0 { @@ -85,7 +70,7 @@ func (m *Module) schemaForNumericScalar(numeric pgs.ProtoType, constraints *vali } } - return jsonschema.AllOf(schemas...), required + return jsonschema.AllOf(schemas...) } func (m *Module) valueSchemaForNumericScalar(numeric pgs.ProtoType) *jsonschema.NumberSchema { diff --git a/internal/module/scalar.go b/internal/module/scalar.go index 427c198..7046468 100644 --- a/internal/module/scalar.go +++ b/internal/module/scalar.go @@ -16,51 +16,40 @@ import ( "github.com/cerbos/protoc-gen-jsonschema/internal/jsonschema" ) -func (m *Module) schemaForScalar(scalar pgs.ProtoType, constraints *validate.FieldConstraints) (jsonschema.Schema, bool) { +func (m *Module) schemaForScalar(scalar pgs.ProtoType, constraints *validate.FieldConstraints) jsonschema.Schema { m.Debug("schemaForScalar") if scalar.IsNumeric() { return m.schemaForNumericScalar(scalar, constraints) } - ignoreEmpty := false - if constraints != nil { - ignoreEmpty = constraints.IgnoreEmpty - } - switch scalar { case pgs.BoolT: return m.schemaForBool(constraints.GetBool()) - case pgs.BytesT: - return m.schemaForBytes(constraints.GetBytes(), ignoreEmpty) - + return m.schemaForBytes() case pgs.StringT: - return m.schemaForString(constraints.GetString_(), ignoreEmpty) - + return m.schemaForString(constraints.GetString_()) default: m.Failf("unexpected scalar type %q", scalar) - return nil, false + return nil } } -func (m *Module) schemaForBool(rules *validate.BoolRules) (jsonschema.Schema, bool) { +func (m *Module) schemaForBool(rules *validate.BoolRules) jsonschema.Schema { m.Debug("schemaForBool") - required := false schema := jsonschema.NewBooleanSchema() if rules != nil { if rules.Const != nil { schema.Const = jsonschema.Boolean(rules.GetConst()) - required = true } } - return schema, required + return schema } -func (m *Module) schemaForBytes(rules *validate.BytesRules, ignoreEmpty bool) (jsonschema.Schema, bool) { +func (m *Module) schemaForBytes() jsonschema.Schema { m.Debug("schemaForBytes") - required := false standard := jsonschema.NewStringSchema() standard.Title = "Standard base64 encoding" @@ -72,25 +61,11 @@ func (m *Module) schemaForBytes(rules *validate.BytesRules, ignoreEmpty bool) (j schema := jsonschema.NewStringSchema() schema.OneOf = []jsonschema.NonTrivialSchema{standard, urlSafe} - - if rules != nil { - required = !ignoreEmpty && - (len(rules.Const) > 0 || - len(rules.Contains) > 0 || - len(rules.In) > 0 || - rules.MinLen != nil || - rules.Pattern != nil || - len(rules.Prefix) > 0 || - len(rules.Suffix) > 0 || - rules.WellKnown != nil) - } - - return schema, required + return schema } -func (m *Module) schemaForString(rules *validate.StringRules, ignoreEmpty bool) (jsonschema.Schema, bool) { +func (m *Module) schemaForString(rules *validate.StringRules) jsonschema.Schema { m.Debug("schemaForString") - required := false schema := jsonschema.NewStringSchema() schemas := []jsonschema.NonTrivialSchema{schema} var patterns []string @@ -99,27 +74,19 @@ func (m *Module) schemaForString(rules *validate.StringRules, ignoreEmpty bool) if rules != nil { if rules.Const != nil { schema.Const = jsonschema.String(rules.GetConst()) - required = !ignoreEmpty } if rules.Contains != nil { patterns = append(patterns, regexp.QuoteMeta(rules.GetContains())) - required = !ignoreEmpty } if len(rules.In) > 0 { schema.Enum = rules.In - required = !ignoreEmpty } if rules.Len != nil { schema.MaxLength = jsonschema.Size(rules.GetLen()) schema.MinLength = jsonschema.Size(rules.GetLen()) - required = !ignoreEmpty - } - - if rules.LenBytes != nil || rules.MinBytes != nil { - required = !ignoreEmpty } if rules.MaxLen != nil { @@ -128,7 +95,6 @@ func (m *Module) schemaForString(rules *validate.StringRules, ignoreEmpty bool) if rules.MinLen != nil { schema.MinLength = jsonschema.Size(rules.GetMinLen()) - required = !ignoreEmpty } if rules.NotContains != nil { @@ -145,19 +111,14 @@ func (m *Module) schemaForString(rules *validate.StringRules, ignoreEmpty bool) if rules.Pattern != nil { patterns = append(patterns, m.makeRegexpCompatibleWithECMAScript(rules.GetPattern())) - if !m.matchesEmptyString(rules.GetPattern()) { - required = !ignoreEmpty - } } if rules.Prefix != nil { patterns = append(patterns, "^"+regexp.QuoteMeta(rules.GetPrefix())) - required = !ignoreEmpty } if rules.Suffix != nil { patterns = append(patterns, regexp.QuoteMeta(rules.GetSuffix())+"$") - required = !ignoreEmpty } if rules.WellKnown != nil { @@ -186,8 +147,6 @@ func (m *Module) schemaForString(rules *validate.StringRules, ignoreEmpty bool) case *validate.StringRules_UriRef: schema.Format = jsonschema.StringFormatURIReference } - - required = !ignoreEmpty } } @@ -201,7 +160,7 @@ func (m *Module) schemaForString(rules *validate.StringRules, ignoreEmpty bool) } } - return jsonschema.AllOf(schemas...), required + return jsonschema.AllOf(schemas...) } func (m *Module) schemaForStringFormats(formats ...jsonschema.StringFormat) jsonschema.NonTrivialSchema { @@ -294,10 +253,3 @@ func writeECMAScriptCompatibleRegexp(w io.StringWriter, expression *syntax.Regex w.WriteString(expression.String()) //nolint:errcheck } } - -func (m *Module) matchesEmptyString(pattern string) bool { - m.Debug("matchesEmptyString") - match, err := regexp.MatchString(pattern, "") - m.CheckErr(err, "failed to check if pattern matches empty string") - return match -} diff --git a/internal/module/well_known.go b/internal/module/well_known.go index cbe0c15..d653932 100644 --- a/internal/module/well_known.go +++ b/internal/module/well_known.go @@ -100,60 +100,44 @@ func (m *Module) defineValue() jsonschema.Schema { } } -func (m *Module) schemaForWellKnownType(name pgs.WellKnownType, constraints *validate.FieldConstraints) (jsonschema.Schema, bool) { +func (m *Module) schemaForWellKnownType(name pgs.WellKnownType, constraints *validate.FieldConstraints) jsonschema.Schema { m.Debug("schemaForWellKnownType") switch name { case pgs.AnyWKT: - return m.schemaForAny(constraints.GetAny()), constraints.Required - + return m.schemaForAny(constraints.GetAny()) case pgs.BoolValueWKT: return m.schemaForBool(constraints.GetBool()) - case pgs.BytesValueWKT: - return m.schemaForBytes(constraints.GetBytes(), constraints.IgnoreEmpty) - + return m.schemaForBytes() case pgs.DoubleValueWKT: return m.schemaForNumericScalar(pgs.DoubleT, constraints) - case pgs.DurationWKT: - return m.schemaForDuration(constraints.GetDuration()), constraints.Required - + return m.schemaForDuration(constraints.GetDuration()) case pgs.EmptyWKT: - return m.ref(wellKnownTypeEmpty, m.defineEmpty), false - + return m.ref(wellKnownTypeEmpty, m.defineEmpty) case pgs.FloatValueWKT: return m.schemaForNumericScalar(pgs.FloatT, constraints) - case pgs.Int32ValueWKT: return m.schemaForNumericScalar(pgs.Int32T, constraints) - case pgs.Int64ValueWKT: return m.schemaForNumericScalar(pgs.Int64T, constraints) - case pgs.ListValueWKT: - return m.ref(wellKnownTypeListValue, m.defineListValue), false - + return m.ref(wellKnownTypeListValue, m.defineListValue) case pgs.StringValueWKT: - return m.schemaForString(constraints.GetString_(), constraints.IgnoreEmpty) - + return m.schemaForString(constraints.GetString_()) case pgs.StructWKT: - return m.ref(wellKnownTypeStruct, m.defineStruct), false - + return m.ref(wellKnownTypeStruct, m.defineStruct) case pgs.TimestampWKT: - return m.schemaForTimestamp(constraints.GetTimestamp()), constraints.Required - + return m.schemaForTimestamp(constraints.GetTimestamp()) case pgs.UInt32ValueWKT: return m.schemaForNumericScalar(pgs.UInt32T, constraints) - case pgs.UInt64ValueWKT: return m.schemaForNumericScalar(pgs.UInt64T, constraints) - case pgs.ValueWKT: - return m.ref(wellKnownTypeValue, m.defineValue), false - + return m.ref(wellKnownTypeValue, m.defineValue) default: m.Failf("unexpected well-known type %q", name) - return nil, false + return nil } }