Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[API] Read default value field option and ensure it matches field type #18

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions internal/converter/converter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,11 @@ func configureSampleProtos() map[string]sampleProto {
ObjectsToValidateFail: []string{testdata.OptionAllowNullValuesFail},
ObjectsToValidatePass: []string{testdata.OptionAllowNullValuesPass},
},
"OptionDefaultValue": {
ExpectedJSONSchema: []string{testdata.OptionDefaultValue},
FilesToGenerate: []string{"OptionDefaultValue.proto"},
ProtoFileName: "OptionDefaultValue.proto",
},
"OptionDisallowAdditionalProperties": {
ExpectedJSONSchema: []string{testdata.OptionDisallowAdditionalProperties},
FilesToGenerate: []string{"OptionDisallowAdditionalProperties.proto"},
Expand Down
1 change: 1 addition & 0 deletions internal/converter/jsonschema/reflect.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ type Type struct {
ManualLink string `json:"manualLink,omitempty"` // custom
IgnoreInAutocomplete bool `json:"ignoreInAutocomplete,omitempty"` // custom
Units protos.NumericalUnits `json:"units,omitempty"` // custom
DefaultValue interface{} `json:"DefaultValue,omitempty"` // custom
Not *Type `json:"not,omitempty"` // section 5.25
Definitions Definitions `json:"definitions,omitempty"` // section 5.26
// RFC draft-wright-json-schema-validation-00, section 6, 7
Expand Down
41 changes: 41 additions & 0 deletions internal/converter/testdata/option_default_value.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package testdata

const OptionDefaultValue = `{
"$schema": "http://json-schema.org/draft-04/schema#",
"$ref": "#/definitions/OptionDefaultValue",
"$fullRef": "#/definitions/samples.OptionDefaultValue",
"definitions": {
"OptionDefaultValue": {
"properties": {
"field_one": {
"type": "string",
"options": {
"DefaultValue": "sample_str"
}
},
"field_two": {
"items": {
"type": "boolean"
},
"type": "array",
"options": {
"DefaultValue": true
}
},
"field_three": {
"type": "integer",
"options": {
"DefaultValue": 7
}
},
"field_four": {
"type": "integer"
}
},
"additionalProperties": true,
"type": "object",
"title": "Option Default Value"
}
}
}`

10 changes: 10 additions & 0 deletions internal/converter/testdata/proto/OptionDefaultValue.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
syntax = "proto3";
package samples;
import "options.proto";

message OptionDefaultValue {
string field_one = 1 [(protoc.gen.jsonschema.default_value).string_value = "sample_str"];
repeated bool field_two = 2 [(protoc.gen.jsonschema.default_value).bool_value = true];
int32 field_three = 3 [(protoc.gen.jsonschema.default_value).number_value = 7];
int32 field_four = 4;
}
54 changes: 54 additions & 0 deletions internal/converter/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (

"github.com/AppliedIntuition/protoc-gen-jsonschema/internal/converter/jsonschema"
"github.com/AppliedIntuition/protoc-gen-jsonschema/internal/protos"

"github.com/golang/protobuf/ptypes/struct"
)

var (
Expand All @@ -33,6 +35,20 @@ var (
}
)

// Expected google.protobuf.Value type
// (this is not 1:1 with protobuf types - for example, doubles and ints
// are both represented by number_value)
type ValueType int

// Currently only support overrides for numbers, strings and booleans.
const (
unset ValueType = iota
number_value
string_value
bool_value
)


func (c *Converter) registerEnum(pkgName string, enum *descriptor.EnumDescriptorProto) {
pkg := globalPkg
if pkgName != "" {
Expand Down Expand Up @@ -114,12 +130,17 @@ func (c *Converter) convertField(curPkg *ProtoPackage, desc *descriptor.FieldDes
}
}

// Initialize expectedValueType to unset
expectedValueType := unset

// Switch the types, and pick a JSONSchema equivalent:
switch desc.GetType() {

// Float32:
case descriptor.FieldDescriptorProto_TYPE_DOUBLE,
descriptor.FieldDescriptorProto_TYPE_FLOAT:

expectedValueType = number_value
if messageFlags.AllowNullValues {
jsonSchemaType.OneOf = []*jsonschema.Type{
{Type: gojsonschema.TYPE_NULL},
Expand All @@ -135,6 +156,8 @@ func (c *Converter) convertField(curPkg *ProtoPackage, desc *descriptor.FieldDes
descriptor.FieldDescriptorProto_TYPE_FIXED32,
descriptor.FieldDescriptorProto_TYPE_SFIXED32,
descriptor.FieldDescriptorProto_TYPE_SINT32:

expectedValueType = number_value
if messageFlags.AllowNullValues {
jsonSchemaType.OneOf = []*jsonschema.Type{
{Type: gojsonschema.TYPE_NULL},
Expand All @@ -150,6 +173,8 @@ func (c *Converter) convertField(curPkg *ProtoPackage, desc *descriptor.FieldDes
descriptor.FieldDescriptorProto_TYPE_FIXED64,
descriptor.FieldDescriptorProto_TYPE_SFIXED64,
descriptor.FieldDescriptorProto_TYPE_SINT64:

expectedValueType = number_value

// As integer:
if c.Flags.DisallowBigIntsAsStrings {
Expand Down Expand Up @@ -177,6 +202,7 @@ func (c *Converter) convertField(curPkg *ProtoPackage, desc *descriptor.FieldDes

// String:
case descriptor.FieldDescriptorProto_TYPE_STRING:
expectedValueType = string_value
stringDef := &jsonschema.Type{Type: gojsonschema.TYPE_STRING}
// Check for custom options
opts := desc.GetOptions()
Expand Down Expand Up @@ -265,6 +291,7 @@ func (c *Converter) convertField(curPkg *ProtoPackage, desc *descriptor.FieldDes

// Bool:
case descriptor.FieldDescriptorProto_TYPE_BOOL:
expectedValueType = bool_value
if messageFlags.AllowNullValues {
jsonSchemaType.OneOf = []*jsonschema.Type{
{Type: gojsonschema.TYPE_NULL},
Expand Down Expand Up @@ -308,6 +335,33 @@ func (c *Converter) convertField(curPkg *ProtoPackage, desc *descriptor.FieldDes
return nil, fmt.Errorf("unrecognized field type: %s", desc.GetType().String())
}

// Read default_value field option if it exists
// and validate that the type matches the field type.
if options != nil {
if proto.HasExtension(options, protos.E_DefaultValue) {
var defaultValue interface{}

defaultValueObj := proto.GetExtension(options, protos.E_DefaultValue).(*structpb.Value)
if defaultValueObj.GetStringValue() != "" && expectedValueType == string_value {
defaultValue = defaultValueObj.GetStringValue()

} else if defaultValueObj.GetBoolValue() != false && expectedValueType == bool_value {
defaultValue = defaultValueObj.GetBoolValue()

} else if defaultValueObj.GetNumberValue() != 0 && expectedValueType == number_value {
defaultValue = defaultValueObj.GetNumberValue()

} else {
return nil, fmt.Errorf("Type of default value is incompatible with type of field.")
}

if jsonSchemaType.Options == nil {
jsonSchemaType.Options = &jsonschema.Type{}
}
jsonSchemaType.Options.DefaultValue = defaultValue
}
}

// Recurse array of primitive types:
if desc.GetLabel() == descriptor.FieldDescriptorProto_LABEL_REPEATED && jsonSchemaType.Type != gojsonschema.TYPE_OBJECT {
jsonSchemaType.Items = &jsonschema.Type{}
Expand Down
122 changes: 68 additions & 54 deletions internal/protos/options.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions options.proto
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
syntax = "proto3";
package protoc.gen.jsonschema;
import "google/protobuf/descriptor.proto";
import "google/protobuf/struct.proto";
option go_package = "./protos";


Expand Down Expand Up @@ -187,6 +188,9 @@ extend google.protobuf.FieldOptions {
string manual_link = 50015;
bool ignore_in_autocomplete = 50000;
NumericalUnits units = 50010;

// Custom default value of a field
google.protobuf.Value default_value = 50019;
}

extend google.protobuf.FileOptions {
Expand Down
Loading